|
******************************************************************************\
8 R- V4 F4 E+ g2 b# ]9 L* ping.c - Simple ping utility using SOCK_RAW 8 ~# F5 j2 P' ?9 |! Z' D7 }
*
8 t x7 j- T# }+ j6 n# z" \* This is a part of the Microsoft Source Code Samples. # C* _4 R7 `/ P8 v2 F* R
* Copyright 1996-1997 Microsoft Corporation. 2 U( C# P# @/ Z& U! K
* All rights reserved. 0 e* s3 q+ E9 R- C3 ^# @
* This source code is only intended as a supplement to
6 m; B5 u# e6 j: R3 h) J9 R* Microsoft Development Tools and/or WinHelp documentation.
1 z6 L, i- I2 ^; {7 ~4 P, {* See these sources for detailed information regarding the 1 y# `. C# _+ [6 s6 H( W% f
* Microsoft samples programs.
9 Z. h6 O; X. O3 f\******************************************************************************/ " l% M6 m! @" e" l4 A9 N
+ N" k* W+ F* {2 X#pragma pack(4) # s2 M, i- q u! Y8 r
u& T6 r1 B! C2 s5 D
#define WIN32_LEAN_AND_MEAN
/ u& \2 x0 B8 z* |% \' K#include
" r4 V) B6 z- Y9 I#include 7 l2 J$ q: s7 u
#include
: y5 u/ a; s' {. l0 g( P% U4 g( }' a2 w' Y. @5 T E$ s
#define ICMP_ECHO 8 2 b8 ?4 A2 ~4 M9 a& I
#define ICMP_ECHOREPLY 0 5 C' l! t+ z+ a% C" a
1 y* f9 H a) b+ X#define ICMP_MIN 8 // minimum 8 byte icmp packet (just header)
4 B4 w5 I, F+ P
' p1 Y2 r T% C/* The IP header */
2 d' u$ P9 I* z: Y. U6 ntypedef struct iphdr {
2 c" N- { e, g, T" f' @' Funsigned int h_len:4; // length of the header
2 A M. N2 t- ~- qunsigned int version:4; // Version of IP
5 V. r q1 N/ k4 Wunsigned char tos; // Type of service * |5 f! \3 x5 x* j9 W
unsigned short total_len; // total length of the packet
/ p$ @& _& g, B, Uunsigned short ident; // unique identifier
2 a7 }! F) f2 O6 K- ^unsigned short frag_and_flags; // flags 1 w2 R: x1 {8 y. F9 Y
unsigned char ttl; ) b! ~. m" U6 Y
unsigned char proto; // protocol (TCP, UDP etc) ' b) h# @. H; j) n: Z5 T
unsigned short checksum; // IP checksum
1 t" O6 s$ r5 j% l/ ~- F$ n: T" L7 C, o; C* A9 _& @
unsigned int sourceIP; 2 G5 D( }5 H+ g6 i d
unsigned int destIP; 2 j. a1 W3 T8 z0 y4 K0 z
& s( R+ I/ ~) T}IpHeader;
0 C& e2 K5 X7 J- b( c! v5 \
; E8 v6 J3 O0 x$ x; i( @// ) H x0 f/ q+ Y& a& B
// ICMP header + c: E! \6 K8 G( \
// 0 T0 O) b, R# _8 g
typedef struct _ihdr { 7 M+ J. d9 ~7 y" Z" \! I. \
BYTE i_type; * [# j; i3 X5 h7 i
BYTE i_code; /* type sub code */ ) _2 `+ N5 |% Q5 T* }7 |
USHORT i_cksum;
/ U$ a$ z' U: H2 s7 uUSHORT i_id;
- _. m' J1 _" o$ F+ }; UUSHORT i_seq;
2 T! v' X# s4 I9 M% _6 R/ p% ~' _1 \/* This is not the std header, but we reserve space for time */ 1 m: D6 R4 u9 Y) ^ v; G( s1 ?
ULONG timestamp;
" ^9 s) s" M/ z/ j k. d7 k}IcmpHeader;
$ U6 h: v0 q) f0 [4 ?+ K3 _0 a( l. e _* m8 O
#define STATUS_FAILED 0xFFFF % ?2 D6 |" I( B! Y5 M7 I
#define DEF_PACKET_SIZE 32 0 O& c% j6 {$ j, u, |% f8 G& Z
#define MAX_PACKET 1024
! U/ @. ^6 p7 R- K
# H$ l) c% q( c: E, P#define xmalloc(s) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(s))
; {5 l& W+ M5 T/ S4 T#define xfree(p) HeapFree (GetProcessHeap(),0,(p))
/ H; d. A' u' R8 `, W4 ~7 |, B {0 x# v& E: q
void fill_icmp_data(char *, int); 0 Y: s! ^( T4 L4 [
USHORT checksum(USHORT *, int); 5 v2 i0 a/ x& Z' Y% G9 m
void decode_resp(char *,int ,struct sockaddr_in *);
7 Q# s) R, l: ]$ X
- C8 Q: m, e# l8 }void Usage(char *progname){ 4 s7 @4 s/ f" O- M6 z
1 `( {, g3 N7 | nfprintf(stderr,"Usage:\n");
& G0 F7 p# z9 F0 D5 ]5 Z: k8 n7 Wfprintf(stderr,"%s [data_size]\n",progname);
H! U7 Q! X# r/ n! ?fprintf(stderr,"datasize can be up to 1Kb\n");
7 p% ]5 n1 c, _( v* {ExitProcess(STATUS_FAILED); $ i7 z D+ _7 L' d: f
: x" b) W9 x8 c, m* C6 \! W}
% G- o- Z; c8 ^) \. N3 pint main(int argc, char **argv){
2 f5 ^; g) {& o" D9 k q+ E$ y' R3 u3 o5 t4 u
WSADATA wsaData;
1 L: m- n- s0 t) v% s3 g/ |! l: [SOCKET sockRaw; " x- i; p1 G, K
struct sockaddr_in dest,from;
/ E" J, |3 K6 v4 c+ _1 M8 @struct hostent * hp; ) ?& S9 e( P# ?+ Y) P% d, o; b1 Q
int bread,datasize;
+ B1 y/ V' x/ d& F, R3 _int fromlen = sizeof(from);
) W5 l& I: Y6 {$ K6 Uint timeout = 1000; 0 I& d0 w1 p4 T6 ], k2 u
char *dest_ip;
0 L8 `7 w$ ?8 f3 A" gchar *icmp_data; : S# q( {2 W: I/ ~
char *recvbuf; |( S6 U2 r2 \! p
unsigned int addr=0; / z' ^- [6 y/ T) ]; O/ N6 g& @: s
USHORT seq_no = 0; 4 C, x3 y% X. F) p. ?. X
: P0 _$ o; [% @9 g- W) E
if (WSAStartup(MAKEWORD(2,1),&wsaData) != 0){
* i( Q7 j7 |$ I1 Ufprintf(stderr,"WSAStartup failed: %d\n",GetLastError()); 2 }7 {+ t9 M- e& `# ]$ X
ExitProcess(STATUS_FAILED); 3 Z, f3 Q5 R& G+ S/ q! j$ @
} # o& Q0 _; ]6 C0 P. I
. s9 v3 Q& `9 p0 h9 }
if (argc <2 ) { 4 x2 l! C4 D4 y3 {& p/ T
Usage(argv[0]);
1 `! W. C+ {7 k3 X}
- v8 V' s. r* v$ MsockRaw = WSASocket (AF_INET, % j( ^' o; g, G8 @7 F0 l
SOCK_RAW, : W& t0 Q$ j2 {, j0 q) T* L
IPPROTO_ICMP, # S5 C1 o% m; h7 l
NULL, 0,0); 9 m( v& t3 H% H. g; y
+ J7 C7 ]7 D9 v) C
if (sockRaw == INVALID_SOCKET) {
. L( T/ M+ P/ |0 u# M; tfprintf(stderr,"WSASocket() failed: %d\n",WSAGetLastError()); 2 l- c. T( V! i4 R2 e
ExitProcess(STATUS_FAILED);
0 Z# b5 L- ]; A9 V% H; ]5 M}
9 ]* p- c0 s* I7 @3 I, e; Qbread = setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout,
+ H! x1 Y% Q, O, ]: Gsizeof(timeout));
3 C, Q+ |: v6 D7 c7 Y) e1 Lif(bread == SOCKET_ERROR) { - |; M ?$ h1 ?9 \0 t
fprintf(stderr,"failed to set recv timeout: %d\n",WSAGetLastError()); 6 @/ y" J/ L4 N- K
ExitProcess(STATUS_FAILED); * @+ A) r( A( a8 |* e8 u
}
% D1 @ b1 h: o4 L* i! M" h. _+ btimeout = 1000; 5 A8 z* m. c7 `3 `, ~4 E) l
bread = setsockopt(sockRaw,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout,
7 Y1 v% h2 K: w% F: Z6 \: C* Lsizeof(timeout)); 2 S* f5 W3 y7 I; Y; ?
if(bread == SOCKET_ERROR) { ( s2 X( J4 @! U( V$ t
fprintf(stderr,"failed to set send timeout: %d\n",WSAGetLastError()); + K/ o8 w1 c: r" y9 r
ExitProcess(STATUS_FAILED);
1 h6 A1 u- Y2 g! p0 p} 2 j' m. h2 p- _2 `* M; V; M
memset(&dest,0,sizeof(dest)); % ?% H Q7 G9 F1 r
1 p7 x2 Z o5 w, w" E
hp = gethostbyname(argv[1]); - M: s4 k6 b2 Q1 p% ?
- ], n* N7 p+ M- Hif (!hp){
1 P8 E& U. y3 E& Uaddr = inet_addr(argv[1]); . Z0 }4 l! E3 e* _; L( x2 O+ u+ n
} ' H; j. P& c9 K+ V: {! o0 H& X8 B6 p
if ((!hp) && (addr == INADDR_NONE) ) { 0 b* D/ N4 w) [8 v! L
fprintf(stderr,"Unable to resolve %s\n",argv[1]);
3 x7 X- O1 [- \1 o7 n$ R3 z$ aExitProcess(STATUS_FAILED); 7 U) I- U1 s) U9 S. V @
} ( C0 g& V3 K& o' O
. g0 S+ D0 t' I8 I- T) Yif (hp != NULL)
$ h8 W) G! _- x( { Nmemcpy(&(dest.sin_addr),hp->h_addr,hp->h_length);
& s' \6 S2 l8 W' S) |& gelse * @7 k. t, y; D: t! [6 \: U
dest.sin_addr.s_addr = addr; " f0 k( l. c% \
8 {1 g2 H8 i1 L
if (hp) ( A1 ^1 R0 k% u6 j4 F5 U
dest.sin_family = hp->h_addrtype;
# A9 U. }+ f1 N7 `& x% g( N6 h; ^else
5 |1 e: \6 _% V- r+ g4 c2 |dest.sin_family = AF_INET;
8 x3 R3 W- x% @+ l0 y" T$ W) r# g9 f8 l. O
dest_ip = inet_ntoa(dest.sin_addr);
6 o2 [# J* y6 F+ e4 ~, Y" ]; g* x+ Y; Y5 }1 x
if (argc >2) { # l0 s, q: D8 z2 z* |
datasize = atoi(argv[2]); 1 O0 v, M( ]: j/ O5 q$ j- k: {5 y
if (datasize == 0)
3 ?+ [$ Y. [% p) i6 z. H+ t' gdatasize = DEF_PACKET_SIZE; 7 y9 a' _& Y7 z' V8 @( m
& b9 y$ A% i! ?4 w n4 V8 [- E
}
8 ]4 A: x4 L: G' \else
' `+ W2 m% X, p5 R( \% idatasize = DEF_PACKET_SIZE; . y0 P( L; v3 x7 ?) p
* `5 N$ v# Z R0 R# n! \+ C8 T( i
datasize += sizeof(IcmpHeader);
! P! Q1 a8 ^( s; r, N" q. Y N
! M7 h# F0 @8 f$ G5 q! @6 `& aicmp_data = xmalloc(MAX_PACKET);
# T3 f) @# }+ n0 R2 \; y# srecvbuf = xmalloc(MAX_PACKET); $ G5 ?9 X) G0 _, j N$ O: T+ g
6 W& n+ l. D8 \& Mif (!icmp_data) { " Y' `6 X/ x3 [) W. c
fprintf(stderr,"HeapAlloc failed %d\n",GetLastError());
8 Y5 X& A6 M7 W3 _. TExitProcess(STATUS_FAILED);
: s; s M7 D4 F" S$ y# A. B}8 d+ B+ A, H: m) m6 F
memset(icmp_data,0,MAX_PACKET); 0 U0 g+ C4 [& {6 M8 o% P1 C$ E
fill_icmp_data(icmp_data,datasize);
; X8 a; d# f) P! }! }* _3 G3 Z; U5 u; D g
while(1) {
0 f3 r/ O- q2 [& iint bwrote;
7 `; b& i! S& s9 ^; d2 g$ y
8 R! c7 f/ G* \; @/ Y& @$ I3 ^((IcmpHeader*)icmp_data)->i_cksum = 0; 8 ^, Y3 N% [( c5 z: ?
((IcmpHeader*)icmp_data)->timestamp = GetTickCount(); + p( _: l* A; `6 o- Z
" ]( o# |" D( E. n) w- U# P1 }
((IcmpHeader*)icmp_data)->i_seq = seq_no++; 6 }+ }1 ?9 X. p
((IcmpHeader*)icmp_data)->i_cksum = checksum((USHORT*)icmp_data,
6 I& v% r0 j, q) X h) d2 M t. |( ~, Jdatasize); & a9 h) H( k U) ] A
$ q% d4 a1 X% G9 p1 n/ {7 n0 Hbwrote = sendto(sockRaw,icmp_data,datasize,0,(struct sockaddr*)&dest,
1 b; Q7 V' D- l' y4 A hsizeof(dest));
' J" @1 |; m5 c( _- Q! Hif (bwrote == SOCKET_ERROR){ ! ~. \: K) R+ Q8 U
if (WSAGetLastError() == WSAETIMEDOUT) {
! l; t8 k u0 C. Cprintf("timed out\n");
- d1 L: T- i# v6 N) \" Rcontinue; 2 @5 u$ d" v9 A W2 G F- f
} . i, G: n9 u* @
fprintf(stderr,"sendto failed: %d\n",WSAGetLastError()); 8 w$ o& J$ o; j2 Q
ExitProcess(STATUS_FAILED);
( Z; Y2 F; b, ^! \4 f' `, J}
* K( H8 ?: F) N) ]; m, o$ H7 }if (bwrote < datasize ) {
( }$ G* k2 L8 `! e7 {8 Vfprintf(stdout,"Wrote %d bytes\n",bwrote);
2 ]0 M* X+ ?) {8 J- S& P2 g6 c}
: N' w' W5 c$ `: M' s0 `bread = recvfrom(sockRaw,recvbuf,MAX_PACKET,0,(struct sockaddr*)&from, " a- ^+ u' H6 F) T# |6 _2 R
&fromlen);
4 J* m" y F4 ?) T3 Bif (bread == SOCKET_ERROR){
! e8 {4 ] A& l# f* @3 z% N2 Oif (WSAGetLastError() == WSAETIMEDOUT) { ' v7 s8 e( p* k, Y& D
printf("timed out\n");
6 @. e( L; f4 mcontinue;
$ x$ t! C6 B2 P( K( [$ j1 @} 1 d0 N* W" X) D+ V' |1 m
fprintf(stderr,"recvfrom failed: %d\n",WSAGetLastError());
! Q& P: y( H, c$ Y! j+ o* I/ A+ a5 uExitProcess(STATUS_FAILED);
" y" [% r/ I+ C, ^ t& |6 S& q}
- b7 ]/ ~4 z+ A5 Y' l" |+ pdecode_resp(recvbuf,bread,&from);
0 o* C6 ^6 ~* v1 V, pSleep(1000);
" h/ K; v) ?3 p' h# f- P; O& G0 ]. M, C3 \/ \" G3 u1 `
}
$ Y; `7 U* [: N- Preturn 0;
% z( |! i8 W$ D Z( ^# o& i5 F3 k
1 L& [5 k0 h7 a S& M: t! P}
4 \4 U1 Q' w7 d I" H. V5 u/*
7 C, [3 z5 X' i" a) W( TThe response is an IP packet. We must decode the IP header to locate 9 w, \4 O/ }! Y1 A
the ICMP data % g) m E+ o7 U" o& L* a! r
*/
: X/ U P+ }$ N& |* Cvoid decode_resp(char *buf, int bytes,struct sockaddr_in *from) {
3 P( J; z6 @/ u1 |. f( O3 p$ c
" u/ A& A- A* V& k/ f j) RIpHeader *iphdr;
, v( K$ M( z8 ZIcmpHeader *icmphdr;
; l) @1 x0 U8 h" l! Z) I) b) k# Uunsigned short iphdrlen;
5 s; `2 I3 T$ Q% c2 P$ L. Y* T1 \' R/ E l+ w9 q0 |
iphdr = (IpHeader *)buf;
1 E* d+ u# y7 b
" u( |3 \" X4 N- B- L1 Qiphdrlen = iphdr->h_len * 4 ; // number of 32-bit words *4 = bytes 1 U' ^6 q+ w L% T, Z
$ K' c! t# ~' H0 J! r; M c! Sif (bytes < iphdrlen + ICMP_MIN) {
5 O5 B* K0 }& o) t- ~printf("Too few bytes from %s\n",inet_ntoa(from->sin_addr));
6 `* x4 |$ I; i% d. k, G9 r6 M4 _7 I' a} ) p8 y3 ~0 a- h) L
" J* B3 Z3 ^% ^% q
icmphdr = (IcmpHeader*)(buf + iphdrlen);
) t" S- ~* u5 \% a% }! B/ p/ Z4 a2 h) h: _+ ~6 L" G
if (icmphdr->i_type != ICMP_ECHOREPLY) { ; ^, X, d* P, d, u
fprintf(stderr,"non-echo type %d recvd\n",icmphdr->i_type); / M: x( Q# G2 z% G
return; " f% n" x; t% R
}
0 F; u1 r9 i Yif (icmphdr->i_id != (USHORT)GetCurrentProcessId()) {
r p [4 s( F, D8 K, lfprintf(stderr,"someone else's packet!\n");
; v' R, ?* [' O [return ; - i8 N0 u1 C/ i" S
}
" J$ U0 M7 m @printf("%d bytes from %s:",bytes, inet_ntoa(from->sin_addr)); . e# l1 D% S P( ?1 ]
printf(" icmp_seq = %d. ",icmphdr->i_seq); 6 M$ y$ h, d' [3 n4 u7 Q# [
printf(" time: %d ms ",GetTickCount()-icmphdr->timestamp);
9 ^+ E# d- u. i, O) ^& y, ~- uprintf("\n");
) {: ^" K! p! f, w: q2 c) E& j. D7 Z( C/ d
} & p% Q3 G1 k6 r, g+ @! ]
4 O1 L+ E! o7 _7 }: d+ _) t6 I7 r% I6 Z4 d
USHORT checksum(USHORT *buffer, int size) { 4 W2 h& L9 v0 k0 a' I; w
4 Y+ L/ T9 `2 m2 E. o6 C. \0 A
unsigned long cksum=0;
' n' t8 E; n9 d) N3 w- N* M: e8 m4 N. e& [
while(size >1) {
9 y0 o8 a+ V1 l9 @1 gcksum+=*buffer++; 3 L3 x% P5 N1 Z8 _0 q
size -=sizeof(USHORT); 3 j2 y/ [/ _; h6 i
} " A0 Q7 }. w3 [$ c: ]
8 E9 |4 c5 s% uif(size ) { ' d! [0 C* b3 a/ ^+ G; f+ @- q8 U
cksum += *(UCHAR*)buffer; 5 k) _: | c6 [$ M
}
! e% Q6 H& q7 U1 s
K! J2 E# |) C: Ccksum = (cksum >> 16) + (cksum & 0xffff); 2 i# p# w! @: t) `+ \' H" N* X3 W5 p: z
cksum += (cksum >>16);
& i4 R/ P3 J9 S9 Ireturn (USHORT)(~cksum);
9 U3 f/ ^2 w ]2 m- A}
4 A: I' V% j: F/*
/ U# ]- m5 s' X, \0 tHelper function to fill in various stuff in our ICMP request.
7 U7 |+ c! \5 h*/ ; u5 N) s ?1 t, t& V2 E
void fill_icmp_data(char * icmp_data, int datasize){ + D4 Z+ o( Y7 X# A
. d' \& ? M! q
IcmpHeader *icmp_hdr; * y7 F. Z8 \+ _; n5 S
char *datapart; * j. A) P0 R+ s; O1 b
( t2 i) q/ ^4 H: j
icmp_hdr = (IcmpHeader*)icmp_data; 0 S6 |0 z" j) P. y$ n
2 g3 R) }/ y' T; R" C
icmp_hdr->i_type = ICMP_ECHO;
. R6 O& x, N7 l" ^+ ^icmp_hdr->i_code = 0;
; @! E. ~" T: Z6 a! Cicmp_hdr->i_id = (USHORT)GetCurrentProcessId();
/ S l! Y& O1 r* V# u. I* A/ Licmp_hdr->i_cksum = 0; ) j% o* u- b6 l6 ?. |1 V. P8 Y
icmp_hdr->i_seq = 0; - `3 j* j/ |; Z9 h' ^
% `- _; ]8 k& l7 s+ Wdatapart = icmp_data + sizeof(IcmpHeader);
! G$ ?: X8 a1 ?0 V& K+ p& K" ^// " k1 f) D/ r; }1 ^8 a1 K
// Place some junk in the buffer. 3 N E3 r" y7 e) o
//
; V% M8 D$ I4 X- e9 B3 B+ y7 D( kmemset(datapart,'E', datasize - sizeof(IcmpHeader));
6 p! T5 M% t% `3 O( `( f1 u8 y8 X9 q8 K- J8 Z5 r" ?3 Z8 l
} |
|