|
|
******************************************************************************\
9 X+ Y1 i d9 J9 K9 Y6 W* B' p* ping.c - Simple ping utility using SOCK_RAW
b( Z, |% k; x5 g+ J2 U( R p( I*
$ `4 b# @; H* a0 D5 j* This is a part of the Microsoft Source Code Samples.
& P6 M) @) L4 f2 R6 M* Copyright 1996-1997 Microsoft Corporation. , z1 a& G+ ]! ~1 ^5 z
* All rights reserved. / h4 w" M6 K2 q. f4 q8 |# }
* This source code is only intended as a supplement to * K- P( Z" j7 {* V% q
* Microsoft Development Tools and/or WinHelp documentation.
5 r, I: x! V7 b$ D) _* See these sources for detailed information regarding the $ i1 G$ l7 o: p3 `0 h
* Microsoft samples programs. 9 P5 W. H" n& f- |' c
\******************************************************************************/ 4 U2 w4 V1 q9 ]3 H+ l) H
- g. d: r2 M# @7 ?0 {6 w2 Z9 S: v
#pragma pack(4) - ~- |- ~3 @) p* {
! w# }6 [7 Y) P0 {9 t, x
#define WIN32_LEAN_AND_MEAN 2 c1 R; T4 k- |3 a' Q: s7 u- }
#include
# ?: R0 m. e# c& ~#include
6 N! ~1 h8 i& ?" A4 w9 Z& |9 q: M#include
5 b h7 A* A6 T9 x$ H5 @" @; R6 p+ _" A
#define ICMP_ECHO 8
4 }: ^7 i& |6 `+ ~. }% _; M& K#define ICMP_ECHOREPLY 0 2 k3 o* @! W' M" j9 b+ U) b+ N1 l
3 _( c7 s# ?3 p/ p. n) r T, c; j#define ICMP_MIN 8 // minimum 8 byte icmp packet (just header) 7 B' L0 |# Z% b3 _, Y
; l1 Y8 J" _2 E& ?+ Z
/* The IP header */
4 O& b0 D0 ^3 F, F) u5 atypedef struct iphdr { ( k, o" z% D) g2 v* h. E. A
unsigned int h_len:4; // length of the header
- n$ a g2 A9 i3 Y. Sunsigned int version:4; // Version of IP
" @1 `2 I1 X% f6 K, kunsigned char tos; // Type of service 8 L2 I/ O. S! y+ L' w
unsigned short total_len; // total length of the packet
8 n+ e& y+ |7 J2 `# B# [" z& ]' ]7 @( munsigned short ident; // unique identifier
& @+ {. l% X# C& i. P2 k" b' eunsigned short frag_and_flags; // flags % B; ?! Z+ u8 c4 }. |3 R# ~; |
unsigned char ttl; " \) s# @5 O7 D$ N. P1 L
unsigned char proto; // protocol (TCP, UDP etc)
! E3 p* @6 x3 e9 I/ Funsigned short checksum; // IP checksum
3 I+ L5 x6 V9 q% S4 `2 h) h1 [
O$ C; t+ z' e& G( x' Aunsigned int sourceIP; , }6 J& `; ^! P+ G* `% q- S
unsigned int destIP; 9 S% X6 r1 x6 k6 E8 A9 ]. v5 S# Q
7 ^; P J' _+ {}IpHeader; T. t0 x# i7 `6 i) b" A# \* M" W
; I0 Y! G+ U: a! O* l4 L( r+ e//
& Q9 O2 v: d2 {$ I3 ~// ICMP header + ~, F9 D: M1 C$ [0 @2 C: ^5 Z
// . h. P' u+ ` |/ h( Y
typedef struct _ihdr {
0 p- N0 ]; {9 v1 mBYTE i_type; $ I. Z' g5 O. X" D H4 G( c. i0 k
BYTE i_code; /* type sub code */ . X/ h8 y" Z4 f/ [+ I
USHORT i_cksum; + _ j) Q/ u9 k" e7 M; e8 O0 l5 |: T( X
USHORT i_id; + V; y- w, g+ g
USHORT i_seq; ' x4 [( l% \$ R$ V5 G" d
/* This is not the std header, but we reserve space for time */
b2 B! ?# g! NULONG timestamp; / ]$ |4 a" @- @( a
}IcmpHeader;
" n2 b9 `3 l/ H) o1 W" j, j+ H; J# J+ G% c
#define STATUS_FAILED 0xFFFF
' e0 L6 H/ F8 j4 w% ^#define DEF_PACKET_SIZE 32 - M, Z- Y+ I( k1 [0 W
#define MAX_PACKET 1024 3 ^% s; n+ u2 F- |" n
1 J! l& L! `, M) x" `" v! W#define xmalloc(s) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(s)) ( q% |3 m9 y6 O" |+ A- z
#define xfree(p) HeapFree (GetProcessHeap(),0,(p))
( s2 v! ~; u9 z; T; O3 E$ b2 g& K7 X, V
void fill_icmp_data(char *, int); $ G1 n7 P% a* G
USHORT checksum(USHORT *, int); # X H+ O% C1 D* K" L+ S
void decode_resp(char *,int ,struct sockaddr_in *);
6 X3 I" K0 [. j- a$ S
8 C% ^! _6 o) c1 ]1 z7 gvoid Usage(char *progname){ , [8 o9 T& f4 `3 Z0 f
, V% v O: m$ g5 _5 s! H# p: C mfprintf(stderr,"Usage:\n"); % w2 l8 K/ y; ?: L4 M2 S% h5 ?9 F
fprintf(stderr,"%s [data_size]\n",progname);
+ I/ `( M F3 h; |$ k+ D" V& yfprintf(stderr,"datasize can be up to 1Kb\n"); 9 [, K& T4 R! {8 m. s) `0 `- X' \8 ?9 Q
ExitProcess(STATUS_FAILED); 4 [# q" k# u2 ]0 y( E
! x% @2 N" w, L) V& e} ' `; c, q) c! V
int main(int argc, char **argv){
7 @4 ~! Z$ {. D h N5 R& J2 X7 l4 O2 \
WSADATA wsaData;
1 Y0 e- S6 n! [( dSOCKET sockRaw;
# h7 D% f* M0 q1 ?1 i$ N& D# Kstruct sockaddr_in dest,from; # {. P3 w+ ?; q1 |, x' ^
struct hostent * hp; & G% C7 k$ M8 j( y+ n4 F e
int bread,datasize; $ [4 \# H: o1 l3 b
int fromlen = sizeof(from); 1 k( F3 u" h3 M- `
int timeout = 1000;
& n6 G7 Q8 Q/ ]6 q$ V* Xchar *dest_ip; 3 A" b! y! V% C3 ?! e
char *icmp_data;
8 C( q! t! ^3 v' f6 _- t5 uchar *recvbuf;
' f4 @) A; T: B; Uunsigned int addr=0;
9 Q1 C: I# g4 L5 v" Q/ {USHORT seq_no = 0; - \& B" s0 C" [# M$ y+ `& F
& C# ~6 m4 B& S7 \$ Cif (WSAStartup(MAKEWORD(2,1),&wsaData) != 0){
k- l/ w% f8 K1 F zfprintf(stderr,"WSAStartup failed: %d\n",GetLastError());
) L9 ?( ~/ H' SExitProcess(STATUS_FAILED);
7 e' j; r9 b7 f4 K" ~& f3 e0 _' z}
& E; D# w" x( x5 B1 p4 x, Q7 f6 [, U% W( r$ x
if (argc <2 ) {
: q% n+ g9 K2 FUsage(argv[0]);
# P2 I, W. l, y) n. u6 g+ l$ Y4 ?9 G8 }} 2 @' R' i% f3 ]$ l& f3 P& v
sockRaw = WSASocket (AF_INET,
5 V; \. b1 ^! m! ?0 e1 TSOCK_RAW,
: z( q( v- F6 B/ @' s) M! v7 zIPPROTO_ICMP, . `. R3 d# x% j* l0 {0 m' E7 r
NULL, 0,0);
: Z7 \+ ]7 r9 a, ^2 V4 b6 L' h
% n# ]$ T/ b. {if (sockRaw == INVALID_SOCKET) { 3 i$ U9 b" B! Y/ d, a7 P4 ~3 E
fprintf(stderr,"WSASocket() failed: %d\n",WSAGetLastError());
. N; I8 A' j' D$ W G, a; b" LExitProcess(STATUS_FAILED);
9 D8 P( F2 y/ z. m) `' `0 ^, f% P( P} + m* K+ n! p$ f' G5 q
bread = setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout, + s7 O4 C5 x; ]& |4 c
sizeof(timeout));
# q0 [+ _7 o" D' |+ [if(bread == SOCKET_ERROR) {
7 Z! d3 \7 V/ { g5 L: U( o% Tfprintf(stderr,"failed to set recv timeout: %d\n",WSAGetLastError());
4 E7 M8 K# b# r# V9 uExitProcess(STATUS_FAILED); + Z' U k; R- v3 y
}
& z2 k8 _7 r3 W- g& g2 Vtimeout = 1000;
0 t' ^4 e D* @5 N$ Ebread = setsockopt(sockRaw,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout,
+ N+ `$ j" G; F0 w' G H' X7 C4 M9 E5 M* A! Jsizeof(timeout));
, c, \0 _& k. {0 d# M( G$ kif(bread == SOCKET_ERROR) {
! v. R: Q3 h+ q4 [8 A* {5 i4 t/ O2 Vfprintf(stderr,"failed to set send timeout: %d\n",WSAGetLastError()); : Y/ g% |0 \" L* O
ExitProcess(STATUS_FAILED);
1 p* K) s8 ~3 r- x" a: I" H* e5 g} 3 c$ p/ x: j) h T, W7 w7 J! C' e
memset(&dest,0,sizeof(dest)); 4 E3 [( ]4 T0 I/ i
4 k8 G' s3 W2 B" z E( X$ X
hp = gethostbyname(argv[1]);
0 d+ u$ F0 L3 {3 R# `' L: g6 z0 R& L+ q) b4 N* Q
if (!hp){ 4 ^8 e0 ]: {9 `6 A9 X* f
addr = inet_addr(argv[1]); 9 P- I& d4 i) p/ _. r! i6 R
} 7 z" y8 {. R- v
if ((!hp) && (addr == INADDR_NONE) ) {
) b. h/ J/ E: X: ~fprintf(stderr,"Unable to resolve %s\n",argv[1]);
7 U9 w, M& U7 |7 a6 lExitProcess(STATUS_FAILED);
; \0 O c" |9 K# C; y1 r% B}
( [4 ?, }; x" ?5 T7 h+ a) j. {0 Y- V
if (hp != NULL)
# a5 b; X( R. p4 Cmemcpy(&(dest.sin_addr),hp->h_addr,hp->h_length); & @6 \! G; ?7 e5 n
else 8 @! N5 \ O5 ^- A. H+ C3 z6 D/ ^* ?
dest.sin_addr.s_addr = addr; , n: U' A9 L9 [* }4 }. B
; H8 Z+ V- o* y& Y+ Z
if (hp)
4 c5 y% c, [( k9 \( }dest.sin_family = hp->h_addrtype;
% s/ N: L7 F. x1 Y- s0 celse : S5 h% v. v _! F1 @
dest.sin_family = AF_INET; & z' D! L7 w) g( t) S
4 H& P' ~( {6 S- S$ \7 Z* U6 x
dest_ip = inet_ntoa(dest.sin_addr); ; K$ ], ^- H7 z# {+ v" i0 }
0 ^3 \6 b! w! v+ b- x
if (argc >2) { 9 p4 Z& D- q0 U5 r% ]7 \
datasize = atoi(argv[2]); 5 @' s6 r) ?( |5 d, i
if (datasize == 0)
. z7 S* i4 U0 I& D. b$ Q" N. xdatasize = DEF_PACKET_SIZE; ( _/ T0 T3 o6 e& T4 C; e
3 l7 m8 t3 G5 P4 l8 F2 j( S/ A
}
* K3 r# e# d( L8 L( X0 aelse
7 u% M3 C& j* ydatasize = DEF_PACKET_SIZE; : H4 Y8 s; G( g# I0 j0 ~2 \; o* o
' h# ^; `1 {8 C* b0 L, Bdatasize += sizeof(IcmpHeader); B: a! P2 K! `0 A3 q/ \0 A" \
6 |" `- V. X' g
icmp_data = xmalloc(MAX_PACKET);
- ^0 _! N: b- N, H# C; }: I' ?recvbuf = xmalloc(MAX_PACKET); + e" B5 o: r- u- V9 W. |1 e. e9 e
' K5 E7 S9 p, ~3 `7 ^ H1 {: Q
if (!icmp_data) {
! b7 W8 I* p- {: }) Q1 x# o3 Cfprintf(stderr,"HeapAlloc failed %d\n",GetLastError()); 0 ^& }/ U' A3 L5 r& S5 k" Z
ExitProcess(STATUS_FAILED);
7 G5 q: D+ \ X) w' o- D}! J+ R( w8 f4 C9 x
memset(icmp_data,0,MAX_PACKET); * j4 h- b! [2 B6 S+ j
fill_icmp_data(icmp_data,datasize);
' N, F! V1 q' }7 f7 \% Q' `5 H% w6 ~$ F" m
6 N# w- [& I; m. uwhile(1) { . Y2 [$ c7 @0 D2 r6 z/ f; |
int bwrote; & F( O1 b0 Z) l( ]: I
3 e. E5 x) s! H* h, E; w
((IcmpHeader*)icmp_data)->i_cksum = 0;
3 r( N; P; _7 x+ w((IcmpHeader*)icmp_data)->timestamp = GetTickCount(); M# R3 K1 q8 A
- H5 }. w9 y- c9 B- F((IcmpHeader*)icmp_data)->i_seq = seq_no++; # f! L d P4 O
((IcmpHeader*)icmp_data)->i_cksum = checksum((USHORT*)icmp_data, 7 L0 a2 z' P! O+ ?. [' B
datasize); ) B( ?: |* c4 B, Q2 o5 t) D
. v% p' I9 c5 H7 e
bwrote = sendto(sockRaw,icmp_data,datasize,0,(struct sockaddr*)&dest, 2 ?1 k5 {( L; _; e8 ~: E! O- d
sizeof(dest));
6 |+ M1 q4 o+ v2 h4 F, rif (bwrote == SOCKET_ERROR){
( q) C) k! n- t* P+ mif (WSAGetLastError() == WSAETIMEDOUT) { 5 Q, N" X9 L, n, R# p
printf("timed out\n");
0 ~" S& y: o D2 a# v) J0 Ocontinue;
2 L$ P0 A, \0 R, A}
* w$ W+ @" f4 cfprintf(stderr,"sendto failed: %d\n",WSAGetLastError());
' J0 N# n7 H! M& ^ExitProcess(STATUS_FAILED);
* T& f M6 ^* M: e; }6 J} 9 ` B2 n! J7 `
if (bwrote < datasize ) { 2 E! f6 l4 d+ a( X4 H4 ^5 h M
fprintf(stdout,"Wrote %d bytes\n",bwrote); % _/ j& a/ _" Q( Y
} * l/ ~2 D5 O# _" P8 U" E' a/ O
bread = recvfrom(sockRaw,recvbuf,MAX_PACKET,0,(struct sockaddr*)&from, ' e% F, x- r1 M$ ~% P! z5 u2 Q
&fromlen); $ C! ?1 H& J8 p$ l* a
if (bread == SOCKET_ERROR){
9 Q9 x6 w: I; I3 u' t, Lif (WSAGetLastError() == WSAETIMEDOUT) { , t% L( Q5 \% x, `
printf("timed out\n");
- U! L% m5 H$ E+ w3 h9 q; r6 dcontinue; ; c( W0 G4 m$ m
}
6 h4 C& R4 Y7 y, t8 L! @ Zfprintf(stderr,"recvfrom failed: %d\n",WSAGetLastError()); 6 [6 w" ?9 G) s& g* E
ExitProcess(STATUS_FAILED); , W2 l# ?5 k: F8 i5 x# c
} 9 \: T9 I% j) p- O) K, D' x. W
decode_resp(recvbuf,bread,&from); 0 o2 D' C4 e1 c
Sleep(1000); 6 c$ g) w2 f# S; `5 Y+ B
" v9 d. @/ |0 l% @) \( \}
, o3 O9 E4 s$ n5 M. p) g, t/ h! mreturn 0;
, A/ }9 p; _( T0 m; \7 ~" o# f
: z( N! _9 X+ s8 \$ ?} : [8 V$ O3 T% b+ X1 y) `% J
/*
5 g6 @4 Z5 w# v. U* m% L( NThe response is an IP packet. We must decode the IP header to locate ; V. K4 T" I/ `6 B' u, E7 a* \
the ICMP data # u6 B' p* F6 k
*/ ( Z/ v5 P" X5 D: a9 X/ o
void decode_resp(char *buf, int bytes,struct sockaddr_in *from) {
% Y, t* i: `! J$ Q2 D* E. g/ O4 X5 S9 a x
IpHeader *iphdr;
" S6 f. j7 Z8 m* G, AIcmpHeader *icmphdr;
" C( @1 i n/ F- f3 I# @2 ~1 r2 k4 tunsigned short iphdrlen;
5 V; k8 y5 n6 f, Z4 y# A& y S, U* g/ t# Y5 `: y, I3 h( M
iphdr = (IpHeader *)buf;
# ?, Q) J( x# G; a6 ~% S! n6 M3 ?: h
Y6 I$ C) y) \4 ]iphdrlen = iphdr->h_len * 4 ; // number of 32-bit words *4 = bytes
* B c, W. q) a4 w# | O( ]: `) y+ D1 X- C3 D: _6 d% r
if (bytes < iphdrlen + ICMP_MIN) { * M! |1 v# O- ]- M8 S. e9 e1 s7 w
printf("Too few bytes from %s\n",inet_ntoa(from->sin_addr));
- C. D* [: f' T% P2 A} - |8 x6 z/ R9 U7 M
( u) g, p* F& H1 g* N
icmphdr = (IcmpHeader*)(buf + iphdrlen);
; }1 N0 v6 |# Z5 M) u k7 }7 [5 `
if (icmphdr->i_type != ICMP_ECHOREPLY) {
; r2 ]8 J( H% l1 n# i- ]; Ifprintf(stderr,"non-echo type %d recvd\n",icmphdr->i_type);
) e5 q% M/ D' U7 U( M7 b! |; a" [return; 8 S6 D% d8 {( l Y3 T- K; f
}
; V# ~ [$ K+ Uif (icmphdr->i_id != (USHORT)GetCurrentProcessId()) { 1 S" T% p1 d# I* q: q5 {
fprintf(stderr,"someone else's packet!\n");
: z! c- |* d3 v" \! U4 A% Ereturn ; * k9 ^7 c0 q- W/ R8 J, [
}
3 O( N( e1 E. S3 {, z6 jprintf("%d bytes from %s:",bytes, inet_ntoa(from->sin_addr)); 8 m; O! s( {, Y! c* W5 B
printf(" icmp_seq = %d. ",icmphdr->i_seq); , ]+ {7 h+ K2 b
printf(" time: %d ms ",GetTickCount()-icmphdr->timestamp); % O7 v+ a6 B+ ?% [/ {# v7 b
printf("\n"); 5 f0 }: S, o3 W! Z0 k; ^
5 X* l- A& c/ n/ W& g7 s* R
} 3 {! h2 }' l [; j; \" e4 Q
7 w2 x6 [7 s2 E$ C
, ?$ m8 }; v7 U3 G& AUSHORT checksum(USHORT *buffer, int size) {
) e7 ^5 V# w) n* n) c7 |- j
& M) H& U7 J0 c) \1 ?unsigned long cksum=0; $ n" I# L* [- _- ^+ f! t
8 u8 Q: w e* j' S
while(size >1) {
6 L/ F# s' f0 d3 @! |8 Y" lcksum+=*buffer++; ! Z# d$ _3 \2 u, k9 s
size -=sizeof(USHORT); # W8 z- c* X' T8 M) a
}
9 L+ h }4 z# M; T6 G% Z7 S1 t: n4 f- z9 T* A7 H: O
if(size ) {
5 ?0 j. T) G: }3 e; icksum += *(UCHAR*)buffer;
! V3 G# m) S ]! M) K} ! d$ x2 w5 c* y4 `
+ A2 B. w% k- N9 K2 O
cksum = (cksum >> 16) + (cksum & 0xffff);
! @# g* M6 B# K0 o& q" Rcksum += (cksum >>16); 7 F/ R& C) I5 { b
return (USHORT)(~cksum);
6 u9 K( K2 y$ |9 M$ D} $ r: L% I( D: [" P
/* 4 j$ I( S3 ~+ U1 v. ?4 d
Helper function to fill in various stuff in our ICMP request.
7 C* \* T# d. h% _1 L1 F( {*/ # j! Y. @& i1 E4 s
void fill_icmp_data(char * icmp_data, int datasize){
" `8 H- x0 N: V) [$ v1 K
: V6 ~& X/ }# m1 ]% F. m, j5 D' {IcmpHeader *icmp_hdr;
/ s$ i/ J8 U$ S6 e% z: {3 m$ J% \char *datapart;
" n1 N) |* k' X) X, E( [% @3 R2 T4 |+ K; U- C; l
icmp_hdr = (IcmpHeader*)icmp_data; 4 g& @2 l' E# J( o
0 a0 k- D( ^3 D' v5 `- g
icmp_hdr->i_type = ICMP_ECHO; # W2 J5 n, m9 }/ E. [ d4 _
icmp_hdr->i_code = 0; 7 ]1 N, k+ C1 s( P) F
icmp_hdr->i_id = (USHORT)GetCurrentProcessId();
$ N7 `1 R% }& W. q: Licmp_hdr->i_cksum = 0;
% K0 P' W$ }/ s+ n1 \, uicmp_hdr->i_seq = 0;
$ X% F7 Z; m+ i/ O4 R, Y$ l6 v) T( A" O* ~4 L' Y" J! F3 ^4 n
datapart = icmp_data + sizeof(IcmpHeader); % j* i( n) V8 ~, J
//
4 `# z/ E4 b1 v R' @4 V// Place some junk in the buffer.
, _9 H! P+ n# l8 P; j//
4 s u* w( `- y/ v# Pmemset(datapart,'E', datasize - sizeof(IcmpHeader));
9 X9 i1 o" r K- m% P8 F- P
" g9 ^* I+ m" H ]4 y; n, \7 v} |
|