aboutsummaryrefslogtreecommitdiff
path: root/usr.sbin/mrouted/mtrace.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/mrouted/mtrace.c')
-rw-r--r--usr.sbin/mrouted/mtrace.c600
1 files changed, 473 insertions, 127 deletions
diff --git a/usr.sbin/mrouted/mtrace.c b/usr.sbin/mrouted/mtrace.c
index 321b2693092d..389084ae2416 100644
--- a/usr.sbin/mrouted/mtrace.c
+++ b/usr.sbin/mrouted/mtrace.c
@@ -46,16 +46,19 @@
* In particular, parts of the prototype version of this program may
* have been derived from mrouted programs sources covered by the
* license in the accompanying file named "LICENSE".
- *
- * $Id: mtrace.c,v 3.6 1995/06/25 19:17:14 fenner Exp $
*/
+#ifndef lint
+static char rcsid[] =
+ "@(#) $Id: mtrace.c,v 3.8 1995/11/29 22:36:34 fenner Rel $";
+#endif
+
#include <netdb.h>
#include <sys/time.h>
-#include <sys/filio.h>
#include <memory.h>
#include <string.h>
#include <ctype.h>
+#include <sys/ioctl.h>
#include "defs.h"
#include <arpa/inet.h>
#ifdef __STDC__
@@ -63,6 +66,9 @@
#else
#include <varargs.h>
#endif
+#ifdef SUNOS5
+#include <sys/systeminfo.h>
+#endif
#define DEFAULT_TIMEOUT 3 /* How long to wait before retrying requests */
#define DEFAULT_RETRIES 3 /* How many times to try */
@@ -91,6 +97,8 @@ struct resp_buf {
#define ndata u.d
char names[MAXHOPS][40];
+int reset[MAXHOPS]; /* To get around 3.4 bug, ... */
+int swaps[MAXHOPS]; /* To get around 3.6 bug, ... */
int timeout = DEFAULT_TIMEOUT;
int nqueries = DEFAULT_RETRIES;
@@ -98,6 +106,8 @@ int numeric = FALSE;
int debug = 0;
int passive = FALSE;
int multicast = FALSE;
+int statint = 10;
+int verbose = 0;
u_int32 defgrp; /* Default group if not specified */
u_int32 query_cast; /* All routers multicast addr */
@@ -140,12 +150,14 @@ u_long fixtime __P((u_long time));
int send_recv __P((u_int32 dst, int type, int code,
int tries, struct resp_buf *save));
char * print_host __P((u_int32 addr));
+char * print_host2 __P((u_int32 addr1, u_int32 addr2));
void print_trace __P((int index, struct resp_buf *buf));
-int what_kind __P((struct resp_buf *buf));
+int what_kind __P((struct resp_buf *buf, char *why));
char * scale __P((int *hop));
void stat_line __P((struct tr_resp *r, struct tr_resp *s,
- int have_next));
+ int have_next, int *res));
void fixup_stats __P((struct resp_buf *base,
+ struct resp_buf *prev,
struct resp_buf *new));
int print_stats __P((struct resp_buf *base,
struct resp_buf *prev,
@@ -313,9 +325,9 @@ int
get_ttl(buf)
struct resp_buf *buf;
{
- register rno;
- register struct tr_resp *b;
- register ttl;
+ int rno;
+ struct tr_resp *b;
+ u_int ttl;
if (buf && (rno = buf->len) > 0) {
b = buf->resps + rno - 1;
@@ -361,6 +373,17 @@ fixtime(time)
return (time);
}
+/*
+ * Swap bytes for poor little-endian machines that don't byte-swap
+ */
+u_long
+byteswap(v)
+ u_long v;
+{
+ return ((v << 24) | ((v & 0xff00) << 8) |
+ ((v >> 8) & 0xff00) | (v >> 24));
+}
+
int
send_recv(dst, type, code, tries, save)
u_int32 dst;
@@ -504,11 +527,11 @@ send_recv(dst, type, code, tries, save)
* addresses in the response.
*/
if (ip->ip_src.s_addr != dst) {
- register u_int32 *p = (u_int32 *)(igmp + 1);
- register u_int32 *ep = p + (len >> 2);
+ u_int32 *p = (u_int32 *)(igmp + 1);
+ u_int32 *ep = p + (len >> 2);
while (p < ep) {
- register u_int32 laddr = *p++;
- register int n = ntohl(*p++) & 0xFF;
+ u_int32 laddr = *p++;
+ int n = ntohl(*p++) & 0xFF;
if (laddr == dst) {
ep = p + 1; /* ensure p < ep after loop */
break;
@@ -586,19 +609,155 @@ send_recv(dst, type, code, tries, save)
return (0);
}
+/*
+ * Most of this code is duplicated elsewhere. I'm not sure if
+ * the duplication is absolutely required or not.
+ *
+ * Ideally, this would keep track of ongoing statistics
+ * collection and print out statistics. (& keep track
+ * of h-b-h traces and only print the longest) For now,
+ * it just snoops on what traces it can.
+ */
+void
+passive_mode()
+{
+ struct timeval tr;
+ struct ip *ip;
+ struct igmp *igmp;
+ struct tr_resp *r;
+ int ipdatalen, iphdrlen, igmpdatalen;
+ int len, recvlen, dummy = 0;
+ u_int32 smask;
+
+ init_igmp();
+
+ if (raddr) {
+ if (IN_MULTICAST(ntohl(raddr))) k_join(raddr, INADDR_ANY);
+ } else k_join(htonl(0xE0000120), INADDR_ANY);
+
+ while (1) {
+ recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE,
+ 0, (struct sockaddr *)0, &dummy);
+ gettimeofday(&tr,0);
+
+ if (recvlen <= 0) {
+ if (recvlen && errno != EINTR) perror("recvfrom");
+ continue;
+ }
+
+ if (recvlen < sizeof(struct ip)) {
+ fprintf(stderr,
+ "packet too short (%u bytes) for IP header", recvlen);
+ continue;
+ }
+ ip = (struct ip *) recv_buf;
+ if (ip->ip_p == 0) /* ignore cache creation requests */
+ continue;
+
+ iphdrlen = ip->ip_hl << 2;
+ ipdatalen = ip->ip_len;
+ if (iphdrlen + ipdatalen != recvlen) {
+ fprintf(stderr,
+ "packet shorter (%u bytes) than hdr+data len (%u+%u)\n",
+ recvlen, iphdrlen, ipdatalen);
+ continue;
+ }
+
+ igmp = (struct igmp *) (recv_buf + iphdrlen);
+ igmpdatalen = ipdatalen - IGMP_MINLEN;
+ if (igmpdatalen < 0) {
+ fprintf(stderr,
+ "IP data field too short (%u bytes) for IGMP from %s\n",
+ ipdatalen, inet_fmt(ip->ip_src.s_addr, s1));
+ continue;
+ }
+
+ switch (igmp->igmp_type) {
+
+ case IGMP_MTRACE: /* For backward compatibility with 3.3 */
+ case IGMP_MTRACE_RESP:
+ if (igmpdatalen < QLEN) continue;
+ if ((igmpdatalen - QLEN)%RLEN) {
+ printf("packet with incorrect datalen\n");
+ continue;
+ }
+
+ len = (igmpdatalen - QLEN)/RLEN;
+
+ break;
+
+ default:
+ continue;
+ }
+
+ base.qtime = ((tr.tv_sec + JAN_1970) << 16) +
+ (tr.tv_usec << 10) / 15625;
+ base.rtime = ((tr.tv_sec + JAN_1970) << 16) +
+ (tr.tv_usec << 10) / 15625;
+ base.len = len;
+ bcopy((char *)igmp, (char *)&base.igmp, ipdatalen);
+ /*
+ * If the user specified which traces to monitor,
+ * only accept traces that correspond to the
+ * request
+ */
+ if ((qsrc != 0 && qsrc != base.qhdr.tr_src) ||
+ (qdst != 0 && qdst != base.qhdr.tr_dst) ||
+ (qgrp != 0 && qgrp != igmp->igmp_group.s_addr))
+ continue;
+
+ printf("Mtrace from %s to %s via group %s (mxhop=%d)\n",
+ inet_fmt(base.qhdr.tr_dst, s1), inet_fmt(base.qhdr.tr_src, s2),
+ inet_fmt(igmp->igmp_group.s_addr, s3), igmp->igmp_code);
+ if (len == 0)
+ continue;
+ printf(" 0 ");
+ print_host(base.qhdr.tr_dst);
+ printf("\n");
+ print_trace(1, &base);
+ r = base.resps + base.len - 1;
+ VAL_TO_MASK(smask, r->tr_smask);
+ if ((r->tr_inaddr & smask) == (base.qhdr.tr_src & smask)) {
+ printf("%3d ", -(base.len+1));
+ print_host(base.qhdr.tr_src);
+ printf("\n");
+ } else if (r->tr_rmtaddr != 0) {
+ printf("%3d ", -(base.len+1));
+ what_kind(&base, r->tr_rflags == TR_OLD_ROUTER ?
+ "doesn't support mtrace"
+ : "is the next hop");
+ }
+ printf("\n");
+ }
+}
char *
print_host(addr)
u_int32 addr;
{
+ return print_host2(addr, 0);
+}
+
+/*
+ * On some routers, one interface has a name and the other doesn't.
+ * We always print the address of the outgoing interface, but can
+ * sometimes get the name from the incoming interface. This might be
+ * confusing but should be slightly more helpful than just a "?".
+ */
+char *
+print_host2(addr1, addr2)
+ u_int32 addr1, addr2;
+{
char *name;
if (numeric) {
- printf("%s", inet_fmt(addr, s1));
+ printf("%s", inet_fmt(addr1, s1));
return ("");
}
- name = inet_name(addr);
- printf("%s (%s)", name, inet_fmt(addr, s1));
+ name = inet_name(addr1);
+ if (*name == '?' && *(name + 1) == '\0' && addr2 != 0)
+ name = inet_name(addr2);
+ printf("%s (%s)", name, inet_fmt(addr1, s1));
return (name);
}
@@ -613,16 +772,22 @@ print_trace(index, buf)
struct tr_resp *r;
char *name;
int i;
+ int hop;
+ char *ms;
i = abs(index);
r = buf->resps + i - 1;
for (; i <= buf->len; ++i, ++r) {
if (index > 0) printf("%3d ", -i);
- name = print_host(r->tr_outaddr);
- printf(" %s thresh^ %d %d ms %s\n", proto_type(r->tr_rproto),
- r->tr_fttl, t_diff(fixtime(ntohl(r->tr_qarr)), buf->qtime),
- flag_type(r->tr_rflags));
+ name = print_host2(r->tr_outaddr, r->tr_inaddr);
+ printf(" %s thresh^ %d", proto_type(r->tr_rproto), r->tr_fttl);
+ if (verbose) {
+ hop = t_diff(fixtime(ntohl(r->tr_qarr)), buf->qtime);
+ ms = scale(&hop);
+ printf(" %d%s", hop, ms);
+ }
+ printf(" %s\n", flag_type(r->tr_rflags));
memcpy(names[i-1], name, sizeof(names[0]) - 1);
names[i-1][sizeof(names[0])-1] = '\0';
}
@@ -632,8 +797,9 @@ print_trace(index, buf)
* See what kind of router is the next hop
*/
int
-what_kind(buf)
+what_kind(buf, why)
struct resp_buf *buf;
+ char *why;
{
u_int32 smask;
int retval;
@@ -666,13 +832,14 @@ what_kind(buf)
case 10:
type = "cisco ";
}
- printf(" [%s%d.%d] didn't respond\n",
- type, version & 0xFF, (version >> 8) & 0xFF);
+ printf(" [%s%d.%d] %s\n",
+ type, version & 0xFF, (version >> 8) & 0xFF,
+ why);
VAL_TO_MASK(smask, r->tr_smask);
while (p < ep) {
- register u_int32 laddr = *p++;
- register int flags = (ntohl(*p) & 0xFF00) >> 8;
- register int n = ntohl(*p++) & 0xFF;
+ u_int32 laddr = *p++;
+ int flags = (ntohl(*p) & 0xFF00) >> 8;
+ int n = ntohl(*p++) & 0xFF;
if (!(flags & (DVMRP_NF_DOWN | DVMRP_NF_DISABLED)) &&
(laddr & smask) == (qsrc & smask)) {
printf("%3d ", -(hops+2));
@@ -684,7 +851,7 @@ what_kind(buf)
}
return retval;
}
- printf(" didn't respond\n");
+ printf(" %s\n", why);
return 0;
}
@@ -708,30 +875,37 @@ scale(hop)
#define OUTS 2
#define BOTH 3
void
-stat_line(r, s, have_next)
+stat_line(r, s, have_next, rst)
struct tr_resp *r, *s;
int have_next;
+ int *rst;
{
- register timediff = (fixtime(ntohl(s->tr_qarr)) -
+ int timediff = (fixtime(ntohl(s->tr_qarr)) -
fixtime(ntohl(r->tr_qarr))) >> 16;
- register v_lost, v_pct;
- register g_lost, g_pct;
- register v_out = ntohl(s->tr_vifout) - ntohl(r->tr_vifout);
- register g_out = ntohl(s->tr_pktcnt) - ntohl(r->tr_pktcnt);
- register v_pps, g_pps;
+ int v_lost, v_pct;
+ int g_lost, g_pct;
+ int v_out = ntohl(s->tr_vifout) - ntohl(r->tr_vifout);
+ int g_out = ntohl(s->tr_pktcnt) - ntohl(r->tr_pktcnt);
+ int v_pps, g_pps;
char v_str[8], g_str[8];
- register have = NEITHER;
+ int have = NEITHER;
+ int res = *rst;
if (timediff == 0) timediff = 1;
v_pps = v_out / timediff;
g_pps = g_out / timediff;
- if (v_out || s->tr_vifout != 0xFFFFFFFF) have |= OUTS;
+ if (v_out && (s->tr_vifout != 0xFFFFFFFF && s->tr_vifout != 0) ||
+ (r->tr_vifout != 0xFFFFFFFF && r->tr_vifout != 0))
+ have |= OUTS;
if (have_next) {
- --r, --s;
- if (s->tr_vifin != 0xFFFFFFFF || r->tr_vifin != 0xFFFFFFFF)
+ --r, --s, --rst;
+ if ((s->tr_vifin != 0xFFFFFFFF && s->tr_vifin != 0) ||
+ (r->tr_vifin != 0xFFFFFFFF && r->tr_vifin != 0))
have |= INS;
+ if (*rst)
+ res = 1;
}
switch (have) {
@@ -750,61 +924,129 @@ stat_line(r, s, have_next)
sprintf(g_str, "%3d", g_pct);
else memcpy(g_str, " --", 4);
- printf("%6d/%-5d=%s%%%4d pps%6d/%-5d=%s%%%4d pps\n",
- v_lost, v_out, v_str, v_pps, g_lost, g_out, g_str, g_pps);
- if (debug > 2) {
- printf("\t\t\t\tv_in: %ld ", ntohl(s->tr_vifin));
- printf("v_out: %ld ", ntohl(s->tr_vifout));
- printf("pkts: %ld\n", ntohl(s->tr_pktcnt));
- printf("\t\t\t\tv_in: %ld ", ntohl(r->tr_vifin));
- printf("v_out: %ld ", ntohl(r->tr_vifout));
- printf("pkts: %ld\n", ntohl(r->tr_pktcnt));
- printf("\t\t\t\tv_in: %ld ",ntohl(s->tr_vifin)-ntohl(r->tr_vifin));
- printf("v_out: %ld ", ntohl(s->tr_vifout) - ntohl(r->tr_vifout));
- printf("pkts: %ld ", ntohl(s->tr_pktcnt) - ntohl(r->tr_pktcnt));
- printf("time: %d\n", timediff);
- }
+ printf("%6d/%-5d=%s%%%4d pps",
+ v_lost, v_out, v_str, v_pps);
+ if (res)
+ printf("\n");
+ else
+ printf("%6d/%-5d=%s%%%4d pps\n",
+ g_lost, g_out, g_str, g_pps);
break;
case INS:
- v_out = (ntohl(s->tr_vifin) - ntohl(r->tr_vifin));
- g_out = (ntohl(s->tr_pktcnt) - ntohl(r->tr_pktcnt));
+ v_out = ntohl(s->tr_vifin) - ntohl(r->tr_vifin);
v_pps = v_out / timediff;
- g_pps = g_out / timediff;
/* Fall through */
case OUTS:
- printf(" %-5d %4d pps %-5d %4d pps\n",
- v_out, v_pps, g_out, g_pps);
+ printf(" %-5d %4d pps",
+ v_out, v_pps);
+ if (res)
+ printf("\n");
+ else
+ printf(" %-5d %4d pps\n",
+ g_out, g_pps);
break;
case NEITHER:
printf("\n");
break;
}
+
+ if (debug > 2) {
+ printf("\t\t\t\tv_in: %ld ", ntohl(s->tr_vifin));
+ printf("v_out: %ld ", ntohl(s->tr_vifout));
+ printf("pkts: %ld\n", ntohl(s->tr_pktcnt));
+ printf("\t\t\t\tv_in: %ld ", ntohl(r->tr_vifin));
+ printf("v_out: %ld ", ntohl(r->tr_vifout));
+ printf("pkts: %ld\n", ntohl(r->tr_pktcnt));
+ printf("\t\t\t\tv_in: %ld ",ntohl(s->tr_vifin)-ntohl(r->tr_vifin));
+ printf("v_out: %ld ", ntohl(s->tr_vifout) - ntohl(r->tr_vifout));
+ printf("pkts: %ld ", ntohl(s->tr_pktcnt) - ntohl(r->tr_pktcnt));
+ printf("time: %d\n", timediff);
+ printf("\t\t\t\tres: %d\n", res);
+ }
}
/*
- * A fixup to check if any pktcnt has been reset.
+ * A fixup to check if any pktcnt has been reset, and to fix the
+ * byteorder bugs in mrouted 3.6 on little-endian machines.
*/
void
-fixup_stats(base, new)
- struct resp_buf *base, *new;
+fixup_stats(base, prev, new)
+ struct resp_buf *base, *prev, *new;
{
- register rno = base->len;
- register struct tr_resp *b = base->resps + rno;
- register struct tr_resp *n = new->resps + rno;
+ int rno = base->len;
+ struct tr_resp *b = base->resps + rno;
+ struct tr_resp *p = prev->resps + rno;
+ struct tr_resp *n = new->resps + rno;
+ int *r = reset + rno;
+ int *s = swaps + rno;
+ int res;
+
+ /* Check for byte-swappers */
+ while (--rno >= 0) {
+ --n; --p; --b; --s;
+ if (*s || abs(ntohl(n->tr_vifout) - ntohl(p->tr_vifout)) > 100000) {
+ /* This host sends byteswapped reports; swap 'em */
+ if (!*s) {
+ *s = 1;
+ b->tr_qarr = byteswap(b->tr_qarr);
+ b->tr_vifin = byteswap(b->tr_vifin);
+ b->tr_vifout = byteswap(b->tr_vifout);
+ b->tr_pktcnt = byteswap(b->tr_pktcnt);
+ }
- while (--rno >= 0)
- if (ntohl((--n)->tr_pktcnt) < ntohl((--b)->tr_pktcnt)) break;
+ n->tr_qarr = byteswap(n->tr_qarr);
+ n->tr_vifin = byteswap(n->tr_vifin);
+ n->tr_vifout = byteswap(n->tr_vifout);
+ n->tr_pktcnt = byteswap(n->tr_pktcnt);
+ }
+ }
+
+ rno = base->len;
+ b = base->resps + rno;
+ p = prev->resps + rno;
+ n = new->resps + rno;
+
+ while (--rno >= 0) {
+ --n; --p; --b; --r;
+ res = ((ntohl(n->tr_pktcnt) < ntohl(b->tr_pktcnt)) ||
+ (ntohl(n->tr_pktcnt) < ntohl(p->tr_pktcnt)));
+ if (debug > 2)
+ printf("\t\tr=%d, res=%d\n", *r, res);
+ if (*r) {
+ if (res || *r > 1) {
+ /*
+ * This router appears to be a 3.4 with that nasty ol'
+ * neighbor version bug, which causes it to constantly
+ * reset. Just nuke the statistics for this node, and
+ * don't even bother giving it the benefit of the
+ * doubt from now on.
+ */
+ p->tr_pktcnt = b->tr_pktcnt = n->tr_pktcnt;
+ *r++;
+ } else {
+ /*
+ * This is simply the situation that the original
+ * fixup_stats was meant to deal with -- that a
+ * 3.3 or 3.4 router deleted a cache entry while
+ * traffic was still active.
+ */
+ *r = 0;
+ break;
+ }
+ } else
+ *r = res;
+ }
if (rno < 0) return;
rno = base->len;
b = base->resps + rno;
- n = new->resps + rno;
+ p = prev->resps + rno;
- while (--rno >= 0) (--b)->tr_pktcnt = (--n)->tr_pktcnt;
+ while (--rno >= 0) (--b)->tr_pktcnt = (--p)->tr_pktcnt;
}
/*
@@ -815,15 +1057,17 @@ print_stats(base, prev, new)
struct resp_buf *base, *prev, *new;
{
int rtt, hop;
- register char *ms;
- register u_int32 smask;
- register rno = base->len - 1;
- register struct tr_resp *b = base->resps + rno;
- register struct tr_resp *p = prev->resps + rno;
- register struct tr_resp *n = new->resps + rno;
- register u_long resptime = new->rtime;
- register u_long qarrtime = fixtime(ntohl(n->tr_qarr));
- register ttl = n->tr_fttl;
+ char *ms;
+ u_int32 smask;
+ int rno = base->len - 1;
+ struct tr_resp *b = base->resps + rno;
+ struct tr_resp *p = prev->resps + rno;
+ struct tr_resp *n = new->resps + rno;
+ int *r = reset + rno;
+ u_long resptime = new->rtime;
+ u_long qarrtime = fixtime(ntohl(n->tr_qarr));
+ u_int ttl = n->tr_fttl;
+ int first = (base == prev);
VAL_TO_MASK(smask, b->tr_smask);
printf(" Source Response Dest");
@@ -833,12 +1077,14 @@ print_stats(base, prev, new)
inet_fmt(base->qhdr.tr_raddr, s2), inet_fmt(qsrc, s1));
rtt = t_diff(resptime, new->qtime);
ms = scale(&rtt);
- printf(" | __/ rtt%5d%s Lost/Sent = Pct Rate To %s\n",
- rtt, ms, inet_fmt(qgrp, s2));
- hop = t_diff(resptime, qarrtime);
- ms = scale(&hop);
- printf(" v / hop%5d%s", hop, ms);
- printf(" --------------------- --------------------\n");
+ printf(" %c __/ rtt%5d%s Lost/Sent = Pct Rate To %s\n",
+ first ? 'v' : '|', rtt, ms, inet_fmt(qgrp, s2));
+ if (!first) {
+ hop = t_diff(resptime, qarrtime);
+ ms = scale(&hop);
+ printf(" v / hop%5d%s", hop, ms);
+ printf(" --------------------- --------------------\n");
+ }
if (debug > 2) {
printf("\t\t\t\tv_in: %ld ", ntohl(n->tr_vifin));
printf("v_out: %ld ", ntohl(n->tr_vifout));
@@ -849,6 +1095,7 @@ print_stats(base, prev, new)
printf("\t\t\t\tv_in: %ld ", ntohl(n->tr_vifin) - ntohl(b->tr_vifin));
printf("v_out: %ld ", ntohl(n->tr_vifout) - ntohl(b->tr_vifout));
printf("pkts: %ld\n", ntohl(n->tr_pktcnt) - ntohl(b->tr_pktcnt));
+ printf("\t\t\t\treset: %d\n", *r);
}
while (TRUE) {
@@ -862,28 +1109,30 @@ print_stats(base, prev, new)
if (rno-- < 1) break;
- printf(" | ^ ttl%5d ", ttl);
- if (prev == new) printf("\n");
- else stat_line(p, n, TRUE);
- resptime = qarrtime;
- qarrtime = fixtime(ntohl((n-1)->tr_qarr));
- hop = t_diff(resptime, qarrtime);
- ms = scale(&hop);
- printf(" v | hop%5d%s", hop, ms);
- stat_line(b, n, TRUE);
+ printf(" %c ^ ttl%5d ", first ? 'v' : '|', ttl);
+ stat_line(p, n, TRUE, r);
+ if (!first) {
+ resptime = qarrtime;
+ qarrtime = fixtime(ntohl((n-1)->tr_qarr));
+ hop = t_diff(resptime, qarrtime);
+ ms = scale(&hop);
+ printf(" v | hop%5d%s", hop, ms);
+ stat_line(b, n, TRUE, r);
+ }
- --b, --p, --n;
+ --b, --p, --n, --r;
if (ttl < n->tr_fttl) ttl = n->tr_fttl;
else ++ttl;
}
- printf(" | \\__ ttl%5d ", ttl);
- if (prev == new) printf("\n");
- else stat_line(p, n, FALSE);
- hop = t_diff(qarrtime, new->qtime);
- ms = scale(&hop);
- printf(" v \\ hop%5d%s", hop, ms);
- stat_line(b, n, FALSE);
+ printf(" %c \\__ ttl%5d ", first ? 'v' : '|', ttl);
+ stat_line(p, n, FALSE, r);
+ if (!first) {
+ hop = t_diff(qarrtime, new->qtime);
+ ms = scale(&hop);
+ printf(" v \\ hop%5d%s", hop, ms);
+ stat_line(b, n, FALSE, r);
+ }
printf("%-15s %s\n", inet_fmt(qdst, s1), inet_fmt(lcl_addr, s2));
printf(" Receiver Query Source\n\n");
return 0;
@@ -923,11 +1172,11 @@ char *argv[];
if (argc == 0) goto usage;
while (argc > 0 && *argv[0] == '-') {
- register char *p = *argv++; argc--;
+ char *p = *argv++; argc--;
p++;
do {
- register char c = *p++;
- register char *arg = (char *) 0;
+ char c = *p++;
+ char *arg = (char *) 0;
if (isdigit(*p)) {
arg = p;
p = "";
@@ -954,6 +1203,9 @@ char *argv[];
case 'p': /* Passive listen for traces */
passive = TRUE;
break;
+ case 'v': /* Verbosity */
+ verbose = TRUE;
+ break;
case 's': /* Short form, don't wait for stats */
numstats = 0;
break;
@@ -1009,6 +1261,14 @@ char *argv[];
break;
} else
goto usage;
+ case 'S': /* Stat accumulation interval */
+ if (arg && isdigit(*arg)) {
+ statint = atoi(arg);
+ if (statint < 1) statint = 1;
+ if (arg == argv[0]) argv++, argc--;
+ break;
+ } else
+ goto usage;
default:
goto usage;
}
@@ -1032,10 +1292,15 @@ char *argv[];
}
}
+ if (passive) {
+ passive_mode();
+ return(0);
+ }
+
if (argc > 0 || qsrc == 0) {
usage: printf("\
Usage: mtrace [-Mlnps] [-w wait] [-m max_hops] [-q nqueries] [-g gateway]\n\
- [-t ttl] [-r resp_dest] [-i if_addr] source [receiver] [group]\n");
+ [-S statint] [-t ttl] [-r resp_dest] [-i if_addr] source [receiver] [group]\n");
exit(1);
}
@@ -1067,6 +1332,36 @@ Usage: mtrace [-Mlnps] [-w wait] [-m max_hops] [-q nqueries] [-g gateway]\n\
exit(-1);
}
+#ifdef SUNOS5
+ /*
+ * SunOS 5.X prior to SunOS 2.6, getsockname returns 0 for udp socket.
+ * This call to sysinfo will return the hostname.
+ * If the default multicast interfface (set with the route
+ * for 224.0.0.0) is not the same as the hostname,
+ * mtrace -i [if_addr] will have to be used.
+ */
+ if (addr.sin_addr.s_addr == 0) {
+ char myhostname[MAXHOSTNAMELEN];
+ struct hostent *hp;
+ int error;
+
+ error = sysinfo(SI_HOSTNAME, myhostname, sizeof(myhostname));
+ if (error == -1) {
+ perror("Getting my hostname");
+ exit(-1);
+ }
+
+ hp = gethostbyname(myhostname);
+ if (hp == NULL || hp->h_addrtype != AF_INET ||
+ hp->h_length != sizeof(addr.sin_addr)) {
+ perror("Finding IP address for my hostname");
+ exit(-1);
+ }
+
+ memcpy((char *)&addr.sin_addr.s_addr, hp->h_addr, hp->h_length);
+ }
+#endif
+
/*
* Default destination for path to be queried is the local host.
*/
@@ -1136,7 +1431,7 @@ Usage: mtrace [-Mlnps] [-w wait] [-m max_hops] [-q nqueries] [-g gateway]\n\
}
/*
- * Try a query at the requested number of hops or MAXOPS if unspecified.
+ * Try a query at the requested number of hops or MAXHOPS if unspecified.
*/
if (qno == 0) {
hops = MAXHOPS;
@@ -1148,7 +1443,7 @@ Usage: mtrace [-Mlnps] [-w wait] [-m max_hops] [-q nqueries] [-g gateway]\n\
tries = nqueries;
printf("Querying reverse path, maximum %d hops... ", qno);
fflush(stdout);
- }
+ }
base.rtime = 0;
base.len = 0;
@@ -1167,9 +1462,12 @@ Usage: mtrace [-Mlnps] [-w wait] [-m max_hops] [-q nqueries] [-g gateway]\n\
printf("\n");
print_trace(1, &base);
r = base.resps + base.len - 1;
- if (r->tr_rflags == TR_OLD_ROUTER) {
+ if (r->tr_rflags == TR_OLD_ROUTER || r->tr_rflags == TR_NO_SPACE ||
+ qno != 0) {
printf("%3d ", -(base.len+1));
- what_kind(&base);
+ what_kind(&base, r->tr_rflags == TR_OLD_ROUTER ?
+ "doesn't support mtrace"
+ : "is the next hop");
} else {
VAL_TO_MASK(smask, r->tr_smask);
if ((r->tr_inaddr & smask) == (qsrc & smask)) {
@@ -1204,7 +1502,7 @@ Usage: mtrace [-Mlnps] [-w wait] [-m max_hops] [-q nqueries] [-g gateway]\n\
if (recvlen == 0) {
if (hops == 1) break;
if (hops == nexthop) {
- if (what_kind(&base)) {
+ if (what_kind(&base, "didn't respond")) {
/* the ask_neighbors determined that the
* not-responding router is the first-hop. */
break;
@@ -1227,36 +1525,62 @@ Usage: mtrace [-Mlnps] [-w wait] [-m max_hops] [-q nqueries] [-g gateway]\n\
print_trace(nexthop, &base);
}
} else {
- if (base.len == hops - 1) {
+ if (base.len < hops) {
+ /*
+ * A shorter trace than requested means a fatal error
+ * occurred along the path, or that the route changed
+ * to a shorter one.
+ *
+ * If the trace is longer than the last one we received,
+ * then we are resuming from a skipped router (but there
+ * is still probably a problem).
+ *
+ * If the trace is shorter than the last one we
+ * received, then the route must have changed (and
+ * there is still probably a problem).
+ */
if (nexthop <= base.len) {
printf("\nResuming...\n");
print_trace(nexthop, &base);
+ } else if (nexthop > base.len + 1) {
+ hops = base.len;
+ printf("\nRoute must have changed...\n");
+ print_trace(1, &base);
}
} else {
+ /*
+ * The last hop address is not the same as it was;
+ * the route probably changed underneath us.
+ */
hops = base.len;
printf("\nRoute must have changed...\n");
print_trace(1, &base);
}
- if (r->tr_rflags == TR_OLD_ROUTER) {
- what_kind(&base);
- break;
- }
- if (r->tr_rflags == TR_NO_SPACE) {
- printf("No space left in trace packet for more hops\n");
- break; /* XXX could do segmented trace */
- }
}
lastout = r->tr_outaddr;
- nexthop = hops + 1;
- VAL_TO_MASK(smask, r->tr_smask);
- if ((r->tr_inaddr & smask) == (qsrc & smask)) {
- printf("%3d ", -nexthop);
- print_host(qsrc);
- printf("\n");
+ if (base.len < hops ||
+ r->tr_rmtaddr == 0 ||
+ (r->tr_rflags & 0x80)) {
+ VAL_TO_MASK(smask, r->tr_smask);
+ if (r->tr_rmtaddr) {
+ if (hops != nexthop) {
+ printf("\n%3d ", -(base.len+1));
+ }
+ what_kind(&base, r->tr_rflags == TR_OLD_ROUTER ?
+ "doesn't support mtrace" :
+ "would be the next hop");
+ /* XXX could do segmented trace if TR_NO_SPACE */
+ } else if (r->tr_rflags == TR_NO_ERR &&
+ (r->tr_inaddr & smask) == (qsrc & smask)) {
+ printf("%3d ", -(hops + 1));
+ print_host(qsrc);
+ printf("\n");
+ }
break;
}
- if (r->tr_rmtaddr == 0 || (r->tr_rflags & 0x80)) break;
+
+ nexthop = hops + 1;
}
}
@@ -1284,8 +1608,9 @@ or multicast at ttl %d doesn't reach its last-hop router for that source\n",
raddr = base.qhdr.tr_raddr;
rttl = base.qhdr.tr_rttl;
gettimeofday(&tv, 0);
- waittime = 10 - (((tv.tv_sec + JAN_1970) & 0xFFFF) - (base.qtime >> 16));
- prev = new = &incr[numstats&1];
+ waittime = statint - (((tv.tv_sec + JAN_1970) & 0xFFFF) - (base.qtime >> 16));
+ prev = &base;
+ new = &incr[numstats&1];
while (numstats--) {
if (waittime < 1) printf("\n");
@@ -1304,14 +1629,23 @@ or multicast at ttl %d doesn't reach its last-hop router for that source\n",
if (rno != new->len) {
printf("Trace length doesn't match:\n");
+ /*
+ * XXX Should this trace result be printed, or is that
+ * too verbose? Perhaps it should just say restarting.
+ * But if the path is changing quickly, this may be the
+ * only snapshot of the current path. But, if the path
+ * is changing that quickly, does the current path really
+ * matter?
+ */
print_trace(1, new);
printf("Restarting.\n\n");
+ numstats++;
goto restart;
}
printf("Results after %d seconds:\n\n",
(int)((new->qtime - base.qtime) >> 16));
- fixup_stats(&base, new);
+ fixup_stats(&base, prev, new);
if (print_stats(&base, prev, new)) {
printf("Route changed:\n");
print_trace(1, new);
@@ -1320,7 +1654,7 @@ or multicast at ttl %d doesn't reach its last-hop router for that source\n",
}
prev = new;
new = &incr[numstats&1];
- waittime = 10;
+ waittime = statint;
}
/*
@@ -1461,3 +1795,15 @@ void accept_neighbors2(src, dst, p, datalen, level)
int datalen;
{
}
+void accept_info_request(src, dst, p, datalen)
+ u_int32 src, dst;
+ u_char *p;
+ int datalen;
+{
+}
+void accept_info_reply(src, dst, p, datalen)
+ u_int32 src, dst;
+ u_char *p;
+ int datalen;
+{
+}