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