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

📄 traceroute.c

📁 linux下traceroute的实现
💻 C
📖 第 1 页 / 共 3 页
字号:
			    set_port, &src_port, 0, CLIF_EXTRA },	{ "U", "udp", 0, "Use UDP to particular port for tracerouting "			    "(instead of increasing the port per each probe), "			    "default port is " _TEXT(DEF_UDP_PORT),			    set_module, "udp", 0, CLIF_EXTRA },	{ 0, "UL", 0, "Use UDPLITE for tracerouting (default dest port is "			    _TEXT(DEF_UDP_PORT) ")",			    set_module, "udplite", 0, CLIF_ONEDASH|CLIF_EXTRA },	{ "P", "protocol", "prot", "Use raw packet of protocol %s "			    "for tracerouting", 			    set_raw, 0, 0, CLIF_EXTRA },	{ 0, "mtu", 0, "Discover MTU along the path being traced. "			    "Implies `-F -N 1'",			    CLIF_set_flag, &mtudisc, 0, CLIF_EXTRA },	{ 0, "back", 0, "Guess the number of hops in the backward path "			    "and print if it differs",			    CLIF_set_flag, &backward, 0, CLIF_EXTRA },	CLIF_VERSION_OPTION (version_string),	CLIF_HELP_OPTION,	CLIF_END_OPTION};static CLIF_argument arg_list[] = {        { "host", "The host to traceroute to",				set_host, 0, CLIF_STRICT },	{ "packetlen", "The full packet length (default is the length of "			"an IP header plus " _TEXT(DEF_DATA_LEN) "). Can be "			"ignored or increased to a minimal allowed value",				CLIF_arg_int, &packet_len, 0 },	CLIF_END_ARGUMENT};static void do_it (void);int main (int argc, char *argv[]) {	setlocale (LC_ALL, "");   // LC_ALL for all of the locale.	setlocale (LC_NUMERIC, "C");	/*  avoid commas in msec printed  */	check_progname (argv[0]);            //程序运行的全路径名	if (CLIF_parse (argc, argv, option_list, arg_list,				CLIF_MAY_JOIN_ARG | CLIF_HELP_EMPTY) < 0	)  exit (2);	ops = tr_get_module (module);	if (!ops)  ex_error ("Unknown traceroute module %s", module);	if (!ops->user && geteuid () != 0)	    ex_error ("The specified type of tracerouting "			"is allowed for superuser only");	if (first_hop > max_hops)		ex_error ("first hop out of range");	if (max_hops > MAX_HOPS)		ex_error ("max hops cannot be more than " _TEXT(MAX_HOPS));	if (!probes_per_hop || probes_per_hop > MAX_PROBES)		ex_error ("no more than " _TEXT(MAX_PROBES) " probes per hop");	if (wait_secs < 0)		ex_error ("bad wait seconds `%g' specified", wait_secs);	if (packet_len > MAX_PACKET_LEN)		ex_error ("too big packetlen %d specified", packet_len);	if (src_addr.sa.sa_family && src_addr.sa.sa_family != af)		ex_error ("IP version mismatch in addresses specified");	if (send_secs < 0)		ex_error ("bad sendtime `%g' specified", send_secs);	if (send_secs >= 10)	/*  it is milliseconds   */		send_secs /= 1000;	if (af == AF_INET6 && (tos || flow_label))		dst_addr.sin6.sin6_flowinfo =			((tos & 0xff) << 20) | (flow_label & 0x000fffff);	if (src_port) {	    src_addr.sin.sin_port = htons ((u_int16_t) src_port);	    src_addr.sa.sa_family = af;	}	if (src_port || ops->one_per_time)		sim_probes = 1;	/*  make sure we don't std{in,out,err} to open sockets  */	make_fd_used (0);	make_fd_used (1);	make_fd_used (2);	init_ip_options ();	header_len = (af == AF_INET ? sizeof (struct iphdr)				    : sizeof (struct ip6_hdr)) +			rtbuf_len + ops->header_len;	if (mtudisc) {	    dontfrag = 1;	    sim_probes = 1;	    packet_len = MAX_PACKET_LEN;	}	if (packet_len < 0) {	    if (DEF_DATA_LEN >= ops->header_len)		    data_len = DEF_DATA_LEN - ops->header_len;	} else {	    if (packet_len >= header_len)		    data_len = packet_len - header_len;	}	num_probes = max_hops * probes_per_hop;	probes = calloc (num_probes, sizeof (*probes));	if (!probes)  error ("calloc");	if (ops->options && opts_idx > 1) {	    opts[0] = strdup (module);	    /*  aka argv[0] ...  */	    if (CLIF_parse (opts_idx, opts, ops->options, 0, CLIF_KEYWORD) < 0)		    exit (2);	}	if (ops->init (&dst_addr, dst_port_seq, &data_len) < 0)		ex_error ("trace method's init failed");	do_it ();	return 0;}/*	PRINT  STUFF	    */static void print_header (void) {                 //打印提示头	/*  Note, without ending new-line!  */	printf ("traceroute to %s (%s), %u hops max, %u byte packets",				dst_name, addr2str (&dst_addr), max_hops,				header_len + data_len);	fflush (stdout);}static void print_addr (sockaddr_any *res) {	const char *str;	if (!res->sa.sa_family)		return;	str = addr2str (res);	if (noresolve)		printf (" %s", str);	else {	    char buf[1024];	    buf[0] = '\0';	    getnameinfo (&res->sa, sizeof (*res), buf, sizeof (buf),							    0, 0, NI_IDN);	    /*  foo on errors.  */	    printf (" %s (%s)", buf, str);	}	if (as_lookups)		printf (" [%s]", get_as_path (str));}static void print_probe (probe *pb) {	unsigned int idx = (pb - probes);	unsigned int ttl = idx / probes_per_hop + 1;	unsigned int np = idx % probes_per_hop;	if (np == 0)		printf ("\n%2u ", ttl);	if (!pb->res.sa.sa_family)		printf (" *");	else {	    int prn = !np;	/*  print if the first...  */	    if (np) {	    /*  ...and if differs with previous   */		probe *p;		/*  skip expired   */		for (p = pb - 1; np && !p->res.sa.sa_family; p--, np--) ;		if (!np ||		    !equal_addr (&p->res, &pb->res) ||		    (extension && p->ext != pb->ext &&			!(p->ext && pb->ext && !strcmp (p->ext, pb->ext))) ||		    (backward && p->recv_ttl != pb->recv_ttl)		)  prn = 1;	    }	    if (prn) {		print_addr (&pb->res);		if (pb->ext)  printf (" <%s>", pb->ext);		if (backward && pb->recv_ttl) {		    int hops = ttl2hops (pb->recv_ttl);		    if (hops != ttl)  printf (" '-%d'", hops);		}	    }	}	if (pb->recv_time) {	    double diff = pb->recv_time - pb->send_time;	    printf ("  %.3f ms", diff * 1000);	}	if (pb->err_str[0])		printf (" %s", pb->err_str);	fflush (stdout);	return;}static void print_end (void) {	printf ("\n");}/*	Check  expiration  stuff	*/static void check_expired (probe *pb) {	int idx = (pb - probes);	probe *p, *endp = probes + num_probes;	probe *fp = NULL, *pfp = NULL;	if (!pb->done)	    /*  an ops method still not release it  */	    return;	/*  check all the previous in the same hop   */	for (p = &probes[idx - (idx % probes_per_hop)]; p < pb; p++) {	    if (!p->done ||     /*  too early to decide something  */		!p->final       /*  already ttl-exceeded in the same hop  */	    )  return;	    pfp = p;	/*  some of the previous probes is final   */	}	/*  check forward all the sent probes   */	for (p = pb + 1; p < endp && p->send_time; p++) {	    if (p->done) {	/*  some next probe already done...  */		if (!p->final)	/*  ...was ttl-exceeded. OK, we are expired.  */		    return;		else {		    fp = p;		    break;		}	    }	}	if (!fp)    /*  no any final probe found. Assume expired.   */	    return;	/*  Well. There is a situation "*(this) * * * * ... * * final"	   We cannot guarantee that "final" is in its right place.	   We've sent "sim_probes" simultaneously, and the final hop	   can drop some of them and answer only for latest ones.	   If we can detect/assume that it so, then just put "final"	   to the (pseudo-expired) "this" place.	*/	if (pfp ||	    (idx % probes_per_hop) + (fp - pb) < probes_per_hop	) {	    /*  Either some previous (pfp) or some next probe		in this hop is final. It means that the whole hop is final.		Do the replace (it also causes further "final"s to be shifted		here too).	    */	    goto  replace_by_final;	}	/*  If the final probe is an icmp_unreachable report	    (either in a case of some error, like "!H", or just port_unreach),	    it could follow the "time-exceed" report from the *same* hop.	*/	for (p = pb - 1; p >= probes; p--) {	    if (equal_addr (&p->res, &fp->res)) {		/*  ...Yes. Put "final" to the "this" place.  */		goto  replace_by_final;	    }	}	if (fp->recv_ttl) {	    /*  Consider the ttl value of the report packet and guess where		the "final" should be. If it seems that it should be		in the same hop as "this", then do replace.	    */	    int back_hops, ttl;	    /*  We assume that the reporting one has an initial ttl value		of either 64, or 128, or 255. It is most widely used		in the modern routers and computers.		The idea comes from tracepath(1) routine.	    */	    back_hops = ttl2hops (fp->recv_ttl);	    /*  It is possible that the back path differs from the forward		and therefore has different number of hops. To minimize		such an influence, get the nearest previous time-exceeded		probe and compare with it.	    */	    for (p = pb - 1; p >= probes; p--) {		if (p->done && !p->final && p->recv_ttl) {		    int hops = ttl2hops (p->recv_ttl);		    if (hops < back_hops) {			ttl = (p - probes) / probes_per_hop + 1;			back_hops = (back_hops - hops) + ttl;			break;		    }		}	    }	    ttl = idx / probes_per_hop + 1;	    if (back_hops == ttl)		/*  Yes! It seems that "final" should be at "this" place   */		goto  replace_by_final;	    else if (back_hops < ttl)		/*  Hmmm... Assume better to replace here too...  */		goto  replace_by_final;	}	/*  No idea what to do. Assume expired.  */	return;replace_by_final:	*pb = *fp;	memset (fp, 0, sizeof (*fp));	/*  block extra re-send  */	fp->send_time = 1.;	return;}probe *probe_by_seq (int seq) {	int n;	if (seq <= 0)  return NULL;	for (n = 0; n < num_probes; n++) {	    if (probes[n].seq == seq)		    return &probes[n];	}	return NULL;}probe *probe_by_sk (int sk) {	int n;	if (sk <= 0)  return NULL;	for (n = 0; n < num_probes; n++) {	    if (probes[n].sk == sk)		    return &probes[n];	}	return NULL;}static void poll_callback (int fd, int revents) {	ops->recv_probe (fd, revents);}static void do_it (void) {	int start = (first_hop - 1) * probes_per_hop;	int end = num_probes;	double last_send = 0;	print_header ();	while (start < end) {	    int n, num = 0;	    double max_time = 0;	    double now_time = get_time ();	    for (n = start; n < end; n++) {		probe *pb = &probes[n];		if (!pb->done &&		    pb->send_time &&		    now_time - pb->send_time >= wait_secs		) {		    ops->expire_probe (pb);		    check_expired (pb);		}		if (pb->done) {		    if (n == start) {	/*  can print it now   */			print_probe (pb);			start++;		    }		    if (pb->final)			end = (n / probes_per_hop + 1) * probes_per_hop;		    continue;		}		if (!pb->send_time) {		    int ttl;		    if (send_secs && (now_time - last_send) < send_secs) {			max_time = (last_send + send_secs) - wait_secs;			break;		    }		    ttl = n / probes_per_hop + 1;		    ops->send_probe (pb, ttl);		    if (!pb->send_time) {			if (max_time)  break;	/*  have chances later   */			else  error ("send probe");		    }		    last_send = pb->send_time;		}		if (pb->send_time > max_time)			max_time = pb->send_time;		num++;		if (num >= sim_probes)  break;	    }	    if (max_time) {		double timeout = (max_time + wait_secs) - now_time;		if (timeout < 0)  timeout = 0;		do_poll (timeout, poll_callback);	    }	}	print_end ();	return;}void tune_socket (int sk) {	int i = 0;	if (debug) {	    i = 1;	    if (setsockopt (sk, SOL_SOCKET, SO_DEBUG, &i, sizeof (i)) < 0)		    error ("setsockopt SO_DEBUG");	}	if (rtbuf && rtbuf_len) {	    if (af == AF_INET) {		if (setsockopt (sk, IPPROTO_IP, IP_OPTIONS,						rtbuf, rtbuf_len) < 0		)  error ("setsockopt IP_OPTIONS");	    }	    else if (af == AF_INET6) {		if (setsockopt (sk, IPPROTO_IPV6, IPV6_RTHDR,

⌨️ 快捷键说明

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