Annotation of embedaddon/mrouted/mtrace.c, revision 1.1.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>