|
|
******************************************************************************\
, ~; X: J$ K. _. s7 s* ping.c - Simple ping utility using SOCK_RAW * u" T+ r( R+ b: |( f
*
8 K- ^! z0 t% y! M0 P7 i* This is a part of the Microsoft Source Code Samples. ! f/ a4 M+ O& n" \' D* _
* Copyright 1996-1997 Microsoft Corporation.
+ d. U d0 F; e& l9 B3 X( g5 m* All rights reserved.
& T% }6 `' V3 o7 b* This source code is only intended as a supplement to # `7 Z1 a& D; a$ Z" N+ h
* Microsoft Development Tools and/or WinHelp documentation. ~7 U5 _. m* ?# M, G' |' n3 [6 A
* See these sources for detailed information regarding the
* W* i+ d- F( G3 {" D* Microsoft samples programs.
( b+ `$ @" E7 y& s) F1 p3 b\******************************************************************************/
: j. T2 M# v8 Q6 y( p' {% @, B2 A, s+ ?& ?! r& X) u- @! Y
#pragma pack(4) : Z7 g k+ U2 b+ ?% E" w7 k
b/ ~+ H7 r) ^
#define WIN32_LEAN_AND_MEAN + x/ {" H* [0 r6 S+ U
#include . v3 z( v6 _8 q1 g; M
#include " Y# |9 O- g/ M& w* Q, R
#include
5 y' @2 g7 v# r
4 ?$ \' I$ r9 ?7 c# k, j; a#define ICMP_ECHO 8
& M4 a1 ?* D$ R, e ]) p1 m#define ICMP_ECHOREPLY 0
$ q$ f5 _# y" s4 W1 |0 f: I
+ ]5 z m3 s, S# d( p* i: I#define ICMP_MIN 8 // minimum 8 byte icmp packet (just header) 2 ]! g% X& L* V. M) Z
9 L' r" L- D. [+ U6 m" x4 p
/* The IP header */ ; A2 C9 t/ Z) y$ ~. y
typedef struct iphdr { 7 K4 r* K# B; Y9 m: q. N5 S4 O
unsigned int h_len:4; // length of the header
* n, ? x$ ?7 @ A$ hunsigned int version:4; // Version of IP
3 ?$ y. R2 ?. c6 {unsigned char tos; // Type of service 4 d) k4 B3 ^/ l6 w# @" |* o
unsigned short total_len; // total length of the packet " T+ l% b6 a3 @, H4 l0 t
unsigned short ident; // unique identifier a* A/ @; B( x
unsigned short frag_and_flags; // flags 7 N" q" |+ |6 W, b) t2 Y
unsigned char ttl;
" x' \; Y5 p* y) w! Yunsigned char proto; // protocol (TCP, UDP etc) 1 @% K8 B( q. j5 O" o- N3 M
unsigned short checksum; // IP checksum
1 F( n! V% {; i2 W) K0 o
* `1 _# k h* z( kunsigned int sourceIP;
( l3 ]1 J% D |unsigned int destIP;
$ n0 _) A( R K7 y. [
g4 c; d1 V& j4 b9 |}IpHeader; ! O6 D7 ^9 X" }5 {& H
2 @! X6 ?" y7 t3 t
// / t1 d4 V) h h; h$ A
// ICMP header ; `& d2 [/ B5 _& L* J" X
//
; N1 J D0 j& d' E, _typedef struct _ihdr {
6 h( x: W# f5 E+ K" JBYTE i_type; ! `2 D0 j! k4 z; ] U8 i8 x
BYTE i_code; /* type sub code */
, b [2 `- e& A; n, DUSHORT i_cksum; ! \' Z% X9 i" z7 `
USHORT i_id; 7 d( D% `9 ]8 w8 ~
USHORT i_seq;
" c# R8 F8 @/ M4 F9 k4 B% ]9 y/* This is not the std header, but we reserve space for time */
" G. p4 B* D) i/ ~ULONG timestamp; ! |( t" X* _% n9 O U$ M9 n8 {1 S
}IcmpHeader; l: a, V6 L3 V9 l, G2 ^
0 y- X. c }; z6 p
#define STATUS_FAILED 0xFFFF T+ t" |1 |5 |6 g% q
#define DEF_PACKET_SIZE 32 " o8 J/ W& ^) w9 h7 L# U" L
#define MAX_PACKET 1024 0 e! l4 ~% L% H, T' N4 T# g
* t/ G+ W7 X9 b
#define xmalloc(s) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(s))
5 |0 M2 V [! T8 Q- b' A#define xfree(p) HeapFree (GetProcessHeap(),0,(p))
1 r0 e1 c; j0 D& x7 e9 J7 Y0 M& i8 _0 K! K% u
void fill_icmp_data(char *, int);
8 a/ \3 [& p, x, T/ BUSHORT checksum(USHORT *, int); 2 m$ Z* A' {, y
void decode_resp(char *,int ,struct sockaddr_in *);
# \6 Y& ~- \% X; W# q
4 _% G1 t# h% n- I! m# Vvoid Usage(char *progname){
) w( }1 d5 l& Q$ \( k: _4 q5 l5 E: t) \. W3 p
fprintf(stderr,"Usage:\n"); : z' U7 o# q$ Z6 U7 p4 G( n
fprintf(stderr,"%s [data_size]\n",progname); 8 t7 t( G# L; B
fprintf(stderr,"datasize can be up to 1Kb\n"); . p [- [8 [% }& C E# K7 j
ExitProcess(STATUS_FAILED); 0 m; V% W/ |( s4 R
# ^7 ?4 I; K! [2 O1 p- I) h4 F$ R
}
7 ~- n) w; b* f uint main(int argc, char **argv){ % L8 `. R8 j Q' l
; Q, r% v6 p: x# @8 \* _5 A9 ^- v; qWSADATA wsaData;
, @% O0 a8 R7 w0 OSOCKET sockRaw; - r; Z# Z A/ j8 V- _. d" [& F
struct sockaddr_in dest,from; 0 o4 L) ~+ \# l3 e
struct hostent * hp;
4 L: p: g, {: E; {' l3 c& k+ Aint bread,datasize; 2 u' f$ D, p& ?
int fromlen = sizeof(from);
" k. R7 o/ a1 {' x# g+ F; xint timeout = 1000; / N6 H9 a+ k$ ?8 o
char *dest_ip; " z& V, X7 @6 L D0 N- g
char *icmp_data;
- @( L0 _+ w8 b* T7 c* W+ ^% [/ Ochar *recvbuf;
: @( V! i9 w( j5 {7 }5 iunsigned int addr=0; # H; ]7 K1 l% Y
USHORT seq_no = 0;
! F! T2 E+ [" g" V7 f% E/ P c# ~; t/ d
if (WSAStartup(MAKEWORD(2,1),&wsaData) != 0){
5 H+ Z K+ ^/ E" ]) V. Mfprintf(stderr,"WSAStartup failed: %d\n",GetLastError());
& Y0 x% ^2 n& TExitProcess(STATUS_FAILED); / _( h8 ~5 K q' _4 V* w3 K
}
2 X" x h0 \, K8 P/ p; Q. B7 `& C5 q
8 R0 b! Z' E3 f( p" m8 z; I8 Fif (argc <2 ) {
& u7 W a, z5 \8 u' @9 oUsage(argv[0]);
$ F f0 B) Y; Q, Q1 u6 T& g}
V; S7 j- B6 g. a2 |3 R0 J9 ^sockRaw = WSASocket (AF_INET, 3 D( `! l* M' A1 }
SOCK_RAW,
/ s. ~0 i# P3 d3 _. g: }; Z! W$ \" HIPPROTO_ICMP,
4 V6 N8 H& c7 [% `+ T& D2 u5 cNULL, 0,0);
7 q K3 V: H5 A5 L7 _3 r$ u! `; M0 w+ S# f! X# R# r- `& G
if (sockRaw == INVALID_SOCKET) {
9 ^4 H! A1 d4 l- O+ b `fprintf(stderr,"WSASocket() failed: %d\n",WSAGetLastError());
; g$ D( H' } a2 l) fExitProcess(STATUS_FAILED); 9 i1 n/ ]1 Z/ j6 d' o
} : y# g6 u% w0 O% l# a
bread = setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout,
8 \2 m) p! K6 {$ @7 J" D* j0 b4 Isizeof(timeout));
$ v- Q5 c" r) w3 T- m- g3 c) iif(bread == SOCKET_ERROR) {
* q: ~4 v( F* ~5 L8 J9 f( dfprintf(stderr,"failed to set recv timeout: %d\n",WSAGetLastError());
+ e" N# i; d' {" JExitProcess(STATUS_FAILED); ; H7 ?3 ^& t2 Y: o! y6 s) T
}
: r) g- C- g6 B0 x# O( L; E4 z. Ptimeout = 1000;
, a5 n* `9 B. e7 q Sbread = setsockopt(sockRaw,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout, ! G) N& V/ j' E9 F7 v8 y1 e2 U
sizeof(timeout)); $ {( \( i7 d- J/ C4 t# ~* x! [' ^
if(bread == SOCKET_ERROR) { - M: v q, y* S! g
fprintf(stderr,"failed to set send timeout: %d\n",WSAGetLastError());
: s6 r' \, s8 i6 r' Y. A2 `ExitProcess(STATUS_FAILED);
' W7 n# `3 Y. z7 T# \1 f0 \}
( z+ g2 i8 m0 V" M) m' n" Q A2 Ymemset(&dest,0,sizeof(dest)); ( v9 X2 k! k( z
! C- ^8 T6 e; n0 @8 Q5 lhp = gethostbyname(argv[1]);
8 E# X4 n0 c$ c% I2 T! Y2 j1 i
if (!hp){ 3 u! e3 R3 l& R" {- D
addr = inet_addr(argv[1]);
5 o$ U; b4 j2 e4 t! J} 9 _+ }: O% P+ j/ I
if ((!hp) && (addr == INADDR_NONE) ) {
6 m& J: ?6 L! Y. v, Qfprintf(stderr,"Unable to resolve %s\n",argv[1]);
0 _3 I" g# l( E3 z3 L9 x4 Q5 ?ExitProcess(STATUS_FAILED);
6 n9 W# ]6 D% u6 p! W( j9 I} 5 n7 g0 Q- Y. p' `6 W9 D* i
8 A. _7 I4 ~1 x+ I9 N0 w6 u) Y
if (hp != NULL)
! b: Q' P! ~* j7 p( g9 P8 qmemcpy(&(dest.sin_addr),hp->h_addr,hp->h_length);
2 |7 m( A. M4 M) G$ Ielse
8 y, W( A9 d) ?1 R# Ndest.sin_addr.s_addr = addr;
; l4 T& p2 E% [$ y9 k
% Q0 Y; X) d# o* Xif (hp)
) @$ |* K6 J2 i$ M) i# Rdest.sin_family = hp->h_addrtype; - F8 V3 {: u' a4 I6 r: w
else
7 L G0 b9 B- @# d; L/ Bdest.sin_family = AF_INET; 0 Y& S) m* y' i! ^# i6 g) m6 U
* h; @7 Q5 ]3 K) O; Ndest_ip = inet_ntoa(dest.sin_addr); 3 E! T# Z; y* r8 L: N
8 l/ q5 t/ y8 V9 ]9 Y" mif (argc >2) {
* g* F3 G, ~5 X' kdatasize = atoi(argv[2]); + N8 O* {. r- y# ~
if (datasize == 0) 5 E: l: R$ ]% D* r& E2 W& P6 c0 j4 L
datasize = DEF_PACKET_SIZE;
- k! a* r H$ C7 `- k6 B4 o
, v o; ^% G5 M: ]' P}
0 H/ P% B( s1 f2 K! Y" zelse
# {9 \. n% K8 J1 N' }. u0 E4 ^- K$ wdatasize = DEF_PACKET_SIZE; , D+ `8 |/ W& v& p0 B
) M2 Q9 \! @2 [2 h5 `9 Vdatasize += sizeof(IcmpHeader); , Z! V/ w! k: Q9 e) s N% G9 h) T
% e8 k4 Z$ R* Eicmp_data = xmalloc(MAX_PACKET); 6 d; X& A3 O8 _- L) A/ W
recvbuf = xmalloc(MAX_PACKET); 4 K: m7 S" {2 c8 T! C1 d, C7 j% ~
/ k$ d/ r/ u1 _1 S
if (!icmp_data) { 7 Q1 e9 m; R+ e, } \) I
fprintf(stderr,"HeapAlloc failed %d\n",GetLastError());
$ X% w8 ?5 B. ?* U$ i- ?# DExitProcess(STATUS_FAILED); 3 ?5 P* |2 @7 w+ d
}
- {- z$ R" t' k F" O9 Jmemset(icmp_data,0,MAX_PACKET);
% {- I+ a0 f# X. F" d/ Q* N/ g3 ffill_icmp_data(icmp_data,datasize);
) g% K# U4 E- F6 B, l- ~
# i- u( X" ^+ {7 [6 G( Zwhile(1) { # q4 o, n9 L0 G% s9 s
int bwrote;
& B4 [, M M$ q b
* Y* j; |) ^6 `# t6 |# ~9 Q((IcmpHeader*)icmp_data)->i_cksum = 0; ; ~9 `* [4 T+ A7 H
((IcmpHeader*)icmp_data)->timestamp = GetTickCount(); $ W4 l' L" A; ?' p; O1 M( a
; [( u1 e9 z9 ]((IcmpHeader*)icmp_data)->i_seq = seq_no++; 7 g2 \/ p3 l" h
((IcmpHeader*)icmp_data)->i_cksum = checksum((USHORT*)icmp_data, 8 x0 p5 X0 _& L: T) l4 ~
datasize);
9 h ]( n* T+ s( J. C5 t9 J0 `! g; d8 U) V0 u* N' u( p; X
bwrote = sendto(sockRaw,icmp_data,datasize,0,(struct sockaddr*)&dest, % }: R* s: m1 m, y9 i8 x+ @. C- A1 r
sizeof(dest)); 0 A, C/ |' E, r/ R
if (bwrote == SOCKET_ERROR){
% _# D. R& W$ K. k1 V! Cif (WSAGetLastError() == WSAETIMEDOUT) { 3 x2 s- J6 ?/ x7 i3 w" ^% T# V
printf("timed out\n");
2 s! k- O S; b, \continue;
) Q" d; k$ j$ f. A' b7 }} & R& C* s8 ^, R
fprintf(stderr,"sendto failed: %d\n",WSAGetLastError());
; d; u( X7 Z g: ~8 lExitProcess(STATUS_FAILED); & Y$ s" z) n* q! D
} $ o' F1 I) z _7 c/ V1 i' j% f7 `
if (bwrote < datasize ) {
/ D+ n& B! \2 `9 Sfprintf(stdout,"Wrote %d bytes\n",bwrote);
8 D8 f4 c" `: y3 D}
- V! e# m7 i& p3 G, ybread = recvfrom(sockRaw,recvbuf,MAX_PACKET,0,(struct sockaddr*)&from,
) k; J8 C' [/ F2 j; E7 u&fromlen);
$ s( `+ Z) h* M9 @+ \, kif (bread == SOCKET_ERROR){
6 z& _ I0 L+ x6 [, }% Lif (WSAGetLastError() == WSAETIMEDOUT) { 2 C$ E* K2 I& j
printf("timed out\n");
# _6 f9 a; e6 Z4 N. L" tcontinue;
) L9 ]9 |+ T* o# c}
' W7 A; f/ d% z" H0 ^) y$ H; Bfprintf(stderr,"recvfrom failed: %d\n",WSAGetLastError()); ! w) ~% D. n3 b% @' Y& f
ExitProcess(STATUS_FAILED);
. ?% u% i! Z l/ w5 S6 l} + L4 e4 o0 [9 b+ Y" S
decode_resp(recvbuf,bread,&from);
; O3 T3 Q% @% ?& d- dSleep(1000);
3 M, p( f- ]- v$ m5 p4 Y
" w% w2 T0 J0 M6 K* j}
# {- Y& y. l7 Lreturn 0; - }2 y; p- m0 z- O, S
4 a% y$ U8 _; D0 E} }3 |7 _, M% X2 g3 w) x7 a+ v$ p
/* 6 S4 V7 H# p- ` C
The response is an IP packet. We must decode the IP header to locate 7 J6 C) Q5 }" U$ Z# a' G+ e5 O
the ICMP data * Y7 A! R- R; I5 v
*/
1 d8 Q2 b7 M. _$ v$ A. evoid decode_resp(char *buf, int bytes,struct sockaddr_in *from) { ' q1 \9 v5 P y- T# Y% w0 x
& N$ h+ c; @$ F+ }4 w$ @% i+ tIpHeader *iphdr;
% a j2 N" D- \9 B5 jIcmpHeader *icmphdr;
, V- c/ A, K8 n3 ?unsigned short iphdrlen; - t, H/ g! ]$ u0 J' y9 R
: J( [7 T. I, F' i Riphdr = (IpHeader *)buf;
+ ]: H; r; d1 D0 @) w" G7 v0 l' w. M" `6 o& f1 n4 a
iphdrlen = iphdr->h_len * 4 ; // number of 32-bit words *4 = bytes
( c, ~4 E* V3 Y+ b3 E+ K
( `! e9 l" O5 A \; e2 Y7 Lif (bytes < iphdrlen + ICMP_MIN) { * [/ ^+ [4 T' g4 C
printf("Too few bytes from %s\n",inet_ntoa(from->sin_addr)); + |$ j3 K( t- d7 M* z! I
} 7 V5 @! {! ?! Y7 K u2 w& o f
% ?# d* `6 [7 |& h: X) w. W) r- g! ]icmphdr = (IcmpHeader*)(buf + iphdrlen);
1 b( J( U" h3 k* z
0 a% @, M2 K. F' q& |if (icmphdr->i_type != ICMP_ECHOREPLY) { }6 b' s, Y e s8 P; @" U
fprintf(stderr,"non-echo type %d recvd\n",icmphdr->i_type);
+ \( p# l$ N8 \# q$ jreturn; 1 u! |" o5 U% s, u7 A
} ) S& ~6 f$ o( C& s& X. S& K* m
if (icmphdr->i_id != (USHORT)GetCurrentProcessId()) {
% H2 C; s$ _# I) Y! M) V! ]fprintf(stderr,"someone else's packet!\n");
5 I4 }3 }4 K0 k: {! f- Lreturn ;
9 C8 \/ A9 R4 z; V5 o} . Y1 Q' [! q* A- S
printf("%d bytes from %s:",bytes, inet_ntoa(from->sin_addr)); ! [. U: P5 M; U+ b6 h) M9 X9 b
printf(" icmp_seq = %d. ",icmphdr->i_seq); ?7 n3 [: e, [1 ?
printf(" time: %d ms ",GetTickCount()-icmphdr->timestamp); , ^% r E! @4 }) `2 a
printf("\n");
- b$ I4 u6 M! N7 _- s, u! q; z/ C) l2 F) J2 M+ w
} ) n+ o' G& L4 ~ M& s$ @
: r0 B& |8 o3 K" C+ T
" @; j) w" l: c# ]7 ?5 w8 HUSHORT checksum(USHORT *buffer, int size) { 4 Z) Z4 T' n# y o( l
; q0 o. r5 o( Q2 G* v
unsigned long cksum=0;
+ N0 ~9 d8 ~% M# Z% Y- ^9 G8 _. B) [5 X' Z
while(size >1) { 8 g4 Q! j5 _$ x- p8 y. c
cksum+=*buffer++; % g6 j# w- n% a$ ~$ B6 V* o0 ^6 ^3 s
size -=sizeof(USHORT);
7 ^7 c* n- t+ x( E- A2 a} ( ]- i* D% R) i! b3 o: u% r
) S9 Q2 z+ x3 u: T+ F+ Gif(size ) {
& U2 g, w7 a3 X U( d, ccksum += *(UCHAR*)buffer;
5 s* u S1 s% a% S- S} $ s2 l3 y. {* ~5 _* h
% r6 O$ D4 @' M/ B( g
cksum = (cksum >> 16) + (cksum & 0xffff);
6 z1 Y2 e0 ~) o3 Hcksum += (cksum >>16); $ J i+ w- I. q5 x+ y
return (USHORT)(~cksum); 7 Y: ^2 z7 j" h! I4 z
} # x5 N$ ~% `) I& s6 q/ g1 r I4 V2 x4 _
/* , F% O$ R, ^% t/ j
Helper function to fill in various stuff in our ICMP request.
# f. a$ C) U! W3 I, h*/ / v& ~; R& K- Z# U3 }
void fill_icmp_data(char * icmp_data, int datasize){
! ^0 l' Z, J5 m1 g$ x- F, P3 k, G, C3 i4 W6 m: n4 v2 r) L
IcmpHeader *icmp_hdr;
( Q/ [' A! U# cchar *datapart;
0 H1 I+ c8 F- b2 g/ H' k# e5 i8 ~. I: O
icmp_hdr = (IcmpHeader*)icmp_data; 5 V$ Z' r7 R3 V) B: P; t
( i" Q# V. d' s6 F! uicmp_hdr->i_type = ICMP_ECHO;
/ k5 b' @7 f. |icmp_hdr->i_code = 0;
& w9 i2 {$ Y! W0 W) Qicmp_hdr->i_id = (USHORT)GetCurrentProcessId();
2 W' l5 i' c% f2 K) L# cicmp_hdr->i_cksum = 0; / B& i2 |. \1 I3 K
icmp_hdr->i_seq = 0;
; z* y9 ?+ L2 v9 w* L1 I: z" h
datapart = icmp_data + sizeof(IcmpHeader); 9 `3 c. U8 y: G. l" ]/ }
//
" K8 X! w7 B, q8 r// Place some junk in the buffer. 8 B' ^% P8 u, F3 [' N
// 4 A% H3 W! M/ [8 D
memset(datapart,'E', datasize - sizeof(IcmpHeader)); 4 k" Z# O+ b, }& U3 p e( _; w+ @
* Z$ f! r3 @" H- L* i; a0 u
} |
|