|
******************************************************************************\ 0 ^: u! T5 q% A a/ ^& O, s( N" j
* ping.c - Simple ping utility using SOCK_RAW
! o) x# @9 U7 N' p/ c9 f*
( X. h# m0 E) q* This is a part of the Microsoft Source Code Samples. 3 ^0 ?% r1 {# @; K1 R+ J, E5 r% o- _
* Copyright 1996-1997 Microsoft Corporation.
0 w2 }5 a% U4 Q, j* All rights reserved. 3 q8 c! K4 B# V) I& m* x- J& O
* This source code is only intended as a supplement to
& L" V1 W+ L _" X* Microsoft Development Tools and/or WinHelp documentation. 1 l- F# G2 S, `! A/ U$ O6 R
* See these sources for detailed information regarding the
- e9 x0 d/ S* f8 X) e5 P/ t" i' O; n# U* Microsoft samples programs. : ]- \' k$ }3 K7 Z0 F$ \2 J
\******************************************************************************/
1 c$ G; U! K/ w- A# g6 s$ p5 P/ s: B2 g5 J* H
#pragma pack(4) 2 F& Y* i8 ?# Q4 V! g* A% N+ f5 ?
; A/ Y" q: D+ g1 J* u
#define WIN32_LEAN_AND_MEAN
5 f% _+ z. s) h; ^#include
F. O, I4 e4 ^0 N: z2 g- T#include
+ I1 U% i- p9 c6 m. f" I3 m#include * e3 \4 I# _6 e( v* M/ ~' j$ }
# v8 Z7 C) u) V: u" j( D#define ICMP_ECHO 8 # R. O; _ B2 C1 s% \1 `
#define ICMP_ECHOREPLY 0 * M5 C' R/ D# a# h9 }
' M3 J, Z" ^: l% u
#define ICMP_MIN 8 // minimum 8 byte icmp packet (just header)
0 \$ D" |% F0 E" l$ P( }6 S E& T% Z7 C8 s
/* The IP header */ ; }1 _% `3 Z e3 o" r
typedef struct iphdr {
0 `0 m/ h4 T9 l7 Iunsigned int h_len:4; // length of the header
6 a3 c* Z- d- ~) I7 Y& ^: M8 P- K% P/ xunsigned int version:4; // Version of IP
% J# F# `; v; V( {% W" ~unsigned char tos; // Type of service
* ?7 a, t: F+ t- A- munsigned short total_len; // total length of the packet
" v ?0 l- V) O4 u, Lunsigned short ident; // unique identifier
& r" o8 X% o. Y/ h3 d2 ?unsigned short frag_and_flags; // flags
8 T* u8 S _0 b" Q9 Q' U6 runsigned char ttl;
! ^$ j& X$ g; Z U. I/ Punsigned char proto; // protocol (TCP, UDP etc) # f' l) Q0 T; Y, G# s8 ]
unsigned short checksum; // IP checksum " b( R |0 v$ q0 i$ o) y
) n3 {+ G% d. ~2 g9 W& D
unsigned int sourceIP;
1 X' O6 C5 T; E- ?unsigned int destIP; + l" N1 W6 l; H) G3 n3 }2 v
- G! H' P- J( k}IpHeader;
% l: ^* \9 Z! d1 e$ `9 [. U, m
// 0 C( {* V' F: v) H8 P/ q* L9 S
// ICMP header
; h s1 G) ]4 o. y+ H+ \1 N//
+ u/ U8 F( a% n( @1 N$ Rtypedef struct _ihdr {
! }+ B6 f& x1 H8 {0 I) |2 o/ CBYTE i_type; - {) ?2 h+ C( i J. M9 Z9 W
BYTE i_code; /* type sub code */
7 ~) A% k0 a) K7 \USHORT i_cksum;
9 r. J8 x" V' m! y' d/ iUSHORT i_id; , k5 G; R% n0 Y" o
USHORT i_seq;
0 E& U! x0 y5 Z% h6 D! O# X& ?$ ~/* This is not the std header, but we reserve space for time */
) T+ i, b9 K0 j5 Q# j! M+ a3 EULONG timestamp; 2 i7 t, u: u1 y
}IcmpHeader;
9 U) }9 D% C/ M2 A2 s1 C, [! l; A4 D( t$ i7 L o) p/ {6 D
#define STATUS_FAILED 0xFFFF
" f0 v8 q2 D* Y. O ~* i) i; G4 S#define DEF_PACKET_SIZE 32
! t, G. s% y$ X#define MAX_PACKET 1024
" @* P+ \8 W0 q! c6 s R9 K# D0 T3 R. X$ i, w
#define xmalloc(s) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(s)) + g; l5 c6 R0 l8 O/ q; S2 D
#define xfree(p) HeapFree (GetProcessHeap(),0,(p)) ) {$ _/ B* ?' D4 n8 i& S( o2 l0 Z
) @% g' x8 ]" c2 T
void fill_icmp_data(char *, int);
; c. X$ }3 ]7 ~+ V; SUSHORT checksum(USHORT *, int);
% a. N& a4 ]( H$ Zvoid decode_resp(char *,int ,struct sockaddr_in *); % g/ P) t0 ]" C3 M
Y5 m5 \1 ~* F0 @; J. |void Usage(char *progname){
, l) k9 C. h" C1 P0 l1 E7 s. D9 c( C. ]8 j& R! L$ K0 W h0 w
fprintf(stderr,"Usage:\n"); 8 B y m, ]+ g1 L2 M4 I
fprintf(stderr,"%s [data_size]\n",progname); 0 U" q c) I" T; Q# }4 u
fprintf(stderr,"datasize can be up to 1Kb\n"); / d0 K3 M' V/ r0 ?
ExitProcess(STATUS_FAILED); * K6 k1 |2 k+ t8 [7 E
! r$ c9 K' D1 D% x9 M8 ?& n1 f
}
8 X+ ~3 A: W7 P# E {: L; Nint main(int argc, char **argv){
+ y: V4 M5 ?% ]8 t- p: e2 ~. C6 E' T6 N2 r- V/ `$ J
WSADATA wsaData;
/ m6 j& e \0 L" MSOCKET sockRaw; 8 V0 N9 a# k! A+ j8 n2 |
struct sockaddr_in dest,from; , S* \4 V( B4 v7 V. W
struct hostent * hp;
* Z2 p2 E. S( T5 uint bread,datasize;
; ~: c. X- }* @, z& c; `# ^int fromlen = sizeof(from); . V1 Z! P9 U7 t+ O
int timeout = 1000;
8 M4 v# P) Z ^- }char *dest_ip;
- p: s4 x$ N" r; }4 Ochar *icmp_data; 6 u2 J2 Q8 h9 ^" L4 p
char *recvbuf; 1 r7 i; y0 B8 @% [5 Y' T7 _
unsigned int addr=0;
9 X+ v# n! j0 B9 M' Z- fUSHORT seq_no = 0; 1 S& E0 k' X* A- N% \+ O
/ ]/ Q( u) L$ j8 D7 A. a; B
if (WSAStartup(MAKEWORD(2,1),&wsaData) != 0){ 2 o) I. W! C, x# X1 p+ N
fprintf(stderr,"WSAStartup failed: %d\n",GetLastError()); ' H, L0 {$ e( T4 Q! e4 X
ExitProcess(STATUS_FAILED); $ n2 V/ l& A$ z+ g* D5 C& Z. n) N- Y
}
8 I" ~! S+ s- c0 X8 G* Y
3 x) d* |9 Z6 _/ r/ Bif (argc <2 ) {
8 v7 q3 r+ u, nUsage(argv[0]);
! T' U/ s4 H, ~; q2 `} 6 D" S/ |; b0 v) W- x& k$ x
sockRaw = WSASocket (AF_INET, 0 z; l5 c% R9 i- W, ?) u
SOCK_RAW,
( L0 d8 c7 o1 n0 c% K) c# pIPPROTO_ICMP, ! _3 M: g \& B1 e- R
NULL, 0,0);
* @; X2 T, b) L6 T, l
! ?3 W4 D. H0 ?0 gif (sockRaw == INVALID_SOCKET) {
5 w- W2 L* ]2 \- d" G. m8 ^fprintf(stderr,"WSASocket() failed: %d\n",WSAGetLastError());
& w: S+ m( R+ G, h6 WExitProcess(STATUS_FAILED); : a& j0 w3 z& g$ g5 N
}
3 y7 W% [! z- x3 f& lbread = setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout, / A+ ?$ i; C* u8 Z9 @0 U; k# H- p" d
sizeof(timeout)); 3 a/ b4 j: U/ e0 ]4 j+ w
if(bread == SOCKET_ERROR) { g- n9 p" z( N
fprintf(stderr,"failed to set recv timeout: %d\n",WSAGetLastError()); c) g" M. S O
ExitProcess(STATUS_FAILED); # f' H4 L1 X9 e; ^ R; C" q
} 0 h3 u2 {& R8 M1 `
timeout = 1000; ; J& R# D2 Z* G
bread = setsockopt(sockRaw,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout,
$ z& a: v& K: ^: J; F; fsizeof(timeout));
8 _0 L7 X$ T) e$ G7 U+ Jif(bread == SOCKET_ERROR) { 5 R8 w9 I4 g |0 p M
fprintf(stderr,"failed to set send timeout: %d\n",WSAGetLastError());
( Z: h6 x% ]0 T7 AExitProcess(STATUS_FAILED);
9 L& T+ j0 u& _# D9 Y/ v} * F& C# C0 z! d& P
memset(&dest,0,sizeof(dest)); ! V. D0 {% l! ^7 P9 a( H6 g
; O- x# ]/ S& E( N0 Y6 _' ? ahp = gethostbyname(argv[1]); , g7 ^- } h, A; F
* n3 G8 n! Y2 D9 P1 aif (!hp){
' Z- [9 \' Z% m% oaddr = inet_addr(argv[1]);
: ? a8 w% |# I' V( w* j} 7 j+ y' {- n4 F
if ((!hp) && (addr == INADDR_NONE) ) { 9 C+ ?3 d, i& y/ C0 }' x9 ^
fprintf(stderr,"Unable to resolve %s\n",argv[1]);
) d8 s1 A1 ^, N! fExitProcess(STATUS_FAILED); . J! P/ g+ h; ]7 i* j/ m0 J7 u$ y
} ' y/ X4 _* [+ ^- l( ?% B4 K- b0 o
3 C- ^6 `/ p' W* m7 D7 \: B; t3 Yif (hp != NULL) : C! F) Z; P. _3 r8 g
memcpy(&(dest.sin_addr),hp->h_addr,hp->h_length); , h. N7 G% _0 J4 G& l7 V& `
else
3 r+ ]$ ]6 s0 Ldest.sin_addr.s_addr = addr; - v2 x( [# q) R- n; Z" S
; ]8 m8 b& K! K% i0 f( g0 h
if (hp)
! n; x/ `# [ N. h: ddest.sin_family = hp->h_addrtype;
' T, ^& ?3 f+ s: telse ; D0 }3 w1 p, l
dest.sin_family = AF_INET; 9 H. H; }) }2 s4 U* Q
* h% l, |+ K. `
dest_ip = inet_ntoa(dest.sin_addr);
# ]0 d, M& V: L4 K9 [1 @9 t; B; z$ h4 T+ r. r" E; i
if (argc >2) { 6 o; J, ?+ S( N; v- X
datasize = atoi(argv[2]);
! J- a" E# p* y: \. lif (datasize == 0) ! z/ I" k. x; V V) U$ M$ R
datasize = DEF_PACKET_SIZE;
: C9 u# N- j6 n+ u. C# \$ k- o$ r& ~
}
1 l n" }2 ]- Z% s( relse ) `$ u' |5 Q- o; J
datasize = DEF_PACKET_SIZE; 4 F. Q) M9 r# }3 |. G; p
" B, H& f; P! J. _4 N1 P
datasize += sizeof(IcmpHeader); ( I( `0 ?5 ?, f* U4 \# I# S
( q; y0 t& c5 ? X: k1 `
icmp_data = xmalloc(MAX_PACKET); 5 U; v1 [: a8 G9 _
recvbuf = xmalloc(MAX_PACKET);
) U' w/ o* F$ e1 T5 ]+ R) ~8 J/ K$ @$ s9 m0 E
if (!icmp_data) {
4 u: L* d2 ^, B, q. c1 s, R6 h) O% [" Ffprintf(stderr,"HeapAlloc failed %d\n",GetLastError()); 3 e3 a0 w- o t; k7 i0 E
ExitProcess(STATUS_FAILED); ( \+ t/ U9 t- D5 ^3 T1 a
}
, d: }* H% b) X1 @- vmemset(icmp_data,0,MAX_PACKET);
1 d& P$ }, r. P/ y) n9 vfill_icmp_data(icmp_data,datasize);
* [! A2 n2 B" ~% c5 M' i# Y
: F( S. b! M% H1 A0 Uwhile(1) {
6 L! e/ a; E( Z$ iint bwrote; 3 B- u1 G- A* g2 N4 F8 k: X
3 }! F4 d$ F9 o3 Y% g+ `((IcmpHeader*)icmp_data)->i_cksum = 0;
* E8 ^" ?9 z0 [((IcmpHeader*)icmp_data)->timestamp = GetTickCount(); & Z4 n( E' X9 E$ o+ g
) w& t) z/ J6 t1 H1 ^& D
((IcmpHeader*)icmp_data)->i_seq = seq_no++;
7 J" q2 x1 K7 t: H# N8 C((IcmpHeader*)icmp_data)->i_cksum = checksum((USHORT*)icmp_data,
' L% \$ |* c$ Q- r6 rdatasize); 4 ?. @& Z2 {: ]2 {9 W
& A& [- t/ j( obwrote = sendto(sockRaw,icmp_data,datasize,0,(struct sockaddr*)&dest, ) a* N, g" p4 k* F2 E: t- [
sizeof(dest));
1 ?4 }' M3 S0 E; |- Mif (bwrote == SOCKET_ERROR){
/ b# H, U! e3 p6 \if (WSAGetLastError() == WSAETIMEDOUT) {
* m1 t9 [' Z$ ?* Kprintf("timed out\n");
' D# l t8 m8 K* B* a( Q7 h5 P- i' Tcontinue; ' {% E8 d! F. H. O# v9 Q* h4 |# U
}
3 p, O' A- R, [9 F1 k! X6 c8 \fprintf(stderr,"sendto failed: %d\n",WSAGetLastError());
6 { o; w K' N& h8 bExitProcess(STATUS_FAILED);
" f/ u9 [; s/ R% ~- i6 S}
' M6 B, }2 I' s T. v. O; V* H% @if (bwrote < datasize ) { + Q" p+ J# B. P
fprintf(stdout,"Wrote %d bytes\n",bwrote);
2 v$ [5 ~: |; j) Z+ f7 |8 m; D. j}
Z6 c9 M$ Y: v$ W4 v2 u: l5 j1 ybread = recvfrom(sockRaw,recvbuf,MAX_PACKET,0,(struct sockaddr*)&from, 3 q* k' T: a2 v, b# f- T% B/ {
&fromlen); : ^( A! B5 Y$ o- o' `4 \; v
if (bread == SOCKET_ERROR){ ) e+ F9 Y% e& n' ^5 S, {: t) F
if (WSAGetLastError() == WSAETIMEDOUT) {
. Y: E) V7 j# W( Q8 Z$ q% s% y* bprintf("timed out\n");
7 I. [ j f1 g+ w6 E$ Q+ Dcontinue;
# \, c, w! G, ]6 U}
* @8 ~' X# l( b4 M6 q6 j- ufprintf(stderr,"recvfrom failed: %d\n",WSAGetLastError());
; t- E3 F+ ~/ r. t* iExitProcess(STATUS_FAILED); ' J; q" z4 h `6 ~: }
}
' X9 q+ k4 K, G+ d3 S- wdecode_resp(recvbuf,bread,&from); ' J! O4 G/ G m
Sleep(1000); ( w1 X/ Z/ G$ Y% ~1 s
& [$ y. P" V+ I8 `}
4 Y! J) E1 f5 N3 b5 J# f0 D+ preturn 0;
X# G$ {6 S/ d- S0 l+ `8 l3 g l! |& _3 _ F" s& E
} 9 U& q" B& V& t
/*
* n2 X3 v! P+ D3 q8 XThe response is an IP packet. We must decode the IP header to locate 3 `) i1 U1 U& y, n: z) \. r5 y+ C
the ICMP data , L* G' u8 q+ l1 {$ s" n" W/ W
*/
: A0 L) C6 x: w" q& _, T' k U% Tvoid decode_resp(char *buf, int bytes,struct sockaddr_in *from) { * v* T: V% L5 I5 P
) [ x1 l5 P3 a4 k9 A1 ~! O* F
IpHeader *iphdr; 4 I" B2 p/ g2 p' n2 n: [3 v" M
IcmpHeader *icmphdr;
) ?; J' e* s7 H( i/ ?* g% sunsigned short iphdrlen;
2 J) V4 r7 {9 Q+ S3 H2 Q" C6 K' \' ~- e5 ]
iphdr = (IpHeader *)buf;
- h4 ~9 {1 } d& C: I3 n% D1 ]3 b' s* v( s; D
iphdrlen = iphdr->h_len * 4 ; // number of 32-bit words *4 = bytes
) K. {9 P u8 y- \' l: N& t& N. M6 F1 _' U
if (bytes < iphdrlen + ICMP_MIN) {
7 J' [6 ]* _" M* R5 B3 ]+ F0 Xprintf("Too few bytes from %s\n",inet_ntoa(from->sin_addr));
! E$ u: \$ L8 a' {} ! O' b& b) f$ |; H/ ]5 c' r
# x3 _, b y) w, `/ Y- Licmphdr = (IcmpHeader*)(buf + iphdrlen); 4 n: ~0 ?& O6 y0 ?& J
D' I$ O* c& k
if (icmphdr->i_type != ICMP_ECHOREPLY) {
, n1 U4 c$ e* b: O7 ffprintf(stderr,"non-echo type %d recvd\n",icmphdr->i_type);
0 V' @+ q# {0 e! G6 zreturn; 8 `3 T8 |* u1 H: B: ?! k# g3 |
}
. M+ m5 G" c- l: D0 w6 `5 Wif (icmphdr->i_id != (USHORT)GetCurrentProcessId()) {
( l# t! v2 U$ [fprintf(stderr,"someone else's packet!\n"); # L# H- `- X1 U+ G
return ;
" Q3 T( i4 M S7 X& R}
$ D* I3 C2 o* n" K7 _printf("%d bytes from %s:",bytes, inet_ntoa(from->sin_addr));
% l1 h2 H2 c$ J0 nprintf(" icmp_seq = %d. ",icmphdr->i_seq); " g) h1 T/ l! N7 H- x+ @
printf(" time: %d ms ",GetTickCount()-icmphdr->timestamp); 7 c# h4 C0 P# s `5 ?4 d/ c
printf("\n");
% k$ G. s y6 a8 p2 S8 @ t
( k7 k, j* I4 a& y} + _9 p0 I# U# j! U
: j8 g7 E9 `7 g2 ]; D# }1 j: ], ~% Y" u+ y
USHORT checksum(USHORT *buffer, int size) { ( q3 ^8 {" }% I' _0 l) ]
- u$ _4 z# w/ n: d% u6 ]unsigned long cksum=0; ' H% W5 m8 H3 X7 ?( C5 `0 X- K
; y4 b& `% z. E" \; Rwhile(size >1) {
, y8 W. R6 V: V4 N' F2 dcksum+=*buffer++;
. S4 \+ }% J- C' D U" esize -=sizeof(USHORT); ) ?6 h* C' x4 t
} 4 _- f; F: w e6 ?7 |% b0 a
3 z, d# ~, l0 w2 }% r- Zif(size ) {
0 l: P4 U% @" e! T1 |cksum += *(UCHAR*)buffer; . R* Y y( v& t4 w0 X& z; l
}
6 G) Z. R0 u/ L7 S) b+ P5 y8 z
cksum = (cksum >> 16) + (cksum & 0xffff);
9 Y) v: p% G8 U' F# Scksum += (cksum >>16);
6 z" {( H3 S% Nreturn (USHORT)(~cksum); p. P& y9 I4 n. T' `4 S, u- G: y
} % h& w: S# I! R* m7 @
/*
7 b `/ J9 a$ rHelper function to fill in various stuff in our ICMP request.
" z/ x* P- z/ Y8 g% y9 w" H*/
& }, E; q T+ e2 D& \void fill_icmp_data(char * icmp_data, int datasize){
0 p6 E& B2 ~( ?( ~+ N: L- X( z+ U. }# o9 m3 U
IcmpHeader *icmp_hdr;
0 u! \' O1 k+ {' C0 achar *datapart;
% s* q' c7 c3 ^: H0 P! o- `; r' N9 L. Y+ V, {
icmp_hdr = (IcmpHeader*)icmp_data;
' q/ N1 z* Y4 C+ e5 Y$ P' R. ^$ {% p8 g1 v# }; s* F
icmp_hdr->i_type = ICMP_ECHO; 0 u; [, `3 w* S: B" ~( U, m
icmp_hdr->i_code = 0; 0 y/ `/ ~8 _% [+ c( y. Z
icmp_hdr->i_id = (USHORT)GetCurrentProcessId();
X. I2 a( Y6 f- O- H7 L- Cicmp_hdr->i_cksum = 0; + `! o5 Y/ o( q$ L" r, p5 Q
icmp_hdr->i_seq = 0; ' H# r2 s# d! C$ y$ u' g9 g
) G9 F' d& A' L! Y0 a" a4 {
datapart = icmp_data + sizeof(IcmpHeader); 8 M- `0 P' x! P
// + \& G3 S! b9 i
// Place some junk in the buffer.
' i2 Q4 }7 H% B2 L( v& C2 k* n// . ?+ f; `1 x/ E; Q5 V; [/ F
memset(datapart,'E', datasize - sizeof(IcmpHeader));
( a0 ]5 F6 b6 d0 W
+ N1 @' q0 j, |5 c. s0 D} |
|