int main(int argc, char *argv[]) { int mib[4] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_DEFHLIM }; char hbuf[NI_MAXHOST], src0[NI_MAXHOST], *ep; int ch, i, on = 1, seq, rcvcmsglen, error, minlen; struct addrinfo hints, *res; static u_char *rcvcmsgbuf; u_long probe, hops, lport; struct hostent *hp; size_t size; uid_t uid; /* * Receive ICMP */ if ((rcvsock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) { perror("socket(ICMPv6)"); exit(5); } /* revoke privs */ uid = getuid(); if (setresuid(uid, uid, uid) == -1) err(1, "setresuid"); size = sizeof(i); (void) sysctl(mib, sizeof(mib)/sizeof(mib[0]), &i, &size, NULL, 0); max_hops = i; /* specify to tell receiving interface */ if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on)) < 0) err(1, "setsockopt(IPV6_RECVPKTINFO)"); /* specify to tell value of hoplimit field of received IP6 hdr */ if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, sizeof(on)) < 0) err(1, "setsockopt(IPV6_RECVHOPLIMIT)"); seq = 0; while ((ch = getopt(argc, argv, "df:g:Ilm:np:q:rs:w:v")) != -1) switch (ch) { case 'd': options |= SO_DEBUG; break; case 'f': ep = NULL; errno = 0; first_hop = strtoul(optarg, &ep, 0); if (errno || !*optarg || *ep|| first_hop > 255) { fprintf(stderr, "traceroute6: invalid min hoplimit.\n"); exit(1); } break; case 'g': hp = getipnodebyname(optarg, AF_INET6, 0, &h_errno); if (hp == NULL) { fprintf(stderr, "traceroute6: unknown host %s\n", optarg); exit(1); } if (rth == NULL) { /* * XXX: We can't detect the number of * intermediate nodes yet. */ if ((rth = inet6_rth_init((void *)rtbuf, sizeof(rtbuf), IPV6_RTHDR_TYPE_0, 0)) == NULL) { fprintf(stderr, "inet6_rth_init failed.\n"); exit(1); } } if (inet6_rth_add((void *)rth, (struct in6_addr *)hp->h_addr)) { fprintf(stderr, "inet6_rth_add failed for %s\n", optarg); exit(1); } freehostent(hp); break; case 'I': useicmp++; ident = htons(getpid() & 0xffff); /* same as ping6 */ break; case 'l': lflag++; break; case 'm': ep = NULL; errno = 0; max_hops = strtoul(optarg, &ep, 0); if (errno || !*optarg || *ep || max_hops > 255) { fprintf(stderr, "traceroute6: invalid max hoplimit.\n"); exit(1); } break; case 'n': nflag++; break; case 'p': ep = NULL; errno = 0; lport = strtoul(optarg, &ep, 0); if (errno || !*optarg || *ep) { fprintf(stderr, "traceroute6: invalid 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; errno = 0; nprobes = strtoul(optarg, &ep, 0); if (errno || !*optarg || *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; errno = 0; waittime = strtoul(optarg, &ep, 0); if (errno || !*optarg || *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 (max_hops < first_hop) { fprintf(stderr, "traceroute6: max hoplimit must be larger than first hoplimit.\n"); exit(1); } 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; errno = 0; datalen = strtoul(*argv, &ep, 0); if (errno || !*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)); /* * 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 i = datalen; if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&i, sizeof(i)) < 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)); 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); } } /* * 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; socklen_t 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); } { socklen_t 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, ", %lu hops max, %lu byte packets\n", max_hops, datalen); (void) fflush(stderr); if (first_hop > 1) printf("Skipping %lu 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("%2lu ", 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); }
int main(int argc, char *argv[]) { char pa[MAXHOSTNAMELEN]; extern char *optarg; extern int optind; struct hostent *hp; struct sockaddr_in6 from, *to; int ch, i, on, probe, seq, tos, ttl; int socket_errno; icmp_sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); socket_errno = errno; if (setuid(getuid())) { perror("traceroute6: setuid"); exit(-1); } on = 1; seq = tos = 0; to = (struct sockaddr_in6 *)&whereto; while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:vi:g:V")) != EOF) { switch(ch) { case 'd': options |= SO_DEBUG; break; case 'm': max_ttl = atoi(optarg); if (max_ttl <= 1) { Fprintf(stderr, "traceroute: max ttl must be >1.\n"); exit(1); } break; case 'n': nflag++; break; case 'p': port = atoi(optarg); if (port < 1) { Fprintf(stderr, "traceroute: port must be >0.\n"); exit(1); } break; case 'q': nprobes = atoi(optarg); if (nprobes < 1) { Fprintf(stderr, "traceroute: 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 'i': device = optarg; break; case 'g': Fprintf(stderr, "Sorry, rthdr is not yet supported\n"); break; case 'v': verbose++; break; case 'w': waittime = atoi(optarg); if (waittime <= 1) { Fprintf(stderr, "traceroute: wait must be >1 sec.\n"); exit(1); } break; case 'V': printf("traceroute6 utility, iputils-ss%s\n", SNAPSHOT); exit(0); default: usage(); } } argc -= optind; argv += optind; if (argc < 1) usage(); setlinebuf (stdout); (void) bzero((char *)&whereto, sizeof(whereto)); to->sin6_family = AF_INET6; to->sin6_port = htons(port); if (inet_pton(AF_INET6, *argv, &to->sin6_addr) > 0) { hostname = *argv; } else { hp = gethostbyname2(*argv, AF_INET6); if (hp) { memmove((caddr_t)&to->sin6_addr, hp->h_addr, sizeof(to->sin6_addr)); hostname = (char *)hp->h_name; } else { (void)fprintf(stderr, "traceroute: unknown host %s\n", *argv); exit(1); } } firsthop = *to; if (*++argv) { datalen = atoi(*argv); /* Message for rpm maintainers: have _shame_. If you want * to fix something send the patch to me for sanity checking. * "datalen" patch is a shit. */ if (datalen == 0) datalen = sizeof(struct pkt_format); else if (datalen < (int)sizeof(struct pkt_format) || datalen >= MAXPACKET) { Fprintf(stderr, "traceroute: packet size must be %d <= s < %d.\n", (int)sizeof(struct pkt_format), MAXPACKET); exit(1); } } ident = getpid(); sendbuff = malloc(datalen); if (sendbuff == NULL) { fprintf(stderr, "malloc failed\n"); exit(1); } if (icmp_sock < 0) { errno = socket_errno; perror("traceroute6: icmp socket"); exit(1); } #ifdef IPV6_RECVPKTINFO setsockopt(icmp_sock, SOL_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on)); setsockopt(icmp_sock, SOL_IPV6, IPV6_2292PKTINFO, &on, sizeof(on)); #else setsockopt(icmp_sock, SOL_IPV6, IPV6_PKTINFO, &on, sizeof(on)); #endif if (options & SO_DEBUG) setsockopt(icmp_sock, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof(on)); if (options & SO_DONTROUTE) setsockopt(icmp_sock, SOL_SOCKET, SO_DONTROUTE, (char *)&on, sizeof(on)); on = 2; if (setsockopt(icmp_sock, SOL_RAW, IPV6_CHECKSUM, &on, sizeof(on)) < 0) { perror("setsockopt(RAW_CHECKSUM)"); exit(2); } if ((sndsock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { perror("traceroute: UDP socket"); exit(5); } #ifdef SO_SNDBUF if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen, sizeof(datalen)) < 0) { perror("traceroute: 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)); if (source == NULL) { socklen_t alen; int probe_fd = socket(AF_INET6, SOCK_DGRAM, 0); if (probe_fd < 0) { perror("socket"); exit(1); } if (device) { if (setsockopt(probe_fd, SOL_SOCKET, SO_BINDTODEVICE, device, strlen(device)+1) == -1) perror("WARNING: interface is ignored"); } firsthop.sin6_port = htons(1025); if (connect(probe_fd, (struct sockaddr*)&firsthop, sizeof(firsthop)) == -1) { perror("connect"); exit(1); } alen = sizeof(saddr); if (getsockname(probe_fd, (struct sockaddr*)&saddr, &alen) == -1) { perror("getsockname"); exit(1); } saddr.sin6_port = 0; close(probe_fd); } else { (void) bzero((char *)&saddr, sizeof(saddr)); saddr.sin6_family = AF_INET6; if (inet_pton(AF_INET6, source, &saddr.sin6_addr) <= 0) { Printf("traceroute: unknown addr %s\n", source); exit(1); } } if (bind(sndsock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) { perror ("traceroute: bind sending socket"); exit (1); } if (bind(icmp_sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) { perror ("traceroute: bind icmp6 socket"); exit (1); } Fprintf(stderr, "traceroute to %s (%s)", hostname, inet_ntop(AF_INET6, &to->sin6_addr, pa, sizeof(pa))); Fprintf(stderr, " from %s", inet_ntop(AF_INET6, &saddr.sin6_addr, pa, sizeof(pa))); Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen); (void) fflush(stderr); for (ttl = 1; ttl <= max_ttl; ++ttl) { struct in6_addr lastaddr = {{{0,}}}; int got_there = 0; int unreachable = 0; Printf("%2d ", ttl); for (probe = 0; probe < nprobes; ++probe) { int cc, reset_timer; struct timeval t1, t2; struct timezone tz; struct in6_addr to; gettimeofday(&t1, &tz); send_probe(++seq, ttl); reset_timer = 1; while ((cc = wait_for_reply(icmp_sock, &from, &to, reset_timer)) != 0) { gettimeofday(&t2, &tz); if ((i = packet_ok(packet, cc, &from, &to, seq, &t1))) { reset_timer = 1; if (memcmp(&from.sin6_addr, &lastaddr, sizeof(from.sin6_addr))) { print(packet, cc, &from); memcpy(&lastaddr, &from.sin6_addr, sizeof(lastaddr)); } Printf(" %g ms", deltaT(&t1, &t2)); switch(i - 1) { case ICMP6_DST_UNREACH_NOPORT: ++got_there; break; case ICMP6_DST_UNREACH_NOROUTE: ++unreachable; Printf(" !N"); break; case ICMP6_DST_UNREACH_ADDR: ++unreachable; Printf(" !H"); break; case ICMP6_DST_UNREACH_ADMIN: ++unreachable; Printf(" !S"); break; } break; } else reset_timer = 0; } if (cc <= 0) Printf(" *"); (void) fflush(stdout); } putchar('\n'); if (got_there || (unreachable > 0 && unreachable >= nprobes-1)) exit(0); } return 0; }
traceroute_main(int argc, char *argv[]) #endif { extern char *optarg; extern int optind; struct hostent *hp; struct sockaddr_in from, *to; int ch, i, on, probe, seq, tos, ttl; int options = 0; /* socket options */ char *source = 0; int nprobes = 3; on = 1; seq = tos = 0; to = (struct sockaddr_in *)&whereto; while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:v")) != EOF) switch(ch) { case 'd': #ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG options |= SO_DEBUG; #endif break; case 'm': max_ttl = atoi(optarg); if (max_ttl <= 1) bb_error_msg_and_die("max ttl must be >1."); break; case 'n': nflag++; break; case 'p': port = atoi(optarg); if (port < 1) bb_error_msg_and_die("port must be >0."); break; case 'q': nprobes = atoi(optarg); if (nprobes < 1) bb_error_msg_and_die("nprobes must be >0."); 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 't': tos = atoi(optarg); if (tos < 0 || tos > 255) bb_error_msg_and_die("tos must be 0 to 255."); break; case 'v': #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE verbose++; #endif break; case 'w': waittime = atoi(optarg); if (waittime <= 1) bb_error_msg_and_die("wait must be >1 sec."); break; default: bb_show_usage(); } argc -= optind; argv += optind; if (argc < 1) bb_show_usage(); setlinebuf (stdout); memset(&whereto, 0, sizeof(struct sockaddr)); hp = xgethostbyname(*argv); to->sin_family = hp->h_addrtype; memcpy(&to->sin_addr, hp->h_addr, hp->h_length); hostname = (char *)hp->h_name; if (*++argv) datalen = atoi(*argv); if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket)) bb_error_msg_and_die("packet size must be 0 <= s < %d.", MAXPACKET - sizeof(struct opacket)); datalen += sizeof(struct opacket); outpacket = (struct opacket *)xmalloc((unsigned)datalen); memset(outpacket, 0, datalen); outpacket->ip.ip_dst = to->sin_addr; outpacket->ip.ip_tos = tos; outpacket->ip.ip_v = IPVERSION; outpacket->ip.ip_id = 0; ident = (getpid() & 0xffff) | 0x8000; if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) bb_perror_msg_and_die(bb_msg_can_not_create_raw_socket); s = create_icmp_socket(); #ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG if (options & SO_DEBUG) (void) setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof(on)); #endif if (options & SO_DONTROUTE) (void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&on, sizeof(on)); #ifdef SO_SNDBUF if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen, sizeof(datalen)) < 0) bb_perror_msg_and_die("SO_SNDBUF"); #endif #ifdef IP_HDRINCL if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on, sizeof(on)) < 0) bb_perror_msg_and_die("IP_HDRINCL"); #endif #ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG if (options & SO_DEBUG) (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof(on)); #endif if (options & SO_DONTROUTE) (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, (char *)&on, sizeof(on)); if (source) { memset(&from, 0, sizeof(struct sockaddr)); from.sin_family = AF_INET; from.sin_addr.s_addr = inet_addr(source); if (from.sin_addr.s_addr == -1) bb_error_msg_and_die("unknown host %s", source); outpacket->ip.ip_src = from.sin_addr; #ifndef IP_HDRINCL if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0) bb_perror_msg_and_die("bind"); #endif } fprintf(stderr, "traceroute to %s (%s)", hostname, inet_ntoa(to->sin_addr)); if (source) fprintf(stderr, " from %s", source); fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen); for (ttl = 1; ttl <= max_ttl; ++ttl) { u_long lastaddr = 0; int got_there = 0; int unreachable = 0; printf("%2d ", ttl); for (probe = 0; probe < nprobes; ++probe) { int cc, reset_timer; struct timeval t1, t2; struct timezone tz; struct ip *ip; (void) gettimeofday(&t1, &tz); send_probe(++seq, ttl); reset_timer = 1; while ((cc = wait_for_reply(s, &from, reset_timer)) != 0) { (void) gettimeofday(&t2, &tz); if ((i = packet_ok(packet, cc, &from, seq))) { reset_timer = 1; if (from.sin_addr.s_addr != lastaddr) { print(packet, cc, &from); lastaddr = from.sin_addr.s_addr; } printf(" %g ms", deltaT(&t1, &t2)); switch(i - 1) { case ICMP_UNREACH_PORT: ip = (struct ip *)packet; if (ip->ip_ttl <= 1) printf(" !"); ++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"); break; case ICMP_UNREACH_SRCFAIL: ++unreachable; printf(" !S"); break; } break; } else reset_timer = 0; } if (cc == 0) printf(" *"); (void) fflush(stdout); } putchar('\n'); if (got_there || unreachable >= nprobes-1) return 0; } return 0; }
static void /* not inline */ send_probe(int seq, int ttl) { struct opacket *op = outpacket; struct ip *ip = &op->ip; struct udphdr *up = &op->udp; int i; struct timezone tz; #if defined (DMP_TRACEROUTE_1) int dataSize = datalen -12; /* Minus some parameters' length in struct opacket*/ #endif ip->ip_off = 0; ip->ip_hl = sizeof(*ip) >> 2; ip->ip_p = IPPROTO_UDP; #if defined (DMP_TRACEROUTE_1) ip->ip_len = dataSize; #else ip->ip_len = datalen; #endif ip->ip_ttl = ttl; ip->ip_v = IPVERSION; ip->ip_id = htons(ident+seq); up->source = htons(ident); up->dest = htons(port+seq); #if defined (DMP_TRACEROUTE_1) up->len = htons((u_short)(dataSize - sizeof(struct ip))); #else up->len = htons((u_short)(datalen - sizeof(struct ip))); #endif up->check = 0; op->seq = seq; op->ttl = ttl; (void) gettimeofday(&op->tv, &tz); #if defined (DMP_TRACEROUTE_1) i = sendto(sndsock, (char *)outpacket, dataSize, 0, &whereto, sizeof(struct sockaddr)); #else i = sendto(sndsock, (char *)outpacket, datalen, 0, &whereto, sizeof(struct sockaddr)); #endif #if defined (DMP_TRACEROUTE_1) if (i < 0 || i != dataSize) { #else if (i < 0 || i != datalen) { #endif if (i<0) perror("sendto"); #if defined (DMP_TRACEROUTE_1) printf("traceroute: wrote %s %d chars, ret=%d\n", hostname, dataSize, i); #else printf("traceroute: wrote %s %d chars, ret=%d\n", hostname, datalen, i); #endif (void) fflush(stdout); } } int #ifndef CONFIG_TRACEROUTE main(int argc, char *argv[]) #else traceroute_main(int argc, char *argv[]) #endif { extern char *optarg; extern int optind; struct hostent *hp; struct sockaddr_in from, *to; int ch, i, on, probe, seq, tos, ttl; int options = 0; /* socket options */ char *source = 0; int nprobes = 3; #if defined(AEI_VDSL_CUSTOMER_QWEST_Q2000) int ttl_set_flag = 0; #endif #if defined(AEI_VDSL_CUSTOMER_NCS) int failcount = 0; #endif #if defined(DMP_TRACEROUTE_1) unsigned int repTime; char strRepTime[16]; TraceRouteDataMsgBody traceRouteInfo; memset(&traceRouteInfo, 0 , sizeof(TraceRouteDataMsgBody)); TraceRouteDataMsgBody *pTraceRouteInfo = &traceRouteInfo; cmsMsg_init(EID_TRACEROUTE, &msgHandle); #endif on = 1; seq = tos = 0; to = (struct sockaddr_in *)&whereto; while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:v")) != EOF) switch(ch) { case 'd': #ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG options |= SO_DEBUG; #endif break; case 'm': max_ttl = atoi(optarg); #if defined(AEI_VDSL_CUSTOMER_QWEST_Q2000) ttl_set_flag = 1; #endif if (max_ttl <= 1) bb_error_msg_and_die("max ttl must be >1."); break; case 'n': nflag++; break; case 'p': port = atoi(optarg); if (port < 1) bb_error_msg_and_die("port must be >0."); break; case 'q': nprobes = atoi(optarg); if (nprobes < 1) bb_error_msg_and_die("nprobes must be >0."); 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 't': tos = atoi(optarg); if (tos < 0 || tos > 255) bb_error_msg_and_die("tos must be 0 to 255."); break; case 'v': #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE verbose++; #endif break; case 'w': waittime = atoi(optarg); if (waittime <= 1) bb_error_msg_and_die("wait must be >1 sec."); break; default: bb_show_usage(); } argc -= optind; argv += optind; if (argc < 1) bb_show_usage(); setlinebuf (stdout); memset(&whereto, 0, sizeof(struct sockaddr)); #if defined(DMP_TRACEROUTE_1) hp = gethostbyname(*argv); if (*++argv) { requesterId = atoi(*argv); } if (hp == NULL) { AEI_sendTraceRouteEventMessage(pTraceRouteInfo, Error_CannotResolveHostName); bb_herror_msg_and_die("%s", *--argv); } #else hp = xgethostbyname(*argv); #endif to->sin_family = hp->h_addrtype; memcpy(&to->sin_addr, hp->h_addr, hp->h_length); hostname = (char *)hp->h_name; if (*++argv) datalen = atoi(*argv); #if defined (DMP_TRACEROUTE_1) if (datalen == 0) { datalen = 40; /*Default data length*/ } #endif if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket)) bb_error_msg_and_die("packet size must be 0 <= s < %d.", MAXPACKET - sizeof(struct opacket)); datalen += sizeof(struct opacket); outpacket = (struct opacket *)xmalloc((unsigned)datalen); memset(outpacket, 0, datalen); outpacket->ip.ip_dst = to->sin_addr; outpacket->ip.ip_tos = tos; #if defined(DMP_TRACEROUTE_1) outpacket->ip.ip_tos = (outpacket->ip.ip_tos)<<2; #endif outpacket->ip.ip_v = IPVERSION; outpacket->ip.ip_id = 0; ident = (getpid() & 0xffff) | 0x8000; if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) bb_perror_msg_and_die(bb_msg_can_not_create_raw_socket); s = create_icmp_socket(); #ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG if (options & SO_DEBUG) (void) setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof(on)); #endif if (options & SO_DONTROUTE) (void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&on, sizeof(on)); #ifdef SO_SNDBUF if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen, sizeof(datalen)) < 0) bb_perror_msg_and_die("SO_SNDBUF"); #endif #ifdef IP_HDRINCL if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on, sizeof(on)) < 0) bb_perror_msg_and_die("IP_HDRINCL"); #endif #ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG if (options & SO_DEBUG) (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof(on)); #endif if (options & SO_DONTROUTE) (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, (char *)&on, sizeof(on)); if (source) { memset(&from, 0, sizeof(struct sockaddr)); from.sin_family = AF_INET; from.sin_addr.s_addr = inet_addr(source); if (from.sin_addr.s_addr == -1) bb_error_msg_and_die("unknown host %s", source); outpacket->ip.ip_src = from.sin_addr; #ifndef IP_HDRINCL if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0) bb_perror_msg_and_die("bind"); #endif } fprintf(stderr, "traceroute to %s (%s)", hostname, inet_ntoa(to->sin_addr)); if (source) fprintf(stderr, " from %s", source); fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen); for (ttl = 1; ttl <= max_ttl; ++ttl) { u_long lastaddr = 0; int got_there = 0; int unreachable = 0; #if defined(DMP_TRACEROUTE_1) pTraceRouteInfo->routeHopsNumberOfEntries++; #endif printf("%2d ", ttl); for (probe = 0; probe < nprobes; ++probe) { int cc, reset_timer; struct timeval t1, t2; struct timezone tz; struct ip *ip; (void) gettimeofday(&t1, &tz); send_probe(++seq, ttl); reset_timer = 1; while ((cc = wait_for_reply(s, &from, reset_timer)) != 0) { (void) gettimeofday(&t2, &tz); if ((i = packet_ok(packet, cc, &from, seq))) { reset_timer = 1; if (from.sin_addr.s_addr != lastaddr) { print(packet, cc, &from); lastaddr = from.sin_addr.s_addr; } printf(" %g ms", deltaT(&t1, &t2)); #if defined(DMP_TRACEROUTE_1) struct icmp *hopIcp; int hopHlen; struct ip *hopIp; hopIp = (struct ip *) packet; hopHlen = hopIp->ip_hl << 2; hopIcp = (struct icmp *)(packet + hopHlen); repTime = ((int)(t2.tv_sec - t1.tv_sec) * 1000 + (int)(t2.tv_usec - t1.tv_usec) / 1000); sprintf(strRepTime, "%d,", repTime); pTraceRouteInfo->responseTime+=repTime; pTraceRouteInfo->routeHops[ttl-1].hopErrorCode = hopIcp->icmp_code; sprintf(pTraceRouteInfo->routeHops[ttl-1].hopHost, "%s", inet_ntoa(from.sin_addr)); sprintf(pTraceRouteInfo->routeHops[ttl-1].hopHostAddress, "%s", inet_ntoa(from.sin_addr)); strcat(pTraceRouteInfo->routeHops[ttl-1].hopRTTimes, strRepTime); #endif switch(i - 1) { case ICMP_UNREACH_PORT: ip = (struct ip *)packet; if (ip->ip_ttl <= 1) printf(" !"); ++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"); break; case ICMP_UNREACH_SRCFAIL: ++unreachable; printf(" !S"); break; } break; } else reset_timer = 0; } if (cc == 0) { #if defined(AEI_VDSL_CUSTOMER_NCS) failcount++; #endif printf(" *"); } #if defined(AEI_VDSL_CUSTOMER_NCS) else failcount=0; #endif (void) fflush(stdout); } putchar('\n'); if (got_there || (unreachable && unreachable >= nprobes-1)) { #if defined(DMP_TRACEROUTE_1) if (got_there) { AEI_sendTraceRouteEventMessage(pTraceRouteInfo, Complete); } else if (unreachable && unreachable >= nprobes-1) { AEI_sendTraceRouteEventMessage(pTraceRouteInfo, Error_MaxHopCountExceeded); } #endif return 0; } #if defined(AEI_VDSL_CUSTOMER_NCS) #if defined(AEI_VDSL_CUSTOMER_QWEST_Q2000) if (failcount >= nprobes*2&&ttl_set_flag==0) #else if (failcount >= nprobes*2) #endif { #if defined(DMP_TRACEROUTE_1) AEI_sendTraceRouteEventMessage(pTraceRouteInfo, Error_MaxHopCountExceeded); #endif return 0; } #endif } #if defined(DMP_TRACEROUTE_1) AEI_sendTraceRouteEventMessage(pTraceRouteInfo, Error_MaxHopCountExceeded); #endif return 0; }