|
|
******************************************************************************\ 7 @8 N9 e$ Y3 j1 Q V9 i3 p
* ping.c - Simple ping utility using SOCK_RAW + r2 C1 a3 G1 P: a, M
* : @, D2 o$ ~0 I, F+ P1 w# E% m' S
* This is a part of the Microsoft Source Code Samples.
$ T+ J. ^6 V2 [. j/ W' e6 z% d* Copyright 1996-1997 Microsoft Corporation. p' a! \! @2 {9 }
* All rights reserved.
' y0 o% C5 r" ^* This source code is only intended as a supplement to
4 \7 l# H. l, t5 c* Microsoft Development Tools and/or WinHelp documentation.
9 P4 L* x* j/ q! O# U* See these sources for detailed information regarding the : u) G5 l) B# |0 v" r1 E: b; S6 ~
* Microsoft samples programs. . B: S5 V0 B2 k+ r1 o; `: R
\******************************************************************************/ + s* _" D: I5 l# X" {+ U1 N# C3 j9 r: X
% H) d% J7 k/ f4 W7 Z7 @7 j
#pragma pack(4) 9 a* u" b$ Z/ d: I/ R- O% S9 ?; p
R# y, U4 W/ M9 d. g#define WIN32_LEAN_AND_MEAN
6 }0 o( j0 G: q2 q# G4 w#include
: Y) b' |0 t% u+ `2 ^ c#include - g: K# _ g+ [" i" \
#include
' p& ]& \! Z" z. _* j) l& n9 a& [0 p$ D5 v$ @: b' k& C
#define ICMP_ECHO 8
- p4 _" c4 T _- y5 o) K#define ICMP_ECHOREPLY 0 + J0 i' ?6 {6 V
2 `- l% y4 c8 h; \
#define ICMP_MIN 8 // minimum 8 byte icmp packet (just header) # v; _5 C+ K% B' O4 X
0 U; @! D# L6 W1 x6 S
/* The IP header */
5 @2 a1 w0 Q% stypedef struct iphdr { * }& }, f Z1 M; C( V
unsigned int h_len:4; // length of the header
v, t5 C) d5 I, C: t, eunsigned int version:4; // Version of IP
6 w% X0 ^" U3 |6 f8 _% A4 nunsigned char tos; // Type of service
! Z: _! j- r6 m/ u. Nunsigned short total_len; // total length of the packet
6 { A. {- T" w& D9 [8 E/ Vunsigned short ident; // unique identifier ( H( x0 D) _1 Y9 v8 P- N% C' S6 f# j
unsigned short frag_and_flags; // flags x( V# q3 [. }3 F% d
unsigned char ttl;
. J( R# @. S2 l+ S; x Junsigned char proto; // protocol (TCP, UDP etc) ! _" I5 S; P5 u+ a2 L$ h3 n# q8 p
unsigned short checksum; // IP checksum % [9 T, M7 [" _- ]' X0 s* D
) M0 q$ F1 X" B2 a: a! \
unsigned int sourceIP; 7 ~) w- F3 c* [! M8 O# Z& V
unsigned int destIP;
, o! p+ `, ]4 \9 b# x, i$ m2 [
/ l! q/ X7 L+ `% S% F}IpHeader;
1 V& w* s. I) r4 ^0 U- Q3 b! Y% E
. o" l# k0 Z1 x$ M0 \1 H6 B//
# P0 c- @# [6 D5 |// ICMP header 2 g; ?- s: c* ]( i5 u5 |' U
// : j, d0 c* a9 y t5 {. ^' F2 ^
typedef struct _ihdr { * r6 y5 Q2 X: Z0 L" x
BYTE i_type;
$ x3 ~$ F7 K1 I( `7 [6 {BYTE i_code; /* type sub code */
, C) G! Z8 _; H o- N- z dUSHORT i_cksum; ! t5 y6 {/ `& Q5 D$ v$ \+ l
USHORT i_id; + N* `& @' j0 k* D3 Y4 c
USHORT i_seq; . a9 A2 R/ I$ D- c. Y
/* This is not the std header, but we reserve space for time */ . l+ E" F6 J" N+ v! D
ULONG timestamp;
5 n6 V4 g* C( @& }5 F+ g' Q& G}IcmpHeader; # g8 w& N: q! J% L5 h" ]" x8 h7 _
* H) [6 H; s! D; d- z! y#define STATUS_FAILED 0xFFFF 2 L" C9 r+ }$ {
#define DEF_PACKET_SIZE 32 * x" V& | G8 S6 U
#define MAX_PACKET 1024 ; y9 |" i4 E+ f' a8 R( X: @/ }
& e; V! U! w$ k. [% _ ], i- ]
#define xmalloc(s) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(s)) ' U3 B `$ a, g$ _7 t Z6 }
#define xfree(p) HeapFree (GetProcessHeap(),0,(p)) % i! x6 f/ u+ c& w# ]; s3 d
* K M# l! _$ c6 W3 cvoid fill_icmp_data(char *, int); , V, S" S! ]7 Y, h; y4 G6 ^
USHORT checksum(USHORT *, int);
; h2 e: L$ r& X( t8 `void decode_resp(char *,int ,struct sockaddr_in *); & q W# v, Z, H* `
$ \8 |: n3 z) d3 h+ X
void Usage(char *progname){
* r2 L: ?* s$ x3 { e6 t
& g4 w @( b2 u, W& afprintf(stderr,"Usage:\n"); # w7 [" p; t& c4 f
fprintf(stderr,"%s [data_size]\n",progname);
. B" s/ n+ I9 _ k4 W' ?fprintf(stderr,"datasize can be up to 1Kb\n"); ( a7 Z7 g: r* b+ `* o
ExitProcess(STATUS_FAILED); : ]- q0 ~: B$ U6 N: o
( c: x# @/ e( X7 F2 {2 L} & F! k, M: @/ k
int main(int argc, char **argv){
8 _$ C3 y" j. q* E6 @. B# I5 W# u+ R# x$ O
WSADATA wsaData; 6 m# ?( T. ~; a
SOCKET sockRaw;
2 f" ^ }/ x: Z7 J: Istruct sockaddr_in dest,from; + {: S3 a, g) y, y% W8 V# |* F1 ?+ F
struct hostent * hp;
- N$ l) i; K# B( O e6 n3 Xint bread,datasize; : Q: N8 q* w, c7 k
int fromlen = sizeof(from);
# X" G( ?: N/ g. l8 x+ J7 l+ Kint timeout = 1000; + h- s/ ]$ q! _
char *dest_ip; : x3 G- T: ?( c8 ?
char *icmp_data;
3 ~1 {0 F/ x: z" uchar *recvbuf; * E1 ?. i. O+ d. y
unsigned int addr=0;
, g6 K, Y7 e1 j7 t" t/ vUSHORT seq_no = 0;
/ G7 s, T8 A8 G* y7 ~2 ^; ?! R' n; q
if (WSAStartup(MAKEWORD(2,1),&wsaData) != 0){ , y1 G& \2 V+ H9 h9 u
fprintf(stderr,"WSAStartup failed: %d\n",GetLastError()); + k% W! M9 U/ j4 s% R( C K
ExitProcess(STATUS_FAILED);
. N# }2 I! N/ P! b}
$ `7 T! \; Z# I& p8 \
! F* x- k6 m5 B/ Lif (argc <2 ) { + a6 \% N5 |- ]5 s/ e* y* W Q
Usage(argv[0]);
" z r5 x( S& }, D3 E7 W9 r} , w5 F6 N, T2 Q0 ~* q
sockRaw = WSASocket (AF_INET, # }# P1 M7 G) q* x# X8 u
SOCK_RAW, - ?8 i4 M! |2 Z1 [9 k0 U
IPPROTO_ICMP,
$ b8 \; l, `4 i [) NNULL, 0,0);
6 d9 Q+ w- _- B, g* u t' l; N/ u! \- r# ^
if (sockRaw == INVALID_SOCKET) { . F7 A# j3 A; ?- Q2 k
fprintf(stderr,"WSASocket() failed: %d\n",WSAGetLastError()); & r( C$ I) B5 ^0 a' [
ExitProcess(STATUS_FAILED); ! r- V; f6 s$ v* C* N
}
/ E& v) D! @' K& E" n/ mbread = setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout,
* t) Q5 ?$ g7 L: D& Q$ vsizeof(timeout)); & R+ K" q2 H2 E$ T( K
if(bread == SOCKET_ERROR) {
* z/ V$ Y9 B9 @$ r {% bfprintf(stderr,"failed to set recv timeout: %d\n",WSAGetLastError()); # l. x0 O! u, b' N
ExitProcess(STATUS_FAILED);
6 a6 T( D3 J1 B1 }1 p. U}
8 L1 D* S2 }9 \" b$ Ttimeout = 1000; $ [- \" q2 _: W8 V. j; D" U
bread = setsockopt(sockRaw,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout, . o2 F+ a7 F( C" D
sizeof(timeout));
8 f5 p) z2 f( G% n( M% p( w" hif(bread == SOCKET_ERROR) { / U! D7 r) F9 Y. n3 {: x
fprintf(stderr,"failed to set send timeout: %d\n",WSAGetLastError());
! Y# o! @* l( L& k" X+ }ExitProcess(STATUS_FAILED);
& M8 m" @& A8 C4 ~} ) G0 F! o5 {8 |3 Q2 Y
memset(&dest,0,sizeof(dest)); 2 x. E1 K- z1 X2 w, ^
& `. |5 M$ M" f- Q! b% ~hp = gethostbyname(argv[1]); - P5 o8 B4 U8 [, u
7 [# f* b% u# i$ Cif (!hp){ ! K7 E; [% Q4 h# F( U
addr = inet_addr(argv[1]);
2 B7 Z# s) y4 }. h4 @}
& `0 \7 O/ L' y- _( k/ fif ((!hp) && (addr == INADDR_NONE) ) { 4 J" j- D, k+ k2 A2 J( V
fprintf(stderr,"Unable to resolve %s\n",argv[1]); 8 O0 C+ Z! [8 b9 P
ExitProcess(STATUS_FAILED);
" ^2 _: O/ X. x% D. C9 m$ F' L n} 7 q) B& E! `* s( d" |7 w3 d) g% l
, O3 r; D2 I/ h: Fif (hp != NULL)
- A9 w2 ^( O4 s4 w3 g4 Lmemcpy(&(dest.sin_addr),hp->h_addr,hp->h_length); ) N5 `2 W7 O; O; P4 W
else
0 _6 `! j; n j9 Gdest.sin_addr.s_addr = addr;
. ~/ @3 k% y$ m& Q: q6 J0 n7 J1 W. b4 c/ i: _
if (hp) $ s2 A. l3 v- i) u* Y7 J# U) U
dest.sin_family = hp->h_addrtype; ' y$ ^5 p. Y ]0 i: s" A6 l
else
" N L" C. y( B+ Z" L: ddest.sin_family = AF_INET; 0 ?# s" C8 P1 ~
2 _' I% ^0 n0 e: S, X! j! |+ ^, T3 Mdest_ip = inet_ntoa(dest.sin_addr);
; h3 _1 m* V! z- [4 w) y g! o
/ q* O! p5 |) w7 d' j+ vif (argc >2) {
- k$ Y+ O q* y0 l m9 ndatasize = atoi(argv[2]); . _5 Y! p5 O1 E" r* u
if (datasize == 0) + |! F0 z9 H$ b' t/ m {2 R
datasize = DEF_PACKET_SIZE; - e- U) _- t+ E; z, v( U0 I
2 f0 h8 D! C3 {9 ?% k0 x; `
} : @6 e5 s3 l' {* B0 R2 B
else ( d! q0 o' ], r8 V% I' R6 d- X: F
datasize = DEF_PACKET_SIZE; 4 ~2 e+ i7 c7 w" V: G1 r# ~
1 Y: U, z7 l2 ~! ^; [datasize += sizeof(IcmpHeader); , R: O! H+ r I. t
K, \6 U2 U# C; C5 I { ?6 ?
icmp_data = xmalloc(MAX_PACKET); % n( L9 h1 B; w6 y! ?+ h9 f& I
recvbuf = xmalloc(MAX_PACKET);
8 d ^- ]+ }+ ~3 l+ h1 Y, y7 K% C5 c+ t2 D9 |: I
if (!icmp_data) {
% @7 I! V0 m1 Yfprintf(stderr,"HeapAlloc failed %d\n",GetLastError()); 1 a8 L1 e' T! T* |: F9 I; X
ExitProcess(STATUS_FAILED); 7 }' x- Q. R, I! g
}
9 ^6 C9 E' `0 `. [memset(icmp_data,0,MAX_PACKET);
1 t1 X3 [3 _8 C7 j) Vfill_icmp_data(icmp_data,datasize); & K! `$ ^7 j$ m
5 _1 N' o# z: G; j0 ~, K
while(1) {
% v1 F& s4 d( d. o! i9 J7 [5 p) lint bwrote; ) j6 R% s$ `/ _( m* s2 X
* M) M7 T! J- ^6 f((IcmpHeader*)icmp_data)->i_cksum = 0; , R) m3 w- n+ \- Z, @
((IcmpHeader*)icmp_data)->timestamp = GetTickCount(); + u! |( R$ W' \1 i1 \2 Z
) G3 R5 U/ l/ D) f3 [1 ]
((IcmpHeader*)icmp_data)->i_seq = seq_no++; ( W+ P- \) F) g$ j( j# ~, g: [
((IcmpHeader*)icmp_data)->i_cksum = checksum((USHORT*)icmp_data, ; |- l; I$ z0 o
datasize);
! w9 f% e* ?) f. E) }
2 O: j8 Y+ N; w! d! e+ W. x0 S+ qbwrote = sendto(sockRaw,icmp_data,datasize,0,(struct sockaddr*)&dest,
! e6 k/ y" k9 Z- Y c8 Wsizeof(dest)); 3 y2 o1 }: B1 l5 h
if (bwrote == SOCKET_ERROR){
' z8 i% x m& Q1 l* hif (WSAGetLastError() == WSAETIMEDOUT) { # m# [6 h3 h' k9 U' D
printf("timed out\n");
2 ~" c# [# b& y) `! v6 Z# jcontinue;
0 V7 Z3 i6 i) U+ W, Y; i}
! d$ a/ ?" b, @. [fprintf(stderr,"sendto failed: %d\n",WSAGetLastError()); ( v( t, J; B3 [6 l
ExitProcess(STATUS_FAILED); + f, A3 M6 r+ ]* w' b
} " d4 e0 j; k) z# y6 D$ h
if (bwrote < datasize ) {
2 x7 J% W4 a+ C7 K, G4 W# @- |fprintf(stdout,"Wrote %d bytes\n",bwrote);
6 _' J" p8 d8 F# }' F3 m4 I: i}
# g9 p+ E6 S- Z! ~3 F9 wbread = recvfrom(sockRaw,recvbuf,MAX_PACKET,0,(struct sockaddr*)&from, % Y! Y. e/ \. Z% P0 X; W
&fromlen); ) ?' i9 y* o" ?% Y( V1 }
if (bread == SOCKET_ERROR){
- a* E5 v0 o% `+ gif (WSAGetLastError() == WSAETIMEDOUT) {
4 j4 r! X' U- \! L' f1 q: hprintf("timed out\n"); + `$ w/ u$ j- K) K$ g. ?2 _
continue;
" |- y0 A* ~' W( `' T1 v} 5 x+ J# b! U) q9 Q5 X0 @( c! Y) A9 ?+ y
fprintf(stderr,"recvfrom failed: %d\n",WSAGetLastError());
" O) x. `9 r7 O1 l: zExitProcess(STATUS_FAILED);
& f5 S G: h7 m2 g0 V} : V* }' \. B% N6 D1 j8 A
decode_resp(recvbuf,bread,&from); ) f/ _7 q. l9 F _3 w* U
Sleep(1000); $ Q; h% O" N1 o- Z) _9 _$ c" H
% c% I& k: n% E' w
}
; {& R6 A0 z D! F) i7 ?' preturn 0; - i! U. d X- Y V# u
8 k8 p3 j% R! ~; l5 D$ X B} E' v4 _9 z& `( ~8 Y8 F9 X" E6 B
/* / Q" Z- c) P, D- u( T& h
The response is an IP packet. We must decode the IP header to locate
% k3 Z _( w" y! uthe ICMP data 8 H, s+ }! m! v* v4 c- E
*/ . r& S4 u& r4 B1 v% M
void decode_resp(char *buf, int bytes,struct sockaddr_in *from) { % A& ~7 [" D" t+ x) j+ g
/ [. B; _" F8 ^, Q$ A; `: V
IpHeader *iphdr;
8 Z- Z2 U1 S% a2 H0 M" eIcmpHeader *icmphdr;
4 d% A# P' j2 O7 ]* S+ a& Dunsigned short iphdrlen; 2 ~7 w5 a D9 m
! b, O! q. k! p8 H3 f; U* R
iphdr = (IpHeader *)buf; * u' d, D6 Y" G# ]% a5 H p$ F
3 O7 W9 n+ ]6 o
iphdrlen = iphdr->h_len * 4 ; // number of 32-bit words *4 = bytes
* e/ y* x& {9 @* h, S8 M+ U
! T- [. ?& C6 dif (bytes < iphdrlen + ICMP_MIN) { 0 ^+ _0 p) P8 N/ \; v# `3 s
printf("Too few bytes from %s\n",inet_ntoa(from->sin_addr)); " S N) p; s! }8 ~) f# b" I
}
1 M5 b3 t4 U0 j1 M1 O; C; O2 L$ r6 k6 O: n7 T5 o2 k% r. S
icmphdr = (IcmpHeader*)(buf + iphdrlen);
1 b, F4 ~2 i) |+ E5 ~: s, L" U. `) b: x8 J: B
if (icmphdr->i_type != ICMP_ECHOREPLY) { 8 d3 M2 m3 m9 B& J- Q% G* i
fprintf(stderr,"non-echo type %d recvd\n",icmphdr->i_type); 6 j8 H0 i' T5 Q, U9 Z/ D' N1 U
return; ) f% P+ u$ j6 c! k7 V5 i( V; b
} ; P; p; i1 Z/ ^% M
if (icmphdr->i_id != (USHORT)GetCurrentProcessId()) { , {- s+ P# L5 i* g
fprintf(stderr,"someone else's packet!\n");
+ j! X! D% p6 z: Lreturn ;
. R; c6 c4 v& o4 F; `* ]3 j6 T}
- i% N3 k1 [7 r! O: u7 `printf("%d bytes from %s:",bytes, inet_ntoa(from->sin_addr));
% P0 V3 Y( [; Zprintf(" icmp_seq = %d. ",icmphdr->i_seq);
, u' [5 |/ W& T6 \6 I2 i8 kprintf(" time: %d ms ",GetTickCount()-icmphdr->timestamp); - t) k( y9 d1 } v* C3 ^
printf("\n");
5 N( _- P6 ?& o6 V' t3 W( h$ h, `% y- c4 Q) ]9 V2 E& T
}
; s; ^; [! _ m! X7 p
2 K, D8 y0 f1 d# e' T6 b( B$ _4 N6 U
9 N1 t3 ^8 i% ~) A* b8 f. iUSHORT checksum(USHORT *buffer, int size) {
: p3 w" H4 L: R: L! O$ k4 P
8 W# b% h9 ?6 F& Lunsigned long cksum=0;
# W2 F0 _; M) A# w% _
# ?) X% \! i: lwhile(size >1) {
" E0 V. E8 e. [) X% h7 d# Scksum+=*buffer++;
( l5 J6 I/ G5 J0 _+ K! Zsize -=sizeof(USHORT);
" B0 e- I- k, M2 }. Q) |* c} ; Z6 l5 O5 F7 b
8 {8 C# x f+ ]1 Y' S6 Gif(size ) { # \: }) |, `( m( h: R
cksum += *(UCHAR*)buffer;
+ E& A3 E T% s}
& D0 s* E$ K# u5 `
: k# j6 V. K/ Scksum = (cksum >> 16) + (cksum & 0xffff);
* ~+ H0 U5 b+ T- s! ^/ U! O' o4 pcksum += (cksum >>16);
7 M: E1 v1 T# \9 D2 D$ u8 `$ Areturn (USHORT)(~cksum); + ~% y" `9 Z/ e9 H. E% e0 n
}
9 _, @! g5 E8 e+ F5 k/* ) `) C" @* N+ @
Helper function to fill in various stuff in our ICMP request. " r5 \7 R: @: h/ F
*/ # V) T) M1 n" N& x: D
void fill_icmp_data(char * icmp_data, int datasize){ ) l- f: L- i7 K N. q6 ]9 r
9 E! x# G1 c7 G% Q# n1 `IcmpHeader *icmp_hdr; % a( V3 a) P& k: s( [1 ?
char *datapart; ) U# h. t+ s0 j. F, @
! t* D. E, r/ cicmp_hdr = (IcmpHeader*)icmp_data;
. j- x3 W- _4 ^0 C
W- u4 o9 F E6 Yicmp_hdr->i_type = ICMP_ECHO;
. B3 J2 l; E# H0 S2 l8 cicmp_hdr->i_code = 0;
$ N1 o: ` C- ~: Micmp_hdr->i_id = (USHORT)GetCurrentProcessId(); ; }. J4 l9 `7 d8 h: ?; o
icmp_hdr->i_cksum = 0; 4 S' c8 p7 b! J" k
icmp_hdr->i_seq = 0; " e) l0 ?# ]0 _2 q
# ]$ H: q" a5 X L- N5 s# ydatapart = icmp_data + sizeof(IcmpHeader);
1 ^# ]& x& ~5 R! { E& O& y// }% J$ T7 P; G% C% K; D
// Place some junk in the buffer. 8 U8 t l' p8 m5 `7 P7 F
// & n: l" G! i( O& L% N( D
memset(datapart,'E', datasize - sizeof(IcmpHeader));
8 j6 k; A3 \8 s0 r, {4 @1 m# p8 N" Y' ~. a" ?
} |
|