[BACK]Return to ping.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sbin / ping

Annotation of src/sbin/ping/ping.c, Revision 1.101.2.4

1.101.2.4! yamt        1: /*     $NetBSD: ping.c,v 1.101.2.3 2013/01/23 00:05:33 yamt Exp $      */
1.13      cgd         2:
1.1       cgd         3: /*
1.8       mycroft     4:  * Copyright (c) 1989, 1993
                      5:  *     The Regents of the University of California.  All rights reserved.
1.1       cgd         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.
1.73      agc        18:  * 3. Neither the name of the University nor the names of its contributors
1.1       cgd        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:  */
1.41      christos   34:
1.1       cgd        35: /*
                     36:  *                     P I N G . C
                     37:  *
1.30      christos   38:  * Using the InterNet Control Message Protocol (ICMP) "ECHO" facility,
1.1       cgd        39:  * measure round-trip-delays and packet loss across network paths.
                     40:  *
                     41:  * Author -
                     42:  *     Mike Muuss
                     43:  *     U. S. Army Ballistic Research Laboratory
                     44:  *     December, 1983
1.22      christos   45:  * Modified at Uc Berkeley
                     46:  * Record Route and verbose headers - Phil Dykstra, BRL, March 1988.
                     47:  * Multicast options (ttl, if, loop) - Steve Deering, Stanford, August 1988.
                     48:  * ttl, duplicate detection - Cliff Frost, UCB, April 1989
                     49:  * Pad pattern - Cliff Frost (from Tom Ferrin, UCSF), April 1989
1.1       cgd        50:  *
                     51:  * Status -
                     52:  *     Public Domain.  Distribution Unlimited.
1.22      christos   53:  *
1.1       cgd        54:  * Bugs -
                     55:  *     More statistics could always be gathered.
                     56:  *     This program has to run SUID to ROOT to access the ICMP socket.
                     57:  */
                     58:
1.32      lukem      59: #include <sys/cdefs.h>
1.22      christos   60: #ifndef lint
1.101.2.4! yamt       61: __RCSID("$NetBSD: ping.c,v 1.101.2.3 2013/01/23 00:05:33 yamt Exp $");
1.22      christos   62: #endif
                     63:
                     64: #include <stdio.h>
1.60      yamt       65: #include <stddef.h>
1.22      christos   66: #include <errno.h>
1.81      christos   67: #include <signal.h>
1.22      christos   68: #include <sys/time.h>
                     69: #include <sys/types.h>
1.1       cgd        70: #include <sys/param.h>
                     71: #include <sys/socket.h>
                     72: #include <sys/file.h>
1.41      christos   73: #include <termios.h>
1.22      christos   74: #include <stdlib.h>
                     75: #include <unistd.h>
1.67      mycroft    76: #include <poll.h>
1.22      christos   77: #include <limits.h>
1.44      jwise      78: #include <math.h>
1.22      christos   79: #include <string.h>
                     80: #include <err.h>
1.1       cgd        81:
                     82: #include <netinet/in_systm.h>
                     83: #include <netinet/in.h>
                     84: #include <netinet/ip.h>
                     85: #include <netinet/ip_icmp.h>
                     86: #include <netinet/ip_var.h>
1.12      cgd        87: #include <arpa/inet.h>
1.22      christos   88: #include <ctype.h>
1.1       cgd        89: #include <netdb.h>
                     90:
1.50      itojun     91: #ifdef IPSEC
1.101.2.1  yamt       92: #include <netipsec/ipsec.h>
1.50      itojun     93: #endif /*IPSEC*/
                     94:
1.92      pooka      95: #include "prog_ops.h"
1.91      pooka      96:
1.22      christos   97: #define FLOOD_INTVL    0.01            /* default flood output interval */
1.61      yamt       98: #define        MAXPACKET       (IP_MAXPACKET-60-8)     /* max packet size */
1.7       hpeyerl    99:
1.22      christos  100: #define F_VERBOSE      0x0001
                    101: #define F_QUIET                0x0002          /* minimize all output */
                    102: #define F_SEMI_QUIET   0x0004          /* ignore our ICMP errors */
                    103: #define F_FLOOD                0x0008          /* flood-ping */
                    104: #define        F_RECORD_ROUTE  0x0010          /* record route */
                    105: #define F_SOURCE_ROUTE 0x0020          /* loose source route */
                    106: #define F_PING_FILLED  0x0040          /* is buffer filled with user data? */
                    107: #define F_PING_RANDOM  0x0080          /* use random data */
                    108: #define        F_NUMERIC       0x0100          /* do not do gethostbyaddr() calls */
                    109: #define F_TIMING       0x0200          /* room for a timestamp */
1.30      christos  110: #define F_DF           0x0400          /* set IP DF bit */
                    111: #define F_SOURCE_ADDR  0x0800          /* set source IP address/interface */
                    112: #define F_ONCE         0x1000          /* exit(0) after receiving 1 reply */
                    113: #define F_MCAST                0x2000          /* multicast target */
                    114: #define F_MCAST_NOLOOP 0x4000          /* no multicast loopback */
1.49      sommerfe  115: #define F_AUDIBLE      0x8000          /* audible output */
1.99      christos  116: #define F_TIMING64     0x10000         /* 64 bit time, nanoseconds */
1.50      itojun    117: #ifdef IPSEC
                    118: #ifdef IPSEC_POLICY_IPSEC
1.101.2.2  yamt      119: #define F_POLICY       0x20000
1.50      itojun    120: #else
1.101.2.2  yamt      121: #define        F_AUTHHDR       0x20000
                    122: #define        F_ENCRYPT       0x40000
1.50      itojun    123: #endif /*IPSEC_POLICY_IPSEC*/
                    124: #endif /*IPSEC*/
1.22      christos  125:
1.41      christos  126:
1.22      christos  127: /* MAX_DUP_CHK is the number of bits in received table, the
                    128:  *     maximum number of received sequence numbers we can track to check
                    129:  *     for duplicates.
1.1       cgd       130:  */
1.22      christos  131: #define MAX_DUP_CHK     (8 * 2048)
1.98      joerg     132: static u_char  rcvd_tbl[MAX_DUP_CHK/8];
                    133: static int     nrepeats = 0;
1.22      christos  134: #define A(seq) rcvd_tbl[(seq/8)%sizeof(rcvd_tbl)]  /* byte in array */
                    135: #define B(seq) (1 << (seq & 0x07))     /* bit in byte */
                    136: #define SET(seq) (A(seq) |= B(seq))
                    137: #define CLR(seq) (A(seq) &= (~B(seq)))
                    138: #define TST(seq) (A(seq) & B(seq))
                    139:
1.75      itojun    140: struct tv32 {
                    141:        int32_t tv32_sec;
                    142:        int32_t tv32_usec;
                    143: };
1.22      christos  144:
                    145:
1.98      joerg     146: static u_char  *packet;
                    147: static int     packlen;
                    148: static int     pingflags = 0, options;
                    149: static int     pongflags = 0;
                    150: static char    *fill_pat;
1.22      christos  151:
1.98      joerg     152: static int s;                                  /* Socket file descriptor */
                    153: static int sloop;                              /* Socket file descriptor/loopback */
1.22      christos  154:
1.99      christos  155: #define PHDR_LEN sizeof(struct tv32)           /* size of timestamp header */
                    156: #define PHDR64_LEN sizeof(struct timespec)     /* size of timestamp header */
1.98      joerg     157: static struct sockaddr_in whereto, send_addr;  /* Who to ping */
                    158: static struct sockaddr_in src_addr;            /* from where */
                    159: static struct sockaddr_in loc_addr;            /* 127.1 */
1.99      christos  160: static int datalen;                            /* How much data */
                    161: static int phdrlen;
1.22      christos  162:
1.59      cgd       163: #ifndef __NetBSD__
                    164: static char *progname;
                    165: #define        getprogname()           (progname)
                    166: #define        setprogname(name)       ((void)(progname = (name)))
1.30      christos  167: #endif
1.22      christos  168:
1.98      joerg     169: static char hostname[MAXHOSTNAMELEN];
1.22      christos  170:
                    171: static struct {
                    172:        struct ip       o_ip;
1.30      christos  173:        char            o_opt[MAX_IPOPTLEN];
1.22      christos  174:        union {
1.60      yamt      175:                u_char      u_buf[MAXPACKET+offsetof(struct icmp, icmp_data)];
1.30      christos  176:                struct icmp u_icmp;
1.22      christos  177:        } o_u;
                    178: } out_pack;
1.30      christos  179: #define        opack_icmp      out_pack.o_u.u_icmp
1.98      joerg     180: static struct ip *opack_ip;
1.30      christos  181:
1.98      joerg     182: static char optspace[MAX_IPOPTLEN];            /* record route space */
                    183: static int optlen;
1.30      christos  184:
1.98      joerg     185: static int npackets;                           /* total packets to send */
                    186: static int preload;                            /* number of packets to "preload" */
                    187: static int ntransmitted;                       /* output sequence # = #sent */
                    188: static int ident;                              /* our ID, in network byte order */
                    189:
                    190: static int nreceived;                          /* # of packets we got back */
                    191:
                    192: static double interval;                        /* interval between packets */
1.99      christos  193: static struct timespec interval_tv;
1.98      joerg     194: static double tmin = 999999999.0;
                    195: static double tmax = 0.0;
                    196: static double tsum = 0.0;                      /* sum of all times */
                    197: static double tsumsq = 0.0;
                    198: static double maxwait = 0.0;
                    199:
                    200: static int bufspace = IP_MAXPACKET;
                    201:
1.99      christos  202: static struct timespec now, clear_cache, last_tx, next_tx, first_tx;
                    203: static struct timespec last_rx, first_rx;
1.98      joerg     204: static int lastrcvd = 1;                       /* last ping sent has been received */
1.22      christos  205:
1.99      christos  206: static struct timespec jiggle_time;
1.22      christos  207: static int jiggle_cnt, total_jiggled, jiggle_direction = -1;
                    208:
1.98      joerg     209: __dead static void doit(void);
1.22      christos  210: static void prefinish(int);
                    211: static void prtsig(int);
1.98      joerg     212: __dead static void finish(int);
1.22      christos  213: static void summary(int);
                    214: static void pinger(void);
                    215: static void fill(void);
                    216: static void rnd_fill(void);
1.99      christos  217: static double diffsec(struct timespec *, struct timespec *);
                    218: #if 0
                    219: static void timespecadd(struct timespec *, struct timespec *);
                    220: #endif
                    221: static void sec_to_timespec(const double, struct timespec *);
                    222: static double timespec_to_sec(const struct timespec *);
1.22      christos  223: static void pr_pack(u_char *, int, struct sockaddr_in *);
1.65      itojun    224: static u_int16_t in_cksum(u_int16_t *, u_int);
1.57      is        225: static void pr_saddr(u_char *);
1.22      christos  226: static char *pr_addr(struct in_addr *);
                    227: static void pr_iph(struct icmp *, int);
                    228: static void pr_retip(struct icmp *, int);
                    229: static int pr_icmph(struct icmp *, struct sockaddr_in *, int);
                    230: static void jiggle(int), jiggle_flush(int);
1.30      christos  231: static void gethost(const char *, const char *,
                    232:                    struct sockaddr_in *, char *, int);
