📄 traceroute6.c
字号:
optarg); exit(1); }#else /* old advanced API */ if (cmsg == NULL) cmsg = inet6_rthdr_init(rtbuf, IPV6_RTHDR_TYPE_0); inet6_rthdr_add(cmsg, (struct in6_addr *)hp->h_addr, IPV6_RTHDR_LOOSE);#endif freehostent(hp); break; case 'I': useicmp++; ident = htons(getpid() & 0xffff); /* same as ping6 */ break; case 'l': lflag++; break; case 'm': ep = NULL; max_hops = strtoul(optarg, &ep, 0); if (!*argv || *ep) { fprintf(stderr, "traceroute6: invalid max hoplimit.\n"); exit(1); } if (max_hops < first_hop) { fprintf(stderr, "traceroute6: max hoplimit must be >= %d.\n", first_hop); exit(1); } break; case 'n': nflag++; break; case 'p': ep = NULL; lport = strtoul(optarg, &ep, 0); if (!*argv || *ep) { fprintf(stderr, "traceroute6: port.\n"); exit(1); } if (lport == 0 || lport != (lport & 0xffff)) { fprintf(stderr, "traceroute6: port out of range.\n"); exit(1); } port = lport & 0xffff; break; case 'q': ep = NULL; nprobes = strtoul(optarg, &ep, 0); if (!*argv || *ep) { fprintf(stderr, "traceroute6: invalid nprobes.\n"); exit(1); } if (nprobes < 1) { fprintf(stderr, "traceroute6: nprobes must be >0.\n"); exit(1); } break; case 'r': options |= SO_DONTROUTE; break; case 's': /* * set the ip source address of the outbound * probe (e.g., on a multi-homed host). */ source = optarg; break; case 'v': verbose++; break; case 'w': ep = NULL; waittime = strtoul(optarg, &ep, 0); if (!*argv || *ep) { fprintf(stderr, "traceroute6: invalid wait time.\n"); exit(1); } if (waittime <= 1) { fprintf(stderr, "traceroute6: wait must be >1 sec.\n"); exit(1); } break; default: usage(); } argc -= optind; argv += optind; if (argc < 1 || argc > 2) usage();#if 1 setvbuf(stdout, NULL, _IOLBF, BUFSIZ);#else setlinebuf (stdout);#endif memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_INET6; hints.ai_socktype = SOCK_RAW; hints.ai_protocol = IPPROTO_ICMPV6; hints.ai_flags = AI_CANONNAME; error = getaddrinfo(*argv, NULL, &hints, &res); if (error) { fprintf(stderr, "traceroute6: %s\n", gai_strerror(error)); exit(1); } if (res->ai_addrlen != sizeof(Dst)) { fprintf(stderr, "traceroute6: size of sockaddr mismatch\n"); exit(1); } memcpy(&Dst, res->ai_addr, res->ai_addrlen); hostname = res->ai_canonname ? strdup(res->ai_canonname) : *argv; if (!hostname) { fprintf(stderr, "traceroute6: not enough core\n"); exit(1); } if (res->ai_next) { if (getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) strlcpy(hbuf, "?", sizeof(hbuf)); fprintf(stderr, "traceroute6: Warning: %s has multiple " "addresses; using %s\n", hostname, hbuf); } if (*++argv) { ep = NULL; datalen = strtoul(*argv, &ep, 0); if (!*argv || *ep) { fprintf(stderr, "traceroute6: invalid packet length.\n"); exit(1); } } if (useicmp) minlen = ICMP6ECHOLEN + sizeof(struct tv32); else minlen = sizeof(struct opacket); if (datalen < minlen) datalen = minlen; else if (datalen >= MAXPACKET) { fprintf(stderr, "traceroute6: packet size must be %d <= s < %ld.\n", minlen, (long)MAXPACKET); exit(1); } outpacket = (struct opacket *)malloc((unsigned)datalen); if (! outpacket) { perror("malloc"); exit(1); } (void) bzero((char *)outpacket, datalen); /* initialize msghdr for receiving packets */ rcviov[0].iov_base = (caddr_t)packet; rcviov[0].iov_len = sizeof(packet); rcvmhdr.msg_name = (caddr_t)&Rcv; rcvmhdr.msg_namelen = sizeof(Rcv); rcvmhdr.msg_iov = rcviov; rcvmhdr.msg_iovlen = 1; rcvcmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int)); if ((rcvcmsgbuf = malloc(rcvcmsglen)) == NULL) { fprintf(stderr, "traceroute6: malloc failed\n"); exit(1); } rcvmhdr.msg_control = (caddr_t) rcvcmsgbuf; rcvmhdr.msg_controllen = rcvcmsglen; if (options & SO_DEBUG) (void) setsockopt(rcvsock, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof(on)); if (options & SO_DONTROUTE) (void) setsockopt(rcvsock, SOL_SOCKET, SO_DONTROUTE, (char *)&on, sizeof(on));#ifdef IPSEC#ifdef IPSEC_POLICY_IPSEC /* * do not raise error even if setsockopt fails, kernel may have ipsec * turned off. */ if (setpolicy(rcvsock, "in bypass") < 0) errx(1, "%s", ipsec_strerror()); if (setpolicy(rcvsock, "out bypass") < 0) errx(1, "%s", ipsec_strerror());#else { int level = IPSEC_LEVEL_NONE; (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, &level, sizeof(level)); (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_ESP_NETWORK_LEVEL, &level, sizeof(level));#ifdef IP_AUTH_TRANS_LEVEL (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, &level, sizeof(level));#else (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_AUTH_LEVEL, &level, sizeof(level));#endif#ifdef IP_AUTH_NETWORK_LEVEL (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_AUTH_NETWORK_LEVEL, &level, sizeof(level));#endif }#endif /*IPSEC_POLICY_IPSEC*/#endif /*IPSEC*/ /* * Send UDP or ICMP */ if (useicmp) { sndsock = rcvsock; } else { if ((sndsock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { perror("socket(SOCK_DGRAM)"); exit(5); } }#ifdef SO_SNDBUF if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen, sizeof(datalen)) < 0) { perror("setsockopt(SO_SNDBUF)"); exit(6); }#endif /* SO_SNDBUF */ if (options & SO_DEBUG) (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof(on)); if (options & SO_DONTROUTE) (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, (char *)&on, sizeof(on));#ifdef USE_RFC2292BIS if (rth) {/* XXX: there is no library to finalize the header... */ rth->ip6r_len = rth->ip6r_segleft * 2; if (setsockopt(sndsock, IPPROTO_IPV6, IPV6_RTHDR, (void *)rth, (rth->ip6r_len + 1) << 3)) { fprintf(stderr, "setsockopt(IPV6_RTHDR): %s\n", strerror(errno)); exit(1); } }#else /* old advanced API */ if (cmsg != NULL) { inet6_rthdr_lasthop(cmsg, IPV6_RTHDR_LOOSE); if (setsockopt(sndsock, IPPROTO_IPV6, IPV6_PKTOPTIONS, rtbuf, cmsg->cmsg_len) < 0) { fprintf(stderr, "setsockopt(IPV6_PKTOPTIONS): %s\n", strerror(errno)); exit(1); } }#endif /* USE_RFC2292BIS */#ifdef IPSEC#ifdef IPSEC_POLICY_IPSEC /* * do not raise error even if setsockopt fails, kernel may have ipsec * turned off. */ if (setpolicy(sndsock, "in bypass") < 0) errx(1, "%s", ipsec_strerror()); if (setpolicy(sndsock, "out bypass") < 0) errx(1, "%s", ipsec_strerror());#else { int level = IPSEC_LEVEL_BYPASS; (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, &level, sizeof(level)); (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_ESP_NETWORK_LEVEL, &level, sizeof(level));#ifdef IP_AUTH_TRANS_LEVEL (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, &level, sizeof(level));#else (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_AUTH_LEVEL, &level, sizeof(level));#endif#ifdef IP_AUTH_NETWORK_LEVEL (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_AUTH_NETWORK_LEVEL, &level, sizeof(level));#endif }#endif /*IPSEC_POLICY_IPSEC*/#endif /*IPSEC*/ /* * Source selection */ bzero(&Src, sizeof(Src)); if (source) { struct addrinfo hints, *res; int error; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET6; hints.ai_socktype = SOCK_DGRAM; /*dummy*/ hints.ai_flags = AI_NUMERICHOST; error = getaddrinfo(source, "0", &hints, &res); if (error) { printf("traceroute6: %s: %s\n", source, gai_strerror(error)); exit(1); } if (res->ai_addrlen > sizeof(Src)) { printf("traceroute6: %s: %s\n", source, gai_strerror(error)); exit(1); } memcpy(&Src, res->ai_addr, res->ai_addrlen); freeaddrinfo(res); } else { struct sockaddr_in6 Nxt; int dummy, len; Nxt = Dst; Nxt.sin6_port = htons(DUMMY_PORT); if (cmsg != NULL) bcopy(inet6_rthdr_getaddr(cmsg, 1), &Nxt.sin6_addr, sizeof(Nxt.sin6_addr)); if ((dummy = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { perror("socket"); exit(1); } if (connect(dummy, (struct sockaddr *)&Nxt, Nxt.sin6_len) < 0) { perror("connect"); exit(1); } len = sizeof(Src); if (getsockname(dummy, (struct sockaddr *)&Src, &len) < 0) { perror("getsockname"); exit(1); } if (getnameinfo((struct sockaddr *)&Src, Src.sin6_len, src0, sizeof(src0), NULL, 0, NI_NUMERICHOST)) { fprintf(stderr, "getnameinfo failed for source\n"); exit(1); } source = src0; close(dummy); } Src.sin6_port = htons(0); if (bind(sndsock, (struct sockaddr *)&Src, Src.sin6_len) < 0) { perror("bind"); exit(1); } { int len; len = sizeof(Src); if (getsockname(sndsock, (struct sockaddr *)&Src, &len) < 0) { perror("getsockname"); exit(1); } srcport = ntohs(Src.sin6_port); } /* * Message to users */ if (getnameinfo((struct sockaddr *)&Dst, Dst.sin6_len, hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST)) strlcpy(hbuf, "(invalid)", sizeof(hbuf)); fprintf(stderr, "traceroute6"); fprintf(stderr, " to %s (%s)", hostname, hbuf); if (source) fprintf(stderr, " from %s", source); fprintf(stderr, ", %d hops max, %d byte packets\n", max_hops, datalen); (void) fflush(stderr); if (first_hop > 1) printf("Skipping %d intermediate hops\n", first_hop - 1); /* * Main loop */ for (hops = first_hop; hops <= max_hops; ++hops) { struct in6_addr lastaddr; int got_there = 0; int unreachable = 0; printf("%2d ", hops); bzero(&lastaddr, sizeof(lastaddr)); for (probe = 0; probe < nprobes; ++probe) { int cc; struct timeval t1, t2; (void) gettimeofday(&t1, NULL); send_probe(++seq, hops); while ((cc = wait_for_reply(rcvsock, &rcvmhdr))) { (void) gettimeofday(&t2, NULL); if ((i = packet_ok(&rcvmhdr, cc, seq))) { if (! IN6_ARE_ADDR_EQUAL(&Rcv.sin6_addr, &lastaddr)) { print(&rcvmhdr, cc); lastaddr = Rcv.sin6_addr; } printf(" %g ms", deltaT(&t1, &t2)); switch (i - 1) { case ICMP6_DST_UNREACH_NOROUTE: ++unreachable; printf(" !N"); break; case ICMP6_DST_UNREACH_ADMIN: ++unreachable; printf(" !P"); break; case ICMP6_DST_UNREACH_NOTNEIGHBOR: ++unreachable; printf(" !S"); break; case ICMP6_DST_UNREACH_ADDR: ++unreachable; printf(" !A"); break; case ICMP6_DST_UNREACH_NOPORT: if (rcvhlim >= 0 && rcvhlim <= 1) printf(" !"); ++got_there; break; } break; } } if (cc == 0) printf(" *"); (void) fflush(stdout); } putchar('\n'); if (got_there || (unreachable > 0 && unreachable >= ((nprobes + 1) / 2))) { exit(0); } } exit(0);}intwait_for_reply(sock, mhdr) int sock; struct msghdr *mhdr;{#ifdef HAVE_POLL struct pollfd pfd[1];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -