diff options
-rw-r--r-- | networking/traceroute.c | 61 |
1 files changed, 37 insertions, 24 deletions
diff --git a/networking/traceroute.c b/networking/traceroute.c index 96f9d3472..85181ab8d 100644 --- a/networking/traceroute.c +++ b/networking/traceroute.c | |||
@@ -398,18 +398,23 @@ static len_and_sockaddr* dup_sockaddr(const len_and_sockaddr *lsa) | |||
398 | 398 | ||
399 | 399 | ||
400 | static int | 400 | static int |
401 | wait_for_reply(len_and_sockaddr *from_lsa, struct sockaddr *to) | 401 | wait_for_reply(len_and_sockaddr *from_lsa, struct sockaddr *to, unsigned *timestamp_us, int *left_ms) |
402 | { | 402 | { |
403 | struct pollfd pfd[1]; | 403 | struct pollfd pfd[1]; |
404 | int read_len = 0; | 404 | int read_len = 0; |
405 | 405 | ||
406 | pfd[0].fd = rcvsock; | 406 | pfd[0].fd = rcvsock; |
407 | pfd[0].events = POLLIN; | 407 | pfd[0].events = POLLIN; |
408 | if (safe_poll(pfd, 1, waittime * 1000) > 0) { | 408 | if (*left_ms >= 0 && safe_poll(pfd, 1, *left_ms) > 0) { |
409 | unsigned t; | ||
410 | |||
409 | read_len = recv_from_to(rcvsock, | 411 | read_len = recv_from_to(rcvsock, |
410 | recv_pkt, sizeof(recv_pkt), | 412 | recv_pkt, sizeof(recv_pkt), |
411 | /*flags:*/ 0, | 413 | /*flags:*/ MSG_DONTWAIT, |
412 | &from_lsa->u.sa, to, from_lsa->len); | 414 | &from_lsa->u.sa, to, from_lsa->len); |
415 | t = monotonic_us(); | ||
416 | *left_ms -= (t - *timestamp_us) / 1000; | ||
417 | *timestamp_us = t; | ||
413 | } | 418 | } |
414 | 419 | ||
415 | return read_len; | 420 | return read_len; |
@@ -730,7 +735,7 @@ packet_ok(int read_len, len_and_sockaddr *from_lsa, | |||
730 | type, pr_type(type), icp->icmp6_code); | 735 | type, pr_type(type), icp->icmp6_code); |
731 | 736 | ||
732 | read_len -= sizeof(struct icmp6_hdr); | 737 | read_len -= sizeof(struct icmp6_hdr); |
733 | for (i = 0; i < read_len ; i++) { | 738 | for (i = 0; i < read_len; i++) { |
734 | if (i % 16 == 0) | 739 | if (i % 16 == 0) |
735 | printf("%04x:", i); | 740 | printf("%04x:", i); |
736 | if (i % 4 == 0) | 741 | if (i % 4 == 0) |
@@ -819,7 +824,6 @@ print_delta_ms(unsigned t1p, unsigned t2p) | |||
819 | static int | 824 | static int |
820 | common_traceroute_main(int op, char **argv) | 825 | common_traceroute_main(int op, char **argv) |
821 | { | 826 | { |
822 | int i; | ||
823 | int minpacket; | 827 | int minpacket; |
824 | int tos = 0; | 828 | int tos = 0; |
825 | int max_ttl = 30; | 829 | int max_ttl = 30; |
@@ -973,6 +977,7 @@ common_traceroute_main(int op, char **argv) | |||
973 | #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE && defined IP_OPTIONS | 977 | #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE && defined IP_OPTIONS |
974 | if (lsrr > 0) { | 978 | if (lsrr > 0) { |
975 | unsigned char optlist[MAX_IPOPTLEN]; | 979 | unsigned char optlist[MAX_IPOPTLEN]; |
980 | unsigned size; | ||
976 | 981 | ||
977 | /* final hop */ | 982 | /* final hop */ |
978 | gwlist[lsrr] = dest_lsa->u.sin.sin_addr.s_addr; | 983 | gwlist[lsrr] = dest_lsa->u.sin.sin_addr.s_addr; |
@@ -982,14 +987,14 @@ common_traceroute_main(int op, char **argv) | |||
982 | optlist[0] = IPOPT_NOP; | 987 | optlist[0] = IPOPT_NOP; |
983 | /* loose source route option */ | 988 | /* loose source route option */ |
984 | optlist[1] = IPOPT_LSRR; | 989 | optlist[1] = IPOPT_LSRR; |
985 | i = lsrr * sizeof(gwlist[0]); | 990 | size = lsrr * sizeof(gwlist[0]); |
986 | optlist[2] = i + 3; | 991 | optlist[2] = size + 3; |
987 | /* pointer to LSRR addresses */ | 992 | /* pointer to LSRR addresses */ |
988 | optlist[3] = IPOPT_MINOFF; | 993 | optlist[3] = IPOPT_MINOFF; |
989 | memcpy(optlist + 4, gwlist, i); | 994 | memcpy(optlist + 4, gwlist, size); |
990 | 995 | ||
991 | if (setsockopt(sndsock, IPPROTO_IP, IP_OPTIONS, | 996 | if (setsockopt(sndsock, IPPROTO_IP, IP_OPTIONS, |
992 | (char *)optlist, i + sizeof(gwlist[0])) < 0) { | 997 | (char *)optlist, size + sizeof(gwlist[0])) < 0) { |
993 | bb_perror_msg_and_die("IP_OPTIONS"); | 998 | bb_perror_msg_and_die("IP_OPTIONS"); |
994 | } | 999 | } |
995 | } | 1000 | } |
@@ -1103,28 +1108,34 @@ common_traceroute_main(int op, char **argv) | |||
1103 | int unreachable = 0; /* counter */ | 1108 | int unreachable = 0; /* counter */ |
1104 | int gotlastaddr = 0; /* flags */ | 1109 | int gotlastaddr = 0; /* flags */ |
1105 | int got_there = 0; | 1110 | int got_there = 0; |
1106 | int first = 1; | ||
1107 | 1111 | ||
1108 | printf("%2d", ttl); | 1112 | printf("%2d", ttl); |
1109 | for (probe = 0; probe < nprobes; ++probe) { | 1113 | for (probe = 0; probe < nprobes; ++probe) { |
1110 | int read_len; | 1114 | int read_len; |
1111 | unsigned t1; | 1115 | unsigned t1; |
1112 | unsigned t2; | 1116 | unsigned t2; |
1117 | int left_ms; | ||
1113 | struct ip *ip; | 1118 | struct ip *ip; |
1114 | 1119 | ||
1115 | if (!first && pausemsecs > 0) | ||
1116 | usleep(pausemsecs * 1000); | ||
1117 | fflush_all(); | 1120 | fflush_all(); |
1121 | if (probe != 0 && pausemsecs > 0) | ||
1122 | usleep(pausemsecs * 1000); | ||
1118 | 1123 | ||
1119 | t1 = monotonic_us(); | ||
1120 | send_probe(++seq, ttl); | 1124 | send_probe(++seq, ttl); |
1125 | t2 = t1 = monotonic_us(); | ||
1126 | |||
1127 | left_ms = waittime * 1000; | ||
1128 | while ((read_len = wait_for_reply(from_lsa, to, &t2, &left_ms)) != 0) { | ||
1129 | int icmp_code; | ||
1130 | |||
1131 | /* Recv'ed a packet, or read error */ | ||
1132 | /* t2 = monotonic_us() - set by wait_for_reply */ | ||
1121 | 1133 | ||
1122 | first = 0; | 1134 | if (read_len < 0) |
1123 | while ((read_len = wait_for_reply(from_lsa, to)) != 0) { | 1135 | continue; |
1124 | t2 = monotonic_us(); | 1136 | icmp_code = packet_ok(read_len, from_lsa, to, seq); |
1125 | i = packet_ok(read_len, from_lsa, to, seq); | ||
1126 | /* Skip short packet */ | 1137 | /* Skip short packet */ |
1127 | if (i == 0) | 1138 | if (icmp_code == 0) |
1128 | continue; | 1139 | continue; |
1129 | 1140 | ||
1130 | if (!gotlastaddr | 1141 | if (!gotlastaddr |
@@ -1143,10 +1154,10 @@ common_traceroute_main(int op, char **argv) | |||
1143 | printf(" (%d)", ip->ip_ttl); | 1154 | printf(" (%d)", ip->ip_ttl); |
1144 | 1155 | ||
1145 | /* time exceeded in transit */ | 1156 | /* time exceeded in transit */ |
1146 | if (i == -1) | 1157 | if (icmp_code == -1) |
1147 | break; | 1158 | break; |
1148 | i--; | 1159 | icmp_code--; |
1149 | switch (i) { | 1160 | switch (icmp_code) { |
1150 | #if ENABLE_TRACEROUTE6 | 1161 | #if ENABLE_TRACEROUTE6 |
1151 | case ICMP6_DST_UNREACH_NOPORT << 8: | 1162 | case ICMP6_DST_UNREACH_NOPORT << 8: |
1152 | got_there = 1; | 1163 | got_there = 1; |
@@ -1219,16 +1230,18 @@ common_traceroute_main(int op, char **argv) | |||
1219 | ++unreachable; | 1230 | ++unreachable; |
1220 | break; | 1231 | break; |
1221 | default: | 1232 | default: |
1222 | printf(" !<%d>", i); | 1233 | printf(" !<%d>", icmp_code); |
1223 | ++unreachable; | 1234 | ++unreachable; |
1224 | break; | 1235 | break; |
1225 | } | 1236 | } |
1226 | break; | 1237 | break; |
1227 | } | 1238 | } /* while (wait and read a packet) */ |
1239 | |||
1228 | /* there was no packet at all? */ | 1240 | /* there was no packet at all? */ |
1229 | if (read_len == 0) | 1241 | if (read_len == 0) |
1230 | printf(" *"); | 1242 | printf(" *"); |
1231 | } | 1243 | } /* for (nprobes) */ |
1244 | |||
1232 | bb_putchar('\n'); | 1245 | bb_putchar('\n'); |
1233 | if (got_there | 1246 | if (got_there |
1234 | || (unreachable > 0 && unreachable >= nprobes - 1) | 1247 | || (unreachable > 0 && unreachable >= nprobes - 1) |