1 |
|
|
/* $OpenBSD: ping.c,v 1.139 2016/03/03 18:30:48 florian Exp $ */ |
2 |
|
|
/* $NetBSD: ping.c,v 1.20 1995/08/11 22:37:58 cgd Exp $ */ |
3 |
|
|
|
4 |
|
|
/* |
5 |
|
|
* Copyright (c) 1989, 1993 |
6 |
|
|
* The Regents of the University of California. All rights reserved. |
7 |
|
|
* |
8 |
|
|
* This code is derived from software contributed to Berkeley by |
9 |
|
|
* Mike Muuss. |
10 |
|
|
* |
11 |
|
|
* Redistribution and use in source and binary forms, with or without |
12 |
|
|
* modification, are permitted provided that the following conditions |
13 |
|
|
* are met: |
14 |
|
|
* 1. Redistributions of source code must retain the above copyright |
15 |
|
|
* notice, this list of conditions and the following disclaimer. |
16 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
17 |
|
|
* notice, this list of conditions and the following disclaimer in the |
18 |
|
|
* documentation and/or other materials provided with the distribution. |
19 |
|
|
* 3. Neither the name of the University nor the names of its contributors |
20 |
|
|
* may be used to endorse or promote products derived from this software |
21 |
|
|
* without specific prior written permission. |
22 |
|
|
* |
23 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
24 |
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
25 |
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
26 |
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
27 |
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
28 |
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
29 |
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
30 |
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
31 |
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
32 |
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
33 |
|
|
* SUCH DAMAGE. |
34 |
|
|
*/ |
35 |
|
|
|
36 |
|
|
/* |
37 |
|
|
* P I N G . C |
38 |
|
|
* |
39 |
|
|
* Using the InterNet Control Message Protocol (ICMP) "ECHO" facility, |
40 |
|
|
* measure round-trip-delays and packet loss across network paths. |
41 |
|
|
* |
42 |
|
|
* Author - |
43 |
|
|
* Mike Muuss |
44 |
|
|
* U. S. Army Ballistic Research Laboratory |
45 |
|
|
* December, 1983 |
46 |
|
|
* |
47 |
|
|
* Status - |
48 |
|
|
* Public Domain. Distribution Unlimited. |
49 |
|
|
* Bugs - |
50 |
|
|
* More statistics could always be gathered. |
51 |
|
|
* This program has to run SUID to ROOT to access the ICMP socket. |
52 |
|
|
*/ |
53 |
|
|
|
54 |
|
|
#include <sys/types.h> |
55 |
|
|
#include <sys/socket.h> |
56 |
|
|
#include <sys/time.h> |
57 |
|
|
|
58 |
|
|
#include <netinet/in.h> |
59 |
|
|
#include <netinet/ip.h> |
60 |
|
|
#include <netinet/ip_icmp.h> |
61 |
|
|
#include <netinet/ip_var.h> |
62 |
|
|
#include <arpa/inet.h> |
63 |
|
|
#include <netdb.h> |
64 |
|
|
|
65 |
|
|
#include <ctype.h> |
66 |
|
|
#include <err.h> |
67 |
|
|
#include <errno.h> |
68 |
|
|
#include <limits.h> |
69 |
|
|
#include <math.h> |
70 |
|
|
#include <poll.h> |
71 |
|
|
#include <signal.h> |
72 |
|
|
#include <siphash.h> |
73 |
|
|
#include <stdint.h> |
74 |
|
|
#include <stdio.h> |
75 |
|
|
#include <stdlib.h> |
76 |
|
|
#include <string.h> |
77 |
|
|
#include <time.h> |
78 |
|
|
#include <unistd.h> |
79 |
|
|
|
80 |
|
|
struct tv64 { |
81 |
|
|
u_int64_t tv64_sec; |
82 |
|
|
u_int64_t tv64_nsec; |
83 |
|
|
}; |
84 |
|
|
|
85 |
|
|
struct payload { |
86 |
|
|
struct tv64 tv64; |
87 |
|
|
u_int8_t mac[SIPHASH_DIGEST_LENGTH]; |
88 |
|
|
}; |
89 |
|
|
|
90 |
|
|
#define DEFDATALEN (64 - 8) /* default data length */ |
91 |
|
|
#define MAXIPLEN 60 |
92 |
|
|
#define MAXICMPLEN 76 |
93 |
|
|
#define MAXPAYLOAD (IP_MAXPACKET - MAXIPLEN - 8) /* max ICMP payload size */ |
94 |
|
|
#define MAXWAIT_DEFAULT 10 /* secs to wait for response */ |
95 |
|
|
#define NROUTES 9 /* number of record route slots */ |
96 |
|
|
|
97 |
|
|
#define A(bit) rcvd_tbl[(bit)>>3] /* identify byte in array */ |
98 |
|
|
#define B(bit) (1 << ((bit) & 0x07)) /* identify bit in byte */ |
99 |
|
|
#define SET(bit) (A(bit) |= B(bit)) |
100 |
|
|
#define CLR(bit) (A(bit) &= (~B(bit))) |
101 |
|
|
#define TST(bit) (A(bit) & B(bit)) |
102 |
|
|
|
103 |
|
|
/* various options */ |
104 |
|
|
int options; |
105 |
|
|
#define F_FLOOD 0x0001 |
106 |
|
|
#define F_INTERVAL 0x0002 |
107 |
|
|
#define F_NUMERIC 0x0004 |
108 |
|
|
#define F_PINGFILLED 0x0008 |
109 |
|
|
#define F_QUIET 0x0010 |
110 |
|
|
#define F_RROUTE 0x0020 |
111 |
|
|
#define F_SO_DEBUG 0x0040 |
112 |
|
|
/* 0x0080 */ |
113 |
|
|
#define F_VERBOSE 0x0100 |
114 |
|
|
/* 0x0200 */ |
115 |
|
|
#define F_HDRINCL 0x0400 |
116 |
|
|
#define F_TTL 0x0800 |
117 |
|
|
#define F_AUD_RECV 0x2000 |
118 |
|
|
#define F_AUD_MISS 0x4000 |
119 |
|
|
|
120 |
|
|
/* multicast options */ |
121 |
|
|
int moptions; |
122 |
|
|
#define MULTICAST_NOLOOP 0x001 |
123 |
|
|
#define MULTICAST_TTL 0x002 |
124 |
|
|
#define MULTICAST_IF 0x004 |
125 |
|
|
|
126 |
|
|
/* |
127 |
|
|
* MAX_DUP_CHK is the number of bits in received table, i.e. the maximum |
128 |
|
|
* number of received sequence numbers we can keep track of. Change 128 |
129 |
|
|
* to 8192 for complete accuracy... |
130 |
|
|
*/ |
131 |
|
|
#define MAX_DUP_CHK (8 * 8192) |
132 |
|
|
int mx_dup_ck = MAX_DUP_CHK; |
133 |
|
|
char rcvd_tbl[MAX_DUP_CHK / 8]; |
134 |
|
|
|
135 |
|
|
struct sockaddr_in whereto; /* who to ping */ |
136 |
|
|
unsigned int datalen = DEFDATALEN; |
137 |
|
|
int s; /* socket file descriptor */ |
138 |
|
|
u_char outpackhdr[IP_MAXPACKET]; /* Max packet size = 65535 */ |
139 |
|
|
u_char *outpack = outpackhdr+sizeof(struct ip); |
140 |
|
|
char BSPACE = '\b'; /* characters written for flood */ |
141 |
|
|
char DOT = '.'; |
142 |
|
|
char *hostname; |
143 |
|
|
int ident; /* process id to identify our packets */ |
144 |
|
|
|
145 |
|
|
/* counters */ |
146 |
|
|
int64_t npackets; /* max packets to transmit */ |
147 |
|
|
int64_t nreceived; /* # of packets we got back */ |
148 |
|
|
int64_t nrepeats; /* number of duplicates */ |
149 |
|
|
int64_t ntransmitted; /* sequence # for outbound packets = #sent */ |
150 |
|
|
int64_t nmissedmax = 1; /* max value of ntransmitted - nreceived - 1 */ |
151 |
|
|
struct timeval interval = {1, 0}; /* interval between packets */ |
152 |
|
|
|
153 |
|
|
/* timing */ |
154 |
|
|
int timing; /* flag to do timing */ |
155 |
|
|
int timinginfo; |
156 |
|
|
unsigned int maxwait = MAXWAIT_DEFAULT; /* max seconds to wait for response */ |
157 |
|
|
double tmin = 999999999.0; /* minimum round trip time */ |
158 |
|
|
double tmax = 0.0; /* maximum round trip time */ |
159 |
|
|
double tsum = 0.0; /* sum of all times, for doing average */ |
160 |
|
|
double tsumsq = 0.0; /* sum of all times squared, for std. dev. */ |
161 |
|
|
int bufspace = IP_MAXPACKET; |
162 |
|
|
|
163 |
|
|
struct tv64 tv64_offset; |
164 |
|
|
SIPHASH_KEY mac_key; |
165 |
|
|
|
166 |
|
|
volatile sig_atomic_t seenalrm; |
167 |
|
|
volatile sig_atomic_t seenint; |
168 |
|
|
volatile sig_atomic_t seeninfo; |
169 |
|
|
|
170 |
|
|
void fill(char *, char *); |
171 |
|
|
void summary(int); |
172 |
|
|
int in_cksum(u_short *, int); |
173 |
|
|
void onsignal(int); |
174 |
|
|
void retransmit(void); |
175 |
|
|
void onint(int); |
176 |
|
|
int pinger(void); |
177 |
|
|
char *pr_addr(in_addr_t); |
178 |
|
|
int check_icmph(struct ip *); |
179 |
|
|
void pr_icmph(struct icmp *); |
180 |
|
|
void pr_pack(char *, int, struct msghdr *); |
181 |
|
|
void pr_retip(struct ip *); |
182 |
|
|
void pr_iph(struct ip *); |
183 |
|
|
#ifndef SMALL |
184 |
|
|
int map_tos(char *, int *); |
185 |
|
|
#endif /* SMALL */ |
186 |
|
|
void usage(void); |
187 |
|
|
|
188 |
|
|
int |
189 |
|
|
main(int argc, char *argv[]) |
190 |
|
|
{ |
191 |
|
|
struct hostent *hp; |
192 |
|
|
struct addrinfo hints, *res; |
193 |
|
|
struct itimerval itimer; |
194 |
|
|
struct sockaddr_in from, from4; |
195 |
|
|
struct sockaddr_in *to; |
196 |
|
|
int64_t preload; |
197 |
|
|
int ch, i, optval = 1, packlen, maxsize, df = 0, tos = 0; |
198 |
|
|
int error; |
199 |
|
|
u_char *datap, *packet, ttl = MAXTTL, loop = 1; |
200 |
|
|
char *e, *target, hnamebuf[HOST_NAME_MAX+1], *source = NULL; |
201 |
|
|
char rspace[3 + 4 * NROUTES + 1]; /* record route space */ |
202 |
|
|
socklen_t maxsizelen; |
203 |
|
|
const char *errstr; |
204 |
|
|
double intval; |
205 |
|
|
uid_t uid; |
206 |
|
|
u_int rtableid = 0; |
207 |
|
|
|
208 |
|
|
if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) |
209 |
|
|
err(1, "socket"); |
210 |
|
|
|
211 |
|
|
/* revoke privs */ |
212 |
|
|
uid = getuid(); |
213 |
|
|
if (setresuid(uid, uid, uid) == -1) |
214 |
|
|
err(1, "setresuid"); |
215 |
|
|
|
216 |
|
|
preload = 0; |
217 |
|
|
datap = &outpack[8 + sizeof(struct payload)]; |
218 |
|
|
while ((ch = getopt(argc, argv, |
219 |
|
|
"DEI:LRS:c:defi:l:np:qs:T:t:V:vw:")) != -1) |
220 |
|
|
switch(ch) { |
221 |
|
|
case 'c': |
222 |
|
|
npackets = strtonum(optarg, 0, INT64_MAX, &errstr); |
223 |
|
|
if (errstr) |
224 |
|
|
errx(1, |
225 |
|
|
"number of packets to transmit is %s: %s", |
226 |
|
|
errstr, optarg); |
227 |
|
|
break; |
228 |
|
|
case 'D': |
229 |
|
|
options |= F_HDRINCL; |
230 |
|
|
df = 1; |
231 |
|
|
break; |
232 |
|
|
case 'd': |
233 |
|
|
options |= F_SO_DEBUG; |
234 |
|
|
break; |
235 |
|
|
case 'E': |
236 |
|
|
options |= F_AUD_MISS; |
237 |
|
|
break; |
238 |
|
|
case 'e': |
239 |
|
|
options |= F_AUD_RECV; |
240 |
|
|
break; |
241 |
|
|
case 'f': |
242 |
|
|
if (getuid()) |
243 |
|
|
errx(1, "%s", strerror(EPERM)); |
244 |
|
|
options |= F_FLOOD; |
245 |
|
|
setvbuf(stdout, NULL, _IONBF, 0); |
246 |
|
|
break; |
247 |
|
|
case 'I': |
248 |
|
|
case 'S': /* deprecated */ |
249 |
|
|
source = optarg; |
250 |
|
|
break; |
251 |
|
|
case 'i': /* wait between sending packets */ |
252 |
|
|
intval = strtod(optarg, &e); |
253 |
|
|
if (*optarg == '\0' || *e != '\0') |
254 |
|
|
errx(1, "illegal timing interval %s", optarg); |
255 |
|
|
if (intval < 1 && getuid()) { |
256 |
|
|
errx(1, "%s: only root may use interval < 1s", |
257 |
|
|
strerror(EPERM)); |
258 |
|
|
} |
259 |
|
|
interval.tv_sec = (time_t)intval; |
260 |
|
|
interval.tv_usec = |
261 |
|
|
(long)((intval - interval.tv_sec) * 1000000); |
262 |
|
|
if (interval.tv_sec < 0) |
263 |
|
|
errx(1, "illegal timing interval %s", optarg); |
264 |
|
|
/* less than 1/Hz does not make sense */ |
265 |
|
|
if (interval.tv_sec == 0 && interval.tv_usec < 10000) { |
266 |
|
|
warnx("too small interval, raised to 0.01"); |
267 |
|
|
interval.tv_usec = 10000; |
268 |
|
|
} |
269 |
|
|
options |= F_INTERVAL; |
270 |
|
|
break; |
271 |
|
|
case 'L': |
272 |
|
|
moptions |= MULTICAST_NOLOOP; |
273 |
|
|
loop = 0; |
274 |
|
|
break; |
275 |
|
|
case 'l': |
276 |
|
|
if (getuid()) |
277 |
|
|
errx(1, "%s", strerror(EPERM)); |
278 |
|
|
preload = strtonum(optarg, 1, INT64_MAX, &errstr); |
279 |
|
|
if (errstr) |
280 |
|
|
errx(1, "preload value is %s: %s", errstr, |
281 |
|
|
optarg); |
282 |
|
|
break; |
283 |
|
|
case 'n': |
284 |
|
|
options |= F_NUMERIC; |
285 |
|
|
break; |
286 |
|
|
case 'p': /* fill buffer with user pattern */ |
287 |
|
|
options |= F_PINGFILLED; |
288 |
|
|
fill((char *)datap, optarg); |
289 |
|
|
break; |
290 |
|
|
case 'q': |
291 |
|
|
options |= F_QUIET; |
292 |
|
|
break; |
293 |
|
|
case 'R': |
294 |
|
|
options |= F_RROUTE; |
295 |
|
|
break; |
296 |
|
|
case 's': /* size of packet to send */ |
297 |
|
|
datalen = strtonum(optarg, 0, MAXPAYLOAD, &errstr); |
298 |
|
|
if (errstr) |
299 |
|
|
errx(1, "packet size is %s: %s", errstr, |
300 |
|
|
optarg); |
301 |
|
|
break; |
302 |
|
|
#ifndef SMALL |
303 |
|
|
case 'T': |
304 |
|
|
options |= F_HDRINCL; |
305 |
|
|
errno = 0; |
306 |
|
|
errstr = NULL; |
307 |
|
|
if (map_tos(optarg, &tos)) |
308 |
|
|
break; |
309 |
|
|
if (strlen(optarg) > 1 && optarg[0] == '0' && |
310 |
|
|
optarg[1] == 'x') |
311 |
|
|
tos = (int)strtol(optarg, NULL, 16); |
312 |
|
|
else |
313 |
|
|
tos = strtonum(optarg, 0, 255, &errstr); |
314 |
|
|
if (tos < 0 || tos > 255 || errstr || errno) |
315 |
|
|
errx(1, "illegal tos value %s", optarg); |
316 |
|
|
break; |
317 |
|
|
#endif /* SMALL */ |
318 |
|
|
case 't': |
319 |
|
|
options |= F_TTL; |
320 |
|
|
ttl = strtonum(optarg, 0, MAXTTL, &errstr); |
321 |
|
|
if (errstr) |
322 |
|
|
errx(1, "ttl value is %s: %s", errstr, optarg); |
323 |
|
|
break; |
324 |
|
|
case 'V': |
325 |
|
|
rtableid = strtonum(optarg, 0, RT_TABLEID_MAX, &errstr); |
326 |
|
|
if (errstr) |
327 |
|
|
errx(1, "rtable value is %s: %s", errstr, |
328 |
|
|
optarg); |
329 |
|
|
if (setsockopt(s, SOL_SOCKET, SO_RTABLE, &rtableid, |
330 |
|
|
sizeof(rtableid)) == -1) |
331 |
|
|
err(1, "setsockopt SO_RTABLE"); |
332 |
|
|
break; |
333 |
|
|
case 'v': |
334 |
|
|
options |= F_VERBOSE; |
335 |
|
|
break; |
336 |
|
|
case 'w': |
337 |
|
|
maxwait = strtonum(optarg, 1, INT_MAX, &errstr); |
338 |
|
|
if (errstr) |
339 |
|
|
errx(1, "maxwait value is %s: %s", |
340 |
|
|
errstr, optarg); |
341 |
|
|
break; |
342 |
|
|
default: |
343 |
|
|
usage(); |
344 |
|
|
} |
345 |
|
|
argc -= optind; |
346 |
|
|
argv += optind; |
347 |
|
|
|
348 |
|
|
if (argc != 1) |
349 |
|
|
usage(); |
350 |
|
|
|
351 |
|
|
target = *argv; |
352 |
|
|
|
353 |
|
|
memset(&whereto, 0, sizeof(whereto)); |
354 |
|
|
to = &whereto; |
355 |
|
|
to->sin_len = sizeof(struct sockaddr_in); |
356 |
|
|
to->sin_family = AF_INET; |
357 |
|
|
if (inet_aton(target, &to->sin_addr) != 0) |
358 |
|
|
hostname = target; |
359 |
|
|
else { |
360 |
|
|
hp = gethostbyname(target); |
361 |
|
|
if (!hp) |
362 |
|
|
errx(1, "unknown host: %s", target); |
363 |
|
|
to->sin_family = hp->h_addrtype; |
364 |
|
|
memcpy(&to->sin_addr, hp->h_addr, (size_t)hp->h_length); |
365 |
|
|
(void)strlcpy(hnamebuf, hp->h_name, sizeof(hnamebuf)); |
366 |
|
|
hostname = hnamebuf; |
367 |
|
|
} |
368 |
|
|
|
369 |
|
|
if (source) { |
370 |
|
|
if (IN_MULTICAST(ntohl(to->sin_addr.s_addr))) |
371 |
|
|
moptions |= MULTICAST_IF; |
372 |
|
|
else { |
373 |
|
|
memset(&from4, 0, sizeof(from4)); |
374 |
|
|
from4.sin_family = AF_INET; |
375 |
|
|
if (inet_aton(source, &from4.sin_addr) == 0) { |
376 |
|
|
memset(&hints, 0, sizeof(hints)); |
377 |
|
|
hints.ai_family = AF_INET; |
378 |
|
|
hints.ai_socktype = SOCK_DGRAM; /*dummy*/ |
379 |
|
|
if ((error = getaddrinfo(source, NULL, &hints, |
380 |
|
|
&res))) |
381 |
|
|
errx(1, "%s: %s", source, |
382 |
|
|
gai_strerror(error)); |
383 |
|
|
if (res->ai_addrlen != sizeof(from4)) |
384 |
|
|
errx(1, "size of sockaddr mismatch"); |
385 |
|
|
memcpy(&from4, res->ai_addr, res->ai_addrlen); |
386 |
|
|
freeaddrinfo(res); |
387 |
|
|
} |
388 |
|
|
if (bind(s, (struct sockaddr *)&from4, sizeof(from4)) |
389 |
|
|
< 0) |
390 |
|
|
err(1, "bind"); |
391 |
|
|
} |
392 |
|
|
} |
393 |
|
|
|
394 |
|
|
if (options & F_SO_DEBUG) |
395 |
|
|
(void)setsockopt(s, SOL_SOCKET, SO_DEBUG, &optval, |
396 |
|
|
sizeof(optval)); |
397 |
|
|
|
398 |
|
|
arc4random_buf(&tv64_offset, sizeof(tv64_offset)); |
399 |
|
|
arc4random_buf(&mac_key, sizeof(mac_key)); |
400 |
|
|
|
401 |
|
|
if (options & F_FLOOD && options & F_INTERVAL) |
402 |
|
|
errx(1, "-f and -i options are incompatible"); |
403 |
|
|
|
404 |
|
|
if ((options & F_FLOOD) && (options & (F_AUD_RECV | F_AUD_MISS))) |
405 |
|
|
warnx("No audible output for flood pings"); |
406 |
|
|
|
407 |
|
|
if (datalen >= sizeof(struct payload)) /* can we time transfer */ |
408 |
|
|
timing = 1; |
409 |
|
|
packlen = datalen + MAXIPLEN + MAXICMPLEN; |
410 |
|
|
if (!(packet = malloc((size_t)packlen))) |
411 |
|
|
err(1, "malloc"); |
412 |
|
|
if (!(options & F_PINGFILLED)) |
413 |
|
|
for (i = sizeof(struct payload); i < datalen; ++i) |
414 |
|
|
*datap++ = i; |
415 |
|
|
|
416 |
|
|
ident = getpid() & 0xFFFF; |
417 |
|
|
|
418 |
|
|
if (options & F_TTL) { |
419 |
|
|
if (IN_MULTICAST(ntohl(to->sin_addr.s_addr))) |
420 |
|
|
moptions |= MULTICAST_TTL; |
421 |
|
|
else |
422 |
|
|
options |= F_HDRINCL; |
423 |
|
|
} |
424 |
|
|
|
425 |
|
|
if (options & F_RROUTE && options & F_HDRINCL) |
426 |
|
|
errx(1, "-R option and -D or -T, or -t to unicast destinations" |
427 |
|
|
" are incompatible"); |
428 |
|
|
|
429 |
|
|
if (options & F_HDRINCL) { |
430 |
|
|
struct ip *ip = (struct ip *)outpackhdr; |
431 |
|
|
|
432 |
|
|
setsockopt(s, IPPROTO_IP, IP_HDRINCL, &optval, sizeof(optval)); |
433 |
|
|
ip->ip_v = IPVERSION; |
434 |
|
|
ip->ip_hl = sizeof(struct ip) >> 2; |
435 |
|
|
ip->ip_tos = tos; |
436 |
|
|
ip->ip_id = 0; |
437 |
|
|
ip->ip_off = htons(df ? IP_DF : 0); |
438 |
|
|
ip->ip_ttl = ttl; |
439 |
|
|
ip->ip_p = IPPROTO_ICMP; |
440 |
|
|
if (source) |
441 |
|
|
ip->ip_src = from4.sin_addr; |
442 |
|
|
else |
443 |
|
|
ip->ip_src.s_addr = INADDR_ANY; |
444 |
|
|
ip->ip_dst = to->sin_addr; |
445 |
|
|
} |
446 |
|
|
|
447 |
|
|
/* record route option */ |
448 |
|
|
if (options & F_RROUTE) { |
449 |
|
|
if (IN_MULTICAST(ntohl(to->sin_addr.s_addr))) |
450 |
|
|
errx(1, "record route not valid to multicast destinations"); |
451 |
|
|
memset(rspace, 0, sizeof(rspace)); |
452 |
|
|
rspace[IPOPT_OPTVAL] = IPOPT_RR; |
453 |
|
|
rspace[IPOPT_OLEN] = sizeof(rspace)-1; |
454 |
|
|
rspace[IPOPT_OFFSET] = IPOPT_MINOFF; |
455 |
|
|
if (setsockopt(s, IPPROTO_IP, IP_OPTIONS, rspace, |
456 |
|
|
sizeof(rspace)) < 0) { |
457 |
|
|
perror("ping: record route"); |
458 |
|
|
exit(1); |
459 |
|
|
} |
460 |
|
|
} |
461 |
|
|
|
462 |
|
|
if ((moptions & MULTICAST_NOLOOP) && |
463 |
|
|
setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, |
464 |
|
|
sizeof(loop)) < 0) |
465 |
|
|
err(1, "setsockopt IP_MULTICAST_LOOP"); |
466 |
|
|
if ((moptions & MULTICAST_TTL) && |
467 |
|
|
setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, |
468 |
|
|
sizeof(ttl)) < 0) |
469 |
|
|
err(1, "setsockopt IP_MULTICAST_TTL"); |
470 |
|
|
if ((moptions & MULTICAST_IF) && |
471 |
|
|
setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &from4.sin_addr, |
472 |
|
|
sizeof(from4.sin_addr)) < 0) |
473 |
|
|
err(1, "setsockopt IP_MULTICAST_IF"); |
474 |
|
|
|
475 |
|
|
/* |
476 |
|
|
* When trying to send large packets, you must increase the |
477 |
|
|
* size of both the send and receive buffers... |
478 |
|
|
*/ |
479 |
|
|
maxsizelen = sizeof maxsize; |
480 |
|
|
if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, &maxsize, &maxsizelen) < 0) |
481 |
|
|
err(1, "getsockopt"); |
482 |
|
|
if (maxsize < packlen && |
483 |
|
|
setsockopt(s, SOL_SOCKET, SO_SNDBUF, &packlen, sizeof(maxsize)) < 0) |
484 |
|
|
err(1, "setsockopt"); |
485 |
|
|
|
486 |
|
|
/* |
487 |
|
|
* When pinging the broadcast address, you can get a lot of answers. |
488 |
|
|
* Doing something so evil is useful if you are trying to stress the |
489 |
|
|
* ethernet, or just want to fill the arp cache to get some stuff for |
490 |
|
|
* /etc/ethers. |
491 |
|
|
*/ |
492 |
|
|
while (setsockopt(s, SOL_SOCKET, SO_RCVBUF, |
493 |
|
|
(void*)&bufspace, sizeof(bufspace)) < 0) { |
494 |
|
|
if ((bufspace -= 1024) <= 0) |
495 |
|
|
err(1, "Cannot set the receive buffer size"); |
496 |
|
|
} |
497 |
|
|
if (bufspace < IP_MAXPACKET) |
498 |
|
|
warnx("Could only allocate a receive buffer of %d bytes (default %d)", |
499 |
|
|
bufspace, IP_MAXPACKET); |
500 |
|
|
|
501 |
|
|
if (to->sin_family == AF_INET) |
502 |
|
|
(void)printf("PING %s (%s): %d data bytes\n", hostname, |
503 |
|
|
inet_ntoa(*(struct in_addr *)&to->sin_addr.s_addr), |
504 |
|
|
datalen); |
505 |
|
|
else |
506 |
|
|
(void)printf("PING %s: %d data bytes\n", hostname, datalen); |
507 |
|
|
|
508 |
|
|
if (options & F_NUMERIC) { |
509 |
|
|
if (pledge("stdio inet rpath cpath wpath", NULL) == -1) |
510 |
|
|
err(1, "pledge"); |
511 |
|
|
} else { |
512 |
|
|
if (pledge("stdio inet dns rpath cpath wpath", NULL) == -1) |
513 |
|
|
err(1, "pledge"); |
514 |
|
|
} |
515 |
|
|
|
516 |
|
|
while (preload--) /* fire off them quickies */ |
517 |
|
|
pinger(); |
518 |
|
|
|
519 |
|
|
(void)signal(SIGINT, onsignal); |
520 |
|
|
(void)signal(SIGINFO, onsignal); |
521 |
|
|
|
522 |
|
|
if ((options & F_FLOOD) == 0) { |
523 |
|
|
(void)signal(SIGALRM, onsignal); |
524 |
|
|
itimer.it_interval = interval; |
525 |
|
|
itimer.it_value = interval; |
526 |
|
|
(void)setitimer(ITIMER_REAL, &itimer, NULL); |
527 |
|
|
if (ntransmitted == 0) |
528 |
|
|
retransmit(); |
529 |
|
|
} |
530 |
|
|
|
531 |
|
|
seenalrm = seenint = 0; |
532 |
|
|
seeninfo = 0; |
533 |
|
|
|
534 |
|
|
for (;;) { |
535 |
|
|
struct msghdr m; |
536 |
|
|
union { |
537 |
|
|
struct cmsghdr hdr; |
538 |
|
|
u_char buf[CMSG_SPACE(1024)]; |
539 |
|
|
} cmsgbuf; |
540 |
|
|
struct iovec iov[1]; |
541 |
|
|
struct pollfd pfd; |
542 |
|
|
ssize_t cc; |
543 |
|
|
int timeout; |
544 |
|
|
|
545 |
|
|
/* signal handling */ |
546 |
|
|
if (seenalrm) { |
547 |
|
|
retransmit(); |
548 |
|
|
seenalrm = 0; |
549 |
|
|
if (ntransmitted - nreceived - 1 > nmissedmax) { |
550 |
|
|
nmissedmax = ntransmitted - nreceived - 1; |
551 |
|
|
if (!(options & F_FLOOD) && |
552 |
|
|
(options & F_AUD_MISS)) |
553 |
|
|
(void)fputc('\a', stderr); |
554 |
|
|
} |
555 |
|
|
continue; |
556 |
|
|
} |
557 |
|
|
if (seenint) { |
558 |
|
|
onint(SIGINT); |
559 |
|
|
seenint = 0; |
560 |
|
|
continue; |
561 |
|
|
} |
562 |
|
|
if (seeninfo) { |
563 |
|
|
summary(0); |
564 |
|
|
seeninfo = 0; |
565 |
|
|
continue; |
566 |
|
|
} |
567 |
|
|
|
568 |
|
|
if (options & F_FLOOD) { |
569 |
|
|
(void)pinger(); |
570 |
|
|
timeout = 10; |
571 |
|
|
} else |
572 |
|
|
timeout = INFTIM; |
573 |
|
|
|
574 |
|
|
pfd.fd = s; |
575 |
|
|
pfd.events = POLLIN; |
576 |
|
|
|
577 |
|
|
if (poll(&pfd, 1, timeout) <= 0) |
578 |
|
|
continue; |
579 |
|
|
|
580 |
|
|
m.msg_name = &from; |
581 |
|
|
m.msg_namelen = sizeof(from); |
582 |
|
|
memset(&iov, 0, sizeof(iov)); |
583 |
|
|
iov[0].iov_base = (caddr_t)packet; |
584 |
|
|
iov[0].iov_len = packlen; |
585 |
|
|
m.msg_iov = iov; |
586 |
|
|
m.msg_iovlen = 1; |
587 |
|
|
m.msg_control = (caddr_t)&cmsgbuf.buf; |
588 |
|
|
m.msg_controllen = sizeof(cmsgbuf.buf); |
589 |
|
|
|
590 |
|
|
cc = recvmsg(s, &m, 0); |
591 |
|
|
if (cc < 0) { |
592 |
|
|
if (errno != EINTR) { |
593 |
|
|
warn("recvmsg"); |
594 |
|
|
sleep(1); |
595 |
|
|
} |
596 |
|
|
continue; |
597 |
|
|
} else |
598 |
|
|
pr_pack(packet, cc, &m); |
599 |
|
|
|
600 |
|
|
if (npackets && nreceived >= npackets) |
601 |
|
|
break; |
602 |
|
|
} |
603 |
|
|
summary(0); |
604 |
|
|
exit(nreceived == 0); |
605 |
|
|
} |
606 |
|
|
|
607 |
|
|
|
608 |
|
|
void |
609 |
|
|
onsignal(int sig) |
610 |
|
|
{ |
611 |
|
|
switch (sig) { |
612 |
|
|
case SIGALRM: |
613 |
|
|
seenalrm++; |
614 |
|
|
break; |
615 |
|
|
case SIGINT: |
616 |
|
|
seenint++; |
617 |
|
|
break; |
618 |
|
|
case SIGINFO: |
619 |
|
|
seeninfo++; |
620 |
|
|
break; |
621 |
|
|
} |
622 |
|
|
} |
623 |
|
|
|
624 |
|
|
/* |
625 |
|
|
* retransmit -- |
626 |
|
|
* This routine transmits another ping. |
627 |
|
|
*/ |
628 |
|
|
void |
629 |
|
|
retransmit(void) |
630 |
|
|
{ |
631 |
|
|
struct itimerval itimer; |
632 |
|
|
|
633 |
|
|
if (pinger() == 0) |
634 |
|
|
return; |
635 |
|
|
|
636 |
|
|
/* |
637 |
|
|
* If we're not transmitting any more packets, change the timer |
638 |
|
|
* to wait two round-trip times if we've received any packets or |
639 |
|
|
* maxwait seconds if we haven't. |
640 |
|
|
*/ |
641 |
|
|
if (nreceived) { |
642 |
|
|
itimer.it_value.tv_sec = 2 * tmax / 1000; |
643 |
|
|
if (itimer.it_value.tv_sec == 0) |
644 |
|
|
itimer.it_value.tv_sec = 1; |
645 |
|
|
} else |
646 |
|
|
itimer.it_value.tv_sec = maxwait; |
647 |
|
|
itimer.it_interval.tv_sec = 0; |
648 |
|
|
itimer.it_interval.tv_usec = 0; |
649 |
|
|
itimer.it_value.tv_usec = 0; |
650 |
|
|
|
651 |
|
|
(void)signal(SIGALRM, onint); |
652 |
|
|
(void)setitimer(ITIMER_REAL, &itimer, NULL); |
653 |
|
|
} |
654 |
|
|
|
655 |
|
|
/* |
656 |
|
|
* pinger -- |
657 |
|
|
* Compose and transmit an ICMP ECHO REQUEST packet. The IP packet |
658 |
|
|
* will be added on by the kernel. The ID field is our UNIX process ID, |
659 |
|
|
* and the sequence number is an ascending integer. The first 8 bytes |
660 |
|
|
* of the data portion are used to hold a UNIX "timeval" struct in VAX |
661 |
|
|
* byte-order, to compute the round-trip time. |
662 |
|
|
*/ |
663 |
|
|
int |
664 |
|
|
pinger(void) |
665 |
|
|
{ |
666 |
|
|
struct icmp *icp; |
667 |
|
|
int cc, i; |
668 |
|
|
u_char *packet = outpack; |
669 |
|
|
|
670 |
|
|
if (npackets && ntransmitted >= npackets) |
671 |
|
|
return(-1); /* no more transmission */ |
672 |
|
|
|
673 |
|
|
icp = (struct icmp *)outpack; |
674 |
|
|
icp->icmp_type = ICMP_ECHO; |
675 |
|
|
icp->icmp_code = 0; |
676 |
|
|
icp->icmp_cksum = 0; |
677 |
|
|
icp->icmp_seq = htons(ntransmitted); |
678 |
|
|
icp->icmp_id = ident; /* ID */ |
679 |
|
|
|
680 |
|
|
CLR(ntohs(icp->icmp_seq) % mx_dup_ck); |
681 |
|
|
|
682 |
|
|
if (timing) { |
683 |
|
|
SIPHASH_CTX ctx; |
684 |
|
|
struct timespec ts; |
685 |
|
|
struct payload payload; |
686 |
|
|
struct tv64 *tv64 = &payload.tv64; |
687 |
|
|
|
688 |
|
|
if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) |
689 |
|
|
err(1, "clock_gettime(CLOCK_MONOTONIC)"); |
690 |
|
|
tv64->tv64_sec = htobe64((u_int64_t)ts.tv_sec + |
691 |
|
|
tv64_offset.tv64_sec); |
692 |
|
|
tv64->tv64_nsec = htobe64((u_int64_t)ts.tv_nsec + |
693 |
|
|
tv64_offset.tv64_nsec); |
694 |
|
|
|
695 |
|
|
SipHash24_Init(&ctx, &mac_key); |
696 |
|
|
SipHash24_Update(&ctx, tv64, sizeof(*tv64)); |
697 |
|
|
SipHash24_Update(&ctx, &ident, sizeof(ident)); |
698 |
|
|
SipHash24_Update(&ctx, &icp->icmp_seq, sizeof(icp->icmp_seq)); |
699 |
|
|
SipHash24_Update(&ctx, &whereto.sin_addr, |
700 |
|
|
sizeof(whereto.sin_addr)); |
701 |
|
|
SipHash24_Final(&payload.mac, &ctx); |
702 |
|
|
|
703 |
|
|
memcpy(&outpack[8], &payload, sizeof(payload)); |
704 |
|
|
} |
705 |
|
|
|
706 |
|
|
cc = datalen + 8; /* skips ICMP portion */ |
707 |
|
|
|
708 |
|
|
/* compute ICMP checksum here */ |
709 |
|
|
icp->icmp_cksum = in_cksum((u_short *)icp, cc); |
710 |
|
|
|
711 |
|
|
if (options & F_HDRINCL) { |
712 |
|
|
struct ip *ip = (struct ip *)outpackhdr; |
713 |
|
|
|
714 |
|
|
packet = (u_char *)ip; |
715 |
|
|
cc += sizeof(struct ip); |
716 |
|
|
ip->ip_len = htons(cc); |
717 |
|
|
ip->ip_sum = in_cksum((u_short *)outpackhdr, cc); |
718 |
|
|
} |
719 |
|
|
|
720 |
|
|
i = sendto(s, packet, cc, 0, (struct sockaddr *)&whereto, |
721 |
|
|
sizeof(whereto)); |
722 |
|
|
|
723 |
|
|
if (i < 0 || i != cc) { |
724 |
|
|
if (i < 0) |
725 |
|
|
perror("ping: sendto"); |
726 |
|
|
dprintf(STDOUT_FILENO, "ping: wrote %s %d chars, ret=%d\n", |
727 |
|
|
hostname, cc, i); |
728 |
|
|
} |
729 |
|
|
if (!(options & F_QUIET) && options & F_FLOOD) |
730 |
|
|
(void)write(STDOUT_FILENO, &DOT, 1); |
731 |
|
|
|
732 |
|
|
ntransmitted++; |
733 |
|
|
return (0); |
734 |
|
|
} |
735 |
|
|
|
736 |
|
|
/* |
737 |
|
|
* pr_pack -- |
738 |
|
|
* Print out the packet, if it came from us. This logic is necessary |
739 |
|
|
* because ALL readers of the ICMP socket get a copy of ALL ICMP packets |
740 |
|
|
* which arrive ('tis only fair). This permits multiple copies of this |
741 |
|
|
* program to be run without having intermingled output (or statistics!). |
742 |
|
|
*/ |
743 |
|
|
void |
744 |
|
|
pr_pack(char *buf, int cc, struct msghdr *mhdr) |
745 |
|
|
{ |
746 |
|
|
struct sockaddr_in *from; |
747 |
|
|
socklen_t fromlen; |
748 |
|
|
struct icmp *icp; |
749 |
|
|
in_addr_t l; |
750 |
|
|
u_int i, j; |
751 |
|
|
u_char *cp, *dp; |
752 |
|
|
static int old_rrlen; |
753 |
|
|
static char old_rr[MAX_IPOPTLEN]; |
754 |
|
|
struct ip *ip, *ip2; |
755 |
|
|
struct timespec ts, tp; |
756 |
|
|
char *pkttime; |
757 |
|
|
double triptime = 0; |
758 |
|
|
int hlen, hlen2, dupflag; |
759 |
|
|
struct payload payload; |
760 |
|
|
|
761 |
|
|
if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) |
762 |
|
|
err(1, "clock_gettime(CLOCK_MONOTONIC)"); |
763 |
|
|
|
764 |
|
|
if (!mhdr || !mhdr->msg_name || |
765 |
|
|
mhdr->msg_namelen != sizeof(struct sockaddr_in) || |
766 |
|
|
((struct sockaddr *)mhdr->msg_name)->sa_family != AF_INET) { |
767 |
|
|
if (options & F_VERBOSE) |
768 |
|
|
warnx("invalid peername"); |
769 |
|
|
return; |
770 |
|
|
} |
771 |
|
|
from = (struct sockaddr_in *)mhdr->msg_name; |
772 |
|
|
fromlen = mhdr->msg_namelen; |
773 |
|
|
|
774 |
|
|
/* Check the IP header */ |
775 |
|
|
ip = (struct ip *)buf; |
776 |
|
|
hlen = ip->ip_hl << 2; |
777 |
|
|
if (cc < hlen + ICMP_MINLEN) { |
778 |
|
|
if (options & F_VERBOSE) |
779 |
|
|
warnx("packet too short (%d bytes) from %s", cc, |
780 |
|
|
inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr)); |
781 |
|
|
return; |
782 |
|
|
} |
783 |
|
|
|
784 |
|
|
/* Now the ICMP part */ |
785 |
|
|
cc -= hlen; |
786 |
|
|
icp = (struct icmp *)(buf + hlen); |
787 |
|
|
if (icp->icmp_type == ICMP_ECHOREPLY) { |
788 |
|
|
if (icp->icmp_id != ident) |
789 |
|
|
return; /* 'Twas not our ECHO */ |
790 |
|
|
++nreceived; |
791 |
|
|
if (cc >= 8 + sizeof(struct payload)) { |
792 |
|
|
SIPHASH_CTX ctx; |
793 |
|
|
struct tv64 *tv64 = &payload.tv64; |
794 |
|
|
u_int8_t mac[SIPHASH_DIGEST_LENGTH]; |
795 |
|
|
|
796 |
|
|
pkttime = (char *)icp->icmp_data; |
797 |
|
|
memcpy(&payload, pkttime, sizeof(payload)); |
798 |
|
|
|
799 |
|
|
SipHash24_Init(&ctx, &mac_key); |
800 |
|
|
SipHash24_Update(&ctx, tv64, sizeof(*tv64)); |
801 |
|
|
SipHash24_Update(&ctx, &ident, sizeof(ident)); |
802 |
|
|
SipHash24_Update(&ctx, &icp->icmp_seq, |
803 |
|
|
sizeof(icp->icmp_seq)); |
804 |
|
|
SipHash24_Update(&ctx, &whereto.sin_addr, |
805 |
|
|
sizeof(whereto.sin_addr)); |
806 |
|
|
SipHash24_Final(mac, &ctx); |
807 |
|
|
|
808 |
|
|
if (timingsafe_memcmp(mac, &payload.mac, |
809 |
|
|
sizeof(mac)) != 0) { |
810 |
|
|
(void)printf("signature mismatch!\n"); |
811 |
|
|
return; |
812 |
|
|
} |
813 |
|
|
timinginfo++; |
814 |
|
|
|
815 |
|
|
tp.tv_sec = betoh64(tv64->tv64_sec) - |
816 |
|
|
tv64_offset.tv64_sec; |
817 |
|
|
tp.tv_nsec = betoh64(tv64->tv64_nsec) - |
818 |
|
|
tv64_offset.tv64_nsec; |
819 |
|
|
|
820 |
|
|
timespecsub(&ts, &tp, &ts); |
821 |
|
|
triptime = ((double)ts.tv_sec) * 1000.0 + |
822 |
|
|
((double)ts.tv_nsec) / 1000000.0; |
823 |
|
|
tsum += triptime; |
824 |
|
|
tsumsq += triptime * triptime; |
825 |
|
|
if (triptime < tmin) |
826 |
|
|
tmin = triptime; |
827 |
|
|
if (triptime > tmax) |
828 |
|
|
tmax = triptime; |
829 |
|
|
} |
830 |
|
|
|
831 |
|
|
if (TST(ntohs(icp->icmp_seq) % mx_dup_ck)) { |
832 |
|
|
++nrepeats; |
833 |
|
|
--nreceived; |
834 |
|
|
dupflag = 1; |
835 |
|
|
} else { |
836 |
|
|
SET(ntohs(icp->icmp_seq) % mx_dup_ck); |
837 |
|
|
dupflag = 0; |
838 |
|
|
} |
839 |
|
|
|
840 |
|
|
if (options & F_QUIET) |
841 |
|
|
return; |
842 |
|
|
|
843 |
|
|
if (options & F_FLOOD) |
844 |
|
|
(void)write(STDOUT_FILENO, &BSPACE, 1); |
845 |
|
|
else { |
846 |
|
|
(void)printf("%d bytes from %s: icmp_seq=%u", cc, |
847 |
|
|
inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr), |
848 |
|
|
ntohs(icp->icmp_seq)); |
849 |
|
|
(void)printf(" ttl=%d", ip->ip_ttl); |
850 |
|
|
if (cc >= 8 + sizeof(struct payload)) |
851 |
|
|
(void)printf(" time=%.3f ms", triptime); |
852 |
|
|
if (dupflag) |
853 |
|
|
(void)printf(" (DUP!)"); |
854 |
|
|
/* check the data */ |
855 |
|
|
if (cc - 8 < datalen) |
856 |
|
|
(void)printf(" (TRUNC!)"); |
857 |
|
|
cp = (u_char *)&icp->icmp_data[sizeof(struct payload)]; |
858 |
|
|
dp = &outpack[8 + sizeof(struct payload)]; |
859 |
|
|
for (i = 8 + sizeof(struct payload); |
860 |
|
|
i < cc && i < datalen; |
861 |
|
|
++i, ++cp, ++dp) { |
862 |
|
|
if (*cp != *dp) { |
863 |
|
|
(void)printf("\nwrong data byte #%d " |
864 |
|
|
"should be 0x%x but was 0x%x", |
865 |
|
|
i - 8, *dp, *cp); |
866 |
|
|
cp = (u_char *)&icp->icmp_data[0]; |
867 |
|
|
for (i = 8; i < cc && i < datalen; |
868 |
|
|
++i, ++cp) { |
869 |
|
|
if ((i % 32) == 8) |
870 |
|
|
(void)printf("\n\t"); |
871 |
|
|
(void)printf("%x ", *cp); |
872 |
|
|
} |
873 |
|
|
break; |
874 |
|
|
} |
875 |
|
|
} |
876 |
|
|
} |
877 |
|
|
} else { |
878 |
|
|
/* We've got something other than an ECHOREPLY */ |
879 |
|
|
if (!(options & F_VERBOSE)) |
880 |
|
|
return; |
881 |
|
|
ip2 = (struct ip *)(buf + hlen + sizeof (struct icmp)); |
882 |
|
|
hlen2 = ip2->ip_hl << 2; |
883 |
|
|
if (cc >= hlen2 + 8 && check_icmph(ip2) != 1) |
884 |
|
|
return; |
885 |
|
|
(void)printf("%d bytes from %s: ", cc, |
886 |
|
|
pr_addr(from->sin_addr.s_addr)); |
887 |
|
|
pr_icmph(icp); |
888 |
|
|
} |
889 |
|
|
|
890 |
|
|
/* Display any IP options */ |
891 |
|
|
cp = (u_char *)buf + sizeof(struct ip); |
892 |
|
|
|
893 |
|
|
for (; hlen > (int)sizeof(struct ip); --hlen, ++cp) |
894 |
|
|
switch (*cp) { |
895 |
|
|
case IPOPT_EOL: |
896 |
|
|
hlen = 0; |
897 |
|
|
break; |
898 |
|
|
case IPOPT_LSRR: |
899 |
|
|
(void)printf("\nLSRR: "); |
900 |
|
|
hlen -= 2; |
901 |
|
|
j = *++cp; |
902 |
|
|
++cp; |
903 |
|
|
i = 0; |
904 |
|
|
if (j > IPOPT_MINOFF) { |
905 |
|
|
for (;;) { |
906 |
|
|
l = *++cp; |
907 |
|
|
l = (l<<8) + *++cp; |
908 |
|
|
l = (l<<8) + *++cp; |
909 |
|
|
l = (l<<8) + *++cp; |
910 |
|
|
if (l == 0) |
911 |
|
|
(void)printf("\t0.0.0.0"); |
912 |
|
|
else |
913 |
|
|
(void)printf("\t%s", |
914 |
|
|
pr_addr(ntohl(l))); |
915 |
|
|
hlen -= 4; |
916 |
|
|
j -= 4; |
917 |
|
|
i += 4; |
918 |
|
|
if (j <= IPOPT_MINOFF) |
919 |
|
|
break; |
920 |
|
|
if (i >= MAX_IPOPTLEN) { |
921 |
|
|
(void)printf("\t(truncated route)"); |
922 |
|
|
break; |
923 |
|
|
} |
924 |
|
|
(void)putchar('\n'); |
925 |
|
|
} |
926 |
|
|
} |
927 |
|
|
break; |
928 |
|
|
case IPOPT_RR: |
929 |
|
|
j = *++cp; /* get length */ |
930 |
|
|
i = *++cp; /* and pointer */ |
931 |
|
|
hlen -= 2; |
932 |
|
|
if (i > j) |
933 |
|
|
i = j; |
934 |
|
|
i -= IPOPT_MINOFF; |
935 |
|
|
if (i <= 0) |
936 |
|
|
continue; |
937 |
|
|
if (i == old_rrlen && |
938 |
|
|
cp == (u_char *)buf + sizeof(struct ip) + 2 && |
939 |
|
|
!memcmp(cp, old_rr, i) && |
940 |
|
|
!(options & F_FLOOD)) { |
941 |
|
|
(void)printf("\t(same route)"); |
942 |
|
|
i = ((i + 3) / 4) * 4; |
943 |
|
|
hlen -= i; |
944 |
|
|
cp += i; |
945 |
|
|
break; |
946 |
|
|
} |
947 |
|
|
if (i < MAX_IPOPTLEN) { |
948 |
|
|
old_rrlen = i; |
949 |
|
|
memcpy(old_rr, cp, i); |
950 |
|
|
} else |
951 |
|
|
old_rrlen = 0; |
952 |
|
|
|
953 |
|
|
(void)printf("\nRR: "); |
954 |
|
|
j = 0; |
955 |
|
|
for (;;) { |
956 |
|
|
l = *++cp; |
957 |
|
|
l = (l<<8) + *++cp; |
958 |
|
|
l = (l<<8) + *++cp; |
959 |
|
|
l = (l<<8) + *++cp; |
960 |
|
|
if (l == 0) |
961 |
|
|
(void)printf("\t0.0.0.0"); |
962 |
|
|
else |
963 |
|
|
(void)printf("\t%s", pr_addr(ntohl(l))); |
964 |
|
|
hlen -= 4; |
965 |
|
|
i -= 4; |
966 |
|
|
j += 4; |
967 |
|
|
if (i <= 0) |
968 |
|
|
break; |
969 |
|
|
if (j >= MAX_IPOPTLEN) { |
970 |
|
|
(void)printf("\t(truncated route)"); |
971 |
|
|
break; |
972 |
|
|
} |
973 |
|
|
(void)putchar('\n'); |
974 |
|
|
} |
975 |
|
|
break; |
976 |
|
|
case IPOPT_NOP: |
977 |
|
|
(void)printf("\nNOP"); |
978 |
|
|
break; |
979 |
|
|
default: |
980 |
|
|
(void)printf("\nunknown option %x", *cp); |
981 |
|
|
hlen = hlen - (cp[IPOPT_OLEN] - 1); |
982 |
|
|
cp = cp + (cp[IPOPT_OLEN] - 1); |
983 |
|
|
break; |
984 |
|
|
} |
985 |
|
|
if (!(options & F_FLOOD)) { |
986 |
|
|
(void)putchar('\n'); |
987 |
|
|
(void)fflush(stdout); |
988 |
|
|
if (options & F_AUD_RECV) |
989 |
|
|
write(STDERR_FILENO, "\a", 1); |
990 |
|
|
} |
991 |
|
|
} |
992 |
|
|
|
993 |
|
|
/* |
994 |
|
|
* in_cksum -- |
995 |
|
|
* Checksum routine for Internet Protocol family headers (C Version) |
996 |
|
|
*/ |
997 |
|
|
int |
998 |
|
|
in_cksum(u_short *addr, int len) |
999 |
|
|
{ |
1000 |
|
|
int nleft = len; |
1001 |
|
|
u_short *w = addr; |
1002 |
|
|
int sum = 0; |
1003 |
|
|
u_short answer = 0; |
1004 |
|
|
|
1005 |
|
|
/* |
1006 |
|
|
* Our algorithm is simple, using a 32 bit accumulator (sum), we add |
1007 |
|
|
* sequential 16 bit words to it, and at the end, fold back all the |
1008 |
|
|
* carry bits from the top 16 bits into the lower 16 bits. |
1009 |
|
|
*/ |
1010 |
|
|
while (nleft > 1) { |
1011 |
|
|
sum += *w++; |
1012 |
|
|
nleft -= 2; |
1013 |
|
|
} |
1014 |
|
|
|
1015 |
|
|
/* mop up an odd byte, if necessary */ |
1016 |
|
|
if (nleft == 1) { |
1017 |
|
|
*(u_char *)(&answer) = *(u_char *)w ; |
1018 |
|
|
sum += answer; |
1019 |
|
|
} |
1020 |
|
|
|
1021 |
|
|
/* add back carry outs from top 16 bits to low 16 bits */ |
1022 |
|
|
sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ |
1023 |
|
|
sum += (sum >> 16); /* add carry */ |
1024 |
|
|
answer = ~sum; /* truncate to 16 bits */ |
1025 |
|
|
return(answer); |
1026 |
|
|
} |
1027 |
|
|
|
1028 |
|
|
/* |
1029 |
|
|
* onint -- |
1030 |
|
|
* SIGINT handler. |
1031 |
|
|
*/ |
1032 |
|
|
void |
1033 |
|
|
onint(int signo) |
1034 |
|
|
{ |
1035 |
|
|
summary(signo); |
1036 |
|
|
|
1037 |
|
|
if (signo) |
1038 |
|
|
_exit(nreceived ? 0 : 1); |
1039 |
|
|
else |
1040 |
|
|
exit(nreceived ? 0 : 1); |
1041 |
|
|
} |
1042 |
|
|
|
1043 |
|
|
void |
1044 |
|
|
summary(int insig) |
1045 |
|
|
{ |
1046 |
|
|
char buf[8192], buft[8192]; |
1047 |
|
|
|
1048 |
|
|
buf[0] = '\0'; |
1049 |
|
|
|
1050 |
|
|
if (!insig) { |
1051 |
|
|
(void)putchar('\r'); |
1052 |
|
|
(void)fflush(stdout); |
1053 |
|
|
} else |
1054 |
|
|
strlcat(buf, "\r", sizeof buf); |
1055 |
|
|
|
1056 |
|
|
|
1057 |
|
|
snprintf(buft, sizeof buft, "--- %s ping statistics ---\n", |
1058 |
|
|
hostname); |
1059 |
|
|
strlcat(buf, buft, sizeof buf); |
1060 |
|
|
|
1061 |
|
|
snprintf(buft, sizeof buft, "%lld packets transmitted, ", ntransmitted); |
1062 |
|
|
strlcat(buf, buft, sizeof buf); |
1063 |
|
|
snprintf(buft, sizeof buft, "%lld packets received, ", nreceived); |
1064 |
|
|
strlcat(buf, buft, sizeof buf); |
1065 |
|
|
|
1066 |
|
|
if (nrepeats) { |
1067 |
|
|
snprintf(buft, sizeof buft, "%lld duplicates, ", nrepeats); |
1068 |
|
|
strlcat(buf, buft, sizeof buf); |
1069 |
|
|
} |
1070 |
|
|
if (ntransmitted) { |
1071 |
|
|
if (nreceived > ntransmitted) |
1072 |
|
|
snprintf(buft, sizeof buft, |
1073 |
|
|
"-- somebody's duplicating packets!"); |
1074 |
|
|
else |
1075 |
|
|
snprintf(buft, sizeof buft, "%.1f%% packet loss", |
1076 |
|
|
((((double)ntransmitted - nreceived) * 100) / |
1077 |
|
|
ntransmitted)); |
1078 |
|
|
strlcat(buf, buft, sizeof buf); |
1079 |
|
|
} |
1080 |
|
|
strlcat(buf, "\n", sizeof buf); |
1081 |
|
|
if (timinginfo) { |
1082 |
|
|
/* Only display average to microseconds */ |
1083 |
|
|
double num = nreceived + nrepeats; |
1084 |
|
|
double avg = tsum / num; |
1085 |
|
|
double dev = sqrt(fmax(0, tsumsq / num - avg * avg)); |
1086 |
|
|
snprintf(buft, sizeof(buft), |
1087 |
|
|
"round-trip min/avg/max/std-dev = %.3f/%.3f/%.3f/%.3f ms\n", |
1088 |
|
|
tmin, avg, tmax, dev); |
1089 |
|
|
strlcat(buf, buft, sizeof(buf)); |
1090 |
|
|
} |
1091 |
|
|
write(STDOUT_FILENO, buf, strlen(buf)); /* XXX atomicio? */ |
1092 |
|
|
} |
1093 |
|
|
|
1094 |
|
|
/* |
1095 |
|
|
* pr_icmph -- |
1096 |
|
|
* Print a descriptive string about an ICMP header. |
1097 |
|
|
*/ |
1098 |
|
|
void |
1099 |
|
|
pr_icmph(struct icmp *icp) |
1100 |
|
|
{ |
1101 |
|
|
switch(icp->icmp_type) { |
1102 |
|
|
case ICMP_ECHOREPLY: |
1103 |
|
|
(void)printf("Echo Reply\n"); |
1104 |
|
|
/* XXX ID + Seq + Data */ |
1105 |
|
|
break; |
1106 |
|
|
case ICMP_UNREACH: |
1107 |
|
|
switch(icp->icmp_code) { |
1108 |
|
|
case ICMP_UNREACH_NET: |
1109 |
|
|
(void)printf("Destination Net Unreachable\n"); |
1110 |
|
|
break; |
1111 |
|
|
case ICMP_UNREACH_HOST: |
1112 |
|
|
(void)printf("Destination Host Unreachable\n"); |
1113 |
|
|
break; |
1114 |
|
|
case ICMP_UNREACH_PROTOCOL: |
1115 |
|
|
(void)printf("Destination Protocol Unreachable\n"); |
1116 |
|
|
break; |
1117 |
|
|
case ICMP_UNREACH_PORT: |
1118 |
|
|
(void)printf("Destination Port Unreachable\n"); |
1119 |
|
|
break; |
1120 |
|
|
case ICMP_UNREACH_NEEDFRAG: |
1121 |
|
|
if (icp->icmp_nextmtu != 0) |
1122 |
|
|
(void)printf("frag needed and DF set (MTU %d)\n", |
1123 |
|
|
ntohs(icp->icmp_nextmtu)); |
1124 |
|
|
else |
1125 |
|
|
(void)printf("frag needed and DF set\n"); |
1126 |
|
|
break; |
1127 |
|
|
case ICMP_UNREACH_SRCFAIL: |
1128 |
|
|
(void)printf("Source Route Failed\n"); |
1129 |
|
|
break; |
1130 |
|
|
case ICMP_UNREACH_NET_UNKNOWN: |
1131 |
|
|
(void)printf("Network Unknown\n"); |
1132 |
|
|
break; |
1133 |
|
|
case ICMP_UNREACH_HOST_UNKNOWN: |
1134 |
|
|
(void)printf("Host Unknown\n"); |
1135 |
|
|
break; |
1136 |
|
|
case ICMP_UNREACH_ISOLATED: |
1137 |
|
|
(void)printf("Source Isolated\n"); |
1138 |
|
|
break; |
1139 |
|
|
case ICMP_UNREACH_NET_PROHIB: |
1140 |
|
|
(void)printf("Dest. Net Administratively Prohibited\n"); |
1141 |
|
|
break; |
1142 |
|
|
case ICMP_UNREACH_HOST_PROHIB: |
1143 |
|
|
(void)printf("Dest. Host Administratively Prohibited\n"); |
1144 |
|
|
break; |
1145 |
|
|
case ICMP_UNREACH_TOSNET: |
1146 |
|
|
(void)printf("Destination Net Unreachable for TOS\n"); |
1147 |
|
|
break; |
1148 |
|
|
case ICMP_UNREACH_TOSHOST: |
1149 |
|
|
(void)printf("Destination Host Unreachable for TOS\n"); |
1150 |
|
|
break; |
1151 |
|
|
case ICMP_UNREACH_FILTER_PROHIB: |
1152 |
|
|
(void)printf("Route administratively prohibited\n"); |
1153 |
|
|
break; |
1154 |
|
|
case ICMP_UNREACH_HOST_PRECEDENCE: |
1155 |
|
|
(void)printf("Host Precedence Violation\n"); |
1156 |
|
|
break; |
1157 |
|
|
case ICMP_UNREACH_PRECEDENCE_CUTOFF: |
1158 |
|
|
(void)printf("Precedence Cutoff\n"); |
1159 |
|
|
break; |
1160 |
|
|
default: |
1161 |
|
|
(void)printf("Dest Unreachable, Unknown Code: %d\n", |
1162 |
|
|
icp->icmp_code); |
1163 |
|
|
break; |
1164 |
|
|
} |
1165 |
|
|
/* Print returned IP header information */ |
1166 |
|
|
pr_retip((struct ip *)icp->icmp_data); |
1167 |
|
|
break; |
1168 |
|
|
case ICMP_SOURCEQUENCH: |
1169 |
|
|
(void)printf("Source Quench\n"); |
1170 |
|
|
pr_retip((struct ip *)icp->icmp_data); |
1171 |
|
|
break; |
1172 |
|
|
case ICMP_REDIRECT: |
1173 |
|
|
switch(icp->icmp_code) { |
1174 |
|
|
case ICMP_REDIRECT_NET: |
1175 |
|
|
(void)printf("Redirect Network"); |
1176 |
|
|
break; |
1177 |
|
|
case ICMP_REDIRECT_HOST: |
1178 |
|
|
(void)printf("Redirect Host"); |
1179 |
|
|
break; |
1180 |
|
|
case ICMP_REDIRECT_TOSNET: |
1181 |
|
|
(void)printf("Redirect Type of Service and Network"); |
1182 |
|
|
break; |
1183 |
|
|
case ICMP_REDIRECT_TOSHOST: |
1184 |
|
|
(void)printf("Redirect Type of Service and Host"); |
1185 |
|
|
break; |
1186 |
|
|
default: |
1187 |
|
|
(void)printf("Redirect, Unknown Code: %d", icp->icmp_code); |
1188 |
|
|
break; |
1189 |
|
|
} |
1190 |
|
|
(void)printf("(New addr: %s)\n", |
1191 |
|
|
inet_ntoa(icp->icmp_gwaddr)); |
1192 |
|
|
pr_retip((struct ip *)icp->icmp_data); |
1193 |
|
|
break; |
1194 |
|
|
case ICMP_ECHO: |
1195 |
|
|
(void)printf("Echo Request\n"); |
1196 |
|
|
/* XXX ID + Seq + Data */ |
1197 |
|
|
break; |
1198 |
|
|
case ICMP_ROUTERADVERT: |
1199 |
|
|
/* RFC1256 */ |
1200 |
|
|
(void)printf("Router Discovery Advertisement\n"); |
1201 |
|
|
(void)printf("(%d entries, lifetime %d seconds)\n", |
1202 |
|
|
icp->icmp_num_addrs, ntohs(icp->icmp_lifetime)); |
1203 |
|
|
break; |
1204 |
|
|
case ICMP_ROUTERSOLICIT: |
1205 |
|
|
/* RFC1256 */ |
1206 |
|
|
(void)printf("Router Discovery Solicitation\n"); |
1207 |
|
|
break; |
1208 |
|
|
case ICMP_TIMXCEED: |
1209 |
|
|
switch(icp->icmp_code) { |
1210 |
|
|
case ICMP_TIMXCEED_INTRANS: |
1211 |
|
|
(void)printf("Time to live exceeded\n"); |
1212 |
|
|
break; |
1213 |
|
|
case ICMP_TIMXCEED_REASS: |
1214 |
|
|
(void)printf("Frag reassembly time exceeded\n"); |
1215 |
|
|
break; |
1216 |
|
|
default: |
1217 |
|
|
(void)printf("Time exceeded, Unknown Code: %d\n", |
1218 |
|
|
icp->icmp_code); |
1219 |
|
|
break; |
1220 |
|
|
} |
1221 |
|
|
pr_retip((struct ip *)icp->icmp_data); |
1222 |
|
|
break; |
1223 |
|
|
case ICMP_PARAMPROB: |
1224 |
|
|
switch(icp->icmp_code) { |
1225 |
|
|
case ICMP_PARAMPROB_OPTABSENT: |
1226 |
|
|
(void)printf("Parameter problem, required option " |
1227 |
|
|
"absent: pointer = 0x%02x\n", |
1228 |
|
|
ntohs(icp->icmp_hun.ih_pptr)); |
1229 |
|
|
break; |
1230 |
|
|
default: |
1231 |
|
|
(void)printf("Parameter problem: pointer = 0x%02x\n", |
1232 |
|
|
ntohs(icp->icmp_hun.ih_pptr)); |
1233 |
|
|
break; |
1234 |
|
|
} |
1235 |
|
|
pr_retip((struct ip *)icp->icmp_data); |
1236 |
|
|
break; |
1237 |
|
|
case ICMP_TSTAMP: |
1238 |
|
|
(void)printf("Timestamp\n"); |
1239 |
|
|
/* XXX ID + Seq + 3 timestamps */ |
1240 |
|
|
break; |
1241 |
|
|
case ICMP_TSTAMPREPLY: |
1242 |
|
|
(void)printf("Timestamp Reply\n"); |
1243 |
|
|
/* XXX ID + Seq + 3 timestamps */ |
1244 |
|
|
break; |
1245 |
|
|
case ICMP_IREQ: |
1246 |
|
|
(void)printf("Information Request\n"); |
1247 |
|
|
/* XXX ID + Seq */ |
1248 |
|
|
break; |
1249 |
|
|
case ICMP_IREQREPLY: |
1250 |
|
|
(void)printf("Information Reply\n"); |
1251 |
|
|
/* XXX ID + Seq */ |
1252 |
|
|
break; |
1253 |
|
|
case ICMP_MASKREQ: |
1254 |
|
|
(void)printf("Address Mask Request\n"); |
1255 |
|
|
break; |
1256 |
|
|
case ICMP_MASKREPLY: |
1257 |
|
|
(void)printf("Address Mask Reply (Mask 0x%08x)\n", |
1258 |
|
|
ntohl(icp->icmp_mask)); |
1259 |
|
|
break; |
1260 |
|
|
default: |
1261 |
|
|
(void)printf("Unknown ICMP type: %d\n", icp->icmp_type); |
1262 |
|
|
} |
1263 |
|
|
} |
1264 |
|
|
|
1265 |
|
|
/* |
1266 |
|
|
* pr_iph -- |
1267 |
|
|
* Print an IP header with options. |
1268 |
|
|
*/ |
1269 |
|
|
void |
1270 |
|
|
pr_iph(struct ip *ip) |
1271 |
|
|
{ |
1272 |
|
|
int hlen; |
1273 |
|
|
u_char *cp; |
1274 |
|
|
|
1275 |
|
|
hlen = ip->ip_hl << 2; |
1276 |
|
|
cp = (u_char *)ip + 20; /* point to options */ |
1277 |
|
|
|
1278 |
|
|
(void)printf("Vr HL TOS Len ID Flg off TTL Pro cks Src Dst Data\n"); |
1279 |
|
|
(void)printf(" %1x %1x %02x %04x %04x", |
1280 |
|
|
ip->ip_v, ip->ip_hl, ip->ip_tos, ip->ip_len, ip->ip_id); |
1281 |
|
|
(void)printf(" %1x %04x", ((ip->ip_off) & 0xe000) >> 13, |
1282 |
|
|
(ip->ip_off) & 0x1fff); |
1283 |
|
|
(void)printf(" %02x %02x %04x", ip->ip_ttl, ip->ip_p, ip->ip_sum); |
1284 |
|
|
(void)printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_src.s_addr)); |
1285 |
|
|
(void)printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_dst.s_addr)); |
1286 |
|
|
/* dump and option bytes */ |
1287 |
|
|
while (hlen-- > 20) { |
1288 |
|
|
(void)printf("%02x", *cp++); |
1289 |
|
|
} |
1290 |
|
|
(void)putchar('\n'); |
1291 |
|
|
} |
1292 |
|
|
|
1293 |
|
|
/* |
1294 |
|
|
* pr_addr -- |
1295 |
|
|
* Return an ascii host address as a dotted quad and optionally with |
1296 |
|
|
* a hostname. |
1297 |
|
|
*/ |
1298 |
|
|
char * |
1299 |
|
|
pr_addr(in_addr_t a) |
1300 |
|
|
{ |
1301 |
|
|
struct hostent *hp; |
1302 |
|
|
struct in_addr in; |
1303 |
|
|
static char buf[16+3+HOST_NAME_MAX+1]; |
1304 |
|
|
|
1305 |
|
|
in.s_addr = a; |
1306 |
|
|
if ((options & F_NUMERIC) || |
1307 |
|
|
!(hp = gethostbyaddr((char *)&in.s_addr, sizeof(in.s_addr), AF_INET))) |
1308 |
|
|
(void)snprintf(buf, sizeof buf, "%s", inet_ntoa(in)); |
1309 |
|
|
else |
1310 |
|
|
(void)snprintf(buf, sizeof buf, "%s (%s)", hp->h_name, |
1311 |
|
|
inet_ntoa(in)); |
1312 |
|
|
return(buf); |
1313 |
|
|
} |
1314 |
|
|
|
1315 |
|
|
/* |
1316 |
|
|
* pr_retip -- |
1317 |
|
|
* Dump some info on a returned (via ICMP) IP packet. |
1318 |
|
|
*/ |
1319 |
|
|
void |
1320 |
|
|
pr_retip(struct ip *ip) |
1321 |
|
|
{ |
1322 |
|
|
int hlen; |
1323 |
|
|
u_char *cp; |
1324 |
|
|
|
1325 |
|
|
pr_iph(ip); |
1326 |
|
|
hlen = ip->ip_hl << 2; |
1327 |
|
|
cp = (u_char *)ip + hlen; |
1328 |
|
|
|
1329 |
|
|
if (ip->ip_p == 6) |
1330 |
|
|
(void)printf("TCP: from port %u, to port %u (decimal)\n", |
1331 |
|
|
(*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3))); |
1332 |
|
|
else if (ip->ip_p == 17) |
1333 |
|
|
(void)printf("UDP: from port %u, to port %u (decimal)\n", |
1334 |
|
|
(*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3))); |
1335 |
|
|
} |
1336 |
|
|
|
1337 |
|
|
void |
1338 |
|
|
fill(char *bp, char *patp) |
1339 |
|
|
{ |
1340 |
|
|
int ii, jj, kk; |
1341 |
|
|
int pat[16]; |
1342 |
|
|
char *cp; |
1343 |
|
|
|
1344 |
|
|
for (cp = patp; *cp; cp++) |
1345 |
|
|
if (!isxdigit((unsigned char)*cp)) |
1346 |
|
|
errx(1, "patterns must be specified as hex digits"); |
1347 |
|
|
ii = sscanf(patp, |
1348 |
|
|
"%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x", |
1349 |
|
|
&pat[0], &pat[1], &pat[2], &pat[3], &pat[4], &pat[5], &pat[6], |
1350 |
|
|
&pat[7], &pat[8], &pat[9], &pat[10], &pat[11], &pat[12], |
1351 |
|
|
&pat[13], &pat[14], &pat[15]); |
1352 |
|
|
|
1353 |
|
|
if (ii > 0) |
1354 |
|
|
for (kk = 0; |
1355 |
|
|
kk <= MAXPAYLOAD - (8 + sizeof(struct payload) + ii); |
1356 |
|
|
kk += ii) |
1357 |
|
|
for (jj = 0; jj < ii; ++jj) |
1358 |
|
|
bp[jj + kk] = pat[jj]; |
1359 |
|
|
if (!(options & F_QUIET)) { |
1360 |
|
|
(void)printf("PATTERN: 0x"); |
1361 |
|
|
for (jj = 0; jj < ii; ++jj) |
1362 |
|
|
(void)printf("%02x", bp[jj] & 0xFF); |
1363 |
|
|
(void)printf("\n"); |
1364 |
|
|
} |
1365 |
|
|
} |
1366 |
|
|
|
1367 |
|
|
/* |
1368 |
|
|
* when we get types of ICMP message with parts of the orig. datagram |
1369 |
|
|
* we want to try to assure ourselves that it is from this instance |
1370 |
|
|
* of ping, and not say, a refused finger connection or something |
1371 |
|
|
*/ |
1372 |
|
|
int |
1373 |
|
|
check_icmph(struct ip *iph) |
1374 |
|
|
{ |
1375 |
|
|
struct icmp *icmph; |
1376 |
|
|
|
1377 |
|
|
/* only allow IP version 4 */ |
1378 |
|
|
if (iph->ip_v != 4) |
1379 |
|
|
return 0; |
1380 |
|
|
|
1381 |
|
|
/* Only allow ICMP */ |
1382 |
|
|
if (iph->ip_p != IPPROTO_ICMP) |
1383 |
|
|
return 0; |
1384 |
|
|
|
1385 |
|
|
icmph = (struct icmp *) (iph + (4 * iph->ip_hl)); |
1386 |
|
|
|
1387 |
|
|
/* make sure it is in response to an ECHO request */ |
1388 |
|
|
if (icmph->icmp_type != 8) |
1389 |
|
|
return 0; |
1390 |
|
|
|
1391 |
|
|
/* ok, make sure it has the right id on it */ |
1392 |
|
|
if (icmph->icmp_hun.ih_idseq.icd_id != ident) |
1393 |
|
|
return 0; |
1394 |
|
|
|
1395 |
|
|
return 1; |
1396 |
|
|
} |
1397 |
|
|
|
1398 |
|
|
#ifndef SMALL |
1399 |
|
|
int |
1400 |
|
|
map_tos(char *key, int *val) |
1401 |
|
|
{ |
1402 |
|
|
/* DiffServ Codepoints and other TOS mappings */ |
1403 |
|
|
const struct toskeywords { |
1404 |
|
|
const char *keyword; |
1405 |
|
|
int val; |
1406 |
|
|
} *t, toskeywords[] = { |
1407 |
|
|
{ "af11", IPTOS_DSCP_AF11 }, |
1408 |
|
|
{ "af12", IPTOS_DSCP_AF12 }, |
1409 |
|
|
{ "af13", IPTOS_DSCP_AF13 }, |
1410 |
|
|
{ "af21", IPTOS_DSCP_AF21 }, |
1411 |
|
|
{ "af22", IPTOS_DSCP_AF22 }, |
1412 |
|
|
{ "af23", IPTOS_DSCP_AF23 }, |
1413 |
|
|
{ "af31", IPTOS_DSCP_AF31 }, |
1414 |
|
|
{ "af32", IPTOS_DSCP_AF32 }, |
1415 |
|
|
{ "af33", IPTOS_DSCP_AF33 }, |
1416 |
|
|
{ "af41", IPTOS_DSCP_AF41 }, |
1417 |
|
|
{ "af42", IPTOS_DSCP_AF42 }, |
1418 |
|
|
{ "af43", IPTOS_DSCP_AF43 }, |
1419 |
|
|
{ "critical", IPTOS_PREC_CRITIC_ECP }, |
1420 |
|
|
{ "cs0", IPTOS_DSCP_CS0 }, |
1421 |
|
|
{ "cs1", IPTOS_DSCP_CS1 }, |
1422 |
|
|
{ "cs2", IPTOS_DSCP_CS2 }, |
1423 |
|
|
{ "cs3", IPTOS_DSCP_CS3 }, |
1424 |
|
|
{ "cs4", IPTOS_DSCP_CS4 }, |
1425 |
|
|
{ "cs5", IPTOS_DSCP_CS5 }, |
1426 |
|
|
{ "cs6", IPTOS_DSCP_CS6 }, |
1427 |
|
|
{ "cs7", IPTOS_DSCP_CS7 }, |
1428 |
|
|
{ "ef", IPTOS_DSCP_EF }, |
1429 |
|
|
{ "inetcontrol", IPTOS_PREC_INTERNETCONTROL }, |
1430 |
|
|
{ "lowdelay", IPTOS_LOWDELAY }, |
1431 |
|
|
{ "netcontrol", IPTOS_PREC_NETCONTROL }, |
1432 |
|
|
{ "reliability", IPTOS_RELIABILITY }, |
1433 |
|
|
{ "throughput", IPTOS_THROUGHPUT }, |
1434 |
|
|
{ NULL, -1 }, |
1435 |
|
|
}; |
1436 |
|
|
|
1437 |
|
|
for (t = toskeywords; t->keyword != NULL; t++) { |
1438 |
|
|
if (strcmp(key, t->keyword) == 0) { |
1439 |
|
|
*val = t->val; |
1440 |
|
|
return (1); |
1441 |
|
|
} |
1442 |
|
|
} |
1443 |
|
|
|
1444 |
|
|
return (0); |
1445 |
|
|
} |
1446 |
|
|
#endif /* SMALL */ |
1447 |
|
|
|
1448 |
|
|
void |
1449 |
|
|
usage(void) |
1450 |
|
|
{ |
1451 |
|
|
(void)fprintf(stderr, |
1452 |
|
|
"usage: ping [-DdEefLnqRv] [-c count] [-I ifaddr] [-i wait]\n" |
1453 |
|
|
"\t[-l preload] [-p pattern] [-s packetsize]" |
1454 |
|
|
#ifndef SMALL |
1455 |
|
|
" [-T toskeyword]" |
1456 |
|
|
#endif /* SMALL */ |
1457 |
|
|
"\n\t[-t ttl] [-V rtable] [-w maxwait] host\n"); |
1458 |
|
|
exit(1); |
1459 |
|
|
} |