home *** CD-ROM | disk | FTP | other *** search
/ ftp.ee.lbl.gov / 2014.05.ftp.ee.lbl.gov.tar / ftp.ee.lbl.gov / mtrace.c < prev    next >
C/C++ Source or Header  |  1995-10-25  |  39KB  |  1,590 lines

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