1.98      joerg     233: __dead static void usage(void);
1.1       cgd       234:
1.12      cgd       235: int
1.22      christos  236: main(int argc, char *argv[])
1.1       cgd       237: {
1.30      christos  238:        int c, i, on = 1, hostind = 0;
                    239:        long l;
1.99      christos  240:        int len = -1, compat = 0;
1.30      christos  241:        u_char ttl = 0;
                    242:        u_long tos = 0;
1.22      christos  243:        char *p;
1.50      itojun    244: #ifdef IPSEC
                    245: #ifdef IPSEC_POLICY_IPSEC
1.55      itojun    246:        char *policy_in = NULL;
                    247:        char *policy_out = NULL;
1.50      itojun    248: #endif
                    249: #endif
1.81      christos  250: #ifdef SIGINFO
                    251:        struct sigaction sa;
                    252: #endif
1.1       cgd       253:
1.92      pooka     254:        if (prog_init && prog_init() == -1)
                    255:                err(1, "init failed");
1.91      pooka     256:
1.92      pooka     257:        if ((s = prog_socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0)
1.83      elad      258:                err(1, "Cannot create socket");
1.92      pooka     259:        if ((sloop = prog_socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0)
1.83      elad      260:                err(1, "Cannot create socket");
                    261:
1.87      seanb     262:        /*
                    263:         * sloop is never read on.  This prevents packets from
                    264:         * queueing in its recv buffer.
                    265:         */
1.92      pooka     266:        if (prog_shutdown(sloop, SHUT_RD) == -1)
1.87      seanb     267:                warn("Cannot shutdown for read");
                    268:
1.93      pooka     269:        if (prog_setuid(prog_getuid()) == -1)
1.85      elad      270:                err(1, "setuid");
1.83      elad      271:
1.59      cgd       272:        setprogname(argv[0]);
                    273:
1.50      itojun    274: #ifndef IPSEC
                    275: #define IPSECOPT
                    276: #else
                    277: #ifdef IPSEC_POLICY_IPSEC
                    278: #define IPSECOPT       "E:"
                    279: #else
                    280: #define IPSECOPT       "AE"
                    281: #endif /*IPSEC_POLICY_IPSEC*/
                    282: #endif
1.30      christos  283:        while ((c = getopt(argc, argv,
1.99      christos  284:                           "ac:CdDfg:h:i:I:l:Lnop:PqQrRs:t:T:vw:" IPSECOPT)) != -1) {
1.50      itojun    285: #undef IPSECOPT
1.22      christos  286:                switch (c) {
1.49      sommerfe  287:                case 'a':
                    288:                        pingflags |= F_AUDIBLE;
                    289:                        break;
1.99      christos  290:                case 'C':
                    291:                        compat = 1;
                    292:                        break;
1.1       cgd       293:                case 'c':
1.22      christos  294:                        npackets = strtol(optarg, &p, 0);
                    295:                        if (*p != '\0' || npackets <= 0)
                    296:                                errx(1, "Bad/invalid number of packets");
                    297:                        break;
                    298:                case 'D':
1.30      christos  299:                        pingflags |= F_DF;
1.1       cgd       300:                        break;
                    301:                case 'd':
1.22      christos  302:                        options |= SO_DEBUG;
1.1       cgd       303:                        break;
                    304:                case 'f':
1.22      christos  305:                        pingflags |= F_FLOOD;
1.8       mycroft   306:                        break;
1.30      christos  307:                case 'h':
                    308:                        hostind = optind-1;
                    309:                        break;
1.1       cgd       310:                case 'i':               /* wait between sending packets */
1.22      christos  311:                        interval = strtod(optarg, &p);
                    312:                        if (*p != '\0' || interval <= 0)
1.30      christos  313:                                errx(1, "Bad/invalid interval %s", optarg);
1.8       mycroft   314:                        break;
1.1       cgd       315:                case 'l':
1.22      christos  316:                        preload = strtol(optarg, &p, 0);
                    317:                        if (*p != '\0' || preload < 0)
1.30      christos  318:                                errx(1, "Bad/invalid preload value %s",
                    319:                                     optarg);
1.1       cgd       320:                        break;
                    321:                case 'n':
1.22      christos  322:                        pingflags |= F_NUMERIC;
1.1       cgd       323:                        break;
1.25      christos  324:                case 'o':
                    325:                        pingflags |= F_ONCE;
                    326:                        break;
1.1       cgd       327:                case 'p':               /* fill buffer with user pattern */
1.22      christos  328:                        if (pingflags & F_PING_RANDOM)
                    329:                                errx(1, "Only one of -P and -p allowed");
                    330:                        pingflags |= F_PING_FILLED;
                    331:                        fill_pat = optarg;
                    332:                        break;
                    333:                case 'P':
                    334:                        if (pingflags & F_PING_FILLED)
                    335:                                errx(1, "Only one of -P and -p allowed");
                    336:                        pingflags |= F_PING_RANDOM;
                    337:                        break;
1.1       cgd       338:                case 'q':
1.22      christos  339:                        pingflags |= F_QUIET;
1.1       cgd       340:                        break;
1.22      christos  341:                case 'Q':
                    342:                        pingflags |= F_SEMI_QUIET;
1.1       cgd       343:                        break;
                    344:                case 'r':
1.22      christos  345:                        options |= SO_DONTROUTE;
1.19      ghudson   346:                        break;
1.1       cgd       347:                case 's':               /* size of packet to send */
1.89      lukem     348:                        l = strtol(optarg, &p, 0);
                    349:                        if (*p != '\0' || l < 0)
1.30      christos  350:                                errx(1, "Bad/invalid packet size %s", optarg);
1.89      lukem     351:                        if (l > MAXPACKET)
1.22      christos  352:                                errx(1, "packet size is too large");
1.99      christos  353:                        len = (int)l;
1.22      christos  354:                        break;
                    355:                case 'v':
                    356:                        pingflags |= F_VERBOSE;
                    357:                        break;
                    358:                case 'R':
                    359:                        pingflags |= F_RECORD_ROUTE;
                    360:                        break;
                    361:                case 'L':
1.30      christos  362:                        pingflags |= F_MCAST_NOLOOP;
1.8       mycroft   363:                        break;
                    364:                case 't':
1.30      christos  365:                        tos = strtoul(optarg, &p, 0);
                    366:                        if (*p != '\0' ||  tos > 0xFF)
                    367:                                errx(1, "bad tos value: %s", optarg);
1.22      christos  368:                        break;
                    369:                case 'T':
1.30      christos  370:                        l = strtol(optarg, &p, 0);
                    371:                        if (*p != '\0' || l > 255 || l <= 0)
                    372:                                errx(1, "ttl out of range");
                    373:                        ttl = (u_char)l;    /* cannot check >255 otherwise */
1.22      christos  374:                        break;
                    375:                case 'I':
1.30      christos  376:                        pingflags |= F_SOURCE_ADDR;
                    377:                        gethost("-I", optarg, &src_addr, 0, 0);
1.1       cgd       378:                        break;
1.22      christos  379:                case 'g':
                    380:                        pingflags |= F_SOURCE_ROUTE;
1.30      christos  381:                        gethost("-g", optarg, &send_addr, 0, 0);
1.1       cgd       382:                        break;
1.19      ghudson   383:                case 'w':
1.22      christos  384:                        maxwait = strtod(optarg, &p);
                    385:                        if (*p != '\0' || maxwait <= 0)
1.30      christos  386:                                errx(1, "Bad/invalid maxwait time %s", optarg);
1.19      ghudson   387:                        break;
1.50      itojun    388: #ifdef IPSEC
                    389: #ifdef IPSEC_POLICY_IPSEC
                    390:                case 'E':
                    391:                        pingflags |= F_POLICY;
1.70      itojun    392:                        if (!strncmp("in", optarg, 2)) {
1.55      itojun    393:                                policy_in = strdup(optarg);
1.70      itojun    394:                                if (!policy_in)
                    395:                                        err(1, "strdup");
                    396:                        } else if (!strncmp("out", optarg, 3)) {
1.55      itojun    397:                                policy_out = strdup(optarg);
1.70      itojun    398:                                if (!policy_out)
                    399:                                        err(1, "strdup");
                    400:                        } else
1.55      itojun    401:                                errx(1, "invalid security policy");
1.50      itojun    402:                        break;
                    403: #else
                    404:                case 'A':
                    405:                        pingflags |= F_AUTHHDR;
                    406:                        break;
                    407:                case 'E':
                    408:                        pingflags |= F_ENCRYPT;
                    409:                        break;
                    410: #endif /*IPSEC_POLICY_IPSEC*/
                    411: #endif /*IPSEC*/
1.1       cgd       412:                default:
                    413:                        usage();
1.22      christos  414:                        break;
1.1       cgd       415:                }
1.22      christos  416:        }
1.8       mycroft   417:
1.22      christos  418:        if (interval == 0)
                    419:                interval = (pingflags & F_FLOOD) ? FLOOD_INTVL : 1.0;
1.28      christos  420: #ifndef sgi
1.93      pooka     421:        if (pingflags & F_FLOOD && prog_getuid())
1.39      tv        422:                errx(1, "Must be superuser to use -f");
1.93      pooka     423:        if (interval < 1.0 && prog_getuid())
1.28      christos  424:                errx(1, "Must be superuser to use < 1 sec ping interval");
1.93      pooka     425:        if (preload > 0 && prog_getuid())
1.39      tv        426:                errx(1, "Must be superuser to use -l");
1.28      christos  427: #endif
1.99      christos  428:        sec_to_timespec(interval, &interval_tv);
1.22      christos  429:
1.49      sommerfe  430:        if ((pingflags & (F_AUDIBLE|F_FLOOD)) == (F_AUDIBLE|F_FLOOD))
                    431:                warnx("Sorry, no audible output for flood pings");
                    432:
1.22      christos  433:        if (npackets != 0) {
                    434:                npackets += preload;
                    435:        } else {
                    436:                npackets = INT_MAX;
                    437:        }
                    438:
1.30      christos  439:        if (hostind == 0) {
                    440:                if (optind != argc-1)
                    441:                        usage();
1.22      christos  442:                else
1.30      christos  443:                        hostind = optind;
1.22      christos  444:        }
1.30      christos  445:        else if (hostind >= argc - 1)
                    446:                usage();
1.22      christos  447:
1.30      christos  448:        gethost("", argv[hostind], &whereto, hostname, sizeof(hostname));
                    449:        if (IN_MULTICAST(ntohl(whereto.sin_addr.s_addr)))
                    450:                pingflags |= F_MCAST;
1.22      christos  451:        if (!(pingflags & F_SOURCE_ROUTE))
                    452:                (void) memcpy(&send_addr, &whereto, sizeof(send_addr));
                    453:
                    454:        loc_addr.sin_family = AF_INET;
1.71      itojun    455:        loc_addr.sin_len = sizeof(struct sockaddr_in);
1.95      christos  456:        loc_addr.sin_addr.s_addr = htonl((127 << 24) + 1);
1.22      christos  457:
1.99      christos  458:        if (len != -1)
                    459:                datalen = len;
                    460:        else
                    461:                datalen = 64;
                    462:        if (!compat && datalen >= (int)PHDR64_LEN) { /* can we time them? */
                    463:                pingflags |= F_TIMING64;
                    464:                phdrlen = PHDR64_LEN;
                    465:        } else if (datalen >= (int)PHDR_LEN) {  /* can we time them? */
1.22      christos  466:                pingflags |= F_TIMING;
1.99      christos  467:                phdrlen = PHDR_LEN;
                    468:        } else
                    469:                phdrlen = 0;
                    470:
1.22      christos  471:        packlen = datalen + 60 + 76;    /* MAXIP + MAXICMP */
1.101.2.3  yamt      472:        datalen -= phdrlen;
1.95      christos  473:        if ((packet = malloc(packlen)) == NULL)
1.22      christos  474:                err(1, "Out of memory");
                    475:
                    476:        if (pingflags & F_PING_FILLED) {
                    477:                fill();
                    478:        } else if (pingflags & F_PING_RANDOM) {
                    479:                rnd_fill();
                    480:        } else {
1.99      christos  481:                for (i = phdrlen; i < datalen; i++)
1.22      christos  482:                        opack_icmp.icmp_data[i] = i;
                    483:        }
1.1       cgd       484:
1.77      kleink    485:        ident = arc4random() & 0xFFFF;
1.1       cgd       486:
1.22      christos  487:        if (options & SO_DEBUG) {
1.92      pooka     488:                if (prog_setsockopt(s, SOL_SOCKET, SO_DEBUG,
1.41      christos  489:                               (char *)&on, sizeof(on)) == -1)
1.30      christos  490:                        warn("Can't turn on socket debugging");
1.22      christos  491:        }
                    492:        if (options & SO_DONTROUTE) {
1.92      pooka     493:                if (prog_setsockopt(s, SOL_SOCKET, SO_DONTROUTE,
1.41      christos  494:                               (char *)&on, sizeof(on)) == -1)
1.30      christos  495:                        warn("SO_DONTROUTE");
1.22      christos  496:        }
                    497:
1.50      itojun    498:        if (options & SO_DEBUG) {
1.92      pooka     499:                if (prog_setsockopt(sloop, SOL_SOCKET, SO_DEBUG,
1.50      itojun    500:                               (char *)&on, sizeof(on)) == -1)
                    501:                        warn("Can't turn on socket debugging");
                    502:        }
                    503:        if (options & SO_DONTROUTE) {
1.92      pooka     504:                if (prog_setsockopt(sloop, SOL_SOCKET, SO_DONTROUTE,
1.50      itojun    505:                               (char *)&on, sizeof(on)) == -1)
                    506:                        warn("SO_DONTROUTE");
                    507:        }
                    508:
1.30      christos  509:        if (pingflags & F_SOURCE_ROUTE) {
                    510:                optspace[IPOPT_OPTVAL] = IPOPT_LSRR;
                    511:                optspace[IPOPT_OLEN] = optlen = 7;
                    512:                optspace[IPOPT_OFFSET] = IPOPT_MINOFF;
1.41      christos  513:                (void)memcpy(&optspace[IPOPT_MINOFF-1], &whereto.sin_addr,
                    514:                             sizeof(whereto.sin_addr));
1.30      christos  515:                optspace[optlen++] = IPOPT_NOP;
                    516:        }
                    517:        if (pingflags & F_RECORD_ROUTE) {
                    518:                optspace[optlen+IPOPT_OPTVAL] = IPOPT_RR;
                    519:                optspace[optlen+IPOPT_OLEN] = (MAX_IPOPTLEN -1-optlen);
                    520:                optspace[optlen+IPOPT_OFFSET] = IPOPT_MINOFF;
                    521:                optlen = MAX_IPOPTLEN;
                    522:        }
                    523:        /* this leaves opack_ip 0(mod 4) aligned */
                    524:        opack_ip = (struct ip *)((char *)&out_pack.o_ip
                    525:                                 + sizeof(out_pack.o_opt)
                    526:                                 - optlen);
                    527:        (void) memcpy(opack_ip + 1, optspace, optlen);
                    528:
1.92      pooka     529:        if (prog_setsockopt(s,IPPROTO_IP,IP_HDRINCL,
                    530:            (char *) &on, sizeof(on)) < 0)
1.30      christos  531:                err(1, "Can't set special IP header");
                    532:
                    533:        opack_ip->ip_v = IPVERSION;
                    534:        opack_ip->ip_hl = (sizeof(struct ip)+optlen) >> 2;
                    535:        opack_ip->ip_tos = tos;
                    536:        opack_ip->ip_off = (pingflags & F_DF) ? IP_DF : 0;
                    537:        opack_ip->ip_ttl = ttl ? ttl : MAXTTL;
                    538:        opack_ip->ip_p = IPPROTO_ICMP;
                    539:        opack_ip->ip_src = src_addr.sin_addr;
                    540:        opack_ip->ip_dst = send_addr.sin_addr;
                    541:
                    542:        if (pingflags & F_MCAST) {
                    543:                if (pingflags & F_MCAST_NOLOOP) {
                    544:                        u_char loop = 0;
1.92      pooka     545:                        if (prog_setsockopt(s, IPPROTO_IP,
                    546:                            IP_MULTICAST_LOOP,
1.30      christos  547:                            (char *) &loop, 1) < 0)
                    548:                                err(1, "Can't disable multicast loopback");
1.22      christos  549:                }
1.1       cgd       550:
1.30      christos  551:                if (ttl != 0
1.92      pooka     552:                    && prog_setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL,
1.30      christos  553:                    (char *) &ttl, 1) < 0)
1.22      christos  554:                        err(1, "Can't set multicast time-to-live");
1.30      christos  555:
                    556:                if ((pingflags & F_SOURCE_ADDR)
1.92      pooka     557:                    && prog_setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF,
1.30      christos  558:                                  (char *) &src_addr.sin_addr,
                    559:                                  sizeof(src_addr.sin_addr)) < 0)
1.22      christos  560:                        err(1, "Can't set multicast source interface");
1.30      christos  561:
                    562:        } else if (pingflags & F_SOURCE_ADDR) {
1.92      pooka     563:                if (prog_setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF,
1.30      christos  564:                               (char *) &src_addr.sin_addr,
                    565:                               sizeof(src_addr.sin_addr)) < 0)
                    566:                        err(1, "Can't set source interface/address");
1.22      christos  567:        }
1.50      itojun    568: #ifdef IPSEC
                    569: #ifdef IPSEC_POLICY_IPSEC
                    570:     {
                    571:        char *buf;
                    572:        if (pingflags & F_POLICY) {
1.55      itojun    573:                if (policy_in != NULL) {
                    574:                        buf = ipsec_set_policy(policy_in, strlen(policy_in));
                    575:                        if (buf == NULL)
1.57      is        576:                                errx(1, "%s", ipsec_strerror());
1.92      pooka     577:                        if (prog_setsockopt(s, IPPROTO_IP, IP_IPSEC_POLICY,
1.55      itojun    578:                                        buf, ipsec_get_policylen(buf)) < 0) {
                    579:                                err(1, "ipsec policy cannot be configured");
                    580:                        }
                    581:                        free(buf);
                    582:                }
                    583:                if (policy_out != NULL) {
                    584:                        buf = ipsec_set_policy(policy_out, strlen(policy_out));
                    585:                        if (buf == NULL)
1.57      is        586:                                errx(1, "%s", ipsec_strerror());
1.92      pooka     587:                        if (prog_setsockopt(s, IPPROTO_IP, IP_IPSEC_POLICY,
1.55      itojun    588:                                        buf, ipsec_get_policylen(buf)) < 0) {
                    589:                                err(1, "ipsec policy cannot be configured");
                    590:                        }
                    591:                        free(buf);
                    592:                }
1.50      itojun    593:        }
1.55      itojun    594:        buf = ipsec_set_policy("out bypass", strlen("out bypass"));
                    595:        if (buf == NULL)
1.57      is        596:                errx(1, "%s", ipsec_strerror());
1.92      pooka     597:        if (prog_setsockopt(sloop, IPPROTO_IP, IP_IPSEC_POLICY,
1.55      itojun    598:                        buf, ipsec_get_policylen(buf)) < 0) {
1.52      itojun    599: #if 0
1.50      itojun    600:                warnx("ipsec is not configured");
1.52      itojun    601: #else
                    602:                /* ignore it, should be okay */
                    603: #endif
                    604:        }
1.50      itojun    605:        free(buf);
                    606:     }
                    607: #else
                    608:     {
                    609:        int optval;
                    610:        if (pingflags & F_AUTHHDR) {
                    611:                optval = IPSEC_LEVEL_REQUIRE;
                    612: #ifdef IP_AUTH_TRANS_LEVEL
1.92      pooka     613:                (void)prog_setsockopt(s, IPPROTO_IP, IP_AUTH_TRANS_LEVEL,
1.50      itojun    614:                        (char *)&optval, sizeof(optval));
                    615: #else
1.92      pooka     616:                (void)prog_setsockopt(s, IPPROTO_IP, IP_AUTH_LEVEL,
1.50      itojun    617:                        (char *)&optval, sizeof(optval));
                    618: #endif
                    619:        }
                    620:        if (pingflags & F_ENCRYPT) {
                    621:                optval = IPSEC_LEVEL_REQUIRE;
1.92      pooka     622:                (void)prog_setsockopt(s, IPPROTO_IP, IP_ESP_TRANS_LEVEL,
1.50      itojun    623:                        (char *)&optval, sizeof(optval));
                    624:        }
                    625:        optval = IPSEC_LEVEL_BYPASS;
                    626: #ifdef IP_AUTH_TRANS_LEVEL
1.92      pooka     627:        (void)prog_setsockopt(sloop, IPPROTO_IP, IP_AUTH_TRANS_LEVEL,
1.50      itojun    628:                (char *)&optval, sizeof(optval));
                    629: #else
1.92      pooka     630:        (void)prog_setsockopt(sloop, IPPROTO_IP, IP_AUTH_LEVEL,
1.50      itojun    631:                (char *)&optval, sizeof(optval));
                    632: #endif
1.92      pooka     633:        (void)prog_setsockopt(sloop, IPPROTO_IP, IP_ESP_TRANS_LEVEL,
1.50      itojun    634:                (char *)&optval, sizeof(optval));
                    635:     }
                    636: #endif /*IPSEC_POLICY_IPSEC*/
                    637: #endif /*IPSEC*/
