1 /*
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
38 char 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 <linux/icmp.h>
65 #include <sched.h>
66
67 #define bzero(b,sz) memset(b, 0, sz)
68
69 /* PING COMMON */
70
71 int options;
72
73 int sndbuf;
74 int ttl;
75 int rtt;
76 int rtt_addend;
77 __u16 acked;
78
79 int mx_dup_ck = MAX_DUP_CHK;
80 char rcvd_tbl[MAX_DUP_CHK / 8];
81
82
83 /* counters */
84 long npackets; /* max packets to transmit */
85 long nreceived; /* # of packets we got back */
86 long nrepeats; /* number of duplicates */
87 long ntransmitted; /* sequence # for outbound packets = #sent */
88 long nchecksum; /* replies with bad checksum */
89 long nerrors; /* icmp errors */
90 int interval = 1000; /* interval between packets (msec) */
91 int preload;
92 int deadline = 0; /* time to die */
93 int lingertime = MAXWAIT*1000;
94 struct timeval start_time, cur_time;
95 volatile int exiting;
96 volatile int status_snapshot;
97 int confirm = 0;
98
99 /* Stupid workarounds for bugs/missing functionality in older linuces.
100 * confirm_flag fixes refusing service of kernels without MSG_CONFIRM.
101 * i.e. for linux-2.2 */
102 int confirm_flag = MSG_CONFIRM;
103 /* And this is workaround for bug in IP_RECVERR on raw sockets which is present
104 * in linux-2.2.[0-19], linux-2.4.[0-7] */
105 int working_recverr;
106
107 /* timing */
108 int timing; /* flag to do timing */
109 long tmin = LONG_MAX; /* minimum round trip time */
110 long tmax; /* maximum round trip time */
111 /* Message for rpm maintainers: have _shame_. If you want
112 * to fix something send the patch to me for sanity checking.
113 * "sparcfix" patch is a complete non-sense, apparenly the person
114 * prepared it was stoned.
115 */
116 long long tsum; /* sum of all times, for doing average */
117 long long tsum2;
118 int pipesize = -1;
119
120 int datalen = DEFDATALEN;
121
122 char *hostname;
123 int uid;
124 int ident; /* process id to identify our packets */
125
126 static int screen_width = INT_MAX;
127
128 /* Fills all the outpack, excluding ICMP header, but _including_
129 * timestamp area with supplied pattern.
130 */
fill(char * patp)131 static void fill(char *patp)
132 {
133 int ii, jj, kk;
134 int pat[16];
135 char *cp;
136 char *bp = outpack+8;
137
138 for (cp = patp; *cp; cp++) {
139 if (!isxdigit(*cp)) {
140 fprintf(stderr,
141 "ping: patterns must be specified as hex digits.\n");
142 exit(2);
143 }
144 }
145 ii = sscanf(patp,
146 "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
147 &pat[0], &pat[1], &pat[2], &pat[3], &pat[4], &pat[5], &pat[6],
148 &pat[7], &pat[8], &pat[9], &pat[10], &pat[11], &pat[12],
149 &pat[13], &pat[14], &pat[15]);
150
151 if (ii > 0) {
152 for (kk = 0; kk <= maxpacket - (8 + ii); kk += ii)
153 for (jj = 0; jj < ii; ++jj)
154 bp[jj + kk] = pat[jj];
155 }
156 if (!(options & F_QUIET)) {
157 printf("PATTERN: 0x");
158 for (jj = 0; jj < ii; ++jj)
159 printf("%02x", bp[jj] & 0xFF);
160 printf("\n");
161 }
162 }
163
common_options(int ch)164 void common_options(int ch)
165 {
166 switch(ch) {
167 case 'a':
168 options |= F_AUDIBLE;
169 break;
170 case 'A':
171 options |= F_ADAPTIVE;
172 break;
173 case 'c':
174 npackets = atoi(optarg);
175 if (npackets <= 0) {
176 fprintf(stderr, "ping: bad number of packets to transmit.\n");
177 exit(2);
178 }
179 break;
180 case 'd':
181 options |= F_SO_DEBUG;
182 break;
183 case 'f':
184 options |= F_FLOOD;
185 //setbuf(stdout, (char *)NULL);
186 break;
187 case 'i': /* wait between sending packets */
188 {
189 if (strchr(optarg, '.')) {
190 float t;
191 if (sscanf(optarg, "%f", &t) != 1) {
192 fprintf(stderr, "ping: bad timing interval.\n");
193 exit(2);
194 }
195 interval = (int)(t*1000);
196 } else if (sscanf(optarg, "%d", &interval) == 1) {
197 interval *= 1000;
198 } else {
199 fprintf(stderr, "ping: bad timing interval.\n");
200 exit(2);
201 }
202
203 if (interval < 0) {
204 fprintf(stderr, "ping: bad timing interval.\n");
205 exit(2);
206 }
207 options |= F_INTERVAL;
208 break;
209 }
210 case 'w':
211 deadline = atoi(optarg);
212 if (deadline < 0) {
213 fprintf(stderr, "ping: bad wait time.\n");
214 exit(2);
215 }
216 break;
217 case 'l':
218 preload = atoi(optarg);
219 if (preload <= 0) {
220 fprintf(stderr, "ping: bad preload value, should be 1..%d\n", mx_dup_ck);
221 exit(2);
222 }
223 if (preload > mx_dup_ck)
224 preload = mx_dup_ck;
225 if (uid && preload > 3) {
226 fprintf(stderr, "ping: cannot set preload to value > 3\n");
227 exit(2);
228 }
229 break;
230 case 'S':
231 sndbuf = atoi(optarg);
232 if (sndbuf <= 0) {
233 fprintf(stderr, "ping: bad sndbuf value.\n");
234 exit(2);
235 }
236 break;
237 case 'n':
238 options |= F_NUMERIC;
239 break;
240 case 'p': /* fill buffer with user pattern */
241 options |= F_PINGFILLED;
242 fill(optarg);
243 break;
244 case 'q':
245 options |= F_QUIET;
246 break;
247 case 'r':
248 options |= F_SO_DONTROUTE;
249 break;
250 case 's': /* size of packet to send */
251 datalen = atoi(optarg);
252 if (datalen < 0) {
253 fprintf(stderr, "ping: illegal negative packet size %d.\n", datalen);
254 exit(2);
255 }
256 break;
257 case 'v':
258 options |= F_VERBOSE;
259 break;
260 case 'L':
261 options |= F_NOLOOP;
262 break;
263 case 't':
264 options |= F_TTL;
265 ttl = atoi(optarg);
266 if (ttl < 0 || ttl > 255) {
267 fprintf(stderr, "ping: ttl %u out of range\n", ttl);
268 exit(2);
269 }
270 break;
271 case 'U':
272 options |= F_LATENCY;
273 break;
274 case 'B':
275 options |= F_STRICTSOURCE;
276 break;
277 case 'W':
278 lingertime = atoi(optarg);
279 if (lingertime < 0 || lingertime > INT_MAX/1000000) {
280 fprintf(stderr, "ping: bad linger time.\n");
281 exit(2);
282 }
283 lingertime *= 1000;
284 break;
285 case 'V':
286 printf("ping utility, iputils-ss\n");
287 exit(0);
288 default:
289 abort();
290 }
291 }
292
293
sigexit(int signo)294 static void sigexit(int signo)
295 {
296 exiting = 1;
297 }
298
sigstatus(int signo)299 static void sigstatus(int signo)
300 {
301 status_snapshot = 1;
302 }
303
304
__schedule_exit(int next)305 int __schedule_exit(int next)
306 {
307 static unsigned long waittime;
308 struct itimerval it;
309
310 if (waittime)
311 return next;
312
313 if (nreceived) {
314 waittime = 2 * tmax;
315 if (waittime < 1000*interval)
316 waittime = 1000*interval;
317 } else
318 waittime = lingertime*1000;
319
320 if (next < 0 || next < waittime/1000)
321 next = waittime/1000;
322
323 it.it_interval.tv_sec = 0;
324 it.it_interval.tv_usec = 0;
325 it.it_value.tv_sec = waittime/1000000;
326 it.it_value.tv_usec = waittime%1000000;
327 setitimer(ITIMER_REAL, &it, NULL);
328 return next;
329 }
330
update_interval(void)331 static inline void update_interval(void)
332 {
333 int est = rtt ? rtt/8 : interval*1000;
334
335 interval = (est+rtt_addend+500)/1000;
336 if (uid && interval < MINUSERINTERVAL)
337 interval = MINUSERINTERVAL;
338 }
339
340 /*
341 * pinger --
342 * Compose and transmit an ICMP ECHO REQUEST packet. The IP packet
343 * will be added on by the kernel. The ID field is our UNIX process ID,
344 * and the sequence number is an ascending integer. The first 8 bytes
345 * of the data portion are used to hold a UNIX "timeval" struct in VAX
346 * byte-order, to compute the round-trip time.
347 */
pinger(void)348 int pinger(void)
349 {
350 static int oom_count;
351 static int tokens;
352 int i;
353
354 /* Have we already sent enough? If we have, return an arbitrary positive value. */
355 if (exiting || (npackets && ntransmitted >= npackets && !deadline))
356 return 1000;
357
358 /* Check that packets < rate*time + preload */
359 if (cur_time.tv_sec == 0) {
360 gettimeofday(&cur_time, NULL);
361 tokens = interval*(preload-1);
362 } else {
363 long ntokens;
364 struct timeval tv;
365
366 gettimeofday(&tv, NULL);
367 ntokens = (tv.tv_sec - cur_time.tv_sec)*1000 +
368 (tv.tv_usec-cur_time.tv_usec)/1000;
369 if (!interval) {
370 /* Case of unlimited flood is special;
371 * if we see no reply, they are limited to 100pps */
372 if (ntokens < MININTERVAL && in_flight() >= preload)
373 return MININTERVAL-ntokens;
374 }
375 ntokens += tokens;
376 if (ntokens > interval*preload)
377 ntokens = interval*preload;
378 if (ntokens < interval)
379 return interval - ntokens;
380
381 cur_time = tv;
382 tokens = ntokens - interval;
383 }
384
385 resend:
386 i = send_probe();
387
388 if (i == 0) {
389 oom_count = 0;
390 advance_ntransmitted();
391 if (!(options & F_QUIET) && (options & F_FLOOD)) {
392 /* Very silly, but without this output with
393 * high preload or pipe size is very confusing. */
394 if ((preload < screen_width && pipesize < screen_width) ||
395 in_flight() < screen_width)
396 write(STDOUT_FILENO, ".", 1);
397 }
398 return interval - tokens;
399 }
400
401 /* And handle various errors... */
402 if (i > 0) {
403 /* Apparently, it is some fatal bug. */
404 abort();
405 } else if (errno == ENOBUFS || errno == ENOMEM) {
406 int nores_interval;
407
408 /* Device queue overflow or OOM. Packet is not sent. */
409 tokens = 0;
410 /* Slowdown. This works only in adaptive mode (option -A) */
411 rtt_addend += (rtt < 8*50000 ? rtt/8 : 50000);
412 if (options&F_ADAPTIVE)
413 update_interval();
414 nores_interval = SCHINT(interval/2);
415 if (nores_interval > 500)
416 nores_interval = 500;
417 oom_count++;
418 if (oom_count*nores_interval < lingertime)
419 return nores_interval;
420 i = 0;
421 /* Fall to hard error. It is to avoid complete deadlock
422 * on stuck output device even when dealine was not requested.
423 * Expected timings are screwed up in any case, but we will
424 * exit some day. :-) */
425 } else if (errno == EAGAIN) {
426 /* Socket buffer is full. */
427 tokens += interval;
428 return MININTERVAL;
429 } else {
430 if ((i=receive_error_msg()) > 0) {
431 /* An ICMP error arrived. */
432 tokens += interval;
433 return MININTERVAL;
434 }
435 /* Compatibility with old linuces. */
436 if (i == 0 && confirm_flag && errno == EINVAL) {
437 confirm_flag = 0;
438 errno = 0;
439 }
440 if (!errno)
441 goto resend;
442 }
443
444 /* Hard local error. Pretend we sent packet. */
445 advance_ntransmitted();
446
447 if (i == 0 && !(options & F_QUIET)) {
448 if (options & F_FLOOD)
449 write(STDOUT_FILENO, "E", 1);
450 else
451 perror("ping: sendmsg");
452 }
453 tokens = 0;
454 return SCHINT(interval);
455 }
456
457 /* Set socket buffers, "alloc" is an estimate of memory taken by single packet. */
458
sock_setbufs(int icmp_sock,int alloc)459 void sock_setbufs(int icmp_sock, int alloc)
460 {
461 int rcvbuf, hold;
462 int tmplen = sizeof(hold);
463
464 if (!sndbuf)
465 sndbuf = alloc;
466 setsockopt(icmp_sock, SOL_SOCKET, SO_SNDBUF, (char *)&sndbuf, sizeof(sndbuf));
467
468 rcvbuf = hold = alloc * preload;
469 if (hold < 65536)
470 hold = 65536;
471 setsockopt(icmp_sock, SOL_SOCKET, SO_RCVBUF, (char *)&hold, sizeof(hold));
472 if (getsockopt(icmp_sock, SOL_SOCKET, SO_RCVBUF, (char *)&hold, &tmplen) == 0) {
473 if (hold < rcvbuf)
474 fprintf(stderr, "WARNING: probably, rcvbuf is not enough to hold preload.\n");
475 }
476 }
477
478 /* Protocol independent setup and parameter checks. */
479
setup(int icmp_sock)480 void setup(int icmp_sock)
481 {
482 int hold;
483 struct timeval tv;
484
485 if ((options & F_FLOOD) && !(options & F_INTERVAL))
486 interval = 0;
487
488 if (uid && interval < MINUSERINTERVAL) {
489 fprintf(stderr, "ping: cannot flood; minimal interval, allowed for user, is %dms\n", MINUSERINTERVAL);
490 exit(2);
491 }
492
493 if (interval >= INT_MAX/preload) {
494 fprintf(stderr, "ping: illegal preload and/or interval\n");
495 exit(2);
496 }
497
498 hold = 1;
499 if (options & F_SO_DEBUG)
500 setsockopt(icmp_sock, SOL_SOCKET, SO_DEBUG, (char *)&hold, sizeof(hold));
501 if (options & F_SO_DONTROUTE)
502 setsockopt(icmp_sock, SOL_SOCKET, SO_DONTROUTE, (char *)&hold, sizeof(hold));
503
504 #ifdef SO_TIMESTAMP
505 if (!(options&F_LATENCY)) {
506 int on = 1;
507 if (setsockopt(icmp_sock, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on)))
508 fprintf(stderr, "Warning: no SO_TIMESTAMP support, falling back to SIOCGSTAMP\n");
509 }
510 #endif
511
512 /* Set some SNDTIMEO to prevent blocking forever
513 * on sends, when device is too slow or stalls. Just put limit
514 * of one second, or "interval", if it is less.
515 */
516 tv.tv_sec = 1;
517 tv.tv_usec = 0;
518 if (interval < 1000) {
519 tv.tv_sec = 0;
520 tv.tv_usec = 1000 * SCHINT(interval);
521 }
522 setsockopt(icmp_sock, SOL_SOCKET, SO_SNDTIMEO, (char*)&tv, sizeof(tv));
523
524 /* Set RCVTIMEO to "interval". Note, it is just an optimization
525 * allowing to avoid redundant poll(). */
526 tv.tv_sec = SCHINT(interval)/1000;
527 tv.tv_usec = 1000*(SCHINT(interval)%1000);
528 if (setsockopt(icmp_sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(tv)))
529 options |= F_FLOOD_POLL;
530
531 if (!(options & F_PINGFILLED)) {
532 int i;
533 char *p = outpack+8;
534
535 /* Do not forget about case of small datalen,
536 * fill timestamp area too!
537 */
538 for (i = 0; i < datalen; ++i)
539 *p++ = i;
540 }
541
542 ident = getpid() & 0xFFFF;
543
544 set_signal(SIGINT, sigexit);
545 set_signal(SIGALRM, sigexit);
546 set_signal(SIGQUIT, sigstatus);
547
548 gettimeofday(&start_time, NULL);
549
550 if (deadline) {
551 struct itimerval it;
552
553 it.it_interval.tv_sec = 0;
554 it.it_interval.tv_usec = 0;
555 it.it_value.tv_sec = deadline;
556 it.it_value.tv_usec = 0;
557 setitimer(ITIMER_REAL, &it, NULL);
558 }
559
560 #if 0
561 if (isatty(STDOUT_FILENO)) {
562 struct winsize w;
563
564 if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) != -1) {
565 if (w.ws_col > 0)
566 screen_width = w.ws_col;
567 }
568 }
569 #endif
570 }
571
main_loop(int icmp_sock,__u8 * packet,int packlen)572 void main_loop(int icmp_sock, __u8 *packet, int packlen)
573 {
574 char addrbuf[128];
575 char ans_data[4096];
576 struct iovec iov;
577 struct msghdr msg;
578 struct cmsghdr *c;
579 int cc;
580 int next;
581 int polling;
582
583 iov.iov_base = (char *)packet;
584
585 for (;;) {
586 /* Check exit conditions. */
587 if (exiting)
588 break;
589 if (npackets && nreceived + nerrors >= npackets)
590 break;
591 if (deadline && nerrors)
592 break;
593 /* Check for and do special actions. */
594 if (status_snapshot)
595 status();
596
597 /* Send probes scheduled to this time. */
598 do {
599 next = pinger();
600 next = schedule_exit(next);
601 } while (next <= 0);
602
603 /* "next" is time to send next probe, if positive.
604 * If next<=0 send now or as soon as possible. */
605
606 /* Technical part. Looks wicked. Could be dropped,
607 * if everyone used the newest kernel. :-)
608 * Its purpose is:
609 * 1. Provide intervals less than resolution of scheduler.
610 * Solution: spinning.
611 * 2. Avoid use of poll(), when recvmsg() can provide
612 * timed waiting (SO_RCVTIMEO). */
613 polling = 0;
614 if ((options & (F_ADAPTIVE|F_FLOOD_POLL)) || next<SCHINT(interval)) {
615 int recv_expected = in_flight();
616
617 /* If we are here, recvmsg() is unable to wait for
618 * required timeout. */
619 if (1000*next <= 1000000/(int)HZ) {
620 /* Very short timeout... So, if we wait for
621 * something, we sleep for MININTERVAL.
622 * Otherwise, spin! */
623 if (recv_expected) {
624 next = MININTERVAL;
625 } else {
626 next = 0;
627 /* When spinning, no reasons to poll.
628 * Use nonblocking recvmsg() instead. */
629 polling = MSG_DONTWAIT;
630 /* But yield yet. */
631 sched_yield();
632 }
633 }
634
635 if (!polling &&
636 ((options & (F_ADAPTIVE|F_FLOOD_POLL)) || interval)) {
637 struct pollfd pset;
638 pset.fd = icmp_sock;
639 pset.events = POLLIN|POLLERR;
640 pset.revents = 0;
641 if (poll(&pset, 1, next) < 1 ||
642 !(pset.revents&(POLLIN|POLLERR)))
643 continue;
644 polling = MSG_DONTWAIT;
645 }
646 }
647
648 for (;;) {
649 struct timeval *recv_timep = NULL;
650 struct timeval recv_time;
651 int not_ours = 0; /* Raw socket can receive messages
652 * destined to other running pings. */
653
654 iov.iov_len = packlen;
655 msg.msg_name = addrbuf;
656 msg.msg_namelen = sizeof(addrbuf);
657 msg.msg_iov = &iov;
658 msg.msg_iovlen = 1;
659 msg.msg_control = ans_data;
660 msg.msg_controllen = sizeof(ans_data);
661
662 cc = recvmsg(icmp_sock, &msg, polling);
663 polling = MSG_DONTWAIT;
664
665 if (cc < 0) {
666 if (errno == EAGAIN || errno == EINTR)
667 break;
668 if (!receive_error_msg()) {
669 if (errno) {
670 perror("ping: recvmsg");
671 break;
672 }
673 not_ours = 1;
674 }
675 } else {
676
677 #ifdef SO_TIMESTAMP
678 for (c = CMSG_FIRSTHDR(&msg); c; c = CMSG_NXTHDR(&msg, c)) {
679 if (c->cmsg_level != SOL_SOCKET ||
680 c->cmsg_type != SO_TIMESTAMP)
681 continue;
682 if (c->cmsg_len < CMSG_LEN(sizeof(struct timeval)))
683 continue;
684 recv_timep = (struct timeval*)CMSG_DATA(c);
685 }
686 #endif
687
688 if ((options&F_LATENCY) || recv_timep == NULL) {
689 if ((options&F_LATENCY) ||
690 ioctl(icmp_sock, SIOCGSTAMP, &recv_time))
691 gettimeofday(&recv_time, NULL);
692 recv_timep = &recv_time;
693 }
694
695 not_ours = parse_reply(&msg, cc, addrbuf, recv_timep);
696 }
697
698 /* See? ... someone runs another ping on this host. */
699 if (not_ours)
700 install_filter();
701
702 /* If nothing is in flight, "break" returns us to pinger. */
703 if (in_flight() == 0)
704 break;
705
706 /* Otherwise, try to recvmsg() again. recvmsg()
707 * is nonblocking after the first iteration, so that
708 * if nothing is queued, it will receive EAGAIN
709 * and return to pinger. */
710 }
711 }
712 finish();
713 }
714
gather_statistics(__u8 * ptr,int cc,__u16 seq,int hops,int csfailed,struct timeval * tv,char * from)715 int gather_statistics(__u8 *ptr, int cc, __u16 seq, int hops,
716 int csfailed, struct timeval *tv, char *from)
717 {
718 int dupflag = 0;
719 long triptime = 0;
720
721 ++nreceived;
722 if (!csfailed)
723 acknowledge(seq);
724
725 if (timing && cc >= 8+sizeof(struct timeval)) {
726 struct timeval tmp_tv;
727 memcpy(&tmp_tv, ptr, sizeof(tmp_tv));
728
729 restamp:
730 tvsub(tv, &tmp_tv);
731 triptime = tv->tv_sec * 1000000 + tv->tv_usec;
732 if (triptime < 0) {
733 fprintf(stderr, "Warning: time of day goes back (%ldus), taking countermeasures.\n", triptime);
734 triptime = 0;
735 if (!(options & F_LATENCY)) {
736 gettimeofday(tv, NULL);
737 options |= F_LATENCY;
738 goto restamp;
739 }
740 }
741 if (!csfailed) {
742 tsum += triptime;
743 tsum2 += (long long)triptime * (long long)triptime;
744 if (triptime < tmin)
745 tmin = triptime;
746 if (triptime > tmax)
747 tmax = triptime;
748 if (!rtt)
749 rtt = triptime*8;
750 else
751 rtt += triptime-rtt/8;
752 if (options&F_ADAPTIVE)
753 update_interval();
754 }
755 }
756
757 if (csfailed) {
758 ++nchecksum;
759 --nreceived;
760 } else if (TST(seq % mx_dup_ck)) {
761 ++nrepeats;
762 --nreceived;
763 dupflag = 1;
764 } else {
765 SET(seq % mx_dup_ck);
766 dupflag = 0;
767 }
768 confirm = confirm_flag;
769
770 if (options & F_QUIET)
771 return 1;
772
773 if (options & F_FLOOD) {
774 if (!csfailed)
775 write(STDOUT_FILENO, "\b \b", 3);
776 else
777 write(STDOUT_FILENO, "\bC", 1);
778 } else {
779 int i;
780 __u8 *cp, *dp;
781 printf("%d bytes from %s: icmp_seq=%u", cc, from, seq);
782
783 if (hops >= 0)
784 printf(" ttl=%d", hops);
785
786 if (cc < datalen+8) {
787 printf(" (truncated)\n");
788 return 1;
789 }
790 if (timing) {
791 if (triptime >= 100000)
792 printf(" time=%ld ms", triptime/1000);
793 else if (triptime >= 10000)
794 printf(" time=%ld.%01ld ms", triptime/1000,
795 (triptime%1000)/100);
796 else if (triptime >= 1000)
797 printf(" time=%ld.%02ld ms", triptime/1000,
798 (triptime%1000)/10);
799 else
800 printf(" time=%ld.%03ld ms", triptime/1000,
801 triptime%1000);
802 }
803 if (dupflag)
804 printf(" (DUP!)");
805 if (csfailed)
806 printf(" (BAD CHECKSUM!)");
807
808 /* check the data */
809 cp = ((u_char*)ptr) + sizeof(struct timeval);
810 dp = &outpack[8 + sizeof(struct timeval)];
811 for (i = sizeof(struct timeval); i < datalen; ++i, ++cp, ++dp) {
812 if (*cp != *dp) {
813 printf("\nwrong data byte #%d should be 0x%x but was 0x%x",
814 i, *dp, *cp);
815 cp = (u_char*)ptr + sizeof(struct timeval);
816 for (i = sizeof(struct timeval); i < datalen; ++i, ++cp) {
817 if ((i % 32) == sizeof(struct timeval))
818 printf("\n#%d\t", i);
819 printf("%x ", *cp);
820 }
821 break;
822 }
823 }
824 }
825 return 0;
826 }
827
llsqrt(long long a)828 static long llsqrt(long long a)
829 {
830 long long prev = ~((long long)1 << 63);
831 long long x = a;
832
833 if (x > 0) {
834 while (x < prev) {
835 prev = x;
836 x = (x+(a/x))/2;
837 }
838 }
839
840 return (long)x;
841 }
842
843 /*
844 * finish --
845 * Print out statistics, and give up.
846 */
finish(void)847 void finish(void)
848 {
849 struct timeval tv = cur_time;
850
851 tvsub(&tv, &start_time);
852
853 putchar('\n');
854 fflush(stdout);
855 printf("--- %s ping statistics ---\n", hostname);
856 printf("%ld packets transmitted, ", ntransmitted);
857 printf("%ld received", nreceived);
858 if (nrepeats)
859 printf(", +%ld duplicates", nrepeats);
860 if (nchecksum)
861 printf(", +%ld corrupted", nchecksum);
862 if (nerrors)
863 printf(", +%ld errors", nerrors);
864 if (ntransmitted) {
865 printf(", %d%% packet loss",
866 (int) ((((long long)(ntransmitted - nreceived)) * 100) /
867 ntransmitted));
868 printf(", time %ldms", 1000*tv.tv_sec+tv.tv_usec/1000);
869 }
870 putchar('\n');
871
872 if (nreceived && timing) {
873 long tmdev;
874
875 tsum /= nreceived + nrepeats;
876 tsum2 /= nreceived + nrepeats;
877 tmdev = llsqrt(tsum2 - tsum * tsum);
878
879 printf("rtt min/avg/max/mdev = %ld.%03ld/%lu.%03ld/%ld.%03ld/%ld.%03ld ms",
880 tmin/1000, tmin%1000,
881 (unsigned long)(tsum/1000), (long)(tsum%1000),
882 tmax/1000, tmax%1000,
883 tmdev/1000, tmdev%1000
884 );
885 }
886 if (pipesize > 1)
887 printf(", pipe %d", pipesize);
888 if (ntransmitted > 1 && (!interval || (options&(F_FLOOD|F_ADAPTIVE)))) {
889 int ipg = (1000000*(long long)tv.tv_sec+tv.tv_usec)/(ntransmitted-1);
890 printf(", ipg/ewma %d.%03d/%d.%03d ms",
891 ipg/1000, ipg%1000, rtt/8000, (rtt/8)%1000);
892 }
893 putchar('\n');
894 exit(!nreceived || (deadline && nreceived < npackets));
895 }
896
897
status(void)898 void status(void)
899 {
900 int loss = 0;
901 long tavg = 0;
902
903 status_snapshot = 0;
904
905 if (ntransmitted)
906 loss = (((long long)(ntransmitted - nreceived)) * 100) / ntransmitted;
907
908 fprintf(stderr, "\r%ld/%ld packets, %d%% loss", ntransmitted, nreceived, loss);
909
910 if (nreceived && timing) {
911 tavg = tsum / (nreceived + nrepeats);
912
913 fprintf(stderr, ", min/avg/ewma/max = %ld.%03ld/%lu.%03ld/%d.%03d/%ld.%03ld ms",
914 tmin/1000, tmin%1000,
915 tavg/1000, tavg%1000,
916 rtt/8000, (rtt/8)%1000,
917 tmax/1000, tmax%1000
918 );
919 }
920 fprintf(stderr, "\n");
921 }
922
923 /* PING COMMON */
924
925 #define MAXIPLEN 60
926 #define MAXICMPLEN 76
927 #define NROUTES 9 /* number of record route slots */
928 #define TOS_MAX 255 /* 8-bit TOS field */
929
930
931 static int ts_type;
932 static int nroute = 0;
933 static __u32 route[10];
934
935
936
937 struct sockaddr_in whereto; /* who to ping */
938 int optlen = 0;
939 int settos = 0; /* Set TOS, Precendence or other QOS options */
940 int icmp_sock; /* socket file descriptor */
941 u_char outpack[0x10000];
942 int maxpacket = sizeof(outpack);
943
944 static int broadcast_pings = 0;
945
946 static char *pr_addr(__u32);
947 static void pr_options(unsigned char * cp, int hlen);
948 static void pr_iph(struct iphdr *ip);
949 static void usage(void) __attribute__((noreturn));
950 static u_short in_cksum(const u_short *addr, int len, u_short salt);
951 static void pr_icmph(__u8 type, __u8 code, __u32 info, struct icmphdr *icp);
952 static int parsetos(char *str);
953
954 static struct {
955 struct cmsghdr cm;
956 struct in_pktinfo ipi;
957 } cmsg = { {sizeof(struct cmsghdr) + sizeof(struct in_pktinfo), SOL_IP, IP_PKTINFO},
958 {0, }};
959 int cmsg_len;
960
961 struct sockaddr_in source;
962 char *device;
963 int pmtudisc = -1;
964
receive_error_msg()965 int receive_error_msg()
966 {
967 int res;
968 char cbuf[512];
969 struct iovec iov;
970 struct msghdr msg;
971 struct cmsghdr *cmsg;
972 struct sock_extended_err *e;
973 struct icmphdr icmph;
974 struct sockaddr_in target;
975 int net_errors = 0;
976 int local_errors = 0;
977 int saved_errno = errno;
978
979 iov.iov_base = &icmph;
980 iov.iov_len = sizeof(icmph);
981 msg.msg_name = (void*)⌖
982 msg.msg_namelen = sizeof(target);
983 msg.msg_iov = &iov;
984 msg.msg_iovlen = 1;
985 msg.msg_flags = 0;
986 msg.msg_control = cbuf;
987 msg.msg_controllen = sizeof(cbuf);
988
989 res = recvmsg(icmp_sock, &msg, MSG_ERRQUEUE|MSG_DONTWAIT);
990 if (res < 0)
991 goto out;
992
993 e = NULL;
994 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
995 if (cmsg->cmsg_level == SOL_IP) {
996 if (cmsg->cmsg_type == IP_RECVERR)
997 e = (struct sock_extended_err *)CMSG_DATA(cmsg);
998 }
999 }
1000 if (e == NULL)
1001 abort();
1002
1003 if (e->ee_origin == SO_EE_ORIGIN_LOCAL) {
1004 local_errors++;
1005 if (options & F_QUIET)
1006 goto out;
1007 if (options & F_FLOOD)
1008 write(STDOUT_FILENO, "E", 1);
1009 else if (e->ee_errno != EMSGSIZE)
1010 fprintf(stderr, "ping: local error: %s\n", strerror(e->ee_errno));
1011 else
1012 fprintf(stderr, "ping: local error: Message too long, mtu=%u\n", e->ee_info);
1013 nerrors++;
1014 } else if (e->ee_origin == SO_EE_ORIGIN_ICMP) {
1015 struct sockaddr_in *sin = (struct sockaddr_in*)(e+1);
1016
1017 if (res < sizeof(icmph) ||
1018 target.sin_addr.s_addr != whereto.sin_addr.s_addr ||
1019 icmph.type != ICMP_ECHO ||
1020 icmph.un.echo.id != ident) {
1021 /* Not our error, not an error at all. Clear. */
1022 saved_errno = 0;
1023 goto out;
1024 }
1025
1026 acknowledge(ntohs(icmph.un.echo.sequence));
1027
1028 if (!working_recverr) {
1029 struct icmp_filter filt;
1030 working_recverr = 1;
1031 /* OK, it works. Add stronger filter. */
1032 filt.data = ~((1<<ICMP_SOURCE_QUENCH)|
1033 (1<<ICMP_REDIRECT)|
1034 (1<<ICMP_ECHOREPLY));
1035 if (setsockopt(icmp_sock, SOL_RAW, ICMP_FILTER, (char*)&filt, sizeof(filt)) == -1)
1036 perror("\rWARNING: setsockopt(ICMP_FILTER)");
1037 }
1038
1039 net_errors++;
1040 nerrors++;
1041 if (options & F_QUIET)
1042 goto out;
1043 if (options & F_FLOOD) {
1044 write(STDOUT_FILENO, "\bE", 2);
1045 } else {
1046 printf("From %s icmp_seq=%u ", pr_addr(sin->sin_addr.s_addr), ntohs(icmph.un.echo.sequence));
1047 pr_icmph(e->ee_type, e->ee_code, e->ee_info, NULL);
1048 fflush(stdout);
1049 }
1050 }
1051
1052 out:
1053 errno = saved_errno;
1054 return net_errors ? : -local_errors;
1055 }
1056
1057 /*
1058 * pinger --
1059 * Compose and transmit an ICMP ECHO REQUEST packet. The IP packet
1060 * will be added on by the kernel. The ID field is our UNIX process ID,
1061 * and the sequence number is an ascending integer. The first 8 bytes
1062 * of the data portion are used to hold a UNIX "timeval" struct in VAX
1063 * byte-order, to compute the round-trip time.
1064 */
send_probe()1065 int send_probe()
1066 {
1067 struct icmphdr *icp;
1068 int cc;
1069 int i;
1070
1071 icp = (struct icmphdr *)outpack;
1072 icp->type = ICMP_ECHO;
1073 icp->code = 0;
1074 icp->checksum = 0;
1075 icp->un.echo.sequence = htons(ntransmitted+1);
1076 icp->un.echo.id = ident; /* ID */
1077
1078 CLR((ntransmitted+1) % mx_dup_ck);
1079
1080 if (timing) {
1081 if (options&F_LATENCY) {
1082 static volatile int fake_fucked_egcs = sizeof(struct timeval);
1083 struct timeval tmp_tv;
1084 gettimeofday(&tmp_tv, NULL);
1085 /* egcs is crap or glibc is crap, but memcpy
1086 does not copy anything, if len is constant! */
1087 memcpy(icp+1, &tmp_tv, fake_fucked_egcs);
1088 } else {
1089 memset(icp+1, 0, sizeof(struct timeval));
1090 }
1091 }
1092
1093 cc = datalen + 8; /* skips ICMP portion */
1094
1095 /* compute ICMP checksum here */
1096 icp->checksum = in_cksum((u_short *)icp, cc, 0);
1097
1098 if (timing && !(options&F_LATENCY)) {
1099 static volatile int fake_fucked_egcs = sizeof(struct timeval);
1100 struct timeval tmp_tv;
1101 gettimeofday(&tmp_tv, NULL);
1102 /* egcs is crap or glibc is crap, but memcpy
1103 does not copy anything, if len is constant! */
1104 memcpy(icp+1, &tmp_tv, fake_fucked_egcs);
1105 icp->checksum = in_cksum((u_short *)(icp+1), fake_fucked_egcs, ~icp->checksum);
1106 }
1107
1108 do {
1109 static struct iovec iov = {outpack, 0};
1110 static struct msghdr m = { &whereto, sizeof(whereto),
1111 &iov, 1, &cmsg, 0, 0 };
1112 m.msg_controllen = cmsg_len;
1113 iov.iov_len = cc;
1114
1115 i = sendmsg(icmp_sock, &m, confirm);
1116 confirm = 0;
1117 } while (0);
1118
1119 return (cc == i ? 0 : i);
1120 }
1121
1122 /*
1123 * parse_reply --
1124 * Print out the packet, if it came from us. This logic is necessary
1125 * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
1126 * which arrive ('tis only fair). This permits multiple copies of this
1127 * program to be run without having intermingled output (or statistics!).
1128 */
1129 int
parse_reply(struct msghdr * msg,int cc,void * addr,struct timeval * tv)1130 parse_reply(struct msghdr *msg, int cc, void *addr, struct timeval *tv)
1131 {
1132 struct sockaddr_in *from = addr;
1133 __u8 *buf = msg->msg_iov->iov_base;
1134 struct icmphdr *icp;
1135 struct iphdr *ip;
1136 int hlen;
1137 int csfailed;
1138
1139 /* Check the IP header */
1140 ip = (struct iphdr *)buf;
1141 hlen = ip->ihl*4;
1142 if (cc < hlen + 8 || ip->ihl < 5) {
1143 if (options & F_VERBOSE)
1144 fprintf(stderr, "ping: packet too short (%d bytes) from %s\n", cc,
1145 pr_addr(from->sin_addr.s_addr));
1146 return 1;
1147 }
1148
1149 /* Now the ICMP part */
1150 cc -= hlen;
1151 icp = (struct icmphdr *)(buf + hlen);
1152 csfailed = in_cksum((u_short *)icp, cc, 0);
1153
1154 if (icp->type == ICMP_ECHOREPLY) {
1155 if (icp->un.echo.id != ident)
1156 return 1; /* 'Twas not our ECHO */
1157 if (gather_statistics((__u8*)(icp+1), cc,
1158 ntohs(icp->un.echo.sequence),
1159 ip->ttl, 0, tv, pr_addr(from->sin_addr.s_addr)))
1160 return 0;
1161 } else {
1162 /* We fall here when a redirect or source quench arrived.
1163 * Also this branch processes icmp errors, when IP_RECVERR
1164 * is broken. */
1165
1166 switch (icp->type) {
1167 case ICMP_ECHO:
1168 /* MUST NOT */
1169 return 1;
1170 case ICMP_SOURCE_QUENCH:
1171 case ICMP_REDIRECT:
1172 case ICMP_DEST_UNREACH:
1173 case ICMP_TIME_EXCEEDED:
1174 case ICMP_PARAMETERPROB:
1175 {
1176 struct iphdr * iph = (struct iphdr *)(&icp[1]);
1177 struct icmphdr *icp1 = (struct icmphdr*)((unsigned char *)iph + iph->ihl*4);
1178 int error_pkt;
1179 if (cc < 8+sizeof(struct iphdr)+8 ||
1180 cc < 8+iph->ihl*4+8)
1181 return 1;
1182 if (icp1->type != ICMP_ECHO ||
1183 iph->daddr != whereto.sin_addr.s_addr ||
1184 icp1->un.echo.id != ident)
1185 return 1;
1186 error_pkt = (icp->type != ICMP_REDIRECT &&
1187 icp->type != ICMP_SOURCE_QUENCH);
1188 if (error_pkt) {
1189 acknowledge(ntohs(icp1->un.echo.sequence));
1190 if (working_recverr) {
1191 return 0;
1192 } else {
1193 static int once;
1194 /* Sigh, IP_RECVERR for raw socket
1195 * was broken until 2.4.9. So, we ignore
1196 * the first error and warn on the second.
1197 */
1198 if (once++ == 1)
1199 fprintf(stderr, "\rWARNING: kernel is not very fresh, upgrade is recommended.\n");
1200 if (once == 1)
1201 return 0;
1202 }
1203 }
1204 nerrors+=error_pkt;
1205 if (options&F_QUIET)
1206 return !error_pkt;
1207 if (options & F_FLOOD) {
1208 if (error_pkt)
1209 write(STDOUT_FILENO, "\bE", 2);
1210 return !error_pkt;
1211 }
1212 printf("From %s: icmp_seq=%u ",
1213 pr_addr(from->sin_addr.s_addr),
1214 ntohs(icp1->un.echo.sequence));
1215 if (csfailed)
1216 printf("(BAD CHECKSUM)");
1217 pr_icmph(icp->type, icp->code, ntohl(icp->un.gateway), icp);
1218 return !error_pkt;
1219 }
1220 default:
1221 /* MUST NOT */
1222 break;
1223 }
1224 if ((options & F_FLOOD) && !(options & (F_VERBOSE|F_QUIET))) {
1225 if (!csfailed)
1226 write(STDOUT_FILENO, "!E", 2);
1227 else
1228 write(STDOUT_FILENO, "!EC", 3);
1229 return 0;
1230 }
1231 if (!(options & F_VERBOSE) || uid)
1232 return 0;
1233 printf("From %s: ", pr_addr(from->sin_addr.s_addr));
1234 if (csfailed) {
1235 printf("(BAD CHECKSUM)\n");
1236 return 0;
1237 }
1238 pr_icmph(icp->type, icp->code, ntohl(icp->un.gateway), icp);
1239 return 0;
1240 }
1241
1242 if (!(options & F_FLOOD)) {
1243 pr_options(buf + sizeof(struct iphdr), hlen);
1244
1245 if (options & F_AUDIBLE)
1246 putchar('\a');
1247 putchar('\n');
1248 fflush(stdout);
1249 }
1250 return 0;
1251 }
1252
1253 u_short
in_cksum(const u_short * addr,register int len,u_short csum)1254 in_cksum(const u_short *addr, register int len, u_short csum)
1255 {
1256 register int nleft = len;
1257 const u_short *w = addr;
1258 register u_short answer;
1259 register int sum = csum;
1260
1261 /*
1262 * Our algorithm is simple, using a 32 bit accumulator (sum),
1263 * we add sequential 16 bit words to it, and at the end, fold
1264 * back all the carry bits from the top 16 bits into the lower
1265 * 16 bits.
1266 */
1267 while (nleft > 1) {
1268 sum += *w++;
1269 nleft -= 2;
1270 }
1271
1272 /* mop up an odd byte, if necessary */
1273 if (nleft == 1)
1274 sum += htons(*(u_char *)w << 8);
1275
1276 /*
1277 * add back carry outs from top 16 bits to low 16 bits
1278 */
1279 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
1280 sum += (sum >> 16); /* add carry */
1281 answer = ~sum; /* truncate to 16 bits */
1282 return (answer);
1283 }
1284
1285 /*
1286 * pr_icmph --
1287 * Print a descriptive string about an ICMP header.
1288 */
pr_icmph(__u8 type,__u8 code,__u32 info,struct icmphdr * icp)1289 void pr_icmph(__u8 type, __u8 code, __u32 info, struct icmphdr *icp)
1290 {
1291 switch(type) {
1292 case ICMP_ECHOREPLY:
1293 printf("Echo Reply\n");
1294 /* XXX ID + Seq + Data */
1295 break;
1296 case ICMP_DEST_UNREACH:
1297 switch(code) {
1298 case ICMP_NET_UNREACH:
1299 printf("Destination Net Unreachable\n");
1300 break;
1301 case ICMP_HOST_UNREACH:
1302 printf("Destination Host Unreachable\n");
1303 break;
1304 case ICMP_PROT_UNREACH:
1305 printf("Destination Protocol Unreachable\n");
1306 break;
1307 case ICMP_PORT_UNREACH:
1308 printf("Destination Port Unreachable\n");
1309 break;
1310 case ICMP_FRAG_NEEDED:
1311 printf("Frag needed and DF set (mtu = %u)\n", info);
1312 break;
1313 case ICMP_SR_FAILED:
1314 printf("Source Route Failed\n");
1315 break;
1316 case ICMP_PKT_FILTERED:
1317 printf("Packet filtered\n");
1318 break;
1319 default:
1320 printf("Dest Unreachable, Bad Code: %d\n", code);
1321 break;
1322 }
1323 if (icp && (options & F_VERBOSE))
1324 pr_iph((struct iphdr*)(icp + 1));
1325 break;
1326 case ICMP_SOURCE_QUENCH:
1327 printf("Source Quench\n");
1328 if (icp && (options & F_VERBOSE))
1329 pr_iph((struct iphdr*)(icp + 1));
1330 break;
1331 case ICMP_REDIRECT:
1332 switch(code) {
1333 case ICMP_REDIR_NET:
1334 printf("Redirect Network");
1335 break;
1336 case ICMP_REDIR_HOST:
1337 printf("Redirect Host");
1338 break;
1339 case ICMP_REDIR_NETTOS:
1340 printf("Redirect Type of Service and Network");
1341 break;
1342 case ICMP_REDIR_HOSTTOS:
1343 printf("Redirect Type of Service and Host");
1344 break;
1345 default:
1346 printf("Redirect, Bad Code: %d", code);
1347 break;
1348 }
1349 if (icp)
1350 printf("(New nexthop: %s)\n", pr_addr(icp->un.gateway));
1351 if (icp && (options & F_VERBOSE))
1352 pr_iph((struct iphdr*)(icp + 1));
1353 break;
1354 case ICMP_ECHO:
1355 printf("Echo Request\n");
1356 /* XXX ID + Seq + Data */
1357 break;
1358 case ICMP_TIME_EXCEEDED:
1359 switch(code) {
1360 case ICMP_EXC_TTL:
1361 printf("Time to live exceeded\n");
1362 break;
1363 case ICMP_EXC_FRAGTIME:
1364 printf("Frag reassembly time exceeded\n");
1365 break;
1366 default:
1367 printf("Time exceeded, Bad Code: %d\n", code);
1368 break;
1369 }
1370 if (icp && (options & F_VERBOSE))
1371 pr_iph((struct iphdr*)(icp + 1));
1372 break;
1373 case ICMP_PARAMETERPROB:
1374 printf("Parameter problem: pointer = %u\n", icp ? (ntohl(icp->un.gateway)>>24) : info);
1375 if (icp && (options & F_VERBOSE))
1376 pr_iph((struct iphdr*)(icp + 1));
1377 break;
1378 case ICMP_TIMESTAMP:
1379 printf("Timestamp\n");
1380 /* XXX ID + Seq + 3 timestamps */
1381 break;
1382 case ICMP_TIMESTAMPREPLY:
1383 printf("Timestamp Reply\n");
1384 /* XXX ID + Seq + 3 timestamps */
1385 break;
1386 case ICMP_INFO_REQUEST:
1387 printf("Information Request\n");
1388 /* XXX ID + Seq */
1389 break;
1390 case ICMP_INFO_REPLY:
1391 printf("Information Reply\n");
1392 /* XXX ID + Seq */
1393 break;
1394 #ifdef ICMP_MASKREQ
1395 case ICMP_MASKREQ:
1396 printf("Address Mask Request\n");
1397 break;
1398 #endif
1399 #ifdef ICMP_MASKREPLY
1400 case ICMP_MASKREPLY:
1401 printf("Address Mask Reply\n");
1402 break;
1403 #endif
1404 default:
1405 printf("Bad ICMP type: %d\n", type);
1406 }
1407 }
1408
pr_options(unsigned char * cp,int hlen)1409 void pr_options(unsigned char * cp, int hlen)
1410 {
1411 int i, j;
1412 int optlen, totlen;
1413 unsigned char * optptr;
1414 static int old_rrlen;
1415 static char old_rr[MAX_IPOPTLEN];
1416
1417 totlen = hlen-sizeof(struct iphdr);
1418 optptr = cp;
1419
1420 while (totlen > 0) {
1421 if (*optptr == IPOPT_EOL)
1422 break;
1423 if (*optptr == IPOPT_NOP) {
1424 totlen--;
1425 optptr++;
1426 printf("\nNOP");
1427 continue;
1428 }
1429 cp = optptr;
1430 optlen = optptr[1];
1431 if (optlen < 2 || optlen > totlen)
1432 break;
1433
1434 switch (*cp) {
1435 case IPOPT_SSRR:
1436 case IPOPT_LSRR:
1437 printf("\n%cSRR: ", *cp==IPOPT_SSRR ? 'S' : 'L');
1438 j = *++cp;
1439 i = *++cp;
1440 i -= 4;
1441 cp++;
1442 if (j > IPOPT_MINOFF) {
1443 for (;;) {
1444 __u32 address;
1445 memcpy(&address, cp, 4);
1446 cp += 4;
1447 if (address == 0)
1448 printf("\t0.0.0.0");
1449 else
1450 printf("\t%s", pr_addr(address));
1451 j -= 4;
1452 putchar('\n');
1453 if (j <= IPOPT_MINOFF)
1454 break;
1455 }
1456 }
1457 break;
1458 case IPOPT_RR:
1459 j = *++cp; /* get length */
1460 i = *++cp; /* and pointer */
1461 if (i > j)
1462 i = j;
1463 i -= IPOPT_MINOFF;
1464 if (i <= 0)
1465 continue;
1466 if (i == old_rrlen
1467 && !memcmp((char *)cp, old_rr, i)
1468 && !(options & F_FLOOD)) {
1469 printf("\t(same route)");
1470 i = ((i + 3) / 4) * 4;
1471 cp += i;
1472 break;
1473 }
1474 old_rrlen = i;
1475 memcpy((char *)cp, old_rr, i);
1476 printf("\nRR: ");
1477 cp++;
1478 for (;;) {
1479 __u32 address;
1480 memcpy(&address, cp, 4);
1481 cp += 4;
1482 if (address == 0)
1483 printf("\t0.0.0.0");
1484 else
1485 printf("\t%s", pr_addr(address));
1486 i -= 4;
1487 putchar('\n');
1488 if (i <= 0)
1489 break;
1490 }
1491 break;
1492 case IPOPT_TS:
1493 {
1494 int stdtime = 0, nonstdtime = 0;
1495 __u8 flags;
1496 j = *++cp; /* get length */
1497 i = *++cp; /* and pointer */
1498 if (i > j)
1499 i = j;
1500 i -= 5;
1501 if (i <= 0)
1502 continue;
1503 flags = *++cp;
1504 printf("\nTS: ");
1505 cp++;
1506 for (;;) {
1507 long l;
1508
1509 if ((flags&0xF) != IPOPT_TS_TSONLY) {
1510 __u32 address;
1511 memcpy(&address, cp, 4);
1512 cp += 4;
1513 if (address == 0)
1514 printf("\t0.0.0.0");
1515 else
1516 printf("\t%s", pr_addr(address));
1517 i -= 4;
1518 if (i <= 0)
1519 break;
1520 }
1521 l = *cp++;
1522 l = (l<<8) + *cp++;
1523 l = (l<<8) + *cp++;
1524 l = (l<<8) + *cp++;
1525
1526 if (l & 0x80000000) {
1527 if (nonstdtime==0)
1528 printf("\t%ld absolute not-standard", l&0x7fffffff);
1529 else
1530 printf("\t%ld not-standard", (l&0x7fffffff) - nonstdtime);
1531 nonstdtime = l&0x7fffffff;
1532 } else {
1533 if (stdtime==0)
1534 printf("\t%ld absolute", l);
1535 else
1536 printf("\t%ld", l - stdtime);
1537 stdtime = l;
1538 }
1539 i -= 4;
1540 putchar('\n');
1541 if (i <= 0)
1542 break;
1543 }
1544 if (flags>>4)
1545 printf("Unrecorded hops: %d\n", flags>>4);
1546 break;
1547 }
1548 default:
1549 printf("\nunknown option %x", *cp);
1550 break;
1551 }
1552 totlen -= optlen;
1553 optptr += optlen;
1554 }
1555 }
1556
1557
1558 /*
1559 * pr_iph --
1560 * Print an IP header with options.
1561 */
pr_iph(struct iphdr * ip)1562 void pr_iph(struct iphdr *ip)
1563 {
1564 int hlen;
1565 u_char *cp;
1566
1567 hlen = ip->ihl << 2;
1568 cp = (u_char *)ip + 20; /* point to options */
1569
1570 printf("Vr HL TOS Len ID Flg off TTL Pro cks Src Dst Data\n");
1571 printf(" %1x %1x %02x %04x %04x",
1572 ip->version, ip->ihl, ip->tos, ip->tot_len, ip->id);
1573 printf(" %1x %04x", ((ip->frag_off) & 0xe000) >> 13,
1574 (ip->frag_off) & 0x1fff);
1575 printf(" %02x %02x %04x", ip->ttl, ip->protocol, ip->check);
1576 printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->saddr));
1577 printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->daddr));
1578 printf("\n");
1579 pr_options(cp, hlen);
1580 }
1581
1582 /*
1583 * pr_addr --
1584 * Return an ascii host address as a dotted quad and optionally with
1585 * a hostname.
1586 */
1587 char *
pr_addr(__u32 addr)1588 pr_addr(__u32 addr)
1589 {
1590 struct hostent *hp;
1591 static char buf[4096];
1592
1593 if ((options & F_NUMERIC) ||
1594 !(hp = gethostbyaddr((char *)&addr, 4, AF_INET)))
1595 sprintf(buf, "%s", inet_ntoa(*(struct in_addr *)&addr));
1596 else
1597 snprintf(buf, sizeof(buf), "%s (%s)", hp->h_name,
1598 inet_ntoa(*(struct in_addr *)&addr));
1599 return(buf);
1600 }
1601
1602
1603 /* Set Type of Service (TOS) and other Quality of Service relating bits */
parsetos(char * str)1604 int parsetos(char *str)
1605 {
1606 const char *cp;
1607 int tos;
1608 char *ep;
1609
1610 /* handle both hex and decimal values */
1611 if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) {
1612 cp = str + 2;
1613 tos = (int)strtol(cp, &ep, 16);
1614 } else
1615 tos = (int)strtol(str, &ep, 10);
1616
1617 /* doesn't look like decimal or hex, eh? */
1618 if (*ep != '\0') {
1619 fprintf(stderr, "ping: \"%s\" bad value for TOS\n", str);
1620 exit(2);
1621 }
1622
1623 if (tos > TOS_MAX) {
1624 fprintf(stderr, "ping: the decimal value of TOS bits must be 0-254 (or zero)\n");
1625 exit(2);
1626 }
1627 return(tos);
1628 }
1629
1630 #include <linux/filter.h>
1631
install_filter(void)1632 void install_filter(void)
1633 {
1634 static int once;
1635 static struct sock_filter insns[] = {
1636 BPF_STMT(BPF_LDX|BPF_B|BPF_MSH, 0), /* Skip IP header. F..g BSD... Look into ping6. */
1637 BPF_STMT(BPF_LD|BPF_H|BPF_IND, 4), /* Load icmp echo ident */
1638 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0xAAAA, 0, 1), /* Ours? */
1639 BPF_STMT(BPF_RET|BPF_K, ~0U), /* Yes, it passes. */
1640 BPF_STMT(BPF_LD|BPF_B|BPF_IND, 0), /* Load icmp type */
1641 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, ICMP_ECHOREPLY, 1, 0), /* Echo? */
1642 BPF_STMT(BPF_RET|BPF_K, 0xFFFFFFF), /* No. It passes. */
1643 BPF_STMT(BPF_RET|BPF_K, 0) /* Echo with wrong ident. Reject. */
1644 };
1645 static struct sock_fprog filter = {
1646 sizeof insns / sizeof(insns[0]),
1647 insns
1648 };
1649
1650 if (once)
1651 return;
1652 once = 1;
1653
1654 /* Patch bpflet for current identifier. */
1655 insns[2] = (struct sock_filter)BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __constant_htons(ident), 0, 1);
1656
1657 if (setsockopt(icmp_sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)))
1658 perror("WARNING: failed to install socket filter\n");
1659 }
1660
1661
usage(void)1662 void usage(void)
1663 {
1664 fprintf(stderr,
1665 "Usage: ping [-LRUbdfnqrvVaA] [-c count] [-i interval] [-w deadline]\n"
1666 " [-p pattern] [-s packetsize] [-t ttl] [-I interface or address]\n"
1667 " [-M mtu discovery hint] [-S sndbuf]\n"
1668 " [ -T timestamp option ] [ -Q tos ] [hop1 ...] destination\n");
1669 exit(2);
1670 }
1671
main(int argc,char * argv[])1672 int main(int argc, char *argv[])
1673 {
1674 struct hostent *hp;
1675 int ch, hold, packlen;
1676 int socket_errno;
1677 u_char *packet;
1678 char *target, hnamebuf[MAXHOSTNAMELEN];
1679 char rspace[3 + 4 * NROUTES + 1]; /* record route space */
1680
1681 icmp_sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
1682 socket_errno = errno;
1683
1684 /* if we were setuid root, undo that */
1685 if (setuid(getuid())) return -1;
1686
1687 source.sin_family = AF_INET;
1688
1689 preload = 1;
1690 while ((ch = getopt(argc, argv, COMMON_OPTSTR "bRT:")) != EOF) {
1691 switch(ch) {
1692 case 'b':
1693 broadcast_pings = 1;
1694 break;
1695 case 'Q':
1696 settos = parsetos(optarg);
1697 if (settos &&
1698 (setsockopt(icmp_sock, IPPROTO_IP, IP_TOS,
1699 (char *)&settos, sizeof(int)) < 0)) {
1700 perror("ping: error setting QOS sockopts");
1701 exit(2);
1702 }
1703 break;
1704 case 'R':
1705 if (options & F_TIMESTAMP) {
1706 fprintf(stderr, "Only one of -T or -R may be used\n");
1707 exit(2);
1708 }
1709 options |= F_RROUTE;
1710 break;
1711 case 'T':
1712 if (options & F_RROUTE) {
1713 fprintf(stderr, "Only one of -T or -R may be used\n");
1714 exit(2);
1715 }
1716 options |= F_TIMESTAMP;
1717 if (strcmp(optarg, "tsonly") == 0)
1718 ts_type = IPOPT_TS_TSONLY;
1719 else if (strcmp(optarg, "tsandaddr") == 0)
1720 ts_type = IPOPT_TS_TSANDADDR;
1721 else if (strcmp(optarg, "tsprespec") == 0)
1722 ts_type = IPOPT_TS_PRESPEC;
1723 else {
1724 fprintf(stderr, "Invalid timestamp type\n");
1725 exit(2);
1726 }
1727 break;
1728 case 'I':
1729 {
1730 char dummy;
1731 int i1, i2, i3, i4;
1732
1733 if (sscanf(optarg, "%u.%u.%u.%u%c",
1734 &i1, &i2, &i3, &i4, &dummy) == 4) {
1735 __u8 *ptr;
1736 ptr = (__u8*)&source.sin_addr;
1737 ptr[0] = i1;
1738 ptr[1] = i2;
1739 ptr[2] = i3;
1740 ptr[3] = i4;
1741 options |= F_STRICTSOURCE;
1742 } else {
1743 device = optarg;
1744 }
1745 break;
1746 }
1747 case 'M':
1748 if (strcmp(optarg, "do") == 0)
1749 pmtudisc = IP_PMTUDISC_DO;
1750 else if (strcmp(optarg, "dont") == 0)
1751 pmtudisc = IP_PMTUDISC_DONT;
1752 else if (strcmp(optarg, "want") == 0)
1753 pmtudisc = IP_PMTUDISC_WANT;
1754 else {
1755 fprintf(stderr, "ping: wrong value for -M: do, dont, want are valid ones.\n");
1756 exit(2);
1757 }
1758 break;
1759 case 'V':
1760 printf("ping utility, iputils-ss\n");
1761 exit(0);
1762 COMMON_OPTIONS
1763 common_options(ch);
1764 break;
1765 default:
1766 usage();
1767 }
1768 }
1769 argc -= optind;
1770 argv += optind;
1771
1772 if (argc == 0)
1773 usage();
1774 if (argc > 1) {
1775 if (options & F_RROUTE)
1776 usage();
1777 else if (options & F_TIMESTAMP) {
1778 if (ts_type != IPOPT_TS_PRESPEC)
1779 usage();
1780 if (argc > 5)
1781 usage();
1782 } else {
1783 if (argc > 10)
1784 usage();
1785 options |= F_SOURCEROUTE;
1786 }
1787 }
1788 while (argc > 0) {
1789 target = *argv;
1790
1791 bzero((char *)&whereto, sizeof(whereto));
1792 whereto.sin_family = AF_INET;
1793 if (inet_aton(target, &whereto.sin_addr) == 1) {
1794 hostname = target;
1795 if (argc == 1)
1796 options |= F_NUMERIC;
1797 } else {
1798 hp = gethostbyname(target);
1799 hp = gethostbyname(target);
1800 hp = gethostbyname(target);
1801 if (!hp) {
1802 fprintf(stderr, "ping: unknown host %s\n", target);
1803 exit(2);
1804 }
1805 memcpy(&whereto.sin_addr, hp->h_addr, 4);
1806 strncpy(hnamebuf, hp->h_name, sizeof(hnamebuf) - 1);
1807 hnamebuf[sizeof(hnamebuf) - 1] = 0;
1808 hostname = hnamebuf;
1809 }
1810 if (argc > 1)
1811 route[nroute++] = whereto.sin_addr.s_addr;
1812 argc--;
1813 argv++;
1814 }
1815
1816 if (source.sin_addr.s_addr == 0) {
1817 int alen;
1818 struct sockaddr_in dst = whereto;
1819 int probe_fd = socket(AF_INET, SOCK_DGRAM, 0);
1820
1821 if (probe_fd < 0) {
1822 perror("socket");
1823 exit(2);
1824 }
1825 if (device) {
1826 struct ifreq ifr;
1827 memset(&ifr, 0, sizeof(ifr));
1828 strncpy(ifr.ifr_name, device, IFNAMSIZ-1);
1829 if (setsockopt(probe_fd, SOL_SOCKET, SO_BINDTODEVICE, device, strlen(device)+1) == -1) {
1830 if (IN_MULTICAST(ntohl(dst.sin_addr.s_addr))) {
1831 struct ip_mreqn imr;
1832 if (ioctl(probe_fd, SIOCGIFINDEX, &ifr) < 0) {
1833 fprintf(stderr, "ping: unknown iface %s\n", device);
1834 exit(2);
1835 }
1836 memset(&imr, 0, sizeof(imr));
1837 imr.imr_ifindex = ifr.ifr_ifindex;
1838 if (setsockopt(probe_fd, SOL_IP, IP_MULTICAST_IF, &imr, sizeof(imr)) == -1) {
1839 perror("ping: IP_MULTICAST_IF");
1840 exit(2);
1841 }
1842 }
1843 }
1844 }
1845
1846 if (settos &&
1847 setsockopt(probe_fd, IPPROTO_IP, IP_TOS, (char *)&settos, sizeof(int)) < 0)
1848 perror("Warning: error setting QOS sockopts");
1849
1850 dst.sin_port = htons(1025);
1851 if (nroute)
1852 dst.sin_addr.s_addr = route[0];
1853 if (connect(probe_fd, (struct sockaddr*)&dst, sizeof(dst)) == -1) {
1854 if (errno == EACCES) {
1855 if (broadcast_pings == 0) {
1856 fprintf(stderr, "Do you want to ping broadcast? Then -b\n");
1857 exit(2);
1858 }
1859 fprintf(stderr, "WARNING: pinging broadcast address\n");
1860 if (setsockopt(probe_fd, SOL_SOCKET, SO_BROADCAST,
1861 &broadcast_pings, sizeof(broadcast_pings)) < 0) {
1862 perror ("can't set broadcasting");
1863 exit(2);
1864 }
1865 if (connect(probe_fd, (struct sockaddr*)&dst, sizeof(dst)) == -1) {
1866 perror("connect");
1867 exit(2);
1868 }
1869 } else {
1870 perror("connect");
1871 exit(2);
1872 }
1873 }
1874 alen = sizeof(source);
1875 if (getsockname(probe_fd, (struct sockaddr*)&source, &alen) == -1) {
1876 perror("getsockname");
1877 exit(2);
1878 }
1879 source.sin_port = 0;
1880 close(probe_fd);
1881 } while (0);
1882
1883 if (whereto.sin_addr.s_addr == 0)
1884 whereto.sin_addr.s_addr = source.sin_addr.s_addr;
1885
1886 if (icmp_sock < 0) {
1887 errno = socket_errno;
1888 perror("ping: icmp open socket");
1889 exit(2);
1890 }
1891
1892 if (device) {
1893 struct ifreq ifr;
1894
1895 memset(&ifr, 0, sizeof(ifr));
1896 strncpy(ifr.ifr_name, device, IFNAMSIZ-1);
1897 if (ioctl(icmp_sock, SIOCGIFINDEX, &ifr) < 0) {
1898 fprintf(stderr, "ping: unknown iface %s\n", device);
1899 exit(2);
1900 }
1901 cmsg.ipi.ipi_ifindex = ifr.ifr_ifindex;
1902 cmsg_len = sizeof(cmsg);
1903 }
1904
1905 if (broadcast_pings || IN_MULTICAST(ntohl(whereto.sin_addr.s_addr))) {
1906 if (uid) {
1907 if (interval < 1000) {
1908 fprintf(stderr, "ping: broadcast ping with too short interval.\n");
1909 exit(2);
1910 }
1911 if (pmtudisc >= 0 && pmtudisc != IP_PMTUDISC_DO) {
1912 fprintf(stderr, "ping: broadcast ping does not fragment.\n");
1913 exit(2);
1914 }
1915 }
1916 if (pmtudisc < 0)
1917 pmtudisc = IP_PMTUDISC_DO;
1918 }
1919
1920 if (pmtudisc >= 0) {
1921 if (setsockopt(icmp_sock, SOL_IP, IP_MTU_DISCOVER, &pmtudisc, sizeof(pmtudisc)) == -1) {
1922 perror("ping: IP_MTU_DISCOVER");
1923 exit(2);
1924 }
1925 }
1926
1927 if ((options&F_STRICTSOURCE) &&
1928 bind(icmp_sock, (struct sockaddr*)&source, sizeof(source)) == -1) {
1929 perror("bind");
1930 exit(2);
1931 }
1932
1933 if (1) {
1934 struct icmp_filter filt;
1935 filt.data = ~((1<<ICMP_SOURCE_QUENCH)|
1936 (1<<ICMP_DEST_UNREACH)|
1937 (1<<ICMP_TIME_EXCEEDED)|
1938 (1<<ICMP_PARAMETERPROB)|
1939 (1<<ICMP_REDIRECT)|
1940 (1<<ICMP_ECHOREPLY));
1941 if (setsockopt(icmp_sock, SOL_RAW, ICMP_FILTER, (char*)&filt, sizeof(filt)) == -1)
1942 perror("WARNING: setsockopt(ICMP_FILTER)");
1943 }
1944
1945 hold = 1;
1946 if (setsockopt(icmp_sock, SOL_IP, IP_RECVERR, (char *)&hold, sizeof(hold)))
1947 fprintf(stderr, "WARNING: your kernel is veeery old. No problems.\n");
1948
1949 /* record route option */
1950 if (options & F_RROUTE) {
1951 bzero(rspace, sizeof(rspace));
1952 rspace[0] = IPOPT_NOP;
1953 rspace[1+IPOPT_OPTVAL] = IPOPT_RR;
1954 rspace[1+IPOPT_OLEN] = sizeof(rspace)-1;
1955 rspace[1+IPOPT_OFFSET] = IPOPT_MINOFF;
1956 optlen = 40;
1957 if (setsockopt(icmp_sock, IPPROTO_IP, IP_OPTIONS, rspace, sizeof(rspace)) < 0) {
1958 perror("ping: record route");
1959 exit(2);
1960 }
1961 }
1962 if (options & F_TIMESTAMP) {
1963 bzero(rspace, sizeof(rspace));
1964 rspace[0] = IPOPT_TIMESTAMP;
1965 rspace[1] = (ts_type==IPOPT_TS_TSONLY ? 40 : 36);
1966 rspace[2] = 5;
1967 rspace[3] = ts_type;
1968 if (ts_type == IPOPT_TS_PRESPEC) {
1969 int i;
1970 rspace[1] = 4+nroute*8;
1971 for (i=0; i<nroute; i++)
1972 *(__u32*)&rspace[4+i*8] = route[i];
1973 }
1974 if (setsockopt(icmp_sock, IPPROTO_IP, IP_OPTIONS, rspace, rspace[1]) < 0) {
1975 rspace[3] = 2;
1976 if (setsockopt(icmp_sock, IPPROTO_IP, IP_OPTIONS, rspace, rspace[1]) < 0) {
1977 perror("ping: ts option");
1978 exit(2);
1979 }
1980 }
1981 optlen = 40;
1982 }
1983 if (options & F_SOURCEROUTE) {
1984 int i;
1985 bzero(rspace, sizeof(rspace));
1986 rspace[0] = IPOPT_NOOP;
1987 rspace[1+IPOPT_OPTVAL] = (options & F_SO_DONTROUTE) ? IPOPT_SSRR
1988 : IPOPT_LSRR;
1989 rspace[1+IPOPT_OLEN] = 3 + nroute*4;
1990 rspace[1+IPOPT_OFFSET] = IPOPT_MINOFF;
1991 for (i=0; i<nroute; i++)
1992 *(__u32*)&rspace[4+i*4] = route[i];
1993
1994 if (setsockopt(icmp_sock, IPPROTO_IP, IP_OPTIONS, rspace, 4 + nroute*4) < 0) {
1995 perror("ping: record route");
1996 exit(2);
1997 }
1998 optlen = 40;
1999 }
2000
2001 /* Estimate memory eaten by single packet. It is rough estimate.
2002 * Actually, for small datalen's it depends on kernel side a lot. */
2003 hold = datalen + 8;
2004 hold += ((hold+511)/512)*(optlen + 20 + 16 + 64 + 160);
2005 sock_setbufs(icmp_sock, hold);
2006
2007 if (broadcast_pings) {
2008 if (setsockopt(icmp_sock, SOL_SOCKET, SO_BROADCAST,
2009 &broadcast_pings, sizeof(broadcast_pings)) < 0) {
2010 perror ("ping: can't set broadcasting");
2011 exit(2);
2012 }
2013 }
2014
2015 if (options & F_NOLOOP) {
2016 int loop = 0;
2017 if (setsockopt(icmp_sock, IPPROTO_IP, IP_MULTICAST_LOOP,
2018 &loop, 1) == -1) {
2019 perror ("ping: can't disable multicast loopback");
2020 exit(2);
2021 }
2022 }
2023 if (options & F_TTL) {
2024 int ittl = ttl;
2025 if (setsockopt(icmp_sock, IPPROTO_IP, IP_MULTICAST_TTL,
2026 &ttl, 1) == -1) {
2027 perror ("ping: can't set multicast time-to-live");
2028 exit(2);
2029 }
2030 if (setsockopt(icmp_sock, IPPROTO_IP, IP_TTL,
2031 &ittl, sizeof(ittl)) == -1) {
2032 perror ("ping: can't set unicast time-to-live");
2033 exit(2);
2034 }
2035 }
2036
2037 if (datalen > 0xFFFF - 8 - optlen - 20) {
2038 if (uid || datalen > sizeof(outpack)-8) {
2039 fprintf(stderr, "Error: packet size %d is too large. Maximum is %d\n", datalen, 0xFFFF-8-20-optlen);
2040 exit(2);
2041 }
2042 /* Allow small oversize to root yet. It will cause EMSGSIZE. */
2043 fprintf(stderr, "WARNING: packet size %d is too large. Maximum is %d\n", datalen, 0xFFFF-8-20-optlen);
2044 }
2045
2046 if (datalen >= sizeof(struct timeval)) /* can we time transfer */
2047 timing = 1;
2048 packlen = datalen + MAXIPLEN + MAXICMPLEN;
2049 if (!(packet = (u_char *)malloc((u_int)packlen))) {
2050 fprintf(stderr, "ping: out of memory.\n");
2051 exit(2);
2052 }
2053
2054 printf("PING %s (%s) ", hostname, inet_ntoa(whereto.sin_addr));
2055 if (device || (options&F_STRICTSOURCE))
2056 printf("from %s %s: ", inet_ntoa(source.sin_addr), device ?: "");
2057 printf("%d(%d) bytes of data.\n", datalen, datalen+8+optlen+20);
2058
2059 setup(icmp_sock);
2060
2061 main_loop(icmp_sock, packet, packlen);
2062 return 0;
2063 }
2064
dlopen(const char * filename,int flag)2065 void *dlopen(const char *filename, int flag) { return 0; }
dlerror(void)2066 char *dlerror(void) { return 0; }
dlsym(void * handle,const char * symbol)2067 void *dlsym(void *handle, const char *symbol) { return 0; }
dlclose(void * handle)2068 int dlclose(void *handle) { return 0; }
2069