|
******************************************************************************\ 0 w' X2 w2 V2 z# H T- H9 i
* ping.c - Simple ping utility using SOCK_RAW $ \: x- s9 y9 ^" _
* 3 p" e. R; D% V% A
* This is a part of the Microsoft Source Code Samples.
) z' {7 p) j# r5 k3 ~* Copyright 1996-1997 Microsoft Corporation. . L4 E1 M3 q$ _1 G3 A
* All rights reserved. E! `* }6 n2 `* b. a
* This source code is only intended as a supplement to 5 S+ U6 p4 i1 e
* Microsoft Development Tools and/or WinHelp documentation.
* T1 N2 k. R9 O% y W* See these sources for detailed information regarding the
S. u& ~6 R/ P6 ?/ g3 l* Microsoft samples programs.
4 a7 v: D# ^6 q! Q! c\******************************************************************************/
; \1 D4 {+ p, C0 o( q! ]0 V3 g9 _% w- O
#pragma pack(4) 0 K+ O/ {) |, w/ H2 S6 j# L
7 i9 h, j/ F* i6 p# _: T3 I#define WIN32_LEAN_AND_MEAN
g# d: ?* m0 y- S& d8 A, [" b#include
! C0 ?- c: t- y$ n0 [#include + R/ u; d8 i9 z7 g2 y
#include % Q- C l b9 `6 U8 |# s
Z4 r% O4 e0 d# ?4 \
#define ICMP_ECHO 8
. g- v7 c4 q6 @7 l( W I( _#define ICMP_ECHOREPLY 0
( S, _, ^0 y) |- a x- L1 K1 g4 C/ u
$ Z: C5 h* @4 V#define ICMP_MIN 8 // minimum 8 byte icmp packet (just header)
# z) v0 A) o6 l& ~
5 d* s* u" ?" A! ]/* The IP header */
' N X" ^# Z# e2 p" X/ ^typedef struct iphdr {
" ~' x: @! V1 ^; D$ i' gunsigned int h_len:4; // length of the header ) T; L2 c( \& t z+ L3 ?8 y% d
unsigned int version:4; // Version of IP
$ U& p) s8 m7 T1 p Iunsigned char tos; // Type of service
2 @) w+ _4 y6 ~. r# Zunsigned short total_len; // total length of the packet 4 e; `2 S. a V* S _
unsigned short ident; // unique identifier
: Q1 c0 o0 B$ Yunsigned short frag_and_flags; // flags / e. }8 d& ]* O6 t, f4 E: Z+ w
unsigned char ttl;
. Z- w: [6 ? E7 uunsigned char proto; // protocol (TCP, UDP etc)
1 e( w1 S2 _" o" a X; Tunsigned short checksum; // IP checksum
" [4 O: F' u# l# O* a; p
2 @3 h4 w2 O) Vunsigned int sourceIP; & v U# N$ {' ]5 u" J% J
unsigned int destIP; 6 a. Q$ |4 z8 r
3 k2 Z4 K3 |$ L3 b) X% I" o3 M7 h- e}IpHeader; 2 C9 b7 J) b! c. \- B+ P3 X# t5 j! y3 M# f
& v4 ?- a k( b
// 5 D' M( f0 C! ^9 |: L
// ICMP header 8 A& E" G1 M: v+ P) K
//
& J6 E3 G: H5 f+ L ?( utypedef struct _ihdr {
& j4 }2 t4 X/ \3 R. u7 k: mBYTE i_type;
) o6 ?$ j: O* l8 o; t& p7 Q( DBYTE i_code; /* type sub code */ ( T) Y% N, d0 J
USHORT i_cksum; ' F) }* ~. y0 e# [
USHORT i_id; 9 n6 K7 m! W0 x7 f ?/ B) y8 b
USHORT i_seq;
9 }7 I; c7 w( f' {: E/* This is not the std header, but we reserve space for time */
( f0 q/ E; I( v; [ULONG timestamp;
" g/ B& F- Q6 u' a" Q- W, U( x2 \}IcmpHeader;
j5 o8 K1 M; D/ ~
2 F- o: P! w7 K#define STATUS_FAILED 0xFFFF
* T6 |+ S; n! V$ R#define DEF_PACKET_SIZE 32
( O* z6 u& _2 D0 m0 h- B/ ]1 c#define MAX_PACKET 1024
: a8 n! v% D/ R( F6 a
$ P$ H% L# T/ p#define xmalloc(s) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(s))
( q" u6 \- f- K# f& {#define xfree(p) HeapFree (GetProcessHeap(),0,(p)) $ r1 k* \+ f- G t. g% `4 a4 P8 j
+ `) Z7 |$ V1 U6 w! V8 A- |- P
void fill_icmp_data(char *, int);
1 m( g- A9 Z6 M( Q, v J) }0 BUSHORT checksum(USHORT *, int);
( A- v3 U' j9 {5 V; Hvoid decode_resp(char *,int ,struct sockaddr_in *); " m$ I8 G7 r& q& e
8 J7 r; I9 c6 B% W2 lvoid Usage(char *progname){
& E5 m/ x1 V, P! J* L S; L! B0 b$ u
+ M2 h6 G# U2 N2 _5 ? Tfprintf(stderr,"Usage:\n");
5 V8 R9 {- l# A! |3 x! p* { mfprintf(stderr,"%s [data_size]\n",progname);
$ b% W* v1 q X. [* j$ efprintf(stderr,"datasize can be up to 1Kb\n");
% s7 v5 u6 }! ^0 s/ _: ?ExitProcess(STATUS_FAILED);
& r- s) x# @; j& ?
9 W- ?% _: V! } Z}
- x( |% }0 r7 X6 }int main(int argc, char **argv){
4 |$ s4 v% i7 ?& ^) D1 V7 L1 c2 N: a% Q8 S2 ]
WSADATA wsaData;
7 }2 V# r n' K$ @$ o( xSOCKET sockRaw;
4 o( E( ~& q9 n, K! x) n n$ P: mstruct sockaddr_in dest,from;
! {% J" f" h2 b# @- U8 X0 Rstruct hostent * hp; / t' B7 S' b( ?' y3 m! \8 n1 m
int bread,datasize;
4 V* k( e- y" b4 E9 Vint fromlen = sizeof(from);
* c& H' Z+ B! I1 P4 O! v$ l8 Eint timeout = 1000;
! S4 M" N$ I/ u4 I4 L8 m4 s- ?, ychar *dest_ip; 2 }0 N. K$ W( O* M: m7 r/ w
char *icmp_data;
( R2 K" `+ u2 K# Y" `char *recvbuf;
) A& D1 c7 u5 Qunsigned int addr=0; 6 Y& J0 c8 [. f' `, L, n6 |0 Z
USHORT seq_no = 0;
3 F" v9 |" S3 t1 \% i% i/ H* q5 O! u+ g0 M$ }, q2 N
if (WSAStartup(MAKEWORD(2,1),&wsaData) != 0){ # S4 D8 y$ F* x1 Q3 y2 I
fprintf(stderr,"WSAStartup failed: %d\n",GetLastError());
# e& M: N0 u$ n- i) B, P9 PExitProcess(STATUS_FAILED);
3 A, C/ S4 P+ C7 G}
. p3 v5 ~. \; k& |2 h# x9 w2 G
if (argc <2 ) {
% }, O4 q' s( RUsage(argv[0]);
7 Z G5 q- h0 R) @* r4 F} 7 f/ S2 E! _) B$ t6 a
sockRaw = WSASocket (AF_INET, 4 C& x' s* b- a: u
SOCK_RAW, $ f3 Y4 l6 T( f* Y+ \% {
IPPROTO_ICMP,
$ e1 c" W" }9 J$ J1 X. WNULL, 0,0); 7 L3 B6 d C+ P4 K, P' q
; a, F8 o9 w! r! ^7 R! h) d( Tif (sockRaw == INVALID_SOCKET) { - \# H5 i+ [' o7 N8 {- z& a
fprintf(stderr,"WSASocket() failed: %d\n",WSAGetLastError());
6 |2 D8 P0 w zExitProcess(STATUS_FAILED);
# n2 B/ a" p& n2 n) r5 B}
' C5 _3 W/ W2 e+ Q* g+ j6 g) Wbread = setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout, , G4 @0 v. ~/ I) T
sizeof(timeout)); + a7 ]0 b* C9 K! [
if(bread == SOCKET_ERROR) { " ^. t$ c/ m" y4 Q
fprintf(stderr,"failed to set recv timeout: %d\n",WSAGetLastError()); 0 U: ~1 G0 A) t. \
ExitProcess(STATUS_FAILED);
7 Y7 u4 t8 i& H2 F4 y5 d5 B}
& K4 c' {' C; V6 Ltimeout = 1000;
9 h/ p9 ], F( l" o, m$ ^( Ubread = setsockopt(sockRaw,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout, ' w* Z2 r7 I/ Y. M6 |* G; D6 @. d
sizeof(timeout));
1 k9 D/ o! H: kif(bread == SOCKET_ERROR) {
# c6 J) k$ g2 R4 X7 m# B, F. wfprintf(stderr,"failed to set send timeout: %d\n",WSAGetLastError());
7 [, _6 O3 }3 Y- B$ qExitProcess(STATUS_FAILED);
; p: I: J. l4 [" F p) x' Y7 J V X}
7 |+ Z3 t3 X; v) l; Xmemset(&dest,0,sizeof(dest));
h; J* `0 l; C6 I y7 Q
2 \0 q3 Q7 |; |hp = gethostbyname(argv[1]);
' R/ y" ^: s( b8 \0 W1 J, g
1 c8 W% y% x. Rif (!hp){
% B, D/ k( Y4 C8 q {addr = inet_addr(argv[1]); : F* S5 d. j ~0 q5 j$ l
}
: r* b2 H- G1 p% {if ((!hp) && (addr == INADDR_NONE) ) { % v" G5 i6 i2 A. O8 b7 q/ z
fprintf(stderr,"Unable to resolve %s\n",argv[1]);
+ B4 I; N+ @8 D4 W) bExitProcess(STATUS_FAILED);
/ W1 f8 X' T. h W6 v& u} 5 |% _3 P& k. s; x/ y6 G
; n/ R) F* `" R* i. Z1 qif (hp != NULL) 9 U$ }$ m' Y% @3 X8 h) l1 k7 Y/ {
memcpy(&(dest.sin_addr),hp->h_addr,hp->h_length); % }& V, H. [# y2 R9 q
else 4 k( {5 i* s* ~+ _- c
dest.sin_addr.s_addr = addr; 6 |( M$ R, y0 s' e3 j
4 u4 L* F% e' v' q" g. T: Z
if (hp) 3 C1 u7 o4 n5 m. b, H Q& X% l, A8 k
dest.sin_family = hp->h_addrtype; 3 [& c& m' k, `; I0 E$ B! b8 f. g, e
else $ r! x$ d T$ L9 Y9 t6 j8 m b
dest.sin_family = AF_INET;
5 [& L+ q1 o# W% [
' E: f \3 K# p) G& _dest_ip = inet_ntoa(dest.sin_addr);
# z$ _+ f! T/ y
* I w; }" e! |) Vif (argc >2) { . {- k9 q) `- F9 O2 J1 q
datasize = atoi(argv[2]);
+ h% _# P2 m* O l1 yif (datasize == 0) ! B' W* ?* N( R0 U2 u" G% A8 M
datasize = DEF_PACKET_SIZE; 6 t7 H) K0 a5 [; n5 i( g
3 P; ^2 y* t6 Z
} : s+ @3 D; `" R# E0 U6 H; ]( O
else ! f% M- F- h' N9 U* j' R! Y
datasize = DEF_PACKET_SIZE; $ N2 E4 \ g! l9 t
/ e( r1 ?4 Y0 |9 @9 z, q) H% v. Rdatasize += sizeof(IcmpHeader); / Q0 |3 p) \) O# C7 U
; d& S; M {) ^0 [icmp_data = xmalloc(MAX_PACKET);
! {# I% V9 C( _# s) D) R Erecvbuf = xmalloc(MAX_PACKET);
6 T2 i# I1 o* i. U" w, I+ F3 Q, n2 T; @4 M8 }6 p) L( K# w' j
if (!icmp_data) { 2 V' r4 F' N j( |+ d% b2 N6 ^
fprintf(stderr,"HeapAlloc failed %d\n",GetLastError()); * Z/ b* M# X; U2 `! |. r
ExitProcess(STATUS_FAILED); * z% Q' l( U1 N% ]
}8 u. E4 i2 G% [, Y6 ^
memset(icmp_data,0,MAX_PACKET);
0 y5 P% d6 V) Pfill_icmp_data(icmp_data,datasize); ) z: w0 V9 p) ]# H" G
Z5 q6 m9 \( C$ J: h( R% l% T9 J9 G
while(1) { - \& t7 y& L9 S
int bwrote; . L7 @: a1 F8 |; G, n; H. Y1 d
" P, A9 y$ @5 X1 H1 o
((IcmpHeader*)icmp_data)->i_cksum = 0; R, U* a M$ K2 A, K1 ~
((IcmpHeader*)icmp_data)->timestamp = GetTickCount();
. ~4 ^! F+ c! y9 M' n, H- r. \( g/ k, d) U
((IcmpHeader*)icmp_data)->i_seq = seq_no++;
: q7 ] w# T7 _7 [4 R7 `" d7 L((IcmpHeader*)icmp_data)->i_cksum = checksum((USHORT*)icmp_data, - C- {1 s; t2 `
datasize);
% V& e& }" c1 I! d) F' b" a @1 P; ]; Q- h7 w5 @& y
bwrote = sendto(sockRaw,icmp_data,datasize,0,(struct sockaddr*)&dest,
+ p6 I' R$ }+ u, _sizeof(dest));
2 _ g6 P r# `0 M- W$ `if (bwrote == SOCKET_ERROR){ / l$ d/ I3 X" Q$ G% x! M
if (WSAGetLastError() == WSAETIMEDOUT) { ) H3 {" g: T0 p4 B' m- Z. `$ O
printf("timed out\n"); 2 h- R" O) V; W# a
continue; - z) _8 @# o6 ~3 s
} 9 r; t1 F5 o6 B- E! R3 g4 C5 ?
fprintf(stderr,"sendto failed: %d\n",WSAGetLastError()); # D5 O0 t+ ~ H! P
ExitProcess(STATUS_FAILED);
1 h! }' P2 o% q- x& k" I1 {2 q. p+ Q} $ }5 h+ E% F, \% P- O% T
if (bwrote < datasize ) {
4 B3 n8 m# \2 O0 A8 o9 h6 afprintf(stdout,"Wrote %d bytes\n",bwrote); - K+ s1 b% n" p+ w
} - s) t8 ]- J. L9 o i, Z" M* l+ ?+ L
bread = recvfrom(sockRaw,recvbuf,MAX_PACKET,0,(struct sockaddr*)&from,
# h! l2 [% X% ~8 {" j1 t6 n&fromlen);
' {! Q$ c. e3 M- y$ e# W$ z9 Z& ]if (bread == SOCKET_ERROR){
, Z# p$ g0 q. K; r( {if (WSAGetLastError() == WSAETIMEDOUT) { 2 H, l' o# `) M: a( J
printf("timed out\n"); ' o$ ]1 t; S$ x
continue;
. Z0 `9 x$ [3 Y- D3 T& S$ U}
; K2 R/ J- ?5 J9 X$ }fprintf(stderr,"recvfrom failed: %d\n",WSAGetLastError()); 8 D7 E9 J, p, I
ExitProcess(STATUS_FAILED);
6 e4 n0 k" s! A, J! S( S} # b+ X0 W' U% S! I
decode_resp(recvbuf,bread,&from); # M$ ^0 ]$ P# Z# j+ ~0 a
Sleep(1000); ( Z4 @ l/ A" _! H
. {. v) S+ B% z& V! h4 L5 p1 B# K}
* _+ x9 u, n; ^, L! X8 j" L, h8 P9 ?return 0;
3 y4 {0 S& i( x% E) c8 o8 u( M9 n: Q, l( I+ t' h) c9 h q
}
` z5 ^; O7 _8 n/* % f3 u7 ?8 S5 g6 z
The response is an IP packet. We must decode the IP header to locate + O- {2 J- U/ g* |$ L8 r0 |' x
the ICMP data / Z+ M3 i1 q. j( I
*/ + M6 s4 D5 C6 E8 e1 A6 F
void decode_resp(char *buf, int bytes,struct sockaddr_in *from) {
6 \" \+ l" A* \8 P1 f. L) B3 n s2 z7 [" a: U' A& B
IpHeader *iphdr;
4 [2 ?: D" [! _/ ^ BIcmpHeader *icmphdr;
5 M# m7 {8 a, ^2 @( n* Punsigned short iphdrlen; . y% r' ]. L# P* p9 n; @
3 N/ y. a7 c' s5 }# H# t |iphdr = (IpHeader *)buf; / a! }/ w6 r+ i! N. r% z4 S
4 @& H: `. l% x5 c. M" Q4 m
iphdrlen = iphdr->h_len * 4 ; // number of 32-bit words *4 = bytes 6 W: F+ P# S2 ~3 _
- t! S8 ^, i: _* _6 c. z
if (bytes < iphdrlen + ICMP_MIN) { 3 S" g7 U" f- l
printf("Too few bytes from %s\n",inet_ntoa(from->sin_addr));
5 `& b% K' f- ^/ K' y}
; y) {, t9 X5 f3 z2 f O# ~& {1 h8 `0 ] E# b4 T
icmphdr = (IcmpHeader*)(buf + iphdrlen); ( J: f7 b6 w( e$ l: L6 T1 g9 n4 O
) w/ v8 E* \& Q: J4 ?' o3 D8 x. B
if (icmphdr->i_type != ICMP_ECHOREPLY) {
7 K+ b3 X0 H. l+ {6 ?, ?/ rfprintf(stderr,"non-echo type %d recvd\n",icmphdr->i_type);
3 T& ^+ A9 V7 qreturn;
8 c* R$ O7 o! I! O6 S} 1 r4 c4 k, Y: C1 H+ [# B
if (icmphdr->i_id != (USHORT)GetCurrentProcessId()) {
1 z- ~& t6 Y& ?( D" {fprintf(stderr,"someone else's packet!\n"); % e+ u$ v G2 ?1 w
return ; 6 q; X6 F' B2 p8 p
} . B# A/ ^0 H2 j% s; D
printf("%d bytes from %s:",bytes, inet_ntoa(from->sin_addr));
7 z6 ^- q/ f7 E& Fprintf(" icmp_seq = %d. ",icmphdr->i_seq); : V1 i! g* p$ Z5 k2 k! V; `3 s
printf(" time: %d ms ",GetTickCount()-icmphdr->timestamp); % S$ ]$ ~ U( s
printf("\n"); h; `' e8 R. u
/ I0 Z# C4 n# c9 k! [0 ]
}
# W) Z( Q1 E0 e. k& T _) K' N3 `! k' D8 \0 h/ y2 h% h
B1 o- g I+ K z1 sUSHORT checksum(USHORT *buffer, int size) {
" {) D% Y; s6 d( O* ^" c! B7 X: C* I; v
unsigned long cksum=0; , c8 w. @' K3 w& _/ e
% M5 L3 T0 P; v* M' jwhile(size >1) {
( b/ d6 E: v: [2 v1 rcksum+=*buffer++; & _7 A0 c) z% G0 | |5 v9 Z' O
size -=sizeof(USHORT);
2 M/ b! p" T/ r1 e# }3 i} ) f) x u& N& q+ @
C( W! s' z3 y3 x' d& w% uif(size ) { $ N M* t- C& B7 t0 n
cksum += *(UCHAR*)buffer; # T: n/ r& v$ N4 Q- @* f
}
% ~9 Z+ r& w* Q# V$ {. {9 n' C; i4 z8 r2 k
cksum = (cksum >> 16) + (cksum & 0xffff);
@) O$ f7 x' r* Rcksum += (cksum >>16); * M, M8 d! Q$ S4 d c( Q) \
return (USHORT)(~cksum); + G( f! C$ }/ G: {* f9 r0 |: m
}
) r! x6 D1 F' p: x/* ) K* ?$ L5 H( s3 x& F# C0 A
Helper function to fill in various stuff in our ICMP request. ( y) Y# H$ d2 @3 I. z! }
*/
8 B2 r5 V+ I2 E$ W8 Evoid fill_icmp_data(char * icmp_data, int datasize){ / D4 X3 {1 M6 @- E& @
+ ]( l3 U' u' V( ~ @& Y: Z, r- a
IcmpHeader *icmp_hdr; / `) ^6 x/ G; |% d8 ?+ k [
char *datapart;
1 H* Y% k# |) B+ S! M1 e0 ~( N+ O, M0 m% o
icmp_hdr = (IcmpHeader*)icmp_data;
9 r2 t7 s3 ^, f4 z* \5 c1 W8 z! e& {
icmp_hdr->i_type = ICMP_ECHO;
# N6 Z* g9 T2 y. licmp_hdr->i_code = 0;
) Z2 ]% C3 @: V7 J3 C) xicmp_hdr->i_id = (USHORT)GetCurrentProcessId();
h+ E5 ]+ s5 x% ^icmp_hdr->i_cksum = 0; ) _! T6 A0 q0 B; t, D
icmp_hdr->i_seq = 0;
' e, K( u- \! R; T# c3 S" x% C1 ~& n+ h( S. ~5 X! b
datapart = icmp_data + sizeof(IcmpHeader); 2 U. p) P# @8 I6 w6 i
//
S2 s) K# l) ~! r% j// Place some junk in the buffer.
9 B; m: Q" l$ o/ O2 t//
; J0 n7 e- z& l. Z4 e' D) r1 V* Rmemset(datapart,'E', datasize - sizeof(IcmpHeader));
# T- {' o8 M4 [4 `/ N ^ M5 f. [5 }) c; a% i
} |
|