⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mtrace.c

📁 mtrace源码
💻 C
📖 第 1 页 / 共 5 页
字号:
    ifrp = (struct ifreq *)ifc.ifc_buf;    ifend = (struct ifreq *)(ifc.ifc_buf + ifc.ifc_len);    /*     * Loop through all of the interfaces.     */    for (; ifrp < ifend && !found; ifrp = (struct ifreq *)((char *)ifrp + n)) {#if BSD >= 199006	n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);	if (n < sizeof(*ifrp))	    n = sizeof(*ifrp);#else	n = sizeof(*ifrp);#endif	/*	 * Ignore any interface for an address family other than IP.	 */	if (ifrp->ifr_addr.sa_family != AF_INET)	    continue;	if_addr = ((struct sockaddr_in *)&(ifrp->ifr_addr))->sin_addr.s_addr;	if (ioctl(s, SIOCGIFFLAGS, (char *)ifrp) < 0) {	    fprintf(stderr, "SIOCGIFFLAGS on ");	    perror(ifrp->ifr_name);	    continue;	}	if ((ifrp->ifr_flags & (IFF_MULTICAST|IFF_UP|IFF_LOOPBACK)) !=				(IFF_MULTICAST|IFF_UP))	    continue;	if (*dst == 0)	    *dst = if_addr;	if (ioctl(s, SIOCGIFNETMASK, (char *)ifrp) >= 0) {	    if_mask = ((struct sockaddr_in *)&(ifrp->ifr_addr))->sin_addr.s_addr;	    if (if_mask != 0 && (*dst & if_mask) == (if_addr & if_mask)) {		retval = if_mask;		if (lcl_addr == 0) lcl_addr = if_addr;	/* XXX what about aliases? */	    }	}	if (lcl_addr == if_addr) found = TRUE;    }    if (!found && lcl_addr != 0) {	printf("Interface address is not valid\n");	exit(1);    }    return (retval);}/* * Try to pick a TTL that will get past all the thresholds in the path. */intget_ttl(buf)    struct resp_buf *buf;{    int rno;    struct tr_resp *b;    u_int ttl;    if (buf && (rno = buf->len) > 0) {	b = buf->resps + rno - 1;	ttl = b->tr_fttl;	while (--rno > 0) {	    --b;	    if (ttl < b->tr_fttl) ttl = b->tr_fttl;	    else ++ttl;	}	ttl += MULTICAST_TTL_INC;	if (ttl < MULTICAST_TTL1) ttl = MULTICAST_TTL1;	if (ttl > MULTICAST_TTL_MAX) ttl = MULTICAST_TTL_MAX;	return (ttl);    } else return(MULTICAST_TTL1);}/* * Calculate the difference between two 32-bit NTP timestamps and return * the result in milliseconds. */intt_diff(a, b)    u_long a, b;{    int d = a - b;    return ((d * 125) >> 13);}/* * Swap bytes for poor little-endian machines that don't byte-swap */u_longbyteswap(v)    u_long v;{    return ((v << 24) | ((v & 0xff00) << 8) |	    ((v >> 8) & 0xff00) | (v >> 24));}#if 0/* * XXX incomplete - need private callback data, too? * XXX since dst doesn't get passed through? */intneighbors_callback(tmo, buf, buflen, igmp, igmplen, addr, addrlen, ts)    int tmo;    u_char *buf;    int buflen;    struct igmp *igmp;    int igmplen;    struct sockaddr *addr;    int *addrlen;    struct timeval *ts;{    int len;    u_int32 dst;    struct ip *ip = (struct ip *)buf;    if (tmo)	return 0;    if (igmp->igmp_code != DVMRP_NEIGHBORS2)	return 0;    len = igmplen;    /*     * Accept DVMRP_NEIGHBORS2 response if it comes from the     * address queried or if that address is one of the local     * addresses in the response.     */    if (ip->ip_src.s_addr != dst) {	u_int32 *p = (u_int32 *)(igmp + 1);	u_int32 *ep = p + (len >> 2);	while (p < ep) {	    u_int32 laddr = *p++;	    int n = ntohl(*p++) & 0xFF;	    if (laddr == dst) {		ep = p + 1;		/* ensure p < ep after loop */		break;	    }	    p += n;	}	if (p >= ep)	    return 0;    }    return buflen;}#endifintmtrace_callback(tmo, buf, buflen, igmp, igmplen, addr, addrlen, ts)    int tmo;    u_char *buf;    int buflen;    struct igmp *igmp;    int igmplen;    struct sockaddr *addr;    int *addrlen;    struct timeval *ts;{    static u_char *savbuf = NULL;    static int savbuflen;    static struct sockaddr *savaddr;    static int savaddrlen;    static struct timeval savts;    int len = (igmplen - QLEN) / RLEN;    struct tr_resp *r = (struct tr_resp *)((struct tr_query *)(igmp + 1) + 1);    if (tmo == 1) {	/*	 * If we timed out with a packet saved, then return that packet.	 * send_recv won't send this same packet to the callback again.	 */	if (savbuf) {	    bcopy(savbuf, buf, savbuflen);	    free(savbuf);	    savbuf = NULL;	    bcopy(savaddr, addr, savaddrlen);	    free(savaddr);	    *addrlen = savaddrlen;	    bcopy(&savts, ts, sizeof(savts));	    return savbuflen;	}	return 0;    }    if (savbuf) {	free(savbuf);	savbuf = NULL;	free(savaddr);    }    /*     * Check for IOS bug described in CSCdi68628, where a router that does     *  not have multicast enabled responds to an mtrace request with a 1-hop     *  error packet.     * Heuristic is:     *  If there is only one hop reported in the packet,     *	And the protocol code is 0,     *  And there is no previous hop,     *	And the forwarding information is "Not Forwarding",     *	And the router is not on the same subnet as the destination of the     *		trace,     *  then drop this packet.  The "#if 0"'d code saves it and returns     *   it on timeout, but timeouts are too common (e.g. routers with     *   limited unicast routing tables, etc).     */    if (len == 1 && r->tr_rproto == 0 && r->tr_rmtaddr == 0 &&					r->tr_rflags == TR_NO_FWD) {	u_int32 smask;	VAL_TO_MASK(smask, r->tr_smask);	if ((r->tr_outaddr & smask) != (qdst & smask)) {#if 0	    /* XXX should do this silently? */	    fprintf(stderr, "mtrace: probably IOS-buggy packet from %s\n",		inet_fmt(((struct sockaddr_in *)addr)->sin_addr.s_addr, s1));	    /* Save the packet to return if a timeout occurs. */	    savbuf = (u_char *)malloc(buflen);	    if (savbuf != NULL) {		bcopy(buf, savbuf, buflen);		savbuflen = buflen;		savaddr = (struct sockaddr *)malloc(*addrlen);		if (savaddr != NULL) {		    bcopy(addr, savaddr, *addrlen);		    savaddrlen = *addrlen;		    bcopy(ts, &savts, sizeof(savts));		} else {		    free(savbuf);		    savbuf = NULL;		}	    }#endif	    return 0;	}    }    return buflen;}intsend_recv(dst, type, code, tries, save, callback)    u_int32 dst;    int type, code, tries;    struct resp_buf *save;    callback_t callback;{    fd_set  fds;    struct timeval tq, tr, tv;    struct ip *ip;    struct igmp *igmp;    struct tr_query *query, *rquery;    struct tr_resp *r;    struct sockaddr_in recvaddr;    u_int32 local, group;    int ipdatalen, iphdrlen, igmpdatalen;    int datalen;    int count, recvlen, socklen = sizeof(recvaddr);    int len;    int i;    if (type == IGMP_MTRACE) {	group = qgrp;	datalen = sizeof(struct tr_query);    } else {	group = htonl(0xff03);	datalen = 0;    }    if (IN_MULTICAST(ntohl(dst))) local = lcl_addr;    else local = INADDR_ANY;    /*     * If the reply address was not explictly specified, start off     * with the standard multicast reply address, or the unicast     * address of this host if the unicast flag was specified.     * Then, if there is no response after trying half the tries     * with multicast, switch to the unicast address of this host     * if the multicast flag was not specified.  If the TTL was     * also not specified, set a multicast TTL and increase it     * for every try.     */    query = (struct tr_query *)(send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);    query->tr_raddr = raddr ? raddr : unicast ? lcl_addr : resp_cast;    TR_SETTTL(query->tr_rttlqid, rttl ? rttl :      IN_MULTICAST(ntohl(query->tr_raddr)) ? get_ttl(save) : UNICAST_TTL);    query->tr_src   = qsrc;    query->tr_dst   = qdst;    for (i = tries ; i > 0; --i) {	int oqid;	if (tries == nqueries && raddr == 0) {	    if (i == (nqueries >> 1)) {		if (multicast && unicast) {		    query->tr_raddr = resp_cast;		    if (!rttl)			TR_SETTTL(query->tr_rttlqid, get_ttl(save));		} else if (!multicast) {		    query->tr_raddr = lcl_addr;		    TR_SETTTL(query->tr_rttlqid, UNICAST_TTL);		}	    }	    if (i < tries && IN_MULTICAST(ntohl(query->tr_raddr)) &&								rttl == 0) {		TR_SETTTL(query->tr_rttlqid,			TR_GETTTL(query->tr_rttlqid) + MULTICAST_TTL_INC);		if (TR_GETTTL(query->tr_rttlqid) > MULTICAST_TTL_MAX)		  TR_SETTTL(query->tr_rttlqid, MULTICAST_TTL_MAX);	    }	}	/*	 * Change the qid for each request sent to avoid being confused	 * by duplicate responses	 */	oqid = TR_GETQID(query->tr_rttlqid);	if (staticqid)	    TR_SETQID(query->tr_rttlqid, staticqid);	else#ifdef SYSV    	    TR_SETQID(query->tr_rttlqid, ((u_int32)lrand48() >> 8));#else	    TR_SETQID(query->tr_rttlqid, ((u_int32)random() >> 8));#endif	/*	 * Set timer to calculate delays, then send query	 */	gettimeofday(&tq, 0);	send_igmp(local, dst, type, code, group, datalen);	/*	 * Wait for response, discarding false alarms	 */	while (TRUE) {	    FD_ZERO(&fds);	    FD_SET(igmp_socket, &fds);	    gettimeofday(&tv, 0);	    tv.tv_sec = tq.tv_sec + timeout - tv.tv_sec;	    tv.tv_usec = tq.tv_usec - tv.tv_usec;	    if (tv.tv_usec < 0) tv.tv_usec += 1000000L, --tv.tv_sec;	    if (tv.tv_sec < 0) tv.tv_sec = tv.tv_usec = 0;	    count = select(igmp_socket + 1, &fds, (fd_set *)0, (fd_set *)0,			   &tv);	    if (count < 0) {		if (errno != EINTR) perror("select");		continue;	    } else if (count == 0) {		/*		 * Timed out.  Notify the callback.		 */		if (!callback || (recvlen = (callback)(1, recv_buf, 0, NULL, 0, (struct sockaddr *)&recvaddr, &socklen, &tr)) == 0) {		    printf("* ");		    fflush(stdout);		    break;		}	    } else {		/*		 * Data is available on the socket, so read it.		 */		gettimeofday(&tr, 0);		recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE,				   0, (struct sockaddr *)&recvaddr, &socklen);	    }	    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_DVMRP:		if (type != IGMP_DVMRP || code != DVMRP_ASK_NEIGHBORS2)			continue;		if (igmp->igmp_code != DVMRP_NEIGHBORS2) continue;		len = igmpdatalen;		/*		 * Accept DVMRP_NEIGHBORS2 response if it comes from the		 * address queried or if that address is one of the local		 * addresses in the response.		 */		if (ip->ip_src.s_addr != dst) {		    u_int32 *p = (u_int32 *)(igmp + 1);		    u_int32 *ep = p + (len >> 2);		    while (p < ep) {			u_int32 laddr = *p++;			int n = ntohl(*p++) & 0xFF;			if (laddr == dst) {			    ep = p + 1;		/* ensure p < ep after loop */			    break;			}			p += n;		    }		    if (p >= ep) continue;		}		break;	      case IGMP_MTRACE:	    /* For backward compatibility with 3.3 */	      case IGMP_MTRACE_RESP:		if (type != IGMP_MTRACE) continue;		if (igmpdatalen <= QLEN) continue;		if ((igmpdatalen - QLEN)%RLEN) {		    printf("packet with incomplete responses (%d bytes)\n",			igmpdatalen);		    continue;		}		/*		 * Ignore responses that don't match query.		 */		rquery = (struct tr_query *)(igmp + 1);		if (rquery->tr_src != qsrc || rquery->tr_dst != qdst)		    continue;		if (TR_GETQID(rquery->tr_rttlqid) !=			TR_GETQID(query->tr_rttlqid)) {		    if (verbose && TR_GETQID(rquery->tr_rttlqid) == oqid)			printf("[D]");		    continue;		}		len = (igmpdatalen - QLEN)/RLEN;		r = (struct tr_resp *)(rquery+1) + len - 1;		/*		 * Ignore trace queries passing through this node when		 * mtrace is run on an mrouter that is in the path		 * (needed only because IGMP_MTRACE is accepted above		 * for backward compatibility with multicast release 3.3).		 */		if (igmp->igmp_type == IGMP_MTRACE) {		    u_int32 smask;		    VAL_TO_MASK(smask, r->tr_smask);		    if (len < code && (r->tr_inaddr & smask) != (qsrc & smask)			&& r->tr_rmtaddr != 0 && !(r->tr_rflags & 0x80))		      continue;		}		/*		 * Some routers will return error messages without		 * filling in their addresses.  We fill in the address		 * for them.		 */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -