Sweep-fix comparing pointers with 0 (and assigning 0 to pointers).
[dragonfly.git] / usr.sbin / mrouted / mtrace.c
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 any purposes and without
27  * fee is hereby granted, provided that the above copyright notice
28  * appear in all copies and that both the copyright notice and this
29  * permission notice appear in supporting documentation, and that any
30  * documentation, advertising materials, and other materials related to
31  * such distribution and use acknowledge that the software was developed
32  * by the University of Southern California, Information Sciences
33  * Institute.  The name of the University may not be used to endorse or
34  * promote products derived from this software without specific prior
35  * 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  * Parts of this software are derived from mrouted, which has the
47  * following license:
48  * 
49  * The mrouted program is covered by the following license.  Use of the
50  * mrouted program represents acceptance of these terms and conditions.
51  * 
52  * 1. STANFORD grants to LICENSEE a nonexclusive and nontransferable
53  * license to use, copy and modify the computer software ``mrouted''
54  * (hereinafter called the ``Program''), upon the terms and conditions
55  * hereinafter set out and until Licensee discontinues use of the Licensed
56  * Program.
57  * 
58  * 2. LICENSEE acknowledges that the Program is a research tool still in
59  * the development state, that it is being supplied ``as is,'' without any
60  * accompanying services from STANFORD, and that this license is entered
61  * into in order to encourage scientific collaboration aimed at further
62  * development and application of the Program.
63  * 
64  * 3. LICENSEE may copy the Program and may sublicense others to use
65  * object code copies of the Program or any derivative version of the
66  * Program.  All copies must contain all copyright and other proprietary
67  * notices found in the Program as provided by STANFORD.  Title to
68  * copyright to the Program remains with STANFORD.
69  * 
70  * 4. LICENSEE may create derivative versions of the Program.  LICENSEE
71  * hereby grants STANFORD a royalty-free license to use, copy, modify,
72  * distribute and sublicense any such derivative works.  At the time
73  * LICENSEE provides a copy of a derivative version of the Program to a
74  * third party, LICENSEE shall provide STANFORD with one copy of the
75  * source code of the derivative version at no charge to STANFORD.
76  * 
77  * 5. STANFORD MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
78  * IMPLIED.  By way of example, but not limitation, STANFORD MAKES NO
79  * REPRESENTATION OR WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY
80  * PARTICULAR PURPOSE OR THAT THE USE OF THE LICENSED PROGRAM WILL NOT
81  * INFRINGE ANY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. STANFORD
82  * shall not be held liable for any liability nor for any direct, indirect
83  * or consequential damages with respect to any claim by LICENSEE or any
84  * third party on account of or arising from this Agreement or use of the
85  * Program.
86  * 
87  * 6. This agreement shall be construed, interpreted and applied in
88  * accordance with the State of California and any legal action arising
89  * out of this Agreement or use of the Program shall be filed in a court
90  * in the State of California.
91  * 
92  * 7. Nothing in this Agreement shall be construed as conferring rights to
93  * use in advertising, publicity or otherwise any trademark or the name
94  * of ``Stanford''.
95  * 
96  * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
97  * Leland Stanford Junior University.
98  *
99  *
100  * The mtrace program has been modified and improved by Xerox
101  * Corporation.  Xerox grants to LICENSEE a non-exclusive and
102  * non-transferable license to use, copy, and modify the Xerox modified
103  * and improved mrouted software on the same terms and conditions which
104  * govern the license Stanford and ISI grant with respect to the mtrace
105  * program.  These terms and conditions are incorporated in this grant
106  * by reference and shall be deemed to have been accepted by LICENSEE
107  * to cover its relationship with Xerox Corporation with respect to any
108  * use of the Xerox improved program.
109  * 
110  * The mtrace program is COPYRIGHT 1998 by Xerox Corporation.
111  *
112  * $FreeBSD: src/usr.sbin/mrouted/mtrace.c,v 1.17.2.3 2002/09/12 16:27:49 nectar Exp $
113  */
114
115 #include <ctype.h>
116 #include <err.h>
117 #include <errno.h>
118 #include <memory.h>
119 #include <netdb.h>
120 #include <stdio.h>
121 #include <stdlib.h>
122 #include <string.h>
123 #include <syslog.h>
124 #include <unistd.h>
125 #include <sys/param.h>
126 #include <sys/types.h>
127 #include <sys/socket.h>
128 #include <sys/time.h>
129 #include <net/if.h>
130 #include <netinet/in.h>
131 #include <netinet/in_systm.h>
132 #include <netinet/ip.h>
133 #include <netinet/igmp.h>
134 #include <sys/ioctl.h>
135 #ifdef SYSV
136 #include <sys/sockio.h>
137 #endif
138 #include <arpa/inet.h>
139 #include <stdarg.h>
140 #ifdef SUNOS5
141 #include <sys/systeminfo.h>
142 #endif
143
144 typedef unsigned int u_int32;   /* XXX */
145 #include "mtrace.h"
146
147 #define DEFAULT_TIMEOUT 3       /* How long to wait before retrying requests */
148 #define DEFAULT_RETRIES 3       /* How many times to try */
149 #define DEFAULT_EXTRAHOPS 3     /* How many hops past a non-responding rtr */
150 #define MAXHOPS 60              /* Don't need more hops than this */
151 #define UNICAST_TTL 255         /* TTL for unicast response */
152 #define MULTICAST_TTL1 127      /* Default TTL for multicast query/response */
153 #define MULTICAST_TTL_INC 32    /* TTL increment for increase after timeout */
154 #define MULTICAST_TTL_MAX 192   /* Maximum TTL allowed (protect low-BW links */
155
156 #define TRUE 1
157 #define FALSE 0
158 #define DVMRP_ASK_NEIGHBORS2    5       /* DVMRP msg requesting neighbors */
159 #define DVMRP_NEIGHBORS2        6       /* reply to above */
160 #define DVMRP_NF_DOWN           0x10    /* kernel state of interface */
161 #define DVMRP_NF_DISABLED       0x20    /* administratively disabled */
162 #define MAX_IP_PACKET_LEN       576
163 #define MIN_IP_HEADER_LEN       20
164 #define MAX_IP_HEADER_LEN       60
165 #define MAX_DVMRP_DATA_LEN \
166                 ( MAX_IP_PACKET_LEN - MAX_IP_HEADER_LEN - IGMP_MINLEN )
167
168 struct resp_buf {
169     u_long qtime;               /* Time query was issued */
170     u_long rtime;               /* Time response was received */
171     int len;                    /* Number of reports or length of data */
172     struct igmp igmp;           /* IGMP header */
173     union {
174         struct {
175             struct tr_query q;          /* Query/response header */
176             struct tr_resp r[MAXHOPS];  /* Per-hop reports */
177         } t;
178         char d[MAX_DVMRP_DATA_LEN];     /* Neighbor data */
179     } u;
180 } base, incr[2];
181
182 #define qhdr u.t.q
183 #define resps u.t.r
184 #define ndata u.d
185
186 char *names[MAXHOPS];
187
188 /*
189  * In mrouted 3.3 and 3.4 (and in some Cisco IOS releases),
190  * cache entries can get deleted even if there is traffic
191  * flowing, which will reset the per-source/group counters.
192  */
193 #define         BUG_RESET       0x01
194
195 /*
196  * Also in mrouted 3.3 and 3.4, there's a bug in neighbor
197  * version processing which can cause them to believe that
198  * the neighbor is constantly resetting.  This causes them
199  * to constantly delete all their state.
200  */
201 #define         BUG_RESET2X     0x02
202
203 /*
204  * Pre-3.7 mrouted's forget to byte-swap their reports.
205  */
206 #define         BUG_SWAP        0x04
207
208 /*
209  * Pre-3.9 mrouted's forgot a parenthesis in the htonl()
210  * on the time calculation so supply bogus times.
211  */
212 #define         BUG_BOGUSTIME   0x08
213
214 #define BUG_NOPRINT     (BUG_RESET | BUG_RESET2X)
215
216 int bugs[MAXHOPS];                      /* List of bugs noticed at each hop */
217
218 struct mtrace {
219         struct mtrace   *next;
220         struct resp_buf  base, incr[2];
221         struct resp_buf *new, *prev;
222         int              nresp;
223         struct timeval   last;
224         int              bugs[MAXHOPS];
225         char            *names[MAXHOPS];
226         int              lastqid;
227 };
228
229 int timeout = DEFAULT_TIMEOUT;
230 int nqueries = DEFAULT_RETRIES;
231 int numeric = FALSE;
232 int debug = 0;
233 int passive = FALSE;
234 int multicast = FALSE;
235 int unicast = FALSE;
236 int statint = 10;
237 int verbose = FALSE;
238 int tunstats = FALSE;
239 int weak = FALSE;
240 int extrahops = DEFAULT_EXTRAHOPS;
241 int printstats = TRUE;
242 int sendopts = TRUE;
243 int lossthresh = 0;
244 int fflag = FALSE;
245 int staticqid = 0;
246
247 u_int32 defgrp;                         /* Default group if not specified */
248 u_int32 query_cast;                     /* All routers multicast addr */
249 u_int32 resp_cast;                      /* Mtrace response multicast addr */
250
251 u_int32 lcl_addr = 0;                   /* This host address, in NET order */
252 u_int32 dst_netmask = 0;                /* netmask to go with qdst */
253
254 /*
255  * Query/response parameters, all initialized to zero and set later
256  * to default values or from options.
257  */
258 u_int32 qsrc = 0;               /* Source address in the query */
259 u_int32 qgrp = 0;               /* Group address in the query */
260 u_int32 qdst = 0;               /* Destination (receiver) address in query */
261 u_char qno  = 0;                /* Max number of hops to query */
262 u_int32 raddr = 0;              /* Address where response should be sent */
263 int    qttl = 0;                /* TTL for the query packet */
264 u_char rttl = 0;                /* TTL for the response packet */
265 u_int32 gwy = 0;                /* User-supplied last-hop router address */
266 u_int32 tdst = 0;               /* Address where trace is sent (last-hop) */
267
268 char s1[19];            /* buffers to hold the string representations  */
269 char s2[19];            /* of IP addresses, to be passed to inet_fmt() */
270 char s3[19];            /* or inet_fmts().                             */
271
272 #if !(defined(BSD) && (BSD >= 199103))
273 extern int              errno;
274 extern int              sys_nerr;
275 extern char *           sys_errlist[];
276 #endif
277
278 #define RECV_BUF_SIZE 8192
279 char    *send_buf, *recv_buf;
280 int     igmp_socket;
281 u_int32 allrtrs_group;
282 char    router_alert[4];                /* Router Alert IP Option           */
283 #ifndef IPOPT_RA
284 #define IPOPT_RA                148
285 #endif
286 #ifdef SUNOS5
287 char    eol[4];                         /* EOL IP Option                    */
288 int ip_addlen = 0;                      /* Workaround for Option bug #2     */
289 #endif
290
291 /*
292  * max macro, with weird case to avoid conflicts
293  */
294 #define MaX(a,b)        ((a) > (b) ? (a) : (b))
295
296 typedef int (*callback_t)(int, u_char *, int, struct igmp *, int,
297                         struct sockaddr *, int *, struct timeval *);
298
299 void                    init_igmp(void);
300 void                    send_igmp(u_int32 src, u_int32 dst, int type,
301                                                 int code, u_int32 group,
302                                                 int datalen);
303 int                     inet_cksum(u_short *addr, u_int len);
304 void                    k_set_rcvbuf(int bufsize);
305 void                    k_hdr_include(int boolv);
306 void                    k_set_ttl(int t);
307 void                    k_set_loop(int l);
308 void                    k_set_if(u_int32 ifa);
309 void                    k_join(u_int32 grp, u_int32 ifa);
310 void                    k_leave(u_int32 grp, u_int32 ifa);
311 char *                  inet_fmt(u_int32 addr, char *s);
312 char *                  inet_fmts(u_int32 addr, u_int32 mask, char *s);
313 char *                  inet_name(u_int32 addr);
314 u_int32                 host_addr(char *name);
315 /* u_int is promoted u_char */
316 char *                  proto_type(u_int type);
317 char *                  flag_type(u_int type);
318
319 u_int32                 get_netmask(int s, u_int32 *dst);
320 int                     get_ttl(struct resp_buf *buf);
321 int                     t_diff(u_long a, u_long b);
322 u_long                  byteswap(u_long v);
323 int                     mtrace_callback(int, u_char *, int, struct igmp *,
324                                         int, struct sockaddr *, int *,
325                                         struct timeval *);
326 int                     send_recv(u_int32 dst, int type, int code,
327                                         int tries, struct resp_buf *save,
328                                         callback_t callback);
329 void                    passive_mode(void);
330 char *                  print_host(u_int32 addr);
331 char *                  print_host2(u_int32 addr1, u_int32 addr2);
332 void                    print_trace(int idx, struct resp_buf *buf,
333                                         char **names);
334 int                     what_kind(struct resp_buf *buf, char *why);
335 char *                  scale(int *hop);
336 void                    stat_line(struct tr_resp *r, struct tr_resp *s,
337                                         int have_next, int *res);
338 void                    fixup_stats(struct resp_buf *base,
339                                         struct resp_buf *prev,
340                                         struct resp_buf *new,
341                                         int *bugs);
342 int                     check_thresh(int thresh,
343                                         struct resp_buf *base,
344                                         struct resp_buf *prev,
345                                         struct resp_buf *new);
346 int                     print_stats(struct resp_buf *base,
347                                         struct resp_buf *prev,
348                                         struct resp_buf *new,
349                                         int *bugs,
350                                         char **names);
351 int                     path_changed(struct resp_buf *base,
352                                         struct resp_buf *new);
353 void                    check_vif_state(void);
354
355 int                     main(int argc, char **argv);
356 void                    dolog(int, int, char *, ...) __printflike(3, 4);
357 static void             usage(void);
358
359
360 /*
361  * Open and initialize the igmp socket, and fill in the non-changing
362  * IP header fields in the output packet buffer.
363  */
364 void
365 init_igmp(void)
366 {
367     struct ip *ip;
368
369     recv_buf = (char *)malloc(RECV_BUF_SIZE);
370     if (recv_buf == NULL)
371         dolog(LOG_ERR, 0, "Out of memory allocating recv_buf!");
372     send_buf = (char *)malloc(RECV_BUF_SIZE);
373     if (send_buf == NULL)
374         dolog(LOG_ERR, 0, "Out of memory allocating send_buf!");
375
376     if ((igmp_socket = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP)) < 0) 
377         dolog(LOG_ERR, errno, "IGMP socket");
378
379     k_hdr_include(TRUE);        /* include IP header when sending */
380     k_set_rcvbuf(48*1024);      /* lots of input buffering        */
381     k_set_ttl(1);               /* restrict multicasts to one hop */
382     k_set_loop(FALSE);          /* disable multicast loopback     */
383
384     ip         = (struct ip *)send_buf;
385     ip->ip_hl  = sizeof(struct ip) >> 2;
386     ip->ip_v   = IPVERSION;
387     ip->ip_tos = 0;
388     ip->ip_off = 0;
389     ip->ip_p   = IPPROTO_IGMP;
390     ip->ip_ttl = MAXTTL;        /* applies to unicasts only */
391
392 #ifndef INADDR_ALLRTRS_GROUP
393 #define INADDR_ALLRTRS_GROUP    0xe0000002      /* 224.0.0.2 */
394 #endif
395     allrtrs_group  = htonl(INADDR_ALLRTRS_GROUP);
396
397     router_alert[0] = IPOPT_RA; /* Router Alert */
398     router_alert[1] = 4;        /* 4 bytes */
399     router_alert[2] = 0;
400     router_alert[3] = 0;
401 }
402
403 #ifdef SUNOS5
404 void
405 checkforsolarisbug(void)
406 {
407     u_int32 localhost = htonl(0x7f000001);
408
409     eol[0] = IPOPT_EOL;
410     eol[1] = IPOPT_EOL;
411     eol[2] = IPOPT_EOL;
412     eol[3] = IPOPT_EOL;
413
414     setsockopt(igmp_socket, IPPROTO_IP, IP_OPTIONS, eol, sizeof(eol));
415     /*
416      * Check if the kernel adds the options length to the packet
417      * length.  Send myself an IGMP packet of type 0 (illegal),
418      * with 4 IPOPT_EOL options, my PID (for collision detection)
419      * and 4 bytes of zero (so that the checksum works whether
420      * the 4 bytes of zero get truncated or not).
421      */
422     bzero(send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN, 8);
423     *(int *)(send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN) = getpid();
424     send_igmp(localhost, localhost, 0, 0, 0, 8);
425     while (1) {
426         int recvlen, dummy = 0;
427
428         recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE,
429                                 0, NULL, &dummy);
430         /* 8 == 4 bytes of options and 4 bytes of PID */
431         if (recvlen >= MIN_IP_HEADER_LEN + IGMP_MINLEN + 8) {
432             struct ip *ip = (struct ip *)recv_buf;
433             struct igmp *igmp;
434             int *p;
435
436             if (ip->ip_hl != 6 ||
437                 ip->ip_p != IPPROTO_IGMP ||
438                 ip->ip_src.s_addr != localhost ||
439                 ip->ip_dst.s_addr != localhost)
440                 continue;
441
442             igmp = (struct igmp *)(recv_buf + (ip->ip_hl << 2));
443             if (igmp->igmp_group.s_addr != 0)
444                 continue;
445             if (igmp->igmp_type != 0 || igmp->igmp_code != 0)
446                 continue;
447
448             p = (int *)((char *)igmp + IGMP_MINLEN);
449             if (*p != getpid())
450                 continue;
451
452 #ifdef RAW_INPUT_IS_RAW
453             ip->ip_len = ntohs(ip->ip_len);
454 #endif
455             if (ip->ip_len == IGMP_MINLEN + 4)
456                 ip_addlen = 4;
457             else if (ip->ip_len == IGMP_MINLEN + 8)
458                 ip_addlen = 0;
459             else
460                 dolog(LOG_ERR, 0, "while checking for Solaris bug: Sent %d bytes and got back %d!", IGMP_MINLEN + 8, ip->ip_len);
461
462             break;
463         }
464     }
465 }
466 #endif
467
468 /*
469  * Construct an IGMP message in the output packet buffer.  The caller may
470  * have already placed data in that buffer, of length 'datalen'.  Then send
471  * the message from the interface with IP address 'src' to destination 'dst'.
472  */
473 void
474 send_igmp(u_int32 src, u_int32 dst, int type, int code, u_int32 group,
475           int datalen)
476 {
477     struct sockaddr_in sdst;
478     struct ip *ip;
479     struct igmp *igmp;
480     int setloop = 0;
481     static int raset = 0;
482     int sendra = 0;
483     int sendlen;
484
485     ip                      = (struct ip *)send_buf;
486     ip->ip_src.s_addr       = src;
487     ip->ip_dst.s_addr       = dst;
488     ip->ip_len              = MIN_IP_HEADER_LEN + IGMP_MINLEN + datalen;
489     sendlen                 = ip->ip_len;
490 #ifdef SUNOS5
491     ip->ip_len             += ip_addlen;
492 #endif
493 #ifdef RAW_OUTPUT_IS_RAW
494     ip->ip_len              = htons(ip->ip_len);
495 #endif
496
497     igmp                    = (struct igmp *)(send_buf + MIN_IP_HEADER_LEN);
498     igmp->igmp_type         = type;
499     igmp->igmp_code         = code;
500     igmp->igmp_group.s_addr = group;
501     igmp->igmp_cksum        = 0;
502     igmp->igmp_cksum        = inet_cksum((u_short *)igmp,
503                                          IGMP_MINLEN + datalen);
504
505     if (IN_MULTICAST(ntohl(dst))) {
506         k_set_if(src);
507         setloop = 1;
508         k_set_loop(TRUE);
509         if (dst != allrtrs_group)
510             sendra = 1;
511     }
512
513     if (sendopts && sendra && !raset) {
514         setsockopt(igmp_socket, IPPROTO_IP, IP_OPTIONS,
515                         router_alert, sizeof(router_alert));
516         raset = 1;
517     } else if (!sendra && raset) {
518 #ifdef SUNOS5
519         /*
520          * SunOS5 < 5.6 cannot properly reset the IP_OPTIONS "socket"
521          * option.  Instead, set up a string of 4 EOL's.
522          */
523         setsockopt(igmp_socket, IPPROTO_IP, IP_OPTIONS,
524                         eol, sizeof(eol));
525 #else
526         setsockopt(igmp_socket, IPPROTO_IP, IP_OPTIONS,
527                         NULL, 0);
528 #endif
529         raset = 0;
530     }
531
532     bzero(&sdst, sizeof(sdst));
533     sdst.sin_family = AF_INET;
534 #if (defined(BSD) && (BSD >= 199103))
535     sdst.sin_len = sizeof(sdst);
536 #endif
537     sdst.sin_addr.s_addr = dst;
538     if (sendto(igmp_socket, send_buf, sendlen, 0,
539                         (struct sockaddr *)&sdst, sizeof(sdst)) < 0) {
540             dolog(LOG_WARNING, errno, "sendto to %s on %s",
541                 inet_fmt(dst, s1), inet_fmt(src, s2));
542     }
543
544     if (setloop)
545             k_set_loop(FALSE);
546
547     dolog(LOG_DEBUG, 0, "SENT %s from %-15s to %s",
548         type == IGMP_MTRACE ? "mtrace request" : "ask_neighbors",
549         src == INADDR_ANY ? "INADDR_ANY" : inet_fmt(src, s1),
550         inet_fmt(dst, s2));
551 }
552
553 /*
554  * inet_cksum extracted from:
555  *                      P I N G . C
556  *
557  * Author -
558  *      Mike Muuss
559  *      U. S. Army Ballistic Research Laboratory
560  *      December, 1983
561  * Modified at Uc Berkeley
562  *
563  * (ping.c) Status -
564  *      Public Domain.  Distribution Unlimited.
565  *
566  *                      I N _ C K S U M
567  *
568  * Checksum routine for Internet Protocol family headers (C Version)
569  *
570  */
571 int
572 inet_cksum(u_short *addr, u_int len)
573 {
574         int nleft = (int)len;
575         u_short *w = addr;
576         u_short answer = 0;
577         int sum = 0;
578
579         /*
580          *  Our algorithm is simple, using a 32 bit accumulator (sum),
581          *  we add sequential 16 bit words to it, and at the end, fold
582          *  back all the carry bits from the top 16 bits into the lower
583          *  16 bits.
584          */
585         while (nleft > 1)  {
586                 sum += *w++;
587                 nleft -= 2;
588         }
589
590         /* mop up an odd byte, if necessary */
591         if (nleft == 1) {
592                 *(u_char *) (&answer) = *(u_char *)w ;
593                 sum += answer;
594         }
595
596         /*
597          * add back carry outs from top 16 bits to low 16 bits
598          */
599         sum = (sum >> 16) + (sum & 0xffff);     /* add hi 16 to low 16 */
600         sum += (sum >> 16);                     /* add carry */
601         answer = ~sum;                          /* truncate to 16 bits */
602         return (answer);
603 }
604
605 void
606 k_set_rcvbuf(int bufsize)
607 {
608     if (setsockopt(igmp_socket, SOL_SOCKET, SO_RCVBUF,
609                    (char *)&bufsize, sizeof(bufsize)) < 0)
610         dolog(LOG_ERR, errno, "setsockopt SO_RCVBUF %u", bufsize);
611 }
612
613
614 void
615 k_hdr_include(int boolv)
616 {
617 #ifdef IP_HDRINCL
618     if (setsockopt(igmp_socket, IPPROTO_IP, IP_HDRINCL,
619                    (char *)&boolv, sizeof(boolv)) < 0)
620         dolog(LOG_ERR, errno, "setsockopt IP_HDRINCL %u", boolv);
621 #endif
622 }
623
624 void
625 k_set_ttl(int t)
626 {
627     u_char ttl;
628
629     ttl = t;
630     if (setsockopt(igmp_socket, IPPROTO_IP, IP_MULTICAST_TTL,
631                    (char *)&ttl, sizeof(ttl)) < 0)
632         dolog(LOG_ERR, errno, "setsockopt IP_MULTICAST_TTL %u", ttl);
633 }
634
635
636 void
637 k_set_loop(int l)
638 {
639     u_char loop;
640
641     loop = l;
642     if (setsockopt(igmp_socket, IPPROTO_IP, IP_MULTICAST_LOOP,
643                    (char *)&loop, sizeof(loop)) < 0)
644         dolog(LOG_ERR, errno, "setsockopt IP_MULTICAST_LOOP %u", loop);
645 }
646
647 void
648 k_set_if(u_int32 ifa)
649 {
650     struct in_addr adr;
651
652     adr.s_addr = ifa;
653     if (setsockopt(igmp_socket, IPPROTO_IP, IP_MULTICAST_IF,
654                    (char *)&adr, sizeof(adr)) < 0)
655         dolog(LOG_ERR, errno, "setsockopt IP_MULTICAST_IF %s",
656                             inet_fmt(ifa, s1));
657 }
658
659 void
660 k_join(u_int32 grp, u_int32 ifa)
661 {
662     struct ip_mreq mreq;
663
664     mreq.imr_multiaddr.s_addr = grp;
665     mreq.imr_interface.s_addr = ifa;
666
667     if (setsockopt(igmp_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP,
668                    (char *)&mreq, sizeof(mreq)) < 0)
669         dolog(LOG_WARNING, errno, "can't join group %s on interface %s",
670                                 inet_fmt(grp, s1), inet_fmt(ifa, s2));
671 }
672
673
674 void
675 k_leave(u_int32 grp, u_int32 ifa)
676 {
677     struct ip_mreq mreq;
678
679     mreq.imr_multiaddr.s_addr = grp;
680     mreq.imr_interface.s_addr = ifa;
681
682     if (setsockopt(igmp_socket, IPPROTO_IP, IP_DROP_MEMBERSHIP,
683                    (char *)&mreq, sizeof(mreq)) < 0)
684         dolog(LOG_WARNING, errno, "can't leave group %s on interface %s",
685                                 inet_fmt(grp, s1), inet_fmt(ifa, s2));
686 }
687
688 /*
689  * Convert an IP address in u_long (network) format into a printable string.
690  */
691 char *
692 inet_fmt(u_int32 addr, char *s)
693 {
694     u_char *a;
695
696     a = (u_char *)&addr;
697     sprintf(s, "%u.%u.%u.%u", a[0], a[1], a[2], a[3]);
698     return (s);
699 }
700
701
702 /*
703  * Convert an IP subnet number in u_long (network) format into a printable
704  * string including the netmask as a number of bits.
705  */
706 char *
707 inet_fmts(u_int32 addr, u_int32 mask, char *s)
708 {
709     u_char *a, *m;
710     int bits;
711
712     if ((addr == 0) && (mask == 0)) {
713         sprintf(s, "default");
714         return (s);
715     }
716     a = (u_char *)&addr;
717     m = (u_char *)&mask;
718     bits = 33 - ffs(ntohl(mask));
719
720     if      (m[3] != 0) sprintf(s, "%u.%u.%u.%u/%d", a[0], a[1], a[2], a[3],
721                                                 bits);
722     else if (m[2] != 0) sprintf(s, "%u.%u.%u/%d",    a[0], a[1], a[2], bits);
723     else if (m[1] != 0) sprintf(s, "%u.%u/%d",       a[0], a[1], bits);
724     else                sprintf(s, "%u/%d",          a[0], bits);
725
726     return (s);
727 }
728
729 char *
730 inet_name(u_int32 addr)
731 {
732     struct hostent *e;
733
734     e = gethostbyaddr(&addr, sizeof(addr), AF_INET);
735
736     return e ? e->h_name : "?";
737 }
738
739
740 u_int32 
741 host_addr(char *name)
742 {
743     struct hostent *e = NULL;
744     u_int32  addr;
745     int i, dots = 3;
746     char        buf[40];
747     char        *ip = name;
748     char        *op = buf;
749
750     /*
751      * Undo BSD's favor -- take fewer than 4 octets as net/subnet address
752      * if the name is all numeric.
753      */
754     for (i = sizeof(buf) - 7; i > 0; --i) {
755         if (*ip == '.') --dots;
756         else if (*ip == '\0') break;
757         else if (!isdigit(*ip)) dots = 0;  /* Not numeric, don't add zeroes */
758         *op++ = *ip++;
759     }
760     for (i = 0; i < dots; ++i) {
761         *op++ = '.';
762         *op++ = '0';
763     }
764     *op = '\0';
765
766     if (dots <= 0)
767         e = gethostbyname(name);
768     if (e && (e->h_length == sizeof(addr))) {
769         memcpy((char *)&addr, e->h_addr_list[0], e->h_length);
770         if (e->h_addr_list[1])
771             fprintf(stderr, "Warning: %s has multiple addresses, using %s\n",
772                         name, inet_fmt(addr, s1));
773     } else {
774         addr = inet_addr(buf);
775         if (addr == -1 || (IN_MULTICAST(addr) && dots)) {
776             addr = 0;
777             printf("Could not parse %s as host name or address\n", name);
778         }
779     }
780     return addr;
781 }
782
783
784 char *
785 proto_type(u_int type)
786 {
787     static char buf[80];
788
789     switch (type) {
790       case PROTO_DVMRP:
791         return ("DVMRP");
792       case PROTO_MOSPF:
793         return ("MOSPF");
794       case PROTO_PIM:
795         return ("PIM");
796       case PROTO_CBT:
797         return ("CBT");
798       case PROTO_PIM_SPECIAL:
799         return ("PIM/Special");
800       case PROTO_PIM_STATIC:
801         return ("PIM/Static");
802       case PROTO_DVMRP_STATIC:
803         return ("DVMRP/Static");
804       case PROTO_PIM_BGP4PLUS:
805         return ("PIM/BGP4+");
806       case PROTO_CBT_SPECIAL:
807         return ("CBT/Special");
808       case PROTO_CBT_STATIC:
809         return ("CBT/Static");
810       case PROTO_PIM_ASSERT:
811         return ("PIM/Assert");
812       case 0:
813         return ("None");
814       default:
815         sprintf(buf, "Unknown protocol code %d", type);
816         return (buf);
817     }
818 }
819
820
821 char *
822 flag_type(u_int type)
823 {
824     static char buf[80];
825
826     switch (type) {
827       case TR_NO_ERR:
828         return ("");
829       case TR_WRONG_IF:
830         return ("Wrong interface");
831       case TR_PRUNED:
832         return ("Prune sent upstream");
833       case TR_OPRUNED:
834         return ("Output pruned");
835       case TR_SCOPED:
836         return ("Hit scope boundary");
837       case TR_NO_RTE:
838         return ("No route");
839       case TR_NO_FWD:
840         return ("Not forwarding");
841       case TR_HIT_RP:
842         return ("Reached RP/Core");
843       case TR_RPF_IF:
844         return ("RPF Interface");
845       case TR_NO_MULTI:
846         return ("Multicast disabled");
847       case TR_OLD_ROUTER:
848         return ("Next router no mtrace");
849       case TR_NO_SPACE:
850         return ("No space in packet");
851       case TR_ADMIN_PROHIB:
852         return ("Admin. Prohibited");
853       default:
854         sprintf(buf, "Unknown error code %d", type);
855         return (buf);
856     }
857 }    
858
859 /*
860  * If destination is on a local net, get the netmask, else set the
861  * netmask to all ones.  There are two side effects: if the local
862  * address was not explicitly set, and if the destination is on a
863  * local net, use that one; in either case, verify that the local
864  * address is valid.
865  */
866 u_int32
867 get_netmask(int s, u_int32 *dst)
868 {
869     unsigned int n;
870     struct ifconf ifc;
871     struct ifreq *ifrp, *ifend;
872     u_int32 if_addr, if_mask;
873     u_int32 retval = 0xFFFFFFFF;
874     int found = FALSE;
875     int num_ifreq = 32;
876
877     ifc.ifc_len = num_ifreq * sizeof(struct ifreq);
878     ifc.ifc_buf = malloc(ifc.ifc_len);
879     while (ifc.ifc_buf) {
880         if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) {
881             perror("ioctl SIOCGIFCONF");
882             return retval;
883         }
884
885         /*
886          * If the buffer was large enough to hold all the addresses
887          * then break out, otherwise increase the buffer size and
888          * try again.
889          *
890          * The only way to know that we definitely had enough space
891          * is to know that there was enough space for at least one
892          * more struct ifreq. ???
893          */
894         if ((num_ifreq * sizeof(struct ifreq)) >=
895              ifc.ifc_len + sizeof(struct ifreq))
896              break;
897
898         num_ifreq *= 2;
899         ifc.ifc_len = num_ifreq * sizeof(struct ifreq);
900         ifc.ifc_buf = realloc(ifc.ifc_buf, ifc.ifc_len);
901     }
902     if (ifc.ifc_buf == NULL) {
903         fprintf(stderr, "getting interface list: ran out of memory");
904         exit(1);
905     }
906
907     ifrp = (struct ifreq *)ifc.ifc_buf;
908     ifend = (struct ifreq *)(ifc.ifc_buf + ifc.ifc_len);
909     /*
910      * Loop through all of the interfaces.
911      */
912     for (; ifrp < ifend && !found; ifrp = (struct ifreq *)((char *)ifrp + n)) {
913 #if BSD >= 199006
914         n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
915         if (n < sizeof(*ifrp))
916             n = sizeof(*ifrp);
917 #else
918         n = sizeof(*ifrp);
919 #endif
920         /*
921          * Ignore any interface for an address family other than IP.
922          */
923         if (ifrp->ifr_addr.sa_family != AF_INET)
924             continue;
925
926         if_addr = ((struct sockaddr_in *)&(ifrp->ifr_addr))->sin_addr.s_addr;
927         if (ioctl(s, SIOCGIFFLAGS, (char *)ifrp) < 0) {
928             fprintf(stderr, "SIOCGIFFLAGS on ");
929             perror(ifrp->ifr_name);
930             continue;
931         }
932         if ((ifrp->ifr_flags & (IFF_MULTICAST|IFF_UP|IFF_LOOPBACK)) !=
933                                 (IFF_MULTICAST|IFF_UP))
934             continue;
935         if (*dst == 0)
936             *dst = if_addr;
937         if (ioctl(s, SIOCGIFNETMASK, (char *)ifrp) >= 0) {
938             if_mask = ((struct sockaddr_in *)&(ifrp->ifr_addr))->sin_addr.s_addr;
939             if (if_mask != 0 && (*dst & if_mask) == (if_addr & if_mask)) {
940                 retval = if_mask;
941                 if (lcl_addr == 0) lcl_addr = if_addr;  /* XXX what about aliases? */
942             }
943         }
944         if (lcl_addr == if_addr) found = TRUE;
945     }
946     if (!found && lcl_addr != 0) {
947         printf("Interface address is not valid\n");
948         exit(1);
949     }
950     return (retval);
951 }
952
953
954 /*
955  * Try to pick a TTL that will get past all the thresholds in the path.
956  */
957 int
958 get_ttl(struct resp_buf *buf)
959 {
960     int rno;
961     struct tr_resp *b;
962     u_int ttl;
963
964     if (buf && (rno = buf->len) > 0) {
965         b = buf->resps + rno - 1;
966         ttl = b->tr_fttl;
967
968         while (--rno > 0) {
969             --b;
970             if (ttl < b->tr_fttl) ttl = b->tr_fttl;
971             else ++ttl;
972         }
973         ttl += MULTICAST_TTL_INC;
974         if (ttl < MULTICAST_TTL1) ttl = MULTICAST_TTL1;
975         if (ttl > MULTICAST_TTL_MAX) ttl = MULTICAST_TTL_MAX;
976         return (ttl);
977     } else return(MULTICAST_TTL1);
978 }
979
980 /*
981  * Calculate the difference between two 32-bit NTP timestamps and return
982  * the result in milliseconds.
983  */
984 int
985 t_diff(u_long a, u_long b)
986 {
987     int d = a - b;
988
989     return ((d * 125) >> 13);
990 }
991
992 /*
993  * Swap bytes for poor little-endian machines that don't byte-swap
994  */
995 u_long
996 byteswap(u_long v)
997 {
998     return ((v << 24) | ((v & 0xff00) << 8) |
999             ((v >> 8) & 0xff00) | (v >> 24));
1000 }
1001
1002 #if 0
1003 /*
1004  * XXX incomplete - need private callback data, too?
1005  * XXX since dst doesn't get passed through?
1006  */
1007 int
1008 neighbors_callback(int tmo, u_char *buf, int buflen, struct igmp *igmp,
1009                    int igmplen, struct sockaddr *addr, int *addrlen,
1010                    struct timeval *ts)
1011 {
1012     int len;
1013     u_int32 dst;
1014     struct ip *ip = (struct ip *)buf;
1015
1016     if (tmo)
1017         return 0;
1018
1019     if (igmp->igmp_code != DVMRP_NEIGHBORS2)
1020         return 0;
1021     len = igmplen;
1022     /*
1023      * Accept DVMRP_NEIGHBORS2 response if it comes from the
1024      * address queried or if that address is one of the local
1025      * addresses in the response.
1026      */
1027     if (ip->ip_src.s_addr != dst) {
1028         u_int32 *p = (u_int32 *)(igmp + 1);
1029         u_int32 *ep = p + (len >> 2);
1030         while (p < ep) {
1031             u_int32 laddr = *p++;
1032             int n = ntohl(*p++) & 0xFF;
1033             if (laddr == dst) {
1034                 ep = p + 1;             /* ensure p < ep after loop */
1035                 break;
1036             }
1037             p += n;
1038         }
1039         if (p >= ep)
1040             return 0;
1041     }
1042     return buflen;
1043 }
1044 #endif
1045
1046 int
1047 mtrace_callback(int tmo, u_char *buf, int buflen, struct igmp *igmp,
1048                 int igmplen, struct sockaddr *addr, int *addrlen,
1049                 struct timeval *ts)
1050 {
1051     static u_char *savbuf = NULL;
1052     static int savbuflen;
1053     static struct sockaddr *savaddr;
1054     static int savaddrlen;
1055     static struct timeval savts;
1056
1057     int len = (igmplen - QLEN) / RLEN;
1058     struct tr_resp *r = (struct tr_resp *)((struct tr_query *)(igmp + 1) + 1);
1059
1060     if (tmo == 1) {
1061         /*
1062          * If we timed out with a packet saved, then return that packet.
1063          * send_recv won't send this same packet to the callback again.
1064          */
1065         if (savbuf) {
1066             bcopy(savbuf, buf, savbuflen);
1067             free(savbuf);
1068             savbuf = NULL;
1069             bcopy(savaddr, addr, savaddrlen);
1070             free(savaddr);
1071             *addrlen = savaddrlen;
1072             bcopy(&savts, ts, sizeof(savts));
1073             return savbuflen;
1074         }
1075         return 0;
1076     }
1077     if (savbuf) {
1078         free(savbuf);
1079         savbuf = NULL;
1080         free(savaddr);
1081     }
1082     /*
1083      * Check for IOS bug described in CSCdi68628, where a router that does
1084      *  not have multicast enabled responds to an mtrace request with a 1-hop
1085      *  error packet.
1086      * Heuristic is:
1087      *  If there is only one hop reported in the packet,
1088      *  And the protocol code is 0,
1089      *  And there is no previous hop,
1090      *  And the forwarding information is "Not Forwarding",
1091      *  And the router is not on the same subnet as the destination of the
1092      *          trace,
1093      *  then drop this packet.  The "#if 0"'d code saves it and returns
1094      *   it on timeout, but timeouts are too common (e.g. routers with
1095      *   limited unicast routing tables, etc).
1096      */
1097     if (len == 1 && r->tr_rproto == 0 && r->tr_rmtaddr == 0 &&
1098                                         r->tr_rflags == TR_NO_FWD) {
1099         u_int32 smask;
1100
1101         VAL_TO_MASK(smask, r->tr_smask);
1102         if ((r->tr_outaddr & smask) != (qdst & smask)) {
1103 #if 0
1104             /* XXX should do this silently? */
1105             fprintf(stderr, "mtrace: probably IOS-buggy packet from %s\n",
1106                 inet_fmt(((struct sockaddr_in *)addr)->sin_addr.s_addr, s1));
1107             /* Save the packet to return if a timeout occurs. */
1108             savbuf = (u_char *)malloc(buflen);
1109             if (savbuf != NULL) {
1110                 bcopy(buf, savbuf, buflen);
1111                 savbuflen = buflen;
1112                 savaddr = (struct sockaddr *)malloc(*addrlen);
1113                 if (savaddr != NULL) {
1114                     bcopy(addr, savaddr, *addrlen);
1115                     savaddrlen = *addrlen;
1116                     bcopy(ts, &savts, sizeof(savts));
1117                 } else {
1118                     free(savbuf);
1119                     savbuf = NULL;
1120                 }
1121             }
1122 #endif
1123             return 0;
1124         }
1125     }
1126     return buflen;
1127 }
1128
1129 int
1130 send_recv(u_int32 dst, int type, int code, int tries, struct resp_buf *save,
1131           callback_t callback)
1132 {
1133     fd_set  fds;
1134     struct timeval tq, tr, tv;
1135     struct ip *ip;
1136     struct igmp *igmp;
1137     struct tr_query *query, *rquery;
1138     struct tr_resp *r;
1139     struct sockaddr_in recvaddr;
1140     u_int32 local, group;
1141     int ipdatalen, iphdrlen, igmpdatalen;
1142     int datalen;
1143     int count, recvlen, socklen = sizeof(recvaddr);
1144     int len;
1145     int i;
1146
1147     if (type == IGMP_MTRACE) {
1148         group = qgrp;
1149         datalen = sizeof(struct tr_query);
1150     } else {
1151         group = htonl(0xff03);
1152         datalen = 0;
1153     }
1154     if (IN_MULTICAST(ntohl(dst))) local = lcl_addr;
1155     else local = INADDR_ANY;
1156
1157     /*
1158      * If the reply address was not explictly specified, start off
1159      * with the standard multicast reply address, or the unicast
1160      * address of this host if the unicast flag was specified.
1161      * Then, if there is no response after trying half the tries
1162      * with multicast, switch to the unicast address of this host
1163      * if the multicast flag was not specified.  If the TTL was
1164      * also not specified, set a multicast TTL and increase it
1165      * for every try.
1166      */
1167     query = (struct tr_query *)(send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
1168     query->tr_raddr = raddr ? raddr : unicast ? lcl_addr : resp_cast;
1169     TR_SETTTL(query->tr_rttlqid, rttl ? rttl :
1170       IN_MULTICAST(ntohl(query->tr_raddr)) ? get_ttl(save) : UNICAST_TTL);
1171     query->tr_src   = qsrc;
1172     query->tr_dst   = qdst;
1173
1174     for (i = tries ; i > 0; --i) {
1175         int oqid;
1176
1177         if (tries == nqueries && raddr == 0) {
1178             if (i == (nqueries >> 1)) {
1179                 if (multicast && unicast) {
1180                     query->tr_raddr = resp_cast;
1181                     if (!rttl)
1182                         TR_SETTTL(query->tr_rttlqid, get_ttl(save));
1183                 } else if (!multicast) {
1184                     query->tr_raddr = lcl_addr;
1185                     TR_SETTTL(query->tr_rttlqid, UNICAST_TTL);
1186                 }
1187             }
1188             if (i < tries && IN_MULTICAST(ntohl(query->tr_raddr)) &&
1189                                                                 rttl == 0) {
1190                 TR_SETTTL(query->tr_rttlqid,
1191                         TR_GETTTL(query->tr_rttlqid) + MULTICAST_TTL_INC);
1192                 if (TR_GETTTL(query->tr_rttlqid) > MULTICAST_TTL_MAX)
1193                   TR_SETTTL(query->tr_rttlqid, MULTICAST_TTL_MAX);
1194             }
1195         }
1196
1197         /*
1198          * Change the qid for each request sent to avoid being confused
1199          * by duplicate responses
1200          */
1201         oqid = TR_GETQID(query->tr_rttlqid);
1202         if (staticqid)
1203             TR_SETQID(query->tr_rttlqid, staticqid);
1204         else
1205 #ifdef SYSV    
1206             TR_SETQID(query->tr_rttlqid, ((u_int32)lrand48() >> 8));
1207 #else
1208             TR_SETQID(query->tr_rttlqid, ((u_int32)arc4random() >> 8));
1209 #endif
1210
1211         /*
1212          * Set timer to calculate delays, then send query
1213          */
1214         gettimeofday(&tq, 0);
1215         send_igmp(local, dst, type, code, group, datalen);
1216
1217         /*
1218          * Wait for response, discarding false alarms
1219          */
1220         while (TRUE) {
1221             if (igmp_socket >= FD_SETSIZE)
1222                     dolog(LOG_ERR, 0, "descriptor too big");
1223             FD_ZERO(&fds);
1224             FD_SET(igmp_socket, &fds);
1225             gettimeofday(&tv, 0);
1226             tv.tv_sec = tq.tv_sec + timeout - tv.tv_sec;
1227             tv.tv_usec = tq.tv_usec - tv.tv_usec;
1228             if (tv.tv_usec < 0) tv.tv_usec += 1000000L, --tv.tv_sec;
1229             if (tv.tv_sec < 0) tv.tv_sec = tv.tv_usec = 0;
1230
1231             count = select(igmp_socket + 1, &fds, NULL, NULL, &tv);
1232
1233             if (count < 0) {
1234                 if (errno != EINTR) warn("select");
1235                 continue;
1236             } else if (count == 0) {
1237                 /*
1238                  * Timed out.  Notify the callback.
1239                  */
1240                 if (!callback || (recvlen = (callback)(1, recv_buf, 0, NULL, 0, (struct sockaddr *)&recvaddr, &socklen, &tr)) == 0) {
1241                     printf("* ");
1242                     fflush(stdout);
1243                     break;
1244                 }
1245             } else {
1246                 /*
1247                  * Data is available on the socket, so read it.
1248                  */
1249                 gettimeofday(&tr, 0);
1250                 recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE,
1251                                    0, (struct sockaddr *)&recvaddr, &socklen);
1252             }
1253
1254             if (recvlen <= 0) {
1255                 if (recvlen && errno != EINTR) warn("recvfrom");
1256                 continue;
1257             }
1258
1259             if (recvlen < sizeof(struct ip)) {
1260                 warnx("packet too short (%u bytes) for IP header", recvlen);
1261                 continue;
1262             }
1263             ip = (struct ip *) recv_buf;
1264             if (ip->ip_p == 0)  /* ignore cache creation requests */
1265                 continue;
1266
1267             iphdrlen = ip->ip_hl << 2;
1268 #ifdef RAW_INPUT_IS_RAW
1269             ipdatalen = ntohs(ip->ip_len);
1270 #else
1271             ipdatalen = ip->ip_len;
1272 #endif
1273             if (iphdrlen + ipdatalen != recvlen) {
1274                 warnx("packet shorter (%u bytes) than hdr+data len (%u+%u)",
1275                         recvlen, iphdrlen, ipdatalen);
1276                 continue;
1277             }
1278
1279             igmp = (struct igmp *) (recv_buf + iphdrlen);
1280             igmpdatalen = ipdatalen - IGMP_MINLEN;
1281             if (igmpdatalen < 0) {
1282                 warnx("IP data field too short (%u bytes) for IGMP from %s",
1283                         ipdatalen, inet_fmt(ip->ip_src.s_addr, s1));
1284                 continue;
1285             }
1286
1287             switch (igmp->igmp_type) {
1288
1289               case IGMP_DVMRP:
1290                 if (type != IGMP_DVMRP || code != DVMRP_ASK_NEIGHBORS2)
1291                         continue;
1292                 if (igmp->igmp_code != DVMRP_NEIGHBORS2) continue;
1293                 len = igmpdatalen;
1294                 /*
1295                  * Accept DVMRP_NEIGHBORS2 response if it comes from the
1296                  * address queried or if that address is one of the local
1297                  * addresses in the response.
1298                  */
1299                 if (ip->ip_src.s_addr != dst) {
1300                     u_int32 *p = (u_int32 *)(igmp + 1);
1301                     u_int32 *ep = p + (len >> 2);
1302                     while (p < ep) {
1303                         u_int32 laddr = *p++;
1304                         int n = ntohl(*p++) & 0xFF;
1305                         if (laddr == dst) {
1306                             ep = p + 1;         /* ensure p < ep after loop */
1307                             break;
1308                         }
1309                         p += n;
1310                     }
1311                     if (p >= ep) continue;
1312                 }
1313                 break;
1314
1315               case IGMP_MTRACE:     /* For backward compatibility with 3.3 */
1316               case IGMP_MTRACE_RESP:
1317                 if (type != IGMP_MTRACE) continue;
1318                 if (igmpdatalen <= QLEN) continue;
1319                 if ((igmpdatalen - QLEN)%RLEN) {
1320                     printf("packet with incomplete responses (%d bytes)\n",
1321                         igmpdatalen);
1322                     continue;
1323                 }
1324
1325                 /*
1326                  * Ignore responses that don't match query.
1327                  */
1328                 rquery = (struct tr_query *)(igmp + 1);
1329                 if (rquery->tr_src != qsrc || rquery->tr_dst != qdst)
1330                     continue;
1331                 if (TR_GETQID(rquery->tr_rttlqid) !=
1332                         TR_GETQID(query->tr_rttlqid)) {
1333                     if (verbose && TR_GETQID(rquery->tr_rttlqid) == oqid)
1334                         printf("[D]");
1335                     continue;
1336                 }
1337                 len = (igmpdatalen - QLEN)/RLEN;
1338                 r = (struct tr_resp *)(rquery+1) + len - 1;
1339
1340                 /*
1341                  * Ignore trace queries passing through this node when
1342                  * mtrace is run on an mrouter that is in the path
1343                  * (needed only because IGMP_MTRACE is accepted above
1344                  * for backward compatibility with multicast release 3.3).
1345                  */
1346                 if (igmp->igmp_type == IGMP_MTRACE) {
1347                     u_int32 smask;
1348
1349                     VAL_TO_MASK(smask, r->tr_smask);
1350                     if (len < code && (r->tr_inaddr & smask) != (qsrc & smask)
1351                         && r->tr_rmtaddr != 0 && !(r->tr_rflags & 0x80))
1352                       continue;
1353                 }
1354                 /*
1355                  * Some routers will return error messages without
1356                  * filling in their addresses.  We fill in the address
1357                  * for them.
1358                  */
1359                 if (r->tr_outaddr == 0)
1360                     r->tr_outaddr = recvaddr.sin_addr.s_addr;
1361
1362                 /*
1363                  * A match, we'll keep this one.
1364                  */
1365                 if (len > code) {
1366                     warnx("num hops received (%d) exceeds request (%d)",
1367                             len, code);
1368                 }
1369                 rquery->tr_raddr = query->tr_raddr;     /* Insure these are */
1370                 TR_SETTTL(rquery->tr_rttlqid, TR_GETTTL(query->tr_rttlqid));
1371                                                         /* as we sent them */
1372                 break;
1373
1374               default:
1375                 continue;
1376             }
1377
1378             /*
1379              * We're pretty sure we want to use this packet now,
1380              * but if the caller gave a callback function, it might
1381              * want to handle it instead.  Give the callback a chance,
1382              * unless the select timed out (in which case the only way
1383              * to get here is because the callback returned a packet).
1384              */
1385             if (callback && (count != 0) && ((callback)(0, recv_buf, recvlen, igmp, igmpdatalen, (struct sockaddr*)&recvaddr, &socklen, &tr)) == 0) {
1386                 /*
1387                  * The callback function didn't like this packet.
1388                  * Go try receiving another one.
1389                  */
1390                 continue;
1391             }
1392
1393             /*
1394              * Most of the sanity checking done at this point.
1395              * Return this packet we have been waiting for.
1396              */
1397             if (save) {
1398                 save->qtime = ((tq.tv_sec + JAN_1970) << 16) +
1399                               (tq.tv_usec << 10) / 15625;
1400                 save->rtime = ((tr.tv_sec + JAN_1970) << 16) +
1401                               (tr.tv_usec << 10) / 15625;
1402                 save->len = len;
1403                 bcopy((char *)igmp, (char *)&save->igmp, ipdatalen);
1404             }
1405             return (recvlen);
1406         }
1407     }
1408     return (0);
1409 }
1410
1411 /*
1412  * Most of this code is duplicated elsewhere.  I'm not sure if
1413  * the duplication is absolutely required or not.
1414  *
1415  * Ideally, this would keep track of ongoing statistics
1416  * collection and print out statistics.  (& keep track
1417  * of h-b-h traces and only print the longest)  For now,
1418  * it just snoops on what traces it can.
1419  */
1420 void
1421 passive_mode(void)
1422 {
1423     struct timeval tr;
1424     time_t tr_sec;
1425     struct ip *ip;
1426     struct igmp *igmp;
1427     struct tr_resp *r;
1428     struct sockaddr_in recvaddr;
1429     struct tm *now;
1430     char timebuf[32];
1431     int socklen;
1432     int ipdatalen, iphdrlen, igmpdatalen;
1433     int len, recvlen;
1434     int qid;
1435     u_int32 smask;
1436     struct mtrace *remembered = NULL, *m, *n, **nn;
1437     int pc = 0;
1438
1439     if (raddr) {
1440         if (IN_MULTICAST(ntohl(raddr))) k_join(raddr, lcl_addr);
1441     } else k_join(htonl(0xE0000120), lcl_addr);
1442
1443     while (1) {
1444         fflush(stdout);         /* make sure previous trace is flushed */
1445
1446         socklen = sizeof(recvaddr);
1447         recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE,
1448                            0, (struct sockaddr *)&recvaddr, &socklen);
1449         gettimeofday(&tr,0);
1450
1451         if (recvlen <= 0) {
1452             if (recvlen && errno != EINTR) warn("recvfrom");
1453             continue;
1454         }
1455
1456         if (recvlen < sizeof(struct ip)) {
1457             warnx("packet too short (%u bytes) for IP header", recvlen);
1458             continue;
1459         }
1460         ip = (struct ip *) recv_buf;
1461         if (ip->ip_p == 0)      /* ignore cache creation requests */
1462             continue;
1463
1464         iphdrlen = ip->ip_hl << 2;
1465 #ifdef RAW_INPUT_IS_RAW
1466         ipdatalen = ntohs(ip->ip_len);
1467 #else
1468         ipdatalen = ip->ip_len;
1469 #endif
1470         if (iphdrlen + ipdatalen != recvlen) {
1471             warnx("packet shorter (%u bytes) than hdr+data len (%u+%u)",
1472                     recvlen, iphdrlen, ipdatalen);
1473             continue;
1474         }
1475
1476         igmp = (struct igmp *) (recv_buf + iphdrlen);
1477         igmpdatalen = ipdatalen - IGMP_MINLEN;
1478         if (igmpdatalen < 0) {
1479             warnx("IP data field too short (%u bytes) for IGMP from %s",
1480                     ipdatalen, inet_fmt(ip->ip_src.s_addr, s1));
1481             continue;
1482         }
1483
1484         switch (igmp->igmp_type) {
1485
1486           case IGMP_MTRACE:         /* For backward compatibility with 3.3 */
1487           case IGMP_MTRACE_RESP:
1488             if (igmpdatalen < QLEN) continue;
1489             if ((igmpdatalen - QLEN)%RLEN) {
1490                 printf("packet with incorrect datalen\n");
1491                 continue;
1492             }
1493
1494             len = (igmpdatalen - QLEN)/RLEN;
1495
1496             break;
1497
1498           default:
1499             continue;
1500         }
1501
1502         base.qtime = ((tr.tv_sec + JAN_1970) << 16) +
1503                       (tr.tv_usec << 10) / 15625;
1504         base.rtime = ((tr.tv_sec + JAN_1970) << 16) +
1505                       (tr.tv_usec << 10) / 15625;
1506         base.len = len;
1507         bcopy((char *)igmp, (char *)&base.igmp, ipdatalen);
1508         /*
1509          * If the user specified which traces to monitor,
1510          * only accept traces that correspond to the
1511          * request
1512          */
1513         if ((qsrc != 0 && qsrc != base.qhdr.tr_src) ||
1514             (qdst != 0 && qdst != base.qhdr.tr_dst) ||
1515             (qgrp != 0 && qgrp != igmp->igmp_group.s_addr))
1516             continue;
1517
1518         /* XXX This should be a hash table */
1519         /* XXX garbage-collection should be more efficient */
1520         for (nn = &remembered, n = *nn, m = NULL; n; n = *nn) {
1521             if ((n->base.qhdr.tr_src == base.qhdr.tr_src) &&
1522                 (n->base.qhdr.tr_dst == base.qhdr.tr_dst) &&
1523                 (n->base.igmp.igmp_group.s_addr == igmp->igmp_group.s_addr)) {
1524                 m = n;
1525                 m->last = tr;
1526             }
1527             if (tr.tv_sec - n->last.tv_sec > 500) { /* XXX don't hardcode */
1528                 *nn = n->next;
1529                 free(n);
1530             } else {
1531                 nn = &n->next;
1532             }
1533         }
1534
1535         tr_sec = tr.tv_sec;
1536         now = localtime(&tr_sec);
1537         strftime(timebuf, sizeof(timebuf) - 1, "%b %e %k:%M:%S", now);
1538         printf("Mtrace %s at %s",
1539                 len == 0 ? "query" :
1540                            igmp->igmp_type == IGMP_MTRACE_RESP ? "response" :
1541                                                                  "in transit",
1542                 timebuf);
1543         if (len == 0)
1544                 printf(" by %s", inet_fmt(recvaddr.sin_addr.s_addr, s1));
1545         if (!IN_MULTICAST(base.qhdr.tr_raddr))
1546                 printf(", resp to %s", (len == 0 && recvaddr.sin_addr.s_addr == base.qhdr.tr_raddr) ? "same" : inet_fmt(base.qhdr.tr_raddr, s1));
1547         else
1548                 printf(", respttl %d", TR_GETTTL(base.qhdr.tr_rttlqid));
1549         printf(", qid %06x\n", qid = TR_GETQID(base.qhdr.tr_rttlqid));
1550         printf("packet from %s to %s\n",
1551                 inet_fmt(ip->ip_src.s_addr, s1),
1552                 inet_fmt(ip->ip_dst.s_addr, s2));
1553
1554         printf("from %s to %s via group %s (mxhop=%d)\n",
1555                 inet_fmt(base.qhdr.tr_dst, s1), inet_fmt(base.qhdr.tr_src, s2),
1556                 inet_fmt(igmp->igmp_group.s_addr, s3), igmp->igmp_code);
1557         if (len == 0) {
1558             printf("\n");
1559             continue;
1560         }
1561         r = base.resps + base.len - 1;
1562         /*
1563          * Some routers will return error messages without
1564          * filling in their addresses.  We fill in the address
1565          * for them.
1566          */
1567         if (r->tr_outaddr == 0)
1568             r->tr_outaddr = recvaddr.sin_addr.s_addr;
1569
1570         /*
1571          * If there was a previous trace, it see if this is a
1572          * statistics candidate.
1573          */
1574         if (m && base.len == m->base.len &&
1575                 !(pc = path_changed(&m->base, &base))) {
1576             /*
1577              * Some mtrace responders send multiple copies of the same
1578              * reply.  Skip this packet if it's got the same query-id
1579              * as the last one.
1580              */
1581             if (m->lastqid == qid) {
1582                 printf("Skipping duplicate reply\n");
1583                 continue;
1584             }
1585
1586             m->lastqid = qid;
1587
1588             ++m->nresp;
1589
1590             bcopy(&base, m->new, sizeof(base));
1591
1592             printf("Results after %d seconds:\n\n",
1593                    (int)((m->new->qtime - m->base.qtime) >> 16));
1594             fixup_stats(&m->base, m->prev, m->new, m->bugs);
1595             print_stats(&m->base, m->prev, m->new, m->bugs, m->names);
1596             m->prev = m->new;
1597             m->new = &m->incr[(m->nresp & 1)];
1598
1599             continue;
1600         }
1601
1602         if (m == NULL) {
1603             m = (struct mtrace *)malloc(sizeof(struct mtrace));
1604             if (m == NULL) {
1605                 fprintf(stderr, "Out of memory!\n");
1606                 continue;
1607             }
1608             bzero(m, sizeof(struct mtrace));
1609             m->next = remembered;
1610             remembered = m;
1611             bcopy(&tr, &m->last, sizeof(tr));
1612         }
1613
1614         /* Either it's a hop-by-hop in progress, or the path changed. */
1615         if (pc) {
1616             printf("[Path Changed...]\n");
1617             bzero(m->bugs, sizeof(m->bugs));
1618         }
1619         bcopy(&base, &m->base, sizeof(base));
1620         m->prev = &m->base;
1621         m->new = &m->incr[0];
1622         m->nresp = 0;
1623
1624         printf("  0  ");
1625         print_host(base.qhdr.tr_dst);
1626         printf("\n");
1627         print_trace(1, &base, m->names);
1628         VAL_TO_MASK(smask, r->tr_smask);
1629         if ((r->tr_inaddr & smask) == (base.qhdr.tr_src & smask)) {
1630             printf("%3d  ", -(base.len+1));
1631             print_host(base.qhdr.tr_src);
1632             printf("\n");
1633         } else if (r->tr_rmtaddr != 0) {
1634             printf("%3d  ", -(base.len+1));
1635             print_host(r->tr_rmtaddr);
1636             printf(" %s\n", r->tr_rflags == TR_OLD_ROUTER ?
1637                                    "doesn't support mtrace"
1638                                  : "is the next hop");
1639         }
1640         printf("\n");
1641     }
1642 }
1643
1644 char *
1645 print_host(u_int32 addr)
1646 {
1647     return print_host2(addr, 0);
1648 }
1649
1650 /*
1651  * On some routers, one interface has a name and the other doesn't.
1652  * We always print the address of the outgoing interface, but can
1653  * sometimes get the name from the incoming interface.  This might be
1654  * confusing but should be slightly more helpful than just a "?".
1655  */
1656 char *
1657 print_host2(u_int32 addr1, u_int32 addr2)
1658 {
1659     char *name;
1660
1661     if (numeric) {
1662         printf("%s", inet_fmt(addr1, s1));
1663         return ("");
1664     }
1665     name = inet_name(addr1);
1666     if (*name == '?' && *(name + 1) == '\0' && addr2 != 0)
1667         name = inet_name(addr2);
1668     printf("%s (%s)", name, inet_fmt(addr1, s1));
1669     return (name);
1670 }
1671
1672 /*
1673  * Print responses as received (reverse path from dst to src)
1674  */
1675 void
1676 print_trace(int idx, struct resp_buf *buf, char **names)
1677 {
1678     struct tr_resp *r;
1679     char *name;
1680     int i;
1681     int hop;
1682     char *ms;
1683
1684     i = abs(idx);
1685     r = buf->resps + i - 1;
1686
1687     for (; i <= buf->len; ++i, ++r) {
1688         if (idx > 0) printf("%3d  ", -i);
1689         name = print_host2(r->tr_outaddr, r->tr_inaddr);
1690         if (r->tr_rflags != TR_NO_RTE)
1691             printf("  %s  thresh^ %d", proto_type(r->tr_rproto), r->tr_fttl);
1692         if (verbose) {
1693             hop = t_diff(ntohl(r->tr_qarr), buf->qtime);
1694             ms = scale(&hop);
1695             printf("  %d%s", hop, ms);
1696         }
1697         printf("  %s", flag_type(r->tr_rflags));
1698         if (i > 1 && r->tr_outaddr != (r-1)->tr_rmtaddr) {
1699             printf(" !RPF!");
1700             print_host((r-1)->tr_rmtaddr);
1701         }
1702         if (r->tr_rflags != TR_NO_RTE) {
1703             if (r->tr_smask <= 1)    /* MASK_TO_VAL() returns 1 for default */
1704                 printf(" [default]");
1705             else if (verbose) {
1706                 u_int32 smask;
1707
1708                 VAL_TO_MASK(smask, r->tr_smask);
1709                 printf(" [%s]", inet_fmts(buf->qhdr.tr_src & smask,
1710                                                         smask, s1));
1711             }
1712         }
1713         printf("\n");
1714         if (names[i-1])
1715             free(names[i-1]);
1716         names[i-1]=malloc(strlen(name) + 1);
1717         strcpy(names[i-1], name);
1718     }
1719 }
1720
1721 /*
1722  * See what kind of router is the next hop
1723  */
1724 int
1725 what_kind(struct resp_buf *buf, char *why)
1726 {
1727     u_int32 smask;
1728     int retval;
1729     int hops = buf->len;
1730     struct tr_resp *r = buf->resps + hops - 1;
1731     u_int32 next = r->tr_rmtaddr;
1732
1733     retval = send_recv(next, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS2, 1, &incr[0], NULL);
1734     print_host(next);
1735     if (retval) {
1736         u_int32 version = ntohl(incr[0].igmp.igmp_group.s_addr);
1737         u_int32 *p = (u_int32 *)incr[0].ndata;
1738         u_int32 *ep = p + (incr[0].len >> 2);
1739         char *type = "version ";
1740
1741         retval = 0;
1742         switch (version & 0xFF) {
1743           case 1:
1744             type = "proteon/mrouted ";
1745             retval = 1;
1746             break;
1747
1748           case 10:
1749           case 11:
1750             type = "cisco ";
1751         }
1752         printf(" [%s%d.%d] %s\n",
1753                type, version & 0xFF, (version >> 8) & 0xFF,
1754                why);
1755         VAL_TO_MASK(smask, r->tr_smask);
1756         while (p < ep) {
1757             u_int32 laddr = *p++;
1758             int flags = (ntohl(*p) & 0xFF00) >> 8;
1759             int n = ntohl(*p++) & 0xFF;
1760             if (!(flags & (DVMRP_NF_DOWN | DVMRP_NF_DISABLED)) &&
1761                  (laddr & smask) == (qsrc & smask)) {
1762                 printf("%3d  ", -(hops+2));
1763                 print_host(qsrc);
1764                 printf("\n");
1765                 return 1;
1766             }
1767             p += n;
1768         }
1769         return retval;
1770     }
1771     printf(" %s\n", why);
1772     return 0;
1773 }
1774
1775
1776 char *
1777 scale(int *hop)
1778 {
1779     if (*hop > -1000 && *hop < 10000) 
1780             return (" ms");
1781     *hop /= 1000;
1782     if (*hop > -1000 && *hop < 10000) 
1783             return (" s ");
1784     return ("s ");
1785 }
1786
1787 /*
1788  * Calculate and print one line of packet loss and packet rate statistics.
1789  * Checks for count of all ones from mrouted 2.3 that doesn't have counters.
1790  */
1791 #define NEITHER 0
1792 #define INS     1
1793 #define OUTS    2
1794 #define BOTH    3
1795 void
1796 stat_line(struct tr_resp *r, struct tr_resp *s, int have_next, int *rst)
1797 {
1798     int timediff = (ntohl(s->tr_qarr) - ntohl(r->tr_qarr)) >> 16;
1799     int v_lost, v_pct;
1800     int g_lost, g_pct;
1801     int v_out = ntohl(s->tr_vifout) - ntohl(r->tr_vifout);
1802     int g_out = ntohl(s->tr_pktcnt) - ntohl(r->tr_pktcnt);
1803     int v_pps, g_pps;
1804     char v_str[8], g_str[8];
1805     int vhave = NEITHER;
1806     int ghave = NEITHER;
1807     int gmissing = NEITHER;
1808     char whochar;
1809     int badtime = 0;
1810
1811     if (timediff == 0) {
1812         badtime = 1;
1813         /* Might be 32 bits of int seconds instead of 16int+16frac */
1814         timediff = ntohl(s->tr_qarr) - ntohl(r->tr_qarr);
1815         if (timediff == 0 || abs(timediff - statint) > statint)
1816             timediff = 1;
1817     }
1818     v_pps = v_out / timediff;
1819     g_pps = g_out / timediff;
1820
1821 #define STATS_MISSING(x)        ((x) == 0xFFFFFFFF)
1822
1823     if (!STATS_MISSING(s->tr_vifout) && !STATS_MISSING(r->tr_vifout))
1824             vhave |= OUTS;
1825     if (STATS_MISSING(s->tr_pktcnt) || STATS_MISSING(r->tr_pktcnt))
1826             gmissing |= OUTS;
1827     if (!(*rst & BUG_NOPRINT))
1828             ghave |= OUTS;
1829
1830     if (have_next) {
1831         --r,  --s,  --rst;
1832         if (!STATS_MISSING(s->tr_vifin) && !STATS_MISSING(r->tr_vifin))
1833             vhave |= INS;
1834         if (STATS_MISSING(s->tr_pktcnt) || STATS_MISSING(r->tr_pktcnt))
1835             gmissing |= INS;
1836         if (!(*rst & BUG_NOPRINT))
1837             ghave |= INS;
1838     }
1839
1840     /*
1841      * Stats can be missing for any number of reasons:
1842      * - The hop may not be capable of collecting stats
1843      * - Traffic may be getting dropped at the previous hop
1844      *   and so this hop may not have any state
1845      *
1846      * We need a stronger heuristic to tell between these
1847      * two cases; in case 1 we don't want to print the stats
1848      * and in case 2 we want to print 100% loss.  We used to
1849      * err on the side of not printing, which is less useful
1850      * than printing 100% loss and dealing with it.
1851      */
1852 #if 0
1853     /*
1854      * If both hops report as missing, then it's likely that there's just
1855      * no traffic flowing.
1856      *
1857      * If just one hop is missing, then we really don't have it.
1858      */
1859     if (gmissing != BOTH)
1860         ghave &= ~gmissing;
1861 #endif
1862
1863     whochar = have_next ? '^' : ' ';
1864     switch (vhave) {
1865       case BOTH:
1866         v_lost = v_out - (ntohl(s->tr_vifin) - ntohl(r->tr_vifin));
1867         if (v_out) v_pct = v_lost * 100 / v_out;
1868         else v_pct = 0;
1869         if (-20 < v_pct && v_pct < 101 && v_out > 10)
1870           sprintf(v_str, "%3d%%", v_pct);
1871         else if (v_pct < -900 && v_out > 10)
1872           sprintf(v_str, "%3dx", (int)(-v_pct / 100. + 1.));
1873         else if (v_pct <= -20 && v_out > 10)
1874           sprintf(v_str, "%1.1fx", -v_pct / 100. + 1.);
1875         else
1876           memcpy(v_str, " -- ", 5);
1877
1878         if (tunstats)
1879             printf("%6d/%-5d=%s", v_lost, v_out, v_str);
1880         else
1881             printf("   ");
1882         printf("%4d pps", v_pps);
1883         if (v_pps && badtime)
1884             printf("?");
1885
1886         break;
1887
1888       case INS:
1889         v_out = ntohl(s->tr_vifin) - ntohl(r->tr_vifin);
1890         v_pps = v_out / timediff;
1891         whochar = 'v';
1892         /* FALLTHROUGH */
1893
1894       case OUTS:
1895         if (tunstats)
1896             printf("      %c%-5d     ", whochar, v_out);
1897         else
1898             printf("  %c", whochar);
1899         printf("%4d pps", v_pps);
1900         if (v_pps && badtime)
1901             printf("?");
1902
1903         break;
1904
1905       case NEITHER:
1906         if (ghave != NEITHER)
1907             if (tunstats)
1908                 printf("                         ");
1909             else
1910                 printf("           ");
1911
1912         break;
1913     }
1914
1915     whochar = have_next ? '^' : ' ';
1916     switch (ghave) {
1917       case BOTH:
1918         g_lost = g_out - (ntohl(s->tr_pktcnt) - ntohl(r->tr_pktcnt));
1919         if (g_out) g_pct = g_lost * 100 / g_out;
1920         else g_pct = 0;
1921         if (-20 < g_pct && g_pct < 101 && g_out > 10)
1922           sprintf(g_str, "%3d%%", g_pct);
1923         else if (g_pct < -900 && g_out > 10)
1924           sprintf(g_str, "%3dx", (int)(-g_pct / 100. + 1.));
1925         else if (g_pct <= -20 && g_out > 10)
1926           sprintf(g_str, "%1.1fx", -g_pct / 100. + 1.);
1927         else
1928           memcpy(g_str, " -- ", 5);
1929
1930         printf("%s%6d/%-5d=%s%4d pps",
1931                tunstats ? "" : "   ", g_lost, g_out, g_str, g_pps);
1932         if (g_pps && badtime)
1933             printf("?");
1934         printf("\n");
1935         break;
1936
1937 #if 0
1938       case INS:
1939         g_out = ntohl(s->tr_pktcnt) - ntohl(r->tr_pktcnt);
1940         g_pps = g_out / timediff;
1941         whochar = 'v';
1942         /* FALLTHROUGH */
1943 #endif
1944
1945       case OUTS:
1946         printf("%s     ?/%-5d     %4d pps",
1947                tunstats ? "" : "   ", g_out, g_pps);
1948         if (badtime)
1949             printf("?");
1950         printf("\n");
1951         break;
1952
1953       case INS:
1954       case NEITHER:
1955         printf("\n");
1956         break;
1957     }
1958
1959
1960     if (debug > 2) {
1961         printf("\t\t\t\tv_in: %ld ", (long)ntohl(s->tr_vifin));
1962         printf("v_out: %ld ", (long)ntohl(s->tr_vifout));
1963         printf("pkts: %ld\n", (long)ntohl(s->tr_pktcnt));
1964         printf("\t\t\t\tv_in: %ld ", (long)ntohl(r->tr_vifin));
1965         printf("v_out: %ld ", (long)ntohl(r->tr_vifout));
1966         printf("pkts: %ld\n", (long)ntohl(r->tr_pktcnt));
1967         printf("\t\t\t\tv_in: %ld ",
1968             (long)(ntohl(s->tr_vifin) - ntohl(r->tr_vifin)));
1969         printf("v_out: %ld ",
1970             (long)(ntohl(s->tr_vifout) - ntohl(r->tr_vifout)));
1971         printf("pkts: %ld ", (long)(ntohl(s->tr_pktcnt) - ntohl(r->tr_pktcnt)));
1972         printf("time: %d\n", timediff);
1973         printf("\t\t\t\treset: %x hoptime: %lx\n", *rst, ntohl(s->tr_qarr));
1974     }
1975 }
1976
1977 /*
1978  * A fixup to check if any pktcnt has been reset, and to fix the
1979  * byteorder bugs in mrouted 3.6 on little-endian machines.
1980  *
1981  * XXX Since periodic traffic sources are likely to have their
1982  *     pktcnt periodically reset, should we save old values when
1983  *     the reset occurs to keep slightly better statistics over
1984  *     the long term?  (e.g. SAP)
1985  */
1986 void
1987 fixup_stats(struct resp_buf *base, struct resp_buf *prev, struct resp_buf *new,
1988             int *bugs)
1989 {
1990     int rno = base->len;
1991     struct tr_resp *b = base->resps + rno;
1992     struct tr_resp *p = prev->resps + rno;
1993     struct tr_resp *n = new->resps + rno;
1994     int *r = bugs + rno;
1995     int res;
1996     int cleanup = 0;
1997
1998     /* Check for byte-swappers.  Only check on the first trace,
1999      * since long-running traces can wrap around and falsely trigger. */
2000     while (--rno >= 0) {
2001 #ifdef TEST_ONLY
2002         u_int32 nvifout = ntohl(n->tr_vifout);
2003         u_int32 pvifout = ntohl(p->tr_vifout);
2004 #endif
2005         --n; --p; --b;
2006 #ifdef TEST_ONLY        /*XXX this is still buggy, so disable it for release */
2007         if ((*r & BUG_SWAP) ||
2008             ((base == prev) &&
2009              (nvifout - pvifout) > (byteswap(nvifout) - byteswap(pvifout)))) {
2010             if (1 || debug > 2) {
2011                 printf("ip %s swaps; b %08x p %08x n %08x\n",
2012                         inet_fmt(n->tr_inaddr, s1),
2013                         ntohl(b->tr_vifout), pvifout, nvifout);
2014             }
2015             /* This host sends byteswapped reports; swap 'em */
2016             if (!(*r & BUG_SWAP)) {
2017                 *r |= BUG_SWAP;
2018                 b->tr_qarr = byteswap(b->tr_qarr);
2019                 b->tr_vifin = byteswap(b->tr_vifin);
2020                 b->tr_vifout = byteswap(b->tr_vifout);
2021                 b->tr_pktcnt = byteswap(b->tr_pktcnt);
2022             }
2023
2024             n->tr_qarr = byteswap(n->tr_qarr);
2025             n->tr_vifin = byteswap(n->tr_vifin);
2026             n->tr_vifout = byteswap(n->tr_vifout);
2027             n->tr_pktcnt = byteswap(n->tr_pktcnt);
2028         }
2029 #endif
2030         /*
2031          * A missing parenthesis in mrouted 3.5-3.8's prune.c
2032          * causes extremely bogus time diff's.
2033          * One half of the time calculation was
2034          * inside an htonl() and one half wasn't.  Therefore, on
2035          * a little-endian machine, both halves of the calculation
2036          * would get added together in the little end.  Thus, the
2037          * low-order 2 bytes are either 0000 (no overflow) or
2038          * 0100 (overflow from the addition).
2039          *
2040          * Odds are against these particular bit patterns
2041          * happening in both prev and new for actual time values.
2042          */
2043         if ((*r & BUG_BOGUSTIME) || (((ntohl(n->tr_qarr) & 0xfeff) == 0x0000) &&
2044             ((ntohl(p->tr_qarr) & 0xfeff) == 0x0000))) {
2045             *r |= BUG_BOGUSTIME;
2046             n->tr_qarr = new->rtime;
2047             p->tr_qarr = prev->rtime;
2048             b->tr_qarr = base->rtime;
2049         }
2050     }
2051
2052     rno = base->len;
2053     b = base->resps + rno;
2054     p = prev->resps + rno;
2055     n = new->resps + rno;
2056     r = bugs + rno;
2057
2058     while (--rno >= 0) {
2059         --n; --p; --b; --r;
2060         /*
2061          * This hop has reset if:
2062          * - There were statistics in the base AND previous pass, AND
2063          *   - There are less packets this time than the first time and
2064          *     we didn't reset last time, OR
2065          *   - There are less packets this time than last time, OR
2066          *   - There are no statistics on this pass.
2067          *
2068          * The "and we didn't reset last time" is necessary in the
2069          * first branch of the OR because if the base is large and
2070          * we reset last time but the constant-resetter-avoidance
2071          * code kicked in so we delayed the copy of prev to base,
2072          * new could still be below base so we trigger the
2073          * constant-resetter code even though it was really only
2074          * a single reset.
2075          */
2076         res = ((b->tr_pktcnt != 0xFFFFFFFF) && (p->tr_pktcnt != 0xFFFFFFFF) &&
2077                ((!(*r & BUG_RESET) && ntohl(n->tr_pktcnt) < ntohl(b->tr_pktcnt)) ||
2078                 (ntohl(n->tr_pktcnt) < ntohl(p->tr_pktcnt)) ||
2079                 (n->tr_pktcnt == 0xFFFFFFFF)));
2080         if (debug > 2) {
2081             printf("\t\tip=%s, r=%d, res=%d\n", inet_fmt(b->tr_inaddr, s1), *r, res);
2082             if (res)
2083                 printf("\t\tbase=%ld, prev=%ld, new=%ld\n", ntohl(b->tr_pktcnt),
2084                             ntohl(p->tr_pktcnt), ntohl(n->tr_pktcnt));
2085         }
2086         if (*r & BUG_RESET) {
2087             if (res || (*r & BUG_RESET2X)) {
2088                 /*
2089                  * This router appears to be a 3.4 with that nasty ol'
2090                  * neighbor version bug, which causes it to constantly
2091                  * reset.  Just nuke the statistics for this node, and
2092                  * don't even bother giving it the benefit of the
2093                  * doubt from now on.
2094                  */
2095                 p->tr_pktcnt = b->tr_pktcnt = n->tr_pktcnt;
2096                 *r |= BUG_RESET2X;
2097             } else {
2098                 /*
2099                  * This is simply the situation that the original
2100                  * fixup_stats was meant to deal with -- that a
2101                  * 3.3 or 3.4 router deleted a cache entry while
2102                  * traffic was still active.
2103                  */
2104                 *r &= ~BUG_RESET;
2105                 cleanup = 1;
2106             }
2107         } else
2108             if (res)
2109                 *r |= BUG_RESET;
2110     }
2111
2112     if (cleanup == 0) return;
2113
2114     /*
2115      * If some hop reset its counters and didn't continue to
2116      * reset, then we pretend that the previous
2117      * trace was the first one.
2118      */
2119     rno = base->len;
2120     b = base->resps + rno;
2121     p = prev->resps + rno;
2122
2123     while (--rno >= 0) (--b)->tr_pktcnt = (--p)->tr_pktcnt;
2124     base->qtime = prev->qtime;
2125     base->rtime = prev->rtime;
2126 }
2127
2128 /*
2129  * Check per-source losses along path and compare with threshold.
2130  */
2131 int
2132 check_thresh(int thresh, struct resp_buf *base, struct resp_buf *prev,
2133              struct resp_buf *new)
2134 {
2135     int rno = base->len - 1;
2136     struct tr_resp *b = base->resps + rno;
2137     struct tr_resp *p = prev->resps + rno;
2138     struct tr_resp *n = new->resps + rno;
2139     int g_out, g_lost;
2140
2141     while (TRUE) {
2142         if ((n->tr_inaddr != b->tr_inaddr) ||
2143             (n->tr_outaddr != b->tr_outaddr) ||
2144             (n->tr_rmtaddr != b->tr_rmtaddr))
2145           return 1;             /* Route changed */
2146
2147         if (rno-- < 1) break;
2148         g_out = ntohl(n->tr_pktcnt) - ntohl(p->tr_pktcnt);
2149         b--; n--; p--;
2150         g_lost = g_out - (ntohl(n->tr_pktcnt) - ntohl(p->tr_pktcnt));
2151         if (g_out && ((g_lost * 100 + (g_out >> 1))/ g_out) > thresh) {
2152             return TRUE;
2153         }
2154     }
2155     return FALSE;
2156 }
2157
2158 /*
2159  * Print responses with statistics for forward path (from src to dst)
2160  */
2161 int
2162 print_stats(struct resp_buf *base, struct resp_buf *prev, struct resp_buf *new,
2163             int *bugs, char **names)
2164 {
2165     int rtt, hop;
2166     char *ms;
2167     u_int32 smask;
2168     int rno = base->len - 1;
2169     struct tr_resp *b = base->resps + rno;
2170     struct tr_resp *p = prev->resps + rno;
2171     struct tr_resp *n = new->resps + rno;
2172     int *r = bugs + rno;
2173     u_long resptime = new->rtime;
2174     u_long qarrtime = ntohl(n->tr_qarr);
2175     u_int ttl = MaX(1, n->tr_fttl) + 1;
2176     int first = (base == prev);
2177
2178     VAL_TO_MASK(smask, b->tr_smask);
2179     printf("  Source        Response Dest    ");
2180     if (tunstats)
2181         printf("Packet Statistics For     Only For Traffic\n");
2182     else
2183         printf("Overall     Packet Statistics For Traffic From\n");
2184     inet_fmt(base->qhdr.tr_src, s1);
2185     printf("%-15s %-15s  ",
2186            ((b->tr_inaddr & smask) == (base->qhdr.tr_src & smask)) ?
2187                 s1 : "   * * *       ",
2188            inet_fmt(base->qhdr.tr_raddr, s2));
2189     inet_fmt(base->igmp.igmp_group.s_addr, s2);
2190     if (tunstats)
2191         printf("All Multicast Traffic     From %s\n", s1);
2192     else
2193         printf("Packet      %s To %s\n", s1, s2);
2194     rtt = t_diff(resptime, new->qtime);
2195     ms = scale(&rtt);
2196     printf("     %c       __/  rtt%5d%s    ",
2197            (first && !verbose) ? 'v' : '|', rtt, ms);
2198     if (tunstats)
2199         printf("Lost/Sent = Pct  Rate       To %s\n", s2);
2200     else
2201         printf(" Rate       Lost/Sent = Pct  Rate\n");
2202     if (!first || verbose) {
2203         hop = t_diff(resptime, qarrtime);
2204         ms = scale(&hop);
2205         printf("     v      /     hop%5d%s    ", hop, ms);
2206         if (tunstats)
2207             printf("---------------------     --------------------\n");
2208         else
2209             printf("-------     ---------------------\n");
2210     }
2211     if ((b->tr_inaddr & smask) != (base->qhdr.tr_src & smask) &&
2212             b->tr_rmtaddr != 0) {
2213         printf("%-15s %-14s is the previous hop\n", inet_fmt(b->tr_rmtaddr, s1),
2214                 inet_name(b->tr_rmtaddr));
2215         printf("     v     ^\n");
2216     }
2217     if (debug > 2) {
2218         printf("\t\t\t\tv_in: %ld ", (long)ntohl(n->tr_vifin));
2219         printf("v_out: %ld ", (long)ntohl(n->tr_vifout));
2220         printf("pkts: %ld\n", (long)ntohl(n->tr_pktcnt));
2221         printf("\t\t\t\tv_in: %ld ", (long)ntohl(b->tr_vifin));
2222         printf("v_out: %ld ", (long)ntohl(b->tr_vifout));
2223         printf("pkts: %ld\n", (long)ntohl(b->tr_pktcnt));
2224         printf("\t\t\t\tv_in: %ld ",
2225             (long)(ntohl(n->tr_vifin) - ntohl(b->tr_vifin)));
2226         printf("v_out: %ld ",
2227             (long)(ntohl(n->tr_vifout) - ntohl(b->tr_vifout)));
2228         printf("pkts: %ld\n",
2229             (long)(ntohl(n->tr_pktcnt) - ntohl(b->tr_pktcnt)));
2230         printf("\t\t\t\treset: %x hoptime: %lx\n", *r, (long)ntohl(n->tr_qarr));
2231     }
2232
2233     while (TRUE) {
2234         if ((n->tr_inaddr != b->tr_inaddr) ||
2235             (n->tr_outaddr != b->tr_outaddr) ||
2236             (n->tr_rmtaddr != b->tr_rmtaddr))
2237           return 1;             /* Route changed */
2238
2239         if ((n->tr_inaddr != n->tr_outaddr) && n->tr_inaddr)
2240           printf("%-15s\n", inet_fmt(n->tr_inaddr, s1));
2241         printf("%-15s %-14s %s%s\n", inet_fmt(n->tr_outaddr, s1), names[rno],
2242                  flag_type(n->tr_rflags),
2243                  (*r & BUG_NOPRINT) ? " [reset counters]" : "");
2244
2245         if (rno-- < 1) break;
2246
2247         printf("     %c     ^      ttl%5d   ", (first && !verbose) ? 'v' : '|',
2248                                                                 ttl);
2249         stat_line(p, n, TRUE, r);
2250         if (!first || verbose) {
2251             resptime = qarrtime;
2252             qarrtime = ntohl((n-1)->tr_qarr);
2253             hop = t_diff(resptime, qarrtime);
2254             ms = scale(&hop);
2255             printf("     v     |      hop%5d%s", hop, ms);
2256             if (first)
2257                 printf("\n");
2258             else
2259                 stat_line(b, n, TRUE, r);
2260         }
2261
2262         --b, --p, --n, --r;
2263         ttl = MaX(ttl, MaX(1, n->tr_fttl) + base->len - rno);
2264     }
2265            
2266     printf("     %c      \\__   ttl%5d   ", (first && !verbose) ? 'v' : '|',
2267                                                         ttl);
2268     stat_line(p, n, FALSE, r);
2269     if (!first || verbose) {
2270         hop = t_diff(qarrtime, new->qtime);
2271         ms = scale(&hop);
2272         printf("     v         \\  hop%5d%s", hop, ms);
2273         if (first)
2274             printf("\n");
2275         else
2276             stat_line(b, n, FALSE, r);
2277     }
2278     printf("%-15s %s\n", inet_fmt(base->qhdr.tr_dst, s1),
2279                         !passive ? inet_fmt(lcl_addr, s2) : "   * * *       ");
2280     printf("  Receiver      Query Source\n\n");
2281     return 0;
2282 }
2283
2284 /*
2285  * Determine whether or not the path has changed.
2286  */
2287 int
2288 path_changed(struct resp_buf *base, struct resp_buf *new)
2289 {
2290     int rno = base->len - 1;
2291     struct tr_resp *b = base->resps + rno;
2292     struct tr_resp *n = new->resps + rno;
2293
2294     while (rno-- >= 0) {
2295         if ((n->tr_inaddr != b->tr_inaddr) ||
2296             (n->tr_outaddr != b->tr_outaddr) ||
2297             (n->tr_rmtaddr != b->tr_rmtaddr))
2298           return 1;             /* Route changed */
2299         if ((b->tr_rflags == TR_NO_RTE) &&
2300             (n->tr_rflags != TR_NO_RTE))
2301           return 1;             /* Route got longer? */
2302         --n;
2303         --b;
2304     }
2305     return 0;
2306 }
2307
2308
2309 /***************************************************************************
2310  *      main
2311  ***************************************************************************/
2312
2313 int
2314 main(int argc, char **argv)
2315 {
2316     int udp;
2317     struct sockaddr_in addr;
2318     int addrlen = sizeof(addr);
2319     int recvlen;
2320     struct timeval tv;
2321     struct resp_buf *prev, *new;
2322     struct tr_resp *r;
2323     u_int32 smask;
2324     int rno;
2325     int hops, nexthop, tries;
2326     u_int32 lastout = 0;
2327     int numstats = 1;
2328     int waittime;
2329     int seed;
2330     int hopbyhop;
2331     int i;
2332     int printed = 1;
2333
2334     if (geteuid() != 0)
2335         errx(1, "must be root");
2336
2337     /*
2338      * We might get spawned by vat with the audio device open.
2339      * Close everything but stdin, stdout, stderr.
2340      */
2341     for (i = 3; i < 255; i++)
2342         close(i);
2343
2344     init_igmp();
2345     setuid(getuid());
2346
2347     argv++, argc--;
2348     if (argc == 0) usage();
2349
2350     while (argc > 0 && *argv[0] == '-') {
2351         char *p = *argv++;  argc--;
2352         p++;
2353         do {
2354             char c = *p++;
2355             char *arg = NULL;
2356             if (isdigit(*p)) {
2357                 arg = p;
2358                 p = "";
2359             } else if (argc > 0) arg = argv[0];
2360             switch (c) {
2361               case 'd':                 /* Unlisted debug print option */
2362                 if (arg && isdigit(*arg)) {
2363                     debug = atoi(arg);
2364                     if (debug < 0) debug = 0;
2365                     if (debug > 3) debug = 3;
2366                     if (arg == argv[0]) argv++, argc--;
2367                     break;
2368                 } else
2369                     usage();
2370               case 'M':                 /* Use multicast for reponse */
2371                 multicast = TRUE;
2372                 break;
2373               case 'U':                 /* Use unicast for response */
2374                 unicast = TRUE;
2375                 break;
2376               case 'L':                 /* Trace w/ loss threshold */
2377                 if (arg && isdigit(*arg)) {
2378                     lossthresh = atoi(arg);
2379                     if (lossthresh < 0)
2380                         lossthresh = 0;
2381                     numstats = 3153600;
2382                     if (arg == argv[0]) argv++, argc--;
2383                     break;
2384                 } else
2385                     usage();
2386                 break;
2387               case 'O':                 /* Don't use IP options */
2388                 sendopts = FALSE;
2389                 break;
2390               case 'P':                 /* Just watch the path */
2391                 printstats = FALSE;
2392                 numstats = 3153600;
2393                 break;
2394               case 'Q':                 /* (undoc.) always use this QID */
2395                 if (arg && isdigit(*arg)) {
2396                     staticqid = atoi(arg);
2397                     if (staticqid < 0)
2398                         staticqid = 0;
2399                     if (arg == argv[0]) argv++, argc--;
2400                     break;
2401                 } else
2402                     usage();
2403                 break;
2404               case 'T':                 /* Print confusing tunnel stats */
2405                 tunstats = TRUE;
2406                 break;
2407               case 'W':                 /* Cisco's "weak" mtrace */
2408                 weak = TRUE;
2409                 break;
2410               case 'V':                 /* Print version and exit */
2411                 fprintf(stderr, "mtrace version 5.2\n");
2412                 exit(1);
2413                 break;
2414               case 'l':                 /* Loop updating stats indefinitely */
2415                 numstats = 3153600;
2416                 break;
2417               case 'n':                 /* Don't reverse map host addresses */
2418                 numeric = TRUE;
2419                 break;
2420               case 'p':                 /* Passive listen for traces */
2421                 passive = TRUE;
2422                 break;
2423               case 'v':                 /* Verbosity */
2424                 verbose = TRUE;
2425                 break;
2426               case 's':                 /* Short form, don't wait for stats */
2427                 numstats = 0;
2428                 break;
2429               case 'w':                 /* Time to wait for packet arrival */
2430                 if (arg && isdigit(*arg)) {
2431                     timeout = atoi(arg);
2432                     if (timeout < 1) timeout = 1;
2433                     if (arg == argv[0]) argv++, argc--;
2434                     break;
2435                 } else
2436                     usage();
2437               case 'f':                 /* first hop */
2438                 if (arg && isdigit(*arg)) {
2439                     qno = atoi(arg);
2440                     if (qno > MAXHOPS) qno = MAXHOPS;
2441                     else if (qno < 1) qno = 0;
2442                     if (arg == argv[0]) argv++, argc--;
2443                     fflag++;
2444                     break;
2445                 } else
2446                     usage();
2447               case 'm':                 /* Max number of hops to trace */
2448                 if (arg && isdigit(*arg)) {
2449                     qno = atoi(arg);
2450                     if (qno > MAXHOPS) qno = MAXHOPS;
2451                     else if (qno < 1) qno = 0;
2452                     if (arg == argv[0]) argv++, argc--;
2453                     break;
2454                 } else
2455                     usage();
2456               case 'q':                 /* Number of query retries */
2457                 if (arg && isdigit(*arg)) {
2458                     nqueries = atoi(arg);
2459                     if (nqueries < 1) nqueries = 1;
2460                     if (arg == argv[0]) argv++, argc--;
2461                     break;
2462                 } else
2463                     usage();
2464               case 'g':                 /* Last-hop gateway (dest of query) */
2465                 if (arg && (gwy = host_addr(arg))) {
2466                     if (arg == argv[0]) argv++, argc--;
2467                     break;
2468                 } else
2469                     usage();
2470               case 't':                 /* TTL for query packet */
2471                 if (arg && isdigit(*arg)) {
2472                     qttl = atoi(arg);
2473                     if (qttl < 1) qttl = 1;
2474                     rttl = qttl;
2475                     if (arg == argv[0]) argv++, argc--;
2476                     break;
2477                 } else
2478                     usage();
2479               case 'e':                 /* Extra hops past non-responder */
2480                 if (arg && isdigit(*arg)) {
2481                     extrahops = atoi(arg);
2482                     if (extrahops < 0) extrahops = 0;
2483                     if (arg == argv[0]) argv++, argc--;
2484                     break;
2485                 } else
2486                     usage();
2487               case 'r':                 /* Dest for response packet */
2488                 if (arg && (raddr = host_addr(arg))) {
2489                     if (arg == argv[0]) argv++, argc--;
2490                     break;
2491                 } else
2492                     usage();
2493               case 'i':                 /* Local interface address */
2494                 if (arg && (lcl_addr = host_addr(arg))) {
2495                     if (arg == argv[0]) argv++, argc--;
2496                     break;
2497                 } else
2498                     usage();
2499               case 'S':                 /* Stat accumulation interval */
2500                 if (arg && isdigit(*arg)) {
2501                     statint = atoi(arg);
2502                     if (statint < 1) statint = 1;
2503                     if (arg == argv[0]) argv++, argc--;
2504                     break;
2505                 } else
2506                     usage();
2507               default:
2508                 usage();
2509             }
2510         } while (*p);
2511     }
2512
2513     if (argc > 0 && (qsrc = host_addr(argv[0]))) {          /* Source of path */
2514         if (IN_MULTICAST(ntohl(qsrc))) {
2515             if (gwy) {
2516                 /* Should probably rewrite arg parsing at some point, as
2517                  * this makes "mtrace -g foo 224.1.2.3 224.2.3.4" valid!... */
2518                 qgrp = qsrc;
2519                 qsrc = 0;
2520             } else {
2521                 usage();
2522             }
2523         }
2524         argv++, argc--;
2525         if (argc > 0 && (qdst = host_addr(argv[0]))) {      /* Dest of path */
2526             argv++, argc--;
2527             if (argc > 0 && (qgrp = host_addr(argv[0]))) {  /* Path via group */
2528                 argv++, argc--;
2529             }
2530             if (IN_MULTICAST(ntohl(qdst))) {
2531                 u_int32 temp = qdst;
2532                 qdst = qgrp;
2533                 qgrp = temp;
2534                 if (IN_MULTICAST(ntohl(qdst))) usage();
2535             } else if (qgrp && !IN_MULTICAST(ntohl(qgrp))) usage();
2536         }
2537     }
2538
2539     if (passive) {
2540         passive_mode();
2541         return(0);
2542     }
2543
2544     if (argc > 0) {
2545         usage();
2546     }
2547
2548 #ifdef SUNOS5
2549     if (sendopts)
2550         checkforsolarisbug();
2551 #endif
2552
2553     /*
2554      * Set useful defaults for as many parameters as possible.
2555      */
2556
2557     defgrp = 0;                         /* Default to no group */
2558     query_cast = htonl(0xE0000002);     /* All routers multicast addr */
2559     resp_cast = htonl(0xE0000120);      /* Mtrace response multicast addr */
2560     if (qgrp == 0) {
2561         if (!weak)
2562             qgrp = defgrp;
2563         if (printstats && numstats != 0 && !tunstats) {
2564             /* Stats are useless without a group */
2565             warnx(
2566         "WARNING: no multicast group specified, so no statistics printed");
2567             numstats = 0;
2568         }
2569     } else {
2570         if (weak)
2571             warnx(
2572         "WARNING: group was specified so not performing \"weak\" mtrace");
2573     }
2574
2575     /*
2576      * Get default local address for multicasts to use in setting defaults.
2577      */
2578     addr.sin_family = AF_INET;
2579 #if (defined(BSD) && (BSD >= 199103))
2580     addr.sin_len = sizeof(addr);
2581 #endif
2582     addr.sin_addr.s_addr = qgrp ? qgrp : query_cast;
2583     addr.sin_port = htons(2000);        /* Any port above 1024 will do */
2584
2585     /*
2586      * Note that getsockname() can return 0 on some systems
2587      * (notably SunOS 5.x, x < 6).  This is taken care of in
2588      * get_netmask().  If the default multicast interface (set
2589      * with the route for 224.0.0.0) is not the same as the
2590      * hostname, mtrace -i [if_addr] will have to be used.
2591      */
2592     if (((udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0) ||
2593         (connect(udp, (struct sockaddr *) &addr, sizeof(addr)) < 0) ||
2594         getsockname(udp, (struct sockaddr *) &addr, &addrlen) < 0)
2595         err(-1, "determining local address");
2596
2597 #ifdef SUNOS5
2598     /*
2599      * SunOS 5.X prior to SunOS 2.6, getsockname returns 0 for udp socket.
2600      * This call to sysinfo will return the hostname.
2601      * If the default multicast interfface (set with the route
2602      * for 224.0.0.0) is not the same as the hostname,
2603      * mtrace -i [if_addr] will have to be used.
2604      */
2605     if (addr.sin_addr.s_addr == 0) {
2606         char myhostname[MAXHOSTNAMELEN];
2607         struct hostent *hp;
2608         int error;
2609     
2610         error = sysinfo(SI_HOSTNAME, myhostname, sizeof(myhostname));
2611         if (error == -1)
2612             err(1, "getting my hostname");
2613
2614         hp = gethostbyname(myhostname);
2615         if (hp == NULL || hp->h_addrtype != AF_INET ||
2616             hp->h_length != sizeof(addr.sin_addr))
2617             err(1, "finding IP address for my hostname");
2618
2619         memcpy((char *)&addr.sin_addr.s_addr, hp->h_addr, hp->h_length);
2620     }
2621 #endif
2622
2623     /*
2624      * Default destination for path to be queried is the local host.
2625      * When gateway specified, default destination is that gateway
2626      *  and default source is local host.
2627      */
2628     if (qdst == 0) {
2629         qdst = lcl_addr ? lcl_addr : addr.sin_addr.s_addr;
2630         dst_netmask = get_netmask(udp, &qdst);
2631         if (gwy && (gwy & dst_netmask) != (qdst & dst_netmask) &&
2632                 !IN_MULTICAST(ntohl(gwy)))
2633             qdst = gwy;
2634     }
2635     if (qsrc == 0 && gwy)
2636         qsrc = lcl_addr ? lcl_addr : addr.sin_addr.s_addr;
2637     if (qsrc == 0)
2638         usage();
2639     if (!dst_netmask)
2640         dst_netmask = get_netmask(udp, &qdst);
2641     close(udp);
2642     if (lcl_addr == 0) lcl_addr = addr.sin_addr.s_addr;
2643
2644     /*
2645      * Initialize the seed for random query identifiers.
2646      */
2647     gettimeofday(&tv, 0);
2648     seed = tv.tv_usec ^ lcl_addr;
2649 #ifdef SYSV    
2650     srand48(seed);
2651 #endif
2652
2653     /*
2654      * Protect against unicast queries to mrouted versions that might crash.
2655      * Also use the obsolete "can mtrace" neighbor bit to warn about
2656      * older implementations.
2657      */
2658     if (gwy && !IN_MULTICAST(ntohl(gwy)))
2659       if (send_recv(gwy, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS2, 1, &incr[0], NULL)) {
2660         int flags = ntohl(incr[0].igmp.igmp_group.s_addr);
2661         int version = flags & 0xFFFF;
2662         int info = (flags & 0xFF0000) >> 16;
2663
2664         if (version == 0x0303 || version == 0x0503) {
2665             printf("Don't use -g to address an mrouted 3.%d, it might crash\n",
2666                    (version >> 8) & 0xFF);
2667             exit(0);
2668         }
2669         if ((info & 0x08) == 0) {
2670             printf("mtrace: ");
2671             print_host(gwy);
2672             printf(" probably doesn't support mtrace, trying anyway...\n");
2673         }
2674       }
2675
2676     printf("Mtrace from %s to %s via group %s\n",
2677            inet_fmt(qsrc, s1), inet_fmt(qdst, s2), inet_fmt(qgrp, s3));
2678
2679     if ((qdst & dst_netmask) == (qsrc & dst_netmask))
2680         fprintf(stderr, "mtrace: Source & receiver appear to be directly connected\n");
2681
2682     /*
2683      * If the response is to be a multicast address, make sure we 
2684      * are listening on that multicast address.
2685      */
2686     if (raddr) {
2687         if (IN_MULTICAST(ntohl(raddr))) k_join(raddr, lcl_addr);
2688     } else k_join(resp_cast, lcl_addr);
2689
2690     memset(&base, 0, sizeof(base));
2691
2692     /*
2693      * If the destination is on the local net, the last-hop router can
2694      * be found by multicast to the all-routers multicast group.
2695      * Otherwise, use the group address that is the subject of the
2696      * query since by definition the last-hop router will be a member.
2697      * Set default TTLs for local remote multicasts.
2698      */
2699     if (gwy == 0)
2700       if ((qdst & dst_netmask) == (lcl_addr & dst_netmask)) tdst = query_cast;
2701       else tdst = qgrp;
2702     else tdst = gwy;
2703     if (tdst == 0 && qgrp == 0)
2704         errx(1, "mtrace: weak mtrace requires -g if destination is not local.\n");
2705
2706     if (IN_MULTICAST(ntohl(tdst))) {
2707       k_set_loop(1);    /* If I am running on a router, I need to hear this */
2708       if (tdst == query_cast) k_set_ttl(qttl ? qttl : 1);
2709       else k_set_ttl(qttl ? qttl : MULTICAST_TTL1);
2710     }
2711
2712     /*
2713      * Try a query at the requested number of hops or MAXHOPS if unspecified.
2714      */
2715     if (qno == 0) {
2716         hops = MAXHOPS;
2717         tries = 1;
2718         printf("Querying full reverse path... ");
2719         fflush(stdout);
2720     } else {
2721         hops = qno;
2722         tries = nqueries;
2723         if (fflag)
2724             printf("Querying full reverse path, starting at hop %d...", qno);
2725         else
2726             printf("Querying reverse path, maximum %d hops... ", qno);
2727         fflush(stdout); 
2728     }
2729     base.rtime = 0;
2730     base.len = 0;
2731     hopbyhop = FALSE;
2732
2733     recvlen = send_recv(tdst, IGMP_MTRACE, hops, tries, &base, mtrace_callback);
2734
2735     /*
2736      * If the initial query was successful, print it.  Otherwise, if
2737      * the query max hop count is the default of zero, loop starting
2738      * from one until there is no response for extrahops more hops.  The
2739      * extra hops allow getting past an mtrace-capable mrouter that can't
2740      * send multicast packets because all phyints are disabled.
2741      */
2742     if (recvlen) {
2743         printf("\n  0  ");
2744         print_host(qdst);
2745         printf("\n");
2746         print_trace(1, &base, names);
2747         r = base.resps + base.len - 1;
2748         if (r->tr_rflags == TR_OLD_ROUTER || r->tr_rflags == TR_NO_SPACE ||
2749                 (qno != 0 && r->tr_rmtaddr != 0 && !fflag)) {
2750             printf("%3d  ", -(base.len+1));
2751             what_kind(&base, r->tr_rflags == TR_OLD_ROUTER ?
2752                                    "doesn't support mtrace"
2753                                  : "is the next hop");
2754         } else {
2755             if (fflag) {
2756                 nexthop = hops = qno;
2757                 goto continuehop;
2758             }
2759             VAL_TO_MASK(smask, r->tr_smask);
2760             if ((r->tr_inaddr & smask) == (qsrc & smask)) {
2761                 printf("%3d  ", -(base.len+1));
2762                 print_host(qsrc);
2763                 printf("\n");
2764             }
2765         }
2766     } else if (qno == 0) {
2767         hopbyhop = TRUE;
2768         printf("switching to hop-by-hop:\n  0  ");
2769         print_host(qdst);
2770         printf("\n");
2771
2772         for (hops = 1, nexthop = 1; hops <= MAXHOPS; ++hops) {
2773             printf("%3d  ", -hops);
2774             fflush(stdout);
2775
2776             /*
2777              * After a successful first hop, try switching to the unicast
2778              * address of the last-hop router instead of multicasting the
2779              * trace query.  This should be safe for mrouted versions 3.3
2780              * and 3.5 because there is a long route timeout with metric
2781              * infinity before a route disappears.  Switching to unicast
2782              * reduces the amount of multicast traffic and avoids a bug
2783              * with duplicate suppression in mrouted 3.5.
2784              */
2785             if (hops == 2 && gwy == 0 && lastout != 0 &&
2786                 (recvlen = send_recv(lastout, IGMP_MTRACE, hops, 1, &base, mtrace_callback)))
2787               tdst = lastout;
2788             else recvlen = send_recv(tdst, IGMP_MTRACE, hops, nqueries, &base, mtrace_callback);
2789
2790             if (recvlen == 0) {
2791                 /*if (hops == 1) break;*/
2792                 if (hops == nexthop) {
2793                     if (hops == 1) {
2794                         printf("\n");
2795                     } else if (what_kind(&base, "didn't respond")) {
2796                         /* the ask_neighbors determined that the
2797                          * not-responding router is the first-hop. */
2798                         break;
2799                     }
2800                     if (extrahops == 0)
2801                         break;
2802                 } else if (hops < nexthop + extrahops) {
2803                     printf("\n");
2804                 } else {
2805                     printf("...giving up\n");
2806                     break;
2807                 }
2808                 continue;
2809             }
2810             if (base.len == hops &&
2811                 (hops == 1 || (base.resps+nexthop-2)->tr_outaddr == lastout)) {
2812                 if (hops == nexthop) {
2813                     print_trace(-hops, &base, names);
2814                 } else {
2815                     printf("\nResuming...\n");
2816                     print_trace(nexthop, &base, names);
2817                 }
2818             } else {
2819                 if (base.len < hops) {
2820                     /*
2821                      * A shorter trace than requested means a fatal error
2822                      * occurred along the path, or that the route changed
2823                      * to a shorter one.
2824                      *
2825                      * If the trace is longer than the last one we received,
2826                      * then we are resuming from a skipped router (but there
2827                      * is still probably a problem).
2828                      *
2829                      * If the trace is shorter than the last one we
2830                      * received, then the route must have changed (and
2831                      * there is still probably a problem).
2832                      */
2833                     if (nexthop <= base.len) {
2834                         printf("\nResuming...\n");
2835                         print_trace(nexthop, &base, names);
2836                     } else if (nexthop > base.len + 1) {
2837                         hops = base.len;
2838                         printf("\nRoute must have changed...\n");
2839                         print_trace(1, &base, names);
2840                     }
2841                 } else {
2842                     /*
2843                      * The last hop address is not the same as it was.
2844                      * If we didn't know the last hop then we just
2845                      * got the first response from a hop-by-hop trace;
2846                      * if we did know the last hop then
2847                      * the route probably changed underneath us.
2848                      */
2849                     hops = base.len;
2850                     if (lastout != 0)
2851                         printf("\nRoute must have changed...\n");
2852                     else
2853                         printf("\nResuming...\n");
2854                     print_trace(1, &base, names);
2855                 }
2856             }
2857 continuehop:
2858             r = base.resps + base.len - 1;
2859             lastout = r->tr_outaddr;
2860
2861             if (base.len < hops ||
2862                 r->tr_rmtaddr == 0 ||
2863                 (r->tr_rflags & 0x80)) {
2864                 VAL_TO_MASK(smask, r->tr_smask);
2865                 if (r->tr_rmtaddr) {
2866                     if (hops != nexthop) {
2867                         printf("\n%3d  ", -(base.len+1));
2868                     }
2869                     what_kind(&base, r->tr_rflags == TR_OLD_ROUTER ?
2870                                 "doesn't support mtrace" :
2871                                 "would be the next hop");
2872                     /* XXX could do segmented trace if TR_NO_SPACE */
2873                 } else if (r->tr_rflags == TR_NO_ERR &&
2874                            (r->tr_inaddr & smask) == (qsrc & smask)) {
2875                     printf("%3d  ", -(hops + 1));
2876                     print_host(qsrc);
2877                     printf("\n");
2878                 }
2879                 break;
2880             }
2881
2882             nexthop = hops + 1;
2883         }
2884     }
2885
2886     if (base.rtime == 0) {
2887         printf("Timed out receiving responses\n");
2888         if (IN_MULTICAST(ntohl(tdst)))
2889           if (tdst == query_cast)
2890             printf("Perhaps no local router has a route for source %s\n",
2891                    inet_fmt(qsrc, s1));
2892           else
2893             printf("Perhaps receiver %s is not a member of group %s,\n\
2894 or no router local to it has a route for source %s,\n\
2895 or multicast at ttl %d doesn't reach its last-hop router for that source\n",
2896                    inet_fmt(qdst, s2), inet_fmt(qgrp, s3), inet_fmt(qsrc, s1),
2897                    qttl ? qttl : MULTICAST_TTL1);
2898         exit(1);
2899     }
2900
2901     printf("Round trip time %d ms; ", t_diff(base.rtime, base.qtime));
2902     {
2903         struct tr_resp *n = base.resps + base.len - 1;
2904         u_int ttl = n->tr_fttl + 1;
2905
2906         rno = base.len - 1;
2907         while (--rno > 0) {
2908             --n;
2909             ttl = MaX(ttl, MaX(1, n->tr_fttl) + base.len - rno);
2910         }
2911         printf("total ttl of %d required.\n\n",ttl);
2912     }
2913
2914     /*
2915      * Use the saved response which was the longest one received,
2916      * and make additional probes after delay to measure loss.
2917      */
2918     raddr = base.qhdr.tr_raddr;
2919     rttl = TR_GETTTL(base.qhdr.tr_rttlqid);
2920     gettimeofday(&tv, 0);
2921     waittime = statint - (((tv.tv_sec + JAN_1970) & 0xFFFF) - (base.qtime >> 16));
2922     prev = &base;
2923     new = &incr[numstats&1];
2924
2925     /*
2926      * Zero out bug-avoidance counters
2927      */
2928     memset(bugs, 0, sizeof(bugs));
2929
2930     if (!printstats)
2931         printf("Monitoring path..");
2932
2933     while (numstats--) {
2934         if (waittime < 1) printf("\n");
2935         else {
2936             if (printstats && (lossthresh == 0 || printed)) {
2937                 printf("Waiting to accumulate statistics...");
2938             } else {
2939                 printf(".");
2940             }
2941             fflush(stdout);
2942             sleep((unsigned)waittime);
2943         }
2944         printed = 0;
2945         rno = hopbyhop ? base.len : qno ? qno : MAXHOPS;
2946         recvlen = send_recv(tdst, IGMP_MTRACE, rno, nqueries, new, mtrace_callback);
2947
2948         if (recvlen == 0) {
2949             printf("Timed out.\n");
2950             if (numstats) {
2951                 numstats++;
2952                 continue;
2953             } else
2954                 exit(1);
2955         }
2956
2957         if (base.len != new->len || path_changed(&base, new)) {
2958             printf("%s", base.len == new->len ? "Route changed" :
2959                                         "Trace length doesn't match");
2960             if (!printstats)
2961                 printf(" after %d seconds",
2962                    (int)((new->qtime - base.qtime) >> 16));
2963             printf(":\n");
2964 printandcontinue:
2965             print_trace(1, new, names);
2966             numstats++;
2967             bcopy(new, &base, sizeof(base));
2968             nexthop = hops = new->len;
2969             printf("Continuing with hop-by-hop...\n");
2970             goto continuehop;
2971         }
2972
2973         if (printstats) {
2974             if (new->igmp.igmp_group.s_addr != qgrp ||
2975                 new->qhdr.tr_src != qsrc || new->qhdr.tr_dst != qdst)
2976                 printf("\nWARNING: trace modified en route; statistics may be incorrect\n");
2977             fixup_stats(&base, prev, new, bugs);
2978             if ((lossthresh == 0) || check_thresh(lossthresh, &base, prev, new)) {
2979                 printf("Results after %d seconds",
2980                        (int)((new->qtime - base.qtime) >> 16));
2981                 if (lossthresh)
2982                     printf(" (this trace %d seconds)",
2983                            (int)((new->qtime - prev->qtime) >> 16));
2984                 if (verbose) {
2985                     time_t t = time(0);
2986                     struct tm *qr = localtime(&t);
2987
2988                     printf(" qid 0x%06x at %2d:%02d:%02d",
2989                                 TR_GETQID(base.qhdr.tr_rttlqid),
2990                                 qr->tm_hour, qr->tm_min, qr->tm_sec);
2991                 }
2992                 printf(":\n\n");
2993                 printed = 1;
2994                 if (print_stats(&base, prev, new, bugs, names)) {
2995                     printf("This should have been detected earlier, but ");
2996                     printf("Route changed:\n");
2997                     goto printandcontinue;
2998                 }
2999             }
3000         }
3001         prev = new;
3002         new = &incr[numstats&1];
3003         waittime = statint;
3004     }
3005
3006     /*
3007      * If the response was multicast back, leave the group
3008      */
3009     if (raddr) {
3010         if (IN_MULTICAST(ntohl(raddr))) k_leave(raddr, lcl_addr);
3011     } else k_leave(resp_cast, lcl_addr);
3012
3013     return (0);
3014 }
3015
3016 static void
3017 usage(void)
3018 {
3019         fprintf(stderr, "%s\n%s\n%s\n",
3020         "usage: mtrace [-MUOPTWVlnpvs] [-e extra_hops] [-f first_hop] [-i if_addr]",
3021         "              [-g gateway] [-m max_hops] [-q nqueries] [-r resp_dest]",
3022         "              [-S statint] [-t ttl] [-w wait] source [receiver] [group]");
3023         exit(1);
3024 }
3025
3026 void
3027 check_vif_state(void)
3028 {
3029     dolog(LOG_WARNING, errno, "sendto");
3030 }
3031
3032 /*
3033  * Log errors and other messages to stderr, according to the severity
3034  * of the message and the current debug level.  For errors of severity
3035  * LOG_ERR or worse, terminate the program.
3036  */
3037 void
3038 dolog(int severity, int syserr, char *format, ...)
3039 {
3040         va_list ap;
3041         char    fmt[100];
3042
3043         va_start(ap, format);
3044
3045     switch (debug) {
3046         case 0: if (severity > LOG_WARNING) return;
3047         case 1: if (severity > LOG_NOTICE) return;
3048         case 2: if (severity > LOG_INFO  ) return;
3049         default:
3050             fmt[0] = '\0';
3051             if (severity == LOG_WARNING) 
3052                 strcpy(fmt, "warning - ");
3053             strncat(fmt, format, sizeof(fmt)-strlen(fmt));
3054             fmt[sizeof(fmt)-1]='\0';
3055             vfprintf(stderr, fmt, ap);
3056             if (syserr == 0)
3057                 fprintf(stderr, "\n");
3058             else if (syserr < sys_nerr)
3059                 fprintf(stderr, ": %s\n", sys_errlist[syserr]);
3060             else
3061                 fprintf(stderr, ": errno %d\n", syserr);
3062     }
3063     if (severity <= LOG_ERR) exit(1);
3064 }