|
******************************************************************************\
+ T0 `8 I, g1 Z* ping.c - Simple ping utility using SOCK_RAW
( t2 S0 g; {( E( A# P( r$ A7 ~*
; @. [- Y5 Y+ X* This is a part of the Microsoft Source Code Samples. 9 ^) Q1 e5 [, B m: S" Q+ h
* Copyright 1996-1997 Microsoft Corporation. 6 d) u8 B& D4 W( F7 i
* All rights reserved.
0 D$ B- I3 n0 W3 w* This source code is only intended as a supplement to : X) Z2 i# f$ d8 v: L
* Microsoft Development Tools and/or WinHelp documentation.
# c9 R6 U+ s( J* See these sources for detailed information regarding the
! R8 J+ p; l. D5 x7 }* Microsoft samples programs. 0 i1 i1 l3 p. t4 e$ \
\******************************************************************************/ * u9 C6 J) i( p3 `: V
8 c9 ^' U7 Z0 Q: \#pragma pack(4)
5 o* K+ I' D& T1 Y: d! f3 E6 l: t+ `; s
#define WIN32_LEAN_AND_MEAN
: E' d- g- f7 g#include
9 k$ o& b! w* p6 f. K5 Z n#include 9 o: b! x5 j. o' A1 U3 ]& h3 M. I2 G1 Z$ {
#include
6 a C5 A( `3 B, k6 @* B8 }1 ]- `9 ~( r
#define ICMP_ECHO 8
8 r2 H" U8 ?8 e, ?' T; t3 W- g0 [#define ICMP_ECHOREPLY 0 ( v: X/ f. k/ c* o4 \
& K0 a2 @* x: }+ x0 a a$ M- h
#define ICMP_MIN 8 // minimum 8 byte icmp packet (just header) ! Z m" q( h; j7 G, ]
6 _6 @0 `; F7 z9 ]& @
/* The IP header */ % p. c! J7 D# Z. @1 I
typedef struct iphdr { $ P9 U3 F5 F/ z2 ]
unsigned int h_len:4; // length of the header 9 K5 b3 m" Y' d# w A5 e( F6 h
unsigned int version:4; // Version of IP
( Z9 _* i; u$ S* y) ?unsigned char tos; // Type of service $ j/ ]9 r# Y, h/ N1 v0 _8 ?. R
unsigned short total_len; // total length of the packet & J0 q% i4 {4 k& e3 R- W
unsigned short ident; // unique identifier
& |2 ?3 u K/ f3 @2 B; D& W3 eunsigned short frag_and_flags; // flags 6 q$ G% K& x9 ~/ h# Q# l/ v5 ~9 l) e
unsigned char ttl;
9 m/ J3 [- q* r; {# Wunsigned char proto; // protocol (TCP, UDP etc) . s7 ?5 X0 Q8 l u. m1 c
unsigned short checksum; // IP checksum . O/ @* J2 M( Y# w5 q& ]6 n
' l' I" g3 t% ~7 t3 `
unsigned int sourceIP;
; A5 C: P& c+ M! qunsigned int destIP; ( ?8 T$ u/ |+ w: Z) g
. K* r6 k/ G" Z; T1 `}IpHeader;
9 n/ `/ Q) `: y
2 y' S- `, M1 C4 U# j3 a// g/ A6 v1 f+ `5 j4 h
// ICMP header ; H" h, |0 U4 N1 A# ?; k
//
: `( U* M2 H% J( Q7 F2 ] D! {typedef struct _ihdr { 9 E0 m* a) P: u7 a6 [5 |
BYTE i_type; + H7 l0 A$ M( X1 u
BYTE i_code; /* type sub code */
5 D, U, u' |+ H0 H! k* Q$ ?USHORT i_cksum;
7 }& U5 ^2 x+ J( A- a9 h: ?USHORT i_id; ! W0 e# ^* L5 y, M
USHORT i_seq;
# ^1 @3 V; T' I9 Z6 O/* This is not the std header, but we reserve space for time */
7 n5 C' G w, PULONG timestamp;
0 j8 @5 Q& _+ J p}IcmpHeader;
- a8 c' ~! c: E6 Y
0 x5 E& ~+ @% _0 P0 f' }- Z( m#define STATUS_FAILED 0xFFFF . V& k# O* o* }
#define DEF_PACKET_SIZE 32 2 }0 P" t- z6 a F
#define MAX_PACKET 1024 / J# D R# s6 w; ~: p# H
7 |, s: _/ X4 }#define xmalloc(s) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(s)) . a9 E( B; q0 w2 x; ^2 |/ y
#define xfree(p) HeapFree (GetProcessHeap(),0,(p)) ) H! M6 t6 x) x! b5 u% X/ i- |
+ [+ w6 Z* F. y: v6 J$ H
void fill_icmp_data(char *, int); 4 Z' r& L: Z* h3 A
USHORT checksum(USHORT *, int);
! R2 |5 x! m# g* X2 ivoid decode_resp(char *,int ,struct sockaddr_in *);
$ X. O$ @0 Q1 Y9 D3 L
% m2 A6 @8 Y; m2 bvoid Usage(char *progname){
. E' `0 p1 C* W% `! d% ]
4 q# d( ?6 S1 g N c; ffprintf(stderr,"Usage:\n"); , q. a4 B: Y" X& s) _2 U* p: B
fprintf(stderr,"%s [data_size]\n",progname); / I x; {; N, z) Y3 K& w$ Z/ k) b
fprintf(stderr,"datasize can be up to 1Kb\n");
! W. O$ v! H' X1 q: }9 l9 q& BExitProcess(STATUS_FAILED);
4 S+ M" |' N9 {. v2 O5 h7 U' s1 {' n* ^$ `5 X/ p
}
0 g" V2 F( j3 A+ F* bint main(int argc, char **argv){
; R- G6 F$ \3 A7 c# l; g
* b: \6 h/ [# gWSADATA wsaData;
! {2 t) C: p2 e# @4 M1 q' J+ Z% jSOCKET sockRaw; : Y6 ~# V' A2 F# W3 o4 @9 r
struct sockaddr_in dest,from; ( G, Q- _! K4 e) z( Z8 P4 i
struct hostent * hp;
; P$ R& P6 _: A/ `8 v2 X5 ^int bread,datasize; 6 I6 ]' G2 G6 }6 b' v! s: p' ?
int fromlen = sizeof(from); & w# u& H" ?/ J# j# @4 c& U
int timeout = 1000;
8 O* Y" J! a8 Wchar *dest_ip;
$ z% [( c0 J2 G' n _$ W- F- `char *icmp_data;
2 l8 T ?# w$ p) A, S2 l1 Vchar *recvbuf;
$ g& ~6 N+ X; z1 M6 z7 e7 [9 zunsigned int addr=0; 4 ^; w4 W8 j; p, g9 H. t
USHORT seq_no = 0; 7 [4 L* H7 L0 D5 ?) b/ H% Q
4 r- R2 a2 F/ ^ ]$ xif (WSAStartup(MAKEWORD(2,1),&wsaData) != 0){
0 J- M! ^. X8 Mfprintf(stderr,"WSAStartup failed: %d\n",GetLastError()); + ]/ a( V5 {/ t; {; M+ i9 D
ExitProcess(STATUS_FAILED);
+ D+ H3 x: g# N7 O" \! y- Z}
( g; [! ]9 p$ s0 S7 `( V& U! t7 p3 y/ m) |7 j
if (argc <2 ) { # I5 @: m3 M b* |5 [
Usage(argv[0]); ; m1 t- `4 @8 E3 ^- y
} 3 t! [- K: K$ t6 r+ _/ f' f
sockRaw = WSASocket (AF_INET, ' n @. y3 \. }" g2 `' }
SOCK_RAW,
( `$ {4 i9 \6 o* x2 _7 f' @# v* A0 cIPPROTO_ICMP,
* ~/ m% D# Y9 J% r9 w9 y7 M) }NULL, 0,0);
8 _% s0 b! \) e2 v& c3 y' \7 Z" N$ V' ]
if (sockRaw == INVALID_SOCKET) { - _+ R5 ]4 X7 Y
fprintf(stderr,"WSASocket() failed: %d\n",WSAGetLastError());
9 K7 [$ @3 v6 ]) k! D' cExitProcess(STATUS_FAILED); : V, X/ l2 k4 n
}
+ K& r. n" _- @( H2 Zbread = setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout, 8 m6 u @3 z9 l, u) [; H+ j# g
sizeof(timeout));
. |, y1 i! I9 k- dif(bread == SOCKET_ERROR) {
: g7 O+ Z \0 }5 Z: X0 m, |fprintf(stderr,"failed to set recv timeout: %d\n",WSAGetLastError()); . e, H/ ^" o% j0 T5 b2 A, n( X! J+ [
ExitProcess(STATUS_FAILED); W5 O" f6 H7 m0 Q/ j$ t
}
, u7 ] D0 w; _- ptimeout = 1000;
% Q7 K: {. O& r! kbread = setsockopt(sockRaw,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout,
$ ]. E8 z3 Y" ^' Gsizeof(timeout));
1 j( ~ Q1 t/ ?# xif(bread == SOCKET_ERROR) { % x2 y0 y- z& r1 x4 l
fprintf(stderr,"failed to set send timeout: %d\n",WSAGetLastError());
/ V$ z" c g" jExitProcess(STATUS_FAILED); / m+ R7 d4 {% H+ q2 ?& @
}
t0 _: V m T W& q, Mmemset(&dest,0,sizeof(dest));
; d. L( ^; F" \
# c2 n' y- U7 s C3 p% zhp = gethostbyname(argv[1]); " j. b' ~% \1 ~
5 t1 P% [5 d+ [, g/ ]
if (!hp){
% d7 E+ P% n, K- a. ~: waddr = inet_addr(argv[1]);
3 b0 X8 L% H- V: N5 { I+ O$ i}
: }8 L$ F L1 B1 t0 Nif ((!hp) && (addr == INADDR_NONE) ) { . I" E1 d8 Q" K
fprintf(stderr,"Unable to resolve %s\n",argv[1]);
" e9 t6 K6 v6 H; C' L+ }ExitProcess(STATUS_FAILED); q* K# M3 N% ?5 o7 ^% R" H
} 9 W1 f6 V& W) \# G
# s6 O! G0 U+ X3 t* U' ?# Tif (hp != NULL)
% \2 q: j+ \ ^$ x4 Ememcpy(&(dest.sin_addr),hp->h_addr,hp->h_length); 0 K4 h$ u( V7 b
else
1 X! [8 u& S& k% b- |' O# j$ {dest.sin_addr.s_addr = addr;
/ {, X5 U, n3 ?4 c6 v. P% H
: Q& |7 k9 S. `! S5 K7 Iif (hp)
& V* ~# \! M/ X* |dest.sin_family = hp->h_addrtype; 2 k5 ~* F( w' ^* i7 i# h
else
" P. k1 a) Q" K8 k! A7 ]+ R0 P0 hdest.sin_family = AF_INET; " L4 R h% z0 `# J4 D
8 i* b% Q8 h' E/ S) P, v/ X) udest_ip = inet_ntoa(dest.sin_addr); , e E& T0 g5 i1 H
/ e; I0 v& V" D) b4 H2 h0 }if (argc >2) { - Z: e% X1 i! ?
datasize = atoi(argv[2]); : C, C% Q& K7 M; q
if (datasize == 0)
6 {& I+ o! [5 V9 S3 R! Kdatasize = DEF_PACKET_SIZE;
3 X$ w" b- o9 ^, e2 q& i9 p8 C8 t. e: p, w* v* u% E# @3 F2 W) P
}
: Y' D T% ]6 V6 B: relse
% S. m0 g+ T% f1 [datasize = DEF_PACKET_SIZE;
8 p& J$ W. V/ N/ X# _
) O% H$ ]' g" }: G- i4 R* X6 I% tdatasize += sizeof(IcmpHeader); / P) A0 _0 S8 f# @5 \: b: J
9 S9 j6 t* ^0 ficmp_data = xmalloc(MAX_PACKET); . s$ u+ }( l! ]* q+ ?
recvbuf = xmalloc(MAX_PACKET);
! H: A9 R# m' j/ d Z. `
* H( r0 `! [1 @: J* rif (!icmp_data) { - c, v2 h6 T: f3 }1 _, N# g
fprintf(stderr,"HeapAlloc failed %d\n",GetLastError()); $ W) ]/ Y2 \; J" R
ExitProcess(STATUS_FAILED);
, R% N7 y6 `5 l) z! ~}2 p9 p+ \* J' K$ A; p1 r; L
memset(icmp_data,0,MAX_PACKET);
, b' @( B! w& C% C) F2 e" Zfill_icmp_data(icmp_data,datasize); 9 s: _4 A& t# J
$ T1 u5 _) h: h, Y7 j, w- Y7 l
while(1) { ( h1 m$ X7 q( {/ _. A; b* A
int bwrote; 4 M* A7 n0 G0 H
% a0 \! Y7 [2 w6 f5 z((IcmpHeader*)icmp_data)->i_cksum = 0;
: F& l) d8 y9 a: a! E) f% ^((IcmpHeader*)icmp_data)->timestamp = GetTickCount();
J8 e! `, s. @: t5 ^2 u4 Y1 D0 m7 y% g% B
((IcmpHeader*)icmp_data)->i_seq = seq_no++;
* E3 y6 m9 O" m8 a m((IcmpHeader*)icmp_data)->i_cksum = checksum((USHORT*)icmp_data,
- Z2 i: |6 h9 ^5 Y; }" ?2 fdatasize); 7 L3 R. \2 i# g7 R
. R5 T: t7 Y6 a+ q- K6 T$ h3 o
bwrote = sendto(sockRaw,icmp_data,datasize,0,(struct sockaddr*)&dest,
( e d* I" c+ S. _. f. Bsizeof(dest)); , s& q( K9 s' o
if (bwrote == SOCKET_ERROR){ 1 Q8 z7 r& f1 c
if (WSAGetLastError() == WSAETIMEDOUT) {
6 W6 _7 W q9 y3 q6 _9 W( n0 Vprintf("timed out\n"); f8 H2 E/ N2 z4 u/ Y
continue;
0 |/ l9 Q1 f! _1 |: i' [3 v}
# P- d9 a2 _$ [; e# X+ Yfprintf(stderr,"sendto failed: %d\n",WSAGetLastError());
]( F, r0 V* e3 H$ I8 mExitProcess(STATUS_FAILED);
, f4 D' P( L1 k4 d$ v0 ^" }9 u4 H} 2 X6 g, ~/ x/ V: b& \, C: ]8 M, o! h
if (bwrote < datasize ) {
) k$ _9 r; A' _fprintf(stdout,"Wrote %d bytes\n",bwrote);
h0 N) M9 r& k" w0 D0 u} 3 V3 m7 w! ^* I0 A, n
bread = recvfrom(sockRaw,recvbuf,MAX_PACKET,0,(struct sockaddr*)&from, 4 `, V* A+ V( O( R
&fromlen);
7 Y" w# F; O8 g7 Y% I/ x) zif (bread == SOCKET_ERROR){ 6 w; n: G* L8 b2 F
if (WSAGetLastError() == WSAETIMEDOUT) {
6 P) e7 X6 ^0 Y c4 lprintf("timed out\n");
5 h, s: Z; o F" s' vcontinue; ) r0 f( a8 G6 D& G! q' I
} 8 }; Y" o2 @( X$ P4 S1 N0 u
fprintf(stderr,"recvfrom failed: %d\n",WSAGetLastError()); ' r% @ X! a$ p# w* f8 e! W. l/ j" h
ExitProcess(STATUS_FAILED);
4 e5 [( `* q) l}
5 F7 Z8 u! H( o; Y' Gdecode_resp(recvbuf,bread,&from);
D+ a+ d5 k1 |! O1 Y) dSleep(1000);
4 U8 [2 g' q1 O' I7 P" }4 N3 Q! g; g& L. `
}
$ H3 e) @ {3 X) G8 T" Z" y' Nreturn 0; + R5 Q8 C" ]9 z# u+ c
1 i' k' Z5 g5 q! N2 P4 e9 P} 4 q7 ]" j! `5 t5 P$ Y
/* * m" J& B' t. v! c7 z* c; C% ]
The response is an IP packet. We must decode the IP header to locate
7 u4 I+ o5 n# lthe ICMP data
3 J* j, z& d9 N3 Q+ ?7 j2 W+ I- `*/
- y) b: S r/ c; |# H/ d6 cvoid decode_resp(char *buf, int bytes,struct sockaddr_in *from) { ( d6 f' u0 v2 U K- O0 t7 ~5 I, b
5 }+ n6 C" Q0 C2 z3 E2 x
IpHeader *iphdr; ( C+ q1 E5 ?: F/ Y4 u" S6 [' `
IcmpHeader *icmphdr; 0 `# u# j2 l2 s% H1 m6 E
unsigned short iphdrlen;
5 k. H! Q" k, K# V
% S* M8 f( M: {% Piphdr = (IpHeader *)buf;
* G+ t" U. a2 [9 a
0 J- w9 e7 @- l/ [+ i3 Jiphdrlen = iphdr->h_len * 4 ; // number of 32-bit words *4 = bytes
7 w# G0 G! ?4 _$ v2 X* b* F/ e+ {9 R* o4 t+ n" E
if (bytes < iphdrlen + ICMP_MIN) { 2 ]" {. m' W4 N# O2 q. c
printf("Too few bytes from %s\n",inet_ntoa(from->sin_addr));
) p, K7 h8 w& I/ W} 7 I# ]- t3 A/ Z- F C5 s% f) N
( I/ [; W; q4 b) [: [% ^* jicmphdr = (IcmpHeader*)(buf + iphdrlen);
* ^7 h0 Q" Q. ]( u9 t! V" Q
( e: e2 U2 R7 n+ ~0 r7 |. g! qif (icmphdr->i_type != ICMP_ECHOREPLY) { ( l0 B% w1 d6 C2 i7 B# q. P
fprintf(stderr,"non-echo type %d recvd\n",icmphdr->i_type); * x; }# E! }9 b/ U& M+ R
return;
" n' [$ B- x6 C- R1 ?} ; ~- C7 w, i. o% H! J! a: U
if (icmphdr->i_id != (USHORT)GetCurrentProcessId()) {
! L8 N( w/ W6 p' r* U! s3 sfprintf(stderr,"someone else's packet!\n"); 0 \& q9 t' Y, C5 u6 F
return ; ( R4 n" {) [ E4 Y
}
6 \3 f* n! H" ]. W) J* Yprintf("%d bytes from %s:",bytes, inet_ntoa(from->sin_addr));
: ?8 Q3 B# t4 ?printf(" icmp_seq = %d. ",icmphdr->i_seq); ; q9 g! d: j" J- v4 T8 H
printf(" time: %d ms ",GetTickCount()-icmphdr->timestamp);
4 ~' X7 J# a' k' p, ~% T; @printf("\n");
, y' p F/ b$ p& \
$ _6 f! O) a& V! X! B}
2 i4 W1 P5 q2 Q
5 |; E6 A4 r- M$ j5 X
! Y9 l; z. n8 ]/ p4 |USHORT checksum(USHORT *buffer, int size) {
( ^# S2 G( y1 \; E' k2 m N2 V& c6 K# O
unsigned long cksum=0; 7 @: X( b0 E0 I. P' V
- D, ~- a; l+ E, Y4 F
while(size >1) {
( V0 R1 A! j! E, A3 m, }cksum+=*buffer++; + H$ \: @$ e7 t/ }0 g5 Q1 ?
size -=sizeof(USHORT); ' R& E5 [1 h5 T8 M1 p8 O+ Q
}
: y' ]3 A' e8 L b5 X4 c* G/ {- I: j( n
2 @, t3 t% T0 B+ J% g3 Aif(size ) {
. g5 F( B& D( ncksum += *(UCHAR*)buffer;
! q0 V% X3 V- a1 U: J" P} 6 b: p9 d, I1 `& t# J0 }
9 R7 D' r% G8 O6 [6 [cksum = (cksum >> 16) + (cksum & 0xffff);
6 R4 x/ B$ l `cksum += (cksum >>16);
}# |$ @, ^$ y% V" qreturn (USHORT)(~cksum);
. x; c/ o. P/ o2 \# ?1 k} - \5 S/ n, a; H/ h2 z
/* ( J# ]! Z/ p7 A' U& H8 ~+ `0 D9 Q
Helper function to fill in various stuff in our ICMP request. ! g6 [$ W- \" }" _% \5 g
*/
1 L/ G: k; G2 U1 f. @5 C5 i q% ivoid fill_icmp_data(char * icmp_data, int datasize){
7 k+ M7 U& X$ l& e- P/ u. v7 `
9 p7 N5 f! ~/ g1 n7 T/ W% M, x( |8 UIcmpHeader *icmp_hdr; ) e3 C/ U1 N# T" P" _ n% r! Z
char *datapart;
: z4 e$ _0 s. r9 R9 o' j5 N' W3 d
5 B" s( y8 Q; u) t+ ~4 ], \4 _/ jicmp_hdr = (IcmpHeader*)icmp_data;
9 y$ D2 H4 g& g# H2 {/ q
- |! l5 ]; E3 ^) u, _icmp_hdr->i_type = ICMP_ECHO;
! q7 L! o6 F0 X$ ]- l* I3 _icmp_hdr->i_code = 0;
' H G0 H! {* m# ?' _( T) k/ Dicmp_hdr->i_id = (USHORT)GetCurrentProcessId();
3 t8 E1 B. g% ^. L) M z' x# Micmp_hdr->i_cksum = 0; # l- L) r. u, d/ q' ^1 I
icmp_hdr->i_seq = 0;
4 `( i# J& C) F8 V2 f+ c
( M, }2 N0 C& O* Q6 T8 Ddatapart = icmp_data + sizeof(IcmpHeader); O9 t R8 g7 o, O/ [1 V8 p _
//
* P4 v6 V# M& r( G' B" \// Place some junk in the buffer.
- O" x4 p9 X& \7 D7 l9 ?//
3 ]2 p% a! `9 ]% R* cmemset(datapart,'E', datasize - sizeof(IcmpHeader));
4 a1 M* _+ R$ A& z; p% d$ ~2 o' H% s( _9 Y6 p/ u5 w$ D
} |
|