1.8       mycroft   638:
1.30      christos  639:        (void)printf("PING %s (%s): %d data bytes\n", hostname,
1.101.2.3  yamt      640:                     inet_ntoa(whereto.sin_addr), datalen + phdrlen);
1.22      christos  641:
                    642:        /* When pinging the broadcast address, you can get a lot
                    643:         * of answers.  Doing something so evil is useful if you
                    644:         * are trying to stress the ethernet, or just want to
                    645:         * fill the arp cache to get some stuff for /etc/ethers.
1.1       cgd       646:         */
1.92      pooka     647:        while (0 > prog_setsockopt(s, SOL_SOCKET, SO_RCVBUF,
1.22      christos  648:                              (char*)&bufspace, sizeof(bufspace))) {
1.60      yamt      649:                if ((bufspace -= 4096) <= 0)
1.22      christos  650:                        err(1, "Cannot set the receive buffer size");
                    651:        }
1.1       cgd       652:
1.30      christos  653:        /* make it possible to send giant probes, but do not worry now
                    654:         * if it fails, since we probably won't send giant probes.
                    655:         */
1.92      pooka     656:        (void)prog_setsockopt(s, SOL_SOCKET, SO_SNDBUF,
1.30      christos  657:                         (char*)&bufspace, sizeof(bufspace));
1.22      christos  658:
                    659:        (void)signal(SIGINT, prefinish);
1.48      mjl       660:
1.22      christos  661: #ifdef SIGINFO
1.81      christos  662:        sa.sa_handler = prtsig;
                    663:        sa.sa_flags = SA_NOKERNINFO;
                    664:        sigemptyset(&sa.sa_mask);
                    665:        (void)sigaction(SIGINFO, &sa, NULL);
