|
|
******************************************************************************\
* F& `4 `$ H+ \9 r* ping.c - Simple ping utility using SOCK_RAW
2 [& e% g1 x' Z% b3 K& ~*
0 W+ t0 R- ?7 P! U" ^( s* This is a part of the Microsoft Source Code Samples. ; `7 j9 C n6 e: f+ A9 l
* Copyright 1996-1997 Microsoft Corporation. 7 m# {- x" v& l% C4 x
* All rights reserved. ( f9 ^# A' C: k9 \! S4 ^4 C
* This source code is only intended as a supplement to
2 _" i& r6 X4 n; ]" [4 B5 q* Microsoft Development Tools and/or WinHelp documentation. 1 L6 ~" B( g( X3 T) P
* See these sources for detailed information regarding the
5 W6 L" m- g8 b& N0 x6 c3 v g2 ]* Microsoft samples programs. " d9 B/ [2 e7 ?2 e% ~
\******************************************************************************/
/ k( \3 D) L. D6 t
" g4 s- i: Z- ^& f& O" N0 Y#pragma pack(4)
' d' {6 b8 C3 {. M* h- M" P1 Y" |3 M. s, R& R1 O- }' ?
#define WIN32_LEAN_AND_MEAN ) r- E: @. d! P- ` M
#include " ~4 h1 D2 T* C9 O9 \' d+ T' P
#include . q; X# H# | x
#include
@* Y7 j$ u1 H5 l" p$ O% m0 W$ M. K/ ]9 U1 L
#define ICMP_ECHO 8 3 o! I, n+ w2 \0 ?
#define ICMP_ECHOREPLY 0
; _2 |4 c# Y' e# V; S, B' [- @9 O7 f, `
#define ICMP_MIN 8 // minimum 8 byte icmp packet (just header) 0 M) W8 D m# C" w) p; c- _
; Z: ~1 a6 ]) ~! |, n) e5 _/* The IP header */
3 G8 {* \( ^1 @7 Gtypedef struct iphdr { $ Y. Q' y, e6 V0 b7 e! R5 z/ a" x) I8 g
unsigned int h_len:4; // length of the header
- {: A9 c/ J% G: munsigned int version:4; // Version of IP
3 R$ a% M j) y4 Ounsigned char tos; // Type of service
; G. ]8 V: D" Iunsigned short total_len; // total length of the packet
! N* {8 p- S6 }; W Sunsigned short ident; // unique identifier
$ J) O2 k v! Q+ m! K) x, T5 j- gunsigned short frag_and_flags; // flags
: \9 `0 x! |5 N$ _5 K' T) I% Vunsigned char ttl;
' d* K! c1 \; |) S" q1 I a1 sunsigned char proto; // protocol (TCP, UDP etc) 0 g8 k* y3 ]$ ?& ?- n! Z) w8 m2 r* a
unsigned short checksum; // IP checksum
4 {. m* U& R8 J, A
; r* M" Q8 r. j! J) g) X: Q' Qunsigned int sourceIP; - u, d: g: p# N, X5 ]/ O: {
unsigned int destIP; 6 }: G9 j( [- w. `% |: j' O
! U+ V* [$ I+ P% h* i9 G( ~6 p- L, g}IpHeader; 3 q' X( Q' U' k9 g! J
' Q1 P7 _, G2 L1 h" \* H//
3 q2 b: L7 {5 O3 v// ICMP header
5 i9 N5 Q$ _5 k: m- B. N3 C//
2 Z L% D: c3 l: N" l7 v3 l5 E. t+ }typedef struct _ihdr { : q2 w2 W# f% c- |- S: n
BYTE i_type;
% {" H$ P: G+ j. E: UBYTE i_code; /* type sub code */
) C$ L; ]! S e' E WUSHORT i_cksum; # T( i* t* u5 Z4 [! j
USHORT i_id; 6 J6 e( K' l: `! }+ g% @
USHORT i_seq; & g* k1 j7 G4 [/ U6 r; ?
/* This is not the std header, but we reserve space for time */ : ?& h. b& p+ O
ULONG timestamp; 0 V% z- O G3 s5 `* k2 H
}IcmpHeader;
x$ J( q4 O( r
( I8 Q" O! {/ \- K4 _* @0 Z#define STATUS_FAILED 0xFFFF . J {9 x6 p3 Y
#define DEF_PACKET_SIZE 32 0 Q2 _, T# ?( ^ V: X- o
#define MAX_PACKET 1024
2 v+ B0 q+ [1 K; s1 F8 Q8 b3 `4 U4 A q& q/ a5 n& ]! @: h
#define xmalloc(s) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(s))
; U9 h$ K# p8 g8 N" n#define xfree(p) HeapFree (GetProcessHeap(),0,(p))
2 I8 u$ D$ p& n9 e% V8 Q; e5 U3 U$ {- A% E- j, f
void fill_icmp_data(char *, int);
6 t2 I. d7 G8 A% L4 B @, jUSHORT checksum(USHORT *, int);
# y' Y u9 e/ @6 r) Tvoid decode_resp(char *,int ,struct sockaddr_in *);
; a+ j+ Z1 U% f8 j9 v6 i) N2 l. Y! B4 B3 @" H. q* L# D& b
void Usage(char *progname){
# p- ^9 i; G$ G& R% Q
* Q9 h! C5 |8 k. o0 J& m/ Dfprintf(stderr,"Usage:\n");
/ d4 _2 Z( x3 _, G5 d/ s% vfprintf(stderr,"%s [data_size]\n",progname); & w6 b! F; o8 L( ]& t: ]- {# |
fprintf(stderr,"datasize can be up to 1Kb\n");
/ W2 E- l, \$ C% h' C/ K4 ~ExitProcess(STATUS_FAILED);
C- [# w' ~) {* q# t" T
w f/ m6 G' D6 K8 d} " N+ T6 U& c0 `8 W/ x
int main(int argc, char **argv){
- m8 A' h8 P, q# l6 S" U6 u) X/ x, e/ ?- [* ]4 ]0 N8 c& D, K
WSADATA wsaData; 2 y1 l: {* ~" R& T# [
SOCKET sockRaw;
/ g0 |! o+ P! R# a& V3 e9 istruct sockaddr_in dest,from; 5 P, d( `& g `* }
struct hostent * hp;
9 p0 c& `' N8 zint bread,datasize;
3 ~4 G! M; r# Qint fromlen = sizeof(from);
6 }/ L( |, `5 Wint timeout = 1000;
* C5 v% [: l: c8 H9 C- @: pchar *dest_ip; " k9 i% q' I4 w# Z4 Z% I- D! ?
char *icmp_data; 8 s3 V+ A% k2 b# Z
char *recvbuf;
& ~ ]& |4 a/ s3 f6 J0 _ Junsigned int addr=0;
6 E, l* v1 B$ p, Q) GUSHORT seq_no = 0;
( P) c+ ?' V4 o }& V$ E2 W% S4 E# L9 }8 G2 r
if (WSAStartup(MAKEWORD(2,1),&wsaData) != 0){ ! n, G1 z! F L6 y- ? D4 r2 U. X
fprintf(stderr,"WSAStartup failed: %d\n",GetLastError());
- R, M/ m0 l% @( Y) U/ i4 eExitProcess(STATUS_FAILED); : _' P- K$ h( j+ k
}
* K' O7 x! b9 r* D! d" N1 t# I+ x0 C" V0 c/ _- U) r
if (argc <2 ) {
8 P2 l" @2 Q5 U) ^: qUsage(argv[0]);
5 p, Z4 Z8 U7 O/ l3 l7 O9 `} & z" V, A8 }, `8 t9 G; v
sockRaw = WSASocket (AF_INET, + m4 p7 |+ [2 v4 g, l6 E
SOCK_RAW,
7 S1 t* P' m/ V. J/ U9 oIPPROTO_ICMP,
- O9 l$ ?8 }5 a% [0 u, A% I* _* CNULL, 0,0);
6 p! _% j: H- V/ g; g/ W) J' U
; m+ Q/ l& j9 }if (sockRaw == INVALID_SOCKET) { 7 q! g$ ^, }% B. J
fprintf(stderr,"WSASocket() failed: %d\n",WSAGetLastError());
# S& S: z1 h- p8 mExitProcess(STATUS_FAILED); 1 y/ j3 j: ^8 ~- W) M0 K
}
/ t. K3 i) q& `7 H" ~% Xbread = setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout, . c6 N) V8 _; }5 P, N
sizeof(timeout)); , v$ @8 G; ]6 ^+ L
if(bread == SOCKET_ERROR) { 4 B' x/ ^& s) i" }! E
fprintf(stderr,"failed to set recv timeout: %d\n",WSAGetLastError());
8 Y5 j1 y7 g! GExitProcess(STATUS_FAILED); - ]% P9 p7 P: d5 r5 I' a% L
} 4 o2 T7 Z8 T! D6 h6 E! |9 C
timeout = 1000;
0 W0 ?1 j$ e) s+ F/ R/ W' c) Zbread = setsockopt(sockRaw,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout, 7 a7 [' ~$ ]6 y' S a6 N; I
sizeof(timeout)); 0 ~# G6 F0 K( |* N2 Y
if(bread == SOCKET_ERROR) { ! B" A9 d( I& ~' a5 Y; w9 y
fprintf(stderr,"failed to set send timeout: %d\n",WSAGetLastError());
7 O; `& C' c5 }7 b0 {2 W# G$ ZExitProcess(STATUS_FAILED);
/ v0 u$ h' d+ Q1 E}
. \1 u9 x; Q* zmemset(&dest,0,sizeof(dest)); 1 ^6 N! q- \4 a: I) k8 {- I
9 [ }0 V! Y! G% u3 O4 p
hp = gethostbyname(argv[1]);
* z# ]7 s* a2 P5 ]) W- v
* a1 f" h2 v) Q5 e# Sif (!hp){
% x3 s" V' P8 L) ?5 Zaddr = inet_addr(argv[1]); + N- W2 r' u8 a/ w4 m
} 4 f2 U; g& w. k! J
if ((!hp) && (addr == INADDR_NONE) ) { + D# f2 J7 d- v5 R( N: S
fprintf(stderr,"Unable to resolve %s\n",argv[1]); 0 q( ^4 A4 z/ _! {+ f
ExitProcess(STATUS_FAILED);
8 z* k: o+ L- A6 p6 N' S9 ~}
& Z; G$ S; y2 q; D) V5 W$ a6 H& V( K3 Q3 p1 q; s* W" p/ ~; T
if (hp != NULL) 5 ~9 |/ Z$ B8 x, `0 e6 }- N% T$ o# o- d
memcpy(&(dest.sin_addr),hp->h_addr,hp->h_length);
, a: \/ I! u( o- o7 b$ @# }9 Eelse ' o) j" n% F0 u$ M B, Q
dest.sin_addr.s_addr = addr;
, B w. I' W/ k" w) A. M8 A" [/ Y2 r) A; t5 J
if (hp)
* `- h5 `/ I6 Y. Idest.sin_family = hp->h_addrtype; - w$ `0 q- t( @* a
else
" e- B) ` M7 y o( a4 o- jdest.sin_family = AF_INET;
8 J. A' i0 J" p1 m7 p
0 o+ X; ^, Q7 b; j9 Qdest_ip = inet_ntoa(dest.sin_addr); 4 |% S, u! T; X- b. C
, Q/ g7 S" B: }( ~3 E( H3 cif (argc >2) {
4 q/ s* n& f; x. A- `/ R6 M* Zdatasize = atoi(argv[2]); 0 S6 C0 L1 ^0 U/ l, | C9 H! Y
if (datasize == 0)
8 q, ^5 v! P- u! Sdatasize = DEF_PACKET_SIZE;
5 n( H. i. g/ `0 u$ i d# s1 ~& m5 X# s
}
5 O5 q" }: m. w& N2 N0 ?else
8 A% S7 U8 p* G2 h6 cdatasize = DEF_PACKET_SIZE; 1 b$ \% Y) M. ^1 W2 N
2 Z" U- h& l2 M9 N! H6 @* |# wdatasize += sizeof(IcmpHeader); : s/ x- l5 A8 Z+ B6 \- p
8 j4 b0 h3 G" |. Hicmp_data = xmalloc(MAX_PACKET); , y; O) L6 C5 S3 i5 M2 V/ z
recvbuf = xmalloc(MAX_PACKET);
% P# ^6 S' r0 X9 C* I2 W5 ^/ l- x) G) F+ O+ }( x% Y
if (!icmp_data) { & H: @8 ^2 P- [& p1 _
fprintf(stderr,"HeapAlloc failed %d\n",GetLastError()); 4 L% z b* N7 d1 l1 m8 P' b
ExitProcess(STATUS_FAILED);
% d2 @2 G8 S- K4 Q- f0 \}% t% [; {$ r' L! b8 f8 E
memset(icmp_data,0,MAX_PACKET);
: E/ Y8 O& [; H/ X* h# g, Z# tfill_icmp_data(icmp_data,datasize);
" N5 q* j) V; i$ R1 j# a2 d& S& v. e( [. H, e* T
while(1) {
$ `( H5 W: s5 g7 f) U" Z2 u/ Uint bwrote; 1 B5 P8 h) e6 z( T6 W
% v8 [4 y. q* N& }" W((IcmpHeader*)icmp_data)->i_cksum = 0; ! A- @( x7 j% z0 }) w+ b
((IcmpHeader*)icmp_data)->timestamp = GetTickCount(); * B" p1 {, z' z3 \
5 k0 s! V# _9 W
((IcmpHeader*)icmp_data)->i_seq = seq_no++; 5 d& P; D! K: q6 a8 g
((IcmpHeader*)icmp_data)->i_cksum = checksum((USHORT*)icmp_data, % a; I% D. n* {/ p H7 I& t) t
datasize); . S4 i( B7 V0 P8 f3 F( E: b) ~
; L1 T: J m! N- a; D5 V' }
bwrote = sendto(sockRaw,icmp_data,datasize,0,(struct sockaddr*)&dest, ! G: v$ w3 N: h' v
sizeof(dest));
+ u; F s9 _0 Q2 cif (bwrote == SOCKET_ERROR){
/ m# t0 B5 t1 _$ |0 L% {if (WSAGetLastError() == WSAETIMEDOUT) {
' u) I0 t: J5 c# t# U/ c5 R# Cprintf("timed out\n");
7 L# [4 ` `. v) ^( c* K/ `3 X. zcontinue;
- Q' q$ C" k& v/ u0 P9 s} $ L! H. a+ ~5 \2 l4 o; m) J) W
fprintf(stderr,"sendto failed: %d\n",WSAGetLastError()); 5 U. B, U( l/ E1 `! q# [
ExitProcess(STATUS_FAILED);
( ]8 ^ ]8 [; k6 F} % a' j6 \9 ~1 H1 ]5 c' y6 g" I
if (bwrote < datasize ) {
- d- ^. Q" t- T3 Ifprintf(stdout,"Wrote %d bytes\n",bwrote); & t) ]& ~: @9 b: H+ |
}
$ m) I9 s( ^9 d4 U; d! U& ]bread = recvfrom(sockRaw,recvbuf,MAX_PACKET,0,(struct sockaddr*)&from, 8 L7 |9 }. I) v# K7 l/ c
&fromlen); : B( T6 f! J" f+ t, o
if (bread == SOCKET_ERROR){
( {- O' ]- w' K: k/ iif (WSAGetLastError() == WSAETIMEDOUT) { ! H: S( t1 G; H& Z4 r( \
printf("timed out\n");
: d% O" T2 i7 J- n; Q5 @continue; 2 z1 l, `! q; m
}
0 A+ e2 R+ u# j& ~& m* ~fprintf(stderr,"recvfrom failed: %d\n",WSAGetLastError());
" H3 A% B0 K, aExitProcess(STATUS_FAILED); " w, Q7 x! i# i5 S- m0 z
} 7 X5 U4 Q6 c4 b
decode_resp(recvbuf,bread,&from); / M& G1 H- o$ V
Sleep(1000);
* Q# J6 Q) i' N, J- v6 @
9 |! [$ O! g* d) ?* @2 L} 4 v% k& m8 n$ q1 r
return 0;
& N4 q: o7 }) }) {& ^
: @0 |/ Z7 Y4 Y1 d) P4 A- I} 1 G0 V$ J" ?" U; g' }; L
/*
1 C6 ?* |' a( d6 `& ~The response is an IP packet. We must decode the IP header to locate * I# m& h6 j- ^
the ICMP data 3 x, L5 d2 w3 {( X- J
*/
8 p9 u3 G0 f' f- ~, v9 Kvoid decode_resp(char *buf, int bytes,struct sockaddr_in *from) {
! B6 |' J5 @2 V0 U1 l' `' O; w
) a9 |# s+ [- z2 }- w4 L" uIpHeader *iphdr; 6 `/ n/ H" x/ S7 e* L/ h
IcmpHeader *icmphdr; : E5 @- r% `2 e
unsigned short iphdrlen;
4 p3 K' e, o) G: c) F9 t# _& f' b+ c- y
iphdr = (IpHeader *)buf;
9 G3 L1 p8 d! r2 r5 Z' w) p
7 n. Z& v& y0 }/ A9 kiphdrlen = iphdr->h_len * 4 ; // number of 32-bit words *4 = bytes
% t6 w I$ k5 |* d; m1 V4 ]- E5 q. C2 L" W% G. v
if (bytes < iphdrlen + ICMP_MIN) {
+ N- O$ d8 e1 P: ~printf("Too few bytes from %s\n",inet_ntoa(from->sin_addr)); 6 a, I) I' s2 S: u/ j! s9 z
} 6 ?+ s1 M/ F0 e ^+ J
# J! {! r/ R9 F8 W$ b$ y5 Xicmphdr = (IcmpHeader*)(buf + iphdrlen); 9 Z6 z/ Z; z1 l/ E
) ^3 l# k' i2 P
if (icmphdr->i_type != ICMP_ECHOREPLY) {
$ x0 m. z7 T) |9 ~& t+ w2 Xfprintf(stderr,"non-echo type %d recvd\n",icmphdr->i_type);
: l% W$ H3 T+ r0 `# yreturn; 9 L! p3 E: R. D$ z' p$ d9 w
} 6 M) S' K% Z- f8 w3 m
if (icmphdr->i_id != (USHORT)GetCurrentProcessId()) {
- f. D& A" V. f7 n% r! O6 \fprintf(stderr,"someone else's packet!\n"); # w0 a, I( L: y1 a
return ; 5 R( ?/ W3 _0 d8 q7 b
}
! U3 t: t+ s- G: Uprintf("%d bytes from %s:",bytes, inet_ntoa(from->sin_addr)); * K3 e. c3 ]9 b& w" K. P p" c
printf(" icmp_seq = %d. ",icmphdr->i_seq);
, y/ @1 h9 R2 q! @9 V; c6 b: E {printf(" time: %d ms ",GetTickCount()-icmphdr->timestamp); 2 a% b, i- ?! u* _ ?+ ], O, @6 f
printf("\n"); 8 ]% O2 d* Y/ F$ P' {2 ]
. _1 d9 s1 X5 H2 t; n} " f8 L" e# \2 G
9 ?# y4 J6 p8 g* c" T5 r( B. A3 p
USHORT checksum(USHORT *buffer, int size) { 8 D' v g& e! U% V* Q: t6 a# d
5 H! f2 h2 w' K" ]# z) tunsigned long cksum=0; 5 \( t$ v" U* J
# g7 ^. u: Z) A8 v9 j
while(size >1) {
* s2 i( M/ G1 }; r) {0 f' t) z" Hcksum+=*buffer++; / K2 l+ C3 d' H! O. A
size -=sizeof(USHORT); 1 H$ [& L/ K0 |. A1 Z
}
7 {; m" J1 X" O2 e
7 X% a9 [% m2 \' `0 P; J9 `# Zif(size ) { " a* B" H# Y+ j7 I Z" ?
cksum += *(UCHAR*)buffer;
9 w6 |* m/ ^$ X" Q- ~} * f1 U+ r" F0 B8 f
4 x) w* s d3 r; {- J
cksum = (cksum >> 16) + (cksum & 0xffff); 3 L; a2 l# n: `. l, L
cksum += (cksum >>16); ! e8 A4 q2 n2 u
return (USHORT)(~cksum);
1 h, b7 Y/ s$ m5 \; d- g) m}
$ a8 m* O! U" ?- w+ I- T/* 1 r: F# v1 O9 ?$ a) U0 D
Helper function to fill in various stuff in our ICMP request. 1 N7 b: N# c- ?5 o1 D. y2 r
*/ : l2 c' r* w4 w7 D
void fill_icmp_data(char * icmp_data, int datasize){
7 M' j& @- b/ u% H7 h
( Y1 Z. i. `7 X& _; UIcmpHeader *icmp_hdr;
7 o7 _' j0 I7 z! echar *datapart;
! `- m p4 d8 t0 B: ? z
7 r& ?+ S& s; [' [! ]icmp_hdr = (IcmpHeader*)icmp_data; ; O, x) |- D9 `
+ D6 B7 Y! i, [, q" x. Yicmp_hdr->i_type = ICMP_ECHO;
C( [3 ~% s0 k# E9 A! M6 a/ F0 y' licmp_hdr->i_code = 0; 8 z) P" Z9 y0 M/ z
icmp_hdr->i_id = (USHORT)GetCurrentProcessId(); 2 Y; ?5 d6 c9 E8 t" y; H
icmp_hdr->i_cksum = 0; 9 ?! X$ r3 \% _6 b* E& T8 t
icmp_hdr->i_seq = 0;
( {2 G7 c0 C: {$ x* v/ v. H* w. ?
- m3 ?2 V. T2 F% k$ @datapart = icmp_data + sizeof(IcmpHeader); ! a8 E# }, x! L' g* B% d! E
//
3 ]# \0 N: @* b& p// Place some junk in the buffer. 5 _; P$ u. k6 g: O2 x
// ; ? M3 l- R0 L; H) x
memset(datapart,'E', datasize - sizeof(IcmpHeader)); 8 a8 G9 V. w: L( E
$ R4 d& y9 Z8 ~, U+ ?9 q' P} |
|