X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=networking%2Ftraceroute.c;h=c32103519f1e1c463eb8dacdde9a1f50716fe228;hb=66426760beef7e87c4735f433d123daf911b5b4a;hp=18a8c25d43db7365d12611f1a45973ef62ed0d97;hpb=4c06531d5e2b053b642cea6fc4e7bc91ea4cbd26;p=oweals%2Fbusybox.git diff --git a/networking/traceroute.c b/networking/traceroute.c index 18a8c25d4..c32103519 100644 --- a/networking/traceroute.c +++ b/networking/traceroute.c @@ -210,6 +210,49 @@ * Tue Dec 20 03:50:13 PST 1988 */ +//usage:#define traceroute_trivial_usage +//usage: "[-"IF_TRACEROUTE6("46")"FIldnrv] [-f 1ST_TTL] [-m MAXTTL] [-p PORT] [-q PROBES]\n" +//usage: " [-s SRC_IP] [-t TOS] [-w WAIT_SEC] [-g GATEWAY] [-i IFACE]\n" +//usage: " [-z PAUSE_MSEC] HOST [BYTES]" +//usage:#define traceroute_full_usage "\n\n" +//usage: "Trace the route to HOST\n" +//usage: IF_TRACEROUTE6( +//usage: "\n -4,-6 Force IP or IPv6 name resolution" +//usage: ) +//usage: "\n -F Set the don't fragment bit" +//usage: "\n -I Use ICMP ECHO instead of UDP datagrams" +//usage: "\n -l Display the TTL value of the returned packet" +//usage: "\n -d Set SO_DEBUG options to socket" +//usage: "\n -n Print numeric addresses" +//usage: "\n -r Bypass routing tables, send directly to HOST" +//usage: "\n -v Verbose" +//usage: "\n -m Max time-to-live (max number of hops)" +//usage: "\n -p Base UDP port number used in probes" +//usage: "\n (default 33434)" +//usage: "\n -q Number of probes per TTL (default 3)" +//usage: "\n -s IP address to use as the source address" +//usage: "\n -t Type-of-service in probe packets (default 0)" +//usage: "\n -w Time in seconds to wait for a response (default 3)" +//usage: "\n -g Loose source route gateway (8 max)" +//usage: +//usage:#define traceroute6_trivial_usage +//usage: "[-dnrv] [-m MAXTTL] [-p PORT] [-q PROBES]\n" +//usage: " [-s SRC_IP] [-t TOS] [-w WAIT_SEC] [-i IFACE]\n" +//usage: " HOST [BYTES]" +//usage:#define traceroute6_full_usage "\n\n" +//usage: "Trace the route to HOST\n" +//usage: "\n -d Set SO_DEBUG options to socket" +//usage: "\n -n Print numeric addresses" +//usage: "\n -r Bypass routing tables, send directly to HOST" +//usage: "\n -v Verbose" +//usage: "\n -m Max time-to-live (max number of hops)" +//usage: "\n -p Base UDP port number used in probes" +//usage: "\n (default is 33434)" +//usage: "\n -q Number of probes per TTL (default 3)" +//usage: "\n -s IP address to use as the source address" +//usage: "\n -t Type-of-service in probe packets (default 0)" +//usage: "\n -w Time in seconds to wait for a response (default 3)" + #define TRACEROUTE_SO_DEBUG 0 /* TODO: undefs were uncommented - ??! we have config system for that! */ @@ -353,18 +396,23 @@ static len_and_sockaddr* dup_sockaddr(const len_and_sockaddr *lsa) static int -wait_for_reply(len_and_sockaddr *from_lsa, struct sockaddr *to) +wait_for_reply(len_and_sockaddr *from_lsa, struct sockaddr *to, unsigned *timestamp_us, int *left_ms) { struct pollfd pfd[1]; int read_len = 0; pfd[0].fd = rcvsock; pfd[0].events = POLLIN; - if (safe_poll(pfd, 1, waittime * 1000) > 0) { + if (*left_ms >= 0 && safe_poll(pfd, 1, *left_ms) > 0) { + unsigned t; + read_len = recv_from_to(rcvsock, recv_pkt, sizeof(recv_pkt), - /*flags:*/ 0, - &from_lsa->u.sa, to, from_lsa->len); + /*flags:*/ MSG_DONTWAIT, + &from_lsa->u.sa, to, from_lsa->len); + t = monotonic_us(); + *left_ms -= (t - *timestamp_us) / 1000; + *timestamp_us = t; } return read_len; @@ -472,26 +520,23 @@ send_probe(int seq, int ttl) } else #endif { -#if defined(IP_TTL) - if (setsockopt(sndsock, IPPROTO_IP, IP_TTL, - (char *)&ttl, sizeof(ttl)) < 0) { +#if defined IP_TTL + res = setsockopt(sndsock, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)); + if (res < 0) bb_perror_msg_and_die("setsockopt ttl %d", ttl); - } #endif + out = outicmp; len = packlen - sizeof(*outip); - if (option_mask32 & OPT_USE_ICMP) - out = outicmp; - else { + if (!(option_mask32 & OPT_USE_ICMP)) { out = outdata; len -= sizeof(*outudp); - set_nport(dest_lsa, htons(port + seq)); + set_nport(&dest_lsa->u.sa, htons(port + seq)); } } res = xsendto(sndsock, out, len, &dest_lsa->u.sa, dest_lsa->len); - if (res != len) { + if (res != len) bb_info_msg("sent %d octets, ret=%d", len, res); - } } #if ENABLE_FEATURE_TRACEROUTE_VERBOSE @@ -669,7 +714,6 @@ packet_ok(int read_len, len_and_sockaddr *from_lsa, return (type == ICMP6_TIME_EXCEEDED ? -1 : (code<<8)+1); } } - } # if ENABLE_FEATURE_TRACEROUTE_VERBOSE @@ -689,7 +733,7 @@ packet_ok(int read_len, len_and_sockaddr *from_lsa, type, pr_type(type), icp->icmp6_code); read_len -= sizeof(struct icmp6_hdr); - for (i = 0; i < read_len ; i++) { + for (i = 0; i < read_len; i++) { if (i % 16 == 0) printf("%04x:", i); if (i % 4 == 0) @@ -706,9 +750,10 @@ packet_ok(int read_len, len_and_sockaddr *from_lsa, } #else /* !ENABLE_TRACEROUTE6 */ static ALWAYS_INLINE int -packet_ok(int read_len, len_and_sockaddr *from_lsa, - struct sockaddr *to UNUSED_PARAM, - int seq) +packet_ok(int read_len, + len_and_sockaddr *from_lsa IF_NOT_FEATURE_TRACEROUTE_VERBOSE(UNUSED_PARAM), + struct sockaddr *to UNUSED_PARAM, + int seq) { return packet4_ok(read_len, &from_lsa->u.sin, seq); } @@ -754,7 +799,8 @@ print(int read_len, const struct sockaddr *from, const struct sockaddr *to) } else #endif { - read_len -= ((struct ip*)recv_pkt)->ip_hl << 2; + struct ip *ip4packet = (struct ip*)recv_pkt; + read_len -= ip4packet->ip_hl << 2; } printf(" %d bytes to %s", read_len, ina); free(ina); @@ -776,7 +822,6 @@ print_delta_ms(unsigned t1p, unsigned t2p) static int common_traceroute_main(int op, char **argv) { - int i; int minpacket; int tos = 0; int max_ttl = 30; @@ -797,7 +842,7 @@ common_traceroute_main(int op, char **argv) int lsrr = 0; #endif #if ENABLE_TRACEROUTE6 - sa_family_t af = AF_UNSPEC; + sa_family_t af; #else enum { af = AF_INET }; #endif @@ -838,7 +883,7 @@ common_traceroute_main(int op, char **argv) * probe (e.g., on a multi-homed host). */ if (getuid() != 0) - bb_error_msg_and_die("you must be root to use -s"); + bb_error_msg_and_die(bb_msg_you_must_be_root); } if (op & OPT_WAITTIME) waittime = xatou_range(waittime_str, 1, 24 * 60 * 60); @@ -863,31 +908,26 @@ common_traceroute_main(int op, char **argv) } #endif + /* Process destination and optional packet size */ + minpacket = sizeof(*outip) + SIZEOF_ICMP_HDR + sizeof(*outdata) + optlen; + if (!(op & OPT_USE_ICMP)) + minpacket += sizeof(*outudp) - SIZEOF_ICMP_HDR; #if ENABLE_TRACEROUTE6 + af = AF_UNSPEC; if (op & OPT_IPV4) af = AF_INET; - if (op & OPT_IPV6) { + if (op & OPT_IPV6) af = AF_INET6; - minpacket = sizeof(struct outdata6_t); - } else -#endif - { - minpacket = sizeof(*outip) + SIZEOF_ICMP_HDR - + sizeof(*outdata) + optlen; - if (!(op & OPT_USE_ICMP)) - minpacket += sizeof(*outudp) - SIZEOF_ICMP_HDR; - } - packlen = minpacket; - - /* Process destination and optional packet size */ - if (argv[1]) - packlen = xatoul_range(argv[1], minpacket, 32 * 1024); -#if ENABLE_TRACEROUTE6 dest_lsa = xhost_and_af2sockaddr(argv[0], port, af); af = dest_lsa->u.sa.sa_family; + if (af == AF_INET6) + minpacket = sizeof(struct outdata6_t); #else dest_lsa = xhost2sockaddr(argv[0], port); #endif + packlen = minpacket; + if (argv[1]) + packlen = xatoul_range(argv[1], minpacket, 32 * 1024); /* Ensure the socket fds won't be 0, 1 or 2 */ bb_sanitize_stdio(); @@ -935,6 +975,7 @@ common_traceroute_main(int op, char **argv) #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE && defined IP_OPTIONS if (lsrr > 0) { unsigned char optlist[MAX_IPOPTLEN]; + unsigned size; /* final hop */ gwlist[lsrr] = dest_lsa->u.sin.sin_addr.s_addr; @@ -944,14 +985,14 @@ common_traceroute_main(int op, char **argv) optlist[0] = IPOPT_NOP; /* loose source route option */ optlist[1] = IPOPT_LSRR; - i = lsrr * sizeof(gwlist[0]); - optlist[2] = i + 3; + size = lsrr * sizeof(gwlist[0]); + optlist[2] = size + 3; /* pointer to LSRR addresses */ optlist[3] = IPOPT_MINOFF; - memcpy(optlist + 4, gwlist, i); + memcpy(optlist + 4, gwlist, size); if (setsockopt(sndsock, IPPROTO_IP, IP_OPTIONS, - (char *)optlist, i + sizeof(gwlist[0])) < 0) { + (char *)optlist, size + sizeof(gwlist[0])) < 0) { bb_perror_msg_and_die("IP_OPTIONS"); } } @@ -1025,9 +1066,10 @@ common_traceroute_main(int op, char **argv) int probe_fd = xsocket(af, SOCK_DGRAM, 0); if (op & OPT_DEVICE) setsockopt_bindtodevice(probe_fd, device); - set_nport(dest_lsa, htons(1025)); + set_nport(&dest_lsa->u.sa, htons(1025)); /* dummy connect. makes kernel pick source IP (and port) */ xconnect(probe_fd, &dest_lsa->u.sa, dest_lsa->len); + set_nport(&dest_lsa->u.sa, htons(port)); /* read IP and port */ source_lsa = get_sock_lsa(probe_fd); @@ -1037,7 +1079,7 @@ common_traceroute_main(int op, char **argv) close(probe_fd); /* bind our sockets to this IP (but not port) */ - set_nport(source_lsa, 0); + set_nport(&source_lsa->u.sa, 0); xbind(sndsock, &source_lsa->u.sa, source_lsa->len); xbind(rcvsock, &source_lsa->u.sa, source_lsa->len); @@ -1064,28 +1106,34 @@ common_traceroute_main(int op, char **argv) int unreachable = 0; /* counter */ int gotlastaddr = 0; /* flags */ int got_there = 0; - int first = 1; printf("%2d", ttl); for (probe = 0; probe < nprobes; ++probe) { int read_len; unsigned t1; unsigned t2; + int left_ms; struct ip *ip; - if (!first && pausemsecs > 0) - usleep(pausemsecs * 1000); fflush_all(); + if (probe != 0 && pausemsecs > 0) + usleep(pausemsecs * 1000); - t1 = monotonic_us(); send_probe(++seq, ttl); + t2 = t1 = monotonic_us(); + + left_ms = waittime * 1000; + while ((read_len = wait_for_reply(from_lsa, to, &t2, &left_ms)) != 0) { + int icmp_code; - first = 0; - while ((read_len = wait_for_reply(from_lsa, to)) != 0) { - t2 = monotonic_us(); - i = packet_ok(read_len, from_lsa, to, seq); + /* Recv'ed a packet, or read error */ + /* t2 = monotonic_us() - set by wait_for_reply */ + + if (read_len < 0) + continue; + icmp_code = packet_ok(read_len, from_lsa, to, seq); /* Skip short packet */ - if (i == 0) + if (icmp_code == 0) continue; if (!gotlastaddr @@ -1104,10 +1152,10 @@ common_traceroute_main(int op, char **argv) printf(" (%d)", ip->ip_ttl); /* time exceeded in transit */ - if (i == -1) + if (icmp_code == -1) break; - i--; - switch (i) { + icmp_code--; + switch (icmp_code) { #if ENABLE_TRACEROUTE6 case ICMP6_DST_UNREACH_NOPORT << 8: got_there = 1; @@ -1180,16 +1228,18 @@ common_traceroute_main(int op, char **argv) ++unreachable; break; default: - printf(" !<%d>", i); + printf(" !<%d>", icmp_code); ++unreachable; break; } break; - } + } /* while (wait and read a packet) */ + /* there was no packet at all? */ if (read_len == 0) printf(" *"); - } + } /* for (nprobes) */ + bb_putchar('\n'); if (got_there || (unreachable > 0 && unreachable >= nprobes - 1)