|
|
******************************************************************************\
8 z5 Y% B0 ]& ^3 f& N* ping.c - Simple ping utility using SOCK_RAW
; j9 Q3 p: n' a$ w. J/ b*
( Q& |* [* ?/ J1 E& G* This is a part of the Microsoft Source Code Samples.
# o6 }, h" d" L& d1 t P; J- h* Copyright 1996-1997 Microsoft Corporation.
; e; S* @+ i7 f3 v3 Q* All rights reserved.
- m2 A5 y" _: W+ {- r5 Y* This source code is only intended as a supplement to
- L3 L* p( g' j0 ]& x; X3 ?# ^* Microsoft Development Tools and/or WinHelp documentation.
2 w+ o' c7 R4 K* See these sources for detailed information regarding the
6 H' Z) u) c2 t% x! u) ?* Microsoft samples programs.
& F) Y$ T- ]: q' x\******************************************************************************/ ! L: z+ _$ U9 ]( P/ z
& w0 n7 f/ N$ K& J5 E#pragma pack(4) 6 V+ U/ q* e" w% S) V( |
Z. R" N" A. i7 ~( E
#define WIN32_LEAN_AND_MEAN
1 p' t0 u# t, a4 V* v- b/ k#include K3 u+ H4 U! o/ P
#include
G4 P7 o( L6 T1 `6 T! Y#include
0 G( |% |2 K2 }) A0 |4 w! m: I$ J o: f. i( `
#define ICMP_ECHO 8 ) I8 L" Q" U: L; k3 B( R! V
#define ICMP_ECHOREPLY 0
3 G8 H q" K2 B# Y/ O* n8 p: t
' U* ]9 n. q! s9 o3 A9 ^+ C#define ICMP_MIN 8 // minimum 8 byte icmp packet (just header)
5 z7 q+ p4 y, u8 |8 b4 K; y0 U3 e4 H* }& r, i
/* The IP header */
6 ]: b! J: L4 ?) r% _- o2 Ktypedef struct iphdr {
7 i5 D0 J- L& C/ a Q* junsigned int h_len:4; // length of the header . H3 u; [' y6 o' \( s4 { f+ A
unsigned int version:4; // Version of IP + C# F1 p9 {7 z/ @ c& M
unsigned char tos; // Type of service
. ^) U. x' o, [unsigned short total_len; // total length of the packet
p" M% f5 U" y8 m& M ~$ Uunsigned short ident; // unique identifier 9 I h2 s: n+ ?7 F i$ ?
unsigned short frag_and_flags; // flags / g, g4 l' x4 k" E8 y. Y0 \
unsigned char ttl; & w9 {! k7 ]9 [& _: J) g) y5 U% j
unsigned char proto; // protocol (TCP, UDP etc) ! t6 S; k! h0 S; A- W. l+ D% w9 \
unsigned short checksum; // IP checksum + w9 A, [8 ]2 X
5 ]* l! Z; q% o& s; vunsigned int sourceIP; 5 A5 u0 @( `! z0 b5 }+ }. d, x
unsigned int destIP; ! G+ v2 v0 v5 g/ U) o7 f) g/ k
9 u; ~' P, |- ~ Z% w/ K3 y}IpHeader; 0 s# d, j7 A, Z4 m' Z
0 p4 }$ j0 z0 f' l3 E! s/ @
//
5 T9 W3 s0 J/ l: _. b' u2 U2 d$ ]' N// ICMP header
5 U! W8 B; n/ t3 h! F// 3 z7 A: }) M: Y& j X! K6 W
typedef struct _ihdr {
7 ?* |2 m; W' fBYTE i_type; 3 ?7 m1 E2 [7 X' f" I
BYTE i_code; /* type sub code */ 0 K$ ?+ _$ [( Y1 B
USHORT i_cksum; 6 u& f) c% ?5 q' p
USHORT i_id;
& j: k& W; r0 ~# a. b! a }USHORT i_seq; $ @' O4 L$ W8 S- n4 U- n! P: v+ q8 ^
/* This is not the std header, but we reserve space for time */
$ A. f, X1 d* a+ W$ l$ |ULONG timestamp; , w4 G0 S6 C: D* x
}IcmpHeader;
0 v* i# h9 G( A- o
! R" I: i- m4 Q! H#define STATUS_FAILED 0xFFFF 9 y+ J3 ?$ S. ?9 w0 w. _% j
#define DEF_PACKET_SIZE 32 & V: {! p0 w2 f0 z' D. a
#define MAX_PACKET 1024
. |) n9 [$ z! [0 L' q1 _: B' s3 t- k- e7 }
#define xmalloc(s) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(s)) & w0 k. h) D0 L
#define xfree(p) HeapFree (GetProcessHeap(),0,(p))
/ {1 u& A6 T" c2 m6 j2 O; c
( ~0 Q/ t3 Y( ]9 G# }, c x# _3 gvoid fill_icmp_data(char *, int);
! D; ?! ?; f( ]USHORT checksum(USHORT *, int); 6 W! ]5 D9 S% z, m% v5 Q0 f
void decode_resp(char *,int ,struct sockaddr_in *);
& P% Q# I9 y% h/ p. u
" d; v7 n$ n" y6 Qvoid Usage(char *progname){ 3 `: F( x _% G( Z9 [3 H# o
' _5 e ?; ?; e4 ]( ~fprintf(stderr,"Usage:\n"); 6 C6 T3 s9 G% B7 X
fprintf(stderr,"%s [data_size]\n",progname); 2 c5 p' I3 F% N# u+ K @! C4 k
fprintf(stderr,"datasize can be up to 1Kb\n"); . [. h8 ~- q6 D! e+ C! a
ExitProcess(STATUS_FAILED);
" z! l0 z, u) i" i3 H+ D7 Q% w4 g# I! X4 n& L* K3 W7 n
}
+ B) ^1 ]/ a+ ]% ^int main(int argc, char **argv){ ( ^% S [) B ~3 \ v' H% A
1 v% w6 I5 A0 G
WSADATA wsaData; k8 t3 w7 C1 Y% W- q+ T0 S
SOCKET sockRaw;
2 [* C" U8 f4 G1 d, k: Jstruct sockaddr_in dest,from; + ]; q# {# P& f5 K3 V: ?9 N
struct hostent * hp; 7 o% l4 B2 m7 n# p; _2 ^/ }2 V# W- O
int bread,datasize;
" H( m v0 [' ?; e( o( P' Hint fromlen = sizeof(from);
4 F: F" W y5 jint timeout = 1000; 7 R/ y! s) {9 B4 ?( w" [
char *dest_ip; ; N8 i2 S: t u5 V4 v
char *icmp_data;
& U& J& W8 v. Jchar *recvbuf;
9 j% @' h. h$ V( a; Munsigned int addr=0;
8 `: \+ }" y6 e; O. A: ZUSHORT seq_no = 0;
( W, {, X- i/ i5 O8 N8 |. W6 m1 T, O1 r: a) R
if (WSAStartup(MAKEWORD(2,1),&wsaData) != 0){ ( S; N/ x2 Z; m9 ?; r
fprintf(stderr,"WSAStartup failed: %d\n",GetLastError()); + l' p% ?% G5 p. q7 Q' v4 \
ExitProcess(STATUS_FAILED); 9 K/ _# O& V) x- @' V
} # J ^: M/ E- N! k& `- I* O$ e
9 c! [/ n! x5 k* [if (argc <2 ) {
" Y- C& E: s5 E, b$ F& n6 D% rUsage(argv[0]);
4 d3 t. y# h1 ^1 C+ x \' K4 H& x}
5 n/ `: N1 S' B3 E0 e" HsockRaw = WSASocket (AF_INET, 7 P5 p: g! C' A: G" m
SOCK_RAW,
# R2 L, J- p4 M; r% x& TIPPROTO_ICMP, & Z& R% `& y" K/ R$ n2 M
NULL, 0,0);
% N# F# {0 U, r! f- X' `: I$ l T- E1 [ U
if (sockRaw == INVALID_SOCKET) { # |) h4 C- I z% y
fprintf(stderr,"WSASocket() failed: %d\n",WSAGetLastError());
- c; t, b6 `& ]4 U6 gExitProcess(STATUS_FAILED);
8 X1 Q( y# e+ t) a" E} 8 p; w0 e5 E( S) Y0 b& s4 y
bread = setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout,
1 A6 i& i4 S" M7 h% v" R7 y0 Jsizeof(timeout));
* |3 A/ J3 u) G6 {2 Kif(bread == SOCKET_ERROR) {
. n% ~7 {0 o6 ^! W. @8 a1 D6 Nfprintf(stderr,"failed to set recv timeout: %d\n",WSAGetLastError()); 3 x, c5 s0 S( n8 W$ ~
ExitProcess(STATUS_FAILED);
$ m' e3 Y+ N5 ?) a3 G$ Q4 B* g+ h} ( H: Q4 L6 v+ r. u6 x( @: q
timeout = 1000;
+ ]+ _ c _$ K8 r$ A S9 e) [bread = setsockopt(sockRaw,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout,
0 u3 z# w/ t; @9 Isizeof(timeout)); ( q1 F0 Z7 Z6 s* L$ [# j
if(bread == SOCKET_ERROR) {
9 o. t$ S6 l5 [$ ?/ r+ dfprintf(stderr,"failed to set send timeout: %d\n",WSAGetLastError()); : s9 z7 z! H- H+ }9 f7 T& s
ExitProcess(STATUS_FAILED); / ]* S3 Y( I5 b! g x' Q% z2 N p
} 7 r( Q! {$ A( [6 T) \
memset(&dest,0,sizeof(dest)); 7 j( X& L6 v9 _9 v! A
( `, Z0 N: k3 J5 D- l
hp = gethostbyname(argv[1]);
/ h8 J q7 z7 N! _4 \- y( c5 [. w$ G) H* w5 R/ o" W6 _
if (!hp){ 9 E6 C# N7 h7 }8 t5 G1 _
addr = inet_addr(argv[1]); ; l; k; ]4 o# e+ R7 L
}
9 ~) \, `% E3 a$ yif ((!hp) && (addr == INADDR_NONE) ) {
" D ^& h* Z6 R6 H% _1 a# l Dfprintf(stderr,"Unable to resolve %s\n",argv[1]); ( a3 C5 S: |2 Y; \
ExitProcess(STATUS_FAILED); * h* d% Z) m' |4 {( F
}
0 f4 Y0 g0 B6 d% J
) x: b* d! r3 w8 X! I, q6 vif (hp != NULL)
3 |; T1 Y7 t: c+ ~( I+ e# u& jmemcpy(&(dest.sin_addr),hp->h_addr,hp->h_length); 8 R) Y" @6 E8 Q& o6 ~
else
) i3 a1 L6 y+ _/ [1 bdest.sin_addr.s_addr = addr; / y/ s7 D3 t2 ~6 u( k# M# v
* H- u& V: T1 u) ]
if (hp) ) v- W9 t8 L; C" X
dest.sin_family = hp->h_addrtype; 5 R( n" O" M: C4 M
else 6 E9 J8 w9 O% Y" N
dest.sin_family = AF_INET; : Z) ]! ^/ Z* {$ O
8 x8 v A9 O+ _dest_ip = inet_ntoa(dest.sin_addr);
- T. i7 M \" f( H" P2 U
. q6 F* A" ]+ I, V0 [8 ~8 |- N2 mif (argc >2) { * z& Z8 _& z$ ^& ~6 E6 ^' P
datasize = atoi(argv[2]);
2 ^$ R/ Q3 P' x: S1 E6 u: g0 rif (datasize == 0) , {( x) v6 ]1 v
datasize = DEF_PACKET_SIZE; 3 F" ?) D1 P2 C, b
2 _) }) n# y1 c8 K7 X
} ; j7 k6 m" t! [ t7 T
else & z6 T, X# k6 y2 }" P
datasize = DEF_PACKET_SIZE; : q3 n6 u) W# ?
# ~, S* u1 C% N0 G
datasize += sizeof(IcmpHeader); 6 f0 A: v7 j" \% r# B
* Z) c5 P- o7 ]5 n* }: q" Picmp_data = xmalloc(MAX_PACKET); 4 g$ @% X, \6 Y5 k, j, }/ i
recvbuf = xmalloc(MAX_PACKET);
' ~$ T) B, ^; Q, h5 C) d& |
- P$ ~& Z9 i( s- eif (!icmp_data) {
8 o3 D- i* w$ j& Q, G3 R3 yfprintf(stderr,"HeapAlloc failed %d\n",GetLastError());
( f1 S7 j4 |. z1 dExitProcess(STATUS_FAILED);
2 [3 x& Z# T2 E4 ?}
: R- Q/ p3 o' `/ b! q' }- g$ Ymemset(icmp_data,0,MAX_PACKET); # B. A8 L0 I- o/ m6 C1 x0 W2 Q& r
fill_icmp_data(icmp_data,datasize); 8 b2 R% {( J) C( _- u, i& Q
& Q4 Q0 Z. a$ Z: h: q8 C
while(1) { ! A# {' @0 I2 J- D7 B' i/ G
int bwrote;
4 W1 Q- t) L! r) r3 F
3 v) v& e5 N3 V! q((IcmpHeader*)icmp_data)->i_cksum = 0; * O' P1 m% ~7 X2 t9 l/ y5 I
((IcmpHeader*)icmp_data)->timestamp = GetTickCount();
# Q; @0 z s# ^3 L( m% p' y$ I+ a4 k6 g( `6 w) f
((IcmpHeader*)icmp_data)->i_seq = seq_no++; 1 Q; u4 }4 g' s$ S$ Y
((IcmpHeader*)icmp_data)->i_cksum = checksum((USHORT*)icmp_data,
0 {4 P Z7 X$ p& x; V; G3 Vdatasize);
5 ?6 _1 B( j( _6 A
& @; N* W' d9 bbwrote = sendto(sockRaw,icmp_data,datasize,0,(struct sockaddr*)&dest, 2 j1 E3 I, \, B2 Q
sizeof(dest));
/ A }) [- r3 h7 {9 Cif (bwrote == SOCKET_ERROR){
( k* t1 ~! ]5 Z" j& h; L8 b( E/ iif (WSAGetLastError() == WSAETIMEDOUT) {
' r! J/ g( I: S5 k c( \printf("timed out\n");
8 K3 @& S g/ A, P* j% xcontinue;
! _- S, h- ?" ]( X& t7 n/ Y7 n}
& \9 {" c) ~1 efprintf(stderr,"sendto failed: %d\n",WSAGetLastError()); : r3 V& _; w6 r$ ~; D
ExitProcess(STATUS_FAILED); # }9 y( ?3 n; R; W/ J
} , O5 {7 T: U J9 k
if (bwrote < datasize ) {
4 s4 X4 R: ?. X3 R9 E) X! x2 qfprintf(stdout,"Wrote %d bytes\n",bwrote); " J" j1 j( w( h2 M8 m+ \
} 2 I8 o% Q6 w! y2 ]3 b/ `" y
bread = recvfrom(sockRaw,recvbuf,MAX_PACKET,0,(struct sockaddr*)&from, * X8 O3 Z8 G) ^! v. t
&fromlen);
6 r$ U7 g* R) F0 g8 I: f; oif (bread == SOCKET_ERROR){ 1 Q/ {8 Z8 `& t4 s p8 _
if (WSAGetLastError() == WSAETIMEDOUT) { $ `' J9 _9 _/ j6 o* z2 W" R6 t7 M
printf("timed out\n");
1 K( V! z' |3 R, R0 h0 G1 scontinue; , A7 z1 S1 v5 i3 I# F
} ; w( a* Y3 \; B" k3 p
fprintf(stderr,"recvfrom failed: %d\n",WSAGetLastError()); ) H7 g1 K- w: O/ s; w
ExitProcess(STATUS_FAILED); , H' P, b9 L# P$ k7 f2 j
}
7 |7 Y! J6 r) ^- l; F2 a- Ddecode_resp(recvbuf,bread,&from);
$ s, L3 V5 Q$ L. r0 n" M. \. NSleep(1000);
$ ~: g; f: W) S: N9 _8 k) b6 o
& J1 l+ i5 `- g}
8 E* o j9 m5 ~; B1 u1 qreturn 0;
2 }$ L! M0 H, Q' T* [3 u2 l! d1 z3 C" o
}
3 h" w( r# a. h- Y/*
4 u6 d6 U. T3 E2 @* j0 }4 T# RThe response is an IP packet. We must decode the IP header to locate
/ d$ W- y/ E. g6 }7 h6 _the ICMP data
- _6 F; ~' q' o: R6 w5 K*/
4 C! h$ {& \; ^7 {void decode_resp(char *buf, int bytes,struct sockaddr_in *from) { 6 m$ `# |) t8 t) y9 B' F& y
8 [9 n4 B6 V$ W3 \' z* }: bIpHeader *iphdr; ) W8 T% C# x0 v
IcmpHeader *icmphdr; 6 z; T! e: L% ?1 H6 Y
unsigned short iphdrlen;
; b) O! {2 u4 u6 ]3 a8 N( }) d
( A% u7 s8 z" ?1 B& iiphdr = (IpHeader *)buf;
7 z! t, p) b/ C9 c7 \: ]* K- y* v5 d# q
iphdrlen = iphdr->h_len * 4 ; // number of 32-bit words *4 = bytes % H1 D; O5 H( D+ ]: P- v( D. W
% v+ M9 |- P" T) s
if (bytes < iphdrlen + ICMP_MIN) { : ]" S8 I' j M9 i
printf("Too few bytes from %s\n",inet_ntoa(from->sin_addr)); ' ?8 S( i3 L% i$ A0 B
} ' V+ O- f7 s/ m6 W6 T& x: k
/ |6 w7 {( C& f( p9 b
icmphdr = (IcmpHeader*)(buf + iphdrlen); , M3 @# Y, P/ a7 b& ]
0 D- ^1 V8 ~& O* N- Q, U3 m3 U
if (icmphdr->i_type != ICMP_ECHOREPLY) {
+ r- j; T4 c: D% Y" s3 x% F2 `fprintf(stderr,"non-echo type %d recvd\n",icmphdr->i_type); ( x4 f( I9 ^4 A
return; " S [. D9 x; Q, L, a
} ) W' f0 S+ B# P% I& i: d4 d$ ]
if (icmphdr->i_id != (USHORT)GetCurrentProcessId()) { + Q+ s+ v- x/ z8 ], S f: i( y" c3 t
fprintf(stderr,"someone else's packet!\n"); # r: Q, b: p7 ?3 ]4 o3 Q8 t b
return ; 5 Z( K3 J$ _! X. N
}
2 f$ A( h, [1 \/ L3 fprintf("%d bytes from %s:",bytes, inet_ntoa(from->sin_addr));
/ w+ v0 J" Q W$ |! t; \5 }* Tprintf(" icmp_seq = %d. ",icmphdr->i_seq);
0 F v0 G2 d2 l" [printf(" time: %d ms ",GetTickCount()-icmphdr->timestamp);
0 d. u: Z7 g" b2 ` \/ iprintf("\n");
$ I8 T# c# ]& q9 O: v; T) F0 B5 M0 ?8 f; Q3 l2 ]7 N, y
} 9 }; i- _$ a4 K }0 d7 g8 ^; X
" a& C" P! j# g1 a7 c' x! {% a7 q& y) S' {8 m+ y: K) w
USHORT checksum(USHORT *buffer, int size) { 1 o+ s9 B$ B. X2 P5 }% j, f
I2 n; O2 m4 s% P
unsigned long cksum=0;
$ c. W5 C* L8 F- l4 e
, _! N( l+ W% ]+ F. x5 H. @- {while(size >1) {
7 ^! a. L* `# H6 v# F6 scksum+=*buffer++;
' k0 D1 }3 [5 Q% e1 `# Ssize -=sizeof(USHORT); - d% _7 S; p9 d+ |/ w
}
! e& F9 [. G/ B$ s! o) M# y% d& U- D9 x; A9 n0 o; y
if(size ) { ' c2 X% H2 s; J0 w' T
cksum += *(UCHAR*)buffer;
# C2 t( G" w" c# [! }1 [! Q' V, S} + J/ S+ ~: }& x- X9 x
" B1 i% f7 R3 Kcksum = (cksum >> 16) + (cksum & 0xffff);
+ ?; |- G& k" q/ Ecksum += (cksum >>16);
7 D1 w9 T( M& | ?( Jreturn (USHORT)(~cksum); $ h5 k0 V# Z# n" H( e2 X' t& N6 S
} * N9 f* q! S* y4 v& d: D$ }( n% M
/* / W9 i: i9 f A6 ]
Helper function to fill in various stuff in our ICMP request.
0 Y0 j5 F' g. w: S0 L; q& f*/
/ [- f! f, t( S/ a& J/ ~( Ovoid fill_icmp_data(char * icmp_data, int datasize){
* t; A0 N) U- }- e, y8 u/ t( A& K: x. u
IcmpHeader *icmp_hdr;
4 S8 f7 Z; M0 k% ^9 R% Echar *datapart; 8 G1 S$ T6 u9 [+ T7 k
8 l+ m$ R- U6 M1 I
icmp_hdr = (IcmpHeader*)icmp_data;
; p4 O2 J" }* B, p7 |
6 H8 r& H% C0 h$ o0 uicmp_hdr->i_type = ICMP_ECHO;
O5 p# b! c) c. Q, ticmp_hdr->i_code = 0;
4 @) ]# `# N/ F& S$ p* d M2 Qicmp_hdr->i_id = (USHORT)GetCurrentProcessId(); 0 G* B, a% _2 v. ]9 K
icmp_hdr->i_cksum = 0; * M; K+ q I$ Z1 p
icmp_hdr->i_seq = 0; % a7 Q. M/ a2 ^/ b) e
d5 }2 c; I5 ?1 b( I& O! v! i
datapart = icmp_data + sizeof(IcmpHeader);
1 y8 v$ o7 p5 K, d( m// 3 Y: Q4 b6 k2 ^- M& W5 |
// Place some junk in the buffer. 9 }" g6 I- j: W, n! S
//
) q K# `" s( S# h& Rmemset(datapart,'E', datasize - sizeof(IcmpHeader));
, X) R. x3 u! V, l2 b9 |/ U) g( r! U( C" T; O1 ]) J
} |
|