Annotation of 43BSDReno/sbin/ping/ping.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1989 The Regents of the University of California.
                      3:  * All rights reserved.
                      4:  *
                      5:  * This code is derived from software contributed to Berkeley by
                      6:  * Mike Muuss.
                      7:  *
                      8:  * Redistribution and use in source and binary forms are permitted
                      9:  * provided that: (1) source distributions retain this entire copyright
                     10:  * notice and comment, and (2) distributions including binaries display
                     11:  * the following acknowledgement:  ``This product includes software
                     12:  * developed by the University of California, Berkeley and its contributors''
                     13:  * in the documentation or other materials provided with the distribution
                     14:  * and in all advertising materials mentioning features or use of this
                     15:  * software. Neither the name of the University nor the names of its
                     16:  * contributors may be used to endorse or promote products derived
                     17:  * from this software without specific prior written permission.
                     18:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
                     19:  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
                     20:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
                     21:  */
                     22: 
                     23: #ifndef lint
                     24: char copyright[] =
                     25: "@(#) Copyright (c) 1989 The Regents of the University of California.\n\
                     26:  All rights reserved.\n";
                     27: #endif /* not lint */
                     28: 
                     29: #ifndef lint
                     30: static char sccsid[] = "@(#)ping.c     5.6 (Berkeley) 6/1/90";
                     31: #endif /* not lint */
                     32: 
                     33: /*
                     34:  *                     P I N G . C
                     35:  *
                     36:  * Using the InterNet Control Message Protocol (ICMP) "ECHO" facility,
                     37:  * measure round-trip-delays and packet loss across network paths.
                     38:  *
                     39:  * Author -
                     40:  *     Mike Muuss
                     41:  *     U. S. Army Ballistic Research Laboratory
                     42:  *     December, 1983
                     43:  *
                     44:  * Status -
                     45:  *     Public Domain.  Distribution Unlimited.
                     46:  * Bugs -
                     47:  *     More statistics could always be gathered.
                     48:  *     This program has to run SUID to ROOT to access the ICMP socket.
                     49:  */
                     50: 
                     51: #include <sys/param.h>
                     52: #include <sys/socket.h>
                     53: #include <sys/file.h>
                     54: #include <sys/time.h>
                     55: #include <sys/signal.h>
                     56: 
                     57: #include <netinet/in_systm.h>
                     58: #include <netinet/in.h>
                     59: #include <netinet/ip.h>
                     60: #include <netinet/ip_icmp.h>
                     61: #include <netinet/ip_var.h>
                     62: #include <netdb.h>
                     63: #include <unistd.h>
                     64: #include <stdio.h>
                     65: #include <ctype.h>
                     66: #include <errno.h>
                     67: #include <string.h>
                     68: 
                     69: #define        DEFDATALEN      (64 - 8)        /* default data length */
                     70: #define        MAXIPLEN        60
                     71: #define        MAXICMPLEN      76
                     72: #define        MAXPACKET       (65536 - 60 - 8)/* max packet size */
                     73: #define        MAXWAIT         10              /* max seconds to wait for response */
                     74: #define        NROUTES         9               /* number of record route slots */
                     75: 
                     76: #define        A(bit)          rcvd_tbl[(bit)>>3]      /* identify byte in array */
                     77: #define        B(bit)          (1 << ((bit) & 0x07))   /* identify bit in byte */
                     78: #define        SET(bit)        (A(bit) |= B(bit))
                     79: #define        CLR(bit)        (A(bit) &= (~B(bit)))
                     80: #define        TST(bit)        (A(bit) & B(bit))
                     81: 
                     82: /* various options */
                     83: int options;
                     84: #define        F_FLOOD         0x001
                     85: #define        F_INTERVAL      0x002
                     86: #define        F_NUMERIC       0x004
                     87: #define        F_PINGFILLED    0x008
                     88: #define        F_QUIET         0x010
                     89: #define        F_RROUTE        0x020
                     90: #define        F_SO_DEBUG      0x040
                     91: #define        F_SO_DONTROUTE  0x080
                     92: #define        F_VERBOSE       0x100
                     93: 
                     94: /*
                     95:  * MAX_DUP_CHK is the number of bits in received table, i.e. the maximum
                     96:  * number of received sequence numbers we can keep track of.  Change 128
                     97:  * to 8192 for complete accuracy...
                     98:  */
                     99: #define        MAX_DUP_CHK     (8 * 128)
                    100: int mx_dup_ck = MAX_DUP_CHK;
                    101: char rcvd_tbl[MAX_DUP_CHK / 8];
                    102: 
                    103: struct sockaddr whereto;       /* who to ping */
                    104: int datalen = DEFDATALEN;
                    105: int s;                         /* socket file descriptor */
                    106: u_char outpack[MAXPACKET];
                    107: char BSPACE = '\b';            /* characters written for flood */
                    108: char DOT = '.';
                    109: char *hostname;
                    110: int ident;                     /* process id to identify our packets */
                    111: 
                    112: /* counters */
                    113: long npackets;                 /* max packets to transmit */
                    114: long nreceived;                        /* # of packets we got back */
                    115: long nrepeats;                 /* number of duplicates */
                    116: long ntransmitted;             /* sequence # for outbound packets = #sent */
                    117: int interval = 1;              /* interval between packets */
                    118: 
                    119: /* timing */
                    120: int timing;                    /* flag to do timing */
                    121: long tmin = LONG_MAX;          /* minimum round trip time */
                    122: long tmax;                     /* maximum round trip time */
                    123: u_long tsum;                   /* sum of all times, for doing average */
                    124: 
                    125: u_long inet_addr();
                    126: char *inet_ntoa(), *pr_addr();
                    127: int catcher(), finish();
                    128: 
                    129: main(argc, argv)
                    130:        int argc;
                    131:        char **argv;
                    132: {
                    133:        extern int errno, optind;
                    134:        extern char *optarg;
                    135:        struct timeval timeout;
                    136:        struct hostent *hp;
                    137:        struct sockaddr_in *to;
                    138:        struct protoent *proto;
                    139:        register int i;
                    140:        int ch, fdmask, hold, packlen, preload;
                    141:        u_char *datap, *packet;
                    142:        char *target, hnamebuf[MAXHOSTNAMELEN], *malloc();
                    143: #ifdef IP_OPTIONS
                    144:        char rspace[3 + 4 * NROUTES + 1];       /* record route space */
                    145: #endif
                    146: 
                    147:        preload = 0;
                    148:        datap = &outpack[8 + sizeof(struct timeval)];
                    149:        while ((ch = getopt(argc, argv, "Rc:dfh:i:l:np:qrs:v")) != EOF)
                    150:                switch(ch) {
                    151:                case 'c':
                    152:                        npackets = atoi(optarg);
                    153:                        if (npackets <= 0) {
                    154:                                (void)fprintf(stderr,
                    155:                                    "ping: bad number of packets to transmit.\n");
                    156:                                exit(1);
                    157:                        }
                    158:                        break;
                    159:                case 'd':
                    160:                        options |= F_SO_DEBUG;
                    161:                        break;
                    162:                case 'f':
                    163:                        if (getuid()) {
                    164:                                (void)fprintf(stderr,
                    165:                                    "ping: you must be root to use the -f option.\n");
                    166:                                exit(1);
                    167:                        }
                    168:                        options |= F_FLOOD;
                    169:                        setbuf(stdout, (char *)NULL);
                    170:                        break;
                    171:                case 'i':               /* wait between sending packets */
                    172:                        interval = atoi(optarg);
                    173:                        if (interval <= 0) {
                    174:                                (void)fprintf(stderr,
                    175:                                    "ping: bad timing interval.\n");
                    176:                                exit(1);
                    177:                        }
                    178:                        options |= F_INTERVAL;
                    179:                        break;
                    180:                case 'l':
                    181:                        preload = atoi(optarg);
                    182:                        if (preload < 0) {
                    183:                                (void)fprintf(stderr,
                    184:                                    "ping: bad preload value.\n");
                    185:                                exit(1);
                    186:                        }
                    187:                        break;
                    188:                case 'n':
                    189:                        options |= F_NUMERIC;
                    190:                        break;
                    191:                case 'p':               /* fill buffer with user pattern */
                    192:                        options |= F_PINGFILLED;
                    193:                        fill((char *)datap, optarg);
                    194:                                break;
                    195:                case 'q':
                    196:                        options |= F_QUIET;
                    197:                        break;
                    198:                case 'R':
                    199:                        options |= F_RROUTE;
                    200:                        break;
                    201:                case 'r':
                    202:                        options |= F_SO_DONTROUTE;
                    203:                        break;
                    204:                case 's':               /* size of packet to send */
                    205:                        datalen = atoi(optarg);
                    206:                        if (datalen > MAXPACKET) {
                    207:                                (void)fprintf(stderr,
                    208:                                    "ping: packet size too large.\n");
                    209:                                exit(1);
                    210:                        }
                    211:                        if (datalen <= 0) {
                    212:                                (void)fprintf(stderr,
                    213:                                    "ping: illegal packet size.\n");
                    214:                                exit(1);
                    215:                        }
                    216:                        break;
                    217:                case 'v':
                    218:                        options |= F_VERBOSE;
                    219:                        break;
                    220:                default:
                    221:                        usage();
                    222:                }
                    223:        argc -= optind;
                    224:        argv += optind;
                    225: 
                    226:        if (argc != 1)
                    227:                usage();
                    228:        target = *argv;
                    229: 
                    230:        bzero((char *)&whereto, sizeof(struct sockaddr));
                    231:        to = (struct sockaddr_in *)&whereto;
                    232:        to->sin_family = AF_INET;
                    233:        to->sin_addr.s_addr = inet_addr(target);
                    234:        if (to->sin_addr.s_addr != (u_int)-1)
                    235:                hostname = target;
                    236:        else {
                    237:                hp = gethostbyname(target);
                    238:                if (!hp) {
                    239:                        (void)fprintf(stderr,
                    240:                            "ping: unknown host %s\n", target);
                    241:                        exit(1);
                    242:                }
                    243:                to->sin_family = hp->h_addrtype;
                    244:                bcopy(hp->h_addr, (caddr_t)&to->sin_addr, hp->h_length);
                    245:                (void)strncpy(hnamebuf, hp->h_name, sizeof(hnamebuf) - 1);
                    246:                hostname = hnamebuf;
                    247:        }
                    248: 
                    249:        if (options & F_FLOOD && options & F_INTERVAL) {
                    250:                (void)fprintf(stderr,
                    251:                    "ping: -f and -i incompatible options.\n");
                    252:                exit(1);
                    253:        }
                    254: 
                    255:        if (datalen >= sizeof(struct timeval))  /* can we time transfer */
                    256:                timing = 1;
                    257:        packlen = datalen + MAXIPLEN + MAXICMPLEN;
                    258:        if (!(packet = (u_char *)malloc((u_int)packlen))) {
                    259:                (void)fprintf(stderr, "ping: out of memory.\n");
                    260:                exit(1);
                    261:        }
                    262:        if (!(options & F_PINGFILLED))
                    263:                for (i = 8; i < datalen; ++i)
                    264:                        *datap++ = i;
                    265: 
                    266:        ident = getpid() & 0xFFFF;
                    267: 
                    268:        if (!(proto = getprotobyname("icmp"))) {
                    269:                (void)fprintf(stderr, "ping: unknown protocol icmp.\n");
                    270:                exit(1);
                    271:        }
                    272:        if ((s = socket(AF_INET, SOCK_RAW, proto->p_proto)) < 0) {
                    273:                perror("ping: socket");
                    274:                exit(1);
                    275:        }
                    276:        hold = 1;
                    277:        if (options & F_SO_DEBUG)
                    278:                (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&hold,
                    279:                    sizeof(hold));
                    280:        if (options & F_SO_DONTROUTE)
                    281:                (void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&hold,
                    282:                    sizeof(hold));
                    283: 
                    284:        /* record route option */
                    285:        if (options & F_RROUTE) {
                    286: #ifdef IP_OPTIONS
                    287:                rspace[IPOPT_OPTVAL] = IPOPT_RR;
                    288:                rspace[IPOPT_OLEN] = sizeof(rspace)-1;
                    289:                rspace[IPOPT_OFFSET] = IPOPT_MINOFF;
                    290:                if (setsockopt(s, IPPROTO_IP, IP_OPTIONS, rspace,
                    291:                    sizeof(rspace)) < 0) {
                    292:                        perror("ping: record route");
                    293:                        exit(1);
                    294:                }
                    295: #else
                    296:                (void)fprintf(stderr,
                    297:                  "ping: record route not available in this implementation.\n");
                    298:                exit(1);
                    299: #endif /* IP_OPTIONS */
                    300:        }
                    301: 
                    302:        /*
                    303:         * When pinging the broadcast address, you can get a lot of answers.
                    304:         * Doing something so evil is useful if you are trying to stress the
                    305:         * ethernet, or just want to fill the arp cache to get some stuff for
                    306:         * /etc/ethers.
                    307:         */
                    308:        hold = 48 * 1024;
                    309:        (void)setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&hold,
                    310:            sizeof(hold));
                    311: 
                    312:        if (to->sin_family == AF_INET)
                    313:                (void)printf("PING %s (%s): %d data bytes\n", hostname,
                    314:                    inet_ntoa(*(struct in_addr *)&to->sin_addr.s_addr),
                    315:                    datalen);
                    316:        else
                    317:                (void)printf("PING %s: %d data bytes\n", hostname, datalen);
                    318: 
                    319:        (void)signal(SIGINT, finish);
                    320:        (void)signal(SIGALRM, catcher);
                    321: 
                    322:        while (preload--)               /* fire off them quickies */
                    323:                pinger();
                    324: 
                    325:        if ((options & F_FLOOD) == 0)
                    326:                catcher();              /* start things going */
                    327: 
                    328:        for (;;) {
                    329:                struct sockaddr_in from;
                    330:                register int cc;
                    331:                int fromlen;
                    332: 
                    333:                if (options & F_FLOOD) {
                    334:                        pinger();
                    335:                        timeout.tv_sec = 0;
                    336:                        timeout.tv_usec = 10000;
                    337:                        fdmask = 1 << s;
                    338:                        if (select(s + 1, (fd_set *)&fdmask, (fd_set *)NULL,
                    339:                            (fd_set *)NULL, &timeout) < 1)
                    340:                                continue;
                    341:                }
                    342:                fromlen = sizeof(from);
                    343:                if ((cc = recvfrom(s, (char *)packet, packlen, 0,
                    344:                    (struct sockaddr *)&from, &fromlen)) < 0) {
                    345:                        if (errno == EINTR)
                    346:                                continue;
                    347:                        perror("ping: recvfrom");
                    348:                        continue;
                    349:                }
                    350:                pr_pack((char *)packet, cc, &from);
                    351:                if (npackets && nreceived >= npackets)
                    352:                        break;
                    353:        }
                    354:        finish();
                    355:        /* NOTREACHED */
                    356: }
                    357: 
                    358: /*
                    359:  * catcher --
                    360:  *     This routine causes another PING to be transmitted, and then
                    361:  * schedules another SIGALRM for 1 second from now.
                    362:  * 
                    363:  * bug --
                    364:  *     Our sense of time will slowly skew (i.e., packets will not be
                    365:  * launched exactly at 1-second intervals).  This does not affect the
                    366:  * quality of the delay and loss statistics.
                    367:  */
                    368: catcher()
                    369: {
                    370:        int waittime;
                    371: 
                    372:        pinger();
                    373:        (void)signal(SIGALRM, catcher);
                    374:        if (!npackets || ntransmitted < npackets)
                    375:                alarm((u_int)interval);
                    376:        else {
                    377:                if (nreceived) {
                    378:                        waittime = 2 * tmax / 1000;
                    379:                        if (!waittime)
                    380:                                waittime = 1;
                    381:                } else
                    382:                        waittime = MAXWAIT;
                    383:                (void)signal(SIGALRM, finish);
                    384:                (void)alarm((u_int)waittime);
                    385:        }
                    386: }
                    387: 
                    388: /*
                    389:  * pinger --
                    390:  *     Compose and transmit an ICMP ECHO REQUEST packet.  The IP packet
                    391:  * will be added on by the kernel.  The ID field is our UNIX process ID,
                    392:  * and the sequence number is an ascending integer.  The first 8 bytes
                    393:  * of the data portion are used to hold a UNIX "timeval" struct in VAX
                    394:  * byte-order, to compute the round-trip time.
                    395:  */
                    396: pinger()
                    397: {
                    398:        register struct icmp *icp;
                    399:        register int cc;
                    400:        int i;
                    401: 
                    402:        icp = (struct icmp *)outpack;
                    403:        icp->icmp_type = ICMP_ECHO;
                    404:        icp->icmp_code = 0;
                    405:        icp->icmp_cksum = 0;
                    406:        icp->icmp_seq = ntransmitted++;
                    407:        icp->icmp_id = ident;                   /* ID */
                    408: 
                    409:        CLR(icp->icmp_seq % mx_dup_ck);
                    410: 
                    411:        if (timing)
                    412:                (void)gettimeofday((struct timeval *)&outpack[8],
                    413:                    (struct timezone *)NULL);
                    414: 
                    415:        cc = datalen + 8;                       /* skips ICMP portion */
                    416: 
                    417:        /* compute ICMP checksum here */
                    418:        icp->icmp_cksum = in_cksum((u_short *)icp, cc);
                    419: 
                    420:        i = sendto(s, (char *)outpack, cc, 0, &whereto,
                    421:            sizeof(struct sockaddr));
                    422: 
                    423:        if (i < 0 || i != cc)  {
                    424:                if (i < 0)
                    425:                        perror("ping: sendto");
                    426:                (void)printf("ping: wrote %s %d chars, ret=%d\n",
                    427:                    hostname, cc, i);
                    428:        }
                    429:        if (options & F_FLOOD)
                    430:                (void)write(STDOUT_FILENO, &DOT, 1);
                    431: }
                    432: 
                    433: /*
                    434:  * pr_pack --
                    435:  *     Print out the packet, if it came from us.  This logic is necessary
                    436:  * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
                    437:  * which arrive ('tis only fair).  This permits multiple copies of this
                    438:  * program to be run without having intermingled output (or statistics!).
                    439:  */
                    440: pr_pack(buf, cc, from)
                    441:        char *buf;
                    442:        int cc;
                    443:        struct sockaddr_in *from;
                    444: {
                    445:        register struct icmp *icp;
                    446:        register u_long l;
                    447:        register int i, j;
                    448:        register u_char *cp,*dp;
                    449:        static int old_rrlen;
                    450:        static char old_rr[MAX_IPOPTLEN];
                    451:        struct ip *ip;
                    452:        struct timeval tv, *tp;
                    453:        long triptime;
                    454:        int hlen, dupflag;
                    455: 
                    456:        (void)gettimeofday(&tv, (struct timezone *)NULL);
                    457: 
                    458:        /* Check the IP header */
                    459:        ip = (struct ip *)buf;
                    460:        hlen = ip->ip_hl << 2;
                    461:        if (cc < hlen + ICMP_MINLEN) {
                    462:                if (options & F_VERBOSE)
                    463:                        (void)fprintf(stderr,
                    464:                          "ping: packet too short (%d bytes) from %s\n", cc,
                    465:                          inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr));
                    466:                return;
                    467:        }
                    468: 
                    469:        /* Now the ICMP part */
                    470:        cc -= hlen;
                    471:        icp = (struct icmp *)(buf + hlen);
                    472:        if (icp->icmp_type == ICMP_ECHOREPLY) {
                    473:                if (icp->icmp_id != ident)
                    474:                        return;                 /* 'Twas not our ECHO */
                    475:                ++nreceived;
                    476:                if (timing) {
                    477: #ifndef icmp_data
                    478:                        tp = (struct timeval *)&icp->icmp_ip;
                    479: #else
                    480:                        tp = (struct timeval *)icp->icmp_data;
                    481: #endif
                    482:                        tvsub(&tv, tp);
                    483:                        triptime = tv.tv_sec * 1000 + (tv.tv_usec / 1000);
                    484:                        tsum += triptime;
                    485:                        if (triptime < tmin)
                    486:                                tmin = triptime;
                    487:                        if (triptime > tmax)
                    488:                                tmax = triptime;
                    489:                }
                    490: 
                    491:                if (TST(icp->icmp_seq % mx_dup_ck)) {
                    492:                        ++nrepeats;
                    493:                        --nreceived;
                    494:                        dupflag = 1;
                    495:                } else {
                    496:                        SET(icp->icmp_seq % mx_dup_ck);
                    497:                        dupflag = 0;
                    498:                }
                    499: 
                    500:                if (options & F_QUIET)
                    501:                        return;
                    502: 
                    503:                if (options & F_FLOOD)
                    504:                        (void)write(STDOUT_FILENO, &BSPACE, 1);
                    505:                else {
                    506:                        (void)printf("%d bytes from %s: icmp_seq=%u", cc,
                    507:                           inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr),
                    508:                           icp->icmp_seq);
                    509:                        (void)printf(" ttl=%d", ip->ip_ttl);
                    510:                        if (timing)
                    511:                                (void)printf(" time=%ld ms", triptime);
                    512:                        if (dupflag)
                    513:                                (void)printf(" (DUP!)");
                    514:                        /* check the data */
                    515:                        cp = (u_char*)&icp->icmp_data[8];
                    516:                        dp = &outpack[8 + sizeof(struct timeval)];
                    517:                        for (i = 8; i < datalen; ++i, ++cp, ++dp) {
                    518:                                if (*cp != *dp) {
                    519:        (void)printf("\nwrong data byte #%d should be 0x%x but was 0x%x",
                    520:            i, *dp, *cp);
                    521:                                        cp = (u_char*)&icp->icmp_data[0];
                    522:                                        for (i = 8; i < datalen; ++i, ++cp) {
                    523:                                                if ((i % 32) == 8)
                    524:                                                        (void)printf("\n\t");
                    525:                                                (void)printf("%x ", *cp);
                    526:                                        }
                    527:                                        break;
                    528:                                }
                    529:                        }
                    530:                }
                    531:        } else {
                    532:                /* We've got something other than an ECHOREPLY */
                    533:                if (!(options & F_VERBOSE))
                    534:                        return;
                    535:                (void)printf("%d bytes from %s: ", cc,
                    536:                    pr_addr(from->sin_addr.s_addr));
                    537:                pr_icmph(icp);
                    538:        }
                    539: 
                    540:        /* Display any IP options */
                    541:        cp = (u_char *)buf + sizeof(struct ip);
                    542: 
                    543:        /* ANSI C will force hlen to unsigned! */
                    544:        for (; hlen > sizeof(struct ip); --hlen, ++cp)
                    545:                switch (*cp) {
                    546:                case IPOPT_EOL:
                    547:                        hlen = 0;
                    548:                        break;
                    549:                case IPOPT_LSRR:
                    550:                        (void)printf("\nLSRR: ");
                    551:                        hlen -= 2;
                    552:                        j = *++cp;
                    553:                        ++cp;
                    554:                        if (j > IPOPT_MINOFF)
                    555:                                for (;;) {
                    556:                                        l = *++cp;
                    557:                                        l = (l<<8) + *++cp;
                    558:                                        l = (l<<8) + *++cp;
                    559:                                        l = (l<<8) + *++cp;
                    560:                                        if (l == 0)
                    561:                                                (void)printf("\t0.0.0.0");
                    562:                                else
                    563:                                        (void)printf("\t%s", pr_addr(ntohl(l)));
                    564:                                hlen -= 4;
                    565:                                j -= 4;
                    566:                                if (j <= IPOPT_MINOFF)
                    567:                                        break;
                    568:                                (void)putchar('\n');
                    569:                        }
                    570:                        break;
                    571:                case IPOPT_RR:
                    572:                        j = *++cp;              /* get length */
                    573:                        i = *++cp;              /* and pointer */
                    574:                        hlen -= 2;
                    575:                        if (i > j)
                    576:                                i = j;
                    577:                        i -= IPOPT_MINOFF;
                    578:                        if (i <= 0)
                    579:                                continue;
                    580:                        if (i == old_rrlen
                    581:                            && cp == (u_char *)buf + sizeof(struct ip) + 2
                    582:                            && !bcmp((char *)cp, old_rr, i)
                    583:                            && !(options & F_FLOOD)) {
                    584:                                (void)printf("\t(same route)");
                    585:                                i = ((i + 3) / 4) * 4;
                    586:                                hlen -= i;
                    587:                                cp += i;
                    588:                                break;
                    589:                        }
                    590:                        old_rrlen = i;
                    591:                        bcopy((char *)cp, old_rr, i);
                    592:                        (void)printf("\nRR: ");
                    593:                        for (;;) {
                    594:                                l = *++cp;
                    595:                                l = (l<<8) + *++cp;
                    596:                                l = (l<<8) + *++cp;
                    597:                                l = (l<<8) + *++cp;
                    598:                                if (l == 0)
                    599:                                        (void)printf("\t0.0.0.0");
                    600:                                else
                    601:                                        (void)printf("\t%s", pr_addr(ntohl(l)));
                    602:                                hlen -= 4;
                    603:                                i -= 4;
                    604:                                if (i <= 0)
                    605:                                        break;
                    606:                                (void)putchar('\n');
                    607:                        }
                    608:                        break;
                    609:                case IPOPT_NOP:
                    610:                        (void)printf("\nNOP");
                    611:                        break;
                    612:                default:
                    613:                        (void)printf("\nunknown option %x", *cp);
                    614:                        break;
                    615:                }
                    616:        if (!(options & F_FLOOD)) {
                    617:                (void)putchar('\n');
                    618:                (void)fflush(stdout);
                    619:        }
                    620: }
                    621: 
                    622: /*
                    623:  * in_cksum --
                    624:  *     Checksum routine for Internet Protocol family headers (C Version)
                    625:  */
                    626: in_cksum(addr, len)
                    627:        u_short *addr;
                    628:        int len;
                    629: {
                    630:        register int nleft = len;
                    631:        register u_short *w = addr;
                    632:        register int sum = 0;
                    633:        u_short answer = 0;
                    634: 
                    635:        /*
                    636:         * Our algorithm is simple, using a 32 bit accumulator (sum), we add
                    637:         * sequential 16 bit words to it, and at the end, fold back all the
                    638:         * carry bits from the top 16 bits into the lower 16 bits.
                    639:         */
                    640:        while (nleft > 1)  {
                    641:                sum += *w++;
                    642:                nleft -= 2;
                    643:        }
                    644: 
                    645:        /* mop up an odd byte, if necessary */
                    646:        if (nleft == 1) {
                    647:                *(u_char *)(&answer) = *(u_char *)w ;
                    648:                sum += answer;
                    649:        }
                    650: 
                    651:        /* add back carry outs from top 16 bits to low 16 bits */
                    652:        sum = (sum >> 16) + (sum & 0xffff);     /* add hi 16 to low 16 */
                    653:        sum += (sum >> 16);                     /* add carry */
                    654:        answer = ~sum;                          /* truncate to 16 bits */
                    655:        return(answer);
                    656: }
                    657: 
                    658: /*
                    659:  * tvsub --
                    660:  *     Subtract 2 timeval structs:  out = out - in.  Out is assumed to
                    661:  * be >= in.
                    662:  */
                    663: tvsub(out, in)
                    664:        register struct timeval *out, *in;
                    665: {
                    666:        if ((out->tv_usec -= in->tv_usec) < 0) {
                    667:                --out->tv_sec;
                    668:                out->tv_usec += 1000000;
                    669:        }
                    670:        out->tv_sec -= in->tv_sec;
                    671: }
                    672: 
                    673: /*
                    674:  * finish --
                    675:  *     Print out statistics, and give up.
                    676:  */
                    677: finish()
                    678: {
                    679:        (void)signal(SIGINT, SIG_IGN);
                    680:        (void)putchar('\n');
                    681:        (void)fflush(stdout);
                    682:        (void)printf("--- %s ping statistics ---\n", hostname);
                    683:        (void)printf("%ld packets transmitted, ", ntransmitted);
                    684:        (void)printf("%ld packets received, ", nreceived);
                    685:        if (nrepeats)
                    686:                (void)printf("+%ld duplicates, ", nrepeats);
                    687:        if (ntransmitted)
                    688:                if (nreceived > ntransmitted)
                    689:                        (void)printf("-- somebody's printing up packets!");
                    690:                else
                    691:                        (void)printf("%d%% packet loss",
                    692:                            (int) (((ntransmitted - nreceived) * 100) /
                    693:                            ntransmitted));
                    694:        (void)putchar('\n');
                    695:        if (nreceived && timing)
                    696:                (void)printf("round-trip min/avg/max = %ld/%lu/%ld ms\n",
                    697:                    tmin, tsum / (nreceived + nrepeats), tmax);
                    698:        exit(0);
                    699: }
                    700: 
                    701: #ifdef notdef
                    702: static char *ttab[] = {
                    703:        "Echo Reply",           /* ip + seq + udata */
                    704:        "Dest Unreachable",     /* net, host, proto, port, frag, sr + IP */
                    705:        "Source Quench",        /* IP */
                    706:        "Redirect",             /* redirect type, gateway, + IP  */
                    707:        "Echo",
                    708:        "Time Exceeded",        /* transit, frag reassem + IP */
                    709:        "Parameter Problem",    /* pointer + IP */
                    710:        "Timestamp",            /* id + seq + three timestamps */
                    711:        "Timestamp Reply",      /* " */
                    712:        "Info Request",         /* id + sq */
                    713:        "Info Reply"            /* " */
                    714: };
                    715: #endif
                    716: 
                    717: /*
                    718:  * pr_icmph --
                    719:  *     Print a descriptive string about an ICMP header.
                    720:  */
                    721: pr_icmph(icp)
                    722:        struct icmp *icp;
                    723: {
                    724:        switch(icp->icmp_type) {
                    725:        case ICMP_ECHOREPLY:
                    726:                (void)printf("Echo Reply\n");
                    727:                /* XXX ID + Seq + Data */
                    728:                break;
                    729:        case ICMP_UNREACH:
                    730:                switch(icp->icmp_code) {
                    731:                case ICMP_UNREACH_NET:
                    732:                        (void)printf("Destination Net Unreachable\n");
                    733:                        break;
                    734:                case ICMP_UNREACH_HOST:
                    735:                        (void)printf("Destination Host Unreachable\n");
                    736:                        break;
                    737:                case ICMP_UNREACH_PROTOCOL:
                    738:                        (void)printf("Destination Protocol Unreachable\n");
                    739:                        break;
                    740:                case ICMP_UNREACH_PORT:
                    741:                        (void)printf("Destination Port Unreachable\n");
                    742:                        break;
                    743:                case ICMP_UNREACH_NEEDFRAG:
                    744:                        (void)printf("frag needed and DF set\n");
                    745:                        break;
                    746:                case ICMP_UNREACH_SRCFAIL:
                    747:                        (void)printf("Source Route Failed\n");
                    748:                        break;
                    749:                default:
                    750:                        (void)printf("Dest Unreachable, Bad Code: %d\n",
                    751:                            icp->icmp_code);
                    752:                        break;
                    753:                }
                    754:                /* Print returned IP header information */
                    755: #ifndef icmp_data
                    756:                pr_retip(&icp->icmp_ip);
                    757: #else
                    758:                pr_retip((struct ip *)icp->icmp_data);
                    759: #endif
                    760:                break;
                    761:        case ICMP_SOURCEQUENCH:
                    762:                (void)printf("Source Quench\n");
                    763: #ifndef icmp_data
                    764:                pr_retip(&icp->icmp_ip);
                    765: #else
                    766:                pr_retip((struct ip *)icp->icmp_data);
                    767: #endif
                    768:                break;
                    769:        case ICMP_REDIRECT:
                    770:                switch(icp->icmp_code) {
                    771:                case ICMP_REDIRECT_NET:
                    772:                        (void)printf("Redirect Network");
                    773:                        break;
                    774:                case ICMP_REDIRECT_HOST:
                    775:                        (void)printf("Redirect Host");
                    776:                        break;
                    777:                case ICMP_REDIRECT_TOSNET:
                    778:                        (void)printf("Redirect Type of Service and Network");
                    779:                        break;
                    780:                case ICMP_REDIRECT_TOSHOST:
                    781:                        (void)printf("Redirect Type of Service and Host");
                    782:                        break;
                    783:                default:
                    784:                        (void)printf("Redirect, Bad Code: %d", icp->icmp_code);
                    785:                        break;
                    786:                }
                    787:                (void)printf("(New addr: 0x%08lx)\n", icp->icmp_gwaddr.s_addr);
                    788: #ifndef icmp_data
                    789:                pr_retip(&icp->icmp_ip);
                    790: #else
                    791:                pr_retip((struct ip *)icp->icmp_data);
                    792: #endif
                    793:                break;
                    794:        case ICMP_ECHO:
                    795:                (void)printf("Echo Request\n");
                    796:                /* XXX ID + Seq + Data */
                    797:                break;
                    798:        case ICMP_TIMXCEED:
                    799:                switch(icp->icmp_code) {
                    800:                case ICMP_TIMXCEED_INTRANS:
                    801:                        (void)printf("Time to live exceeded\n");
                    802:                        break;
                    803:                case ICMP_TIMXCEED_REASS:
                    804:                        (void)printf("Frag reassembly time exceeded\n");
                    805:                        break;
                    806:                default:
                    807:                        (void)printf("Time exceeded, Bad Code: %d\n",
                    808:                            icp->icmp_code);
                    809:                        break;
                    810:                }
                    811: #ifndef icmp_data
                    812:                pr_retip(&icp->icmp_ip);
                    813: #else
                    814:                pr_retip((struct ip *)icp->icmp_data);
                    815: #endif
                    816:                break;
                    817:        case ICMP_PARAMPROB:
                    818:                (void)printf("Parameter problem: pointer = 0x%02x\n",
                    819:                    icp->icmp_hun.ih_pptr);
                    820: #ifndef icmp_data
                    821:                pr_retip(&icp->icmp_ip);
                    822: #else
                    823:                pr_retip((struct ip *)icp->icmp_data);
                    824: #endif
                    825:                break;
                    826:        case ICMP_TSTAMP:
                    827:                (void)printf("Timestamp\n");
                    828:                /* XXX ID + Seq + 3 timestamps */
                    829:                break;
                    830:        case ICMP_TSTAMPREPLY:
                    831:                (void)printf("Timestamp Reply\n");
                    832:                /* XXX ID + Seq + 3 timestamps */
                    833:                break;
                    834:        case ICMP_IREQ:
                    835:                (void)printf("Information Request\n");
                    836:                /* XXX ID + Seq */
                    837:                break;
                    838:        case ICMP_IREQREPLY:
                    839:                (void)printf("Information Reply\n");
                    840:                /* XXX ID + Seq */
                    841:                break;
                    842: #ifdef ICMP_MASKREQ
                    843:        case ICMP_MASKREQ:
                    844:                (void)printf("Address Mask Request\n");
                    845:                break;
                    846: #endif
                    847: #ifdef ICMP_MASKREPLY
                    848:        case ICMP_MASKREPLY:
                    849:                (void)printf("Address Mask Reply\n");
                    850:                break;
                    851: #endif
                    852:        default:
                    853:                (void)printf("Bad ICMP type: %d\n", icp->icmp_type);
                    854:        }
                    855: }
                    856: 
                    857: /*
                    858:  * pr_iph --
                    859:  *     Print an IP header with options.
                    860:  */
                    861: pr_iph(ip)
                    862:        struct ip *ip;
                    863: {
                    864:        int hlen;
                    865:        u_char *cp;
                    866: 
                    867:        hlen = ip->ip_hl << 2;
                    868:        cp = (u_char *)ip + 20;         /* point to options */
                    869: 
                    870:        (void)printf("Vr HL TOS  Len   ID Flg  off TTL Pro  cks      Src      Dst Data\n");
                    871:        (void)printf(" %1x  %1x  %02x %04x %04x",
                    872:            ip->ip_v, ip->ip_hl, ip->ip_tos, ip->ip_len, ip->ip_id);
                    873:        (void)printf("   %1x %04x", ((ip->ip_off) & 0xe000) >> 13,
                    874:            (ip->ip_off) & 0x1fff);
                    875:        (void)printf("  %02x  %02x %04x", ip->ip_ttl, ip->ip_p, ip->ip_sum);
                    876:        (void)printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_src.s_addr));
                    877:        (void)printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_dst.s_addr));
                    878:        /* dump and option bytes */
                    879:        while (hlen-- > 20) {
                    880:                (void)printf("%02x", *cp++);
                    881:        }
                    882:        (void)putchar('\n');
                    883: }
                    884: 
                    885: /*
                    886:  * pr_addr --
                    887:  *     Return an ascii host address as a dotted quad and optionally with
                    888:  * a hostname.
                    889:  */
                    890: char *
                    891: pr_addr(l)
                    892:        u_long l;
                    893: {
                    894:        struct hostent *hp;
                    895:        static char buf[80];
                    896: 
                    897:        if ((options & F_NUMERIC) ||
                    898:            !(hp = gethostbyaddr((char *)&l, 4, AF_INET)))
                    899:                (void)sprintf(buf, "%s", inet_ntoa(*(struct in_addr *)&l));
                    900:        else
                    901:                (void)sprintf(buf, "%s (%s)", hp->h_name,
                    902:                    inet_ntoa(*(struct in_addr *)&l));
                    903:        return(buf);
                    904: }
                    905: 
                    906: /*
                    907:  * pr_retip --
                    908:  *     Dump some info on a returned (via ICMP) IP packet.
                    909:  */
                    910: pr_retip(ip)
                    911:        struct ip *ip;
                    912: {
                    913:        int hlen;
                    914:        u_char *cp;
                    915: 
                    916:        pr_iph(ip);
                    917:        hlen = ip->ip_hl << 2;
                    918:        cp = (u_char *)ip + hlen;
                    919: 
                    920:        if (ip->ip_p == 6)
                    921:                (void)printf("TCP: from port %u, to port %u (decimal)\n",
                    922:                    (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3)));
                    923:        else if (ip->ip_p == 17)
                    924:                (void)printf("UDP: from port %u, to port %u (decimal)\n",
                    925:                        (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3)));
                    926: }
                    927: 
                    928: fill(bp, patp)
                    929:        char *bp, *patp;
                    930: {
                    931:        register int ii, jj, kk;
                    932:        int pat[16];
                    933:        char *cp;
                    934: 
                    935:        for (cp = patp; *cp; cp++)
                    936:                if (!isxdigit(*cp)) {
                    937:                        (void)fprintf(stderr,
                    938:                            "ping: patterns must be specified as hex digits.\n");
                    939:                        exit(1);
                    940:                }
                    941:        ii = sscanf(patp,
                    942:            "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
                    943:            &pat[0], &pat[1], &pat[2], &pat[3], &pat[4], &pat[5], &pat[6],
                    944:            &pat[7], &pat[8], &pat[9], &pat[10], &pat[11], &pat[12],
                    945:            &pat[13], &pat[14], &pat[15]);
                    946: 
                    947:        if (ii > 0)
                    948:                for (kk = 0; kk <= MAXPACKET - (8 + ii); kk += ii)
                    949:                        for (jj = 0; jj < ii; ++jj)
                    950:                                bp[jj + kk] = pat[jj];
                    951:        if (!(options & F_QUIET)) {
                    952:                (void)printf("PATTERN: 0x");
                    953:                for (jj = 0; jj < ii; ++jj)
                    954:                        (void)printf("%02x", bp[jj] & 0xFF);
                    955:                (void)printf("\n");
                    956:        }
                    957: }
                    958: 
                    959: usage()
                    960: {
                    961:        (void)fprintf(stderr,
                    962:            "usage: ping [-Rdfnqrv] [-c count] [-i wait] [-l preload]\n\t[-p pattern] [-s packetsize] host\n");
                    963:        exit(1);
                    964: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.