1.22      christos  666: #else
                    667:        (void)signal(SIGQUIT, prtsig);
                    668: #endif
                    669:        (void)signal(SIGCONT, prtsig);
                    670:
                    671:        /* fire off them quickies */
                    672:        for (i = 0; i < preload; i++) {
1.99      christos  673:                clock_gettime(CLOCK_MONOTONIC, &now);
1.1       cgd       674:                pinger();
1.22      christos  675:        }
                    676:
                    677:        doit();
                    678:        return 0;
                    679: }
                    680:
                    681:
                    682: static void
                    683: doit(void)
                    684: {
                    685:        int cc;
                    686:        struct sockaddr_in from;
1.78      mrg       687:        socklen_t fromlen;
1.30      christos  688:        double sec, last, d_last;
1.67      mycroft   689:        struct pollfd fdmaskp[1];
1.1       cgd       690:
1.99      christos  691:        (void)clock_gettime(CLOCK_MONOTONIC, &clear_cache);
1.30      christos  692:        if (maxwait != 0) {
1.99      christos  693:                last = timespec_to_sec(&clear_cache) + maxwait;
1.30      christos  694:                d_last = 0;
                    695:        } else {
                    696:                last = 0;
                    697:                d_last = 365*24*60*60;
                    698:        }
1.1       cgd       699:
1.30      christos  700:        do {
1.99      christos  701:                clock_gettime(CLOCK_MONOTONIC, &now);
1.22      christos  702:
1.30      christos  703:                if (last != 0)
1.99      christos  704:                        d_last = last - timespec_to_sec(&now);
1.22      christos  705:
1.30      christos  706:                if (ntransmitted < npackets && d_last > 0) {
1.22      christos  707:                        /* send if within 100 usec or late for next packet */
1.95      christos  708:                        sec = diffsec(&next_tx, &now);
1.75      itojun    709:                        if (sec <= 0.0001 ||
                    710:                            (lastrcvd && (pingflags & F_FLOOD))) {
1.22      christos  711:                                pinger();
1.95      christos  712:                                sec = diffsec(&next_tx, &now);
1.22      christos  713:                        }
                    714:                        if (sec < 0.0)
                    715:                                sec = 0.0;
1.30      christos  716:                        if (d_last < sec)
                    717:                                sec = d_last;
1.22      christos  718:
                    719:                } else {
                    720:                        /* For the last response, wait twice as long as the
                    721:                         * worst case seen, or 10 times as long as the
                    722:                         * maximum interpacket interval, whichever is longer.
                    723:                         */
1.75      itojun    724:                        sec = MAX(2 * tmax, 10 * interval) -
                    725:                            diffsec(&now, &last_tx);
1.30      christos  726:                        if (d_last < sec)
                    727:                                sec = d_last;
1.22      christos  728:                        if (sec <= 0)
1.30      christos  729:                                break;
1.22      christos  730:                }
                    731:
1.67      mycroft   732:                fdmaskp[0].fd = s;
                    733:                fdmaskp[0].events = POLLIN;
1.92      pooka     734:                cc = prog_poll(fdmaskp, 1, (int)(sec * 1000));
1.22      christos  735:                if (cc <= 0) {
                    736:                        if (cc < 0) {
                    737:                                if (errno == EINTR)
                    738:                                        continue;
                    739:                                jiggle_flush(1);
1.68      mycroft   740:                                err(1, "poll");
1.22      christos  741:                        }
                    742:                        continue;
1.1       cgd       743:                }
1.22      christos  744:
                    745:                fromlen  = sizeof(from);
1.92      pooka     746:                cc = prog_recvfrom(s, (char *) packet, packlen,
1.30      christos  747:                              0, (struct sockaddr *)&from,
1.22      christos  748:                              &fromlen);
                    749:                if (cc < 0) {
                    750:                        if (errno != EINTR) {
                    751:                                jiggle_flush(1);
1.30      christos  752:                                warn("recvfrom");
1.22      christos  753:                                (void)fflush(stderr);
                    754:                        }
1.1       cgd       755:                        continue;
                    756:                }
1.99      christos  757:                clock_gettime(CLOCK_MONOTONIC, &now);
1.22      christos  758:                pr_pack(packet, cc, &from);
1.30      christos  759:
                    760:        } while (nreceived < npackets
                    761:                 && (nreceived == 0 || !(pingflags & F_ONCE)));
                    762:
                    763:        finish(0);
1.22      christos  764: }
                    765:
                    766:
                    767: static void
                    768: jiggle_flush(int nl)                   /* new line if there are dots */
                    769: {
                    770:        int serrno = errno;
                    771:
                    772:        if (jiggle_cnt > 0) {
                    773:                total_jiggled += jiggle_cnt;
                    774:                jiggle_direction = 1;
                    775:                do {
                    776:                        (void)putchar('.');
                    777:                } while (--jiggle_cnt > 0);
                    778:
                    779:        } else if (jiggle_cnt < 0) {
                    780:                total_jiggled -= jiggle_cnt;
                    781:                jiggle_direction = -1;
                    782:                do {
                    783:                        (void)putchar('\b');
                    784:                } while (++jiggle_cnt < 0);
                    785:        }
                    786:
                    787:        if (nl) {
                    788:                if (total_jiggled != 0)
                    789:                        (void)putchar('\n');
                    790:                total_jiggled = 0;
                    791:                jiggle_direction = -1;
1.1       cgd       792:        }
1.22      christos  793:
                    794:        (void)fflush(stdout);
                    795:        (void)fflush(stderr);
                    796:        jiggle_time = now;
                    797:        errno = serrno;
1.1       cgd       798: }
                    799:
1.22      christos  800:
                    801: /* jiggle the cursor for flood-ping
1.1       cgd       802:  */
1.22      christos  803: static void
                    804: jiggle(int delta)
1.1       cgd       805: {
1.22      christos  806:        double dt;
1.1       cgd       807:
1.22      christos  808:        if (pingflags & F_QUIET)
                    809:                return;
                    810:
                    811:        /* do not back up into messages */
                    812:        if (total_jiggled+jiggle_cnt+delta < 0)
                    813:                return;
                    814:
                    815:        jiggle_cnt += delta;
                    816:
                    817:        /* flush the FLOOD dots when things are quiet
                    818:         * or occassionally to make the cursor jiggle.
                    819:         */
                    820:        dt = diffsec(&last_tx, &jiggle_time);
                    821:        if (dt > 0.2 || (dt >= 0.15 && delta*jiggle_direction < 0))
                    822:                jiggle_flush(0);
1.1       cgd       823: }
                    824:
1.22      christos  825:
1.1       cgd       826: /*
1.22      christos  827:  * Compose and transmit an ICMP ECHO REQUEST packet.  The IP packet
1.30      christos  828:  * will be added on by the kernel.  The ID field is our UNIX process ID,
1.99      christos  829:  * and the sequence number is an ascending integer.  The first phdrlen bytes
1.1       cgd       830:  * of the data portion are used to hold a UNIX "timeval" struct in VAX
1.99      christos  831:  * byte-order, to compute the round-trip time, or a UNIX "timespec" in native
                    832:  * format.
1.1       cgd       833:  */
1.22      christos  834: static void
                    835: pinger(void)
1.1       cgd       836: {
1.75      itojun    837:        struct tv32 tv32;
1.30      christos  838:        int i, cc, sw;
1.22      christos  839:
                    840:        opack_icmp.icmp_code = 0;
1.65      itojun    841:        opack_icmp.icmp_seq = htons((u_int16_t)(ntransmitted));
1.30      christos  842:
                    843:        /* clear the cached route in the kernel after an ICMP
                    844:         * response such as a Redirect is seen to stop causing
                    845:         * more such packets.  Also clear the cached route
                    846:         * periodically in case of routing changes that make
                    847:         * black holes come and go.
                    848:         */
1.22      christos  849:        if (clear_cache.tv_sec != now.tv_sec) {
                    850:                opack_icmp.icmp_type = ICMP_ECHOREPLY;
                    851:                opack_icmp.icmp_id = ~ident;
                    852:                opack_icmp.icmp_cksum = 0;
1.65      itojun    853:                opack_icmp.icmp_cksum = in_cksum((u_int16_t *)&opack_icmp,
1.99      christos  854:                    phdrlen);
1.30      christos  855:                sw = 0;
1.92      pooka     856:                if (prog_setsockopt(sloop,IPPROTO_IP,IP_HDRINCL,
1.30      christos  857:                               (char *)&sw,sizeof(sw)) < 0)
                    858:                        err(1, "Can't turn off special IP header");
1.92      pooka     859:                if (prog_sendto(sloop, (char *) &opack_icmp,
1.101.2.3  yamt      860:                           ICMP_MINLEN, MSG_DONTROUTE,
1.30      christos  861:                           (struct sockaddr *)&loc_addr,
1.34      christos  862:                           sizeof(struct sockaddr_in)) < 0) {
                    863:                        /*
                    864:                         * XXX: we only report this as a warning in verbose
                    865:                         * mode because people get confused when they see
                    866:                         * this error when they are running in single user
                    867:                         * mode and they have not configured lo0
                    868:                         */
                    869:                        if (pingflags & F_VERBOSE)
                    870:                                warn("failed to clear cached route");
                    871:                }
1.30      christos  872:                sw = 1;
1.92      pooka     873:                if (prog_setsockopt(sloop,IPPROTO_IP,IP_HDRINCL,
1.30      christos  874:                               (char *)&sw, sizeof(sw)) < 0)
                    875:                        err(1, "Can't set special IP header");
                    876:
1.99      christos  877:                (void)clock_gettime(CLOCK_MONOTONIC, &clear_cache);
1.22      christos  878:        }
1.30      christos  879:
1.22      christos  880:        opack_icmp.icmp_type = ICMP_ECHO;
                    881:        opack_icmp.icmp_id = ident;
1.99      christos  882:
                    883:        if (pingflags & F_TIMING) {
                    884:                tv32.tv32_sec = (uint32_t)htonl(now.tv_sec);
                    885:                tv32.tv32_usec = htonl(now.tv_nsec / 1000);
1.75      itojun    886:                (void) memcpy(&opack_icmp.icmp_data[0], &tv32, sizeof(tv32));
1.99      christos  887:        } else if (pingflags & F_TIMING64)
                    888:                (void) memcpy(&opack_icmp.icmp_data[0], &now, sizeof(now));
                    889:
1.101.2.3  yamt      890:        cc = MAX(datalen, ICMP_MINLEN) + phdrlen;
1.22      christos  891:        opack_icmp.icmp_cksum = 0;
1.65      itojun    892:        opack_icmp.icmp_cksum = in_cksum((u_int16_t *)&opack_icmp, cc);
1.22      christos  893:
1.30      christos  894:        cc += opack_ip->ip_hl<<2;
                    895:        opack_ip->ip_len = cc;
1.92      pooka     896:        i = prog_sendto(s, (char *) opack_ip, cc, 0,
1.30      christos  897:                   (struct sockaddr *)&send_addr, sizeof(struct sockaddr_in));
1.22      christos  898:        if (i != cc) {
                    899:                jiggle_flush(1);
                    900:                if (i < 0)
1.30      christos  901:                        warn("sendto");
1.22      christos  902:                else
1.30      christos  903:                        warnx("wrote %s %d chars, ret=%d", hostname, cc, i);
1.22      christos  904:                (void)fflush(stderr);
                    905:        }
                    906:        lastrcvd = 0;
                    907:
                    908:        CLR(ntransmitted);
                    909:        ntransmitted++;
                    910:
                    911:        last_tx = now;
                    912:        if (next_tx.tv_sec == 0) {
                    913:                first_tx = now;
                    914:                next_tx = now;
                    915:        }
1.1       cgd       916:
1.22      christos  917:        /* Transmit regularly, at always the same microsecond in the
                    918:         * second when going at one packet per second.
                    919:         * If we are at most 100 ms behind, send extras to get caught up.
                    920:         * Otherwise, skip packets we were too slow to send.
                    921:         */
                    922:        if (diffsec(&next_tx, &now) <= interval) {
                    923:                do {
1.99      christos  924:                        timespecadd(&next_tx, &interval_tv, &next_tx);
1.22      christos  925:                } while (diffsec(&next_tx, &now) < -0.1);
                    926:        }
1.1       cgd       927:
1.22      christos  928:        if (pingflags & F_FLOOD)
                    929:                jiggle(1);
1.1       cgd       930:
1.22      christos  931:        /* While the packet is going out, ready buffer for the next
                    932:         * packet. Use a fast but not very good random number generator.
                    933:         */
                    934:        if (pingflags & F_PING_RANDOM)
                    935:                rnd_fill();
                    936: }
1.1       cgd       937:
                    938:
