|
******************************************************************************\ % D6 Z) L7 h& R* O4 M. j# o
* ping.c - Simple ping utility using SOCK_RAW , L+ C, Q/ |5 \' l, o/ A
* - P' a& X! _5 f8 Y6 u7 |' a
* This is a part of the Microsoft Source Code Samples.
5 `0 A: P E, O7 W1 ?4 X* Copyright 1996-1997 Microsoft Corporation.
+ o7 U0 {6 _# w6 `3 W9 c( V* m* All rights reserved. $ c R3 R1 Q; p, X! ?1 b9 U& m
* This source code is only intended as a supplement to 1 K; ~1 W4 t- U- m# {
* Microsoft Development Tools and/or WinHelp documentation. 4 U( E" ?9 i0 `' J
* See these sources for detailed information regarding the / \5 d( e' _1 g# U8 _- o
* Microsoft samples programs. / U# j' W, q1 ]4 t+ }9 D) ^
\******************************************************************************/
' B j0 t+ l) C1 O% n/ I& z
3 I: x# W7 s0 P; [1 H#pragma pack(4) ( {- m, H1 [( o4 E
+ Y9 W* t- j* j8 V, q6 |: W#define WIN32_LEAN_AND_MEAN
+ {0 d% `5 M3 T; t#include + A6 K' a; z9 C0 a/ c+ `5 V
#include $ v i+ e& I4 n+ V% u# K# b- ~: V
#include
, ?$ y! W. q4 g/ w1 s* z/ K
4 u( y5 H8 m4 @$ o#define ICMP_ECHO 8
8 k0 b; k9 R8 @; `% u3 E4 r5 ~ Y#define ICMP_ECHOREPLY 0
: D$ D; V; f) \8 t! F9 d- Q6 [ }3 J. i4 ^7 C1 `' i: H1 W" v
#define ICMP_MIN 8 // minimum 8 byte icmp packet (just header)
4 V# h5 W( M1 ?- `1 Y; ]: y
1 K6 e( N% N4 G$ B; i$ L/* The IP header */
- e5 J4 o3 `/ o% p% A" N: n& Ytypedef struct iphdr { ! A+ ^1 l7 A9 T5 L9 H: k) g
unsigned int h_len:4; // length of the header
2 m* |- k2 ? C9 L: hunsigned int version:4; // Version of IP
0 |9 c+ b1 Y, e/ _+ junsigned char tos; // Type of service
# N2 O2 j3 ]$ q7 Tunsigned short total_len; // total length of the packet
% |. Q) O3 l" X! G( Z1 G5 qunsigned short ident; // unique identifier
2 @# x$ f: ^8 d$ hunsigned short frag_and_flags; // flags
/ L2 j3 A( K& @; a2 M+ L, Q. funsigned char ttl;
+ B n# @) U: E# b0 ~- Q3 ~1 }/ Tunsigned char proto; // protocol (TCP, UDP etc) 5 Z1 x' O4 y* S# J
unsigned short checksum; // IP checksum 8 ~# @4 C. @5 c& N
3 z& c" l1 C% Q% _. N; X
unsigned int sourceIP; " ~& ~* A" F5 ]; r0 S
unsigned int destIP; & j- `0 N v, E) w2 n
# D, F- Y+ |& m4 ?. @
}IpHeader; 2 b6 c( P3 Y3 b6 ]
7 Z4 k& y) s1 }& D6 ~
// ! a6 V2 O" [, H3 a' }
// ICMP header
4 o0 g( J+ z5 V// 4 V6 C1 A' K, b. u7 I
typedef struct _ihdr {
5 D' o2 Y3 _& u5 G9 N: IBYTE i_type; 8 n i- V* c4 }3 w
BYTE i_code; /* type sub code */ ; X) h+ ^4 N9 L5 C! q. n
USHORT i_cksum;
* ?" A( C; y; C2 ?. gUSHORT i_id;
1 P8 t9 c0 y' b+ d1 J+ o+ f% @! BUSHORT i_seq; # u! _% R# k5 L3 D* a% G
/* This is not the std header, but we reserve space for time */ 1 D5 I" [* ~" P7 ?) b
ULONG timestamp; . D, @* |, d% {8 L; i' a* M# J
}IcmpHeader; : e4 |+ s5 A# C% w- u
w. l9 g9 i8 \1 }- c8 f. C#define STATUS_FAILED 0xFFFF
# ]$ k8 L/ ~) B#define DEF_PACKET_SIZE 32 % s+ H: M: P8 e2 Z8 f: i
#define MAX_PACKET 1024
9 c: a% u$ z" Z/ z5 Q. |7 T- _: v& g2 Y$ w
#define xmalloc(s) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(s)) % _" K X4 Q. m
#define xfree(p) HeapFree (GetProcessHeap(),0,(p))
7 R$ X) K. Q, z1 m9 [$ F* b; A) x' O
, c& j+ K/ I9 zvoid fill_icmp_data(char *, int);
{# `0 G7 w' k5 w- B$ o1 I& wUSHORT checksum(USHORT *, int); 0 |; D, x/ F* ^5 m. M- g
void decode_resp(char *,int ,struct sockaddr_in *); ( Y/ G# l- L' |( w9 j# r; \
+ D0 b5 ]- S+ e+ g4 K4 E; g
void Usage(char *progname){ ; ]- e4 A0 O& v F
, c. x' U1 T. h5 X
fprintf(stderr,"Usage:\n"); 7 t. b& |: E- K. g6 z
fprintf(stderr,"%s [data_size]\n",progname);
1 e3 m" v1 A3 b6 f) h0 X. }, {fprintf(stderr,"datasize can be up to 1Kb\n"); $ w/ g5 k0 T; u; a! q9 j
ExitProcess(STATUS_FAILED);
( `! E) _) k! i. y/ m1 s* Z" Y6 |9 ?) O
}
! x4 b% @/ M& G. }int main(int argc, char **argv){
) Z+ @8 K# w: a* H0 L% l. u# [" Y2 g" D) z9 o" |) r; Z! n
WSADATA wsaData;
3 Z7 m4 c! K% R. I$ eSOCKET sockRaw; : S; J2 [" V8 ]4 y
struct sockaddr_in dest,from;
9 K( X8 Q. e+ M8 @ H+ N0 Z. X6 Dstruct hostent * hp; / W+ ^. I4 ]$ y- e$ C$ b
int bread,datasize;
/ Z8 T/ E. A; C& U4 z- q9 `int fromlen = sizeof(from);
! H3 c& u! d4 z7 d- @int timeout = 1000; e- D l% a! ]$ d7 y4 l, Q3 V5 d, Q
char *dest_ip;
; h; M8 i( ^+ i- Ochar *icmp_data;
- C% e& P: f, _4 e1 ~char *recvbuf; & `3 P4 a8 I+ z) O1 {
unsigned int addr=0;
+ z( V% ?2 s8 IUSHORT seq_no = 0; % o9 z, G( J2 r z( }
% Z# ]! Q0 G8 [( w+ |% D
if (WSAStartup(MAKEWORD(2,1),&wsaData) != 0){ 8 F( H# C: Y# S) X
fprintf(stderr,"WSAStartup failed: %d\n",GetLastError());
$ L j: |* d4 O2 ^3 lExitProcess(STATUS_FAILED);
9 s8 X. v4 Y# X8 k7 A) A% y} - G4 W1 S! g) g; b
) a+ e t. x0 _9 I4 y% {, h8 eif (argc <2 ) { ( ~, C- |/ {- V' G4 z% W; y
Usage(argv[0]); + R6 i& s5 ~6 u/ l W6 ?: c7 X D
}
4 G4 M; S- Y* C! f4 w* E8 UsockRaw = WSASocket (AF_INET,
2 @/ }: p8 |0 T6 ^$ x" s0 u0 ?, QSOCK_RAW,
5 b) Q6 D6 C" EIPPROTO_ICMP, 9 Y& q B! |3 ^- ]8 N+ \9 s
NULL, 0,0);
3 N$ P% f; C8 H6 J; E, n( H9 U
+ F% T1 N: [- j7 [) B1 oif (sockRaw == INVALID_SOCKET) {
' W# c7 K B- hfprintf(stderr,"WSASocket() failed: %d\n",WSAGetLastError()); ! a3 g0 c) G# {. G& k. P7 N8 [; l
ExitProcess(STATUS_FAILED); , G5 N8 g- u2 k `5 J! ^) M: A
}
* B7 Y5 E! K/ t+ vbread = setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout, * H. p0 ^: X( I: e/ g; j
sizeof(timeout)); & X2 x% V! L0 `# k, F
if(bread == SOCKET_ERROR) { 5 l3 m0 C1 @' `& U
fprintf(stderr,"failed to set recv timeout: %d\n",WSAGetLastError()); 7 B+ B' ] Y4 c+ P' d9 u7 u# J
ExitProcess(STATUS_FAILED); 9 q, U. X6 ?! P4 A, K5 T; }
}
2 _! t9 Z' V4 A) F; f0 D/ W, M1 i, }timeout = 1000; , h1 z- v [, N$ ]: v' I
bread = setsockopt(sockRaw,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout,
; }2 o: q+ k# h- X& ?$ Bsizeof(timeout));
. w1 e7 J! N* a; J6 x+ bif(bread == SOCKET_ERROR) {
" ~: z: Y* H: Y q0 k( ifprintf(stderr,"failed to set send timeout: %d\n",WSAGetLastError()); " Z- N4 v5 r+ F- o
ExitProcess(STATUS_FAILED); ; L; ?" U0 \, C3 G) b7 W
}
7 H, V' z; d4 S: ~0 q9 Jmemset(&dest,0,sizeof(dest));
4 i9 p0 j, ]1 P. P6 m/ ?. }/ ?
2 w/ d8 w! X# w) o. B3 Hhp = gethostbyname(argv[1]); 3 N) Z( Z6 x4 Y" g) C. \/ s
& f9 ]1 }" c0 Q- j7 ]
if (!hp){
& L; C5 e o% y& ]8 L- U' R, }- k2 Saddr = inet_addr(argv[1]); 8 ] h" C& S1 r2 W
} ! q/ m2 }3 y2 _
if ((!hp) && (addr == INADDR_NONE) ) {
: I, u5 X0 I6 ^* w/ dfprintf(stderr,"Unable to resolve %s\n",argv[1]);
" I) ]5 j$ `1 P: D" u5 F& n: RExitProcess(STATUS_FAILED);
* T3 h1 V, y- \! g( Y} ' ~, [' S; ?' e# u
I; r- c# n8 g: b- x
if (hp != NULL) 0 u! a1 [$ z! w' ~* R# R
memcpy(&(dest.sin_addr),hp->h_addr,hp->h_length); ; {9 B8 V8 F" u& Z
else
- l+ i- R, x6 H) ?. i: X) |dest.sin_addr.s_addr = addr;
" N7 w, I) K! `, ]
; H, k/ L- f4 c# c0 u# u( dif (hp) 5 {; O# {- V$ w7 J
dest.sin_family = hp->h_addrtype;
# x" }3 c# e/ T6 j. selse
4 V. g6 U* f$ v# Q$ {dest.sin_family = AF_INET;
: v! o: F J' A0 X; g! @
$ O. M: }# l1 D1 C9 sdest_ip = inet_ntoa(dest.sin_addr); ) z/ p6 a* L; _6 n- d* a- n
, }9 f+ N" g) ]- ]if (argc >2) { : G* h$ O g: K; O
datasize = atoi(argv[2]); * e) V, K% I* K1 x- x
if (datasize == 0)
, m6 F0 D) J1 m. c' H* gdatasize = DEF_PACKET_SIZE;
( H' d# R! `% a9 b i/ J9 C4 I0 r. m8 ?% T( K" p5 ^7 g, `7 l) S
}
+ B* ^4 J* y& n- q" T; ^else
+ B( p% f2 N2 M, \/ q) Z, u0 U& bdatasize = DEF_PACKET_SIZE;
9 _+ O6 |* i( S w/ l4 I6 i- [
4 F% _6 j. N/ z2 I" Adatasize += sizeof(IcmpHeader); ) K- X% }" Q6 c1 y/ q. N
) K c' [- l, A# P, x! Sicmp_data = xmalloc(MAX_PACKET); 3 G; q; \; k7 U/ K. L7 V ?0 h
recvbuf = xmalloc(MAX_PACKET); ; ~6 V3 E7 ]% A/ ]0 g# v5 ]
2 |$ B& i3 K Q* k1 L4 }$ \if (!icmp_data) {
; M n& Y- p0 R4 T$ x' O4 B' S mfprintf(stderr,"HeapAlloc failed %d\n",GetLastError()); ) [% W" ~5 n. L4 E+ ^" r
ExitProcess(STATUS_FAILED);
( C+ H5 v* n4 U}2 t9 i1 Q4 O8 {" D% C# y1 s# [
memset(icmp_data,0,MAX_PACKET);
9 G4 @" C, A$ y7 i/ }9 D1 bfill_icmp_data(icmp_data,datasize);
8 D* `* [* y6 @
/ [/ g8 S/ d& B% i8 h" rwhile(1) { / _. s+ t% K: I; Z
int bwrote; ' _8 [' }& U i) l* d/ j8 Q
/ G1 e! N P$ s5 G0 L((IcmpHeader*)icmp_data)->i_cksum = 0;
; d% U6 s- w/ n2 \((IcmpHeader*)icmp_data)->timestamp = GetTickCount(); ' q+ k# ]; `: [# _7 [
! P4 `2 z, C0 P/ H1 Y F((IcmpHeader*)icmp_data)->i_seq = seq_no++;
+ b* ^* D1 S) `( T2 Q6 Y9 b: |((IcmpHeader*)icmp_data)->i_cksum = checksum((USHORT*)icmp_data,
% o `$ K) @) vdatasize); $ B* q$ ]" e$ c
- R* Y' x* W" j2 {0 Obwrote = sendto(sockRaw,icmp_data,datasize,0,(struct sockaddr*)&dest, 6 k0 U/ p8 V7 a6 d) P! T- r! N; k+ W
sizeof(dest));
( ` l: |6 M; Qif (bwrote == SOCKET_ERROR){ 1 p6 L+ N0 |+ L, J' h$ g! w9 I
if (WSAGetLastError() == WSAETIMEDOUT) {
$ }- w* e1 O; ^$ |3 q8 |printf("timed out\n"); 6 a& H& h1 `7 ^* O! G+ y
continue;
$ F4 @" r6 r9 Q2 P}
4 ~) E' x4 R! B, l/ n+ Y8 m7 wfprintf(stderr,"sendto failed: %d\n",WSAGetLastError());
- `( j) E0 V: \5 R( JExitProcess(STATUS_FAILED);
: C$ s) `% S. e' Y# F T; r} 4 n4 b* ^5 v) \# k8 g
if (bwrote < datasize ) {
9 z3 `8 p5 n: j) V4 ~* Y( Wfprintf(stdout,"Wrote %d bytes\n",bwrote);
( Q W/ s9 ^" c: G} ; |! u; u3 h# d* s6 c6 {
bread = recvfrom(sockRaw,recvbuf,MAX_PACKET,0,(struct sockaddr*)&from, ( F& B8 E9 v: g6 a$ x, o
&fromlen); N6 A9 Z! H/ Y9 }$ q* Q4 A% H
if (bread == SOCKET_ERROR){
. N0 X2 ~6 ?8 jif (WSAGetLastError() == WSAETIMEDOUT) { 1 ?8 M; y7 b' M$ W
printf("timed out\n"); 2 n5 d& @" J, C4 |
continue;
0 k" t0 R! W+ F M* o9 M7 T+ s} 3 n. P/ { Q( C0 X6 W9 T9 ?: O
fprintf(stderr,"recvfrom failed: %d\n",WSAGetLastError()); 1 u' }5 S) t& r9 f# U
ExitProcess(STATUS_FAILED); 7 Z3 h" @/ a# A+ k
}
5 ~7 x6 k; R6 R. A+ N& t5 d; x2 |" Rdecode_resp(recvbuf,bread,&from); ! g6 P( P5 t/ _
Sleep(1000);
$ V- \5 t! j: w$ I# f; n2 q
5 I0 I$ ]. D% _ j4 j2 k}
4 A5 {% ?! C1 J/ breturn 0;
/ n# J- ^' T) q. X
8 ?/ s7 \0 {3 [8 ]} / }8 o/ k+ \4 S0 s) e! z3 Q# a* ~" ~
/* & F8 j* t R" r- q" D
The response is an IP packet. We must decode the IP header to locate
, o8 p* ?& D. e& G" }+ Athe ICMP data
- h9 ?' T; o" s% N% r*/
' [% ?+ l( Q2 {; K3 v0 wvoid decode_resp(char *buf, int bytes,struct sockaddr_in *from) {
j. i( K' X% O+ I# q. B
( z$ T& j+ L& S7 rIpHeader *iphdr;
2 [/ o0 I+ o7 h, z/ D4 Z0 {IcmpHeader *icmphdr;
6 b) b% N& V6 ]6 |8 _2 Funsigned short iphdrlen; 1 w# h2 H# i2 t! s5 B9 F
, U8 D) J' `, Z: j( qiphdr = (IpHeader *)buf;
& i2 D M R6 X5 O+ j" u3 z2 j" H2 o7 }+ G; t
iphdrlen = iphdr->h_len * 4 ; // number of 32-bit words *4 = bytes
/ n+ z% r& z) w8 |+ Y
7 D! f7 k [2 r0 M5 w& s. Vif (bytes < iphdrlen + ICMP_MIN) {
I/ D @7 C$ F. o8 S- nprintf("Too few bytes from %s\n",inet_ntoa(from->sin_addr)); ! H! c- }! J- C+ V, V) @$ O# p$ g
} 6 ~1 G/ {& z8 u/ ]7 F3 R. N/ x
! b7 Z' P4 \/ l
icmphdr = (IcmpHeader*)(buf + iphdrlen);
" H0 N/ ?1 c! }
& f! e A3 H% g0 Q. ?( Yif (icmphdr->i_type != ICMP_ECHOREPLY) { 1 f8 F! g5 A+ Z
fprintf(stderr,"non-echo type %d recvd\n",icmphdr->i_type);
# c5 K0 d. b# r2 }return; 4 w' }! P6 C o3 M' k, l
}
$ i, R! q. Z- z; z! ^, ` ^; Lif (icmphdr->i_id != (USHORT)GetCurrentProcessId()) {
. @# j. s: U3 }) w9 r8 `% k. qfprintf(stderr,"someone else's packet!\n");
# m; e/ a6 m' P* P4 V! R/ zreturn ; . X* q+ v9 q5 p3 _) t+ P
} ; [ K5 g P1 N1 d1 f e
printf("%d bytes from %s:",bytes, inet_ntoa(from->sin_addr)); - M; e1 I; C* U) G9 G1 K
printf(" icmp_seq = %d. ",icmphdr->i_seq);
: V% f. ^6 T* y8 R+ hprintf(" time: %d ms ",GetTickCount()-icmphdr->timestamp);
7 t1 D7 D: Y; X/ Z9 Pprintf("\n"); ; v3 [. T U( M2 j
$ T p7 }4 V; m7 Y. K* k
} ( M: b4 w Z! t [4 I" @
+ ^! D1 m" s& r$ Q
1 k. T& H( J1 N. u9 ~6 FUSHORT checksum(USHORT *buffer, int size) { ( D" A5 t! v- G9 ^2 B- s& o
/ ^2 ^) ~3 z3 vunsigned long cksum=0;
% Z4 f8 h. t$ j& |7 n: C U3 u# b% }& H* W! Z" L9 g3 B2 j; R
while(size >1) {
, e& U9 k2 S7 H# C' E; bcksum+=*buffer++;
" A; E2 F& J1 b: E0 z$ hsize -=sizeof(USHORT); $ E4 X0 {0 y [5 r, `. Z r
} ) h9 L, |! J' S4 j6 a6 |; y" W7 m# U
s0 G- E* a6 C' Zif(size ) {
/ J J0 P7 v9 R- T+ v/ S7 w! Hcksum += *(UCHAR*)buffer;
|6 y* ]7 j+ Y C# K* _- L}
+ E q$ h! j9 _
+ X. m; F& r! e$ Bcksum = (cksum >> 16) + (cksum & 0xffff);
H1 Q( U$ N" l8 ~- }. \cksum += (cksum >>16); % ~2 n3 q* P+ \, K% I7 D
return (USHORT)(~cksum); / G/ ?* x: M. r( E2 x% }2 R4 Q
} 7 T; S8 r7 B4 s0 e: {" M
/*
% `0 p' y( g& \( RHelper function to fill in various stuff in our ICMP request.
1 B2 P, K+ F# r, Q$ `( A: A*/
/ e" C! r& ~! M0 }5 ivoid fill_icmp_data(char * icmp_data, int datasize){
& w) O, R. @; H
1 O3 c4 @1 r6 Y' S5 H% e: c1 v+ p" MIcmpHeader *icmp_hdr;
1 ^! _# w# |9 ?! M8 X0 c/ F+ {- Fchar *datapart;
) A8 ?6 Z9 L" t- x1 X8 z7 b
1 K4 s1 [+ R& {5 [icmp_hdr = (IcmpHeader*)icmp_data; $ R! H. u t1 g" w, o% X& M9 C
, n5 U0 D. D( ?, Qicmp_hdr->i_type = ICMP_ECHO; $ |) `+ }7 u! E0 S6 C
icmp_hdr->i_code = 0; 7 F6 M. x! [( j! v6 T0 f8 R
icmp_hdr->i_id = (USHORT)GetCurrentProcessId();
/ {6 N+ D5 W" X* Aicmp_hdr->i_cksum = 0;
2 Q/ F& N3 i" x o$ X# |, ticmp_hdr->i_seq = 0; " g" ]" {/ T2 R
& U6 W; O( G- x$ F; u" gdatapart = icmp_data + sizeof(IcmpHeader);
w7 _0 x6 l7 Y0 u5 I// 3 s9 R( Z P" N, j( { I& F
// Place some junk in the buffer.
1 \: r! c; U$ {, g/ b// ; e6 ^% f. c# R, M
memset(datapart,'E', datasize - sizeof(IcmpHeader)); 5 c& h9 v* @% }% M
$ O; p- _* Z/ G |" F, k9 Z} |
|