Annotation of embedaddon/mrouted/mtrace.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * mtrace.c
        !             3:  *
        !             4:  * This tool traces the branch of a multicast tree from a source to a
        !             5:  * receiver for a particular multicast group and gives statistics
        !             6:  * about packet rate and loss for each hop along the path.  It can
        !             7:  * usually be invoked just as
        !             8:  *
        !             9:  *     mtrace source
        !            10:  *
        !            11:  * to trace the route from that source to the local host for a default
        !            12:  * group when only the route is desired and not group-specific packet
        !            13:  * counts.  See the usage line for more complex forms.
        !            14:  *
        !            15:  *
        !            16:  * Released 4 Apr 1995.  This program was adapted by Steve Casner
        !            17:  * (USC/ISI) from a prototype written by Ajit Thyagarajan (UDel and
        !            18:  * Xerox PARC).  It attempts to parallel in command syntax and output
        !            19:  * format the unicast traceroute program written by Van Jacobson (LBL)
        !            20:  * for the parts where that makes sense.
        !            21:  * 
        !            22:  * Copyright (c) 1998-2001.
        !            23:  * The University of Southern California/Information Sciences Institute.
        !            24:  * All rights reserved.
        !            25:  *
        !            26:  * Redistribution and use in source and binary forms, with or without
        !            27:  * modification, are permitted provided that the following conditions
        !            28:  * are met:
        !            29:  * 1. Redistributions of source code must retain the above copyright
        !            30:  *    notice, this list of conditions and the following disclaimer.
        !            31:  * 2. Redistributions in binary form must reproduce the above copyright
        !            32:  *    notice, this list of conditions and the following disclaimer in the
        !            33:  *    documentation and/or other materials provided with the distribution.
        !            34:  * 3. Neither the name of the project nor the names of its contributors
        !            35:  *    may be used to endorse or promote products derived from this software
        !            36:  *    without specific prior written permission.
        !            37:  *
        !            38:  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
        !            39:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            40:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            41:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
        !            42:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            43:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            44:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            45:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            46:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            47:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            48:  * SUCH DAMAGE.
        !            49:  */
        !            50: 
        !            51: #include "defs.h"
        !            52: #include <arpa/inet.h>
        !            53: #include <ctype.h>
        !            54: #include <err.h>
        !            55: #include <ifaddrs.h>
        !            56: #include <memory.h>
        !            57: #include <netdb.h>
        !            58: #include <poll.h>
        !            59: #include <stdarg.h>
        !            60: #include <string.h>
        !            61: #include <sys/ioctl.h>
        !            62: #ifdef SUNOS5
        !            63: #include <sys/systeminfo.h>
        !            64: #endif
        !            65: #include <sys/time.h>
        !            66: 
        !            67: #define DEFAULT_TIMEOUT        3       /* How long to wait before retrying requests */
        !            68: #define DEFAULT_RETRIES 3      /* How many times to try */
        !            69: #define MAXHOPS UNREACHABLE    /* Don't need more hops than max metric */
        !            70: #define UNICAST_TTL 255                /* TTL for unicast response */
        !            71: #define MULTICAST_TTL1 64      /* Default TTL for multicast query/response */
        !            72: #define MULTICAST_TTL_INC 32   /* TTL increment for increase after timeout */
        !            73: #define MULTICAST_TTL_MAX 192  /* Maximum TTL allowed (protect low-BW links */
        !            74: 
        !            75: struct resp_buf {
        !            76:     u_long qtime;              /* Time query was issued */
        !            77:     u_long rtime;              /* Time response was received */
        !            78:     int        len;                    /* Number of reports or length of data */
        !            79:     struct igmp igmp;          /* IGMP header */
        !            80:     union {
        !            81:        struct {
        !            82:            struct tr_query q;          /* Query/response header */
        !            83:            struct tr_resp r[MAXHOPS];  /* Per-hop reports */
        !            84:        } t;
        !            85:        char d[MAX_DVMRP_DATA_LEN];     /* Neighbor data */
        !            86:     } u;
        !            87: } base, incr[2];
        !            88: 
        !            89: #define qhdr u.t.q
        !            90: #define resps u.t.r
        !            91: #define ndata u.d
        !            92: 
        !            93: char names[MAXHOPS][40];
        !            94: int reset[MAXHOPS];                    /* To get around 3.4 bug, ... */
        !            95: int swaps[MAXHOPS];                    /* To get around 3.6 bug, ... */
        !            96: 
        !            97: int timeout = DEFAULT_TIMEOUT;
        !            98: int nqueries = DEFAULT_RETRIES;
        !            99: int numeric = FALSE;
        !           100: int debug = 0;
        !           101: int passive = FALSE;
        !           102: int multicast = FALSE;
        !           103: int statint = 10;
        !           104: int verbose = 0;
        !           105: 
        !           106: u_int32_t defgrp;                      /* Default group if not specified */
        !           107: u_int32_t query_cast;                  /* All routers multicast addr */
        !           108: u_int32_t resp_cast;                   /* Mtrace response multicast addr */
        !           109: 
        !           110: u_int32_t lcl_addr = 0;                        /* This host address, in NET order */
        !           111: u_int32_t dst_netmask;                 /* netmask to go with qdst */
        !           112: 
        !           113: /*
        !           114:  * Query/response parameters, all initialized to zero and set later
        !           115:  * to default values or from options.
        !           116:  */
        !           117: u_int32_t qsrc  = 0;           /* Source address in the query */
        !           118: u_int32_t qgrp  = 0;           /* Group address in the query */
        !           119: u_int32_t qdst  = 0;           /* Destination (receiver) address in query */
        !           120: u_char    qno   = 0;           /* Max number of hops to query */
        !           121: u_int32_t raddr = 0;           /* Address where response should be sent */
        !           122: int       qttl  = 0;           /* TTL for the query packet */
        !           123: u_char    rttl  = 0;           /* TTL for the response packet */
        !           124: u_int32_t gwy   = 0;           /* User-supplied last-hop router address */
        !           125: u_int32_t tdst  = 0;           /* Address where trace is sent (last-hop) */
        !           126: 
        !           127: vifi_t  numvifs;               /* to keep loader happy */
        !           128:                                /* (see kern.c) */
        !           129: 
        !           130: char *                 inet_name(u_int32_t addr);
        !           131: u_int32_t              host_addr(char *name);
        !           132: /* u_int is promoted u_char */
        !           133: char *                 proto_type(u_int type);
        !           134: char *                 flag_type(u_int type);
        !           135: 
        !           136: u_int32_t              get_netmask(int s, u_int32_t dst);
        !           137: int                    get_ttl(struct resp_buf *buf);
        !           138: int                    t_diff(u_long a, u_long b);
        !           139: u_long                 fixtime(u_long time);
        !           140: int                    send_recv(u_int32_t dst, int type, int code,
        !           141:                                  int tries, struct resp_buf *save);
        !           142: char *                 print_host(u_int32_t addr);
        !           143: char *                 print_host2(u_int32_t addr1, u_int32_t addr2);
        !           144: void                   print_trace(int index, struct resp_buf *buf);
        !           145: int                    what_kind(struct resp_buf *buf, char *why);
        !           146: char *                 scale(int *hop);
        !           147: void                   stat_line(struct tr_resp *r, struct tr_resp *s,
        !           148:                                  int have_next, int *res);
        !           149: void                   fixup_stats(struct resp_buf *base,
        !           150:                                    struct resp_buf *prev, struct resp_buf *new);
        !           151: int                    print_stats(struct resp_buf *base,
        !           152:                                    struct resp_buf *prev, struct resp_buf *new);
        !           153: void                   check_vif_state(void);
        !           154: u_long                 byteswap(u_long v);
        !           155: 
        !           156: 
        !           157: char *inet_name(u_int32_t addr)
        !           158: {
        !           159:     struct hostent *e;
        !           160: 
        !           161:     e = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET);
        !           162: 
        !           163:     return e ? e->h_name : "?";
        !           164: }
        !           165: 
        !           166: u_int32_t host_addr(char *name)
        !           167: {
        !           168:     struct hostent *e = (struct hostent *)0;
        !           169:     u_int32_t  addr;
        !           170:     int        i, dots = 3;
        !           171:     char       buf[40];
        !           172:     char       *ip = name;
        !           173:     char       *op = buf;
        !           174: 
        !           175:     /*
        !           176:      * Undo BSD's favor -- take fewer than 4 octets as net/subnet address
        !           177:      * if the name is all numeric.
        !           178:      */
        !           179:     for (i = sizeof(buf) - 7; i > 0; --i) {
        !           180:        if (*ip == '.') --dots;
        !           181:        else if (*ip == '\0') break;
        !           182:        else if (!isdigit((int)*ip)) dots = 0;  /* Not numeric, don't add zeroes */
        !           183:        *op++ = *ip++;
        !           184:     }
        !           185:     for (i = 0; i < dots; ++i) {
        !           186:        *op++ = '.';
        !           187:        *op++ = '0';
        !           188:     }
        !           189:     *op = '\0';
        !           190: 
        !           191:     if (dots <= 0) e = gethostbyname(name);
        !           192:     if (e) memcpy((char *)&addr, e->h_addr_list[0], e->h_length);
        !           193:     else {
        !           194:        addr = inet_addr(buf);
        !           195:        if (addr == INADDR_NONE) {
        !           196:            addr = 0;
        !           197:            printf("Could not parse %s as host name or address\n", name);
        !           198:        }
        !           199:     }
        !           200:     return addr;
        !           201: }
        !           202: 
        !           203: 
        !           204: char *proto_type(u_int type)
        !           205: {
        !           206:     static char buf[80];
        !           207: 
        !           208:     switch (type) {
        !           209:        case PROTO_DVMRP:
        !           210:            return ("DVMRP");
        !           211:        case PROTO_MOSPF:
        !           212:            return ("MOSPF");
        !           213:        case PROTO_PIM:
        !           214:            return ("PIM");
        !           215:        case PROTO_CBT:
        !           216:            return ("CBT");
        !           217:        default:
        !           218:            (void) snprintf(buf, sizeof buf, "Unknown protocol code %d", type);
        !           219:            return (buf);
        !           220:     }
        !           221: }
        !           222: 
        !           223: 
        !           224: char *flag_type(u_int type)
        !           225: {
        !           226:     static char buf[80];
        !           227: 
        !           228:     switch (type) {
        !           229:        case TR_NO_ERR:
        !           230:            return ("");
        !           231:        case TR_WRONG_IF:
        !           232:            return ("Wrong interface");
        !           233:        case TR_PRUNED:
        !           234:            return ("Prune sent upstream");
        !           235:        case TR_OPRUNED:
        !           236:            return ("Output pruned");
        !           237:        case TR_SCOPED:
        !           238:            return ("Hit scope boundary");
        !           239:        case TR_NO_RTE:
        !           240:            return ("No route");
        !           241:        case TR_OLD_ROUTER:
        !           242:            return ("Next router no mtrace");
        !           243:        case TR_NO_FWD:
        !           244:            return ("Not forwarding");
        !           245:        case TR_NO_SPACE:
        !           246:            return ("No space in packet");
        !           247:        default:
        !           248:            (void) snprintf(buf, sizeof buf, "Unknown error code %d", type);
        !           249:            return (buf);
        !           250:     }
        !           251: }    
        !           252: 
        !           253: /*
        !           254:  * If destination is on a local net, get the netmask, else set the
        !           255:  * netmask to all ones.  There are two side effects: if the local
        !           256:  * address was not explicitly set, and if the destination is on a
        !           257:  * local net, use that one; in either case, verify that the local
        !           258:  * address is valid.
        !           259:  */
        !           260: u_int32_t get_netmask(int UNUSED s, u_int32_t dst)
        !           261: {
        !           262:     u_int32_t if_addr, if_mask;
        !           263:     u_int32_t retval = 0xFFFFFFFF;
        !           264:     int found = FALSE;
        !           265:     struct ifaddrs *ifap, *ifa;
        !           266: 
        !           267:     if (getifaddrs(&ifap) != 0) {
        !           268:        perror("getifaddrs");
        !           269:        return (retval);
        !           270:     }
        !           271:     for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
        !           272:        if (!ifa->ifa_addr || ifa->ifa_addr->sa_family != AF_INET) 
        !           273:            continue;
        !           274:        if_addr = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr;
        !           275:        if_mask = ((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr.s_addr;
        !           276:        if ((dst & if_mask) == (if_addr & if_mask)) {
        !           277:            retval = if_mask;
        !           278:            if (lcl_addr == 0)
        !           279:                lcl_addr = if_addr;
        !           280:        }
        !           281:        if (lcl_addr == if_addr)
        !           282:            found = TRUE;
        !           283:     }
        !           284:     if (!found && lcl_addr != 0) {
        !           285:        printf("Interface address is not valid\n");
        !           286:        exit(1);
        !           287:     }
        !           288:     freeifaddrs(ifap);
        !           289:     return (retval);
        !           290: }
        !           291: 
        !           292: 
        !           293: int get_ttl(struct resp_buf *buf)
        !           294: {
        !           295:     int rno;
        !           296:     struct tr_resp *b;
        !           297:     u_int ttl;
        !           298: 
        !           299:     if (buf && (rno = buf->len) > 0) {
        !           300:        b = buf->resps + rno - 1;
        !           301:        ttl = b->tr_fttl;
        !           302: 
        !           303:        while (--rno > 0) {
        !           304:            --b;
        !           305:            if (ttl < b->tr_fttl) ttl = b->tr_fttl;
        !           306:            else ++ttl;
        !           307:        }
        !           308:        ttl += MULTICAST_TTL_INC;
        !           309:        if (ttl < MULTICAST_TTL1) ttl = MULTICAST_TTL1;
        !           310:        if (ttl > MULTICAST_TTL_MAX) ttl = MULTICAST_TTL_MAX;
        !           311:        return (ttl);
        !           312:     } else return(MULTICAST_TTL1);
        !           313: }
        !           314: 
        !           315: /*
        !           316:  * Calculate the difference between two 32-bit NTP timestamps and return
        !           317:  * the result in milliseconds.
        !           318:  */
        !           319: int t_diff(u_long a, u_long b)
        !           320: {
        !           321:     int d = a - b;
        !           322: 
        !           323:     return ((d * 125) >> 13);
        !           324: }
        !           325: 
        !           326: /*
        !           327:  * Fixup for incorrect time format in 3.3 mrouted.
        !           328:  * This is possible because (JAN_1970 mod 64K) is quite close to 32K,
        !           329:  * so correct and incorrect times will be far apart.
        !           330:  */
        !           331: u_long fixtime(u_long time)
        !           332: {
        !           333:     if (abs((int)(time-base.qtime)) > 0x3FFFFFFF)
        !           334:         time = ((time & 0xFFFF0000) + (JAN_1970 << 16)) +
        !           335:            ((time & 0xFFFF) << 14) / 15625;
        !           336:     return (time);
        !           337: }
        !           338: 
        !           339: /*
        !           340:  * Swap bytes for poor little-endian machines that don't byte-swap
        !           341:  */
        !           342: u_long byteswap(u_long v)
        !           343: {
        !           344:     return ((v << 24) | ((v & 0xff00) << 8) |
        !           345:            ((v >> 8) & 0xff00) | (v >> 24));
        !           346: }
        !           347: 
        !           348: int send_recv(u_int32_t dst, int type, int code, int tries, struct resp_buf *save)
        !           349: {
        !           350:     struct timeval tq, tr, tv;
        !           351:     struct ip *ip;
        !           352:     struct igmp *igmp;
        !           353:     struct tr_query *query, *rquery;
        !           354:     size_t ipdatalen, iphdrlen;
        !           355:     u_int32_t local, group;
        !           356:     int datalen;
        !           357:     struct pollfd pfd[1];
        !           358:     int count, len, i;
        !           359:     size_t igmpdatalen;
        !           360:     ssize_t recvlen;
        !           361:     socklen_t dummy = 0;
        !           362: 
        !           363:     if (type == IGMP_MTRACE) {
        !           364:        group = qgrp;
        !           365:        datalen = sizeof(struct tr_query);
        !           366:     } else {
        !           367:        group = htonl(MROUTED_LEVEL);
        !           368:        datalen = 0;
        !           369:     }
        !           370:     if (IN_MULTICAST(ntohl(dst))) local = lcl_addr;
        !           371:     else local = INADDR_ANY;
        !           372: 
        !           373:     /*
        !           374:      * If the reply address was not explicitly specified, start off
        !           375:      * with the unicast address of this host.  Then, if there is no
        !           376:      * response after trying half the tries with unicast, switch to
        !           377:      * the standard multicast reply address.  If the TTL was also not
        !           378:      * specified, set a multicast TTL and if needed increase it for the
        !           379:      * last quarter of the tries.
        !           380:      */
        !           381:     query = (struct tr_query *)(send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
        !           382:     query->tr_raddr = raddr ? raddr : multicast ? resp_cast : lcl_addr;
        !           383:     query->tr_rttl  = rttl ? rttl :
        !           384:        IN_MULTICAST(ntohl(query->tr_raddr)) ? get_ttl(save) : UNICAST_TTL;
        !           385:     query->tr_src   = qsrc;
        !           386:     query->tr_dst   = qdst;
        !           387: 
        !           388:     for (i = tries ; i > 0; --i) {
        !           389:        if (tries == nqueries && raddr == 0) {
        !           390:            if (i == ((nqueries + 1) >> 1)) {
        !           391:                query->tr_raddr = resp_cast;
        !           392:                if (rttl == 0) query->tr_rttl = get_ttl(save);
        !           393:            }
        !           394:            if (i <= ((nqueries + 3) >> 2) && rttl == 0) {
        !           395:                query->tr_rttl += MULTICAST_TTL_INC;
        !           396:                if (query->tr_rttl > MULTICAST_TTL_MAX)
        !           397:                    query->tr_rttl = MULTICAST_TTL_MAX;
        !           398:            }
        !           399:        }
        !           400: 
        !           401:        /*
        !           402:         * Change the qid for each request sent to avoid being confused
        !           403:         * by duplicate responses
        !           404:         */
        !           405: #ifdef SYSV    
        !           406:        query->tr_qid  = ((u_int32_t)lrand48() >> 8);
        !           407: #else
        !           408:        query->tr_qid  = ((u_int32_t)random() >> 8);
        !           409: #endif
        !           410: 
        !           411:        /*
        !           412:         * Set timer to calculate delays, then send query
        !           413:         */
        !           414:        gettimeofday(&tq, 0);
        !           415:        send_igmp(local, dst, type, code, group, datalen);
        !           416: 
        !           417:        /*
        !           418:         * Wait for response, discarding false alarms
        !           419:         */
        !           420:        pfd[0].fd = igmp_socket;
        !           421:        pfd[0].events = POLLIN;
        !           422:        while (TRUE) {
        !           423:            gettimeofday(&tv, 0);
        !           424:            tv.tv_sec = tq.tv_sec + timeout - tv.tv_sec;
        !           425:            tv.tv_usec = tq.tv_usec - tv.tv_usec;
        !           426:            if (tv.tv_usec < 0) tv.tv_usec += 1000000L, --tv.tv_sec;
        !           427:            if (tv.tv_sec < 0) tv.tv_sec = tv.tv_usec = 0;
        !           428: 
        !           429:            count = poll(pfd, 1, tv.tv_sec * 1000);
        !           430: 
        !           431:            if (count < 0) {
        !           432:                if (errno != EINTR) perror("poll");
        !           433:                continue;
        !           434:            } else if (count == 0) {
        !           435:                printf("* ");
        !           436:                fflush(stdout);
        !           437:                break;
        !           438:            }
        !           439: 
        !           440:            gettimeofday(&tr, 0);
        !           441:            recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE,
        !           442:                               0, (struct sockaddr *)0, &dummy);
        !           443: 
        !           444:            if (recvlen <= 0) {
        !           445:                if (recvlen && errno != EINTR) perror("recvfrom");
        !           446:                continue;
        !           447:            }
        !           448: 
        !           449:            if ((size_t)recvlen < sizeof(struct ip)) {
        !           450:                fprintf(stderr, "packet too short (%zd bytes) for IP header", recvlen);
        !           451:                continue;
        !           452:            }
        !           453:            ip = (struct ip *) recv_buf;
        !           454:            if (ip->ip_p == 0)  /* ignore cache creation requests */
        !           455:                continue;
        !           456: 
        !           457:            iphdrlen = ip->ip_hl << 2;
        !           458:            ipdatalen = ntohs(ip->ip_len) - iphdrlen;
        !           459:            if (iphdrlen + ipdatalen != (size_t)recvlen) {
        !           460:                fprintf(stderr, "packet shorter (%zd bytes) than hdr+data len (%zu+%zu)\n",
        !           461:                        recvlen, iphdrlen, ipdatalen);
        !           462:                continue;
        !           463:            }
        !           464: 
        !           465:            igmp = (struct igmp *) (recv_buf + iphdrlen);
        !           466:            if (ipdatalen < IGMP_MINLEN) {
        !           467:                fprintf(stderr,
        !           468:                        "IP data field too short (%zu bytes) for IGMP from %s\n",
        !           469:                        ipdatalen, inet_fmt(ip->ip_src.s_addr, s1, sizeof(s1)));
        !           470:                continue;
        !           471:            }
        !           472:            igmpdatalen = ipdatalen - IGMP_MINLEN;
        !           473: 
        !           474:            switch (igmp->igmp_type) {
        !           475: 
        !           476:                case IGMP_DVMRP:
        !           477:                    if (igmp->igmp_code != DVMRP_NEIGHBORS2) continue;
        !           478:                    len = igmpdatalen;
        !           479:                    /*
        !           480:                     * Accept DVMRP_NEIGHBORS2 response if it comes from the
        !           481:                     * address queried or if that address is one of the local
        !           482:                     * addresses in the response.
        !           483:                     */
        !           484:                    if (ip->ip_src.s_addr != dst) {
        !           485:                        u_int32_t *p = (u_int32_t *)(igmp + 1);
        !           486:                        u_int32_t *ep = p + (len >> 2);
        !           487:                        while (p < ep) {
        !           488:                            u_int32_t laddr = *p++;
        !           489:                            int n = ntohl(*p++) & 0xFF;
        !           490:                            if (laddr == dst) {
        !           491:                                ep = p + 1;             /* ensure p < ep after loop */
        !           492:                                break;
        !           493:                            }
        !           494:                            p += n;
        !           495:                        }
        !           496:                        if (p >= ep) continue;
        !           497:                    }
        !           498:                    break;
        !           499: 
        !           500:                case IGMP_MTRACE:           /* For backward compatibility with 3.3 */
        !           501:                case IGMP_MTRACE_RESP:
        !           502:                    if (igmpdatalen <= QLEN) continue;
        !           503:                    if ((igmpdatalen - QLEN) % RLEN) {
        !           504:                        printf("packet with incorrect datalen\n");
        !           505:                        continue;
        !           506:                    }
        !           507: 
        !           508:                    /*
        !           509:                     * Ignore responses that don't match query.
        !           510:                     */
        !           511:                    rquery = (struct tr_query *)(igmp + 1);
        !           512:                    if (rquery->tr_qid != query->tr_qid) continue;
        !           513:                    if (rquery->tr_src != qsrc) continue;
        !           514:                    if (rquery->tr_dst != qdst) continue;
        !           515:                    len = (igmpdatalen - QLEN) / RLEN;
        !           516: 
        !           517:                    /*
        !           518:                     * Ignore trace queries passing through this node when
        !           519:                     * mtrace is run on an mrouter that is in the path
        !           520:                     * (needed only because IGMP_MTRACE is accepted above
        !           521:                     * for backward compatibility with multicast release 3.3).
        !           522:                     */
        !           523:                    if (igmp->igmp_type == IGMP_MTRACE) {
        !           524:                        struct tr_resp *r = (struct tr_resp *)(rquery+1) + len - 1;
        !           525:                        u_int32_t smask;
        !           526: 
        !           527:                        VAL_TO_MASK(smask, r->tr_smask);
        !           528:                        if (len < code && (r->tr_inaddr & smask) != (qsrc & smask)
        !           529:                            && r->tr_rmtaddr != 0 && !(r->tr_rflags & 0x80))
        !           530:                            continue;
        !           531:                    }
        !           532: 
        !           533:                    /*
        !           534:                     * A match, we'll keep this one.
        !           535:                     */
        !           536:                    if (len > code) {
        !           537:                        fprintf(stderr,
        !           538:                                "Num hops received (%d) exceeds request (%d)\n",
        !           539:                                len, code);
        !           540:                    }
        !           541:                    rquery->tr_raddr = query->tr_raddr; /* Insure these are */
        !           542:                    rquery->tr_rttl = query->tr_rttl;   /* as we sent them */
        !           543:                    break;
        !           544: 
        !           545:                default:
        !           546:                    continue;
        !           547:            }
        !           548: 
        !           549:            /*
        !           550:             * Most of the sanity checking done at this point.
        !           551:             * Return this packet we have been waiting for.
        !           552:             */
        !           553:            if (save) {
        !           554:                save->qtime = ((tq.tv_sec + JAN_1970) << 16) +
        !           555:                    (tq.tv_usec << 10) / 15625;
        !           556:                save->rtime = ((tr.tv_sec + JAN_1970) << 16) +
        !           557:                    (tr.tv_usec << 10) / 15625;
        !           558:                save->len = len;
        !           559:                bcopy((char *)igmp, (char *)&save->igmp, ipdatalen);
        !           560:            }
        !           561:            return recvlen;
        !           562:        }
        !           563:     }
        !           564:     return 0;
        !           565: }
        !           566: 
        !           567: /*
        !           568:  * Most of this code is duplicated elsewhere.  I'm not sure if
        !           569:  * the duplication is absolutely required or not.
        !           570:  *
        !           571:  * Ideally, this would keep track of ongoing statistics
        !           572:  * collection and print out statistics.  (& keep track
        !           573:  * of h-b-h traces and only print the longest)  For now,
        !           574:  * it just snoops on what traces it can.
        !           575:  */
        !           576: void passive_mode(void)
        !           577: {
        !           578:     struct timeval tr;
        !           579:     struct ip *ip;
        !           580:     struct igmp *igmp;
        !           581:     struct tr_resp *r;
        !           582:     size_t ipdatalen, iphdrlen, igmpdatalen;
        !           583:     size_t len;
        !           584:     ssize_t recvlen;
        !           585:     socklen_t dummy = 0;
        !           586:     u_int32_t smask;
        !           587: 
        !           588:     if (raddr) {
        !           589:        if (IN_MULTICAST(ntohl(raddr))) k_join(raddr, INADDR_ANY);
        !           590:     } else k_join(htonl(0xE0000120), INADDR_ANY);
        !           591: 
        !           592:     while (1) {
        !           593:        recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE,
        !           594:                           0, (struct sockaddr *)0, &dummy);
        !           595:        gettimeofday(&tr,0);
        !           596: 
        !           597:        if (recvlen <= 0) {
        !           598:            if (recvlen && errno != EINTR) perror("recvfrom");
        !           599:            continue;
        !           600:        }
        !           601: 
        !           602:        if ((size_t)recvlen < sizeof(struct ip)) {
        !           603:            fprintf(stderr, "packet too short (%zd bytes) for IP header", recvlen);
        !           604:            continue;
        !           605:        }
        !           606:        ip = (struct ip *) recv_buf;
        !           607:        if (ip->ip_p == 0)      /* ignore cache creation requests */
        !           608:            continue;
        !           609: 
        !           610:        iphdrlen = ip->ip_hl << 2;
        !           611:        ipdatalen = ntohs(ip->ip_len) - iphdrlen;
        !           612:        if (iphdrlen + ipdatalen != (size_t)recvlen) {
        !           613:            fprintf(stderr, "packet shorter (%zd bytes) than hdr+data len (%zu+%zu)\n",
        !           614:                    recvlen, iphdrlen, ipdatalen);
        !           615:            continue;
        !           616:        }
        !           617: 
        !           618:        igmp = (struct igmp *) (recv_buf + iphdrlen);
        !           619:        if (ipdatalen < IGMP_MINLEN) {
        !           620:            fprintf(stderr, "IP data field too short (%zu bytes) for IGMP from %s\n",
        !           621:                    ipdatalen, inet_fmt(ip->ip_src.s_addr, s1, sizeof(s1)));
        !           622:            continue;
        !           623:        }
        !           624:        igmpdatalen = ipdatalen - IGMP_MINLEN;
        !           625: 
        !           626:        switch (igmp->igmp_type) {
        !           627: 
        !           628:            case IGMP_MTRACE:       /* For backward compatibility with 3.3 */
        !           629:            case IGMP_MTRACE_RESP:
        !           630:                if (igmpdatalen < QLEN) continue;
        !           631:                if ((igmpdatalen - QLEN) % RLEN) {
        !           632:                    printf("packet with incorrect datalen\n");
        !           633:                    continue;
        !           634:                }
        !           635: 
        !           636:                len = (igmpdatalen - QLEN)/RLEN;
        !           637: 
        !           638:                break;
        !           639: 
        !           640:            default:
        !           641:                continue;
        !           642:        }
        !           643: 
        !           644:        base.qtime = ((tr.tv_sec + JAN_1970) << 16) +
        !           645:            (tr.tv_usec << 10) / 15625;
        !           646:        base.rtime = ((tr.tv_sec + JAN_1970) << 16) +
        !           647:            (tr.tv_usec << 10) / 15625;
        !           648:        base.len = len;
        !           649:        bcopy((char *)igmp, (char *)&base.igmp, ipdatalen);
        !           650:        /*
        !           651:         * If the user specified which traces to monitor,
        !           652:         * only accept traces that correspond to the
        !           653:         * request
        !           654:         */
        !           655:        if ((qsrc != 0 && qsrc != base.qhdr.tr_src) ||
        !           656:            (qdst != 0 && qdst != base.qhdr.tr_dst) ||
        !           657:            (qgrp != 0 && qgrp != igmp->igmp_group.s_addr))
        !           658:            continue;
        !           659: 
        !           660:        printf("Mtrace from %s to %s via group %s (mxhop=%d)\n",
        !           661:               inet_fmt(base.qhdr.tr_dst, s1, sizeof(s1)), inet_fmt(base.qhdr.tr_src, s2, sizeof(s2)),
        !           662:               inet_fmt(igmp->igmp_group.s_addr, s3, sizeof(s3)), igmp->igmp_code);
        !           663:        if (len == 0)
        !           664:            continue;
        !           665:        printf("  0  ");
        !           666:        print_host(base.qhdr.tr_dst);
        !           667:        printf("\n");
        !           668:        print_trace(1, &base);
        !           669:        r = base.resps + base.len - 1;
        !           670:        VAL_TO_MASK(smask, r->tr_smask);
        !           671:        if ((r->tr_inaddr & smask) == (base.qhdr.tr_src & smask)) {
        !           672:            printf("%3d  ", -(base.len+1));
        !           673:            print_host(base.qhdr.tr_src);
        !           674:            printf("\n");
        !           675:        } else if (r->tr_rmtaddr != 0) {
        !           676:            printf("%3d  ", -(base.len+1));
        !           677:            what_kind(&base, r->tr_rflags == TR_OLD_ROUTER ?
        !           678:                      "doesn't support mtrace"
        !           679:                      : "is the next hop");
        !           680:        }
        !           681:        printf("\n");
        !           682:     }
        !           683: }
        !           684: 
        !           685: char *print_host(u_int32_t addr)
        !           686: {
        !           687:     return print_host2(addr, 0);
        !           688: }
        !           689: 
        !           690: /*
        !           691:  * On some routers, one interface has a name and the other doesn't.
        !           692:  * We always print the address of the outgoing interface, but can
        !           693:  * sometimes get the name from the incoming interface.  This might be
        !           694:  * confusing but should be slightly more helpful than just a "?".
        !           695:  */
        !           696: char *print_host2(u_int32_t addr1, u_int32_t addr2)
        !           697: {
        !           698:     char *name;
        !           699: 
        !           700:     if (numeric) {
        !           701:        printf("%s", inet_fmt(addr1, s1, sizeof(s1)));
        !           702:        return ("");
        !           703:     }
        !           704:     name = inet_name(addr1);
        !           705:     if (*name == '?' && *(name + 1) == '\0' && addr2 != 0)
        !           706:        name = inet_name(addr2);
        !           707:     printf("%s (%s)", name, inet_fmt(addr1, s1, sizeof(s1)));
        !           708:     return (name);
        !           709: }
        !           710: 
        !           711: /*
        !           712:  * Print responses as received (reverse path from dst to src)
        !           713:  */
        !           714: void print_trace(int index, struct resp_buf *buf)
        !           715: {
        !           716:     struct tr_resp *r;
        !           717:     char *name;
        !           718:     int i;
        !           719:     int hop;
        !           720:     char *ms;
        !           721: 
        !           722:     i = abs(index);
        !           723:     r = buf->resps + i - 1;
        !           724: 
        !           725:     for (; i <= buf->len; ++i, ++r) {
        !           726:        if (index > 0) printf("%3d  ", -i);
        !           727:        name = print_host2(r->tr_outaddr, r->tr_inaddr);
        !           728:        printf("  %s  thresh^ %d", proto_type(r->tr_rproto), r->tr_fttl);
        !           729:        if (verbose) {
        !           730:            hop = t_diff(fixtime(ntohl(r->tr_qarr)), buf->qtime);
        !           731:            ms = scale(&hop);
        !           732:            printf("  %d%s", hop, ms);
        !           733:        }
        !           734:        printf("  %s\n", flag_type(r->tr_rflags));
        !           735:        memcpy(names[i-1], name, sizeof(names[0]) - 1);
        !           736:        names[i-1][sizeof(names[0])-1] = '\0';
        !           737:     }
        !           738: }
        !           739: 
        !           740: /*
        !           741:  * See what kind of router is the next hop
        !           742:  */
        !           743: int what_kind(struct resp_buf *buf, char *why)
        !           744: {
        !           745:     u_int32_t smask;
        !           746:     int retval;
        !           747:     int hops = buf->len;
        !           748:     struct tr_resp *r = buf->resps + hops - 1;
        !           749:     u_int32_t next = r->tr_rmtaddr;
        !           750: 
        !           751:     retval = send_recv(next, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS2, 1, &incr[0]);
        !           752:     print_host(next);
        !           753:     if (retval) {
        !           754:        u_int32_t version = ntohl(incr[0].igmp.igmp_group.s_addr);
        !           755:        u_int32_t *p = (u_int32_t *)incr[0].ndata;
        !           756:        u_int32_t *ep = p + (incr[0].len >> 2);
        !           757:        char *type = "";
        !           758:        retval = 0;
        !           759:        switch (version & 0xFF) {
        !           760:            case 1:
        !           761:                type = "proteon/mrouted ";
        !           762:                retval = 1;
        !           763:                break;
        !           764: 
        !           765:            case 2:
        !           766:            case 3:
        !           767:                if (((version >> 8) & 0xFF) < 3) retval = 1;
        !           768:                /* Fall through */
        !           769:            case 4:
        !           770:                type = "mrouted ";
        !           771:                break;
        !           772: 
        !           773:            case 10:
        !           774:                type = "cisco ";
        !           775:        }
        !           776:        printf(" [%s%d.%d] %s\n",
        !           777:               type, version & 0xFF, (version >> 8) & 0xFF,
        !           778:               why);
        !           779:        VAL_TO_MASK(smask, r->tr_smask);
        !           780:        while (p < ep) {
        !           781:            u_int32_t laddr = *p++;
        !           782:            int flags = (ntohl(*p) & 0xFF00) >> 8;
        !           783:            int n = ntohl(*p++) & 0xFF;
        !           784:            if (!(flags & (DVMRP_NF_DOWN | DVMRP_NF_DISABLED)) &&
        !           785:                (laddr & smask) == (qsrc & smask)) {
        !           786:                printf("%3d  ", -(hops+2));
        !           787:                print_host(qsrc);
        !           788:                printf("\n");
        !           789:                return 1;
        !           790:            }
        !           791:            p += n;
        !           792:        }
        !           793:        return retval;
        !           794:     }
        !           795:     printf(" %s\n", why);
        !           796:     return 0;
        !           797: }
        !           798: 
        !           799: 
        !           800: char *scale(int *hop)
        !           801: {
        !           802:     if (*hop > -1000 && *hop < 10000) return (" ms");
        !           803:     *hop /= 1000;
        !           804:     if (*hop > -1000 && *hop < 10000) return (" s ");
        !           805:     return ("s ");
        !           806: }
        !           807: 
        !           808: /*
        !           809:  * Calculate and print one line of packet loss and packet rate statistics.
        !           810:  * Checks for count of all ones from mrouted 2.3 that doesn't have counters.
        !           811:  */
        !           812: #define NEITHER 0
        !           813: #define INS     1
        !           814: #define OUTS    2
        !           815: #define BOTH    3
        !           816: void stat_line(struct tr_resp *r, struct tr_resp *s, int have_next, int *rst)
        !           817: {
        !           818:     int timediff = (fixtime(ntohl(s->tr_qarr)) -
        !           819:                    fixtime(ntohl(r->tr_qarr))) >> 16;
        !           820:     int v_lost, v_pct;
        !           821:     int g_lost, g_pct;
        !           822:     int v_out = ntohl(s->tr_vifout) - ntohl(r->tr_vifout);
        !           823:     int g_out = ntohl(s->tr_pktcnt) - ntohl(r->tr_pktcnt);
        !           824:     int v_pps, g_pps;
        !           825:     char v_str[8], g_str[8];
        !           826:     int have = NEITHER;
        !           827:     int res = *rst;
        !           828: 
        !           829:     if (timediff == 0) timediff = 1;
        !           830:     v_pps = v_out / timediff;
        !           831:     g_pps = g_out / timediff;
        !           832: 
        !           833:     if (v_out && ((s->tr_vifout != 0xFFFFFFFF && s->tr_vifout != 0) ||
        !           834:                   (r->tr_vifout != 0xFFFFFFFF && r->tr_vifout != 0)))
        !           835:        have |= OUTS;
        !           836: 
        !           837:     if (have_next) {
        !           838:        --r,  --s,  --rst;
        !           839:        if ((s->tr_vifin != 0xFFFFFFFF && s->tr_vifin != 0) ||
        !           840:            (r->tr_vifin != 0xFFFFFFFF && r->tr_vifin != 0))
        !           841:            have |= INS;
        !           842:        if (*rst)
        !           843:            res = 1;
        !           844:     }
        !           845: 
        !           846:     switch (have) {
        !           847:        case BOTH:
        !           848:            v_lost = v_out - (ntohl(s->tr_vifin) - ntohl(r->tr_vifin));
        !           849:            if (v_out) v_pct = (v_lost * 100 + (v_out >> 1)) / v_out;
        !           850:            else v_pct = 0;
        !           851:            if (-100 < v_pct && v_pct < 101 && v_out > 10)
        !           852:                snprintf(v_str, sizeof v_str, "%3d", v_pct);
        !           853:            else memcpy(v_str, " --", 4);
        !           854: 
        !           855:            g_lost = g_out - (ntohl(s->tr_pktcnt) - ntohl(r->tr_pktcnt));
        !           856:            if (g_out) g_pct = (g_lost * 100 + (g_out >> 1))/ g_out;
        !           857:            else g_pct = 0;
        !           858:            if (-100 < g_pct && g_pct < 101 && g_out > 10)
        !           859:                snprintf(g_str, sizeof g_str, "%3d", g_pct);
        !           860:            else memcpy(g_str, " --", 4);
        !           861: 
        !           862:            printf("%6d/%-5d=%s%%%4d pps",
        !           863:                   v_lost, v_out, v_str, v_pps);
        !           864:            if (res)
        !           865:                printf("\n");
        !           866:            else
        !           867:                printf("%6d/%-5d=%s%%%4d pps\n",
        !           868:                       g_lost, g_out, g_str, g_pps);
        !           869:            break;
        !           870: 
        !           871:        case INS:
        !           872:            v_out = ntohl(s->tr_vifin) - ntohl(r->tr_vifin);
        !           873:            v_pps = v_out / timediff;
        !           874:            /* Fall through */
        !           875: 
        !           876:        case OUTS:
        !           877:            printf("       %-5d     %4d pps",
        !           878:                   v_out, v_pps);
        !           879:            if (res)
        !           880:                printf("\n");
        !           881:            else
        !           882:                printf("       %-5d     %4d pps\n",
        !           883:                       g_out, g_pps);
        !           884:            break;
        !           885: 
        !           886:        case NEITHER:
        !           887:            printf("\n");
        !           888:            break;
        !           889:     }
        !           890: 
        !           891:     if (debug > 2) {
        !           892:        printf("\t\t\t\tv_in: %u ", ntohl(s->tr_vifin));
        !           893:        printf("v_out: %u ", ntohl(s->tr_vifout));
        !           894:        printf("pkts: %u\n", ntohl(s->tr_pktcnt));
        !           895:        printf("\t\t\t\tv_in: %u ", ntohl(r->tr_vifin));
        !           896:        printf("v_out: %u ", ntohl(r->tr_vifout));
        !           897:        printf("pkts: %u\n", ntohl(r->tr_pktcnt));
        !           898:        printf("\t\t\t\tv_in: %u ", ntohl(s->tr_vifin)-ntohl(r->tr_vifin));
        !           899:        printf("v_out: %u ", ntohl(s->tr_vifout) - ntohl(r->tr_vifout));
        !           900:        printf("pkts: %u ", ntohl(s->tr_pktcnt) - ntohl(r->tr_pktcnt));
        !           901:        printf("time: %d\n", timediff);
        !           902:        printf("\t\t\t\tres: %d\n", res);
        !           903:     }
        !           904: }
        !           905: 
        !           906: /*
        !           907:  * A fixup to check if any pktcnt has been reset, and to fix the
        !           908:  * byteorder bugs in mrouted 3.6 on little-endian machines.
        !           909:  */
        !           910: void fixup_stats(struct resp_buf *base, struct resp_buf *prev, struct resp_buf *new)
        !           911: {
        !           912:     int rno = base->len;
        !           913:     struct tr_resp *b = base->resps + rno;
        !           914:     struct tr_resp *p = prev->resps + rno;
        !           915:     struct tr_resp *n = new->resps + rno;
        !           916:     int *r = reset + rno;
        !           917:     int *s = swaps + rno;
        !           918:     int res;
        !           919: 
        !           920:     /* Check for byte-swappers */
        !           921:     while (--rno >= 0) {
        !           922:        --n; --p; --b; --s;
        !           923:        if (*s || abs(ntohl(n->tr_vifout) - ntohl(p->tr_vifout)) > 100000) {
        !           924:            /* This host sends byteswapped reports; swap 'em */
        !           925:            if (!*s) {
        !           926:                *s = 1;
        !           927:                b->tr_qarr = byteswap(b->tr_qarr);
        !           928:                b->tr_vifin = byteswap(b->tr_vifin);
        !           929:                b->tr_vifout = byteswap(b->tr_vifout);
        !           930:                b->tr_pktcnt = byteswap(b->tr_pktcnt);
        !           931:            }
        !           932: 
        !           933:            n->tr_qarr = byteswap(n->tr_qarr);
        !           934:            n->tr_vifin = byteswap(n->tr_vifin);
        !           935:            n->tr_vifout = byteswap(n->tr_vifout);
        !           936:            n->tr_pktcnt = byteswap(n->tr_pktcnt);
        !           937:        }
        !           938:     }
        !           939: 
        !           940:     rno = base->len;
        !           941:     b = base->resps + rno;
        !           942:     p = prev->resps + rno;
        !           943:     n = new->resps + rno;
        !           944: 
        !           945:     while (--rno >= 0) {
        !           946:        --n; --p; --b; --r;
        !           947:        res = ((ntohl(n->tr_pktcnt) < ntohl(b->tr_pktcnt)) ||
        !           948:               (ntohl(n->tr_pktcnt) < ntohl(p->tr_pktcnt)));
        !           949:        if (debug > 2)
        !           950:            printf("\t\tr=%d, res=%d\n", *r, res);
        !           951:        if (*r) {
        !           952:            if (res || *r > 1) {
        !           953:                /*
        !           954:                 * This router appears to be a 3.4 with that nasty ol'
        !           955:                 * neighbor version bug, which causes it to constantly
        !           956:                 * reset.  Just nuke the statistics for this node, and
        !           957:                 * don't even bother giving it the benefit of the
        !           958:                 * doubt from now on.
        !           959:                 */
        !           960:                p->tr_pktcnt = b->tr_pktcnt = n->tr_pktcnt;
        !           961:                r++;
        !           962:            } else {
        !           963:                /*
        !           964:                 * This is simply the situation that the original
        !           965:                 * fixup_stats was meant to deal with -- that a
        !           966:                 * 3.3 or 3.4 router deleted a cache entry while
        !           967:                 * traffic was still active.
        !           968:                 */
        !           969:                *r = 0;
        !           970:                break;
        !           971:            }
        !           972:        } else
        !           973:            *r = res;
        !           974:     }
        !           975: 
        !           976:     if (rno < 0) return;
        !           977: 
        !           978:     rno = base->len;
        !           979:     b = base->resps + rno;
        !           980:     p = prev->resps + rno;
        !           981: 
        !           982:     while (--rno >= 0) (--b)->tr_pktcnt = (--p)->tr_pktcnt;
        !           983: }
        !           984: 
        !           985: /*
        !           986:  * Print responses with statistics for forward path (from src to dst)
        !           987:  */
        !           988: int print_stats(struct resp_buf *base, struct resp_buf *prev, struct resp_buf *new)
        !           989: {
        !           990:     int rtt, hop;
        !           991:     char *ms;
        !           992:     u_int32_t smask;
        !           993:     int rno = base->len - 1;
        !           994:     struct tr_resp *b = base->resps + rno;
        !           995:     struct tr_resp *p = prev->resps + rno;
        !           996:     struct tr_resp *n = new->resps + rno;
        !           997:     int *r = reset + rno;
        !           998:     u_long resptime = new->rtime;
        !           999:     u_long qarrtime = fixtime(ntohl(n->tr_qarr));
        !          1000:     u_int ttl = n->tr_fttl;
        !          1001:     int first = (base == prev);
        !          1002: 
        !          1003:     VAL_TO_MASK(smask, b->tr_smask);
        !          1004:     printf("  Source        Response Dest");
        !          1005:     printf("    Packet Statistics For     Only For Traffic\n");
        !          1006:     printf("%-15s %-15s  All Multicast Traffic     From %s\n",
        !          1007:           ((b->tr_inaddr & smask) == (qsrc & smask)) ? s1 : "   * * *       ",
        !          1008:           inet_fmt(base->qhdr.tr_raddr, s2, sizeof(s2)), inet_fmt(qsrc, s1, sizeof(s1)));
        !          1009:     rtt = t_diff(resptime, new->qtime);
        !          1010:     ms = scale(&rtt);
        !          1011:     printf("     %c       __/  rtt%5d%s    Lost/Sent = Pct  Rate       To %s\n",
        !          1012:           first ? 'v' : '|', rtt, ms, inet_fmt(qgrp, s2, sizeof(s2)));
        !          1013:     if (!first) {
        !          1014:        hop = t_diff(resptime, qarrtime);
        !          1015:        ms = scale(&hop);
        !          1016:        printf("     v      /     hop%5d%s", hop, ms);
        !          1017:        printf("    ---------------------     --------------------\n");
        !          1018:     }
        !          1019:     if (debug > 2) {
        !          1020:        printf("\t\t\t\tv_in: %u ", ntohl(n->tr_vifin));
        !          1021:        printf("v_out: %u ", ntohl(n->tr_vifout));
        !          1022:        printf("pkts: %u\n", ntohl(n->tr_pktcnt));
        !          1023:        printf("\t\t\t\tv_in: %u ", ntohl(b->tr_vifin));
        !          1024:        printf("v_out: %u ", ntohl(b->tr_vifout));
        !          1025:        printf("pkts: %u\n", ntohl(b->tr_pktcnt));
        !          1026:        printf("\t\t\t\tv_in: %u ", ntohl(n->tr_vifin) - ntohl(b->tr_vifin));
        !          1027:        printf("v_out: %u ", ntohl(n->tr_vifout) - ntohl(b->tr_vifout));
        !          1028:        printf("pkts: %u\n", ntohl(n->tr_pktcnt) - ntohl(b->tr_pktcnt));
        !          1029:        printf("\t\t\t\treset: %d\n", *r);
        !          1030:     }
        !          1031: 
        !          1032:     while (TRUE) {
        !          1033:        if ((n->tr_inaddr != b->tr_inaddr) || (n->tr_inaddr != b->tr_inaddr))
        !          1034:            return 1;           /* Route changed */
        !          1035: 
        !          1036:        if ((n->tr_inaddr != n->tr_outaddr))
        !          1037:            printf("%-15s\n", inet_fmt(n->tr_inaddr, s1, sizeof(s1)));
        !          1038:        printf("%-15s %-14s %s\n", inet_fmt(n->tr_outaddr, s1, sizeof(s1)), names[rno],
        !          1039:               flag_type(n->tr_rflags));
        !          1040: 
        !          1041:        if (rno-- < 1) break;
        !          1042: 
        !          1043:        printf("     %c     ^      ttl%5d   ", first ? 'v' : '|', ttl);
        !          1044:        stat_line(p, n, TRUE, r);
        !          1045:        if (!first) {
        !          1046:            resptime = qarrtime;
        !          1047:            qarrtime = fixtime(ntohl((n-1)->tr_qarr));
        !          1048:            hop = t_diff(resptime, qarrtime);
        !          1049:            ms = scale(&hop);
        !          1050:            printf("     v     |      hop%5d%s", hop, ms);
        !          1051:            stat_line(b, n, TRUE, r);
        !          1052:        }
        !          1053: 
        !          1054:        --b, --p, --n, --r;
        !          1055:        if (ttl < n->tr_fttl) ttl = n->tr_fttl;
        !          1056:        else ++ttl;
        !          1057:     }
        !          1058:           
        !          1059:     printf("     %c      \\__   ttl%5d   ", first ? 'v' : '|', ttl);
        !          1060:     stat_line(p, n, FALSE, r);
        !          1061:     if (!first) {
        !          1062:        hop = t_diff(qarrtime, new->qtime);
        !          1063:        ms = scale(&hop);
        !          1064:        printf("     v         \\  hop%5d%s", hop, ms);
        !          1065:        stat_line(b, n, FALSE, r);
        !          1066:     }
        !          1067:     printf("%-15s %s\n", inet_fmt(qdst, s1, sizeof(s1)), inet_fmt(lcl_addr, s2, sizeof(s2)));
        !          1068:     printf("  Receiver      Query Source\n\n");
        !          1069:     return 0;
        !          1070: }
        !          1071: 
        !          1072: 
        !          1073: void usage(void)
        !          1074: {
        !          1075:     fprintf(stderr, "Usage: mtrace [-lMnpsv] [-g gateway] [-i if_addr] [-m max_hops] [-q nqueries]\n"
        !          1076:            "              [-r host] [-S stat_int] [-t ttl] [-w waittime] source [receiver]\n"
        !          1077:            "              [group]\n");
        !          1078:     exit(1);
        !          1079: }
        !          1080: 
        !          1081: int main(int argc, char *argv[])
        !          1082: {
        !          1083:     int udp;
        !          1084:     struct sockaddr_in addr;
        !          1085:     socklen_t addrlen = sizeof(addr);
        !          1086:     ssize_t recvlen;
        !          1087:     struct timeval tv;
        !          1088:     struct resp_buf *prev, *new;
        !          1089:     struct tr_resp *r;
        !          1090:     u_int32_t smask;
        !          1091:     int rno;
        !          1092:     int hops, nexthop, tries;
        !          1093:     u_int32_t lastout = 0;
        !          1094:     int numstats = 1;
        !          1095:     int waittime;
        !          1096:     int seed, ch;
        !          1097:     uid_t uid;
        !          1098:     const char *errstr;
        !          1099: 
        !          1100:     while ((ch = getopt(argc, argv, "d:g:i:lm:Mnpq:r:sS:t:vw:")) != -1) {
        !          1101:         switch (ch) {
        !          1102:             case 'd':                  /* Unlisted debug print option */
        !          1103:                 debug = strtonum(optarg, 0, 3, &errstr);
        !          1104:                 if (errstr) {
        !          1105:                     warnx("debug level %s", errstr);
        !          1106:                     debug = 0;
        !          1107:                 }
        !          1108:                 break;
        !          1109: 
        !          1110:             case 'g':                  /* Last-hop gateway (dest of query) */
        !          1111:                gwy = host_addr(optarg);
        !          1112:                 break;
        !          1113: 
        !          1114:             case 'l':                  /* Loop updating stats indefinitely */
        !          1115:                numstats = 3153600;
        !          1116:                break;
        !          1117: 
        !          1118:             case 'm':                  /* Max number of hops to trace */
        !          1119:                 qno = strtonum(optarg, 1, MAXHOPS, &errstr);
        !          1120:                 if (errstr) {
        !          1121:                     warnx("max hops %s", errstr);
        !          1122:                     qno = 0;
        !          1123:                 }
        !          1124:                 break;
        !          1125: 
        !          1126:             case 'M':                  /* Use multicast for response */
        !          1127:                multicast = TRUE;
        !          1128:                break;
        !          1129: 
        !          1130:             case 'n':                  /* Don't reverse map host addresses */
        !          1131:                numeric = TRUE;
        !          1132:                break;
        !          1133: 
        !          1134:             case 'p':                  /* Passive listen for traces */
        !          1135:                passive = TRUE;
        !          1136:                break;
        !          1137: 
        !          1138:             case 'q':                  /* Number of query retries */
        !          1139:                 nqueries = strtonum(optarg, 1, 65535, &errstr);
        !          1140:                 if (errstr) {
        !          1141:                     warnx("query retries %s", errstr);
        !          1142:                     qno = 0;
        !          1143:                 }
        !          1144:                 break;
        !          1145: 
        !          1146:             case 'r':                  /* Dest for response packet */
        !          1147:                raddr = host_addr(optarg);
        !          1148:                 break;
        !          1149: 
        !          1150:             case 's':                  /* Short form, don't wait for stats */
        !          1151:                numstats = 0;
        !          1152:                break;
        !          1153: 
        !          1154:             case 'S':                  /* Stat accumulation interval */
        !          1155:                 statint = strtonum(optarg, 1, 65535, &errstr);
        !          1156:                 if (errstr) {
        !          1157:                     warnx("stat accumulation interval %s", errstr);
        !          1158:                     statint = 10;
        !          1159:                 }
        !          1160:                 break;
        !          1161: 
        !          1162:             case 't':                  /* TTL for query packet */
        !          1163:                 qttl = strtonum(optarg, 1, 32767, &errstr);
        !          1164:                 if (errstr) {
        !          1165:                     warnx("TTL for query packet %s", errstr);
        !          1166:                     qttl = 0;
        !          1167:                 }
        !          1168:                 rttl = qttl;
        !          1169:                 break;
        !          1170: 
        !          1171:             case 'v':                  /* Verbosity */
        !          1172:                verbose = TRUE;
        !          1173:                break;
        !          1174: 
        !          1175:             case 'w':                  /* Time to wait for packet arrival */
        !          1176:                 timeout = strtonum(optarg, 1, 65535, &errstr);
        !          1177:                 if (errstr) {
        !          1178:                     warnx("TTL for query packet %s", errstr);
        !          1179:                     timeout = DEFAULT_TIMEOUT;
        !          1180:                 }
        !          1181:                 break;
        !          1182: 
        !          1183:             case 'i':                  /* Local interface address */
        !          1184:                lcl_addr = host_addr(optarg);
        !          1185:                 break;
        !          1186: 
        !          1187:             default:
        !          1188:                usage();
        !          1189:         }
        !          1190:     }
        !          1191:     argc -= optind;
        !          1192:     argv += optind;
        !          1193: 
        !          1194:     if (geteuid() != 0) {
        !          1195:         fprintf(stderr, "mtrace: must be root\n");
        !          1196:         exit(1);
        !          1197:     }
        !          1198: 
        !          1199:     init_igmp();
        !          1200: 
        !          1201:     uid = getuid();
        !          1202:     if (setuid(uid) == -1)
        !          1203:        err(1, "setuid");
        !          1204: 
        !          1205:     if (argc > 0 && (qsrc = host_addr(argv[0]))) {          /* Source of path */
        !          1206:        if (IN_MULTICAST(ntohl(qsrc))) usage();
        !          1207:        argv++, argc--;
        !          1208:        if (argc > 0 && (qdst = host_addr(argv[0]))) {      /* Dest of path */
        !          1209:            argv++, argc--;
        !          1210:            if (argc > 0 && (qgrp = host_addr(argv[0]))) {  /* Path via group */
        !          1211:                argv++, argc--;
        !          1212:            }
        !          1213:            if (IN_MULTICAST(ntohl(qdst))) {
        !          1214:                u_int32_t temp = qdst;
        !          1215:                qdst = qgrp;
        !          1216:                qgrp = temp;
        !          1217:                if (IN_MULTICAST(ntohl(qdst))) usage();
        !          1218:            } else if (qgrp && !IN_MULTICAST(ntohl(qgrp))) usage();
        !          1219:        }
        !          1220:     }
        !          1221: 
        !          1222:     if (passive) {
        !          1223:        passive_mode();
        !          1224:        return(0);
        !          1225:     }
        !          1226: 
        !          1227:     if (argc > 0 || qsrc == 0) {
        !          1228:         usage();
        !          1229:     }
        !          1230: 
        !          1231:     /*
        !          1232:      * Set useful defaults for as many parameters as possible.
        !          1233:      */
        !          1234: 
        !          1235:     defgrp = htonl(0xE0020001);                /* MBone Audio (224.2.0.1) */
        !          1236:     query_cast = htonl(0xE0000002);    /* All routers multicast addr */
        !          1237:     resp_cast = htonl(0xE0000120);     /* Mtrace response multicast addr */
        !          1238:     if (qgrp == 0) qgrp = defgrp;
        !          1239: 
        !          1240:     /*
        !          1241:      * Get default local address for multicasts to use in setting defaults.
        !          1242:      */
        !          1243:     memset(&addr, 0, sizeof addr);
        !          1244:     addr.sin_family = AF_INET;
        !          1245: #ifdef HAVE_SA_LEN
        !          1246:     addr.sin_len = sizeof(addr);
        !          1247: #endif
        !          1248:     addr.sin_addr.s_addr = qgrp;
        !          1249:     addr.sin_port = htons(2000);       /* Any port above 1024 will do */
        !          1250: 
        !          1251:     if (((udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0) ||
        !          1252:        (connect(udp, (struct sockaddr *) &addr, sizeof(addr)) < 0) ||
        !          1253:        getsockname(udp, (struct sockaddr *) &addr, &addrlen) < 0) {
        !          1254:        perror("Determining local address");
        !          1255:        exit(1);
        !          1256:     }
        !          1257: 
        !          1258: #ifdef SUNOS5
        !          1259:     /*
        !          1260:      * SunOS 5.X prior to SunOS 2.6, getsockname returns 0 for udp socket.
        !          1261:      * This call to sysinfo will return the hostname.
        !          1262:      * If the default multicast interface (set with the route
        !          1263:      * for 224.0.0.0) is not the same as the hostname,
        !          1264:      * mtrace -i [if_addr] will have to be used.
        !          1265:      */
        !          1266:     if (addr.sin_addr.s_addr == 0) {
        !          1267:        char myhostname[MAXHOSTNAMELEN];
        !          1268:        struct hostent *hp;
        !          1269:        int error;
        !          1270:     
        !          1271:        error = sysinfo(SI_HOSTNAME, myhostname, sizeof(myhostname));
        !          1272:        if (error == -1) {
        !          1273:            perror("Getting my hostname");
        !          1274:            exit(1);
        !          1275:        }
        !          1276: 
        !          1277:        hp = gethostbyname(myhostname);
        !          1278:        if (hp == NULL || hp->h_addrtype != AF_INET ||
        !          1279:            hp->h_length != sizeof(addr.sin_addr)) {
        !          1280:            perror("Finding IP address for my hostname");
        !          1281:            exit(1);
        !          1282:        }
        !          1283: 
        !          1284:        memcpy((char *)&addr.sin_addr.s_addr, hp->h_addr, hp->h_length);
        !          1285:     }
        !          1286: #endif
        !          1287: 
        !          1288:     /*
        !          1289:      * Default destination for path to be queried is the local host.
        !          1290:      */
        !          1291:     if (qdst == 0) qdst = lcl_addr ? lcl_addr : addr.sin_addr.s_addr;
        !          1292:     dst_netmask = get_netmask(udp, qdst);
        !          1293:     close(udp);
        !          1294:     if (lcl_addr == 0) lcl_addr = addr.sin_addr.s_addr;
        !          1295: 
        !          1296:     /*
        !          1297:      * Initialize the seed for random query identifiers.
        !          1298:      */
        !          1299:     gettimeofday(&tv, 0);
        !          1300:     seed = tv.tv_usec ^ lcl_addr;
        !          1301: #ifdef SYSV    
        !          1302:     srand48(seed);
        !          1303: #else
        !          1304:     srandom(seed);
        !          1305: #endif
        !          1306: 
        !          1307:     /*
        !          1308:      * Protect against unicast queries to mrouted versions that might crash.
        !          1309:      */
        !          1310:     if (gwy && !IN_MULTICAST(ntohl(gwy)))
        !          1311:        if (send_recv(gwy, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS2, 1, &incr[0])) {
        !          1312:            int version = ntohl(incr[0].igmp.igmp_group.s_addr) & 0xFFFF;
        !          1313:            if (version == 0x0303 || version == 0x0503) {
        !          1314:                printf("Don't use -g to address an mrouted 3.%d, it might crash\n",
        !          1315:                       (version >> 8) & 0xFF);
        !          1316:                exit(0);
        !          1317:            }
        !          1318:        }
        !          1319: 
        !          1320:     printf("Mtrace from %s to %s via group %s\n",
        !          1321:           inet_fmt(qsrc, s1, sizeof(s1)), inet_fmt(qdst, s2, sizeof(s2)), inet_fmt(qgrp, s3, sizeof(s3)));
        !          1322: 
        !          1323:     if ((qdst & dst_netmask) == (qsrc & dst_netmask)) {
        !          1324:        printf("Source & receiver are directly connected, no path to trace\n");
        !          1325:        exit(0);
        !          1326:     }
        !          1327: 
        !          1328:     /*
        !          1329:      * If the response is to be a multicast address, make sure we 
        !          1330:      * are listening on that multicast address.
        !          1331:      */
        !          1332:     if (raddr) {
        !          1333:        if (IN_MULTICAST(ntohl(raddr))) k_join(raddr, lcl_addr);
        !          1334:     } else k_join(resp_cast, lcl_addr);
        !          1335: 
        !          1336:     /*
        !          1337:      * If the destination is on the local net, the last-hop router can
        !          1338:      * be found by multicast to the all-routers multicast group.
        !          1339:      * Otherwise, use the group address that is the subject of the
        !          1340:      * query since by definition the last-hop router will be a member.
        !          1341:      * Set default TTLs for local remote multicasts.
        !          1342:      */
        !          1343:   restart:
        !          1344: 
        !          1345:     if (gwy == 0) {
        !          1346:        if ((qdst & dst_netmask) == (lcl_addr & dst_netmask)) 
        !          1347:            tdst = query_cast;
        !          1348:        else
        !          1349:            tdst = qgrp;
        !          1350:     } else {
        !          1351:         tdst = gwy;
        !          1352:     }
        !          1353: 
        !          1354:     if (IN_MULTICAST(ntohl(tdst))) {
        !          1355:        k_set_loop(1);  /* If I am running on a router, I need to hear this */
        !          1356:        if (tdst == query_cast) k_set_ttl(qttl ? qttl : 1);
        !          1357:        else k_set_ttl(qttl ? qttl : MULTICAST_TTL1);
        !          1358:     }
        !          1359: 
        !          1360:     /*
        !          1361:      * Try a query at the requested number of hops or MAXHOPS if unspecified.
        !          1362:      */
        !          1363:     if (qno == 0) {
        !          1364:        hops = MAXHOPS;
        !          1365:        tries = 1;
        !          1366:        printf("Querying full reverse path... ");
        !          1367:        fflush(stdout);
        !          1368:     } else {
        !          1369:        hops = qno;
        !          1370:        tries = nqueries;
        !          1371:        printf("Querying reverse path, maximum %d hops... ", qno);
        !          1372:        fflush(stdout); 
        !          1373:     }
        !          1374:     base.rtime = 0;
        !          1375:     base.len = 0;
        !          1376: 
        !          1377:     recvlen = send_recv(tdst, IGMP_MTRACE, hops, tries, &base);
        !          1378: 
        !          1379:     /*
        !          1380:      * If the initial query was successful, print it.  Otherwise, if
        !          1381:      * the query max hop count is the default of zero, loop starting
        !          1382:      * from one until there is no response for four hops.  The extra
        !          1383:      * hops allow getting past an mtrace-capable mrouter that can't
        !          1384:      * send multicast packets because all phyints are disabled.
        !          1385:      */
        !          1386:     if (recvlen) {
        !          1387:        printf("\n  0  ");
        !          1388:        print_host(qdst);
        !          1389:        printf("\n");
        !          1390:        print_trace(1, &base);
        !          1391:        r = base.resps + base.len - 1;
        !          1392:        if (r->tr_rflags == TR_OLD_ROUTER || r->tr_rflags == TR_NO_SPACE ||
        !          1393:            qno != 0) {
        !          1394:            printf("%3d  ", -(base.len+1));
        !          1395:            what_kind(&base, r->tr_rflags == TR_OLD_ROUTER ?
        !          1396:                      "doesn't support mtrace"
        !          1397:                      : "is the next hop");
        !          1398:        } else {
        !          1399:            VAL_TO_MASK(smask, r->tr_smask);
        !          1400:            if ((r->tr_inaddr & smask) == (qsrc & smask)) {
        !          1401:                printf("%3d  ", -(base.len+1));
        !          1402:                print_host(qsrc);
        !          1403:                printf("\n");
        !          1404:            }
        !          1405:        }
        !          1406:     } else if (qno == 0) {
        !          1407:        printf("switching to hop-by-hop:\n  0  ");
        !          1408:        print_host(qdst);
        !          1409:        printf("\n");
        !          1410: 
        !          1411:        for (hops = 1, nexthop = 1; hops <= MAXHOPS; ++hops) {
        !          1412:            printf("%3d  ", -hops);
        !          1413:            fflush(stdout);
        !          1414: 
        !          1415:            /*
        !          1416:             * After a successful first hop, try switching to the unicast
        !          1417:             * address of the last-hop router instead of multicasting the
        !          1418:             * trace query.  This should be safe for mrouted versions 3.3
        !          1419:             * and 3.5 because there is a long route timeout with metric
        !          1420:             * infinity before a route disappears.  Switching to unicast
        !          1421:             * reduces the amount of multicast traffic and avoids a bug
        !          1422:             * with duplicate suppression in mrouted 3.5.
        !          1423:             */
        !          1424:            if (hops == 2 && gwy == 0 &&
        !          1425:                (recvlen = send_recv(lastout, IGMP_MTRACE, hops, 1, &base)))
        !          1426:                tdst = lastout;
        !          1427:            else recvlen = send_recv(tdst, IGMP_MTRACE, hops, nqueries, &base);
        !          1428: 
        !          1429:            if (recvlen == 0) {
        !          1430:                if (hops == 1) break;
        !          1431:                if (hops == nexthop) {
        !          1432:                    if (what_kind(&base, "didn't respond")) {
        !          1433:                        /* the ask_neighbors determined that the
        !          1434:                         * not-responding router is the first-hop. */
        !          1435:                        break;
        !          1436:                    }
        !          1437:                } else if (hops < nexthop + 3) {
        !          1438:                    printf("\n");
        !          1439:                } else {
        !          1440:                    printf("...giving up\n");
        !          1441:                    break;
        !          1442:                }
        !          1443:                continue;
        !          1444:            }
        !          1445:            r = base.resps + base.len - 1;
        !          1446:            if (base.len == hops &&
        !          1447:                (hops == 1 || (base.resps+nexthop-2)->tr_outaddr == lastout)) {
        !          1448:                if (hops == nexthop) {
        !          1449:                    print_trace(-hops, &base);
        !          1450:                } else {
        !          1451:                    printf("\nResuming...\n");
        !          1452:                    print_trace(nexthop, &base);
        !          1453:                }
        !          1454:            } else {
        !          1455:                if (base.len < hops) {
        !          1456:                    /*
        !          1457:                     * A shorter trace than requested means a fatal error
        !          1458:                     * occurred along the path, or that the route changed
        !          1459:                     * to a shorter one.
        !          1460:                     *
        !          1461:                     * If the trace is longer than the last one we received,
        !          1462:                     * then we are resuming from a skipped router (but there
        !          1463:                     * is still probably a problem).
        !          1464:                     *
        !          1465:                     * If the trace is shorter than the last one we
        !          1466:                     * received, then the route must have changed (and
        !          1467:                     * there is still probably a problem).
        !          1468:                     */
        !          1469:                    if (nexthop <= base.len) {
        !          1470:                        printf("\nResuming...\n");
        !          1471:                        print_trace(nexthop, &base);
        !          1472:                    } else if (nexthop > base.len + 1) {
        !          1473:                        hops = base.len;
        !          1474:                        printf("\nRoute must have changed...\n");
        !          1475:                        print_trace(1, &base);
        !          1476:                    }
        !          1477:                } else {
        !          1478:                    /*
        !          1479:                     * The last hop address is not the same as it was;
        !          1480:                     * the route probably changed underneath us.
        !          1481:                     */
        !          1482:                    hops = base.len;
        !          1483:                    printf("\nRoute must have changed...\n");
        !          1484:                    print_trace(1, &base);
        !          1485:                }
        !          1486:            }
        !          1487:            lastout = r->tr_outaddr;
        !          1488: 
        !          1489:            if (base.len < hops ||
        !          1490:                r->tr_rmtaddr == 0 ||
        !          1491:                (r->tr_rflags & 0x80)) {
        !          1492:                VAL_TO_MASK(smask, r->tr_smask);
        !          1493:                if (r->tr_rmtaddr) {
        !          1494:                    if (hops != nexthop) {
        !          1495:                        printf("\n%3d  ", -(base.len+1));
        !          1496:                    }
        !          1497:                    what_kind(&base, r->tr_rflags == TR_OLD_ROUTER ?
        !          1498:                              "doesn't support mtrace" :
        !          1499:                              "would be the next hop");
        !          1500:                    /* XXX could do segmented trace if TR_NO_SPACE */
        !          1501:                } else if (r->tr_rflags == TR_NO_ERR &&
        !          1502:                           (r->tr_inaddr & smask) == (qsrc & smask)) {
        !          1503:                    printf("%3d  ", -(hops + 1));
        !          1504:                    print_host(qsrc);
        !          1505:                    printf("\n");
        !          1506:                }
        !          1507:                break;
        !          1508:            }
        !          1509: 
        !          1510:            nexthop = hops + 1;
        !          1511:        }
        !          1512:     }
        !          1513: 
        !          1514:     if (base.rtime == 0) {
        !          1515:        printf("Timed out receiving responses\n");
        !          1516:        if (IN_MULTICAST(ntohl(tdst))) {
        !          1517:             if (tdst == query_cast)
        !          1518:                 printf("Perhaps no local router has a route for source %s\n",
        !          1519:                        inet_fmt(qsrc, s1, sizeof(s1)));
        !          1520:             else
        !          1521:                 printf("Perhaps receiver %s is not a member of group %s,\n"
        !          1522:                       "or no router local to it has a route for source %s,\n"
        !          1523:                       "or multicast at ttl %d doesn't reach its last-hop router for that source\n",
        !          1524:                        inet_fmt(qdst, s2, sizeof(s2)), inet_fmt(qgrp, s3, sizeof(s3)), inet_fmt(qsrc, s1, sizeof(s1)),
        !          1525:                        qttl ? qttl : MULTICAST_TTL1);
        !          1526:         }
        !          1527:        exit(1);
        !          1528:     }
        !          1529: 
        !          1530:     printf("Round trip time %d ms\n\n", t_diff(base.rtime, base.qtime));
        !          1531: 
        !          1532:     /*
        !          1533:      * Use the saved response which was the longest one received,
        !          1534:      * and make additional probes after delay to measure loss.
        !          1535:      */
        !          1536:     raddr = base.qhdr.tr_raddr;
        !          1537:     rttl = base.qhdr.tr_rttl;
        !          1538:     gettimeofday(&tv, 0);
        !          1539:     waittime = statint - (((tv.tv_sec + JAN_1970) & 0xFFFF) - (base.qtime >> 16));
        !          1540:     prev = &base;
        !          1541:     new = &incr[numstats&1];
        !          1542: 
        !          1543:     while (numstats--) {
        !          1544:        if (waittime < 1) printf("\n");
        !          1545:        else {
        !          1546:            printf("Waiting to accumulate statistics... ");
        !          1547:            fflush(stdout);
        !          1548:            sleep((unsigned)waittime);
        !          1549:        }
        !          1550:        rno = base.len;
        !          1551:        recvlen = send_recv(tdst, IGMP_MTRACE, rno, nqueries, new);
        !          1552: 
        !          1553:        if (recvlen == 0) {
        !          1554:            printf("Timed out.\n");
        !          1555:            exit(1);
        !          1556:        }
        !          1557: 
        !          1558:        if (rno != new->len) {
        !          1559:            printf("Trace length doesn't match:\n");
        !          1560:            /*
        !          1561:             * XXX Should this trace result be printed, or is that
        !          1562:             * too verbose?  Perhaps it should just say restarting.
        !          1563:             * But if the path is changing quickly, this may be the
        !          1564:             * only snapshot of the current path.  But, if the path
        !          1565:             * is changing that quickly, does the current path really
        !          1566:             * matter?
        !          1567:             */
        !          1568:            print_trace(1, new);
        !          1569:            printf("Restarting.\n\n");
        !          1570:            numstats++;
        !          1571:            goto restart;
        !          1572:        }
        !          1573: 
        !          1574:        printf("Results after %d seconds:\n\n",
        !          1575:               (int)((new->qtime - base.qtime) >> 16));
        !          1576:        fixup_stats(&base, prev, new);
        !          1577:        if (print_stats(&base, prev, new)) {
        !          1578:            printf("Route changed:\n");
        !          1579:            print_trace(1, new);
        !          1580:            printf("Restarting.\n\n");
        !          1581:            goto restart;
        !          1582:        }
        !          1583:        prev = new;
        !          1584:        new = &incr[numstats&1];
        !          1585:        waittime = statint;
        !          1586:     }
        !          1587: 
        !          1588:     /*
        !          1589:      * If the response was multicast back, leave the group
        !          1590:      */
        !          1591:     if (raddr) {
        !          1592:        if (IN_MULTICAST(ntohl(raddr))) k_leave(raddr, lcl_addr);
        !          1593:     } else k_leave(resp_cast, lcl_addr);
        !          1594: 
        !          1595:     return (0);
        !          1596: }
        !          1597: 
        !          1598: void check_vif_state(void)
        !          1599: {
        !          1600:     logit(LOG_WARNING, errno, "sendto");
        !          1601: }
        !          1602: 
        !          1603: /*
        !          1604:  * Log errors and other messages to stderr, according to the severity
        !          1605:  * of the message and the current debug level.  For errors of severity
        !          1606:  * LOG_ERR or worse, terminate the program.
        !          1607:  */
        !          1608: void logit(int severity, int syserr, const char *format, ...)
        !          1609: {
        !          1610:     va_list ap;
        !          1611: 
        !          1612:     switch (debug) {
        !          1613:        case 0:
        !          1614:            if (severity > LOG_WARNING)
        !          1615:                return;
        !          1616:        case 1:
        !          1617:            if (severity > LOG_NOTICE)
        !          1618:                return;
        !          1619:        case 2:
        !          1620:            if (severity > LOG_INFO)
        !          1621:                return;
        !          1622:        default:
        !          1623:            if (severity == LOG_WARNING)
        !          1624:                fprintf(stderr, "warning - ");
        !          1625:            va_start(ap, format);
        !          1626:            vfprintf(stderr, format, ap);
        !          1627:            va_end(ap);
        !          1628:            if (syserr == 0)
        !          1629:                fprintf(stderr, "\n");
        !          1630:            else
        !          1631:                fprintf(stderr, ": %s\n", strerror(syserr));
        !          1632:     }
        !          1633: 
        !          1634:     if (severity <= LOG_ERR)
        !          1635:        exit(1);
        !          1636: }
        !          1637: 
        !          1638: /* dummies */
        !          1639: void accept_probe(u_int32_t UNUSED src, u_int32_t UNUSED dst, char UNUSED *p, size_t UNUSED datalen, u_int32_t UNUSED level)
        !          1640: {
        !          1641: }
        !          1642: 
        !          1643: void accept_group_report(u_int32_t UNUSED src, u_int32_t UNUSED dst, u_int32_t UNUSED group, int UNUSED r_type)
        !          1644: {
        !          1645: }
        !          1646: 
        !          1647: void accept_neighbor_request2(u_int32_t UNUSED src, u_int32_t UNUSED dst)
        !          1648: {
        !          1649: }
        !          1650: 
        !          1651: void accept_report(u_int32_t UNUSED src, u_int32_t UNUSED dst, char UNUSED *p, size_t UNUSED datalen, u_int32_t UNUSED level)
        !          1652: {
        !          1653: }
        !          1654: 
        !          1655: void accept_neighbor_request(u_int32_t UNUSED src, u_int32_t UNUSED dst)
        !          1656: {
        !          1657: }
        !          1658: 
        !          1659: void accept_prune(u_int32_t UNUSED src, u_int32_t UNUSED dst, char UNUSED *p, size_t UNUSED datalen)
        !          1660: {
        !          1661: }
        !          1662: 
        !          1663: void accept_graft(u_int32_t UNUSED src, u_int32_t UNUSED dst, char UNUSED *p, size_t UNUSED datalen)
        !          1664: {
        !          1665: }
        !          1666: 
        !          1667: void accept_g_ack(u_int32_t UNUSED src, u_int32_t UNUSED dst, char UNUSED *p, size_t UNUSED datalen)
        !          1668: {
        !          1669: }
        !          1670: 
        !          1671: void add_table_entry(u_int32_t UNUSED origin, u_int32_t UNUSED mcastgrp)
        !          1672: {
        !          1673: }
        !          1674: 
        !          1675: void accept_leave_message(u_int32_t UNUSED src, u_int32_t UNUSED dst, u_int32_t UNUSED group)
        !          1676: {
        !          1677: }
        !          1678: 
        !          1679: void accept_mtrace(u_int32_t UNUSED src, u_int32_t UNUSED dst, u_int32_t UNUSED group, char UNUSED *data, u_int8_t UNUSED no, size_t UNUSED datalen)
        !          1680: {
        !          1681: }
        !          1682: 
        !          1683: void accept_membership_query(u_int32_t UNUSED src, u_int32_t UNUSED dst, u_int32_t UNUSED group, int UNUSED tmo)
        !          1684: {
        !          1685: }
        !          1686: 
        !          1687: void accept_neighbors(u_int32_t UNUSED src, u_int32_t UNUSED dst, u_char UNUSED *p, size_t UNUSED datalen, u_int32_t UNUSED level)
        !          1688: {
        !          1689: }
        !          1690: 
        !          1691: void accept_neighbors2(u_int32_t UNUSED src, u_int32_t UNUSED dst, u_char UNUSED *p, size_t UNUSED datalen, u_int32_t UNUSED level)
        !          1692: {
        !          1693: }
        !          1694: 
        !          1695: void accept_info_request(u_int32_t UNUSED src, u_int32_t UNUSED dst, u_char UNUSED *p, size_t UNUSED datalen)
        !          1696: {
        !          1697: }
        !          1698: 
        !          1699: void accept_info_reply(u_int32_t UNUSED src, u_int32_t UNUSED dst, u_char UNUSED *p, size_t UNUSED datalen)
        !          1700: {
        !          1701: }
        !          1702: 
        !          1703: /**
        !          1704:  * Local Variables:
        !          1705:  *  version-control: t
        !          1706:  *  indent-tabs-mode: t
        !          1707:  *  c-file-style: "ellemtel"
        !          1708:  *  c-basic-offset: 4
        !          1709:  * End:
        !          1710:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>