1.22      christos  939: static void
1.30      christos  940: pr_pack_sub(int cc,
                    941:            char *addr,
                    942:            int seqno,
                    943:            int dupflag,
                    944:            int ttl,
1.22      christos  945:            double triptime)
                    946: {
                    947:        jiggle_flush(1);
1.1       cgd       948:
1.22      christos  949:        if (pingflags & F_FLOOD)
                    950:                return;
1.1       cgd       951:
1.22      christos  952:        (void)printf("%d bytes from %s: icmp_seq=%u", cc, addr, seqno);
1.30      christos  953:        if (dupflag)
                    954:                (void)printf(" DUP!");
1.22      christos  955:        (void)printf(" ttl=%d", ttl);
1.101.2.4! yamt      956:        if (pingflags & (F_TIMING|F_TIMING64)) {
        !           957:                const unsigned int prec = (pingflags & F_TIMING64) != 0 ? 6 : 3;
        !           958:
        !           959:                (void)printf(" time=%.*f ms", prec, triptime*1000.0);
        !           960:        }
1.49      sommerfe  961:
                    962:        /*
                    963:         * Send beep to stderr, since that's more likely than stdout
                    964:         * to go to a terminal..
                    965:         */
                    966:        if (pingflags & F_AUDIBLE && !dupflag)
                    967:                (void)fprintf(stderr,"\a");
1.1       cgd       968: }
                    969:
1.22      christos  970:
1.1       cgd       971: /*
1.22      christos  972:  * Print out the packet, if it came from us.  This logic is necessary
1.1       cgd       973:  * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
                    974:  * which arrive ('tis only fair).  This permits multiple copies of this
                    975:  * program to be run without having intermingled output (or statistics!).
                    976:  */
1.22      christos  977: static void
1.30      christos  978: pr_pack(u_char *buf,
1.41      christos  979:        int tot_len,
1.22      christos  980:        struct sockaddr_in *from)
1.1       cgd       981: {
1.22      christos  982:        struct ip *ip;
1.32      lukem     983:        struct icmp *icp;
1.41      christos  984:        int i, j, net_len;
1.32      lukem     985:        u_char *cp;
1.1       cgd       986:        static int old_rrlen;
                    987:        static char old_rr[MAX_IPOPTLEN];
1.22      christos  988:        int hlen, dupflag = 0, dumped;
                    989:        double triptime = 0.0;
                    990: #define PR_PACK_SUB() {if (!dumped) {                  \
                    991:        dumped = 1;                                     \
1.41      christos  992:        pr_pack_sub(net_len, inet_ntoa(from->sin_addr), \
1.65      itojun    993:                    ntohs((u_int16_t)icp->icmp_seq),    \
1.22      christos  994:                    dupflag, ip->ip_ttl, triptime);}}
1.1       cgd       995:
                    996:        /* Check the IP header */
1.22      christos  997:        ip = (struct ip *) buf;
1.1       cgd       998:        hlen = ip->ip_hl << 2;
1.41      christos  999:        if (tot_len < hlen + ICMP_MINLEN) {
1.22      christos 1000:                if (pingflags & F_VERBOSE) {
                   1001:                        jiggle_flush(1);
1.30      christos 1002:                        (void)printf("packet too short (%d bytes) from %s\n",
1.41      christos 1003:                                     tot_len, inet_ntoa(from->sin_addr));
1.22      christos 1004:                }
1.1       cgd      1005:                return;
                   1006:        }
                   1007:
                   1008:        /* Now the ICMP part */
1.22      christos 1009:        dumped = 0;
1.41      christos 1010:        net_len = tot_len - hlen;
1.1       cgd      1011:        icp = (struct icmp *)(buf + hlen);
1.22      christos 1012:        if (icp->icmp_type == ICMP_ECHOREPLY
                   1013:            && icp->icmp_id == ident) {
1.99      christos 1014:
1.65      itojun   1015:                if (icp->icmp_seq == htons((u_int16_t)(ntransmitted-1)))
1.22      christos 1016:                        lastrcvd = 1;
                   1017:                last_rx = now;
                   1018:                if (first_rx.tv_sec == 0)
                   1019:                        first_rx = last_rx;
                   1020:                nreceived++;
1.101.2.4! yamt     1021:                if (pingflags & (F_TIMING|F_TIMING64)) {
        !          1022:                        struct timespec tv;
1.75      itojun   1023:
1.101.2.4! yamt     1024:                        if (pingflags & F_TIMING) {
        !          1025:                                struct tv32 tv32;
        !          1026:
        !          1027:                                (void)memcpy(&tv32, icp->icmp_data, sizeof(tv32));
        !          1028:                                tv.tv_sec = (uint32_t)ntohl(tv32.tv32_sec);
        !          1029:                                tv.tv_nsec = ntohl(tv32.tv32_usec) * 1000;
        !          1030:                        } else if (pingflags & F_TIMING64)
        !          1031:                                (void)memcpy(&tv, icp->icmp_data, sizeof(tv));
        !          1032:                        else
        !          1033:                                memset(&tv, 0, sizeof(tv));     /* XXX: gcc */
1.99      christos 1034:
1.26      christos 1035:                        triptime = diffsec(&last_rx, &tv);
1.1       cgd      1036:                        tsum += triptime;
1.44      jwise    1037:                        tsumsq += triptime * triptime;
1.1       cgd      1038:                        if (triptime < tmin)
                   1039:                                tmin = triptime;
                   1040:                        if (triptime > tmax)
                   1041:                                tmax = triptime;
                   1042:                }
                   1043:
1.65      itojun   1044:                if (TST(ntohs((u_int16_t)icp->icmp_seq))) {
1.22      christos 1045:                        nrepeats++, nreceived--;
                   1046:                        dupflag=1;
1.30      christos 1047:                } else {
1.65      itojun   1048:                        SET(ntohs((u_int16_t)icp->icmp_seq));
1.30      christos 1049:                }
1.1       cgd      1050:
1.41      christos 1051:                if (tot_len != opack_ip->ip_len) {
                   1052:                        PR_PACK_SUB();
1.88      christos 1053:                        switch (opack_ip->ip_len - tot_len) {
                   1054:                        case MAX_IPOPTLEN:
                   1055:                                if ((pongflags & F_RECORD_ROUTE) != 0)
                   1056:                                        break;
                   1057:                                if ((pingflags & F_RECORD_ROUTE) == 0)
                   1058:                                        goto out;
                   1059:                                pongflags |= F_RECORD_ROUTE;
                   1060:                                (void)printf("\nremote host does not "
                   1061:                                    "support record route");
                   1062:                                break;
                   1063:                        case 8:
                   1064:                                if ((pongflags & F_SOURCE_ROUTE) != 0)
                   1065:                                        break;
                   1066:                                if ((pingflags & F_SOURCE_ROUTE) == 0)
                   1067:                                        goto out;
                   1068:                                pongflags |= F_SOURCE_ROUTE;
                   1069:                                (void)printf("\nremote host does not "
                   1070:                                    "support source route");
                   1071:                                break;
                   1072:                        default:
                   1073:                        out:
                   1074:                                (void)printf("\nwrong total length %d "
                   1075:                                    "instead of %d", tot_len, opack_ip->ip_len);
                   1076:                                break;
                   1077:                        }
1.66      matt     1078:                }
                   1079:
                   1080:                if (!dupflag) {
                   1081:                        static u_int16_t last_seqno = 0xffff;
                   1082:                        u_int16_t seqno = ntohs((u_int16_t)icp->icmp_seq);
                   1083:                        u_int16_t gap = seqno - (last_seqno + 1);
                   1084:                        if (gap > 0 && gap < 0x8000 &&
                   1085:                            (pingflags & F_VERBOSE)) {
                   1086:                                (void)printf("[*** sequence gap of %u "
                   1087:                                    "packets from %u ... %u ***]\n", gap,
                   1088:                                    (u_int16_t) (last_seqno + 1),
                   1089:                                    (u_int16_t) (seqno - 1));
                   1090:                                if (pingflags & F_QUIET)
                   1091:                                        summary(0);
                   1092:                        }
                   1093:
                   1094:                        if (gap < 0x8000)
                   1095:                                last_seqno = seqno;
1.41      christos 1096:                }
                   1097:
1.22      christos 1098:                if (pingflags & F_QUIET)
1.1       cgd      1099:                        return;
                   1100:
1.22      christos 1101:                if (!(pingflags & F_FLOOD))
                   1102:                        PR_PACK_SUB();
                   1103:
                   1104:                /* check the data */
1.101.2.3  yamt     1105:                if ((size_t)(tot_len - hlen) >
                   1106:                    offsetof(struct icmp, icmp_data) + datalen
1.22      christos 1107:                    && !(pingflags & F_PING_RANDOM)
1.99      christos 1108:                    && memcmp(icp->icmp_data + phdrlen,
                   1109:                            opack_icmp.icmp_data + phdrlen,
                   1110:                            datalen - phdrlen)) {
                   1111:                        for (i = phdrlen; i < datalen; i++) {
1.54      mycroft  1112:                                if (icp->icmp_data[i] !=
                   1113:                                    opack_icmp.icmp_data[i])
1.1       cgd      1114:                                        break;
1.22      christos 1115:                        }
                   1116:                        PR_PACK_SUB();
                   1117:                        (void)printf("\nwrong data byte #%d should have been"
1.54      mycroft  1118:                                     " %#x but was %#x", i,
                   1119:                                     (u_char)opack_icmp.icmp_data[i],
1.22      christos 1120:                                     (u_char)icp->icmp_data[i]);
1.99      christos 1121:                        for (i = phdrlen; i < datalen; i++) {
1.101.2.3  yamt     1122:                                if ((i % 16) == 0)
1.22      christos 1123:                                        (void)printf("\n\t");
1.30      christos 1124:                                (void)printf("%2x ",(u_char)icp->icmp_data[i]);
1.1       cgd      1125:                        }
                   1126:                }
1.22      christos 1127:
1.1       cgd      1128:        } else {
1.41      christos 1129:                if (!pr_icmph(icp, from, net_len))
1.1       cgd      1130:                        return;
1.22      christos 1131:                dumped = 2;
1.1       cgd      1132:        }
                   1133:
                   1134:        /* Display any IP options */
