Annotation of 43BSDReno/sbin/ping/ping.c, revision 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.