source: rtems-libbsd/freebsd-userspace/commands/sbin/ping/ping.c @ 99ae4eb

4.1155-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since 99ae4eb was 99ae4eb, checked in by Jennifer Averett <jennifer.averett@…>, on 10/16/12 at 18:38:09

Added rtems exit code to ping, route, and ifconfig commands.

The rtems shell commands should not exit but allow multiple
command attempts and some of the commands share code that
will exit. For this reason a common exit routine was
provided and code added to err.h to address this.

allow access to it.

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