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