-
Notifications
You must be signed in to change notification settings - Fork 0
/
ping.h
383 lines (302 loc) · 8.73 KB
/
ping.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
/*
* This file is part of QGateway.
*
* QGateway is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* QGateway is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with QGateway. If not, see <http://www.gnu.org/licenses/>.
*
* Copyright (C) 2012 Roman Ustyugov.
*/
/*
* "ping.h" Version 1.1
*
* Copyright (C) 2002 Michael Cowan.
* All Rights Reserved
*
* 2012, Roman Ustyugov: some fixes and improvements.
*
*/
#ifndef _INC_PING
#define _INC_PING
#ifndef DEBUG_ALL
#define DEBUG_ALL 0
#endif
#pragma pack(4)
#ifndef WIN32
/* FreeBSD */
//#define _BSD_SOURCE
#define BYTE int
#define USHORT unsigned short
#define ULONG unsigned long
#define UCHAR unsigned char
#define INVALID_SOCKET -1
#define SOCKET_ERROR -1
#define SOCKET int
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/tcp.h>
#include <netinet/ip.h>
#include <netinet/in.h>
#include <netinet/ip_icmp.h>
#include <netdb.h>
#include <unistd.h>
#include <sys/ioctl.h>
#ifdef __GLIBC__
#include <netinet/if_ether.h>
#else
#include <linux/if_ether.h>
#endif
#include <net/if_arp.h>
#include <net/if.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/time.h>
#else
/* Windows */
#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#endif
/* Common */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ICMP_ECHO 8
#define ICMP_MIN 8
#define DEF_PACKET_SIZE 24
#define MAX_PACKET 64
/* The IP header */
typedef struct _iphdr {
unsigned int h_len:4; // length of the header
unsigned int version:4; // Version of IP
unsigned char tos; // Type of service
unsigned short total_len; // total length of the packet
unsigned short ident; // unique identifier
unsigned short frag_and_flags; // flags
unsigned char ttl;
unsigned char proto; // protocol (TCP, UDP etc)
unsigned short checksum; // IP checksum
unsigned int sourceIP;
unsigned int destIP;
}IpHeader;
/* The ICMP header */
typedef struct _ihdr {
BYTE i_type;
BYTE i_code;
USHORT i_cksum;
USHORT i_id;
USHORT i_seq;
ULONG timestamp;
}IcmpHeader;
/* Linux version of Windows functions */
#ifndef WIN32
#define GetCurrentProcessId() getpid()
unsigned long GetTickCount(){
struct timeval tv;
gettimeofday(&tv, NULL);
return ((tv.tv_sec*1000000)+(tv.tv_usec))/1000; // msec
};
#endif
/* Function declerations (not for external use) */
/* Format for error messages */
void ping_error(const char *pMessage){
fprintf(stderr, "[error]: <ping.h> %s\n", pMessage);
};
/* Helper function to fill in various stuff in our ICMP request. */
void fill_icmp_d(char * icmp_d, int datasize){
IcmpHeader *icmp_hdr;
char *datapart;
icmp_hdr = (IcmpHeader*)icmp_d;
icmp_hdr->i_type = ICMP_ECHO;
icmp_hdr->i_code = 0;
icmp_hdr->i_id = (USHORT)GetCurrentProcessId();
icmp_hdr->i_cksum = 0;
icmp_hdr->i_seq = 0;
datapart = icmp_d + sizeof(IcmpHeader);
//memset(datapart,'E', datasize - sizeof(IcmpHeader));
strncpy(datapart, "Whee, i`m a fast packet.",
datasize - sizeof(IcmpHeader));
};
/* Krappy checksum algorithm */
USHORT checksum(USHORT *buffer, int size) {
unsigned long cksum=0;
while(size >1) {
cksum+=*buffer++;
size -=sizeof(USHORT);
}
if(size ) {
cksum += *(UCHAR*)buffer;
}
cksum = (cksum >> 16) + (cksum & 0xffff);
cksum += (cksum >>16);
return (USHORT)(~cksum);
};
/* Used to decode recvd buffer back into an IP header */
int decode_resp(char *buf, int bytes,struct sockaddr_in *from) {
int DEBUG=0;
IpHeader *iphdr;
IcmpHeader *icmphdr;
unsigned short iphdrlen;
int nTime;
if(DEBUG_ALL)DEBUG=1;
nTime=GetTickCount();
iphdr = (IpHeader *)buf;
iphdrlen = iphdr->h_len * 4 ; // number of 32-bit words *4 = bytes
if (bytes<iphdrlen+ICMP_MIN)
ping_error("decode_resp(), too few bytes recieved");
icmphdr = (IcmpHeader*)(buf + iphdrlen);
if (icmphdr->i_id != (USHORT)GetCurrentProcessId()) {
//ping_error("someone elses packet");
//printf("--->Packets ID is %i\n", icmphdr->i_id);
return -1;
}
if(DEBUG) {
printf("[debug]: <ping.h> %d bytes from %s:",
bytes, inet_ntoa(from->sin_addr));
printf(" icmp_seq=%d",icmphdr->i_seq);
printf(" time=%d ms\n",nTime-((int)icmphdr->timestamp));}
return (nTime-(icmphdr->timestamp));
};
/*****************************************************************************/
/* DESCRIPTION: Sends a ping packet to *pDest, with nTimeout msec to live */
/* RETURN VALUE: -1 on error (dead target), else time in ms */
/*****************************************************************************/
int ping(const char *pDest, unsigned int nTimeout)
{
SOCKET sockRaw;
struct sockaddr_in dest,from;
struct hostent * hp;
int bread,datasize;
int fromlen = sizeof(from);
int bwrote;
int next=1;
int nTime=0;
char *pToken;
char target[32];
int nTargetLen;
char *dest_ip;
char icmp_d[MAX_PACKET];
char recvbuf[MAX_PACKET];
unsigned int addr=0;
USHORT seq_no = 0;
if (pDest==NULL) {
ping_error("*pDest is NULL.");
return -1;
}
memset(target, 0, sizeof(target));
pToken=(char *)strstr(pDest, ":");
if(pToken==NULL) {
nTargetLen=strlen(pDest);
strcpy(target, pDest);
}
else {
nTargetLen=pToken-pDest;
strncpy(target, pDest, nTargetLen);
}
#ifdef WIN32
sockRaw = WSASocket (AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0,0);
if (sockRaw == INVALID_SOCKET) {
ping_error("ping(), WSASocket() failed.");
return -1;
}
#else
sockRaw = socket ( AF_INET, SOCK_RAW,IPPROTO_ICMP );
if (sockRaw == INVALID_SOCKET) {
ping_error("ping(), socket failed.");
return -1;
}
#endif
memset(&dest,0,sizeof(dest));
hp = gethostbyname(target);
if (!hp)
addr=inet_addr(target);
if ((!hp) && (addr == INADDR_NONE) ) {
ping_error("ping(), unable to resolve.");
return -1;
}
if (hp != NULL)
memcpy(&(dest.sin_addr),hp->h_addr,hp->h_length);
else
dest.sin_addr.s_addr = addr;
if (hp)
dest.sin_family = hp->h_addrtype;
else
dest.sin_family = AF_INET;
dest_ip = inet_ntoa(dest.sin_addr);
datasize = DEF_PACKET_SIZE; datasize += sizeof(IcmpHeader);
memset(icmp_d, 0, MAX_PACKET);
fill_icmp_d(icmp_d,datasize);
if (next>=0) {
memset(recvbuf, 0, MAX_PACKET);
((IcmpHeader*)icmp_d)->i_cksum = 0;
((IcmpHeader*)icmp_d)->timestamp = GetTickCount();
((IcmpHeader*)icmp_d)->i_seq = seq_no++;
((IcmpHeader*)icmp_d)->i_cksum = checksum((USHORT*)icmp_d, datasize);
nTime=GetTickCount();
bwrote = sendto(sockRaw,icmp_d,datasize,0,(struct sockaddr*)&dest,
sizeof(dest));
if (bwrote == SOCKET_ERROR){
ping_error("ping(), sendto failed.");
return -1;
}
if (bwrote < datasize )
ping_error("ping(), couldn't write all bytes.");
}
#ifndef WIN32
fcntl(sockRaw, F_SETFL, O_NONBLOCK);
for (unsigned int to = 0; to < nTimeout; to += 1)
{
if (GetTickCount()-nTime>nTimeout)
return -1;
bread = recvfrom(sockRaw,recvbuf,MAX_PACKET,0,
(struct sockaddr*)&from, (socklen_t*)&fromlen);
if (bread > 0)
break;
usleep(1000);
qApp->processEvents();
}
close(sockRaw);
#else
u_long nonblocking = 1;
ioctlsocket(sockRaw, FIONBIO, &nonblocking);
for (unsigned int to = 0; to < nTimeout; to += 1)
{
if (GetTickCount()-nTime>nTimeout)
return -1;
bread = recvfrom(sockRaw,recvbuf,MAX_PACKET,0,
(struct sockaddr*)&from, &fromlen);
if (WSAGetLastError() != WSAEWOULDBLOCK)
break;
else
{
Sleep(1);
qApp->processEvents();
}
}
closesocket(sockRaw);
#endif
if (GetTickCount()-nTime>nTimeout)
return -1;
if (bread == SOCKET_ERROR)
{
ping_error("ping(), recvfrom failed.");
return -1;
}
next = decode_resp(recvbuf,bread,&from);
if (next>=0)
return next;
return 0;
};
#endif