📄 mtrace.c
字号:
if (r->tr_outaddr == 0) r->tr_outaddr = recvaddr.sin_addr.s_addr; /* * A match, we'll keep this one. */ if (len > code) { fprintf(stderr, "Num hops received (%d) exceeds request (%d)\n", len, code); } rquery->tr_raddr = query->tr_raddr; /* Insure these are */ TR_SETTTL(rquery->tr_rttlqid, TR_GETTTL(query->tr_rttlqid)); /* as we sent them */ break; default: continue; } /* * We're pretty sure we want to use this packet now, * but if the caller gave a callback function, it might * want to handle it instead. Give the callback a chance, * unless the select timed out (in which case the only way * to get here is because the callback returned a packet). */ if (callback && (count != 0) && ((callback)(0, recv_buf, recvlen, igmp, igmpdatalen, (struct sockaddr*)&recvaddr, &socklen, &tr)) == 0) { /* * The callback function didn't like this packet. * Go try receiving another one. */ continue; } /* * Most of the sanity checking done at this point. * Return this packet we have been waiting for. */ if (save) { save->qtime = ((tq.tv_sec + JAN_1970) << 16) + (tq.tv_usec << 10) / 15625; save->rtime = ((tr.tv_sec + JAN_1970) << 16) + (tr.tv_usec << 10) / 15625; save->len = len; bcopy((char *)igmp, (char *)&save->igmp, ipdatalen); } return (recvlen); } } 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. */voidpassive_mode(){ struct timeval tr; struct ip *ip; struct igmp *igmp; struct tr_resp *r; struct sockaddr_in recvaddr; struct tm *now; char timebuf[32]; int socklen; int ipdatalen, iphdrlen, igmpdatalen; int len, recvlen; int qid; u_int32 smask; struct mtrace *remembered = NULL, *m, *n, **nn; int pc = 0; if (raddr) { if (IN_MULTICAST(ntohl(raddr))) k_join(raddr, lcl_addr); } else k_join(htonl(0xE0000120), lcl_addr); while (1) { fflush(stdout); /* make sure previous trace is flushed */ socklen = sizeof(recvaddr); recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE, 0, (struct sockaddr *)&recvaddr, &socklen); 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;#ifdef RAW_INPUT_IS_RAW ipdatalen = ntohs(ip->ip_len);#else ipdatalen = ip->ip_len;#endif 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; /* XXX This should be a hash table */ /* XXX garbage-collection should be more efficient */ for (nn = &remembered, n = *nn, m = 0; n; n = *nn) { if ((n->base.qhdr.tr_src == base.qhdr.tr_src) && (n->base.qhdr.tr_dst == base.qhdr.tr_dst) && (n->base.igmp.igmp_group.s_addr == igmp->igmp_group.s_addr)) { m = n; m->last = tr; } if (tr.tv_sec - n->last.tv_sec > 500) { /* XXX don't hardcode */ *nn = n->next; free(n); } else { nn = &n->next; } } now = localtime(&tr.tv_sec); strftime(timebuf, sizeof(timebuf) - 1, "%b %e %k:%M:%S", now); printf("Mtrace %s at %s", len == 0 ? "query" : igmp->igmp_type == IGMP_MTRACE_RESP ? "response" : "in transit", timebuf); if (len == 0) printf(" by %s", inet_fmt(recvaddr.sin_addr.s_addr, s1)); if (!IN_MULTICAST(base.qhdr.tr_raddr)) printf(", resp to %s", (len == 0 && recvaddr.sin_addr.s_addr == base.qhdr.tr_raddr) ? "same" : inet_fmt(base.qhdr.tr_raddr, s1)); else printf(", respttl %d", TR_GETTTL(base.qhdr.tr_rttlqid)); printf(", qid %06x\n", qid = TR_GETQID(base.qhdr.tr_rttlqid)); printf("packet from %s to %s\n", inet_fmt(ip->ip_src.s_addr, s1), inet_fmt(ip->ip_dst.s_addr, s2)); printf("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) { printf("\n"); continue; } r = base.resps + base.len - 1; /* * Some routers will return error messages without * filling in their addresses. We fill in the address * for them. */ if (r->tr_outaddr == 0) r->tr_outaddr = recvaddr.sin_addr.s_addr; /* * If there was a previous trace, it see if this is a * statistics candidate. */ if (m && base.len == m->base.len && !(pc = path_changed(&m->base, &base))) { /* * Some mtrace responders send multiple copies of the same * reply. Skip this packet if it's got the same query-id * as the last one. */ if (m->lastqid == qid) { printf("Skipping duplicate reply\n"); continue; } m->lastqid = qid; ++m->nresp; bcopy(&base, m->new, sizeof(base)); printf("Results after %d seconds:\n\n", (int)((m->new->qtime - m->base.qtime) >> 16)); fixup_stats(&m->base, m->prev, m->new, m->bugs); print_stats(&m->base, m->prev, m->new, m->bugs, m->names); m->prev = m->new; m->new = &m->incr[(m->nresp & 1)]; continue; } if (m == NULL) { m = (struct mtrace *)malloc(sizeof(struct mtrace)); if (m == NULL) { fprintf(stderr, "Out of memory!\n"); continue; } bzero(m, sizeof(struct mtrace)); m->next = remembered; remembered = m; bcopy(&tr, &m->last, sizeof(tr)); } /* Either it's a hop-by-hop in progress, or the path changed. */ if (pc) { printf("[Path Changed...]\n"); bzero(m->bugs, sizeof(m->bugs)); } bcopy(&base, &m->base, sizeof(base)); m->prev = &m->base; m->new = &m->incr[0]; m->nresp = 0; printf(" 0 "); print_host(base.qhdr.tr_dst); printf("\n"); print_trace(1, &base, m->names); 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)); print_host(r->tr_rmtaddr); printf(" %s\n", 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(addr1, s1)); return (""); } 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);}/* * Print responses as received (reverse path from dst to src) */voidprint_trace(idx, buf, names) int idx; struct resp_buf *buf; char **names;{ struct tr_resp *r; char *name; int i; int hop; char *ms; i = abs(idx); r = buf->resps + i - 1; for (; i <= buf->len; ++i, ++r) { if (idx > 0) printf("%3d ", -i); name = print_host2(r->tr_outaddr, r->tr_inaddr); if (r->tr_rflags != TR_NO_RTE) printf(" %s thresh^ %d", proto_type(r->tr_rproto), r->tr_fttl); if (verbose) { hop = t_diff(ntohl(r->tr_qarr), buf->qtime); ms = scale(&hop); printf(" %d%s", hop, ms); } printf(" %s", flag_type(r->tr_rflags)); if (i > 1 && r->tr_outaddr != (r-1)->tr_rmtaddr) { printf(" !RPF!"); print_host((r-1)->tr_rmtaddr); } if (r->tr_rflags != TR_NO_RTE) { if (r->tr_smask <= 1) /* MASK_TO_VAL() returns 1 for default */ printf(" [default]"); else if (verbose) { u_int32 smask; VAL_TO_MASK(smask, r->tr_smask); printf(" [%s]", inet_fmts(buf->qhdr.tr_src & smask, smask, s1)); } } printf("\n"); if (names[i-1]) free(names[i-1]); names[i-1]=malloc(strlen(name) + 1); strcpy(names[i-1], name); }}/* * See what kind of router is the next hop */intwhat_kind(buf, why) struct resp_buf *buf; char *why;{ u_int32 smask; int retval; int hops = buf->len; struct tr_resp *r = buf->resps + hops - 1; u_int32 next = r->tr_rmtaddr; retval = send_recv(next, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS2, 1, &incr[0], NULL); print_host(next); if (retval) { u_int32 version = ntohl(incr[0].igmp.igmp_group.s_addr); u_int32 *p = (u_int32 *)incr[0].ndata; u_int32 *ep = p + (incr[0].len >> 2); char *type = "version "; retval = 0; switch (version & 0xFF) { case 1: type = "proteon/mrouted "; retval = 1; break; case 10: case 11: type = "cisco "; } printf(" [%s%d.%d] %s\n", type, version & 0xFF, (version >> 8) & 0xFF, why); VAL_TO_MASK(smask, r->tr_smask); while (p < ep) { 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)); print_host(qsrc); printf("\n"); return 1; } p += n; } return retval; } printf(" %s\n", why); return 0;}char *scale(hop) int *hop;{ if (*hop > -1000 && *hop < 10000) return (" ms"); *hop /= 1000; if (*hop > -1000 && *hop < 10000) return (" s "); return ("s ");}/* * Calculate and print one line of packet loss and packet rate statistics. * Checks for count of all ones from mrouted 2.3 that doesn't have counters. */#define NEITHER 0#define INS 1#define OUTS 2#define BOTH 3voidstat_line(r, s, have_next, rst) struct tr_resp *r, *s; int have_next; int *rst;{ int timediff = (ntohl(s->tr_qarr) - ntohl(r->tr_qarr)) >> 16; 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]; int vhave = NEITHER; int ghave = NEITHER; int gmissing = NEITHER; char whochar; int badtime = 0; if (timediff == 0) { badtime = 1; /* Might be 32 bits of int seconds instead of 16int+16frac */ timediff = ntohl(s->tr_qarr) - ntohl(r->tr_qarr); if (timediff == 0 || abs(timediff - statint) > statint) timediff = 1; } v_pps = v_out / timediff; g_pps = g_out / timediff;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -