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