1.22      christos 1135:        cp = buf + sizeof(struct ip);
                   1136:        while (hlen > (int)sizeof(struct ip)) {
1.1       cgd      1137:                switch (*cp) {
                   1138:                case IPOPT_EOL:
                   1139:                        hlen = 0;
                   1140:                        break;
                   1141:                case IPOPT_LSRR:
                   1142:                        hlen -= 2;
                   1143:                        j = *++cp;
                   1144:                        ++cp;
1.22      christos 1145:                        j -= IPOPT_MINOFF;
                   1146:                        if (j <= 0)
                   1147:                                continue;
                   1148:                        if (dumped <= 1) {
                   1149:                                j = ((j+3)/4)*4;
                   1150:                                hlen -= j;
                   1151:                                cp += j;
                   1152:                                break;
                   1153:                        }
                   1154:                        PR_PACK_SUB();
                   1155:                        (void)printf("\nLSRR: ");
                   1156:                        for (;;) {
1.57      is       1157:                                pr_saddr(cp);
1.22      christos 1158:                                cp += 4;
1.1       cgd      1159:                                hlen -= 4;
                   1160:                                j -= 4;
1.22      christos 1161:                                if (j <= 0)
1.1       cgd      1162:                                        break;
                   1163:                                (void)putchar('\n');
                   1164:                        }
                   1165:                        break;
                   1166:                case IPOPT_RR:
1.22      christos 1167:                        j = *++cp;      /* get length */
                   1168:                        i = *++cp;      /* and pointer */
1.1       cgd      1169:                        hlen -= 2;
                   1170:                        if (i > j)
                   1171:                                i = j;
                   1172:                        i -= IPOPT_MINOFF;
                   1173:                        if (i <= 0)
                   1174:                                continue;
1.22      christos 1175:                        if (dumped <= 1) {
                   1176:                                if (i == old_rrlen
1.30      christos 1177:                                    && !memcmp(cp, old_rr, i)) {
1.22      christos 1178:                                        if (dumped)
                   1179:                                            (void)printf("\t(same route)");
                   1180:                                        j = ((i+3)/4)*4;
                   1181:                                        hlen -= j;
                   1182:                                        cp += j;
                   1183:                                        break;
                   1184:                                }
                   1185:                                old_rrlen = i;
1.30      christos 1186:                                (void) memcpy(old_rr, cp, i);
1.22      christos 1187:                        }
                   1188:                        if (!dumped) {
                   1189:                                jiggle_flush(1);
                   1190:                                (void)printf("RR: ");
                   1191:                                dumped = 1;
                   1192:                        } else {
                   1193:                                (void)printf("\nRR: ");
1.1       cgd      1194:                        }
                   1195:                        for (;;) {
1.57      is       1196:                                pr_saddr(cp);
1.22      christos 1197:                                cp += 4;
1.1       cgd      1198:                                hlen -= 4;
                   1199:                                i -= 4;
                   1200:                                if (i <= 0)
                   1201:                                        break;
                   1202:                                (void)putchar('\n');
                   1203:                        }
                   1204:                        break;
                   1205:                case IPOPT_NOP:
1.22      christos 1206:                        if (dumped <= 1)
                   1207:                                break;
                   1208:                        PR_PACK_SUB();
1.1       cgd      1209:                        (void)printf("\nNOP");
                   1210:                        break;
1.22      christos 1211: #ifdef sgi
                   1212:                case IPOPT_SECURITY:    /* RFC 1108 RIPSO BSO */
                   1213:                case IPOPT_ESO:         /* RFC 1108 RIPSO ESO */
                   1214:                case IPOPT_CIPSO:       /* Commercial IPSO */
                   1215:                        if ((sysconf(_SC_IP_SECOPTS)) > 0) {
                   1216:                                i = (unsigned)cp[1];
                   1217:                                hlen -= i - 1;
                   1218:                                PR_PACK_SUB();
                   1219:                                (void)printf("\nSEC:");
                   1220:                                while (i--) {
                   1221:                                        (void)printf(" %02x", *cp++);
                   1222:                                }
                   1223:                                cp--;
                   1224:                                break;
                   1225:                        }
                   1226: #endif
1.1       cgd      1227:                default:
1.22      christos 1228:                        PR_PACK_SUB();
1.32      lukem    1229:                        (void)printf("\nunknown option 0x%x", *cp);
1.1       cgd      1230:                        break;
                   1231:                }
1.22      christos 1232:                hlen--;
                   1233:                cp++;
                   1234:        }
                   1235:
                   1236:        if (dumped) {
1.1       cgd      1237:                (void)putchar('\n');
                   1238:                (void)fflush(stdout);
1.22      christos 1239:        } else {
                   1240:                jiggle(-1);
                   1241:        }
                   1242: }
                   1243:
                   1244:
                   1245: /* Compute the IP checksum
                   1246:  *     This assumes the packet is less than 32K long.
                   1247:  */
1.65      itojun   1248: static u_int16_t
                   1249: in_cksum(u_int16_t *p, u_int len)
1.22      christos 1250: {
1.65      itojun   1251:        u_int32_t sum = 0;
1.22      christos 1252:        int nwords = len >> 1;
                   1253:
                   1254:        while (nwords-- != 0)
                   1255:                sum += *p++;
                   1256:
                   1257:        if (len & 1) {
                   1258:                union {
1.65      itojun   1259:                        u_int16_t w;
                   1260:                        u_int8_t c[2];
1.22      christos 1261:                } u;
                   1262:                u.c[0] = *(u_char *)p;
                   1263:                u.c[1] = 0;
                   1264:                sum += u.w;
1.1       cgd      1265:        }
1.22      christos 1266:
                   1267:        /* end-around-carry */
                   1268:        sum = (sum >> 16) + (sum & 0xffff);
                   1269:        sum += (sum >> 16);
                   1270:        return (~sum);
1.1       cgd      1271: }
                   1272:
1.22      christos 1273:
1.1       cgd      1274: /*
1.99      christos 1275:  * compute the difference of two timespecs in seconds
1.1       cgd      1276:  */
1.22      christos 1277: static double
1.99      christos 1278: diffsec(struct timespec *timenow,
                   1279:        struct timespec *then)
1.22      christos 1280: {
1.97      christos 1281:        if (timenow->tv_sec == 0)
                   1282:                return -1;
1.99      christos 1283:        return (timenow->tv_sec - then->tv_sec)
                   1284:            * 1.0 + (timenow->tv_nsec - then->tv_nsec) / 1000000000.0;
1.22      christos 1285: }
                   1286:
                   1287:
1.99      christos 1288: #if 0
1.22      christos 1289: static void
1.99      christos 1290: timespecadd(struct timespec *t1,
                   1291:           struct timespec *t2)
1.22      christos 1292: {
                   1293:
                   1294:        t1->tv_sec += t2->tv_sec;
1.99      christos 1295:        if ((t1->tv_nsec += t2->tv_nsec) >= 1000000000) {
1.22      christos 1296:                t1->tv_sec++;
1.99      christos 1297:                t1->tv_nsec -= 1000000000;
1.22      christos 1298:        }
                   1299: }
1.99      christos 1300: #endif
1.22      christos 1301:
                   1302:
                   1303: static void
1.99      christos 1304: sec_to_timespec(const double sec, struct timespec *tp)
1.22      christos 1305: {
1.30      christos 1306:        tp->tv_sec = sec;
1.99      christos 1307:        tp->tv_nsec = (sec - tp->tv_sec) * 1000000000.0;
1.22      christos 1308: }
1.1       cgd      1309:
1.41      christos 1310:
1.22      christos 1311: static double
1.99      christos 1312: timespec_to_sec(const struct timespec *tp)
1.22      christos 1313: {
1.99      christos 1314:        return tp->tv_sec + tp->tv_nsec / 1000000000.0;
1.1       cgd      1315: }
                   1316:
1.22      christos 1317:
1.1       cgd      1318: /*
1.22      christos 1319:  * Print statistics.
                   1320:  * Heavily buffered STDIO is used here, so that all the statistics
                   1321:  * will be written with 1 sys-write call.  This is nice when more
                   1322:  * than one copy of the program is running on a terminal;  it prevents
                   1323:  * the statistics output from becomming intermingled.
1.1       cgd      1324:  */
1.22      christos 1325: static void
                   1326: summary(int header)
1.1       cgd      1327: {
1.22      christos 1328:        jiggle_flush(1);
1.8       mycroft  1329:
1.22      christos 1330:        if (header)
                   1331:                (void)printf("\n----%s PING Statistics----\n", hostname);
                   1332:        (void)printf("%d packets transmitted, ", ntransmitted);
                   1333:        (void)printf("%d packets received, ", nreceived);
1.1       cgd      1334:        if (nrepeats)
1.22      christos 1335:                (void)printf("+%d duplicates, ", nrepeats);
                   1336:        if (ntransmitted) {
1.1       cgd      1337:                if (nreceived > ntransmitted)
1.64      itojun   1338:                        (void)printf("-- somebody's duplicating packets!");
1.1       cgd      1339:                else
1.41      christos 1340:                        (void)printf("%.1f%% packet loss",
                   1341:                                     (((ntransmitted-nreceived)*100.0) /
1.22      christos 1342:                                            ntransmitted));
                   1343:        }
                   1344:        (void)printf("\n");
1.101     christos 1345:        if (nreceived && (pingflags & (F_TIMING|F_TIMING64))) {
1.44      jwise    1346:                double n = nreceived + nrepeats;
                   1347:                double avg = (tsum / n);
1.47      sommerfe 1348:                double variance = 0.0;
1.101.2.4! yamt     1349:                const unsigned int prec = (pingflags & F_TIMING64) != 0 ? 6 : 3;
1.47      sommerfe 1350:                if (n>1)
                   1351:                        variance = (tsumsq - n*avg*avg) /(n-1);
1.44      jwise    1352:
                   1353:                printf("round-trip min/avg/max/stddev = "
1.101.2.4! yamt     1354:                        "%.*f/%.*f/%.*f/%.*f ms\n",
        !          1355:                        prec, tmin * 1000.0,
        !          1356:                        prec, avg * 1000.0,
        !          1357:                        prec, tmax * 1000.0,
        !          1358:                        prec, sqrt(variance) * 1000.0);
1.22      christos 1359:                if (pingflags & F_FLOOD) {
                   1360:                        double r = diffsec(&last_rx, &first_rx);
                   1361:                        double t = diffsec(&last_tx, &first_tx);
                   1362:                        if (r == 0)
                   1363:                                r = 0.0001;
                   1364:                        if (t == 0)
                   1365:                                t = 0.0001;
                   1366:                        (void)printf("  %.1f packets/sec sent, "
1.30      christos 1367:                                     " %.1f packets/sec received\n",
1.22      christos 1368:                                     ntransmitted/t, nreceived/r);
                   1369:                }
1.8       mycroft  1370:        }
1.21      cgd      1371: }
                   1372:
1.22      christos 1373:
                   1374: /*
                   1375:  * Print statistics when SIGINFO is received.
                   1376:  */
                   1377: /* ARGSUSED */
                   1378: static void
1.62      lukem    1379: prtsig(int dummy)
1.22      christos 1380: {
1.82      yamt     1381:
1.22      christos 1382:        summary(0);
1.81      christos 1383: #ifndef SIGINFO
1.22      christos 1384:        (void)signal(SIGQUIT, prtsig);
                   1385: #endif
                   1386: }
                   1387:
                   1388:
1.21      cgd      1389: /*
1.22      christos 1390:  * On the first SIGINT, allow any outstanding packets to dribble in
1.21      cgd      1391:  */
1.22      christos 1392: static void
1.62      lukem    1393: prefinish(int dummy)
1.21      cgd      1394: {
1.22      christos 1395:        if (lastrcvd                    /* quit now if caught up */
                   1396:            || nreceived == 0)          /* or if remote is dead */
                   1397:                finish(0);
                   1398:
1.62      lukem    1399:        (void)signal(dummy, finish);    /* do this only the 1st time */
1.21      cgd      1400:
1.22      christos 1401:        if (npackets > ntransmitted)    /* let the normal limit work */
                   1402:                npackets = ntransmitted;
1.21      cgd      1403: }
                   1404:
                   1405: /*
1.22      christos 1406:  * Print statistics and give up.
1.21      cgd      1407:  */
1.22      christos 1408: /* ARGSUSED */
                   1409: static void
1.62      lukem    1410: finish(int dummy)
1.21      cgd      1411: {
1.81      christos 1412: #ifdef SIGINFO
                   1413:        (void)signal(SIGINFO, SIG_DFL);
1.22      christos 1414: #else
                   1415:        (void)signal(SIGQUIT, SIG_DFL);
                   1416: #endif
                   1417:
                   1418:        summary(1);
1.30      christos 1419:        exit(nreceived > 0 ? 0 : 2);
1.22      christos 1420: }
                   1421:
                   1422:
                   1423: static int                             /* 0=do not print it */
