📄 mtrace.c
字号:
/* * mtrace.c * * This tool traces the branch of a multicast tree from a source to a * receiver for a particular multicast group and gives statistics * about packet rate and loss for each hop along the path. It can * usually be invoked just as * * mtrace source * * to trace the route from that source to the local host for a default * group when only the route is desired and not group-specific packet * counts. See the usage line for more complex forms. * * * Released 4 Apr 1995. This program was adapted by Steve Casner * (USC/ISI) from a prototype written by Ajit Thyagarajan (UDel and * Xerox PARC). It attempts to parallel in command syntax and output * format the unicast traceroute program written by Van Jacobson (LBL) * for the parts where that makes sense. * * Copyright (c) 1995 by the University of Southern California * All rights reserved. * * Permission to use, copy, modify, and distribute this software and its * documentation in source and binary forms for any purposes and without * fee is hereby granted, provided that the above copyright notice * appear in all copies and that both the copyright notice and this * permission notice appear in supporting documentation, and that any * documentation, advertising materials, and other materials related to * such distribution and use acknowledge that the software was developed * by the University of Southern California, Information Sciences * Institute. The name of the University may not be used to endorse or * promote products derived from this software without specific prior * written permission. * * THE UNIVERSITY OF SOUTHERN CALIFORNIA makes no representations about * the suitability of this software for any purpose. THIS SOFTWARE IS * PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * Other copyrights might apply to parts of this software and are so * noted when applicable. * * Parts of this software are derived from mrouted, which has the * following license: * * The mrouted program is covered by the following license. Use of the * mrouted program represents acceptance of these terms and conditions. * * 1. STANFORD grants to LICENSEE a nonexclusive and nontransferable * license to use, copy and modify the computer software ``mrouted'' * (hereinafter called the ``Program''), upon the terms and conditions * hereinafter set out and until Licensee discontinues use of the Licensed * Program. * * 2. LICENSEE acknowledges that the Program is a research tool still in * the development state, that it is being supplied ``as is,'' without any * accompanying services from STANFORD, and that this license is entered * into in order to encourage scientific collaboration aimed at further * development and application of the Program. * * 3. LICENSEE may copy the Program and may sublicense others to use * object code copies of the Program or any derivative version of the * Program. All copies must contain all copyright and other proprietary * notices found in the Program as provided by STANFORD. Title to * copyright to the Program remains with STANFORD. * * 4. LICENSEE may create derivative versions of the Program. LICENSEE * hereby grants STANFORD a royalty-free license to use, copy, modify, * distribute and sublicense any such derivative works. At the time * LICENSEE provides a copy of a derivative version of the Program to a * third party, LICENSEE shall provide STANFORD with one copy of the * source code of the derivative version at no charge to STANFORD. * * 5. STANFORD MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR * IMPLIED. By way of example, but not limitation, STANFORD MAKES NO * REPRESENTATION OR WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY * PARTICULAR PURPOSE OR THAT THE USE OF THE LICENSED PROGRAM WILL NOT * INFRINGE ANY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. STANFORD * shall not be held liable for any liability nor for any direct, indirect * or consequential damages with respect to any claim by LICENSEE or any * third party on account of or arising from this Agreement or use of the * Program. * * 6. This agreement shall be construed, interpreted and applied in * accordance with the State of California and any legal action arising * out of this Agreement or use of the Program shall be filed in a court * in the State of California. * * 7. Nothing in this Agreement shall be construed as conferring rights to * use in advertising, publicity or otherwise any trademark or the name * of ``Stanford''. * * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of * Leland Stanford Junior University. * * * The mtrace program has been modified and improved by Xerox * Corporation. Xerox grants to LICENSEE a non-exclusive and * non-transferable license to use, copy, and modify the Xerox modified * and improved mrouted software on the same terms and conditions which * govern the license Stanford and ISI grant with respect to the mtrace * program. These terms and conditions are incorporated in this grant * by reference and shall be deemed to have been accepted by LICENSEE * to cover its relationship with Xerox Corporation with respect to any * use of the Xerox improved program. * * The mtrace program is COPYRIGHT 1998 by Xerox Corporation. * */#ifndef lintstatic char rcsid[] = "@(#) mtrace.c,v 5.2 1998/12/04 04:48:19 fenner Exp";#endif#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <memory.h>#include <string.h>#include <ctype.h>#include <errno.h>#include <syslog.h>#include <netdb.h>#include <sys/param.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/time.h>#include <net/if.h>#include <netinet/in.h>#include <netinet/in_systm.h>#include <netinet/ip.h>#include <netinet/igmp.h>#include <sys/ioctl.h>#ifdef SYSV#include <sys/sockio.h>#endif#include <arpa/inet.h>#ifdef __STDC__#include <stdarg.h>#else#include <varargs.h>#endif#ifdef SUNOS5#include <sys/systeminfo.h>#endiftypedef unsigned int u_int32; /* XXX */#include "mtrace.h"#define DEFAULT_TIMEOUT 3 /* How long to wait before retrying requests */#define DEFAULT_RETRIES 3 /* How many times to try */#define DEFAULT_EXTRAHOPS 3 /* How many hops past a non-responding rtr */#define MAXHOPS 60 /* Don't need more hops than this */#define UNICAST_TTL 255 /* TTL for unicast response */#define MULTICAST_TTL1 127 /* Default TTL for multicast query/response */#define MULTICAST_TTL_INC 32 /* TTL increment for increase after timeout */#define MULTICAST_TTL_MAX 192 /* Maximum TTL allowed (protect low-BW links */#define TRUE 1#define FALSE 0#define DVMRP_ASK_NEIGHBORS2 5 /* DVMRP msg requesting neighbors */#define DVMRP_NEIGHBORS2 6 /* reply to above */#define DVMRP_NF_DOWN 0x10 /* kernel state of interface */#define DVMRP_NF_DISABLED 0x20 /* administratively disabled */#define MAX_IP_PACKET_LEN 576#define MIN_IP_HEADER_LEN 20#define MAX_IP_HEADER_LEN 60#define MAX_DVMRP_DATA_LEN \ ( MAX_IP_PACKET_LEN - MAX_IP_HEADER_LEN - IGMP_MINLEN )struct resp_buf { u_long qtime; /* Time query was issued */ u_long rtime; /* Time response was received */ int len; /* Number of reports or length of data */ struct igmp igmp; /* IGMP header */ union { struct { struct tr_query q; /* Query/response header */ struct tr_resp r[MAXHOPS]; /* Per-hop reports */ } t; char d[MAX_DVMRP_DATA_LEN]; /* Neighbor data */ } u;} base, incr[2];#define qhdr u.t.q#define resps u.t.r#define ndata u.dchar *names[MAXHOPS];/* * In mrouted 3.3 and 3.4 (and in some Cisco IOS releases), * cache entries can get deleted even if there is traffic * flowing, which will reset the per-source/group counters. */#define BUG_RESET 0x01/* * Also in mrouted 3.3 and 3.4, there's a bug in neighbor * version processing which can cause them to believe that * the neighbor is constantly resetting. This causes them * to constantly delete all their state. */#define BUG_RESET2X 0x02/* * Pre-3.7 mrouted's forget to byte-swap their reports. */#define BUG_SWAP 0x04/* * Pre-3.9 mrouted's forgot a parenthesis in the htonl() * on the time calculation so supply bogus times. */#define BUG_BOGUSTIME 0x08#define BUG_NOPRINT (BUG_RESET | BUG_RESET2X)int bugs[MAXHOPS]; /* List of bugs noticed at each hop */struct mtrace { struct mtrace *next; struct resp_buf base, incr[2]; struct resp_buf *new, *prev; int nresp; struct timeval last; int bugs[MAXHOPS]; char *names[MAXHOPS]; int lastqid;};int timeout = DEFAULT_TIMEOUT;int nqueries = DEFAULT_RETRIES;int numeric = FALSE;int debug = 0;int passive = FALSE;int multicast = FALSE;int unicast = FALSE;int statint = 10;int verbose = FALSE;int tunstats = FALSE;int weak = FALSE;int extrahops = DEFAULT_EXTRAHOPS;int printstats = TRUE;int sendopts = TRUE;int lossthresh = 0;int fflag = FALSE;int staticqid = 0;u_int32 defgrp; /* Default group if not specified */u_int32 query_cast; /* All routers multicast addr */u_int32 resp_cast; /* Mtrace response multicast addr */u_int32 lcl_addr = 0; /* This host address, in NET order */u_int32 dst_netmask = 0; /* netmask to go with qdst *//* * Query/response parameters, all initialized to zero and set later * to default values or from options. */u_int32 qsrc = 0; /* Source address in the query */u_int32 qgrp = 0; /* Group address in the query */u_int32 qdst = 0; /* Destination (receiver) address in query */u_char qno = 0; /* Max number of hops to query */u_int32 raddr = 0; /* Address where response should be sent */int qttl = 0; /* TTL for the query packet */u_char rttl = 0; /* TTL for the response packet */u_int32 gwy = 0; /* User-supplied last-hop router address */u_int32 tdst = 0; /* Address where trace is sent (last-hop) */char s1[19]; /* buffers to hold the string representations */char s2[19]; /* of IP addresses, to be passed to inet_fmt() */char s3[19]; /* or inet_fmts(). */#if !(defined(BSD) && (BSD >= 199103))extern int errno;extern int sys_nerr;extern char * sys_errlist[];#endif#define RECV_BUF_SIZE 8192char *send_buf, *recv_buf;int igmp_socket;u_int32 allrtrs_group;char router_alert[4]; /* Router Alert IP Option */#ifndef IPOPT_RA#define IPOPT_RA 148#endif#ifdef SUNOS5char eol[4]; /* EOL IP Option */int ip_addlen = 0; /* Workaround for Option bug #2 */#endif/* * max macro, with weird case to avoid conflicts */#define MaX(a,b) ((a) > (b) ? (a) : (b))#ifndef __P#ifdef __STDC__#define __P(x) x#else#define __P(x) ()#endif#endiftypedef int (*callback_t) __P((int, u_char *, int, struct igmp *, int, struct sockaddr *, int *, struct timeval *));void init_igmp __P((void));void send_igmp __P((u_int32 src, u_int32 dst, int type, int code, u_int32 group, int datalen));int inet_cksum __P((u_short *addr, u_int len));void k_set_rcvbuf __P((int bufsize));void k_hdr_include __P((int bool));void k_set_ttl __P((int t));void k_set_loop __P((int l));void k_set_if __P((u_int32 ifa));void k_join __P((u_int32 grp, u_int32 ifa));void k_leave __P((u_int32 grp, u_int32 ifa));char * inet_fmt __P((u_int32 addr, char *s));char * inet_fmts __P((u_int32 addr, u_int32 mask, char *s));char * inet_name __P((u_int32 addr));u_int32 host_addr __P((char *name));/* u_int is promoted u_char */char * proto_type __P((u_int type));char * flag_type __P((u_int type));u_int32 get_netmask __P((int s, u_int32 *dst));int get_ttl __P((struct resp_buf *buf));int t_diff __P((u_long a, u_long b));u_long byteswap __P((u_long v));int mtrace_callback __P((int, u_char *, int, struct igmp *, int, struct sockaddr *, int *, struct timeval *));int send_recv __P((u_int32 dst, int type, int code, int tries, struct resp_buf *save, callback_t callback));void passive_mode __P((void));char * print_host __P((u_int32 addr));char * print_host2 __P((u_int32 addr1, u_int32 addr2));void print_trace __P((int idx, struct resp_buf *buf, char **names));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 *res));void fixup_stats __P((struct resp_buf *base, struct resp_buf *prev, struct resp_buf *new, int *bugs));int check_thresh __P((int thresh, struct resp_buf *base, struct resp_buf *prev, struct resp_buf *new));int print_stats __P((struct resp_buf *base, struct resp_buf *prev, struct resp_buf *new, int *bugs, char **names));int path_changed __P((struct resp_buf *base, struct resp_buf *new));void check_vif_state __P((void));int main __P((int argc, char *argv[]));void log __P((int, int, char *, ...));/* * Open and initialize the igmp socket, and fill in the non-changing * IP header fields in the output packet buffer. */voidinit_igmp(){ struct ip *ip; recv_buf = (char *)malloc(RECV_BUF_SIZE); if (recv_buf == 0) log(LOG_ERR, 0, "Out of memory allocating recv_buf!"); send_buf = (char *)malloc(RECV_BUF_SIZE); if (send_buf == 0) log(LOG_ERR, 0, "Out of memory allocating send_buf!"); if ((igmp_socket = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP)) < 0) log(LOG_ERR, errno, "IGMP socket"); k_hdr_include(TRUE); /* include IP header when sending */ k_set_rcvbuf(48*1024); /* lots of input buffering */ k_set_ttl(1); /* restrict multicasts to one hop */ k_set_loop(FALSE); /* disable multicast loopback */ ip = (struct ip *)send_buf; ip->ip_hl = sizeof(struct ip) >> 2; ip->ip_v = IPVERSION; ip->ip_tos = 0; ip->ip_off = 0; ip->ip_p = IPPROTO_IGMP; ip->ip_ttl = MAXTTL; /* applies to unicasts only */#ifndef INADDR_ALLRTRS_GROUP#define INADDR_ALLRTRS_GROUP 0xe0000002 /* 224.0.0.2 */#endif allrtrs_group = htonl(INADDR_ALLRTRS_GROUP); router_alert[0] = IPOPT_RA; /* Router Alert */ router_alert[1] = 4; /* 4 bytes */ router_alert[2] = 0; router_alert[3] = 0;}#ifdef SUNOS5voidcheckforsolarisbug(){ u_int32 localhost = htonl(0x7f000001); eol[0] = IPOPT_EOL; eol[1] = IPOPT_EOL; eol[2] = IPOPT_EOL; eol[3] = IPOPT_EOL; setsockopt(igmp_socket, IPPROTO_IP, IP_OPTIONS, eol, sizeof(eol)); /* * Check if the kernel adds the options length to the packet * length. Send myself an IGMP packet of type 0 (illegal), * with 4 IPOPT_EOL options, my PID (for collision detection) * and 4 bytes of zero (so that the checksum works whether * the 4 bytes of zero get truncated or not). */ bzero(send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN, 8); *(int *)(send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN) = getpid(); send_igmp(localhost, localhost, 0, 0, 0, 8); while (1) { int recvlen, dummy = 0; recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE, 0, NULL, &dummy); /* 8 == 4 bytes of options and 4 bytes of PID */ if (recvlen >= MIN_IP_HEADER_LEN + IGMP_MINLEN + 8) { struct ip *ip = (struct ip *)recv_buf; struct igmp *igmp; int *p; if (ip->ip_hl != 6 || ip->ip_p != IPPROTO_IGMP || ip->ip_src.s_addr != localhost || ip->ip_dst.s_addr != localhost) continue; igmp = (struct igmp *)(recv_buf + (ip->ip_hl << 2)); if (igmp->igmp_group.s_addr != 0) continue; if (igmp->igmp_type != 0 || igmp->igmp_code != 0) continue; p = (int *)((char *)igmp + IGMP_MINLEN); if (*p != getpid()) continue;#ifdef RAW_INPUT_IS_RAW ip->ip_len = ntohs(ip->ip_len);#endif if (ip->ip_len == IGMP_MINLEN + 4) ip_addlen = 4; else if (ip->ip_len == IGMP_MINLEN + 8) ip_addlen = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -