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