source: rtems-libbsd/freebsd/sbin/ping/ping.c @ fef6dd1

4.11
Last change on this file since fef6dd1 was fef6dd1, checked in by Christian Mauderer <Christian.Mauderer@…>, on 07/15/16 at 05:32:56

freebsd: Don't use new wrappers for old ports.

Some of the commands have been adapted manually. So the wrapper
currently don't necessarily work as expected. For example ifconfig calls
malloc outside of the program call.

  • Property mode set to 100644
File size: 45.9 KB
Line 
1#include <machine/rtems-bsd-user-space.h>
2
3/*
4 * Copyright (c) 1989, 1993
5 *      The Regents of the University of California.  All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Mike Muuss.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 4. Neither the name of the University nor the names of its contributors
19 *    may be used to endorse or promote products derived from this software
20 *    without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35#if 0
36#ifndef lint
37static const char copyright[] =
38"@(#) Copyright (c) 1989, 1993\n\
39        The Regents of the University of California.  All rights reserved.\n";
40#endif /* not lint */
41
42#ifndef lint
43static char sccsid[] = "@(#)ping.c      8.1 (Berkeley) 6/5/93";
44#endif /* not lint */
45#endif
46#ifdef __rtems__
47#define __need_getopt_newlib
48#include <getopt.h>
49#define RTEMS_BSD_PROGRAM_NO_OPEN_WRAP
50#define RTEMS_BSD_PROGRAM_NO_SOCKET_WRAP
51#define RTEMS_BSD_PROGRAM_NO_CLOSE_WRAP
52#define RTEMS_BSD_PROGRAM_NO_FOPEN_WRAP
53#define RTEMS_BSD_PROGRAM_NO_FCLOSE_WRAP
54#define RTEMS_BSD_PROGRAM_NO_MALLOC_WRAP
55#define RTEMS_BSD_PROGRAM_NO_CALLOC_WRAP
56#define RTEMS_BSD_PROGRAM_NO_REALLOC_WRAP
57#define RTEMS_BSD_PROGRAM_NO_FREE_WRAP
58#include <machine/rtems-bsd-program.h>
59#include <machine/rtems-bsd-commands.h>
60#endif /* __rtems__ */
61#include <sys/cdefs.h>
62__FBSDID("$FreeBSD$");
63
64/*
65 *                      P I N G . C
66 *
67 * Using the Internet Control Message Protocol (ICMP) "ECHO" facility,
68 * measure round-trip-delays and packet loss across network paths.
69 *
70 * Author -
71 *      Mike Muuss
72 *      U. S. Army Ballistic Research Laboratory
73 *      December, 1983
74 *
75 * Status -
76 *      Public Domain.  Distribution Unlimited.
77 * Bugs -
78 *      More statistics could always be gathered.
79 *      This program has to run SUID to ROOT to access the ICMP socket.
80 */
81
82#include <rtems/bsd/sys/param.h>                /* NB: we rely on this for <sys/types.h> */
83#include <sys/socket.h>
84#include <sys/sysctl.h>
85#include <rtems/bsd/sys/time.h>
86#include <sys/uio.h>
87
88#include <netinet/in.h>
89#include <netinet/in_systm.h>
90#include <netinet/ip.h>
91#include <netinet/ip_icmp.h>
92#include <netinet/ip_var.h>
93#include <arpa/inet.h>
94
95#ifdef IPSEC
96#include <netipsec/ipsec.h>
97#endif /*IPSEC*/
98
99#include <ctype.h>
100#include <err.h>
101#include <errno.h>
102#include <math.h>
103#include <netdb.h>
104#include <signal.h>
105#include <stdio.h>
106#include <stdlib.h>
107#include <string.h>
108#include <sysexits.h>
109#include <unistd.h>
110
111#define INADDR_LEN      ((int)sizeof(in_addr_t))
112#define TIMEVAL_LEN     ((int)sizeof(struct tv32))
113#define MASK_LEN        (ICMP_MASKLEN - ICMP_MINLEN)
114#define TS_LEN          (ICMP_TSLEN - ICMP_MINLEN)
115#define DEFDATALEN      56              /* default data length */
116#define FLOOD_BACKOFF   20000           /* usecs to back off if F_FLOOD mode */
117                                        /* runs out of buffer space */
118#define MAXIPLEN        (sizeof(struct ip) + MAX_IPOPTLEN)
119#define MAXICMPLEN      (ICMP_ADVLENMIN + MAX_IPOPTLEN)
120#define MAXWAIT         10000           /* max ms to wait for response */
121#define MAXALARM        (60 * 60)       /* max seconds for alarm timeout */
122#define MAXTOS          255
123
124#define A(bit)          rcvd_tbl[(bit)>>3]      /* identify byte in array */
125#define B(bit)          (1 << ((bit) & 0x07))   /* identify bit in byte */
126#define SET(bit)        (A(bit) |= B(bit))
127#define CLR(bit)        (A(bit) &= (~B(bit)))
128#define TST(bit)        (A(bit) & B(bit))
129
130struct tv32 {
131        int32_t tv32_sec;
132        int32_t tv32_usec;
133};
134
135/* various options */
136static int options;
137#define F_FLOOD         0x0001
138#define F_INTERVAL      0x0002
139#define F_NUMERIC       0x0004
140#define F_PINGFILLED    0x0008
141#define F_QUIET         0x0010
142#define F_RROUTE        0x0020
143#define F_SO_DEBUG      0x0040
144#define F_SO_DONTROUTE  0x0080
145#define F_VERBOSE       0x0100
146#define F_QUIET2        0x0200
147#define F_NOLOOP        0x0400
148#define F_MTTL          0x0800
149#define F_MIF           0x1000
150#define F_AUDIBLE       0x2000
151#ifdef IPSEC
152#ifdef IPSEC_POLICY_IPSEC
153#define F_POLICY        0x4000
154#endif /*IPSEC_POLICY_IPSEC*/
155#endif /*IPSEC*/
156#define F_TTL           0x8000
157#define F_MISSED        0x10000
158#define F_ONCE          0x20000
159#define F_HDRINCL       0x40000
160#define F_MASK          0x80000
161#define F_TIME          0x100000
162#define F_SWEEP         0x200000
163#define F_WAITTIME      0x400000
164
165/*
166 * MAX_DUP_CHK is the number of bits in received table, i.e. the maximum
167 * number of received sequence numbers we can keep track of.  Change 128
168 * to 8192 for complete accuracy...
169 */
170#define MAX_DUP_CHK     (8 * 128)
171static const int mx_dup_ck = MAX_DUP_CHK;
172static char rcvd_tbl[MAX_DUP_CHK / 8];
173
174static struct sockaddr_in whereto;      /* who to ping */
175static int datalen = DEFDATALEN;
176static int maxpayload;
177static int s;                           /* socket file descriptor */
178static u_char outpackhdr[IP_MAXPACKET], *outpack;
179static const char BBELL = '\a';         /* characters written for MISSED and AUDIBLE */
180static const char BSPACE = '\b';                /* characters written for flood */
181static const char DOT = '.';
182static char *hostname;
183static char *shostname;
184static int ident;                       /* process id to identify our packets */
185static int uid;                 /* cached uid for micro-optimization */
186static u_char icmp_type = ICMP_ECHO;
187static u_char icmp_type_rsp = ICMP_ECHOREPLY;
188static int phdr_len = 0;
189static int send_len;
190
191/* counters */
192static long nmissedmax;         /* max value of ntransmitted - nreceived - 1 */
193static long npackets;                   /* max packets to transmit */
194static long nreceived;                  /* # of packets we got back */
195static long nrepeats;                   /* number of duplicates */
196static long ntransmitted;               /* sequence # for outbound packets = #sent */
197static long snpackets;                  /* max packets to transmit in one sweep */
198static long sntransmitted;              /* # of packets we sent in this sweep */
199static int sweepmax;                    /* max value of payload in sweep */
200static int sweepmin = 0;                /* start value of payload in sweep */
201static int sweepincr = 1;               /* payload increment in sweep */
202static int interval = 1000;             /* interval between packets, ms */
203static int waittime = MAXWAIT;          /* timeout for each packet */
204static long nrcvtimeout = 0;            /* # of packets we got back after waittime */
205
206/* timing */
207static int timing;                      /* flag to do timing */
208static double tmin = 999999999.0;       /* minimum round trip time */
209static double tmax = 0.0;               /* maximum round trip time */
210static double tsum = 0.0;               /* sum of all times, for doing average */
211static double tsumsq = 0.0;             /* sum of all times squared, for std. dev. */
212
213static volatile sig_atomic_t finish_up;  /* nonzero if we've been told to finish up */
214static volatile sig_atomic_t siginfo_p;
215
216static void fill(char *, char *);
217static u_short in_cksum(u_short *, int);
218static void check_status(void);
219static void finish(void) __dead2;
220static void pinger(void);
221static char *pr_addr(struct in_addr);
222static char *pr_ntime(n_time);
223static void pr_icmph(struct icmp *);
224static void pr_iph(struct ip *);
225static void pr_pack(char *, int, struct sockaddr_in *, struct timeval *);
226static void pr_retip(struct ip *);
227#ifndef __rtems__
228static void status(int);
229static void stopit(int);
230#endif /* __rtems__ */
231static void tvsub(struct timeval *, const struct timeval *);
232static void usage(void) __dead2;
233
234#ifdef __rtems__
235static int main(int argc, char **argv);
236
237int rtems_bsd_command_ping(int argc, char *argv[])
238{
239        int exit_code;
240
241        rtems_bsd_program_lock();
242
243        memset(&rcvd_tbl[0], 0, sizeof(rcvd_tbl));
244        s = -1;
245        memset(&outpackhdr[0], 0, sizeof(outpackhdr));
246        icmp_type = ICMP_ECHO;
247        icmp_type_rsp = ICMP_ECHOREPLY;
248        phdr_len = 0;
249        nmissedmax = 0;
250        npackets = 3;
251        nreceived = 0;
252        nrepeats = 0;
253        ntransmitted = 0;
254        snpackets = 0;
255        sntransmitted = 0;
256        sweepmax = 0;
257        sweepmin = 0;
258        sweepincr = 1;
259        interval = 1000;
260        waittime = MAXWAIT;
261        nrcvtimeout = 0;
262        timing = 0;
263        tmin = 999999999.0;
264        tmax = 0.0;
265        tsum = 0.0;
266        tsumsq = 0.0;
267        finish_up = 0;
268        siginfo_p = 0;
269
270        exit_code = rtems_bsd_program_call_main("ping", main, argc, argv);
271
272        rtems_bsd_program_unlock();
273
274        close(s);
275
276        return exit_code;
277}
278#endif /* __rtems__ */
279int
280#ifndef __rtems__
281main(int argc, char *const *argv)
282#else /* __rtems__ */
283main(int argc, char **argv)
284#endif /* __rtems__ */
285{
286        struct sockaddr_in from, sock_in;
287        struct in_addr ifaddr;
288        struct timeval last, intvl;
289        struct iovec iov;
290        struct ip *ip;
291        struct msghdr msg;
292        struct sigaction si_sa;
293        size_t sz;
294#ifndef __rtems__
295        u_char *datap, packet[IP_MAXPACKET] __aligned(4);
296#else /* __rtems__ */
297        u_char *datap;
298        static u_char packet[IP_MAXPACKET] __aligned(4);
299#endif /* __rtems__ */
300        char *ep, *source, *target, *payload;
301        struct hostent *hp;
302#ifdef IPSEC_POLICY_IPSEC
303        char *policy_in, *policy_out;
304#endif
305        struct sockaddr_in *to;
306        double t;
307        u_long alarmtimeout, ultmp;
308        int almost_done, ch, df, hold, i, icmp_len, mib[4], preload, sockerrno,
309            tos, ttl;
310        char ctrl[CMSG_SPACE(sizeof(struct timeval))];
311#ifndef __rtems__
312        char hnamebuf[MAXHOSTNAMELEN], snamebuf[MAXHOSTNAMELEN];
313#else /* __rtems__ */
314        static char hnamebuf[MAXHOSTNAMELEN];
315        static char snamebuf[MAXHOSTNAMELEN];
316#endif /* __rtems__ */
317#ifdef IP_OPTIONS
318        char rspace[MAX_IPOPTLEN];      /* record route space */
319#endif
320        unsigned char loop, mttl;
321#ifdef __rtems__
322        struct getopt_data getopt_data;
323        memset(&getopt_data, 0, sizeof(getopt_data));
324#define optind getopt_data.optind
325#define optarg getopt_data.optarg
326#define opterr getopt_data.opterr
327#define optopt getopt_data.optopt
328#define getopt(argc, argv, opt) getopt_r(argc, argv, "+" opt, &getopt_data)
329#endif /* __rtems__ */
330
331        payload = source = NULL;
332#ifdef IPSEC_POLICY_IPSEC
333        policy_in = policy_out = NULL;
334#endif
335
336        /*
337         * Do the stuff that we need root priv's for *first*, and
338         * then drop our setuid bit.  Save error reporting for
339         * after arg parsing.
340         */
341        s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
342        sockerrno = errno;
343
344        setuid(getuid());
345        uid = getuid();
346
347        alarmtimeout = df = preload = tos = 0;
348
349        outpack = outpackhdr + sizeof(struct ip);
350        while ((ch = getopt(argc, argv,
351                "Aac:DdfG:g:h:I:i:Ll:M:m:nop:QqRrS:s:T:t:vW:z:"
352#ifdef IPSEC
353#ifdef IPSEC_POLICY_IPSEC
354                "P:"
355#endif /*IPSEC_POLICY_IPSEC*/
356#endif /*IPSEC*/
357                )) != -1)
358        {
359                switch(ch) {
360                case 'A':
361                        options |= F_MISSED;
362                        break;
363                case 'a':
364                        options |= F_AUDIBLE;
365                        break;
366                case 'c':
367                        ultmp = strtoul(optarg, &ep, 0);
368                        if (*ep || ep == optarg || ultmp > LONG_MAX || !ultmp)
369                                errx(EX_USAGE,
370                                    "invalid count of packets to transmit: `%s'",
371                                    optarg);
372                        npackets = ultmp;
373                        break;
374                case 'D':
375                        options |= F_HDRINCL;
376                        df = 1;
377                        break;
378                case 'd':
379                        options |= F_SO_DEBUG;
380                        break;
381                case 'f':
382                        if (uid) {
383                                errno = EPERM;
384                                err(EX_NOPERM, "-f flag");
385                        }
386                        options |= F_FLOOD;
387                        setbuf(stdout, (char *)NULL);
388                        break;
389                case 'G': /* Maximum packet size for ping sweep */
390                        ultmp = strtoul(optarg, &ep, 0);
391                        if (*ep || ep == optarg)
392                                errx(EX_USAGE, "invalid packet size: `%s'",
393                                    optarg);
394                        if (uid != 0 && ultmp > DEFDATALEN) {
395                                errno = EPERM;
396                                err(EX_NOPERM,
397                                    "packet size too large: %lu > %u",
398                                    ultmp, DEFDATALEN);
399                        }
400                        options |= F_SWEEP;
401                        sweepmax = ultmp;
402                        break;
403                case 'g': /* Minimum packet size for ping sweep */
404                        ultmp = strtoul(optarg, &ep, 0);
405                        if (*ep || ep == optarg)
406                                errx(EX_USAGE, "invalid packet size: `%s'",
407                                    optarg);
408                        if (uid != 0 && ultmp > DEFDATALEN) {
409                                errno = EPERM;
410                                err(EX_NOPERM,
411                                    "packet size too large: %lu > %u",
412                                    ultmp, DEFDATALEN);
413                        }
414                        options |= F_SWEEP;
415                        sweepmin = ultmp;
416                        break;
417                case 'h': /* Packet size increment for ping sweep */
418                        ultmp = strtoul(optarg, &ep, 0);
419                        if (*ep || ep == optarg || ultmp < 1)
420                                errx(EX_USAGE, "invalid increment size: `%s'",
421                                    optarg);
422                        if (uid != 0 && ultmp > DEFDATALEN) {
423                                errno = EPERM;
424                                err(EX_NOPERM,
425                                    "packet size too large: %lu > %u",
426                                    ultmp, DEFDATALEN);
427                        }
428                        options |= F_SWEEP;
429                        sweepincr = ultmp;
430                        break;
431                case 'I':               /* multicast interface */
432                        if (inet_aton(optarg, &ifaddr) == 0)
433                                errx(EX_USAGE,
434                                    "invalid multicast interface: `%s'",
435                                    optarg);
436                        options |= F_MIF;
437                        break;
438                case 'i':               /* wait between sending packets */
439                        t = strtod(optarg, &ep) * 1000.0;
440                        if (*ep || ep == optarg || t > (double)INT_MAX)
441                                errx(EX_USAGE, "invalid timing interval: `%s'",
442                                    optarg);
443                        options |= F_INTERVAL;
444                        interval = (int)t;
445                        if (uid && interval < 1000) {
446                                errno = EPERM;
447                                err(EX_NOPERM, "-i interval too short");
448                        }
449                        break;
450                case 'L':
451                        options |= F_NOLOOP;
452                        loop = 0;
453                        break;
454                case 'l':
455                        ultmp = strtoul(optarg, &ep, 0);
456                        if (*ep || ep == optarg || ultmp > INT_MAX)
457                                errx(EX_USAGE,
458                                    "invalid preload value: `%s'", optarg);
459                        if (uid) {
460                                errno = EPERM;
461                                err(EX_NOPERM, "-l flag");
462                        }
463                        preload = ultmp;
464                        break;
465                case 'M':
466                        switch(optarg[0]) {
467                        case 'M':
468                        case 'm':
469                                options |= F_MASK;
470                                break;
471                        case 'T':
472                        case 't':
473                                options |= F_TIME;
474                                break;
475                        default:
476                                errx(EX_USAGE, "invalid message: `%c'", optarg[0]);
477                                break;
478                        }
479                        break;
480                case 'm':               /* TTL */
481                        ultmp = strtoul(optarg, &ep, 0);
482                        if (*ep || ep == optarg || ultmp > MAXTTL)
483                                errx(EX_USAGE, "invalid TTL: `%s'", optarg);
484                        ttl = ultmp;
485                        options |= F_TTL;
486                        break;
487                case 'n':
488                        options |= F_NUMERIC;
489                        break;
490                case 'o':
491                        options |= F_ONCE;
492                        break;
493#ifdef IPSEC
494#ifdef IPSEC_POLICY_IPSEC
495                case 'P':
496                        options |= F_POLICY;
497                        if (!strncmp("in", optarg, 2))
498                                policy_in = strdup(optarg);
499                        else if (!strncmp("out", optarg, 3))
500                                policy_out = strdup(optarg);
501                        else
502                                errx(1, "invalid security policy");
503                        break;
504#endif /*IPSEC_POLICY_IPSEC*/
505#endif /*IPSEC*/
506                case 'p':               /* fill buffer with user pattern */
507                        options |= F_PINGFILLED;
508                        payload = optarg;
509                        break;
510                case 'Q':
511                        options |= F_QUIET2;
512                        break;
513                case 'q':
514                        options |= F_QUIET;
515                        break;
516                case 'R':
517                        options |= F_RROUTE;
518                        break;
519                case 'r':
520                        options |= F_SO_DONTROUTE;
521                        break;
522                case 'S':
523                        source = optarg;
524                        break;
525                case 's':               /* size of packet to send */
526                        ultmp = strtoul(optarg, &ep, 0);
527                        if (*ep || ep == optarg)
528                                errx(EX_USAGE, "invalid packet size: `%s'",
529                                    optarg);
530                        if (uid != 0 && ultmp > DEFDATALEN) {
531                                errno = EPERM;
532                                err(EX_NOPERM,
533                                    "packet size too large: %lu > %u",
534                                    ultmp, DEFDATALEN);
535                        }
536                        datalen = ultmp;
537                        break;
538                case 'T':               /* multicast TTL */
539                        ultmp = strtoul(optarg, &ep, 0);
540                        if (*ep || ep == optarg || ultmp > MAXTTL)
541                                errx(EX_USAGE, "invalid multicast TTL: `%s'",
542                                    optarg);
543                        mttl = ultmp;
544                        options |= F_MTTL;
545                        break;
546                case 't':
547                        alarmtimeout = strtoul(optarg, &ep, 0);
548                        if ((alarmtimeout < 1) || (alarmtimeout == ULONG_MAX))
549                                errx(EX_USAGE, "invalid timeout: `%s'",
550                                    optarg);
551                        if (alarmtimeout > MAXALARM)
552                                errx(EX_USAGE, "invalid timeout: `%s' > %d",
553                                    optarg, MAXALARM);
554                        alarm((int)alarmtimeout);
555                        break;
556                case 'v':
557                        options |= F_VERBOSE;
558                        break;
559                case 'W':               /* wait ms for answer */
560                        t = strtod(optarg, &ep);
561                        if (*ep || ep == optarg || t > (double)INT_MAX)
562                                errx(EX_USAGE, "invalid timing interval: `%s'",
563                                    optarg);
564                        options |= F_WAITTIME;
565                        waittime = (int)t;
566                        break;
567                case 'z':
568                        options |= F_HDRINCL;
569                        ultmp = strtoul(optarg, &ep, 0);
570                        if (*ep || ep == optarg || ultmp > MAXTOS)
571                                errx(EX_USAGE, "invalid TOS: `%s'", optarg);
572                        tos = ultmp;
573                        break;
574                default:
575                        usage();
576                }
577        }
578
579        if (argc - optind != 1)
580                usage();
581        target = argv[optind];
582
583        switch (options & (F_MASK|F_TIME)) {
584        case 0: break;
585        case F_MASK:
586                icmp_type = ICMP_MASKREQ;
587                icmp_type_rsp = ICMP_MASKREPLY;
588                phdr_len = MASK_LEN;
589                if (!(options & F_QUIET))
590                        (void)printf("ICMP_MASKREQ\n");
591                break;
592        case F_TIME:
593                icmp_type = ICMP_TSTAMP;
594                icmp_type_rsp = ICMP_TSTAMPREPLY;
595                phdr_len = TS_LEN;
596                if (!(options & F_QUIET))
597                        (void)printf("ICMP_TSTAMP\n");
598                break;
599        default:
600                errx(EX_USAGE, "ICMP_TSTAMP and ICMP_MASKREQ are exclusive.");
601                break;
602        }
603        icmp_len = sizeof(struct ip) + ICMP_MINLEN + phdr_len;
604        if (options & F_RROUTE)
605                icmp_len += MAX_IPOPTLEN;
606        maxpayload = IP_MAXPACKET - icmp_len;
607        if (datalen > maxpayload)
608                errx(EX_USAGE, "packet size too large: %d > %d", datalen,
609                    maxpayload);
610        send_len = icmp_len + datalen;
611        datap = &outpack[ICMP_MINLEN + phdr_len + TIMEVAL_LEN];
612        if (options & F_PINGFILLED) {
613                fill((char *)datap, payload);
614        }
615        if (source) {
616                bzero((char *)&sock_in, sizeof(sock_in));
617                sock_in.sin_family = AF_INET;
618                if (inet_aton(source, &sock_in.sin_addr) != 0) {
619                        shostname = source;
620                } else {
621                        hp = gethostbyname2(source, AF_INET);
622                        if (!hp)
623                                errx(EX_NOHOST, "cannot resolve %s: %s",
624                                    source, hstrerror(h_errno));
625
626                        sock_in.sin_len = sizeof sock_in;
627                        if ((unsigned)hp->h_length > sizeof(sock_in.sin_addr) ||
628                            hp->h_length < 0)
629                                errx(1, "gethostbyname2: illegal address");
630                        memcpy(&sock_in.sin_addr, hp->h_addr_list[0],
631                            sizeof(sock_in.sin_addr));
632                        (void)strncpy(snamebuf, hp->h_name,
633                            sizeof(snamebuf) - 1);
634                        snamebuf[sizeof(snamebuf) - 1] = '\0';
635                        shostname = snamebuf;
636                }
637                if (bind(s, (struct sockaddr *)&sock_in, sizeof sock_in) == -1)
638                        err(1, "bind");
639        }
640
641        bzero(&whereto, sizeof(whereto));
642        to = &whereto;
643        to->sin_family = AF_INET;
644        to->sin_len = sizeof *to;
645        if (inet_aton(target, &to->sin_addr) != 0) {
646                hostname = target;
647        } else {
648                hp = gethostbyname2(target, AF_INET);
649                if (!hp)
650                        errx(EX_NOHOST, "cannot resolve %s: %s",
651                            target, hstrerror(h_errno));
652
653                if ((unsigned)hp->h_length > sizeof(to->sin_addr))
654                        errx(1, "gethostbyname2 returned an illegal address");
655                memcpy(&to->sin_addr, hp->h_addr_list[0], sizeof to->sin_addr);
656                (void)strncpy(hnamebuf, hp->h_name, sizeof(hnamebuf) - 1);
657                hnamebuf[sizeof(hnamebuf) - 1] = '\0';
658                hostname = hnamebuf;
659        }
660
661        if (options & F_FLOOD && options & F_INTERVAL)
662                errx(EX_USAGE, "-f and -i: incompatible options");
663
664        if (options & F_FLOOD && IN_MULTICAST(ntohl(to->sin_addr.s_addr)))
665                errx(EX_USAGE,
666                    "-f flag cannot be used with multicast destination");
667        if (options & (F_MIF | F_NOLOOP | F_MTTL)
668            && !IN_MULTICAST(ntohl(to->sin_addr.s_addr)))
669                errx(EX_USAGE,
670                    "-I, -L, -T flags cannot be used with unicast destination");
671
672        if (datalen >= TIMEVAL_LEN)     /* can we time transfer */
673                timing = 1;
674
675        if (!(options & F_PINGFILLED))
676                for (i = TIMEVAL_LEN; i < datalen; ++i)
677                        *datap++ = i;
678
679        ident = getpid() & 0xFFFF;
680
681        if (s < 0) {
682                errno = sockerrno;
683                err(EX_OSERR, "socket");
684        }
685        hold = 1;
686        if (options & F_SO_DEBUG)
687                (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&hold,
688                    sizeof(hold));
689        if (options & F_SO_DONTROUTE)
690                (void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&hold,
691                    sizeof(hold));
692#ifdef IPSEC
693#ifdef IPSEC_POLICY_IPSEC
694        if (options & F_POLICY) {
695                char *buf;
696                if (policy_in != NULL) {
697                        buf = ipsec_set_policy(policy_in, strlen(policy_in));
698                        if (buf == NULL)
699                                errx(EX_CONFIG, "%s", ipsec_strerror());
700                        if (setsockopt(s, IPPROTO_IP, IP_IPSEC_POLICY,
701                                        buf, ipsec_get_policylen(buf)) < 0)
702                                err(EX_CONFIG,
703                                    "ipsec policy cannot be configured");
704                        free(buf);
705                }
706
707                if (policy_out != NULL) {
708                        buf = ipsec_set_policy(policy_out, strlen(policy_out));
709                        if (buf == NULL)
710                                errx(EX_CONFIG, "%s", ipsec_strerror());
711                        if (setsockopt(s, IPPROTO_IP, IP_IPSEC_POLICY,
712                                        buf, ipsec_get_policylen(buf)) < 0)
713                                err(EX_CONFIG,
714                                    "ipsec policy cannot be configured");
715                        free(buf);
716                }
717        }
718#endif /*IPSEC_POLICY_IPSEC*/
719#endif /*IPSEC*/
720
721        if (options & F_HDRINCL) {
722                ip = (struct ip*)outpackhdr;
723                if (!(options & (F_TTL | F_MTTL))) {
724                        mib[0] = CTL_NET;
725                        mib[1] = PF_INET;
726                        mib[2] = IPPROTO_IP;
727                        mib[3] = IPCTL_DEFTTL;
728                        sz = sizeof(ttl);
729                        if (sysctl(mib, 4, &ttl, &sz, NULL, 0) == -1)
730                                err(1, "sysctl(net.inet.ip.ttl)");
731                }
732                setsockopt(s, IPPROTO_IP, IP_HDRINCL, &hold, sizeof(hold));
733                ip->ip_v = IPVERSION;
734                ip->ip_hl = sizeof(struct ip) >> 2;
735                ip->ip_tos = tos;
736                ip->ip_id = 0;
737                ip->ip_off = df ? IP_DF : 0;
738                ip->ip_ttl = ttl;
739                ip->ip_p = IPPROTO_ICMP;
740                ip->ip_src.s_addr = source ? sock_in.sin_addr.s_addr : INADDR_ANY;
741                ip->ip_dst = to->sin_addr;
742        }
743        /* record route option */
744        if (options & F_RROUTE) {
745#ifdef IP_OPTIONS
746                bzero(rspace, sizeof(rspace));
747                rspace[IPOPT_OPTVAL] = IPOPT_RR;
748                rspace[IPOPT_OLEN] = sizeof(rspace) - 1;
749                rspace[IPOPT_OFFSET] = IPOPT_MINOFF;
750                rspace[sizeof(rspace) - 1] = IPOPT_EOL;
751                if (setsockopt(s, IPPROTO_IP, IP_OPTIONS, rspace,
752                    sizeof(rspace)) < 0)
753                        err(EX_OSERR, "setsockopt IP_OPTIONS");
754#else
755                errx(EX_UNAVAILABLE,
756                    "record route not available in this implementation");
757#endif /* IP_OPTIONS */
758        }
759
760        if (options & F_TTL) {
761                if (setsockopt(s, IPPROTO_IP, IP_TTL, &ttl,
762                    sizeof(ttl)) < 0) {
763                        err(EX_OSERR, "setsockopt IP_TTL");
764                }
765        }
766        if (options & F_NOLOOP) {
767                if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, &loop,
768                    sizeof(loop)) < 0) {
769                        err(EX_OSERR, "setsockopt IP_MULTICAST_LOOP");
770                }
771        }
772        if (options & F_MTTL) {
773                if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, &mttl,
774                    sizeof(mttl)) < 0) {
775                        err(EX_OSERR, "setsockopt IP_MULTICAST_TTL");
776                }
777        }
778        if (options & F_MIF) {
779                if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &ifaddr,
780                    sizeof(ifaddr)) < 0) {
781                        err(EX_OSERR, "setsockopt IP_MULTICAST_IF");
782                }
783        }
784#ifdef SO_TIMESTAMP
785        { int on = 1;
786        if (setsockopt(s, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on)) < 0)
787                err(EX_OSERR, "setsockopt SO_TIMESTAMP");
788        }
789#endif
790        if (sweepmax) {
791                if (sweepmin >= sweepmax)
792                        errx(EX_USAGE, "Maximum packet size must be greater than the minimum packet size");
793
794                if (datalen != DEFDATALEN)
795                        errx(EX_USAGE, "Packet size and ping sweep are mutually exclusive");
796
797                if (npackets > 0) {
798                        snpackets = npackets;
799                        npackets = 0;
800                } else
801                        snpackets = 1;
802                datalen = sweepmin;
803                send_len = icmp_len + sweepmin;
804        }
805        if (options & F_SWEEP && !sweepmax)
806                errx(EX_USAGE, "Maximum sweep size must be specified");
807
808        /*
809         * When pinging the broadcast address, you can get a lot of answers.
810         * Doing something so evil is useful if you are trying to stress the
811         * ethernet, or just want to fill the arp cache to get some stuff for
812         * /etc/ethers.  But beware: RFC 1122 allows hosts to ignore broadcast
813         * or multicast pings if they wish.
814         */
815
816        /*
817         * XXX receive buffer needs undetermined space for mbuf overhead
818         * as well.
819         */
820        hold = IP_MAXPACKET + 128;
821        (void)setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&hold,
822            sizeof(hold));
823        if (uid == 0)
824                (void)setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&hold,
825                    sizeof(hold));
826
827        if (to->sin_family == AF_INET) {
828                (void)printf("PING %s (%s)", hostname,
829                    inet_ntoa(to->sin_addr));
830                if (source)
831                        (void)printf(" from %s", shostname);
832                if (sweepmax)
833                        (void)printf(": (%d ... %d) data bytes\n",
834                            sweepmin, sweepmax);
835                else
836                        (void)printf(": %d data bytes\n", datalen);
837               
838        } else {
839                if (sweepmax)
840                        (void)printf("PING %s: (%d ... %d) data bytes\n",
841                            hostname, sweepmin, sweepmax);
842                else
843                        (void)printf("PING %s: %d data bytes\n", hostname, datalen);
844        }
845
846#ifndef __rtems__
847        /*
848         * Use sigaction() instead of signal() to get unambiguous semantics,
849         * in particular with SA_RESTART not set.
850         */
851
852        sigemptyset(&si_sa.sa_mask);
853        si_sa.sa_flags = 0;
854
855        si_sa.sa_handler = stopit;
856        if (sigaction(SIGINT, &si_sa, 0) == -1) {
857                err(EX_OSERR, "sigaction SIGINT");
858        }
859
860        si_sa.sa_handler = status;
861        if (sigaction(SIGINFO, &si_sa, 0) == -1) {
862                err(EX_OSERR, "sigaction");
863        }
864
865        if (alarmtimeout > 0) {
866                si_sa.sa_handler = stopit;
867                if (sigaction(SIGALRM, &si_sa, 0) == -1)
868                        err(EX_OSERR, "sigaction SIGALRM");
869        }
870#else /* __rtems__ */
871        (void) si_sa;
872#endif /* __rtems__ */
873
874        bzero(&msg, sizeof(msg));
875        msg.msg_name = (caddr_t)&from;
876        msg.msg_iov = &iov;
877        msg.msg_iovlen = 1;
878#ifdef SO_TIMESTAMP
879        msg.msg_control = (caddr_t)ctrl;
880#endif
881        iov.iov_base = packet;
882        iov.iov_len = IP_MAXPACKET;
883
884        if (preload == 0)
885                pinger();               /* send the first ping */
886        else {
887                if (npackets != 0 && preload > npackets)
888                        preload = npackets;
889                while (preload--)       /* fire off them quickies */
890                        pinger();
891        }
892        (void)gettimeofday(&last, NULL);
893
894        if (options & F_FLOOD) {
895                intvl.tv_sec = 0;
896                intvl.tv_usec = 10000;
897        } else {
898                intvl.tv_sec = interval / 1000;
899                intvl.tv_usec = interval % 1000 * 1000;
900        }
901
902        almost_done = 0;
903        while (!finish_up) {
904                struct timeval now, timeout;
905                fd_set rfds;
906                int cc, n;
907
908                check_status();
909                if ((unsigned)s >= FD_SETSIZE)
910                        errx(EX_OSERR, "descriptor too large");
911                FD_ZERO(&rfds);
912                FD_SET(s, &rfds);
913                (void)gettimeofday(&now, NULL);
914                timeout.tv_sec = last.tv_sec + intvl.tv_sec - now.tv_sec;
915                timeout.tv_usec = last.tv_usec + intvl.tv_usec - now.tv_usec;
916                while (timeout.tv_usec < 0) {
917                        timeout.tv_usec += 1000000;
918                        timeout.tv_sec--;
919                }
920                while (timeout.tv_usec >= 1000000) {
921                        timeout.tv_usec -= 1000000;
922                        timeout.tv_sec++;
923                }
924                if (timeout.tv_sec < 0)
925                        timeout.tv_sec = timeout.tv_usec = 0;
926                n = select(s + 1, &rfds, NULL, NULL, &timeout);
927                if (n < 0)
928                        continue;       /* Must be EINTR. */
929                if (n == 1) {
930                        struct timeval *tv = NULL;
931#ifdef SO_TIMESTAMP
932                        struct cmsghdr *cmsg = (struct cmsghdr *)&ctrl;
933
934                        msg.msg_controllen = sizeof(ctrl);
935#endif
936                        msg.msg_namelen = sizeof(from);
937                        if ((cc = recvmsg(s, &msg, 0)) < 0) {
938                                if (errno == EINTR)
939                                        continue;
940                                warn("recvmsg");
941                                continue;
942                        }
943#ifdef SO_TIMESTAMP
944                        if (cmsg->cmsg_level == SOL_SOCKET &&
945                            cmsg->cmsg_type == SCM_TIMESTAMP &&
946                            cmsg->cmsg_len == CMSG_LEN(sizeof *tv)) {
947                                /* Copy to avoid alignment problems: */
948                                memcpy(&now, CMSG_DATA(cmsg), sizeof(now));
949                                tv = &now;
950                        }
951#endif
952                        if (tv == NULL) {
953                                (void)gettimeofday(&now, NULL);
954                                tv = &now;
955                        }
956                        pr_pack((char *)packet, cc, &from, tv);
957                        if ((options & F_ONCE && nreceived) ||
958                            (npackets && nreceived >= npackets))
959                                break;
960                }
961                if (n == 0 || options & F_FLOOD) {
962                        if (sweepmax && sntransmitted == snpackets) {
963                                for (i = 0; i < sweepincr ; ++i)
964                                        *datap++ = i;
965                                datalen += sweepincr;
966                                if (datalen > sweepmax)
967                                        break;
968                                send_len = icmp_len + datalen;
969                                sntransmitted = 0;
970                        }
971                        if (!npackets || ntransmitted < npackets)
972                                pinger();
973                        else {
974                                if (almost_done)
975                                        break;
976                                almost_done = 1;
977                                intvl.tv_usec = 0;
978                                if (nreceived) {
979                                        intvl.tv_sec = 2 * tmax / 1000;
980                                        if (!intvl.tv_sec)
981                                                intvl.tv_sec = 1;
982                                } else {
983                                        intvl.tv_sec = waittime / 1000;
984                                        intvl.tv_usec = waittime % 1000 * 1000;
985                                }
986                        }
987                        (void)gettimeofday(&last, NULL);
988                        if (ntransmitted - nreceived - 1 > nmissedmax) {
989                                nmissedmax = ntransmitted - nreceived - 1;
990                                if (options & F_MISSED)
991                                        (void)write(STDOUT_FILENO, &BBELL, 1);
992                        }
993                }
994        }
995        finish();
996        /* NOTREACHED */
997        exit(0);        /* Make the compiler happy */
998}
999
1000#ifndef __rtems__
1001/*
1002 * stopit --
1003 *      Set the global bit that causes the main loop to quit.
1004 * Do NOT call finish() from here, since finish() does far too much
1005 * to be called from a signal handler.
1006 */
1007void
1008stopit(int sig __unused)
1009{
1010
1011        /*
1012         * When doing reverse DNS lookups, the finish_up flag might not
1013         * be noticed for a while.  Just exit if we get a second SIGINT.
1014         */
1015        if (!(options & F_NUMERIC) && finish_up)
1016                _exit(nreceived ? 0 : 2);
1017        finish_up = 1;
1018}
1019#endif /* __rtems__ */
1020
1021/*
1022 * pinger --
1023 *      Compose and transmit an ICMP ECHO REQUEST packet.  The IP packet
1024 * will be added on by the kernel.  The ID field is our UNIX process ID,
1025 * and the sequence number is an ascending integer.  The first TIMEVAL_LEN
1026 * bytes of the data portion are used to hold a UNIX "timeval" struct in
1027 * host byte-order, to compute the round-trip time.
1028 */
1029static void
1030pinger(void)
1031{
1032        struct timeval now;
1033        struct tv32 tv32;
1034        struct ip *ip;
1035        struct icmp *icp;
1036        int cc, i;
1037        u_char *packet;
1038
1039        packet = outpack;
1040        icp = (struct icmp *)outpack;
1041        icp->icmp_type = icmp_type;
1042        icp->icmp_code = 0;
1043        icp->icmp_cksum = 0;
1044        icp->icmp_seq = htons(ntransmitted);
1045        icp->icmp_id = ident;                   /* ID */
1046
1047        CLR(ntransmitted % mx_dup_ck);
1048
1049        if ((options & F_TIME) || timing) {
1050                (void)gettimeofday(&now, NULL);
1051
1052                tv32.tv32_sec = htonl(now.tv_sec);
1053                tv32.tv32_usec = htonl(now.tv_usec);
1054                if (options & F_TIME)
1055                        icp->icmp_otime = htonl((now.tv_sec % (24*60*60))
1056                                * 1000 + now.tv_usec / 1000);
1057                if (timing)
1058                        bcopy((void *)&tv32,
1059                            (void *)&outpack[ICMP_MINLEN + phdr_len],
1060                            sizeof(tv32));
1061        }
1062
1063        cc = ICMP_MINLEN + phdr_len + datalen;
1064
1065        /* compute ICMP checksum here */
1066        icp->icmp_cksum = in_cksum((u_short *)icp, cc);
1067
1068        if (options & F_HDRINCL) {
1069                cc += sizeof(struct ip);
1070                ip = (struct ip *)outpackhdr;
1071                ip->ip_len = cc;
1072                ip->ip_sum = in_cksum((u_short *)outpackhdr, cc);
1073                packet = outpackhdr;
1074        }
1075        i = sendto(s, (char *)packet, cc, 0, (struct sockaddr *)&whereto,
1076            sizeof(whereto));
1077
1078        if (i < 0 || i != cc)  {
1079                if (i < 0) {
1080                        if (options & F_FLOOD && errno == ENOBUFS) {
1081                                usleep(FLOOD_BACKOFF);
1082                                return;
1083                        }
1084                        warn("sendto");
1085                } else {
1086                        warn("%s: partial write: %d of %d bytes",
1087                             hostname, i, cc);
1088                }
1089        }
1090        ntransmitted++;
1091        sntransmitted++;
1092        if (!(options & F_QUIET) && options & F_FLOOD)
1093                (void)write(STDOUT_FILENO, &DOT, 1);
1094}
1095
1096/*
1097 * pr_pack --
1098 *      Print out the packet, if it came from us.  This logic is necessary
1099 * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
1100 * which arrive ('tis only fair).  This permits multiple copies of this
1101 * program to be run without having intermingled output (or statistics!).
1102 */
1103static void
1104pr_pack(char *buf, int cc, struct sockaddr_in *from, struct timeval *tv)
1105{
1106        struct in_addr ina;
1107        u_char *cp, *dp;
1108        struct icmp *icp;
1109        struct ip *ip;
1110        const void *tp;
1111        double triptime;
1112        int dupflag, hlen, i, j, recv_len, seq;
1113        static int old_rrlen;
1114        static char old_rr[MAX_IPOPTLEN];
1115
1116        /* Check the IP header */
1117        ip = (struct ip *)buf;
1118        hlen = ip->ip_hl << 2;
1119        recv_len = cc;
1120        if (cc < hlen + ICMP_MINLEN) {
1121                if (options & F_VERBOSE)
1122                        warn("packet too short (%d bytes) from %s", cc,
1123                             inet_ntoa(from->sin_addr));
1124                return;
1125        }
1126
1127        /* Now the ICMP part */
1128        cc -= hlen;
1129        icp = (struct icmp *)(buf + hlen);
1130        if (icp->icmp_type == icmp_type_rsp) {
1131                if (icp->icmp_id != ident)
1132                        return;                 /* 'Twas not our ECHO */
1133                ++nreceived;
1134                triptime = 0.0;
1135                if (timing) {
1136                        struct timeval tv1;
1137                        struct tv32 tv32;
1138#ifndef icmp_data
1139                        tp = &icp->icmp_ip;
1140#else
1141                        tp = icp->icmp_data;
1142#endif
1143                        tp = (const char *)tp + phdr_len;
1144
1145                        if (cc - ICMP_MINLEN - phdr_len >= sizeof(tv1)) {
1146                                /* Copy to avoid alignment problems: */
1147                                memcpy(&tv32, tp, sizeof(tv32));
1148                                tv1.tv_sec = ntohl(tv32.tv32_sec);
1149                                tv1.tv_usec = ntohl(tv32.tv32_usec);
1150                                tvsub(tv, &tv1);
1151                                triptime = ((double)tv->tv_sec) * 1000.0 +
1152                                    ((double)tv->tv_usec) / 1000.0;
1153                                tsum += triptime;
1154                                tsumsq += triptime * triptime;
1155                                if (triptime < tmin)
1156                                        tmin = triptime;
1157                                if (triptime > tmax)
1158                                        tmax = triptime;
1159                        } else
1160                                timing = 0;
1161                }
1162
1163                seq = ntohs(icp->icmp_seq);
1164
1165                if (TST(seq % mx_dup_ck)) {
1166                        ++nrepeats;
1167                        --nreceived;
1168                        dupflag = 1;
1169                } else {
1170                        SET(seq % mx_dup_ck);
1171                        dupflag = 0;
1172                }
1173
1174                if (options & F_QUIET)
1175                        return;
1176       
1177                if (options & F_WAITTIME && triptime > waittime) {
1178                        ++nrcvtimeout;
1179                        return;
1180                }
1181
1182                if (options & F_FLOOD)
1183                        (void)write(STDOUT_FILENO, &BSPACE, 1);
1184                else {
1185                        (void)printf("%d bytes from %s: icmp_seq=%u", cc,
1186                           inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr),
1187                           seq);
1188                        (void)printf(" ttl=%d", ip->ip_ttl);
1189                        if (timing)
1190                                (void)printf(" time=%.3f ms", triptime);
1191                        if (dupflag)
1192                                (void)printf(" (DUP!)");
1193                        if (options & F_AUDIBLE)
1194                                (void)write(STDOUT_FILENO, &BBELL, 1);
1195                        if (options & F_MASK) {
1196                                /* Just prentend this cast isn't ugly */
1197                                (void)printf(" mask=%s",
1198                                        pr_addr(*(struct in_addr *)&(icp->icmp_mask)));
1199                        }
1200                        if (options & F_TIME) {
1201                                (void)printf(" tso=%s", pr_ntime(icp->icmp_otime));
1202                                (void)printf(" tsr=%s", pr_ntime(icp->icmp_rtime));
1203                                (void)printf(" tst=%s", pr_ntime(icp->icmp_ttime));
1204                        }
1205                        if (recv_len != send_len) {
1206                                (void)printf(
1207                                     "\nwrong total length %d instead of %d",
1208                                     recv_len, send_len);
1209                        }
1210                        /* check the data */
1211                        cp = (u_char*)&icp->icmp_data[phdr_len];
1212                        dp = &outpack[ICMP_MINLEN + phdr_len];
1213                        cc -= ICMP_MINLEN + phdr_len;
1214                        i = 0;
1215                        if (timing) {   /* don't check variable timestamp */
1216                                cp += TIMEVAL_LEN;
1217                                dp += TIMEVAL_LEN;
1218                                cc -= TIMEVAL_LEN;
1219                                i += TIMEVAL_LEN;
1220                        }
1221                        for (; i < datalen && cc > 0; ++i, ++cp, ++dp, --cc) {
1222                                if (*cp != *dp) {
1223        (void)printf("\nwrong data byte #%d should be 0x%x but was 0x%x",
1224            i, *dp, *cp);
1225                                        (void)printf("\ncp:");
1226                                        cp = (u_char*)&icp->icmp_data[0];
1227                                        for (i = 0; i < datalen; ++i, ++cp) {
1228                                                if ((i % 16) == 8)
1229                                                        (void)printf("\n\t");
1230                                                (void)printf("%2x ", *cp);
1231                                        }
1232                                        (void)printf("\ndp:");
1233                                        cp = &outpack[ICMP_MINLEN];
1234                                        for (i = 0; i < datalen; ++i, ++cp) {
1235                                                if ((i % 16) == 8)
1236                                                        (void)printf("\n\t");
1237                                                (void)printf("%2x ", *cp);
1238                                        }
1239                                        break;
1240                                }
1241                        }
1242                }
1243        } else {
1244                /*
1245                 * We've got something other than an ECHOREPLY.
1246                 * See if it's a reply to something that we sent.
1247                 * We can compare IP destination, protocol,
1248                 * and ICMP type and ID.
1249                 *
1250                 * Only print all the error messages if we are running
1251                 * as root to avoid leaking information not normally
1252                 * available to those not running as root.
1253                 */
1254#ifndef icmp_data
1255                struct ip *oip = &icp->icmp_ip;
1256#else
1257                struct ip *oip = (struct ip *)icp->icmp_data;
1258#endif
1259                struct icmp *oicmp = (struct icmp *)(oip + 1);
1260
1261                if (((options & F_VERBOSE) && uid == 0) ||
1262                    (!(options & F_QUIET2) &&
1263                     (oip->ip_dst.s_addr == whereto.sin_addr.s_addr) &&
1264                     (oip->ip_p == IPPROTO_ICMP) &&
1265                     (oicmp->icmp_type == ICMP_ECHO) &&
1266                     (oicmp->icmp_id == ident))) {
1267                    (void)printf("%d bytes from %s: ", cc,
1268                        pr_addr(from->sin_addr));
1269                    pr_icmph(icp);
1270                } else
1271                    return;
1272        }
1273
1274        /* Display any IP options */
1275        cp = (u_char *)buf + sizeof(struct ip);
1276
1277        for (; hlen > (int)sizeof(struct ip); --hlen, ++cp)
1278                switch (*cp) {
1279                case IPOPT_EOL:
1280                        hlen = 0;
1281                        break;
1282                case IPOPT_LSRR:
1283                case IPOPT_SSRR:
1284                        (void)printf(*cp == IPOPT_LSRR ?
1285                            "\nLSRR: " : "\nSSRR: ");
1286                        j = cp[IPOPT_OLEN] - IPOPT_MINOFF + 1;
1287                        hlen -= 2;
1288                        cp += 2;
1289                        if (j >= INADDR_LEN &&
1290                            j <= hlen - (int)sizeof(struct ip)) {
1291                                for (;;) {
1292                                        bcopy(++cp, &ina.s_addr, INADDR_LEN);
1293                                        if (ina.s_addr == 0)
1294                                                (void)printf("\t0.0.0.0");
1295                                        else
1296                                                (void)printf("\t%s",
1297                                                     pr_addr(ina));
1298                                        hlen -= INADDR_LEN;
1299                                        cp += INADDR_LEN - 1;
1300                                        j -= INADDR_LEN;
1301                                        if (j < INADDR_LEN)
1302                                                break;
1303                                        (void)putchar('\n');
1304                                }
1305                        } else
1306                                (void)printf("\t(truncated route)\n");
1307                        break;
1308                case IPOPT_RR:
1309                        j = cp[IPOPT_OLEN];             /* get length */
1310                        i = cp[IPOPT_OFFSET];           /* and pointer */
1311                        hlen -= 2;
1312                        cp += 2;
1313                        if (i > j)
1314                                i = j;
1315                        i = i - IPOPT_MINOFF + 1;
1316                        if (i < 0 || i > (hlen - (int)sizeof(struct ip))) {
1317                                old_rrlen = 0;
1318                                continue;
1319                        }
1320                        if (i == old_rrlen
1321                            && !bcmp((char *)cp, old_rr, i)
1322                            && !(options & F_FLOOD)) {
1323                                (void)printf("\t(same route)");
1324                                hlen -= i;
1325                                cp += i;
1326                                break;
1327                        }
1328                        old_rrlen = i;
1329                        bcopy((char *)cp, old_rr, i);
1330                        (void)printf("\nRR: ");
1331                        if (i >= INADDR_LEN &&
1332                            i <= hlen - (int)sizeof(struct ip)) {
1333                                for (;;) {
1334                                        bcopy(++cp, &ina.s_addr, INADDR_LEN);
1335                                        if (ina.s_addr == 0)
1336                                                (void)printf("\t0.0.0.0");
1337                                        else
1338                                                (void)printf("\t%s",
1339                                                     pr_addr(ina));
1340                                        hlen -= INADDR_LEN;
1341                                        cp += INADDR_LEN - 1;
1342                                        i -= INADDR_LEN;
1343                                        if (i < INADDR_LEN)
1344                                                break;
1345                                        (void)putchar('\n');
1346                                }
1347                        } else
1348                                (void)printf("\t(truncated route)");
1349                        break;
1350                case IPOPT_NOP:
1351                        (void)printf("\nNOP");
1352                        break;
1353                default:
1354                        (void)printf("\nunknown option %x", *cp);
1355                        break;
1356                }
1357        if (!(options & F_FLOOD)) {
1358                (void)putchar('\n');
1359                (void)fflush(stdout);
1360        }
1361}
1362
1363/*
1364 * in_cksum --
1365 *      Checksum routine for Internet Protocol family headers (C Version)
1366 */
1367u_short
1368in_cksum(u_short *addr, int len)
1369{
1370        int nleft, sum;
1371        u_short *w;
1372        union {
1373                u_short us;
1374                u_char  uc[2];
1375        } last;
1376        u_short answer;
1377
1378        nleft = len;
1379        sum = 0;
1380        w = addr;
1381
1382        /*
1383         * Our algorithm is simple, using a 32 bit accumulator (sum), we add
1384         * sequential 16 bit words to it, and at the end, fold back all the
1385         * carry bits from the top 16 bits into the lower 16 bits.
1386         */
1387        while (nleft > 1)  {
1388                sum += *w++;
1389                nleft -= 2;
1390        }
1391
1392        /* mop up an odd byte, if necessary */
1393        if (nleft == 1) {
1394                last.uc[0] = *(u_char *)w;
1395                last.uc[1] = 0;
1396                sum += last.us;
1397        }
1398
1399        /* add back carry outs from top 16 bits to low 16 bits */
1400        sum = (sum >> 16) + (sum & 0xffff);     /* add hi 16 to low 16 */
1401        sum += (sum >> 16);                     /* add carry */
1402        answer = ~sum;                          /* truncate to 16 bits */
1403        return(answer);
1404}
1405
1406/*
1407 * tvsub --
1408 *      Subtract 2 timeval structs:  out = out - in.  Out is assumed to
1409 * be >= in.
1410 */
1411static void
1412tvsub(struct timeval *out, const struct timeval *in)
1413{
1414
1415        if ((out->tv_usec -= in->tv_usec) < 0) {
1416                --out->tv_sec;
1417                out->tv_usec += 1000000;
1418        }
1419        out->tv_sec -= in->tv_sec;
1420}
1421
1422#ifndef __rtems__
1423/*
1424 * status --
1425 *      Print out statistics when SIGINFO is received.
1426 */
1427
1428static void
1429status(int sig __unused)
1430{
1431
1432        siginfo_p = 1;
1433}
1434#endif /* __rtems__ */
1435
1436static void
1437check_status(void)
1438{
1439
1440        if (siginfo_p) {
1441                siginfo_p = 0;
1442                (void)fprintf(stderr, "\r%ld/%ld packets received (%.1f%%)",
1443                    nreceived, ntransmitted,
1444                    ntransmitted ? nreceived * 100.0 / ntransmitted : 0.0);
1445                if (nreceived && timing)
1446                        (void)fprintf(stderr, " %.3f min / %.3f avg / %.3f max",
1447                            tmin, tsum / (nreceived + nrepeats), tmax);
1448                (void)fprintf(stderr, "\n");
1449        }
1450}
1451
1452/*
1453 * finish --
1454 *      Print out statistics, and give up.
1455 */
1456static void
1457finish(void)
1458{
1459
1460        (void)signal(SIGINT, SIG_IGN);
1461        (void)signal(SIGALRM, SIG_IGN);
1462        (void)putchar('\n');
1463        (void)fflush(stdout);
1464        (void)printf("--- %s ping statistics ---\n", hostname);
1465        (void)printf("%ld packets transmitted, ", ntransmitted);
1466        (void)printf("%ld packets received, ", nreceived);
1467        if (nrepeats)
1468                (void)printf("+%ld duplicates, ", nrepeats);
1469        if (ntransmitted) {
1470                if (nreceived > ntransmitted)
1471                        (void)printf("-- somebody's printing up packets!");
1472                else
1473                        (void)printf("%.1f%% packet loss",
1474                            ((ntransmitted - nreceived) * 100.0) /
1475                            ntransmitted);
1476        }
1477        if (nrcvtimeout)
1478                (void)printf(", %ld packets out of wait time", nrcvtimeout);
1479        (void)putchar('\n');
1480        if (nreceived && timing) {
1481                double n = nreceived + nrepeats;
1482                double avg = tsum / n;
1483                double vari = tsumsq / n - avg * avg;
1484                (void)printf(
1485                    "round-trip min/avg/max/stddev = %.3f/%.3f/%.3f/%.3f ms\n",
1486                    tmin, avg, tmax, sqrt(vari));
1487        }
1488
1489        if (nreceived)
1490                exit(0);
1491        else
1492                exit(2);
1493}
1494
1495#ifdef notdef
1496static char *ttab[] = {
1497        "Echo Reply",           /* ip + seq + udata */
1498        "Dest Unreachable",     /* net, host, proto, port, frag, sr + IP */
1499        "Source Quench",        /* IP */
1500        "Redirect",             /* redirect type, gateway, + IP  */
1501        "Echo",
1502        "Time Exceeded",        /* transit, frag reassem + IP */
1503        "Parameter Problem",    /* pointer + IP */
1504        "Timestamp",            /* id + seq + three timestamps */
1505        "Timestamp Reply",      /* " */
1506        "Info Request",         /* id + sq */
1507        "Info Reply"            /* " */
1508};
1509#endif
1510
1511/*
1512 * pr_icmph --
1513 *      Print a descriptive string about an ICMP header.
1514 */
1515static void
1516pr_icmph(struct icmp *icp)
1517{
1518
1519        switch(icp->icmp_type) {
1520        case ICMP_ECHOREPLY:
1521                (void)printf("Echo Reply\n");
1522                /* XXX ID + Seq + Data */
1523                break;
1524        case ICMP_UNREACH:
1525                switch(icp->icmp_code) {
1526                case ICMP_UNREACH_NET:
1527                        (void)printf("Destination Net Unreachable\n");
1528                        break;
1529                case ICMP_UNREACH_HOST:
1530                        (void)printf("Destination Host Unreachable\n");
1531                        break;
1532                case ICMP_UNREACH_PROTOCOL:
1533                        (void)printf("Destination Protocol Unreachable\n");
1534                        break;
1535                case ICMP_UNREACH_PORT:
1536                        (void)printf("Destination Port Unreachable\n");
1537                        break;
1538                case ICMP_UNREACH_NEEDFRAG:
1539                        (void)printf("frag needed and DF set (MTU %d)\n",
1540                                        ntohs(icp->icmp_nextmtu));
1541                        break;
1542                case ICMP_UNREACH_SRCFAIL:
1543                        (void)printf("Source Route Failed\n");
1544                        break;
1545                case ICMP_UNREACH_FILTER_PROHIB:
1546                        (void)printf("Communication prohibited by filter\n");
1547                        break;
1548                default:
1549                        (void)printf("Dest Unreachable, Bad Code: %d\n",
1550                            icp->icmp_code);
1551                        break;
1552                }
1553                /* Print returned IP header information */
1554#ifndef icmp_data
1555                pr_retip(&icp->icmp_ip);
1556#else
1557                pr_retip((struct ip *)icp->icmp_data);
1558#endif
1559                break;
1560        case ICMP_SOURCEQUENCH:
1561                (void)printf("Source Quench\n");
1562#ifndef icmp_data
1563                pr_retip(&icp->icmp_ip);
1564#else
1565                pr_retip((struct ip *)icp->icmp_data);
1566#endif
1567                break;
1568        case ICMP_REDIRECT:
1569                switch(icp->icmp_code) {
1570                case ICMP_REDIRECT_NET:
1571                        (void)printf("Redirect Network");
1572                        break;
1573                case ICMP_REDIRECT_HOST:
1574                        (void)printf("Redirect Host");
1575                        break;
1576                case ICMP_REDIRECT_TOSNET:
1577                        (void)printf("Redirect Type of Service and Network");
1578                        break;
1579                case ICMP_REDIRECT_TOSHOST:
1580                        (void)printf("Redirect Type of Service and Host");
1581                        break;
1582                default:
1583                        (void)printf("Redirect, Bad Code: %d", icp->icmp_code);
1584                        break;
1585                }
1586                (void)printf("(New addr: %s)\n", inet_ntoa(icp->icmp_gwaddr));
1587#ifndef icmp_data
1588                pr_retip(&icp->icmp_ip);
1589#else
1590                pr_retip((struct ip *)icp->icmp_data);
1591#endif
1592                break;
1593        case ICMP_ECHO:
1594                (void)printf("Echo Request\n");
1595                /* XXX ID + Seq + Data */
1596                break;
1597        case ICMP_TIMXCEED:
1598                switch(icp->icmp_code) {
1599                case ICMP_TIMXCEED_INTRANS:
1600                        (void)printf("Time to live exceeded\n");
1601                        break;
1602                case ICMP_TIMXCEED_REASS:
1603                        (void)printf("Frag reassembly time exceeded\n");
1604                        break;
1605                default:
1606                        (void)printf("Time exceeded, Bad Code: %d\n",
1607                            icp->icmp_code);
1608                        break;
1609                }
1610#ifndef icmp_data
1611                pr_retip(&icp->icmp_ip);
1612#else
1613                pr_retip((struct ip *)icp->icmp_data);
1614#endif
1615                break;
1616        case ICMP_PARAMPROB:
1617                (void)printf("Parameter problem: pointer = 0x%02x\n",
1618                    icp->icmp_hun.ih_pptr);
1619#ifndef icmp_data
1620                pr_retip(&icp->icmp_ip);
1621#else
1622                pr_retip((struct ip *)icp->icmp_data);
1623#endif
1624                break;
1625        case ICMP_TSTAMP:
1626                (void)printf("Timestamp\n");
1627                /* XXX ID + Seq + 3 timestamps */
1628                break;
1629        case ICMP_TSTAMPREPLY:
1630                (void)printf("Timestamp Reply\n");
1631                /* XXX ID + Seq + 3 timestamps */
1632                break;
1633        case ICMP_IREQ:
1634                (void)printf("Information Request\n");
1635                /* XXX ID + Seq */
1636                break;
1637        case ICMP_IREQREPLY:
1638                (void)printf("Information Reply\n");
1639                /* XXX ID + Seq */
1640                break;
1641        case ICMP_MASKREQ:
1642                (void)printf("Address Mask Request\n");
1643                break;
1644        case ICMP_MASKREPLY:
1645                (void)printf("Address Mask Reply\n");
1646                break;
1647        case ICMP_ROUTERADVERT:
1648                (void)printf("Router Advertisement\n");
1649                break;
1650        case ICMP_ROUTERSOLICIT:
1651                (void)printf("Router Solicitation\n");
1652                break;
1653        default:
1654                (void)printf("Bad ICMP type: %d\n", icp->icmp_type);
1655        }
1656}
1657
1658/*
1659 * pr_iph --
1660 *      Print an IP header with options.
1661 */
1662static void
1663pr_iph(struct ip *ip)
1664{
1665        u_char *cp;
1666        int hlen;
1667
1668        hlen = ip->ip_hl << 2;
1669        cp = (u_char *)ip + 20;         /* point to options */
1670
1671        (void)printf("Vr HL TOS  Len   ID Flg  off TTL Pro  cks      Src      Dst\n");
1672        (void)printf(" %1x  %1x  %02x %04x %04x",
1673            ip->ip_v, ip->ip_hl, ip->ip_tos, ntohs(ip->ip_len),
1674            ntohs(ip->ip_id));
1675        (void)printf("   %1lx %04lx",
1676            (u_long) (ntohl(ip->ip_off) & 0xe000) >> 13,
1677            (u_long) ntohl(ip->ip_off) & 0x1fff);
1678        (void)printf("  %02x  %02x %04x", ip->ip_ttl, ip->ip_p,
1679                                                            ntohs(ip->ip_sum));
1680        (void)printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_src.s_addr));
1681        (void)printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_dst.s_addr));
1682        /* dump any option bytes */
1683        while (hlen-- > 20) {
1684                (void)printf("%02x", *cp++);
1685        }
1686        (void)putchar('\n');
1687}
1688
1689/*
1690 * pr_addr --
1691 *      Return an ascii host address as a dotted quad and optionally with
1692 * a hostname.
1693 */
1694static char *
1695pr_addr(struct in_addr ina)
1696{
1697        struct hostent *hp;
1698        static char buf[16 + 3 + MAXHOSTNAMELEN];
1699
1700        if ((options & F_NUMERIC) ||
1701            !(hp = gethostbyaddr((char *)&ina, 4, AF_INET)))
1702                return inet_ntoa(ina);
1703        else
1704                (void)snprintf(buf, sizeof(buf), "%s (%s)", hp->h_name,
1705                    inet_ntoa(ina));
1706        return(buf);
1707}
1708
1709/*
1710 * pr_retip --
1711 *      Dump some info on a returned (via ICMP) IP packet.
1712 */
1713static void
1714pr_retip(struct ip *ip)
1715{
1716        u_char *cp;
1717        int hlen;
1718
1719        pr_iph(ip);
1720        hlen = ip->ip_hl << 2;
1721        cp = (u_char *)ip + hlen;
1722
1723        if (ip->ip_p == 6)
1724                (void)printf("TCP: from port %u, to port %u (decimal)\n",
1725                    (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3)));
1726        else if (ip->ip_p == 17)
1727                (void)printf("UDP: from port %u, to port %u (decimal)\n",
1728                        (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3)));
1729}
1730
1731static char *
1732pr_ntime(n_time timestamp)
1733{
1734        static char buf[10];
1735        int hour, min, sec;
1736
1737        sec = ntohl(timestamp) / 1000;
1738        hour = sec / 60 / 60;
1739        min = (sec % (60 * 60)) / 60;
1740        sec = (sec % (60 * 60)) % 60;
1741
1742        (void)snprintf(buf, sizeof(buf), "%02d:%02d:%02d", hour, min, sec);
1743
1744        return (buf);
1745}
1746
1747static void
1748fill(char *bp, char *patp)
1749{
1750        char *cp;
1751        int pat[16];
1752        u_int ii, jj, kk;
1753
1754        for (cp = patp; *cp; cp++) {
1755                if (!isxdigit((unsigned char) *cp))
1756                        errx(EX_USAGE,
1757                            "patterns must be specified as hex digits");
1758
1759        }
1760        ii = sscanf(patp,
1761            "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
1762            &pat[0], &pat[1], &pat[2], &pat[3], &pat[4], &pat[5], &pat[6],
1763            &pat[7], &pat[8], &pat[9], &pat[10], &pat[11], &pat[12],
1764            &pat[13], &pat[14], &pat[15]);
1765
1766        if (ii > 0)
1767                for (kk = 0; kk <= maxpayload - (TIMEVAL_LEN + ii); kk += ii)
1768                        for (jj = 0; jj < ii; ++jj)
1769                                bp[jj + kk] = pat[jj];
1770        if (!(options & F_QUIET)) {
1771                (void)printf("PATTERN: 0x");
1772                for (jj = 0; jj < ii; ++jj)
1773                        (void)printf("%02x", bp[jj] & 0xFF);
1774                (void)printf("\n");
1775        }
1776}
1777
1778#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
1779#define SECOPT          " [-P policy]"
1780#else
1781#define SECOPT          ""
1782#endif
1783static void
1784usage(void)
1785{
1786
1787        (void)fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
1788"usage: ping [-AaDdfnoQqRrv] [-c count] [-G sweepmaxsize] [-g sweepminsize]",
1789"            [-h sweepincrsize] [-i wait] [-l preload] [-M mask | time] [-m ttl]",
1790"           " SECOPT " [-p pattern] [-S src_addr] [-s packetsize] [-t timeout]",
1791"            [-W waittime] [-z tos] host",
1792"       ping [-AaDdfLnoQqRrv] [-c count] [-I iface] [-i wait] [-l preload]",
1793"            [-M mask | time] [-m ttl]" SECOPT " [-p pattern] [-S src_addr]",
1794"            [-s packetsize] [-T ttl] [-t timeout] [-W waittime]",
1795"            [-z tos] mcast-group");
1796        exit(EX_USAGE);
1797}
Note: See TracBrowser for help on using the repository browser.