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