|
|
******************************************************************************\ 2 m9 Y) r H; W
* ping.c - Simple ping utility using SOCK_RAW _( y) x% D4 A! w. A
*
" f5 q( D h$ R2 s* This is a part of the Microsoft Source Code Samples. , S n% `$ i a' M- A, ~
* Copyright 1996-1997 Microsoft Corporation. 4 k) f, b$ i, X" x9 {% X
* All rights reserved.
: V4 I2 b1 r( E% e5 m* This source code is only intended as a supplement to
5 L! G; n! L, R# F8 v0 o" g* Microsoft Development Tools and/or WinHelp documentation.
8 ^4 j% x* _; `" M$ f5 R% r* See these sources for detailed information regarding the
, X9 [) R" p( `0 k* Microsoft samples programs.
* i/ T. _5 {7 h\******************************************************************************/ $ v, |+ [. i% O, h, Z4 H1 N
. I" T. k, b( o' H# h4 n
#pragma pack(4) ; N( K2 m2 F5 K6 u R
" d& g* h7 P/ D: B) e
#define WIN32_LEAN_AND_MEAN
! u' [: A% Y0 R' {+ A$ X) ~#include ; _; i8 B" U/ r" h/ o
#include - t8 e7 z6 T$ R
#include 1 s$ g- E: s- q+ v' Z- q3 X% t+ p! k
/ G4 \$ |! g& _) A. s#define ICMP_ECHO 8
6 P$ D7 g. Y* [# I#define ICMP_ECHOREPLY 0 ; f/ ~& e% A o& m' |5 C
2 W( Q5 G1 ?9 c1 @" C#define ICMP_MIN 8 // minimum 8 byte icmp packet (just header)
, V2 f" Z4 S& E+ c( j8 \& o0 J' T8 N6 z2 {$ Y& q% M, Q
/* The IP header */
+ z( b3 `5 a# Vtypedef struct iphdr { ) A% u% J5 n; |3 M0 D I
unsigned int h_len:4; // length of the header Y, s+ S! c( @) e: N
unsigned int version:4; // Version of IP - n0 ~" l( W/ C; K# ~2 x0 q- n
unsigned char tos; // Type of service
( d- c* _, Y$ K! {1 eunsigned short total_len; // total length of the packet
8 ], ~# {. \3 ]# @, E/ F, Wunsigned short ident; // unique identifier
0 Z6 M" s/ n# i3 C% i1 b/ {unsigned short frag_and_flags; // flags
8 r5 a2 V% \5 Z1 \$ U$ U. Gunsigned char ttl;
6 p0 l6 z# Z. v- Punsigned char proto; // protocol (TCP, UDP etc)
( d8 v3 m' U5 A; Nunsigned short checksum; // IP checksum 1 R' I3 \4 I# z/ o' M
8 K. w: m! } Q
unsigned int sourceIP;
$ N+ J; P8 K; u- lunsigned int destIP; 7 Q% s& q# q% R- D/ R2 p, b
6 a, e4 P0 ?3 X" `3 E3 T
}IpHeader; 7 t+ I- }3 u6 K# X& _
! t3 I0 Q1 D3 g7 w" s// ' |" t! h+ B0 m" B" D
// ICMP header
- f+ r% U; A0 t//
4 F$ l4 v5 S# ttypedef struct _ihdr {
$ d) n0 K/ w3 E3 L. iBYTE i_type;
1 U; s0 }$ _" {# v* N7 [7 r+ bBYTE i_code; /* type sub code */
0 I9 Z I6 E% R/ |0 yUSHORT i_cksum;
9 r' t/ p* Y2 a2 L4 e; u s/ SUSHORT i_id; % \/ w" z( @: Q: X Q) n8 j
USHORT i_seq; 7 |9 j/ T; [. B
/* This is not the std header, but we reserve space for time */ - K2 r6 d! I: x) N/ k
ULONG timestamp;
2 j3 b$ f/ Z* [* ^! B2 ?. _# w}IcmpHeader;
' I6 Q3 t/ V2 Z: w) x9 Z/ Y; m/ p0 B' n) V# o
#define STATUS_FAILED 0xFFFF
$ O! C6 H l" K0 f#define DEF_PACKET_SIZE 32 8 _6 P; V. E* L$ E4 Z* b' p5 y
#define MAX_PACKET 1024
6 Q$ @' _( e# n( V, \5 z8 Q0 P" u+ i8 o! r f4 T7 s' Y
#define xmalloc(s) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(s)) 4 E n6 H: `3 c6 r
#define xfree(p) HeapFree (GetProcessHeap(),0,(p))
5 t; y! A* c' Z$ c$ h
% B; ]. L7 ]' ~/ w6 U* X$ n* Kvoid fill_icmp_data(char *, int);
9 N7 N6 {7 y. ~6 h! q4 ]; xUSHORT checksum(USHORT *, int);
; Z1 c5 h2 T4 wvoid decode_resp(char *,int ,struct sockaddr_in *); ) A' \! O# W8 R8 D, j. N
" G7 Q: r2 H( k/ n6 _7 M
void Usage(char *progname){ 8 t3 D# q1 ~' G/ d
6 c1 L: v$ Y& y! K8 Yfprintf(stderr,"Usage:\n");
. Q' `3 u% P' x: Bfprintf(stderr,"%s [data_size]\n",progname); k* E7 M2 r! c* x
fprintf(stderr,"datasize can be up to 1Kb\n");
' @. @0 h) v0 NExitProcess(STATUS_FAILED);
1 y9 ]/ W* _0 @. ^: @* w
$ H8 @4 E" s2 Z} ( F2 q- H2 i, r% I1 l9 e
int main(int argc, char **argv){ . X; j) m( Q8 ]5 }0 D6 m
" O# j' Z3 z" rWSADATA wsaData; 9 a' v' \. |4 o- {* h& a
SOCKET sockRaw; / l. O% `( u# M9 {# S3 T
struct sockaddr_in dest,from;
0 L* ^/ g* U5 U& astruct hostent * hp;
" P# w( d" v" N8 R* I t t% Mint bread,datasize; % I/ {' \) s2 s$ l. ]4 Q
int fromlen = sizeof(from);
9 r! F( i! ?* D/ Z! o! r7 \int timeout = 1000; ! L* c6 ^# S: ?+ i; k
char *dest_ip;
v/ k& @7 c* v$ k$ r8 J9 ?; Qchar *icmp_data; Y% Y( g3 A2 P- E' b5 Q% c
char *recvbuf; 0 W+ c& c- A/ q. Y3 }! f$ V
unsigned int addr=0;
/ ^$ L' e+ g1 N6 d! I' V6 |( x( k" q7 r. HUSHORT seq_no = 0; $ X) V0 Z, O M# f8 q, R- z& Y; _
9 y( { L( g2 I
if (WSAStartup(MAKEWORD(2,1),&wsaData) != 0){ 2 _( w7 H5 l$ z' D5 `
fprintf(stderr,"WSAStartup failed: %d\n",GetLastError()); * b7 W a% F _2 ?) y
ExitProcess(STATUS_FAILED); / ^/ W5 G+ c, X0 {
}
/ J) \8 P9 j2 {" b
! b: q+ i& O7 D3 Dif (argc <2 ) {
! o* {( Y$ H% PUsage(argv[0]); 9 F* a) V0 C: k% z/ ?% \
} . }2 J }5 q" i3 ^( x
sockRaw = WSASocket (AF_INET, ; p6 ?2 S) h( N! a5 g# ~
SOCK_RAW,
4 M; e9 G& q/ B F3 AIPPROTO_ICMP,
X& ]$ N" Z% w* Q9 v* TNULL, 0,0);
: v- m. f/ @. b
1 M9 f3 m% C9 i) D8 a8 W& Kif (sockRaw == INVALID_SOCKET) { / x% f. z. W' V$ w3 k0 t
fprintf(stderr,"WSASocket() failed: %d\n",WSAGetLastError());
4 j6 _4 i C5 IExitProcess(STATUS_FAILED); 1 L$ R& g* m, p% B7 z% S8 |* Q' f
}
# S8 y' e) W# P( Fbread = setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout, " k: R- P4 u# m/ p9 w
sizeof(timeout));
! x \( h0 p! u! Yif(bread == SOCKET_ERROR) {
9 ?$ R$ |7 `! g3 A3 h+ xfprintf(stderr,"failed to set recv timeout: %d\n",WSAGetLastError()); 8 B# t N# V4 N0 P5 J5 j
ExitProcess(STATUS_FAILED);
- @. f' z; \6 K) ^}
: L: z- L9 u4 ]4 Y9 etimeout = 1000;
( R1 y0 V; ]1 F( B! e, sbread = setsockopt(sockRaw,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout,
% ~; r: _4 e; z# ~: P7 n1 s; csizeof(timeout)); 4 \- f/ G9 T3 E! ~
if(bread == SOCKET_ERROR) {
* ?6 { o h/ Q/ ~, u+ U8 sfprintf(stderr,"failed to set send timeout: %d\n",WSAGetLastError());
2 G+ j8 g* h7 y6 u2 J% GExitProcess(STATUS_FAILED); + j* T# B4 H/ s( j L
} 4 E/ U# J& N3 H3 g% r) d; I1 r
memset(&dest,0,sizeof(dest)); 3 u. u. W5 X4 z$ W2 m$ p
6 e: r! l% l. I+ `) i' A' Dhp = gethostbyname(argv[1]); P/ O ?/ M( T( R: r
; F6 o8 A' `# f( C: b/ D {
if (!hp){
M4 Q' E( P' a% w0 ^! }8 oaddr = inet_addr(argv[1]);
F C' A6 T" | B}
- S( y* ~) _/ w9 xif ((!hp) && (addr == INADDR_NONE) ) { 9 d+ l7 \/ I7 y y+ ]" b2 ` m% F6 [
fprintf(stderr,"Unable to resolve %s\n",argv[1]);
( U9 A5 k6 h2 z3 A! F3 gExitProcess(STATUS_FAILED); 0 Z+ A; w8 s3 R8 E+ Y
} ) T5 \+ G/ u$ w" S2 o: W8 Y) n
9 d) b- ~8 [# l8 @. s
if (hp != NULL)
' ^, S2 }3 ~& {* Q: Imemcpy(&(dest.sin_addr),hp->h_addr,hp->h_length); # U$ x: K/ C- W) \1 c0 ]; B8 F
else 7 M. Y/ ~ V# d, b, @
dest.sin_addr.s_addr = addr;
+ a- ?. d" U4 H. E# ]1 a4 [: g8 |. Z" I J) e# S6 l% x B
if (hp) : L1 a. C: S _+ `
dest.sin_family = hp->h_addrtype;
: G7 \5 M9 e; ~ y. c! c/ Qelse & x/ e1 U% ]9 C7 g, r
dest.sin_family = AF_INET; 0 Y% }1 H# Z* |5 z
, K l+ S( ~& L% y$ ^" Z. gdest_ip = inet_ntoa(dest.sin_addr);
& ?) \9 |+ V3 C0 L# s$ s' {' x' F; v0 t+ L
if (argc >2) {
# c) S+ }& _* J% |datasize = atoi(argv[2]); / d, F1 |# \3 b* d7 I$ r
if (datasize == 0) - R- D* \6 e: i! M% F
datasize = DEF_PACKET_SIZE;
( c# L( v; ]8 z3 C" c
/ R$ l. ~; F* X2 E% ]# _0 N- r3 d. o} # e3 ]& Q: z- X) @9 V: I* c( f. k9 D
else
3 W5 I5 Z6 S& [+ o$ ?datasize = DEF_PACKET_SIZE;
/ E% f* v' }, s" E* h4 Z* a8 A0 n0 Z7 }6 w, n8 m
datasize += sizeof(IcmpHeader); 9 {2 O. p0 j0 m5 d: X
2 w- q' j+ o" p1 e' Eicmp_data = xmalloc(MAX_PACKET);
4 N$ v: ~1 O/ C3 y5 u! Krecvbuf = xmalloc(MAX_PACKET); - F3 a8 a; O* Z
4 D' c- r, d+ t; e6 H" P
if (!icmp_data) {
. [1 t( M' p6 ?& y1 `. Xfprintf(stderr,"HeapAlloc failed %d\n",GetLastError()); 7 i1 ?; D- L8 z$ x" i/ h7 t0 S
ExitProcess(STATUS_FAILED);
0 g4 }8 y" ~3 M3 t2 ^4 |}
. X! _7 N/ P: j9 Fmemset(icmp_data,0,MAX_PACKET);
0 O/ w+ D( j8 Rfill_icmp_data(icmp_data,datasize); # g5 e" V* v% @6 y( m2 Q
4 }. x, j/ u# q, h- X2 |! a8 uwhile(1) {
% }) @; b0 Z- m7 [* \- x" K/ x& j5 Cint bwrote; 8 B5 V) r6 ^; z, J$ ?
$ G/ N1 R4 V# N \((IcmpHeader*)icmp_data)->i_cksum = 0; ) }" V! a: S% c4 [
((IcmpHeader*)icmp_data)->timestamp = GetTickCount();
% F6 v- E1 e5 S# U N( M: w- I/ I3 Y
((IcmpHeader*)icmp_data)->i_seq = seq_no++;
( |$ j7 z- J8 E((IcmpHeader*)icmp_data)->i_cksum = checksum((USHORT*)icmp_data, 5 b! Q8 ?1 O, R& i5 C
datasize); $ O: D! x# I8 U, |) l# E* {
/ w. [6 v z) p8 K
bwrote = sendto(sockRaw,icmp_data,datasize,0,(struct sockaddr*)&dest,
# N W& ?2 q2 }' asizeof(dest));
( e9 z+ D l) [% a+ W0 zif (bwrote == SOCKET_ERROR){ ' |- Y$ C" E$ {& x% B9 L% ^
if (WSAGetLastError() == WSAETIMEDOUT) {
0 y% O0 B( ^0 M3 G4 I5 zprintf("timed out\n"); + }0 S- E" u* v6 s$ y S
continue; : U& u- Q9 @. L: L5 U
}
7 p( K/ h4 z5 X9 \, Tfprintf(stderr,"sendto failed: %d\n",WSAGetLastError()); 8 E: d2 _" j1 b
ExitProcess(STATUS_FAILED); ' P4 B. u, X& Y6 o& j9 y, r
} 3 s1 S: F- G: x6 s" L9 ^
if (bwrote < datasize ) { - ~& H& ^; Q: W2 C8 `4 g' S+ v$ `
fprintf(stdout,"Wrote %d bytes\n",bwrote);
1 t5 q/ b2 _' n+ U: Z( k% W} 1 ?6 p6 o* F) d* A8 ?- ]; L! s0 s
bread = recvfrom(sockRaw,recvbuf,MAX_PACKET,0,(struct sockaddr*)&from,
! F1 |! a# ?& c8 q+ L- s$ f, ^' {; @&fromlen); " f& L% ~' q* u
if (bread == SOCKET_ERROR){ 3 Q0 g8 @( m3 x- J. z/ V
if (WSAGetLastError() == WSAETIMEDOUT) { , b; O- _& ?# k0 O+ I8 j2 K
printf("timed out\n");
3 y! D- o+ N) Dcontinue;
, }. R" C2 r8 m. _4 r}
8 j$ q7 t; C- @5 Afprintf(stderr,"recvfrom failed: %d\n",WSAGetLastError()); + Z `0 q6 [1 H4 \! ]" Q6 c* N4 `
ExitProcess(STATUS_FAILED);
6 r, B P, W2 e p' S$ s" _}
$ }& f0 z/ f% R$ jdecode_resp(recvbuf,bread,&from); ; V; R) C8 `& t' X0 l/ W+ H
Sleep(1000);
9 f9 b2 ] f3 R: Q2 K7 P
4 [% _6 n1 l: }. [8 D! G L3 A3 w" [, G} 5 c; D4 m& m9 {; S. Z$ i/ b
return 0; & `1 [3 o, ?! D. ~2 L
. H' d6 l% w& R0 U! R4 y
} : _: A/ X5 O s4 z! Y" e4 l5 O
/* + ^8 x6 o" C9 w: F3 A
The response is an IP packet. We must decode the IP header to locate
/ c h4 ?# n, dthe ICMP data
" u5 U: G( Y: R3 ]! J4 |( y6 d*/ / f4 o# F+ {) h; D
void decode_resp(char *buf, int bytes,struct sockaddr_in *from) {
/ r/ I+ v% }7 ?
3 _: |" ~# A8 `9 g7 a, h# r* TIpHeader *iphdr;
9 T4 k. ?6 m' }" h( l1 [& t: qIcmpHeader *icmphdr; " u+ Q0 T) H, e
unsigned short iphdrlen; 3 Q% K9 Z% I" E* Q! D& {- O
4 r1 S( Z5 D; F9 ^/ a1 ^
iphdr = (IpHeader *)buf;
( K! k0 u5 T. R+ f, g) l9 u) _. B: Z! _
iphdrlen = iphdr->h_len * 4 ; // number of 32-bit words *4 = bytes
; y/ N' ]8 N+ O& y: ]2 }. ]1 o4 }+ }) A$ F/ y! d
if (bytes < iphdrlen + ICMP_MIN) { : @% B1 m" N8 ]# m3 \3 z
printf("Too few bytes from %s\n",inet_ntoa(from->sin_addr));
5 t# l! I" A( G# k# K}
2 @" B. B _9 d
/ Y' ~: s3 F! g3 \; R% S1 dicmphdr = (IcmpHeader*)(buf + iphdrlen); ' x/ m) \2 x8 H7 f/ b& M. Y g
1 R/ m. A0 K, V4 v
if (icmphdr->i_type != ICMP_ECHOREPLY) { . h3 C9 `- t; ]
fprintf(stderr,"non-echo type %d recvd\n",icmphdr->i_type);
( p" H$ N6 m& Oreturn; 8 k/ i0 c8 ]- T' p# B8 }
}
( m( }4 }4 r. j+ K, Hif (icmphdr->i_id != (USHORT)GetCurrentProcessId()) { % [3 v/ U; K7 Z4 H* X- f
fprintf(stderr,"someone else's packet!\n");
/ [: ?: h: S( A1 V ereturn ; - l9 N- H, Q# F) X
} / D& E" S* m/ f6 l$ U/ R3 M
printf("%d bytes from %s:",bytes, inet_ntoa(from->sin_addr));
0 Y2 C( [! D3 e2 E2 x) E' v! _printf(" icmp_seq = %d. ",icmphdr->i_seq);
" l* k" ` L( t# y' S' y9 tprintf(" time: %d ms ",GetTickCount()-icmphdr->timestamp);
; D$ k: I# w) [. l \* V' I. ?printf("\n"); % q) i# e/ N/ c3 q- ^# j8 @
7 c8 s, I: l' J. v! m8 f& `} - ^3 G. k% p8 N) O4 C5 x
( l9 G# C2 ?1 h# ?. m
3 {( w7 J0 ~/ p* H3 kUSHORT checksum(USHORT *buffer, int size) {
7 [! s* Z" r' q' n, _7 f6 m( c$ n2 o' k1 R: q+ O$ C
unsigned long cksum=0; " K# f& W% ]* m( `- M" n
: d6 d! V: u `& J
while(size >1) {
# W5 V$ _ l( Z& i* n+ t: t- Ycksum+=*buffer++;
) t7 O* l1 i: C8 o9 y/ lsize -=sizeof(USHORT); " g# I5 s$ q! s8 F, i" V2 H
} 5 b" R' r, F0 u% C/ h- P2 B
/ S g1 w) T& i+ n- {, Nif(size ) { / R2 L; j% G! b2 G
cksum += *(UCHAR*)buffer; $ W" t0 \2 J7 z1 y7 {9 F$ C
} 7 T- ?3 Z! Q+ ~/ g' |1 L- T6 ~
. u% d! O6 T& r8 k" v+ _) vcksum = (cksum >> 16) + (cksum & 0xffff);
5 }+ p; a- h2 O7 T$ `cksum += (cksum >>16);
7 F. g9 W. P( U8 Y3 S. E8 ]return (USHORT)(~cksum);
$ u0 _8 ^1 N Q! ^7 _" R% a} 0 c- ]3 Q% ]8 w2 F0 P
/*
I5 \' g) [ L- Y/ Z# kHelper function to fill in various stuff in our ICMP request. 5 T/ K4 }' i, b- x- k( }
*/ - c+ p# N: Q0 V. t, R3 E5 ]; }. t) A
void fill_icmp_data(char * icmp_data, int datasize){
( ~$ V! J* [# t; ^) H- l, B/ O- H$ m9 j
IcmpHeader *icmp_hdr;
. n2 g! |9 G( _8 l& s1 g8 achar *datapart;
9 b! m3 o, Y4 M; [
8 Y8 Y) ]% }9 L! r, e* N! licmp_hdr = (IcmpHeader*)icmp_data; 6 P7 \1 L" y1 x/ d5 X, @
9 g5 @- \5 l) U* Y& k; ?. aicmp_hdr->i_type = ICMP_ECHO;
1 p+ c; B* Z/ Micmp_hdr->i_code = 0; 7 G/ w: f3 I' D2 i( K
icmp_hdr->i_id = (USHORT)GetCurrentProcessId();
3 j7 ^: [1 m" J' m' M/ P, zicmp_hdr->i_cksum = 0; 1 Q M1 }- e# }( B) E3 v
icmp_hdr->i_seq = 0;
" e" b: s& p2 H7 O6 c( k: h: ?& |8 }% x& R) q% i) ^
datapart = icmp_data + sizeof(IcmpHeader); & T @9 P, {) O: q$ `" R$ [
//
. O/ H# ?1 J/ p" T7 u1 H4 n// Place some junk in the buffer.
( o o6 e2 U6 b v; q// ( k- ^" x9 o: n
memset(datapart,'E', datasize - sizeof(IcmpHeader));
3 S" H# ? B& e# v6 e6 U. F3 u0 r6 {" m& D: ~; w4 b8 P! f5 n
} |
|