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

📄 traceroute.c

📁 traceroute
💻 C
字号:

#include "traceroute.h"

extern int  errno;


/*------------------------------------------------------------------------

 * main

 *------------------------------------------------------------------------

 */
int main(int argc, char *argv[])
{
	register int op, code, n;
	register char *cp;
	register u_char *outp;
	register u_int32_t *ap;
	register struct sockaddr_in *from = (struct sockaddr_in *)&wherefrom;
	register struct sockaddr_in *to = (struct sockaddr_in *)&whereto;
	register struct hostinfo *hi;
	int on = 1;
	register struct protoent *pe;
	register int ttl, probe, i;
	register int seq = 0;
	int tos = 0, settos = 0;
	register int lsrr = 0;
	register u_short off = 0;

	
	if (argv[0] == NULL)
			prog = "traceroute";
	else if ((cp = strrchr(argv[0], '/')) != NULL)
			prog = cp + 1;
	else
			prog = argv[0];


	
	while ((op = getopt(argc, argv, "nf:g:m:p:q:s:t:w:z:")) != EOF)
		switch (op) 
			{

				case 'f':					/*[-f first_ttl]*/
					first_ttl = str2val(optarg, "first ttl", 1, 255);
					break;

				case 'g':					/*[-g gateway]---->optarg=gateway*/
					if (lsrr >= NGATEWAYS) 
							errexit("%s: No more than %d gateways\n", prog, NGATEWAYS);
					
					getaddr(gwlist + lsrr, optarg);
					++lsrr;
					break;

				case 'm':					/*[-m max_ttl]*/
					max_ttl = str2val(optarg, "max ttl", 1, 255);
					break;

				case 'n':					/*显示的地址是用点分十进制表示还是用域名*/
					++nflag;
					break;

				case 'p':					/*[ -p port]UDP端口设置(缺省为33434)*/
					port = (u_short)str2val(optarg, "port",
						1, (1 << 16) - 1);
					break;

				case 'q':					/*[-q nqueries]设置TTL测试数目(缺省为3)*/
					nprobes = str2val(optarg, "nprobes", 1, -1);
					break;

				case 's':					/*[-s src_addr]*/
					/*
					 * set the ip source address of the outbound
					 * probe (e.g., on a multi-homed host).
					 */
					source = optarg;
					break;

				case 't':					/*[-t tos]设置测包的服务类型*/
					tos = str2val(optarg, "tos", 0, 255);
					++settos;
					break;

				case 'w':					/*[-w waittime] */
					waittime = str2val(optarg, "wait time",
						2, 24 * 60 * 60);
					break;

				default:
					errexit("Usage: %s [-n] [-g gateway] [-f first_ttl] [-m max_ttl] [ -p port] [-q nqueries]\n"
							"\t[-s src_addr] [-t tos] [-w waittime] host [packetlen]\n", prog);
			}

	if (first_ttl > max_ttl) 
			errexit("%s: first ttl (%d) may not be greater than max ttl (%d)\n", prog, first_ttl, max_ttl);
		

	if (lsrr > 0)
			/*ip选项的长度,加1是由于选项中除了ip地址还有其它的标志*/
			optlen = (lsrr + 1) * sizeof(gwlist[0]);	
	
	minpacket = sizeof(*outip) + sizeof(*outdata) + optlen;
	
	packlen = minpacket + sizeof(*outudp);
	


	switch (argc - optind) 
		{

			case 2:
				packlen = str2val(argv[optind + 1],
					"packet length", minpacket, maxpacket);
				/* Fall through */

			case 1:
				hostname = argv[optind];
				hi = gethostinfo(hostname);
				setsin(to, hi->addrs[0]);
				if (hi->n > 1)
					printf("%s: Warning: %s has multiple addresses; using %s\n",
						prog, hostname, inet_ntoa(to->sin_addr));
				hostname = hi->name;
				hi->name = NULL;
				freehostinfo(hi);
				break;

			default:
				errexit("Usage: %s [-n] [-g gateway] [-f first_ttl] [-m max_ttl] [ -p port] [-q nqueries]\n"
						"\t[-s src_addr] [-t tos] [-w waittime] host [packetlen]\n", prog);
		}

	setlinebuf (stdout);

	outip = (struct ip *)malloc((unsigned)packlen);
	if (outip == NULL) 
		{
			errexit( "%s: malloc: %s\n", prog, strerror(errno));		
		}

	memset((char *)outip, 0, packlen);

	outip->ip_v = IPVERSION;

	if (settos)
		outip->ip_tos = tos;

	outip->ip_len = packlen;
	outip->ip_off = off;//=0;


	outp = (u_char *)(outip + 1);		/*相当于outp指向结构outip[1]*/

	if (lsrr > 0) 
		{
			register u_char *optlist;

			optlist = outp;
			outp += optlen;

			/* final hop,把目的地址存入gwlist数组中 */
			gwlist[lsrr] = to->sin_addr.s_addr;

			outip->ip_dst.s_addr = gwlist[0];

			/* force 4 byte alignment */
			optlist[0] = IPOPT_NOP;
			/* loose source route option */
			optlist[1] = IPOPT_LSRR;
			i = lsrr * sizeof(gwlist[0]);		/*gwlist中存储的所有gateway总字节长*/
			optlist[2] = i + 3;					/* ????pad to an even boundary */
			/* Pointer to LSRR addresses */
			optlist[3] = IPOPT_MINOFF;

			memcpy(optlist + 4, gwlist + 1, i);	/*gwlist中存储gateway*/
		}

	
	outip->ip_dst = to->sin_addr;

	/*因为outp - (u_char *)outip是以char为单位的个数,即多少个字节,比如20>>2=5*/
	outip->ip_hl = (outp - (u_char *)outip) >> 2;

	ident = (getpid() & 0xffff) | 0x8000;


	outip->ip_p = IPPROTO_UDP;

	outudp = (struct udphdr *)outp;
	
	outudp->len = htons((u_short)(packlen - (sizeof(*outip) + optlen)));	/*=sizeof(*outudp)+sizeof(*outdata)*/

	outdata = (struct outdata *)(outudp + 1);


	cp = "icmp";
	if ((pe = getprotobyname(cp)) == NULL) 		
			errexit("%s: unknown protocol %s\n", prog, cp);		
		

	/*建立接收icmp数据报的socket*/
	if ((s = socket(AF_INET, SOCK_RAW, pe->p_proto)) < 0) 		
			errexit("%s: icmp socket: %s\n", prog, strerror(errno));
		

	/*建立发送udp数据报的socket*/
	if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_UDP)) <0)		
			errexit("%s: raw socket: %s\n", prog, strerror(errno));
		

	/*设置IP_HDRINCL以自己填充IPv4首部,亲自对IP头进行处理*/
	if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,  sizeof(on)) < 0) 		
			errexit("traceroute: IP_HDRINCL");

	if (source) 
		{
			hi = gethostinfo(source);
			source = hi->name;
			hi->name = NULL;

			setsin(from, hi->addrs[0]);
			if (hi->n > 1)
				printf("%s: Warning: %s has multiple addresses; using %s\n",
						prog, source, inet_ntoa(from->sin_addr));

			freehostinfo(hi);			
		}

	outip->ip_src = from->sin_addr;

	
	if (bind(sndsock, (struct sockaddr *)from, sizeof(*from)) < 0) 
			errexit("%s: bind: %s\n", prog, strerror(errno));



	printf("%s to %s (%s)", prog, hostname, inet_ntoa(to->sin_addr));
	if (source)
		printf(" from %s", source);
	printf(", %d hops max, %d byte packets\n", max_ttl, packlen);

	/*更新缓冲区*/
	(void)fflush(stderr);

	for (ttl = first_ttl; ttl <= max_ttl; ++ttl)
		{
			u_int32_t lastaddr = 0;
			int gotlastaddr = 0;
			int got_there = 0;
			int unreachable = 0;
			int sentfirst = 0;

			printf("%2d ", ttl);
			for (probe = 0; probe < nprobes; ++probe) 
				{
					register int cc;
					struct timeval t1, t2;
					struct timezone tz;
					register struct ip *ip;

					(void)gettimeofday(&t1, &tz);

					send_probe(++seq, ttl, &t1);

					++sentfirst;

					while ((cc = wait_for_reply(s, from, &t1)) != 0) 
						{
							(void)gettimeofday(&t2, &tz);

							i = packet_ok(packet, cc, from, seq);

							/* Skip short packet */
							if (i == 0)
								continue;

							if (!gotlastaddr ||	from->sin_addr.s_addr != lastaddr) 
								{
									print(packet, cc, from);
									lastaddr = from->sin_addr.s_addr;
									++gotlastaddr;
								}

							printf("  %.3f ms", deltaT(&t1, &t2));

							/* time exceeded in transit */
							if (i == -1)
								break;
							code = i - 1;
							switch (code) 
								{

									case ICMP_UNREACH_PORT:
#ifndef ARCHAIC
										ip = (struct ip *)packet;
										if (ip->ip_ttl <= 1)
											printf(" !");
#endif
										++got_there;
										break;

									case ICMP_UNREACH_NET:
										++unreachable;
										printf(" !N");
										break;

									case ICMP_UNREACH_HOST:
										++unreachable;
										printf(" !H");
										break;

									case ICMP_UNREACH_PROTOCOL:
										++got_there;
										printf(" !P");
										break;

									case ICMP_UNREACH_NEEDFRAG:
										++unreachable;
										//printf(" !F-%d", pmtu);
										break;

									case ICMP_UNREACH_SRCFAIL:
										++unreachable;
										printf(" !S");
										break;

									case ICMP_UNREACH_FILTER_PROHIB:
										++unreachable;
										printf(" !X");
										break;

									case ICMP_UNREACH_HOST_PRECEDENCE:
										++unreachable;
										printf(" !V");
										break;

									case ICMP_UNREACH_PRECEDENCE_CUTOFF:
										++unreachable;
										printf(" !C");
										break;

									default:
										++unreachable;
										printf(" !<%d>", code);
										break;
								}
							break;
						}/*end while*/

					if (cc == 0)
						printf(" *");
					
					/*更新缓冲区*/
					(void)fflush(stdout);
				}/*end for (probe = 0; probe < nprobes; ++probe)*/

			putchar('\n');

			if (got_there ||(unreachable > 0 && unreachable >= nprobes - 1))
				break;

		}/*end for (ttl = first_ttl; ttl <= max_ttl; ++ttl)*/

	exit(0);

}

⌨️ 快捷键说明

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