1.30      christos 1424: ck_pr_icmph(struct icmp *icp,
                   1425:            struct sockaddr_in *from,
                   1426:            int cc,
1.22      christos 1427:            int override)               /* 1=override VERBOSE if interesting */
                   1428: {
                   1429:        int     hlen;
1.41      christos 1430:        struct ip ipb, *ip = &ipb;
                   1431:        struct icmp icp2b, *icp2 = &icp2b;
1.22      christos 1432:        int res;
1.21      cgd      1433:
1.22      christos 1434:        if (pingflags & F_VERBOSE) {
                   1435:                res = 1;
                   1436:                jiggle_flush(1);
                   1437:        } else {
                   1438:                res = 0;
                   1439:        }
1.21      cgd      1440:
1.41      christos 1441:        (void) memcpy(ip, icp->icmp_data, sizeof(*ip));
                   1442:        hlen = ip->ip_hl << 2;
                   1443:        if (ip->ip_p == IPPROTO_ICMP
1.22      christos 1444:            && hlen + 6 <= cc) {
1.41      christos 1445:                (void) memcpy(icp2, &icp->icmp_data[hlen], sizeof(*icp2));
                   1446:                if (icp2->icmp_id == ident) {
1.22      christos 1447:                        /* remember to clear route cached in kernel
1.41      christos 1448:                         * if this non-Echo-Reply ICMP message was for one
                   1449:                         * of our packets.
1.22      christos 1450:                         */
                   1451:                        clear_cache.tv_sec = 0;
                   1452:
                   1453:                        if (!res && override
                   1454:                            && (pingflags & (F_QUIET|F_SEMI_QUIET)) == 0) {
                   1455:                                jiggle_flush(1);
1.30      christos 1456:                                (void)printf("%d bytes from %s: ",
1.22      christos 1457:                                             cc, pr_addr(&from->sin_addr));
                   1458:                                res = 1;
                   1459:                        }
                   1460:                }
                   1461:        }
                   1462:
                   1463:        return res;
1.1       cgd      1464: }
                   1465:
                   1466:
                   1467: /*
1.22      christos 1468:  *  Print a descriptive string about an ICMP header other than an echo reply.
1.1       cgd      1469:  */
1.22      christos 1470: static int                             /* 0=printed nothing */
1.30      christos 1471: pr_icmph(struct icmp *icp,
                   1472:         struct sockaddr_in *from,
1.22      christos 1473:         int cc)
1.1       cgd      1474: {
1.22      christos 1475:        switch (icp->icmp_type ) {
1.1       cgd      1476:        case ICMP_UNREACH:
1.22      christos 1477:                if (!ck_pr_icmph(icp, from, cc, 1))
                   1478:                        return 0;
                   1479:                switch (icp->icmp_code) {
1.1       cgd      1480:                case ICMP_UNREACH_NET:
1.22      christos 1481:                        (void)printf("Destination Net Unreachable");
1.1       cgd      1482:                        break;
                   1483:                case ICMP_UNREACH_HOST:
1.22      christos 1484:                        (void)printf("Destination Host Unreachable");
1.1       cgd      1485:                        break;
                   1486:                case ICMP_UNREACH_PROTOCOL:
1.22      christos 1487:                        (void)printf("Destination Protocol Unreachable");
1.1       cgd      1488:                        break;
                   1489:                case ICMP_UNREACH_PORT:
1.22      christos 1490:                        (void)printf("Destination Port Unreachable");
1.1       cgd      1491:                        break;
                   1492:                case ICMP_UNREACH_NEEDFRAG:
1.30      christos 1493:                        (void)printf("frag needed and DF set.  Next MTU=%d",
1.36      kleink   1494:                               ntohs(icp->icmp_nextmtu));
1.1       cgd      1495:                        break;
                   1496:                case ICMP_UNREACH_SRCFAIL:
1.22      christos 1497:                        (void)printf("Source Route Failed");
                   1498:                        break;
                   1499:                case ICMP_UNREACH_NET_UNKNOWN:
                   1500:                        (void)printf("Unreachable unknown net");
                   1501:                        break;
                   1502:                case ICMP_UNREACH_HOST_UNKNOWN:
                   1503:                        (void)printf("Unreachable unknown host");
                   1504:                        break;
                   1505:                case ICMP_UNREACH_ISOLATED:
                   1506:                        (void)printf("Unreachable host isolated");
                   1507:                        break;
                   1508:                case ICMP_UNREACH_NET_PROHIB:
                   1509:                        (void)printf("Net prohibited access");
                   1510:                        break;
                   1511:                case ICMP_UNREACH_HOST_PROHIB:
                   1512:                        (void)printf("Host prohibited access");
                   1513:                        break;
                   1514:                case ICMP_UNREACH_TOSNET:
                   1515:                        (void)printf("Bad TOS for net");
                   1516:                        break;
                   1517:                case ICMP_UNREACH_TOSHOST:
                   1518:                        (void)printf("Bad TOS for host");
                   1519:                        break;
                   1520:                case 13:
                   1521:                        (void)printf("Communication prohibited");
                   1522:                        break;
                   1523:                case 14:
                   1524:                        (void)printf("Host precedence violation");
                   1525:                        break;
                   1526:                case 15:
                   1527:                        (void)printf("Precedence cutoff");
1.1       cgd      1528:                        break;
                   1529:                default:
1.30      christos 1530:                        (void)printf("Bad Destination Unreachable Code: %d",
1.22      christos 1531:                                     icp->icmp_code);
1.1       cgd      1532:                        break;
                   1533:                }
                   1534:                /* Print returned IP header information */
1.22      christos 1535:                pr_retip(icp, cc);
1.1       cgd      1536:                break;
1.22      christos 1537:
1.1       cgd      1538:        case ICMP_SOURCEQUENCH:
1.22      christos 1539:                if (!ck_pr_icmph(icp, from, cc, 1))
                   1540:                        return 0;
                   1541:                (void)printf("Source Quench");
                   1542:                pr_retip(icp, cc);
1.1       cgd      1543:                break;
1.22      christos 1544:
1.1       cgd      1545:        case ICMP_REDIRECT:
1.22      christos 1546:                if (!ck_pr_icmph(icp, from, cc, 1))
                   1547:                        return 0;
                   1548:                switch (icp->icmp_code) {
1.1       cgd      1549:                case ICMP_REDIRECT_NET:
1.41      christos 1550:                        (void)printf("Redirect Network");
1.1       cgd      1551:                        break;
                   1552:                case ICMP_REDIRECT_HOST:
1.41      christos 1553:                        (void)printf("Redirect Host");
1.1       cgd      1554:                        break;
                   1555:                case ICMP_REDIRECT_TOSNET:
1.41      christos 1556:                        (void)printf("Redirect Type of Service and Network");
1.1       cgd      1557:                        break;
                   1558:                case ICMP_REDIRECT_TOSHOST:
1.41      christos 1559:                        (void)printf("Redirect Type of Service and Host");
1.1       cgd      1560:                        break;
                   1561:                default:
1.41      christos 1562:                        (void)printf("Redirect--Bad Code: %d", icp->icmp_code);
1.1       cgd      1563:                        break;
                   1564:                }
1.41      christos 1565:                (void)printf(" New router addr: %s",
1.22      christos 1566:                             pr_addr(&icp->icmp_hun.ih_gwaddr));
                   1567:                pr_retip(icp, cc);
                   1568:                break;
                   1569:
                   1570:        case ICMP_ECHO:
                   1571:                if (!ck_pr_icmph(icp, from, cc, 0))
                   1572:                        return 0;
1.30      christos 1573:                (void)printf("Echo Request: ID=%d seq=%d",
1.41      christos 1574:                             ntohs(icp->icmp_id), ntohs(icp->icmp_seq));
1.22      christos 1575:                break;
                   1576:
                   1577:        case ICMP_ECHOREPLY:
                   1578:                /* displaying other's pings is too noisey */
                   1579: #if 0
                   1580:                if (!ck_pr_icmph(icp, from, cc, 0))
                   1581:                        return 0;
1.30      christos 1582:                (void)printf("Echo Reply: ID=%d seq=%d",
1.41      christos 1583:                             ntohs(icp->icmp_id), ntohs(icp->icmp_seq));
1.22      christos 1584:                break;
1.1       cgd      1585: #else
1.22      christos 1586:                return 0;
1.1       cgd      1587: #endif
1.22      christos 1588:
                   1589:        case ICMP_ROUTERADVERT:
                   1590:                if (!ck_pr_icmph(icp, from, cc, 0))
                   1591:                        return 0;
                   1592:                (void)printf("Router Discovery Advert");
1.1       cgd      1593:                break;
1.22      christos 1594:
                   1595:        case ICMP_ROUTERSOLICIT:
                   1596:                if (!ck_pr_icmph(icp, from, cc, 0))
                   1597:                        return 0;
                   1598:                (void)printf("Router Discovery Solicit");
1.1       cgd      1599:                break;
1.22      christos 1600:
1.1       cgd      1601:        case ICMP_TIMXCEED:
1.22      christos 1602:                if (!ck_pr_icmph(icp, from, cc, 1))
                   1603:                        return 0;
                   1604:                switch (icp->icmp_code ) {
1.1       cgd      1605:                case ICMP_TIMXCEED_INTRANS:
1.22      christos 1606:                        (void)printf("Time To Live exceeded");
1.1       cgd      1607:                        break;
                   1608:                case ICMP_TIMXCEED_REASS:
1.22      christos 1609:                        (void)printf("Frag reassembly time exceeded");
1.1       cgd      1610:                        break;
                   1611:                default:
1.30      christos 1612:                        (void)printf("Time exceeded, Bad Code: %d",
1.22      christos 1613:                                     icp->icmp_code);
1.1       cgd      1614:                        break;
                   1615:                }
1.22      christos 1616:                pr_retip(icp, cc);
1.1       cgd      1617:                break;
1.22      christos 1618:
1.1       cgd      1619:        case ICMP_PARAMPROB:
1.22      christos 1620:                if (!ck_pr_icmph(icp, from, cc, 1))
                   1621:                        return 0;
1.30      christos 1622:                (void)printf("Parameter problem: pointer = 0x%02x",
1.22      christos 1623:                             icp->icmp_hun.ih_pptr);
                   1624:                pr_retip(icp, cc);
1.1       cgd      1625:                break;
1.22      christos 1626:
1.1       cgd      1627:        case ICMP_TSTAMP:
1.22      christos 1628:                if (!ck_pr_icmph(icp, from, cc, 0))
                   1629:                        return 0;
                   1630:                (void)printf("Timestamp");
1.1       cgd      1631:                break;
1.22      christos 1632:
1.1       cgd      1633:        case ICMP_TSTAMPREPLY:
1.22      christos 1634:                if (!ck_pr_icmph(icp, from, cc, 0))
                   1635:                        return 0;
                   1636:                (void)printf("Timestamp Reply");
1.1       cgd      1637:                break;
1.22      christos 1638:
1.1       cgd      1639:        case ICMP_IREQ:
1.22      christos 1640:                if (!ck_pr_icmph(icp, from, cc, 0))
                   1641:                        return 0;
                   1642:                (void)printf("Information Request");
1.1       cgd      1643:                break;
1.22      christos 1644:
1.1       cgd      1645:        case ICMP_IREQREPLY:
1.22      christos 1646:                if (!ck_pr_icmph(icp, from, cc, 0))
                   1647:                        return 0;
                   1648:                (void)printf("Information Reply");
1.1       cgd      1649:                break;
1.22      christos 1650:
1.1       cgd      1651:        case ICMP_MASKREQ:
1.22      christos 1652:                if (!ck_pr_icmph(icp, from, cc, 0))
                   1653:                        return 0;
                   1654:                (void)printf("Address Mask Request");
1.1       cgd      1655:                break;
1.22      christos 1656:
1.1       cgd      1657:        case ICMP_MASKREPLY:
1.22      christos 1658:                if (!ck_pr_icmph(icp, from, cc, 0))
                   1659:                        return 0;
                   1660:                (void)printf("Address Mask Reply");
1.1       cgd      1661:                break;
1.22      christos 1662:
1.1       cgd      1663:        default:
1.22      christos 1664:                if (!ck_pr_icmph(icp, from, cc, 0))
                   1665:                        return 0;
                   1666:                (void)printf("Bad ICMP type: %d", icp->icmp_type);
                   1667:                if (pingflags & F_VERBOSE)
                   1668:                        pr_iph(icp, cc);
1.1       cgd      1669:        }
1.22      christos 1670:
                   1671:        return 1;
1.1       cgd      1672: }
                   1673:
