[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.65

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

CVSweb <webmaster@jp.NetBSD.org>