blob: c0366cdacd626dde1669bf2d97588eb7c6ece3fd [file] [log] [blame]
Lorenzo Colitti313379e2013-07-11 01:07:11 +09001/*
2 * Copyright (c) 1989 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Mike Muuss.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37#ifndef lint
38char copyright[] =
39"@(#) Copyright (c) 1989 The Regents of the University of California.\n\
40 All rights reserved.\n";
41#endif /* not lint */
42
43/*
44 * P I N G . C
45 *
46 * Using the InterNet Control Message Protocol (ICMP) "ECHO" facility,
47 * measure round-trip-delays and packet loss across network paths.
48 *
49 * Author -
50 * Mike Muuss
51 * U. S. Army Ballistic Research Laboratory
52 * December, 1983
53 *
54 * Status -
55 * Public Domain. Distribution Unlimited.
56 * Bugs -
57 * More statistics could always be gathered.
58 * This program has to run SUID to ROOT to access the ICMP socket.
59 */
60
61#include "ping_common.h"
62
63#include <netinet/ip.h>
64#include <netinet/ip_icmp.h>
65#ifndef WITHOUT_IFADDRS
66#include <ifaddrs.h>
67#endif
68
69#ifndef ICMP_FILTER
70#define ICMP_FILTER 1
71struct icmp_filter {
72 __u32 data;
73};
74#endif
75
76
77#define MAXIPLEN 60
78#define MAXICMPLEN 76
79#define NROUTES 9 /* number of record route slots */
80#define TOS_MAX 255 /* 8-bit TOS field */
81#define MAX_HOSTNAMELEN NI_MAXHOST
82
83
84static int ts_type;
85static int nroute = 0;
86static __u32 route[10];
87
88
89
90struct sockaddr_in whereto; /* who to ping */
91int optlen = 0;
92int settos = 0; /* Set TOS, Precendence or other QOS options */
93int icmp_sock; /* socket file descriptor */
94u_char outpack[0x10000];
95int maxpacket = sizeof(outpack);
96
97static int broadcast_pings = 0;
98
99static char *pr_addr(__u32);
100static void pr_options(unsigned char * cp, int hlen);
101static void pr_iph(struct iphdr *ip);
102static void usage(void) __attribute__((noreturn));
103static u_short in_cksum(const u_short *addr, int len, u_short salt);
104static void pr_icmph(__u8 type, __u8 code, __u32 info, struct icmphdr *icp);
105static int parsetos(char *str);
106
107static struct {
108 struct cmsghdr cm;
109 struct in_pktinfo ipi;
110} cmsg = { {sizeof(struct cmsghdr) + sizeof(struct in_pktinfo), SOL_IP, IP_PKTINFO},
111 {0, }};
112int cmsg_len;
113
114struct sockaddr_in source;
115char *device;
116int pmtudisc = -1;
117
118
119int
120main(int argc, char **argv)
121{
122 struct hostent *hp;
123 int ch, hold, packlen;
124 int socket_errno;
125 u_char *packet;
126 char *target;
127#ifdef USE_IDN
128 char *hnamebuf = NULL;
129#else
130 char hnamebuf[MAX_HOSTNAMELEN];
131#endif
132 char rspace[3 + 4 * NROUTES + 1]; /* record route space */
133
134 limit_capabilities();
135
136#ifdef USE_IDN
137 setlocale(LC_ALL, "");
138#endif
139
140 enable_capability_raw();
141
142 icmp_sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
143 socket_errno = errno;
144
145 disable_capability_raw();
146
147 source.sin_family = AF_INET;
148
149 preload = 1;
150 while ((ch = getopt(argc, argv, COMMON_OPTSTR "bRT:")) != EOF) {
151 switch(ch) {
152 case 'b':
153 broadcast_pings = 1;
154 break;
155 case 'Q':
156 settos = parsetos(optarg);
157 if (settos &&
158 (setsockopt(icmp_sock, IPPROTO_IP, IP_TOS,
159 (char *)&settos, sizeof(int)) < 0)) {
160 perror("ping: error setting QOS sockopts");
161 exit(2);
162 }
163 break;
164 case 'R':
165 if (options & F_TIMESTAMP) {
166 fprintf(stderr, "Only one of -T or -R may be used\n");
167 exit(2);
168 }
169 options |= F_RROUTE;
170 break;
171 case 'T':
172 if (options & F_RROUTE) {
173 fprintf(stderr, "Only one of -T or -R may be used\n");
174 exit(2);
175 }
176 options |= F_TIMESTAMP;
177 if (strcmp(optarg, "tsonly") == 0)
178 ts_type = IPOPT_TS_TSONLY;
179 else if (strcmp(optarg, "tsandaddr") == 0)
180 ts_type = IPOPT_TS_TSANDADDR;
181 else if (strcmp(optarg, "tsprespec") == 0)
182 ts_type = IPOPT_TS_PRESPEC;
183 else {
184 fprintf(stderr, "Invalid timestamp type\n");
185 exit(2);
186 }
187 break;
188 case 'I':
189 {
190#if 0
191 char dummy;
192 int i1, i2, i3, i4;
193
194 if (sscanf(optarg, "%u.%u.%u.%u%c",
195 &i1, &i2, &i3, &i4, &dummy) == 4) {
196 __u8 *ptr;
197 ptr = (__u8*)&source.sin_addr;
198 ptr[0] = i1;
199 ptr[1] = i2;
200 ptr[2] = i3;
201 ptr[3] = i4;
202 options |= F_STRICTSOURCE;
203 } else {
204 device = optarg;
205 }
206#else
207 if (inet_pton(AF_INET, optarg, &source.sin_addr) > 0)
208 options |= F_STRICTSOURCE;
209 else
210 device = optarg;
211#endif
212 break;
213 }
214 case 'M':
215 if (strcmp(optarg, "do") == 0)
216 pmtudisc = IP_PMTUDISC_DO;
217 else if (strcmp(optarg, "dont") == 0)
218 pmtudisc = IP_PMTUDISC_DONT;
219 else if (strcmp(optarg, "want") == 0)
220 pmtudisc = IP_PMTUDISC_WANT;
221 else {
222 fprintf(stderr, "ping: wrong value for -M: do, dont, want are valid ones.\n");
223 exit(2);
224 }
225 break;
226 case 'V':
227 printf("ping utility, iputils-%s\n", SNAPSHOT);
228 exit(0);
229 COMMON_OPTIONS
230 common_options(ch);
231 break;
232 default:
233 usage();
234 }
235 }
236 argc -= optind;
237 argv += optind;
238
239 if (argc == 0)
240 usage();
241 if (argc > 1) {
242 if (options & F_RROUTE)
243 usage();
244 else if (options & F_TIMESTAMP) {
245 if (ts_type != IPOPT_TS_PRESPEC)
246 usage();
247 if (argc > 5)
248 usage();
249 } else {
250 if (argc > 10)
251 usage();
252 options |= F_SOURCEROUTE;
253 }
254 }
255 while (argc > 0) {
256 target = *argv;
257
258 memset((char *)&whereto, 0, sizeof(whereto));
259 whereto.sin_family = AF_INET;
260 if (inet_aton(target, &whereto.sin_addr) == 1) {
261 hostname = target;
262 if (argc == 1)
263 options |= F_NUMERIC;
264 } else {
265 char *idn;
266#ifdef USE_IDN
267 int rc;
268
269 if (hnamebuf) {
270 free(hnamebuf);
271 hnamebuf = NULL;
272 }
273
274 rc = idna_to_ascii_lz(target, &idn, 0);
275 if (rc != IDNA_SUCCESS) {
276 fprintf(stderr, "ping: IDN encoding failed: %s\n", idna_strerror(rc));
277 exit(2);
278 }
279#else
280 idn = target;
281#endif
282 hp = gethostbyname(idn);
283 if (!hp) {
284 fprintf(stderr, "ping: unknown host %s\n", target);
285 exit(2);
286 }
287#ifdef USE_IDN
288 free(idn);
289#endif
290 memcpy(&whereto.sin_addr, hp->h_addr, 4);
291#ifdef USE_IDN
292 if (idna_to_unicode_lzlz(hp->h_name, &hnamebuf, 0) != IDNA_SUCCESS) {
293 hnamebuf = strdup(hp->h_name);
294 if (!hnamebuf) {
295 perror("ping: strdup");
296 exit(-1);
297 }
298 }
299#else
300 strncpy(hnamebuf, hp->h_name, sizeof(hnamebuf) - 1);
301 hnamebuf[sizeof(hnamebuf) - 1] = 0;
302#endif
303 hostname = hnamebuf;
304 }
305 if (argc > 1)
306 route[nroute++] = whereto.sin_addr.s_addr;
307 argc--;
308 argv++;
309 }
310
311 if (source.sin_addr.s_addr == 0) {
312 socklen_t alen;
313 struct sockaddr_in dst = whereto;
314 int probe_fd = socket(AF_INET, SOCK_DGRAM, 0);
315
316 if (probe_fd < 0) {
317 perror("socket");
318 exit(2);
319 }
320 if (device) {
321 struct ifreq ifr;
322 int rc;
323
324 memset(&ifr, 0, sizeof(ifr));
325 strncpy(ifr.ifr_name, device, IFNAMSIZ-1);
326
327 enable_capability_raw();
328 rc = setsockopt(probe_fd, SOL_SOCKET, SO_BINDTODEVICE, device, strlen(device)+1);
329 disable_capability_raw();
330
331 if (rc == -1) {
332 if (IN_MULTICAST(ntohl(dst.sin_addr.s_addr))) {
333 struct ip_mreqn imr;
334 if (ioctl(probe_fd, SIOCGIFINDEX, &ifr) < 0) {
335 fprintf(stderr, "ping: unknown iface %s\n", device);
336 exit(2);
337 }
338 memset(&imr, 0, sizeof(imr));
339 imr.imr_ifindex = ifr.ifr_ifindex;
340 if (setsockopt(probe_fd, SOL_IP, IP_MULTICAST_IF, &imr, sizeof(imr)) == -1) {
341 perror("ping: IP_MULTICAST_IF");
342 exit(2);
343 }
344 } else {
345 perror("ping: SO_BINDTODEVICE");
346 exit(2);
347 }
348 }
349 }
350
351 if (settos &&
352 setsockopt(probe_fd, IPPROTO_IP, IP_TOS, (char *)&settos, sizeof(int)) < 0)
353 perror("Warning: error setting QOS sockopts");
354
355 dst.sin_port = htons(1025);
356 if (nroute)
357 dst.sin_addr.s_addr = route[0];
358 if (connect(probe_fd, (struct sockaddr*)&dst, sizeof(dst)) == -1) {
359 if (errno == EACCES) {
360 if (broadcast_pings == 0) {
361 fprintf(stderr, "Do you want to ping broadcast? Then -b\n");
362 exit(2);
363 }
364 fprintf(stderr, "WARNING: pinging broadcast address\n");
365 if (setsockopt(probe_fd, SOL_SOCKET, SO_BROADCAST,
366 &broadcast_pings, sizeof(broadcast_pings)) < 0) {
367 perror ("can't set broadcasting");
368 exit(2);
369 }
370 if (connect(probe_fd, (struct sockaddr*)&dst, sizeof(dst)) == -1) {
371 perror("connect");
372 exit(2);
373 }
374 } else {
375 perror("connect");
376 exit(2);
377 }
378 }
379 alen = sizeof(source);
380 if (getsockname(probe_fd, (struct sockaddr*)&source, &alen) == -1) {
381 perror("getsockname");
382 exit(2);
383 }
384 source.sin_port = 0;
385
386#ifndef WITHOUT_IFADDRS
387 if (device) {
388 struct ifaddrs *ifa0, *ifa;
389 int ret;
390
391 ret = getifaddrs(&ifa0);
392 if (ret) {
393 fprintf(stderr, "gatifaddrs() failed.\n");
394 exit(2);
395 }
396 for (ifa = ifa0; ifa; ifa = ifa->ifa_next) {
397 if (!ifa->ifa_addr || ifa->ifa_addr->sa_family != AF_INET)
398 continue;
399 if (!strncmp(ifa->ifa_name, device, sizeof(device) - 1) &&
400 !memcmp(&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr,
401 &source.sin_addr, sizeof(source.sin_addr)))
402 break;
403 }
404 freeifaddrs(ifa0);
405 if (!ifa)
406 fprintf(stderr, "ping: Warning: source address might be selected on device other than %s.\n", device);
407 }
408#endif
409 close(probe_fd);
410 } while (0);
411
412 if (whereto.sin_addr.s_addr == 0)
413 whereto.sin_addr.s_addr = source.sin_addr.s_addr;
414
415 if (icmp_sock < 0) {
416 errno = socket_errno;
417 perror("ping: icmp open socket");
418 exit(2);
419 }
420
421 if (device) {
422 struct ifreq ifr;
423
424 memset(&ifr, 0, sizeof(ifr));
425 strncpy(ifr.ifr_name, device, IFNAMSIZ-1);
426 if (ioctl(icmp_sock, SIOCGIFINDEX, &ifr) < 0) {
427 fprintf(stderr, "ping: unknown iface %s\n", device);
428 exit(2);
429 }
430 cmsg.ipi.ipi_ifindex = ifr.ifr_ifindex;
431 cmsg_len = sizeof(cmsg);
432 }
433
434 if (broadcast_pings || IN_MULTICAST(ntohl(whereto.sin_addr.s_addr))) {
435 if (uid) {
436 if (interval < 1000) {
437 fprintf(stderr, "ping: broadcast ping with too short interval.\n");
438 exit(2);
439 }
440 if (pmtudisc >= 0 && pmtudisc != IP_PMTUDISC_DO) {
441 fprintf(stderr, "ping: broadcast ping does not fragment.\n");
442 exit(2);
443 }
444 }
445 if (pmtudisc < 0)
446 pmtudisc = IP_PMTUDISC_DO;
447 }
448
449 if (pmtudisc >= 0) {
450 if (setsockopt(icmp_sock, SOL_IP, IP_MTU_DISCOVER, &pmtudisc, sizeof(pmtudisc)) == -1) {
451 perror("ping: IP_MTU_DISCOVER");
452 exit(2);
453 }
454 }
455
456 if ((options&F_STRICTSOURCE) &&
457 bind(icmp_sock, (struct sockaddr*)&source, sizeof(source)) == -1) {
458 perror("bind");
459 exit(2);
460 }
461
462 if (1) {
463 struct icmp_filter filt;
464 filt.data = ~((1<<ICMP_SOURCE_QUENCH)|
465 (1<<ICMP_DEST_UNREACH)|
466 (1<<ICMP_TIME_EXCEEDED)|
467 (1<<ICMP_PARAMETERPROB)|
468 (1<<ICMP_REDIRECT)|
469 (1<<ICMP_ECHOREPLY));
470 if (setsockopt(icmp_sock, SOL_RAW, ICMP_FILTER, (char*)&filt, sizeof(filt)) == -1)
471 perror("WARNING: setsockopt(ICMP_FILTER)");
472 }
473
474 hold = 1;
475 if (setsockopt(icmp_sock, SOL_IP, IP_RECVERR, (char *)&hold, sizeof(hold)))
476 fprintf(stderr, "WARNING: your kernel is veeery old. No problems.\n");
477
478 /* record route option */
479 if (options & F_RROUTE) {
480 memset(rspace, 0, sizeof(rspace));
481 rspace[0] = IPOPT_NOP;
482 rspace[1+IPOPT_OPTVAL] = IPOPT_RR;
483 rspace[1+IPOPT_OLEN] = sizeof(rspace)-1;
484 rspace[1+IPOPT_OFFSET] = IPOPT_MINOFF;
485 optlen = 40;
486 if (setsockopt(icmp_sock, IPPROTO_IP, IP_OPTIONS, rspace, sizeof(rspace)) < 0) {
487 perror("ping: record route");
488 exit(2);
489 }
490 }
491 if (options & F_TIMESTAMP) {
492 memset(rspace, 0, sizeof(rspace));
493 rspace[0] = IPOPT_TIMESTAMP;
494 rspace[1] = (ts_type==IPOPT_TS_TSONLY ? 40 : 36);
495 rspace[2] = 5;
496 rspace[3] = ts_type;
497 if (ts_type == IPOPT_TS_PRESPEC) {
498 int i;
499 rspace[1] = 4+nroute*8;
500 for (i=0; i<nroute; i++)
501 *(__u32*)&rspace[4+i*8] = route[i];
502 }
503 if (setsockopt(icmp_sock, IPPROTO_IP, IP_OPTIONS, rspace, rspace[1]) < 0) {
504 rspace[3] = 2;
505 if (setsockopt(icmp_sock, IPPROTO_IP, IP_OPTIONS, rspace, rspace[1]) < 0) {
506 perror("ping: ts option");
507 exit(2);
508 }
509 }
510 optlen = 40;
511 }
512 if (options & F_SOURCEROUTE) {
513 int i;
514 memset(rspace, 0, sizeof(rspace));
515 rspace[0] = IPOPT_NOOP;
516 rspace[1+IPOPT_OPTVAL] = (options & F_SO_DONTROUTE) ? IPOPT_SSRR
517 : IPOPT_LSRR;
518 rspace[1+IPOPT_OLEN] = 3 + nroute*4;
519 rspace[1+IPOPT_OFFSET] = IPOPT_MINOFF;
520 for (i=0; i<nroute; i++)
521 *(__u32*)&rspace[4+i*4] = route[i];
522
523 if (setsockopt(icmp_sock, IPPROTO_IP, IP_OPTIONS, rspace, 4 + nroute*4) < 0) {
524 perror("ping: record route");
525 exit(2);
526 }
527 optlen = 40;
528 }
529
530 /* Estimate memory eaten by single packet. It is rough estimate.
531 * Actually, for small datalen's it depends on kernel side a lot. */
532 hold = datalen + 8;
533 hold += ((hold+511)/512)*(optlen + 20 + 16 + 64 + 160);
534 sock_setbufs(icmp_sock, hold);
535
536 if (broadcast_pings) {
537 if (setsockopt(icmp_sock, SOL_SOCKET, SO_BROADCAST,
538 &broadcast_pings, sizeof(broadcast_pings)) < 0) {
539 perror ("ping: can't set broadcasting");
540 exit(2);
541 }
542 }
543
544 if (options & F_NOLOOP) {
545 int loop = 0;
546 if (setsockopt(icmp_sock, IPPROTO_IP, IP_MULTICAST_LOOP,
547 &loop, 1) == -1) {
548 perror ("ping: can't disable multicast loopback");
549 exit(2);
550 }
551 }
552 if (options & F_TTL) {
553 int ittl = ttl;
554 if (setsockopt(icmp_sock, IPPROTO_IP, IP_MULTICAST_TTL,
555 &ttl, 1) == -1) {
556 perror ("ping: can't set multicast time-to-live");
557 exit(2);
558 }
559 if (setsockopt(icmp_sock, IPPROTO_IP, IP_TTL,
560 &ittl, sizeof(ittl)) == -1) {
561 perror ("ping: can't set unicast time-to-live");
562 exit(2);
563 }
564 }
565
566 if (datalen > 0xFFFF - 8 - optlen - 20) {
567 if (uid || datalen > sizeof(outpack)-8) {
568 fprintf(stderr, "Error: packet size %d is too large. Maximum is %d\n", datalen, 0xFFFF-8-20-optlen);
569 exit(2);
570 }
571 /* Allow small oversize to root yet. It will cause EMSGSIZE. */
572 fprintf(stderr, "WARNING: packet size %d is too large. Maximum is %d\n", datalen, 0xFFFF-8-20-optlen);
573 }
574
575 if (datalen >= sizeof(struct timeval)) /* can we time transfer */
576 timing = 1;
577 packlen = datalen + MAXIPLEN + MAXICMPLEN;
578 if (!(packet = (u_char *)malloc((u_int)packlen))) {
579 fprintf(stderr, "ping: out of memory.\n");
580 exit(2);
581 }
582
583 printf("PING %s (%s) ", hostname, inet_ntoa(whereto.sin_addr));
584 if (device || (options&F_STRICTSOURCE))
585 printf("from %s %s: ", inet_ntoa(source.sin_addr), device ?: "");
586 printf("%d(%d) bytes of data.\n", datalen, datalen+8+optlen+20);
587
588 setup(icmp_sock);
589
590 main_loop(icmp_sock, packet, packlen);
591}
592
593
594int receive_error_msg()
595{
596 int res;
597 char cbuf[512];
598 struct iovec iov;
599 struct msghdr msg;
600 struct cmsghdr *cmsg;
601 struct sock_extended_err *e;
602 struct icmphdr icmph;
603 struct sockaddr_in target;
604 int net_errors = 0;
605 int local_errors = 0;
606 int saved_errno = errno;
607
608 iov.iov_base = &icmph;
609 iov.iov_len = sizeof(icmph);
610 msg.msg_name = (void*)&target;
611 msg.msg_namelen = sizeof(target);
612 msg.msg_iov = &iov;
613 msg.msg_iovlen = 1;
614 msg.msg_flags = 0;
615 msg.msg_control = cbuf;
616 msg.msg_controllen = sizeof(cbuf);
617
618 res = recvmsg(icmp_sock, &msg, MSG_ERRQUEUE|MSG_DONTWAIT);
619 if (res < 0)
620 goto out;
621
622 e = NULL;
623 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
624 if (cmsg->cmsg_level == SOL_IP) {
625 if (cmsg->cmsg_type == IP_RECVERR)
626 e = (struct sock_extended_err *)CMSG_DATA(cmsg);
627 }
628 }
629 if (e == NULL)
630 abort();
631
632 if (e->ee_origin == SO_EE_ORIGIN_LOCAL) {
633 local_errors++;
634 if (options & F_QUIET)
635 goto out;
636 if (options & F_FLOOD)
637 write_stdout("E", 1);
638 else if (e->ee_errno != EMSGSIZE)
639 fprintf(stderr, "ping: local error: %s\n", strerror(e->ee_errno));
640 else
641 fprintf(stderr, "ping: local error: Message too long, mtu=%u\n", e->ee_info);
642 nerrors++;
643 } else if (e->ee_origin == SO_EE_ORIGIN_ICMP) {
644 struct sockaddr_in *sin = (struct sockaddr_in*)(e+1);
645
646 if (res < sizeof(icmph) ||
647 target.sin_addr.s_addr != whereto.sin_addr.s_addr ||
648 icmph.type != ICMP_ECHO ||
649 icmph.un.echo.id != ident) {
650 /* Not our error, not an error at all. Clear. */
651 saved_errno = 0;
652 goto out;
653 }
654
655 acknowledge(ntohs(icmph.un.echo.sequence));
656
657 if (!working_recverr) {
658 struct icmp_filter filt;
659 working_recverr = 1;
660 /* OK, it works. Add stronger filter. */
661 filt.data = ~((1<<ICMP_SOURCE_QUENCH)|
662 (1<<ICMP_REDIRECT)|
663 (1<<ICMP_ECHOREPLY));
664 if (setsockopt(icmp_sock, SOL_RAW, ICMP_FILTER, (char*)&filt, sizeof(filt)) == -1)
665 perror("\rWARNING: setsockopt(ICMP_FILTER)");
666 }
667
668 net_errors++;
669 nerrors++;
670 if (options & F_QUIET)
671 goto out;
672 if (options & F_FLOOD) {
673 write_stdout("\bE", 2);
674 } else {
675 print_timestamp();
676 printf("From %s icmp_seq=%u ", pr_addr(sin->sin_addr.s_addr), ntohs(icmph.un.echo.sequence));
677 pr_icmph(e->ee_type, e->ee_code, e->ee_info, NULL);
678 fflush(stdout);
679 }
680 }
681
682out:
683 errno = saved_errno;
684 return net_errors ? : -local_errors;
685}
686
687/*
688 * pinger --
689 * Compose and transmit an ICMP ECHO REQUEST packet. The IP packet
690 * will be added on by the kernel. The ID field is our UNIX process ID,
691 * and the sequence number is an ascending integer. The first 8 bytes
692 * of the data portion are used to hold a UNIX "timeval" struct in VAX
693 * byte-order, to compute the round-trip time.
694 */
695int send_probe()
696{
697 struct icmphdr *icp;
698 int cc;
699 int i;
700
701 icp = (struct icmphdr *)outpack;
702 icp->type = ICMP_ECHO;
703 icp->code = 0;
704 icp->checksum = 0;
705 icp->un.echo.sequence = htons(ntransmitted+1);
706 icp->un.echo.id = ident; /* ID */
707
708 rcvd_clear(ntransmitted+1);
709
710 if (timing) {
711 if (options&F_LATENCY) {
712 struct timeval tmp_tv;
713 gettimeofday(&tmp_tv, NULL);
714 memcpy(icp+1, &tmp_tv, sizeof(tmp_tv));
715 } else {
716 memset(icp+1, 0, sizeof(struct timeval));
717 }
718 }
719
720 cc = datalen + 8; /* skips ICMP portion */
721
722 /* compute ICMP checksum here */
723 icp->checksum = in_cksum((u_short *)icp, cc, 0);
724
725 if (timing && !(options&F_LATENCY)) {
726 struct timeval tmp_tv;
727 gettimeofday(&tmp_tv, NULL);
728 memcpy(icp+1, &tmp_tv, sizeof(tmp_tv));
729 icp->checksum = in_cksum((u_short *)&tmp_tv, sizeof(tmp_tv), ~icp->checksum);
730 }
731
732 do {
733 static struct iovec iov = {outpack, 0};
734 static struct msghdr m = { &whereto, sizeof(whereto),
735 &iov, 1, &cmsg, 0, 0 };
736 m.msg_controllen = cmsg_len;
737 iov.iov_len = cc;
738
739 i = sendmsg(icmp_sock, &m, confirm);
740 confirm = 0;
741 } while (0);
742
743 return (cc == i ? 0 : i);
744}
745
746/*
747 * parse_reply --
748 * Print out the packet, if it came from us. This logic is necessary
749 * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
750 * which arrive ('tis only fair). This permits multiple copies of this
751 * program to be run without having intermingled output (or statistics!).
752 */
753void pr_echo_reply(__u8 *_icp, int len)
754{
755 struct icmphdr *icp = (struct icmphdr *)_icp;
756 printf(" icmp_seq=%u", ntohs(icp->un.echo.sequence));
757}
758
759int
760parse_reply(struct msghdr *msg, int cc, void *addr, struct timeval *tv)
761{
762 struct sockaddr_in *from = addr;
763 __u8 *buf = msg->msg_iov->iov_base;
764 struct icmphdr *icp;
765 struct iphdr *ip;
766 int hlen;
767 int csfailed;
768
769 /* Check the IP header */
770 ip = (struct iphdr *)buf;
771 hlen = ip->ihl*4;
772 if (cc < hlen + 8 || ip->ihl < 5) {
773 if (options & F_VERBOSE)
774 fprintf(stderr, "ping: packet too short (%d bytes) from %s\n", cc,
775 pr_addr(from->sin_addr.s_addr));
776 return 1;
777 }
778
779 /* Now the ICMP part */
780 cc -= hlen;
781 icp = (struct icmphdr *)(buf + hlen);
782 csfailed = in_cksum((u_short *)icp, cc, 0);
783
784 if (icp->type == ICMP_ECHOREPLY) {
785 if (icp->un.echo.id != ident)
786 return 1; /* 'Twas not our ECHO */
787 if (gather_statistics((__u8*)icp, sizeof(*icp), cc,
788 ntohs(icp->un.echo.sequence),
789 ip->ttl, 0, tv, pr_addr(from->sin_addr.s_addr),
790 pr_echo_reply))
791 return 0;
792 } else {
793 /* We fall here when a redirect or source quench arrived.
794 * Also this branch processes icmp errors, when IP_RECVERR
795 * is broken. */
796
797 switch (icp->type) {
798 case ICMP_ECHO:
799 /* MUST NOT */
800 return 1;
801 case ICMP_SOURCE_QUENCH:
802 case ICMP_REDIRECT:
803 case ICMP_DEST_UNREACH:
804 case ICMP_TIME_EXCEEDED:
805 case ICMP_PARAMETERPROB:
806 {
807 struct iphdr * iph = (struct iphdr *)(&icp[1]);
808 struct icmphdr *icp1 = (struct icmphdr*)((unsigned char *)iph + iph->ihl*4);
809 int error_pkt;
810 if (cc < 8+sizeof(struct iphdr)+8 ||
811 cc < 8+iph->ihl*4+8)
812 return 1;
813 if (icp1->type != ICMP_ECHO ||
814 iph->daddr != whereto.sin_addr.s_addr ||
815 icp1->un.echo.id != ident)
816 return 1;
817 error_pkt = (icp->type != ICMP_REDIRECT &&
818 icp->type != ICMP_SOURCE_QUENCH);
819 if (error_pkt) {
820 acknowledge(ntohs(icp1->un.echo.sequence));
821 if (working_recverr) {
822 return 0;
823 } else {
824 static int once;
825 /* Sigh, IP_RECVERR for raw socket
826 * was broken until 2.4.9. So, we ignore
827 * the first error and warn on the second.
828 */
829 if (once++ == 1)
830 fprintf(stderr, "\rWARNING: kernel is not very fresh, upgrade is recommended.\n");
831 if (once == 1)
832 return 0;
833 }
834 }
835 nerrors+=error_pkt;
836 if (options&F_QUIET)
837 return !error_pkt;
838 if (options & F_FLOOD) {
839 if (error_pkt)
840 write_stdout("\bE", 2);
841 return !error_pkt;
842 }
843 print_timestamp();
844 printf("From %s: icmp_seq=%u ",
845 pr_addr(from->sin_addr.s_addr),
846 ntohs(icp1->un.echo.sequence));
847 if (csfailed)
848 printf("(BAD CHECKSUM)");
849 pr_icmph(icp->type, icp->code, ntohl(icp->un.gateway), icp);
850 return !error_pkt;
851 }
852 default:
853 /* MUST NOT */
854 break;
855 }
856 if ((options & F_FLOOD) && !(options & (F_VERBOSE|F_QUIET))) {
857 if (!csfailed)
858 write_stdout("!E", 2);
859 else
860 write_stdout("!EC", 3);
861 return 0;
862 }
863 if (!(options & F_VERBOSE) || uid)
864 return 0;
865 if (options & F_PTIMEOFDAY) {
866 struct timeval recv_time;
867 gettimeofday(&recv_time, NULL);
868 printf("%lu.%06lu ", (unsigned long)recv_time.tv_sec, (unsigned long)recv_time.tv_usec);
869 }
870 printf("From %s: ", pr_addr(from->sin_addr.s_addr));
871 if (csfailed) {
872 printf("(BAD CHECKSUM)\n");
873 return 0;
874 }
875 pr_icmph(icp->type, icp->code, ntohl(icp->un.gateway), icp);
876 return 0;
877 }
878
879 if (!(options & F_FLOOD)) {
880 pr_options(buf + sizeof(struct iphdr), hlen);
881
882 if (options & F_AUDIBLE)
883 putchar('\a');
884 putchar('\n');
885 fflush(stdout);
886 } else {
887 putchar('\a');
888 fflush(stdout);
889 }
890 return 0;
891}
892
893
894#if BYTE_ORDER == LITTLE_ENDIAN
895# define ODDBYTE(v) (v)
896#elif BYTE_ORDER == BIG_ENDIAN
897# define ODDBYTE(v) ((u_short)(v) << 8)
898#else
899# define ODDBYTE(v) htons((u_short)(v) << 8)
900#endif
901
902u_short
903in_cksum(const u_short *addr, register int len, u_short csum)
904{
905 register int nleft = len;
906 const u_short *w = addr;
907 register u_short answer;
908 register int sum = csum;
909
910 /*
911 * Our algorithm is simple, using a 32 bit accumulator (sum),
912 * we add sequential 16 bit words to it, and at the end, fold
913 * back all the carry bits from the top 16 bits into the lower
914 * 16 bits.
915 */
916 while (nleft > 1) {
917 sum += *w++;
918 nleft -= 2;
919 }
920
921 /* mop up an odd byte, if necessary */
922 if (nleft == 1)
923 sum += ODDBYTE(*(u_char *)w); /* le16toh() may be unavailable on old systems */
924
925 /*
926 * add back carry outs from top 16 bits to low 16 bits
927 */
928 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
929 sum += (sum >> 16); /* add carry */
930 answer = ~sum; /* truncate to 16 bits */
931 return (answer);
932}
933
934/*
935 * pr_icmph --
936 * Print a descriptive string about an ICMP header.
937 */
938void pr_icmph(__u8 type, __u8 code, __u32 info, struct icmphdr *icp)
939{
940 switch(type) {
941 case ICMP_ECHOREPLY:
942 printf("Echo Reply\n");
943 /* XXX ID + Seq + Data */
944 break;
945 case ICMP_DEST_UNREACH:
946 switch(code) {
947 case ICMP_NET_UNREACH:
948 printf("Destination Net Unreachable\n");
949 break;
950 case ICMP_HOST_UNREACH:
951 printf("Destination Host Unreachable\n");
952 break;
953 case ICMP_PROT_UNREACH:
954 printf("Destination Protocol Unreachable\n");
955 break;
956 case ICMP_PORT_UNREACH:
957 printf("Destination Port Unreachable\n");
958 break;
959 case ICMP_FRAG_NEEDED:
960 printf("Frag needed and DF set (mtu = %u)\n", info);
961 break;
962 case ICMP_SR_FAILED:
963 printf("Source Route Failed\n");
964 break;
965 case ICMP_NET_UNKNOWN:
966 printf("Destination Net Unknown\n");
967 break;
968 case ICMP_HOST_UNKNOWN:
969 printf("Destination Host Unknown\n");
970 break;
971 case ICMP_HOST_ISOLATED:
972 printf("Source Host Isolated\n");
973 break;
974 case ICMP_NET_ANO:
975 printf("Destination Net Prohibited\n");
976 break;
977 case ICMP_HOST_ANO:
978 printf("Destination Host Prohibited\n");
979 break;
980 case ICMP_NET_UNR_TOS:
981 printf("Destination Net Unreachable for Type of Service\n");
982 break;
983 case ICMP_HOST_UNR_TOS:
984 printf("Destination Host Unreachable for Type of Service\n");
985 break;
986 case ICMP_PKT_FILTERED:
987 printf("Packet filtered\n");
988 break;
989 case ICMP_PREC_VIOLATION:
990 printf("Precedence Violation\n");
991 break;
992 case ICMP_PREC_CUTOFF:
993 printf("Precedence Cutoff\n");
994 break;
995 default:
996 printf("Dest Unreachable, Bad Code: %d\n", code);
997 break;
998 }
999 if (icp && (options & F_VERBOSE))
1000 pr_iph((struct iphdr*)(icp + 1));
1001 break;
1002 case ICMP_SOURCE_QUENCH:
1003 printf("Source Quench\n");
1004 if (icp && (options & F_VERBOSE))
1005 pr_iph((struct iphdr*)(icp + 1));
1006 break;
1007 case ICMP_REDIRECT:
1008 switch(code) {
1009 case ICMP_REDIR_NET:
1010 printf("Redirect Network");
1011 break;
1012 case ICMP_REDIR_HOST:
1013 printf("Redirect Host");
1014 break;
1015 case ICMP_REDIR_NETTOS:
1016 printf("Redirect Type of Service and Network");
1017 break;
1018 case ICMP_REDIR_HOSTTOS:
1019 printf("Redirect Type of Service and Host");
1020 break;
1021 default:
1022 printf("Redirect, Bad Code: %d", code);
1023 break;
1024 }
1025 if (icp)
1026 printf("(New nexthop: %s)\n", pr_addr(icp->un.gateway));
1027 if (icp && (options & F_VERBOSE))
1028 pr_iph((struct iphdr*)(icp + 1));
1029 break;
1030 case ICMP_ECHO:
1031 printf("Echo Request\n");
1032 /* XXX ID + Seq + Data */
1033 break;
1034 case ICMP_TIME_EXCEEDED:
1035 switch(code) {
1036 case ICMP_EXC_TTL:
1037 printf("Time to live exceeded\n");
1038 break;
1039 case ICMP_EXC_FRAGTIME:
1040 printf("Frag reassembly time exceeded\n");
1041 break;
1042 default:
1043 printf("Time exceeded, Bad Code: %d\n", code);
1044 break;
1045 }
1046 if (icp && (options & F_VERBOSE))
1047 pr_iph((struct iphdr*)(icp + 1));
1048 break;
1049 case ICMP_PARAMETERPROB:
1050 printf("Parameter problem: pointer = %u\n", icp ? (ntohl(icp->un.gateway)>>24) : info);
1051 if (icp && (options & F_VERBOSE))
1052 pr_iph((struct iphdr*)(icp + 1));
1053 break;
1054 case ICMP_TIMESTAMP:
1055 printf("Timestamp\n");
1056 /* XXX ID + Seq + 3 timestamps */
1057 break;
1058 case ICMP_TIMESTAMPREPLY:
1059 printf("Timestamp Reply\n");
1060 /* XXX ID + Seq + 3 timestamps */
1061 break;
1062 case ICMP_INFO_REQUEST:
1063 printf("Information Request\n");
1064 /* XXX ID + Seq */
1065 break;
1066 case ICMP_INFO_REPLY:
1067 printf("Information Reply\n");
1068 /* XXX ID + Seq */
1069 break;
1070#ifdef ICMP_MASKREQ
1071 case ICMP_MASKREQ:
1072 printf("Address Mask Request\n");
1073 break;
1074#endif
1075#ifdef ICMP_MASKREPLY
1076 case ICMP_MASKREPLY:
1077 printf("Address Mask Reply\n");
1078 break;
1079#endif
1080 default:
1081 printf("Bad ICMP type: %d\n", type);
1082 }
1083}
1084
1085void pr_options(unsigned char * cp, int hlen)
1086{
1087 int i, j;
1088 int optlen, totlen;
1089 unsigned char * optptr;
1090 static int old_rrlen;
1091 static char old_rr[MAX_IPOPTLEN];
1092
1093 totlen = hlen-sizeof(struct iphdr);
1094 optptr = cp;
1095
1096 while (totlen > 0) {
1097 if (*optptr == IPOPT_EOL)
1098 break;
1099 if (*optptr == IPOPT_NOP) {
1100 totlen--;
1101 optptr++;
1102 printf("\nNOP");
1103 continue;
1104 }
1105 cp = optptr;
1106 optlen = optptr[1];
1107 if (optlen < 2 || optlen > totlen)
1108 break;
1109
1110 switch (*cp) {
1111 case IPOPT_SSRR:
1112 case IPOPT_LSRR:
1113 printf("\n%cSRR: ", *cp==IPOPT_SSRR ? 'S' : 'L');
1114 j = *++cp;
1115 i = *++cp;
1116 i -= 4;
1117 cp++;
1118 if (j > IPOPT_MINOFF) {
1119 for (;;) {
1120 __u32 address;
1121 memcpy(&address, cp, 4);
1122 cp += 4;
1123 if (address == 0)
1124 printf("\t0.0.0.0");
1125 else
1126 printf("\t%s", pr_addr(address));
1127 j -= 4;
1128 putchar('\n');
1129 if (j <= IPOPT_MINOFF)
1130 break;
1131 }
1132 }
1133 break;
1134 case IPOPT_RR:
1135 j = *++cp; /* get length */
1136 i = *++cp; /* and pointer */
1137 if (i > j)
1138 i = j;
1139 i -= IPOPT_MINOFF;
1140 if (i <= 0)
1141 break;
1142 if (i == old_rrlen
1143 && !memcmp(cp, old_rr, i)
1144 && !(options & F_FLOOD)) {
1145 printf("\t(same route)");
1146 i = ((i + 3) / 4) * 4;
1147 cp += i;
1148 break;
1149 }
1150 old_rrlen = i;
1151 memcpy(old_rr, (char *)cp, i);
1152 printf("\nRR: ");
1153 cp++;
1154 for (;;) {
1155 __u32 address;
1156 memcpy(&address, cp, 4);
1157 cp += 4;
1158 if (address == 0)
1159 printf("\t0.0.0.0");
1160 else
1161 printf("\t%s", pr_addr(address));
1162 i -= 4;
1163 putchar('\n');
1164 if (i <= 0)
1165 break;
1166 }
1167 break;
1168 case IPOPT_TS:
1169 {
1170 int stdtime = 0, nonstdtime = 0;
1171 __u8 flags;
1172 j = *++cp; /* get length */
1173 i = *++cp; /* and pointer */
1174 if (i > j)
1175 i = j;
1176 i -= 5;
1177 if (i <= 0)
1178 break;
1179 flags = *++cp;
1180 printf("\nTS: ");
1181 cp++;
1182 for (;;) {
1183 long l;
1184
1185 if ((flags&0xF) != IPOPT_TS_TSONLY) {
1186 __u32 address;
1187 memcpy(&address, cp, 4);
1188 cp += 4;
1189 if (address == 0)
1190 printf("\t0.0.0.0");
1191 else
1192 printf("\t%s", pr_addr(address));
1193 i -= 4;
1194 if (i <= 0)
1195 break;
1196 }
1197 l = *cp++;
1198 l = (l<<8) + *cp++;
1199 l = (l<<8) + *cp++;
1200 l = (l<<8) + *cp++;
1201
1202 if (l & 0x80000000) {
1203 if (nonstdtime==0)
1204 printf("\t%ld absolute not-standard", l&0x7fffffff);
1205 else
1206 printf("\t%ld not-standard", (l&0x7fffffff) - nonstdtime);
1207 nonstdtime = l&0x7fffffff;
1208 } else {
1209 if (stdtime==0)
1210 printf("\t%ld absolute", l);
1211 else
1212 printf("\t%ld", l - stdtime);
1213 stdtime = l;
1214 }
1215 i -= 4;
1216 putchar('\n');
1217 if (i <= 0)
1218 break;
1219 }
1220 if (flags>>4)
1221 printf("Unrecorded hops: %d\n", flags>>4);
1222 break;
1223 }
1224 default:
1225 printf("\nunknown option %x", *cp);
1226 break;
1227 }
1228 totlen -= optlen;
1229 optptr += optlen;
1230 }
1231}
1232
1233
1234/*
1235 * pr_iph --
1236 * Print an IP header with options.
1237 */
1238void pr_iph(struct iphdr *ip)
1239{
1240 int hlen;
1241 u_char *cp;
1242
1243 hlen = ip->ihl << 2;
1244 cp = (u_char *)ip + 20; /* point to options */
1245
1246 printf("Vr HL TOS Len ID Flg off TTL Pro cks Src Dst Data\n");
1247 printf(" %1x %1x %02x %04x %04x",
1248 ip->version, ip->ihl, ip->tos, ip->tot_len, ip->id);
1249 printf(" %1x %04x", ((ip->frag_off) & 0xe000) >> 13,
1250 (ip->frag_off) & 0x1fff);
1251 printf(" %02x %02x %04x", ip->ttl, ip->protocol, ip->check);
1252 printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->saddr));
1253 printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->daddr));
1254 printf("\n");
1255 pr_options(cp, hlen);
1256}
1257
1258/*
1259 * pr_addr --
1260 * Return an ascii host address as a dotted quad and optionally with
1261 * a hostname.
1262 */
1263char *
1264pr_addr(__u32 addr)
1265{
1266 struct hostent *hp;
1267 static char buf[4096];
1268
1269 in_pr_addr = !setjmp(pr_addr_jmp);
1270
1271 if (exiting || (options & F_NUMERIC) ||
1272 !(hp = gethostbyaddr((char *)&addr, 4, AF_INET)))
1273 sprintf(buf, "%s", inet_ntoa(*(struct in_addr *)&addr));
1274 else {
1275 char *s;
1276#if USE_IDN
1277 if (idna_to_unicode_lzlz(hp->h_name, &s, 0) != IDNA_SUCCESS)
1278 s = NULL;
1279#else
1280 s = NULL;
1281#endif
1282 snprintf(buf, sizeof(buf), "%s (%s)", s ? s : hp->h_name,
1283 inet_ntoa(*(struct in_addr *)&addr));
1284#if USE_IDN
1285 free(s);
1286#endif
1287 }
1288
1289 in_pr_addr = 0;
1290
1291 return(buf);
1292}
1293
1294
1295/* Set Type of Service (TOS) and other Quality of Service relating bits */
1296int parsetos(char *str)
1297{
1298 const char *cp;
1299 int tos;
1300 char *ep;
1301
1302 /* handle both hex and decimal values */
1303 if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) {
1304 cp = str + 2;
1305 tos = (int)strtol(cp, &ep, 16);
1306 } else
1307 tos = (int)strtol(str, &ep, 10);
1308
1309 /* doesn't look like decimal or hex, eh? */
1310 if (*ep != '\0') {
1311 fprintf(stderr, "ping: \"%s\" bad value for TOS\n", str);
1312 exit(2);
1313 }
1314
1315 if (tos > TOS_MAX) {
1316 fprintf(stderr, "ping: the decimal value of TOS bits must be 0-254 (or zero)\n");
1317 exit(2);
1318 }
1319 return(tos);
1320}
1321
1322#include <linux/filter.h>
1323
1324void install_filter(void)
1325{
1326 static int once;
1327 static struct sock_filter insns[] = {
1328 BPF_STMT(BPF_LDX|BPF_B|BPF_MSH, 0), /* Skip IP header. F..g BSD... Look into ping6. */
1329 BPF_STMT(BPF_LD|BPF_H|BPF_IND, 4), /* Load icmp echo ident */
1330 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0xAAAA, 0, 1), /* Ours? */
1331 BPF_STMT(BPF_RET|BPF_K, ~0U), /* Yes, it passes. */
1332 BPF_STMT(BPF_LD|BPF_B|BPF_IND, 0), /* Load icmp type */
1333 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, ICMP_ECHOREPLY, 1, 0), /* Echo? */
1334 BPF_STMT(BPF_RET|BPF_K, 0xFFFFFFF), /* No. It passes. */
1335 BPF_STMT(BPF_RET|BPF_K, 0) /* Echo with wrong ident. Reject. */
1336 };
1337 static struct sock_fprog filter = {
1338 sizeof insns / sizeof(insns[0]),
1339 insns
1340 };
1341
1342 if (once)
1343 return;
1344 once = 1;
1345
1346 /* Patch bpflet for current identifier. */
1347 insns[2] = (struct sock_filter)BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(ident), 0, 1);
1348
1349 if (setsockopt(icmp_sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)))
1350 perror("WARNING: failed to install socket filter\n");
1351}
1352
1353#define USAGE_NEWLINE "\n "
1354
1355void usage(void)
1356{
1357 fprintf(stderr,
1358 "Usage: ping"
1359 " [-"
1360 "aAbBdDfhLnOqrRUvV"
1361 "]"
1362 " [-c count]"
1363 " [-i interval]"
1364 " [-I interface]"
1365 USAGE_NEWLINE
1366 " [-m mark]"
1367 " [-M pmtudisc_option]"
1368 " [-l preload]"
1369 " [-p pattern]"
1370 " [-Q tos]"
1371 USAGE_NEWLINE
1372 " [-s packetsize]"
1373 " [-S sndbuf]"
1374 " [-t ttl]"
1375 " [-T timestamp_option]"
1376 USAGE_NEWLINE
1377 " [-w deadline]"
1378 " [-W timeout]"
1379 " [hop1 ...] destination"
1380 "\n"
1381 );
1382 exit(2);
1383}