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