|
|
******************************************************************************\
) Q7 h; H- U5 a, Y$ N n( Q0 d* ping.c - Simple ping utility using SOCK_RAW
! ~3 v; S! d, L4 o7 S1 C. q" \( L*
7 m8 y) Q! V* H* \) o' v- n* This is a part of the Microsoft Source Code Samples. $ ~4 y7 F( m6 G# P
* Copyright 1996-1997 Microsoft Corporation. 1 o# ]. d. f9 |' j! O
* All rights reserved. , D z. \3 T0 g: K: e
* This source code is only intended as a supplement to / o) f) e+ @+ [* E A
* Microsoft Development Tools and/or WinHelp documentation.
! S# f4 J' W( s) f' G* See these sources for detailed information regarding the
$ [) z9 [- W1 a4 ]8 d3 ?# D$ |' `* Microsoft samples programs. 9 Q" i0 n5 S- b# Y. w) G
\******************************************************************************/ ; v- M4 j. N2 M
* ~9 p2 p, L% @- H- w# {- v a
#pragma pack(4) 0 B$ Z* b- u( K7 X1 F6 W+ j
+ A z& i% W, \1 T) V
#define WIN32_LEAN_AND_MEAN
2 e, o$ S1 @: Y) S/ f6 d#include . ]6 Y3 y# J6 l% ]- Q! m
#include
R: w7 P( g1 Q3 r- E* Y#include ; \; i; Y8 S3 W) ]
5 r" [9 h0 n! d' h#define ICMP_ECHO 8
5 z8 Z' B) P& z" Z) W7 r#define ICMP_ECHOREPLY 0 ! w J/ L$ m4 ]" r1 X* P
% c# f' j3 V2 d2 _; a& [" i* s: ~
#define ICMP_MIN 8 // minimum 8 byte icmp packet (just header) ) ^# p3 }* y; u: `5 I3 d# s9 H
% G- X. {! @ p+ a/* The IP header */
% t! V# f9 g& Mtypedef struct iphdr {
- {# j1 n' h! f. Qunsigned int h_len:4; // length of the header
- J, \; a8 V$ D# Uunsigned int version:4; // Version of IP ' h, J, P' S/ |/ x s8 D. o
unsigned char tos; // Type of service
7 m4 Q: ^2 g& H8 e3 E: y* dunsigned short total_len; // total length of the packet 5 k' |2 L' q! B2 Z$ W6 h7 W4 M
unsigned short ident; // unique identifier
" Z) Q" S# I3 F$ m3 A/ wunsigned short frag_and_flags; // flags 7 f$ P6 X' n* A
unsigned char ttl;
" H# Z; h; c H; u- ?unsigned char proto; // protocol (TCP, UDP etc) 4 U7 c# E: @ g0 X$ k
unsigned short checksum; // IP checksum 6 U4 V% W; s* I3 h9 w4 g2 C
+ P# e0 L0 l1 H, z6 }* j' Gunsigned int sourceIP; # w- N9 V6 |2 b1 u0 s! ~
unsigned int destIP; ' x! c, A0 n( u! _% X0 k
0 S$ e9 T, j; e
}IpHeader;
* O! d. S: h; W o$ h7 g; C2 h8 v7 H& g, ?! X! ?6 |1 R5 L* b$ W
// " A8 n. {8 P& v1 s
// ICMP header
0 C( X8 y0 t! S# R//
: ^! F/ b; M! gtypedef struct _ihdr { - F9 ]; n: e; R- k. `( s
BYTE i_type; 8 S) m3 B' S2 q6 y( |" F9 v. Q6 a* a1 @5 O
BYTE i_code; /* type sub code */ 8 F" T! g; I/ D9 ~1 C
USHORT i_cksum;
; j! w3 X1 L5 W. L# Z' vUSHORT i_id; ' j$ E5 L6 X: j: L
USHORT i_seq;
1 s; Q, R" Z, u8 v% C/* This is not the std header, but we reserve space for time */
8 r1 y5 O& N, }; E" P5 p7 F6 \ULONG timestamp; . w3 |, i: h4 }$ V+ n
}IcmpHeader;
! x, k v. Z" }1 H$ E: j! p
4 t+ d4 [- {% C% r#define STATUS_FAILED 0xFFFF 9 E- Y+ K' x% z" g5 L
#define DEF_PACKET_SIZE 32 2 D. l5 U$ K: b7 l
#define MAX_PACKET 1024
( w! ^2 E( o% `9 z9 l) o7 l+ i+ w6 r, {
#define xmalloc(s) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(s)) 1 _, P+ W, C" p+ y( J
#define xfree(p) HeapFree (GetProcessHeap(),0,(p))
R% z9 ]; b) a: M/ D$ ?; c- u; N, O: v) O
void fill_icmp_data(char *, int);
0 k7 ?' G8 a- F3 HUSHORT checksum(USHORT *, int); + q) n% R1 b: {
void decode_resp(char *,int ,struct sockaddr_in *); 4 L& i0 n& v7 n
. J+ R$ ^! N$ E8 {6 R* R! L( gvoid Usage(char *progname){
9 B8 @5 L+ G f3 r( g% o- x, f% ]3 i
fprintf(stderr,"Usage:\n"); T" S e x1 u, o; Q, l
fprintf(stderr,"%s [data_size]\n",progname); 2 ~2 w% A- |1 L
fprintf(stderr,"datasize can be up to 1Kb\n"); 9 s" o- [) Y0 k6 v
ExitProcess(STATUS_FAILED);
5 G5 q$ {; d7 ^% x9 B1 G! ?9 g& C& a+ R* B& q
} - A% Z# w9 L" A; j
int main(int argc, char **argv){
' ^: w+ `" g9 b/ K& r5 W/ a3 {5 B3 {; }* [2 C
WSADATA wsaData;
0 M3 m/ i4 q% i7 WSOCKET sockRaw; 7 m4 ]' [7 I, k( w
struct sockaddr_in dest,from; * H3 B7 \$ y0 Z( H
struct hostent * hp; 1 d: U) M9 c x" V
int bread,datasize;
, J* g4 o0 |& E: i+ }9 D: f( I; c, D* Fint fromlen = sizeof(from); 4 N; Y/ V, Q' ?* k6 ]4 v
int timeout = 1000; / b9 j( N9 j& Y/ i& v
char *dest_ip; 2 [: s5 T5 v3 |3 R1 N5 b5 @% \
char *icmp_data; # y9 h, R+ F" Q& V. F
char *recvbuf;
3 D2 R; S% X: k; E# dunsigned int addr=0;
. e- p. J2 r- w2 F7 LUSHORT seq_no = 0;
& g" H% L6 x7 O8 q/ Y
' G0 G# n/ X# M6 z: F' Oif (WSAStartup(MAKEWORD(2,1),&wsaData) != 0){ 7 ^' z0 k% N) m) M8 j, e. r
fprintf(stderr,"WSAStartup failed: %d\n",GetLastError()); ; m9 x% p. |2 H* j" F, _
ExitProcess(STATUS_FAILED); 1 S6 _- ], ~ J: H: C/ ]4 O& O
}
' [4 T) k$ _! W9 D6 j. G7 T4 U
5 ^" i+ z3 d J% S6 z% L' m# dif (argc <2 ) {
! C: O7 K5 ?' I+ f' o0 r4 M. C* f! I6 hUsage(argv[0]); " p* ?, L8 Q% H& G( F- G
}
5 S- C2 L! X8 U; {$ N# j2 zsockRaw = WSASocket (AF_INET, 2 o7 b" M+ K4 F+ g
SOCK_RAW,
3 M! [: W# c/ {3 ?$ w6 bIPPROTO_ICMP, ' F& g) L& ~7 r8 a! `% p
NULL, 0,0);
9 U$ e* d5 Z4 M
; {7 Z- N/ [( W' eif (sockRaw == INVALID_SOCKET) {
! r; P" m# o D% l1 F$ G/ A" ^fprintf(stderr,"WSASocket() failed: %d\n",WSAGetLastError()); : {! F) n7 z, b/ }& y1 o# w! T
ExitProcess(STATUS_FAILED); ' R5 a( H2 W4 [1 ?8 q- j
} ( h% Y! c6 u! a# X6 L F
bread = setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout,
/ E# C, W2 H2 D5 ssizeof(timeout)); : @4 [ l, ?- n3 ?/ p E, w
if(bread == SOCKET_ERROR) {
; j: v0 V, q" h9 y; J' H) m3 X) l0 ?fprintf(stderr,"failed to set recv timeout: %d\n",WSAGetLastError());
/ a# W' n6 M$ o. @ ]( SExitProcess(STATUS_FAILED);
5 p: F( L8 v2 X3 `% A}
% K+ Y {( n( k7 O* otimeout = 1000;
" c5 x3 q1 ~( hbread = setsockopt(sockRaw,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout,
' E! m) G7 D7 j+ Y1 \, m7 t) y) hsizeof(timeout));
6 {' Q4 l& A* }! Cif(bread == SOCKET_ERROR) {
7 P V, z; Y6 H$ B9 Sfprintf(stderr,"failed to set send timeout: %d\n",WSAGetLastError());
- T1 `3 J `) ~! P' I/ {ExitProcess(STATUS_FAILED);
1 R2 n5 @9 L$ y, I; A, ^} ' @7 @; O @. j; q
memset(&dest,0,sizeof(dest));
0 E7 G ^% `- p5 E3 Y
, Q1 M5 H: Y+ `* i* `! D9 c6 Jhp = gethostbyname(argv[1]); 5 Y* \; v* y- J8 f& N0 @0 K
7 l% F: |4 i R S* E5 D/ `9 q0 f
if (!hp){ 4 v/ u. ]/ V4 C
addr = inet_addr(argv[1]);
% [: J; U: c5 L. b, w, E" T+ |}
\+ L7 X& v8 i. q: jif ((!hp) && (addr == INADDR_NONE) ) {
# {0 e- B! }1 ^" e3 B$ {6 rfprintf(stderr,"Unable to resolve %s\n",argv[1]); # w5 m- m$ o: W! l- B* k: Z
ExitProcess(STATUS_FAILED);
) T+ w. H" g) N2 b} ! W4 q& P1 W) [; L
1 I; u/ _, D5 v( f! x: [: Tif (hp != NULL)
) t _6 w) q) K$ C. o, n7 u5 Smemcpy(&(dest.sin_addr),hp->h_addr,hp->h_length);
7 {- a4 ]1 b% i; U( |% Aelse , Z5 M) Z( z0 M2 b! `4 ^0 j
dest.sin_addr.s_addr = addr;
' i5 m& x2 h, x3 w' d& b
3 N1 [0 M( a7 W8 P% u' sif (hp) # r" J8 n& N; }: L( A2 o( C
dest.sin_family = hp->h_addrtype; * p% y, ?3 k. D$ N: ^ _- H8 x
else 7 v$ i/ W2 [5 _) }
dest.sin_family = AF_INET; 3 t9 c5 b& u* ~8 K4 P
& ? `) V2 M5 r2 k% D9 _# |( c
dest_ip = inet_ntoa(dest.sin_addr); J1 y4 \% b9 ~3 F; ~
2 j$ G2 t+ L5 d i) B( Q" q( Mif (argc >2) { 0 E4 Z, t* j- ?6 a
datasize = atoi(argv[2]); , N# P0 k- H% @- g
if (datasize == 0)
% y" x; i o" f! K9 _datasize = DEF_PACKET_SIZE; 4 t9 O* K! P& r; r+ C/ I. C0 a; N
- ^' ~9 n% `% ^4 \ {
} ! Y5 f3 k) [* }
else . e/ K! {, Z [& B1 _* O- H
datasize = DEF_PACKET_SIZE;
; D, K" h6 W9 q9 Q% ~7 `, O: e; p! R; i2 p
datasize += sizeof(IcmpHeader);
( M- v3 q. _3 f ^7 U' F( Y; h4 a2 p7 O6 Z8 U
icmp_data = xmalloc(MAX_PACKET); . ^" P2 n7 P6 f6 v6 R
recvbuf = xmalloc(MAX_PACKET);
5 ^$ [9 K8 A0 V7 b. ^
7 t+ W o& b% A" Xif (!icmp_data) {
3 \6 ?: c6 t! C4 x" J" S$ Kfprintf(stderr,"HeapAlloc failed %d\n",GetLastError()); - `' Y. h/ N' `+ D L& W2 |# m% H' T
ExitProcess(STATUS_FAILED); ; J, ]4 o6 s2 c5 Y
}
4 u0 D& {: r5 f4 i/ n" jmemset(icmp_data,0,MAX_PACKET); * y% j% d" d h0 @! D
fill_icmp_data(icmp_data,datasize);
( _. W1 I' B: E# k( K v
3 w- G/ Q% @1 I0 w0 [while(1) {
* R9 X0 y6 H: m3 Tint bwrote; / ^- B+ X5 ^0 g) i' `1 }9 R, Z
. k( A* a) n3 z3 q2 s( v6 t((IcmpHeader*)icmp_data)->i_cksum = 0; 6 ^# }: d; R8 x% X; l: {# \
((IcmpHeader*)icmp_data)->timestamp = GetTickCount(); ! T' n2 m! ?9 x! e# y
2 |6 l. p4 Q7 b. ^9 N" { a( h
((IcmpHeader*)icmp_data)->i_seq = seq_no++;
$ `: Q# D5 ?8 {; ~* ^- a' p% L((IcmpHeader*)icmp_data)->i_cksum = checksum((USHORT*)icmp_data, 5 n' k4 l' ]6 U/ T6 G4 N
datasize); ' s- H. O# l5 o) A# s; q3 k& h
: E; R+ }7 z G$ Jbwrote = sendto(sockRaw,icmp_data,datasize,0,(struct sockaddr*)&dest, " P6 d% o }3 x
sizeof(dest));
( K8 t+ y6 p( [6 \5 z) b/ b& Qif (bwrote == SOCKET_ERROR){ 0 k: u, z4 {5 z% m4 F
if (WSAGetLastError() == WSAETIMEDOUT) { . |1 ` ?- I$ \* v
printf("timed out\n"); 7 `. c+ I: p% E$ }3 c6 [
continue; % L$ Y5 `! `: H$ K5 }+ e8 K
}
3 C( y0 t2 p5 O7 sfprintf(stderr,"sendto failed: %d\n",WSAGetLastError());
: E( c: {) `# J# O/ K( L4 {ExitProcess(STATUS_FAILED); 4 n$ c2 N" a* L; z5 \
} ) X, U$ m! {% O& D( E, p& s
if (bwrote < datasize ) { " M; w: x$ c) ?, {
fprintf(stdout,"Wrote %d bytes\n",bwrote);
D1 |! @/ y0 J% f8 f! P$ d0 R} 6 b% L) D; |1 ?+ y8 b% y
bread = recvfrom(sockRaw,recvbuf,MAX_PACKET,0,(struct sockaddr*)&from,
4 L \2 D* K. g! B* J: f0 Y$ R&fromlen); 8 I( {% E0 L% f7 y
if (bread == SOCKET_ERROR){ V" a: w& b; c, Y2 C" I" s
if (WSAGetLastError() == WSAETIMEDOUT) {
* W/ ?* k. b! m% Wprintf("timed out\n"); S# V6 X4 [2 v
continue;
# i& K; g5 S2 ?( S& j: u6 c" I6 q}
* X0 C3 t* g5 c" {fprintf(stderr,"recvfrom failed: %d\n",WSAGetLastError()); # F! V/ P% N8 n( Y
ExitProcess(STATUS_FAILED); 3 k% u7 [" _- N- U
}
0 c: v1 }0 ^6 X+ V, ^9 udecode_resp(recvbuf,bread,&from);
) {( D' d( L! G; Z1 v0 z( W$ zSleep(1000);
9 T9 B/ B& g2 s1 P5 ` Z: g6 G# [' i) W, }: J4 X
} 3 Q. {1 A- _$ o9 W3 H
return 0; 5 O7 @( B2 S& p* J
2 K1 r/ b: T0 i; U3 ?3 Q
}
* G$ M" T* I* n7 H3 R# v/*
& W5 [: Z3 f; E- c" w8 VThe response is an IP packet. We must decode the IP header to locate + u- p+ u7 h) \6 V' R
the ICMP data . s& G- e8 x6 j) ?% `2 I4 v0 Y
*/
6 p* G7 _+ W3 ~& x9 f& e( @) kvoid decode_resp(char *buf, int bytes,struct sockaddr_in *from) { 2 k- E% k" L4 ? \! ?
+ K$ K/ R3 I' d) v2 q; r1 V5 tIpHeader *iphdr;
2 h7 ~ t5 v( e: V# z5 PIcmpHeader *icmphdr; 9 Q& r$ F# ?$ x6 u
unsigned short iphdrlen;
! r; T, w- D2 c9 @0 [3 e( U
v2 k! @2 H; C2 I$ siphdr = (IpHeader *)buf; - B6 W! y) Q4 S O1 j4 P& y
1 Q6 I4 s% J+ J. z Y6 W- ^
iphdrlen = iphdr->h_len * 4 ; // number of 32-bit words *4 = bytes : }% e6 r; K- q( m
3 |6 f! F3 W: L6 L! l5 ?- T; f# ~if (bytes < iphdrlen + ICMP_MIN) { . c X2 V. z1 y; }# x1 a- `9 U
printf("Too few bytes from %s\n",inet_ntoa(from->sin_addr));
; |8 F3 Z+ L. U7 j. V, Z} 4 H& O$ z6 L9 U v
/ {$ j7 M5 D: Z5 G- h- Dicmphdr = (IcmpHeader*)(buf + iphdrlen);
9 e9 \7 C* k4 W5 ^+ e& N' e5 ^3 Y/ @6 i: K9 u2 y0 j( c" v# e7 ]
if (icmphdr->i_type != ICMP_ECHOREPLY) {
) p& N. i3 m% Xfprintf(stderr,"non-echo type %d recvd\n",icmphdr->i_type);
+ G/ [3 w4 K: H- ereturn; L; V- U/ Y2 F1 s4 S* ]- g" w
}
5 M+ [) q$ \) o/ M- r; fif (icmphdr->i_id != (USHORT)GetCurrentProcessId()) { / l Z; `4 @5 e
fprintf(stderr,"someone else's packet!\n");
; @6 O+ E5 \3 [' sreturn ; ) o X$ M2 d2 _) k. j+ Q: n
}
$ s; M8 h9 @* {% A4 C2 |printf("%d bytes from %s:",bytes, inet_ntoa(from->sin_addr)); % B+ E0 ?6 B+ D) v7 \
printf(" icmp_seq = %d. ",icmphdr->i_seq); 7 Z6 h; [' s3 U+ [, A9 Y) J
printf(" time: %d ms ",GetTickCount()-icmphdr->timestamp); J* H* p3 H+ D1 u+ j* p4 P
printf("\n"); 1 D7 j$ {1 f0 f& X3 S" P
. M8 ?* Y0 i4 G% `) F2 J
}
4 g1 }% w2 o2 X! Z9 `6 D- g. h+ ?3 s4 E y; e" Z
/ m. f+ i8 ]2 ^ S% c/ k! J$ GUSHORT checksum(USHORT *buffer, int size) { , U6 L: a) }) ]% ]' o
, _' s4 g+ w4 L9 G# Z0 `) _6 m
unsigned long cksum=0;
1 c/ ?4 ] ^6 A, J6 D7 V
; x+ Y( l+ X3 t9 Lwhile(size >1) {
- X( k- K7 w' E4 R: Xcksum+=*buffer++;
! j4 y+ N7 S2 _ U! m7 n1 e% ysize -=sizeof(USHORT); 9 o! y z& [. u T
}
" S, S5 y X0 ?5 K" M# m- g' t- `
& z0 M* Y! k( U8 m7 t8 yif(size ) { / _6 J" T2 y1 l! L; C# y, @( w1 q
cksum += *(UCHAR*)buffer;
9 w4 V1 }! F& M; G5 a% l} - ?# C. ~: ^$ `; k
, C. h8 o$ n, t; icksum = (cksum >> 16) + (cksum & 0xffff); : s) D! `& P8 A! T U
cksum += (cksum >>16);
' \! w+ L* q3 n8 Q- Qreturn (USHORT)(~cksum);
$ K! |1 B* l* x" y3 E9 h- D8 F}
! x; w! u/ ~; A) i. |% |3 y3 H; P/*
/ Q9 o& K1 C- { _8 H) OHelper function to fill in various stuff in our ICMP request. 1 |& h5 c' u$ F
*/ 9 [2 M7 M+ I, M6 d' P# z0 G) l
void fill_icmp_data(char * icmp_data, int datasize){
. W K" X" L+ ~9 t
% G7 T B2 R5 j y/ I: S1 j9 XIcmpHeader *icmp_hdr;
2 ]9 o9 }( }" Nchar *datapart; 5 Z3 P1 m) m" C3 s v/ o4 [
6 L7 A$ L. [0 C" g- X- Z3 ]: `icmp_hdr = (IcmpHeader*)icmp_data; ; B6 s$ ?' p: S
* h% c% x, t2 s# v# Oicmp_hdr->i_type = ICMP_ECHO; % C2 L+ P+ h7 c+ M8 c! {5 }+ H* M
icmp_hdr->i_code = 0; 5 P8 O7 y, p8 F$ O1 p$ J5 Y9 ?7 a
icmp_hdr->i_id = (USHORT)GetCurrentProcessId();
& i# M: B: Y1 q& d5 ^0 [- S `icmp_hdr->i_cksum = 0;
* C' }; P/ a% N$ Uicmp_hdr->i_seq = 0;
8 \0 T! m; n0 c' G* Y( v5 U- ~% t. d3 q" x% C) |$ c* y
datapart = icmp_data + sizeof(IcmpHeader); , v( Q! m2 r; P) ~3 T
//
. m; B6 y' h# W9 u// Place some junk in the buffer. 8 j* b4 z! N5 o" ~. W
//
) ]! |7 D& ~# Bmemset(datapart,'E', datasize - sizeof(IcmpHeader));
! U5 l9 _6 l" u' \! Y! ?
2 O/ W* j- {( [} |
|