1.22      christos 1674:
1.1       cgd      1675: /*
1.22      christos 1676:  *  Print an IP header with options.
1.1       cgd      1677:  */
1.22      christos 1678: static void
1.30      christos 1679: pr_iph(struct icmp *icp,
1.22      christos 1680:        int cc)
1.1       cgd      1681: {
1.22      christos 1682:        int     hlen;
                   1683:        u_char  *cp;
1.41      christos 1684:        struct ip ipb, *ip = &ipb;
1.26      christos 1685:
1.41      christos 1686:        (void) memcpy(ip, icp->icmp_data, sizeof(*ip));
1.1       cgd      1687:
1.41      christos 1688:        hlen = ip->ip_hl << 2;
1.30      christos 1689:        cp = (u_char *) &icp->icmp_data[20];    /* point to options */
1.1       cgd      1690:
1.22      christos 1691:        (void)printf("\n Vr HL TOS  Len   ID Flg  off TTL Pro  cks      Src          Dst\n");
1.30      christos 1692:        (void)printf("  %1x  %1x  %02x %04x %04x",
1.41      christos 1693:                     ip->ip_v, ip->ip_hl, ip->ip_tos, ip->ip_len, ip->ip_id);
1.30      christos 1694:        (void)printf("   %1x %04x",
1.41      christos 1695:                     ((ip->ip_off)&0xe000)>>13, (ip->ip_off)&0x1fff);
1.30      christos 1696:        (void)printf("  %02x  %02x %04x",
1.41      christos 1697:                     ip->ip_ttl, ip->ip_p, ip->ip_sum);
1.30      christos 1698:        (void)printf(" %15s ",
1.41      christos 1699:                     inet_ntoa(*(struct in_addr *)&ip->ip_src.s_addr));
                   1700:        (void)printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_dst.s_addr));
1.22      christos 1701:        /* dump any option bytes */
                   1702:        while (hlen-- > 20 && cp < (u_char*)icp+cc) {
1.1       cgd      1703:                (void)printf("%02x", *cp++);
                   1704:        }
                   1705: }
                   1706:
                   1707: /*
1.22      christos 1708:  * Print an ASCII host address starting from a string of bytes.
1.1       cgd      1709:  */
1.22      christos 1710: static void
1.57      is       1711: pr_saddr(u_char *cp)
1.22      christos 1712: {
1.32      lukem    1713:        n_long l;
1.22      christos 1714:        struct in_addr addr;
                   1715:
                   1716:        l = (u_char)*++cp;
                   1717:        l = (l<<8) + (u_char)*++cp;
                   1718:        l = (l<<8) + (u_char)*++cp;
                   1719:        l = (l<<8) + (u_char)*++cp;
                   1720:        addr.s_addr = htonl(l);
1.57      is       1721:        (void)printf("\t%s", (l == 0) ? "0.0.0.0" : pr_addr(&addr));
1.22      christos 1722: }
                   1723:
                   1724:
                   1725: /*
                   1726:  *  Return an ASCII host address
                   1727:  *  as a dotted quad and optionally with a hostname
                   1728:  */
                   1729: static char *
                   1730: pr_addr(struct in_addr *addr)          /* in network order */
                   1731: {
                   1732:        struct  hostent *hp;
                   1733:        static  char buf[MAXHOSTNAMELEN+4+16+1];
                   1734:
                   1735:        if ((pingflags & F_NUMERIC)
                   1736:            || !(hp = gethostbyaddr((char *)addr, sizeof(*addr), AF_INET))) {
1.37      mycroft  1737:                (void)snprintf(buf, sizeof(buf), "%s", inet_ntoa(*addr));
1.22      christos 1738:        } else {
1.37      mycroft  1739:                (void)snprintf(buf, sizeof(buf), "%s (%s)", hp->h_name,
                   1740:                    inet_ntoa(*addr));
1.22      christos 1741:        }
                   1742:
                   1743:        return buf;
1.1       cgd      1744: }
                   1745:
                   1746: /*
1.22      christos 1747:  *  Dump some info on a returned (via ICMP) IP packet.
1.1       cgd      1748:  */
1.22      christos 1749: static void
1.30      christos 1750: pr_retip(struct icmp *icp,
1.22      christos 1751:         int cc)
1.1       cgd      1752: {
1.22      christos 1753:        int     hlen;
1.30      christos 1754:        u_char  *cp;
1.41      christos 1755:        struct ip ipb, *ip = &ipb;
1.26      christos 1756:
1.41      christos 1757:        (void) memcpy(ip, icp->icmp_data, sizeof(*ip));
1.22      christos 1758:
                   1759:        if (pingflags & F_VERBOSE)
                   1760:                pr_iph(icp, cc);
1.1       cgd      1761:
1.41      christos 1762:        hlen = ip->ip_hl << 2;
1.30      christos 1763:        cp = (u_char *) &icp->icmp_data[hlen];
1.1       cgd      1764:
1.41      christos 1765:        if (ip->ip_p == IPPROTO_TCP) {
1.22      christos 1766:                if (pingflags & F_VERBOSE)
1.30      christos 1767:                        (void)printf("\n  TCP: from port %u, to port %u",
1.22      christos 1768:                                     (*cp*256+*(cp+1)), (*(cp+2)*256+*(cp+3)));
1.41      christos 1769:        } else if (ip->ip_p == IPPROTO_UDP) {
1.22      christos 1770:                if (pingflags & F_VERBOSE)
1.30      christos 1771:                        (void)printf("\n  UDP: from port %u, to port %u",
1.22      christos 1772:                                     (*cp*256+*(cp+1)), (*(cp+2)*256+*(cp+3)));
1.41      christos 1773:        } else if (ip->ip_p == IPPROTO_ICMP) {
1.26      christos 1774:                struct icmp icp2;
                   1775:                (void) memcpy(&icp2, cp, sizeof(icp2));
                   1776:                if (icp2.icmp_type == ICMP_ECHO) {
                   1777:                        if (pingflags & F_VERBOSE)
1.30      christos 1778:                                (void)printf("\n  ID=%u icmp_seq=%u",
1.65      itojun   1779:                                             ntohs((u_int16_t)icp2.icmp_id),
                   1780:                                             ntohs((u_int16_t)icp2.icmp_seq));
1.26      christos 1781:                        else
1.30      christos 1782:                                (void)printf(" for icmp_seq=%u",
1.65      itojun   1783:                                             ntohs((u_int16_t)icp2.icmp_seq));
1.26      christos 1784:                }
1.22      christos 1785:        }
1.1       cgd      1786: }
                   1787:
1.22      christos 1788: static void
                   1789: fill(void)
1.1       cgd      1790: {
1.32      lukem    1791:        int i, j, k;
1.22      christos 1792:        char *cp;
1.1       cgd      1793:        int pat[16];
                   1794:
1.22      christos 1795:        for (cp = fill_pat; *cp != '\0'; cp++) {
1.43      christos 1796:                if (!isxdigit((unsigned char)*cp))
1.22      christos 1797:                        break;
                   1798:        }
                   1799:        if (cp == fill_pat || *cp != '\0' || (cp-fill_pat) > 16*2) {
                   1800:                (void)fflush(stdout);
1.30      christos 1801:                errx(1, "\"-p %s\": patterns must be specified with"
                   1802:                     " 1-32 hex digits\n",
                   1803:                     fill_pat);
1.22      christos 1804:        }
                   1805:
1.30      christos 1806:        i = sscanf(fill_pat,
                   1807:                   "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
                   1808:                    &pat[0], &pat[1], &pat[2], &pat[3],
                   1809:                    &pat[4], &pat[5], &pat[6], &pat[7],
                   1810:                    &pat[8], &pat[9], &pat[10], &pat[11],
1.22      christos 1811:                    &pat[12], &pat[13], &pat[14], &pat[15]);
                   1812:
1.99      christos 1813:        for (k = phdrlen, j = 0; k <= datalen; k++) {
1.22      christos 1814:                opack_icmp.icmp_data[k] = pat[j];
                   1815:                if (++j >= i)
                   1816:                        j = 0;
                   1817:        }
                   1818:
                   1819:        if (!(pingflags & F_QUIET)) {
1.1       cgd      1820:                (void)printf("PATTERN: 0x");
1.22      christos 1821:                for (j=0; j<i; j++)
1.30      christos 1822:                        (void)printf("%02x",
1.99      christos 1823:                                     (u_char)opack_icmp.icmp_data[phdrlen + j]);
1.1       cgd      1824:                (void)printf("\n");
                   1825:        }
1.22      christos 1826:
1.1       cgd      1827: }
                   1828:
1.22      christos 1829:
                   1830: static void
                   1831: rnd_fill(void)
                   1832: {
1.41      christos 1833:        static u_int32_t rnd;
1.22      christos 1834:        int i;
                   1835:
1.99      christos 1836:        for (i = phdrlen; i < datalen; i++) {
1.41      christos 1837:                rnd = (3141592621U * rnd + 663896637U);
                   1838:                opack_icmp.icmp_data[i] = rnd>>24;
1.22      christos 1839:        }
                   1840: }
                   1841:
1.41      christos 1842:
1.22      christos 1843: static void
1.30      christos 1844: gethost(const char *arg,
                   1845:        const char *name,
                   1846:        struct sockaddr_in *sa,
                   1847:        char *realname,
                   1848:        int realname_len)
1.22      christos 1849: {
1.30      christos 1850:        struct hostent *hp;
1.22      christos 1851:
1.33      cgd      1852:        (void)memset(sa, 0, sizeof(*sa));
1.30      christos 1853:        sa->sin_family = AF_INET;
1.69      itojun   1854:        sa->sin_len = sizeof(struct sockaddr_in);
1.22      christos 1855:
1.30      christos 1856:        /* If it is an IP address, try to convert it to a name to
                   1857:         * have something nice to display.
                   1858:         */
                   1859:        if (inet_aton(name, &sa->sin_addr) != 0) {
                   1860:                if (realname) {
                   1861:                        if (pingflags & F_NUMERIC)
                   1862:                                hp = 0;
                   1863:                        else
                   1864:                                hp = gethostbyaddr((char *)&sa->sin_addr,
                   1865:                                                   sizeof(sa->sin_addr),
                   1866:                                                   AF_INET);
1.69      itojun   1867:                        (void)strlcpy(realname, hp ? hp->h_name : name,
                   1868:                            realname_len);
1.30      christos 1869:                }
1.22      christos 1870:                return;
1.30      christos 1871:        }
                   1872:
                   1873:        hp = gethostbyname(name);
                   1874:        if (!hp)
                   1875:                errx(1, "Cannot resolve \"%s\" (%s)",name,hstrerror(h_errno));
                   1876:
                   1877:        if (hp->h_addrtype != AF_INET)
                   1878:                errx(1, "%s only supported with IP", arg);
                   1879:
1.41      christos 1880:        (void)memcpy(&sa->sin_addr, hp->h_addr, sizeof(sa->sin_addr));
1.30      christos 1881:
1.69      itojun   1882:        if (realname)
                   1883:                (void)strlcpy(realname, hp->h_name, realname_len);
1.22      christos 1884: }
                   1885:
                   1886:
                   1887: static void
                   1888: usage(void)
1.1       cgd      1889: {
1.50      itojun   1890: #ifdef IPSEC
                   1891: #ifdef IPSEC_POLICY_IPSEC
                   1892: #define IPSECOPT       "\n     [-E policy] "
                   1893: #else
                   1894: #define IPSECOPT       "\n     [-AE] "
                   1895: #endif /*IPSEC_POLICY_IPSEC*/
                   1896: #else
                   1897: #define IPSECOPT       ""
                   1898: #endif /*IPSEC*/
1.42      enami    1899:
1.74      jmmv     1900:        (void)fprintf(stderr, "usage: \n"
1.100     wiz      1901:            "%s [-aCDdfLnoPQqRrv] [-c count] [-g gateway] [-h host]"
                   1902:            " [-I addr] [-i interval]\n"
                   1903:            "     [-l preload] [-p pattern] [-s size] [-T ttl] [-t tos]"
1.50      itojun   1904:            " [-w maxwait] " IPSECOPT "host\n",
1.59      cgd      1905:            getprogname());
1.1       cgd      1906:        exit(1);
                   1907: }

CVSweb <webmaster@jp.NetBSD.org>