📄 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 + -