diff options
Diffstat (limited to 'usr.sbin/mrouted/mtrace.c')
-rw-r--r-- | usr.sbin/mrouted/mtrace.c | 600 |
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; +{ +} |