diff options
| author | Leonid Lisovskiy <lly.dev@gmail.com> | 2009-11-23 06:20:09 +0100 |
|---|---|---|
| committer | Denys Vlasenko <vda.linux@googlemail.com> | 2009-11-23 06:20:09 +0100 |
| commit | 4c06531d5e2b053b642cea6fc4e7bc91ea4cbd26 (patch) | |
| tree | d652a32a9dcc9e1acaff57bf019211068db55cdc | |
| parent | 0d56568654973a522bd005616b86d4dc8c833c81 (diff) | |
| download | busybox-w32-4c06531d5e2b053b642cea6fc4e7bc91ea4cbd26.tar.gz busybox-w32-4c06531d5e2b053b642cea6fc4e7bc91ea4cbd26.tar.bz2 busybox-w32-4c06531d5e2b053b642cea6fc4e7bc91ea4cbd26.zip | |
traceroute6: new applet by Leonid Lisovskiy. +1562 bytes
Signed-off-by: Leonid Lisovskiy <lly.dev@gmail.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
| -rw-r--r-- | include/applets.h | 1 | ||||
| -rw-r--r-- | include/usage.h | 27 | ||||
| -rw-r--r-- | networking/Config.in | 7 | ||||
| -rw-r--r-- | networking/traceroute.c | 502 |
4 files changed, 428 insertions, 109 deletions
diff --git a/include/applets.h b/include/applets.h index a2d1e95a5..d1a84eeaf 100644 --- a/include/applets.h +++ b/include/applets.h | |||
| @@ -395,6 +395,7 @@ IF_TOP(APPLET(top, _BB_DIR_USR_BIN, _BB_SUID_DROP)) | |||
| 395 | IF_TOUCH(APPLET_NOFORK(touch, touch, _BB_DIR_BIN, _BB_SUID_DROP, touch)) | 395 | IF_TOUCH(APPLET_NOFORK(touch, touch, _BB_DIR_BIN, _BB_SUID_DROP, touch)) |
| 396 | IF_TR(APPLET(tr, _BB_DIR_USR_BIN, _BB_SUID_DROP)) | 396 | IF_TR(APPLET(tr, _BB_DIR_USR_BIN, _BB_SUID_DROP)) |
| 397 | IF_TRACEROUTE(APPLET(traceroute, _BB_DIR_USR_BIN, _BB_SUID_MAYBE)) | 397 | IF_TRACEROUTE(APPLET(traceroute, _BB_DIR_USR_BIN, _BB_SUID_MAYBE)) |
| 398 | IF_TRACEROUTE6(APPLET(traceroute6, _BB_DIR_USR_BIN, _BB_SUID_MAYBE)) | ||
| 398 | IF_TRUE(APPLET_NOFORK(true, true, _BB_DIR_BIN, _BB_SUID_DROP, true)) | 399 | IF_TRUE(APPLET_NOFORK(true, true, _BB_DIR_BIN, _BB_SUID_DROP, true)) |
| 399 | IF_TTY(APPLET(tty, _BB_DIR_USR_BIN, _BB_SUID_DROP)) | 400 | IF_TTY(APPLET(tty, _BB_DIR_USR_BIN, _BB_SUID_DROP)) |
| 400 | IF_TTYSIZE(APPLET(ttysize, _BB_DIR_USR_BIN, _BB_SUID_DROP)) | 401 | IF_TTYSIZE(APPLET(ttysize, _BB_DIR_USR_BIN, _BB_SUID_DROP)) |
diff --git a/include/usage.h b/include/usage.h index 3ccf160bd..920f8e8c9 100644 --- a/include/usage.h +++ b/include/usage.h | |||
| @@ -4648,17 +4648,18 @@ | |||
| 4648 | "hello world\n" | 4648 | "hello world\n" |
| 4649 | 4649 | ||
| 4650 | #define traceroute_trivial_usage \ | 4650 | #define traceroute_trivial_usage \ |
| 4651 | "[-FIldnrv] [-f 1st_ttl] [-m max_ttl] [-p port#] [-q nqueries]\n" \ | 4651 | "[-46FIldnrv] [-f 1st_ttl] [-m max_ttl] [-p port#] [-q nqueries]\n" \ |
| 4652 | " [-s src_addr] [-t tos] [-w wait] [-g gateway] [-i iface]\n" \ | 4652 | " [-s src_addr] [-t tos] [-w wait] [-g gateway] [-i iface]\n" \ |
| 4653 | " [-z pausemsecs] HOST [data size]" | 4653 | " [-z pausemsecs] HOST [data size]" |
| 4654 | #define traceroute_full_usage "\n\n" \ | 4654 | #define traceroute_full_usage "\n\n" \ |
| 4655 | "Trace the route to HOST\n" \ | 4655 | "Trace the route to HOST\n" \ |
| 4656 | "\nOptions:" \ | 4656 | "\nOptions:" \ |
| 4657 | "\n -4, -6 Force IPv4 or IPv6 hostname resolution" \ | ||
| 4657 | "\n -F Set the don't fragment bit" \ | 4658 | "\n -F Set the don't fragment bit" \ |
| 4658 | "\n -I Use ICMP ECHO instead of UDP datagrams" \ | 4659 | "\n -I Use ICMP ECHO instead of UDP datagrams" \ |
| 4659 | "\n -l Display the ttl value of the returned packet" \ | 4660 | "\n -l Display the ttl value of the returned packet" \ |
| 4660 | "\n -d Set SO_DEBUG options to socket" \ | 4661 | "\n -d Set SO_DEBUG options to socket" \ |
| 4661 | "\n -n Print hop addresses numerically rather than symbolically" \ | 4662 | "\n -n Print numeric addresses" \ |
| 4662 | "\n -r Bypass the normal routing tables and send directly to a host" \ | 4663 | "\n -r Bypass the normal routing tables and send directly to a host" \ |
| 4663 | "\n -v Verbose" \ | 4664 | "\n -v Verbose" \ |
| 4664 | "\n -m max_ttl Max time-to-live (max number of hops)" \ | 4665 | "\n -m max_ttl Max time-to-live (max number of hops)" \ |
| @@ -4668,9 +4669,29 @@ | |||
| 4668 | "\n -s src_addr IP address to use as the source address" \ | 4669 | "\n -s src_addr IP address to use as the source address" \ |
| 4669 | "\n -t tos Type-of-service in probe packets (default 0)" \ | 4670 | "\n -t tos Type-of-service in probe packets (default 0)" \ |
| 4670 | "\n -w wait Time in seconds to wait for a response" \ | 4671 | "\n -w wait Time in seconds to wait for a response" \ |
| 4671 | "\n (default 3 sec)" \ | 4672 | "\n (default 3)" \ |
| 4672 | "\n -g Loose source route gateway (8 max)" \ | 4673 | "\n -g Loose source route gateway (8 max)" \ |
| 4673 | 4674 | ||
| 4675 | #define traceroute6_trivial_usage \ | ||
| 4676 | "[-dnrv] [-m max_ttl] [-p port#] [-q nqueries]\n" \ | ||
| 4677 | " [-s src_addr] [-t tos] [-w wait] [-i iface]\n" \ | ||
| 4678 | " HOST [data size]" | ||
| 4679 | #define traceroute6_full_usage "\n\n" \ | ||
| 4680 | "Trace the route to HOST\n" \ | ||
| 4681 | "\nOptions:" \ | ||
| 4682 | "\n -d Set SO_DEBUG options to socket" \ | ||
| 4683 | "\n -n Print numeric addresses" \ | ||
| 4684 | "\n -r Bypass the normal routing tables and send directly to a host" \ | ||
| 4685 | "\n -v Verbose" \ | ||
| 4686 | "\n -m max_ttl Max time-to-live (max number of hops)" \ | ||
| 4687 | "\n -p port# Base UDP port number used in probes" \ | ||
| 4688 | "\n (default is 33434)" \ | ||
| 4689 | "\n -q nqueries Number of probes per 'ttl' (default 3)" \ | ||
| 4690 | "\n -s src_addr IP address to use as the source address" \ | ||
| 4691 | "\n -t tos Type-of-service in probe packets (default 0)" \ | ||
| 4692 | "\n -w wait Time in seconds to wait for a response" \ | ||
| 4693 | "\n (default 3)" \ | ||
| 4694 | |||
| 4674 | #define true_trivial_usage \ | 4695 | #define true_trivial_usage \ |
| 4675 | "" | 4696 | "" |
| 4676 | #define true_full_usage "\n\n" \ | 4697 | #define true_full_usage "\n\n" \ |
diff --git a/networking/Config.in b/networking/Config.in index 3d29622da..668823784 100644 --- a/networking/Config.in +++ b/networking/Config.in | |||
| @@ -888,6 +888,13 @@ config TRACEROUTE | |||
| 888 | help | 888 | help |
| 889 | Utility to trace the route of IP packets. | 889 | Utility to trace the route of IP packets. |
| 890 | 890 | ||
| 891 | config TRACEROUTE6 | ||
| 892 | bool "traceroute6" | ||
| 893 | default n | ||
| 894 | depends on FEATURE_IPV6 && TRACEROUTE | ||
| 895 | help | ||
| 896 | Utility to trace the route of IPv6 packets. | ||
| 897 | |||
| 891 | config FEATURE_TRACEROUTE_VERBOSE | 898 | config FEATURE_TRACEROUTE_VERBOSE |
| 892 | bool "Enable verbose output" | 899 | bool "Enable verbose output" |
| 893 | default n | 900 | default n |
diff --git a/networking/traceroute.c b/networking/traceroute.c index d36ddee14..18a8c25d4 100644 --- a/networking/traceroute.c +++ b/networking/traceroute.c | |||
| @@ -23,6 +23,23 @@ | |||
| 23 | */ | 23 | */ |
| 24 | 24 | ||
| 25 | /* | 25 | /* |
| 26 | * traceroute6 | ||
| 27 | * | ||
| 28 | * Modified for NRL 4.4BSD IPv6 release. | ||
| 29 | * 07/31/96 bgp | ||
| 30 | * | ||
| 31 | * Modified for Linux IPv6 by Pedro Roque <roque@di.fc.ul.pt> | ||
| 32 | * 31/07/1996 | ||
| 33 | * | ||
| 34 | * As ICMP error messages for IPv6 now include more than 8 bytes | ||
| 35 | * UDP datagrams are now sent via an UDP socket instead of magic | ||
| 36 | * RAW socket tricks. | ||
| 37 | * | ||
| 38 | * Converted to busybox applet by Leonid Lisovskiy <lly@sf.net> | ||
| 39 | * 2009-11-16 | ||
| 40 | */ | ||
| 41 | |||
| 42 | /* | ||
| 26 | * traceroute host - trace the route ip packets follow going to "host". | 43 | * traceroute host - trace the route ip packets follow going to "host". |
| 27 | * | 44 | * |
| 28 | * Attempt to trace the route an ip packet would follow to some | 45 | * Attempt to trace the route an ip packet would follow to some |
| @@ -231,7 +248,8 @@ | |||
| 231 | 248 | ||
| 232 | 249 | ||
| 233 | #define OPT_STRING "FIlnrdvxt:i:m:p:q:s:w:z:f:" \ | 250 | #define OPT_STRING "FIlnrdvxt:i:m:p:q:s:w:z:f:" \ |
| 234 | IF_FEATURE_TRACEROUTE_SOURCE_ROUTE("g:") | 251 | IF_FEATURE_TRACEROUTE_SOURCE_ROUTE("g:") \ |
| 252 | "4" IF_TRACEROUTE6("6") | ||
| 235 | enum { | 253 | enum { |
| 236 | OPT_DONT_FRAGMNT = (1 << 0), /* F */ | 254 | OPT_DONT_FRAGMNT = (1 << 0), /* F */ |
| 237 | OPT_USE_ICMP = (1 << 1) * ENABLE_FEATURE_TRACEROUTE_USE_ICMP, /* I */ | 255 | OPT_USE_ICMP = (1 << 1) * ENABLE_FEATURE_TRACEROUTE_USE_ICMP, /* I */ |
| @@ -250,6 +268,9 @@ enum { | |||
| 250 | OPT_WAITTIME = (1 << 14), /* w */ | 268 | OPT_WAITTIME = (1 << 14), /* w */ |
| 251 | OPT_PAUSE_MS = (1 << 15), /* z */ | 269 | OPT_PAUSE_MS = (1 << 15), /* z */ |
| 252 | OPT_FIRST_TTL = (1 << 16), /* f */ | 270 | OPT_FIRST_TTL = (1 << 16), /* f */ |
| 271 | OPT_SOURCE_ROUTE = (1 << 17) * ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE, /* g */ | ||
| 272 | OPT_IPV4 = (1 << (17+ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE)), /* 4 */ | ||
| 273 | OPT_IPV6 = (1 << (18+ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE)) * ENABLE_TRACEROUTE6, /* 6 */ | ||
| 253 | }; | 274 | }; |
| 254 | #define verbose (option_mask32 & OPT_VERBOSE) | 275 | #define verbose (option_mask32 & OPT_VERBOSE) |
| 255 | 276 | ||
| @@ -267,13 +288,21 @@ struct outdata_t { | |||
| 267 | struct timeval tv_UNUSED PACKED; /* time packet left */ | 288 | struct timeval tv_UNUSED PACKED; /* time packet left */ |
| 268 | }; | 289 | }; |
| 269 | 290 | ||
| 291 | #if ENABLE_TRACEROUTE6 | ||
| 292 | struct outdata6_t { | ||
| 293 | uint32_t ident6; | ||
| 294 | uint32_t seq6; | ||
| 295 | struct timeval tv_UNUSED PACKED; /* time packet left */ | ||
| 296 | }; | ||
| 297 | #endif | ||
| 298 | |||
| 270 | struct globals { | 299 | struct globals { |
| 271 | struct ip *outip; | 300 | struct ip *outip; |
| 272 | struct outdata_t *outdata; | 301 | struct outdata_t *outdata; |
| 273 | len_and_sockaddr *dest_lsa; | 302 | len_and_sockaddr *dest_lsa; |
| 274 | int packlen; /* total length of packet */ | 303 | int packlen; /* total length of packet */ |
| 275 | int pmtu; /* Path MTU Discovery (RFC1191) */ | 304 | int pmtu; /* Path MTU Discovery (RFC1191) */ |
| 276 | uint16_t ident; | 305 | uint32_t ident; |
| 277 | uint16_t port; // 32768 + 666; /* start udp dest port # for probe packets */ | 306 | uint16_t port; // 32768 + 666; /* start udp dest port # for probe packets */ |
| 278 | int waittime; // 5; /* time to wait for response (in seconds) */ | 307 | int waittime; // 5; /* time to wait for response (in seconds) */ |
| 279 | #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE | 308 | #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE |
| @@ -314,18 +343,30 @@ struct globals { | |||
| 314 | #define outudp ((struct udphdr *)(outip + 1)) | 343 | #define outudp ((struct udphdr *)(outip + 1)) |
| 315 | 344 | ||
| 316 | 345 | ||
| 346 | /* libbb candidate? tftp uses this idiom too */ | ||
| 347 | static len_and_sockaddr* dup_sockaddr(const len_and_sockaddr *lsa) | ||
| 348 | { | ||
| 349 | len_and_sockaddr *new_lsa = xzalloc(LSA_LEN_SIZE + lsa->len); | ||
| 350 | memcpy(new_lsa, lsa, LSA_LEN_SIZE + lsa->len); | ||
| 351 | return new_lsa; | ||
| 352 | } | ||
| 353 | |||
| 354 | |||
| 317 | static int | 355 | static int |
| 318 | wait_for_reply(struct sockaddr_in *fromp) | 356 | wait_for_reply(len_and_sockaddr *from_lsa, struct sockaddr *to) |
| 319 | { | 357 | { |
| 320 | struct pollfd pfd[1]; | 358 | struct pollfd pfd[1]; |
| 321 | int read_len = 0; | 359 | int read_len = 0; |
| 322 | socklen_t fromlen = sizeof(*fromp); | ||
| 323 | 360 | ||
| 324 | pfd[0].fd = rcvsock; | 361 | pfd[0].fd = rcvsock; |
| 325 | pfd[0].events = POLLIN; | 362 | pfd[0].events = POLLIN; |
| 326 | if (safe_poll(pfd, 1, waittime * 1000) > 0) | 363 | if (safe_poll(pfd, 1, waittime * 1000) > 0) { |
| 327 | read_len = recvfrom(rcvsock, recv_pkt, sizeof(recv_pkt), 0, | 364 | read_len = recv_from_to(rcvsock, |
| 328 | (struct sockaddr *)fromp, &fromlen); | 365 | recv_pkt, sizeof(recv_pkt), |
| 366 | /*flags:*/ 0, | ||
| 367 | &from_lsa->u.sa, to, from_lsa->len); | ||
| 368 | } | ||
| 369 | |||
| 329 | return read_len; | 370 | return read_len; |
| 330 | } | 371 | } |
| 331 | 372 | ||
| @@ -369,20 +410,30 @@ send_probe(int seq, int ttl) | |||
| 369 | void *out; | 410 | void *out; |
| 370 | 411 | ||
| 371 | /* Payload */ | 412 | /* Payload */ |
| 372 | outdata->seq = seq; | 413 | #if ENABLE_TRACEROUTE6 |
| 373 | outdata->ttl = ttl; | 414 | if (dest_lsa->u.sa.sa_family == AF_INET6) { |
| 415 | struct outdata6_t *pkt = (struct outdata6_t *) outip; | ||
| 416 | pkt->ident6 = htonl(ident); | ||
| 417 | pkt->seq6 = htonl(seq); | ||
| 418 | /*gettimeofday(&pkt->tv, &tz);*/ | ||
| 419 | } else | ||
| 420 | #endif | ||
| 421 | { | ||
| 422 | outdata->seq = seq; | ||
| 423 | outdata->ttl = ttl; | ||
| 374 | // UNUSED: was storing gettimeofday's result there, but never ever checked it | 424 | // UNUSED: was storing gettimeofday's result there, but never ever checked it |
| 375 | /*memcpy(&outdata->tv, tp, sizeof(outdata->tv));*/ | 425 | /*memcpy(&outdata->tv, tp, sizeof(outdata->tv));*/ |
| 376 | |||
| 377 | if (option_mask32 & OPT_USE_ICMP) { | ||
| 378 | outicmp->icmp_seq = htons(seq); | ||
| 379 | 426 | ||
| 380 | /* Always calculate checksum for icmp packets */ | 427 | if (option_mask32 & OPT_USE_ICMP) { |
| 381 | outicmp->icmp_cksum = 0; | 428 | outicmp->icmp_seq = htons(seq); |
| 382 | outicmp->icmp_cksum = in_cksum((uint16_t *)outicmp, | 429 | |
| 383 | packlen - (sizeof(*outip) + optlen)); | 430 | /* Always calculate checksum for icmp packets */ |
| 384 | if (outicmp->icmp_cksum == 0) | 431 | outicmp->icmp_cksum = 0; |
| 385 | outicmp->icmp_cksum = 0xffff; | 432 | outicmp->icmp_cksum = in_cksum((uint16_t *)outicmp, |
| 433 | packlen - (sizeof(*outip) + optlen)); | ||
| 434 | if (outicmp->icmp_cksum == 0) | ||
| 435 | outicmp->icmp_cksum = 0xffff; | ||
| 436 | } | ||
| 386 | } | 437 | } |
| 387 | 438 | ||
| 388 | //BUG! verbose is (x & OPT_VERBOSE), not a counter! | 439 | //BUG! verbose is (x & OPT_VERBOSE), not a counter! |
| @@ -411,21 +462,32 @@ send_probe(int seq, int ttl) | |||
| 411 | } | 462 | } |
| 412 | #endif | 463 | #endif |
| 413 | 464 | ||
| 465 | #if ENABLE_TRACEROUTE6 | ||
| 466 | if (dest_lsa->u.sa.sa_family == AF_INET6) { | ||
| 467 | res = setsockopt(sndsock, SOL_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)); | ||
| 468 | if (res < 0) | ||
| 469 | bb_perror_msg_and_die("setsockopt UNICAST_HOPS %d", ttl); | ||
| 470 | out = outip; | ||
| 471 | len = packlen; | ||
| 472 | } else | ||
| 473 | #endif | ||
| 474 | { | ||
| 414 | #if defined(IP_TTL) | 475 | #if defined(IP_TTL) |
| 415 | if (setsockopt(sndsock, IPPROTO_IP, IP_TTL, | 476 | if (setsockopt(sndsock, IPPROTO_IP, IP_TTL, |
| 416 | (char *)&ttl, sizeof(ttl)) < 0) { | 477 | (char *)&ttl, sizeof(ttl)) < 0) { |
| 417 | bb_perror_msg_and_die("setsockopt ttl %d", ttl); | 478 | bb_perror_msg_and_die("setsockopt ttl %d", ttl); |
| 418 | } | 479 | } |
| 419 | #endif | 480 | #endif |
| 420 | 481 | len = packlen - sizeof(*outip); | |
| 421 | len = packlen - sizeof(*outip); | 482 | if (option_mask32 & OPT_USE_ICMP) |
| 422 | if (option_mask32 & OPT_USE_ICMP) | 483 | out = outicmp; |
| 423 | out = outicmp; | 484 | else { |
| 424 | else { | 485 | out = outdata; |
| 425 | out = outdata; | 486 | len -= sizeof(*outudp); |
| 426 | len -= sizeof(*outudp); | 487 | set_nport(dest_lsa, htons(port + seq)); |
| 427 | set_nport(dest_lsa, htons(port + seq)); | 488 | } |
| 428 | } | 489 | } |
| 490 | |||
| 429 | res = xsendto(sndsock, out, len, &dest_lsa->u.sa, dest_lsa->len); | 491 | res = xsendto(sndsock, out, len, &dest_lsa->u.sa, dest_lsa->len); |
| 430 | if (res != len) { | 492 | if (res != len) { |
| 431 | bb_info_msg("sent %d octets, ret=%d", len, res); | 493 | bb_info_msg("sent %d octets, ret=%d", len, res); |
| @@ -436,7 +498,7 @@ send_probe(int seq, int ttl) | |||
| 436 | /* | 498 | /* |
| 437 | * Convert an ICMP "type" field to a printable string. | 499 | * Convert an ICMP "type" field to a printable string. |
| 438 | */ | 500 | */ |
| 439 | static inline const char * | 501 | static const char * |
| 440 | pr_type(unsigned char t) | 502 | pr_type(unsigned char t) |
| 441 | { | 503 | { |
| 442 | static const char *const ttab[] = { | 504 | static const char *const ttab[] = { |
| @@ -446,7 +508,23 @@ pr_type(unsigned char t) | |||
| 446 | "Param Problem", "Timestamp", "Timestamp Reply", "Info Request", | 508 | "Param Problem", "Timestamp", "Timestamp Reply", "Info Request", |
| 447 | "Info Reply", "Mask Request", "Mask Reply" | 509 | "Info Reply", "Mask Request", "Mask Reply" |
| 448 | }; | 510 | }; |
| 511 | # if ENABLE_TRACEROUTE6 | ||
| 512 | static const char *const ttab6[] = { | ||
| 513 | [0] "Error", "Dest Unreachable", "Packet Too Big", "Time Exceeded", | ||
| 514 | [4] "Param Problem", | ||
| 515 | [8] "Echo Request", "Echo Reply", "Membership Query", "Membership Report", | ||
| 516 | [12] "Membership Reduction", "Router Solicit", "Router Advert", "Neighbor Solicit", | ||
| 517 | [16] "Neighbor Advert", "Redirect", | ||
| 518 | }; | ||
| 449 | 519 | ||
| 520 | if (dest_lsa->u.sa.sa_family == AF_INET6) { | ||
| 521 | if (t < 5) | ||
| 522 | return ttab6[t]; | ||
| 523 | if (t < 128 || t > ND_REDIRECT) | ||
| 524 | return "OUT-OF-RANGE"; | ||
| 525 | return ttab6[(t & 63) + 8]; | ||
| 526 | } | ||
| 527 | # endif | ||
| 450 | if (t >= ARRAY_SIZE(ttab)) | 528 | if (t >= ARRAY_SIZE(ttab)) |
| 451 | return "OUT-OF-RANGE"; | 529 | return "OUT-OF-RANGE"; |
| 452 | 530 | ||
| @@ -455,11 +533,11 @@ pr_type(unsigned char t) | |||
| 455 | #endif | 533 | #endif |
| 456 | 534 | ||
| 457 | #if !ENABLE_FEATURE_TRACEROUTE_VERBOSE | 535 | #if !ENABLE_FEATURE_TRACEROUTE_VERBOSE |
| 458 | #define packet_ok(read_len, from, seq) \ | 536 | #define packet4_ok(read_len, from, seq) \ |
| 459 | packet_ok(read_len, seq) | 537 | packet4_ok(read_len, seq) |
| 460 | #endif | 538 | #endif |
| 461 | static int | 539 | static int |
| 462 | packet_ok(int read_len, const struct sockaddr_in *from, int seq) | 540 | packet4_ok(int read_len, const struct sockaddr_in *from, int seq) |
| 463 | { | 541 | { |
| 464 | const struct icmp *icp; | 542 | const struct icmp *icp; |
| 465 | unsigned char type, code; | 543 | unsigned char type, code; |
| @@ -502,7 +580,7 @@ packet_ok(int read_len, const struct sockaddr_in *from, int seq) | |||
| 502 | && icp->icmp_id == htons(ident) | 580 | && icp->icmp_id == htons(ident) |
| 503 | && icp->icmp_seq == htons(seq) | 581 | && icp->icmp_seq == htons(seq) |
| 504 | ) { | 582 | ) { |
| 505 | return -2; | 583 | return ICMP_UNREACH_PORT+1; |
| 506 | } | 584 | } |
| 507 | 585 | ||
| 508 | hicmp = (struct icmp *)((unsigned char *)hip + hlen); | 586 | hicmp = (struct icmp *)((unsigned char *)hip + hlen); |
| @@ -544,6 +622,98 @@ packet_ok(int read_len, const struct sockaddr_in *from, int seq) | |||
| 544 | return 0; | 622 | return 0; |
| 545 | } | 623 | } |
| 546 | 624 | ||
| 625 | #if ENABLE_TRACEROUTE6 | ||
| 626 | # if !ENABLE_FEATURE_TRACEROUTE_VERBOSE | ||
| 627 | #define packet_ok(read_len, from_lsa, to, seq) \ | ||
| 628 | packet_ok(read_len, from_lsa, seq) | ||
| 629 | # endif | ||
| 630 | static int | ||
| 631 | packet_ok(int read_len, len_and_sockaddr *from_lsa, | ||
| 632 | struct sockaddr *to, | ||
| 633 | int seq) | ||
| 634 | { | ||
| 635 | const struct icmp6_hdr *icp; | ||
| 636 | unsigned char type, code; | ||
| 637 | |||
| 638 | if (from_lsa->u.sa.sa_family == AF_INET) | ||
| 639 | return packet4_ok(read_len, &from_lsa->u.sin, seq); | ||
| 640 | |||
| 641 | icp = (struct icmp6_hdr *) recv_pkt; | ||
| 642 | |||
| 643 | type = icp->icmp6_type; | ||
| 644 | code = icp->icmp6_code; | ||
| 645 | |||
| 646 | if ((type == ICMP6_TIME_EXCEEDED && code == ICMP6_TIME_EXCEED_TRANSIT) | ||
| 647 | || type == ICMP6_DST_UNREACH | ||
| 648 | ) { | ||
| 649 | struct ip6_hdr *hip; | ||
| 650 | struct udphdr *up; | ||
| 651 | int nexthdr; | ||
| 652 | |||
| 653 | hip = (struct ip6_hdr *)(icp + 1); | ||
| 654 | up = (struct udphdr *) (hip + 1); | ||
| 655 | nexthdr = hip->ip6_nxt; | ||
| 656 | |||
| 657 | if (nexthdr == IPPROTO_FRAGMENT) { | ||
| 658 | nexthdr = *(unsigned char*)up; | ||
| 659 | up++; | ||
| 660 | } | ||
| 661 | if (nexthdr == IPPROTO_UDP) { | ||
| 662 | struct outdata6_t *pkt; | ||
| 663 | |||
| 664 | pkt = (struct outdata6_t *) (up + 1); | ||
| 665 | |||
| 666 | if (ntohl(pkt->ident6) == ident | ||
| 667 | && ntohl(pkt->seq6) == seq | ||
| 668 | ) { | ||
| 669 | return (type == ICMP6_TIME_EXCEEDED ? -1 : (code<<8)+1); | ||
| 670 | } | ||
| 671 | } | ||
| 672 | |||
| 673 | } | ||
| 674 | |||
| 675 | # if ENABLE_FEATURE_TRACEROUTE_VERBOSE | ||
| 676 | if (verbose) { | ||
| 677 | unsigned char *p; | ||
| 678 | char pa1[MAXHOSTNAMELEN]; | ||
| 679 | char pa2[MAXHOSTNAMELEN]; | ||
| 680 | int i; | ||
| 681 | |||
| 682 | p = (unsigned char *) (icp + 1); | ||
| 683 | |||
| 684 | printf("\n%d bytes from %s to " | ||
| 685 | "%s: icmp type %d (%s) code %d\n", | ||
| 686 | read_len, | ||
| 687 | inet_ntop(AF_INET6, &from_lsa->u.sin6.sin6_addr, pa1, sizeof(pa1)), | ||
| 688 | inet_ntop(AF_INET6, &((struct sockaddr_in6*)to)->sin6_addr, pa2, sizeof(pa2)), | ||
| 689 | type, pr_type(type), icp->icmp6_code); | ||
| 690 | |||
| 691 | read_len -= sizeof(struct icmp6_hdr); | ||
| 692 | for (i = 0; i < read_len ; i++) { | ||
| 693 | if (i % 16 == 0) | ||
| 694 | printf("%04x:", i); | ||
| 695 | if (i % 4 == 0) | ||
| 696 | bb_putchar(' '); | ||
| 697 | printf("%02x", p[i]); | ||
| 698 | if ((i % 16 == 15) && (i + 1 < read_len)) | ||
| 699 | bb_putchar('\n'); | ||
| 700 | } | ||
| 701 | bb_putchar('\n'); | ||
| 702 | } | ||
| 703 | # endif | ||
| 704 | |||
| 705 | return 0; | ||
| 706 | } | ||
| 707 | #else /* !ENABLE_TRACEROUTE6 */ | ||
| 708 | static ALWAYS_INLINE int | ||
| 709 | packet_ok(int read_len, len_and_sockaddr *from_lsa, | ||
| 710 | struct sockaddr *to UNUSED_PARAM, | ||
| 711 | int seq) | ||
| 712 | { | ||
| 713 | return packet4_ok(read_len, &from_lsa->u.sin, seq); | ||
| 714 | } | ||
| 715 | #endif | ||
| 716 | |||
| 547 | /* | 717 | /* |
| 548 | * Construct an Internet address representation. | 718 | * Construct an Internet address representation. |
| 549 | * If the -n flag has been supplied, give | 719 | * If the -n flag has been supplied, give |
| @@ -572,17 +742,22 @@ print_inetname(const struct sockaddr *from) | |||
| 572 | } | 742 | } |
| 573 | 743 | ||
| 574 | static void | 744 | static void |
| 575 | print(int read_len, const struct sockaddr_in *from) | 745 | print(int read_len, const struct sockaddr *from, const struct sockaddr *to) |
| 576 | { | 746 | { |
| 577 | print_inetname((const struct sockaddr*)from); | 747 | print_inetname(from); |
| 578 | if (verbose) { | ||
| 579 | const struct ip *ip; | ||
| 580 | int hlen; | ||
| 581 | 748 | ||
| 582 | ip = (struct ip *) recv_pkt; | 749 | if (verbose) { |
| 583 | hlen = ip->ip_hl << 2; | 750 | char *ina = xmalloc_sockaddr2dotted_noport(to); |
| 584 | read_len -= hlen; | 751 | #if ENABLE_TRACEROUTE6 |
| 585 | printf(" %d bytes to %s", read_len, inet_ntoa(ip->ip_dst)); | 752 | if (to->sa_family == AF_INET6) { |
| 753 | read_len -= sizeof(struct ip6_hdr); | ||
| 754 | } else | ||
| 755 | #endif | ||
| 756 | { | ||
| 757 | read_len -= ((struct ip*)recv_pkt)->ip_hl << 2; | ||
| 758 | } | ||
| 759 | printf(" %d bytes to %s", read_len, ina); | ||
| 760 | free(ina); | ||
| 586 | } | 761 | } |
| 587 | } | 762 | } |
| 588 | 763 | ||
| @@ -598,9 +773,8 @@ print_delta_ms(unsigned t1p, unsigned t2p) | |||
| 598 | * [-m max_ttl] [ -p port] [-q nqueries] [-s src_addr] [-t tos] | 773 | * [-m max_ttl] [ -p port] [-q nqueries] [-s src_addr] [-t tos] |
| 599 | * [-w waittime] [-z pausemsecs] host [packetlen]" | 774 | * [-w waittime] [-z pausemsecs] host [packetlen]" |
| 600 | */ | 775 | */ |
| 601 | 776 | static int | |
| 602 | int traceroute_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 777 | common_traceroute_main(int op, char **argv) |
| 603 | int traceroute_main(int argc UNUSED_PARAM, char **argv) | ||
| 604 | { | 778 | { |
| 605 | int i; | 779 | int i; |
| 606 | int minpacket; | 780 | int minpacket; |
| @@ -609,7 +783,6 @@ int traceroute_main(int argc UNUSED_PARAM, char **argv) | |||
| 609 | int nprobes = 3; | 783 | int nprobes = 3; |
| 610 | int first_ttl = 1; | 784 | int first_ttl = 1; |
| 611 | unsigned pausemsecs = 0; | 785 | unsigned pausemsecs = 0; |
| 612 | unsigned op; | ||
| 613 | char *source; | 786 | char *source; |
| 614 | char *device; | 787 | char *device; |
| 615 | char *tos_str; | 788 | char *tos_str; |
| @@ -623,20 +796,29 @@ int traceroute_main(int argc UNUSED_PARAM, char **argv) | |||
| 623 | llist_t *source_route_list = NULL; | 796 | llist_t *source_route_list = NULL; |
| 624 | int lsrr = 0; | 797 | int lsrr = 0; |
| 625 | #endif | 798 | #endif |
| 799 | #if ENABLE_TRACEROUTE6 | ||
| 800 | sa_family_t af = AF_UNSPEC; | ||
| 801 | #else | ||
| 802 | enum { af = AF_INET }; | ||
| 803 | #endif | ||
| 626 | int ttl; | 804 | int ttl; |
| 627 | int seq; | 805 | int seq; |
| 806 | len_and_sockaddr *from_lsa; | ||
| 807 | struct sockaddr *lastaddr; | ||
| 808 | struct sockaddr *to; | ||
| 628 | 809 | ||
| 629 | INIT_G(); | 810 | INIT_G(); |
| 630 | 811 | ||
| 631 | /* minimum 1 arg */ | 812 | /* minimum 1 arg */ |
| 632 | opt_complementary = "-1:x-x" IF_FEATURE_TRACEROUTE_SOURCE_ROUTE(":g::"); | 813 | opt_complementary = "-1:x-x" IF_FEATURE_TRACEROUTE_SOURCE_ROUTE(":g::"); |
| 633 | op = getopt32(argv, OPT_STRING | 814 | op |= getopt32(argv, OPT_STRING |
| 634 | , &tos_str, &device, &max_ttl_str, &port_str, &nprobes_str | 815 | , &tos_str, &device, &max_ttl_str, &port_str, &nprobes_str |
| 635 | , &source, &waittime_str, &pausemsecs_str, &first_ttl_str | 816 | , &source, &waittime_str, &pausemsecs_str, &first_ttl_str |
| 636 | #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE | 817 | #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE |
| 637 | , &source_route_list | 818 | , &source_route_list |
| 638 | #endif | 819 | #endif |
| 639 | ); | 820 | ); |
| 821 | argv += optind; | ||
| 640 | 822 | ||
| 641 | #if 0 /* IGNORED */ | 823 | #if 0 /* IGNORED */ |
| 642 | if (op & OPT_IP_CHKSUM) | 824 | if (op & OPT_IP_CHKSUM) |
| @@ -681,21 +863,53 @@ int traceroute_main(int argc UNUSED_PARAM, char **argv) | |||
| 681 | } | 863 | } |
| 682 | #endif | 864 | #endif |
| 683 | 865 | ||
| 684 | minpacket = sizeof(*outip) + SIZEOF_ICMP_HDR + sizeof(*outdata) + optlen; | 866 | #if ENABLE_TRACEROUTE6 |
| 685 | if (!(op & OPT_USE_ICMP)) | 867 | if (op & OPT_IPV4) |
| 686 | minpacket += sizeof(*outudp) - SIZEOF_ICMP_HDR; | 868 | af = AF_INET; |
| 869 | if (op & OPT_IPV6) { | ||
| 870 | af = AF_INET6; | ||
| 871 | minpacket = sizeof(struct outdata6_t); | ||
| 872 | } else | ||
| 873 | #endif | ||
| 874 | { | ||
| 875 | minpacket = sizeof(*outip) + SIZEOF_ICMP_HDR | ||
| 876 | + sizeof(*outdata) + optlen; | ||
| 877 | if (!(op & OPT_USE_ICMP)) | ||
| 878 | minpacket += sizeof(*outudp) - SIZEOF_ICMP_HDR; | ||
| 879 | } | ||
| 687 | packlen = minpacket; | 880 | packlen = minpacket; |
| 688 | 881 | ||
| 689 | /* Process destination and optional packet size */ | 882 | /* Process destination and optional packet size */ |
| 690 | argv += optind; | ||
| 691 | if (argv[1]) | 883 | if (argv[1]) |
| 692 | packlen = xatoul_range(argv[1], minpacket, 32 * 1024); | 884 | packlen = xatoul_range(argv[1], minpacket, 32 * 1024); |
| 885 | #if ENABLE_TRACEROUTE6 | ||
| 886 | dest_lsa = xhost_and_af2sockaddr(argv[0], port, af); | ||
| 887 | af = dest_lsa->u.sa.sa_family; | ||
| 888 | #else | ||
| 693 | dest_lsa = xhost2sockaddr(argv[0], port); | 889 | dest_lsa = xhost2sockaddr(argv[0], port); |
| 890 | #endif | ||
| 694 | 891 | ||
| 695 | /* Ensure the socket fds won't be 0, 1 or 2 */ | 892 | /* Ensure the socket fds won't be 0, 1 or 2 */ |
| 696 | bb_sanitize_stdio(); | 893 | bb_sanitize_stdio(); |
| 697 | 894 | ||
| 698 | xmove_fd(xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP), rcvsock); | 895 | #if ENABLE_TRACEROUTE6 |
| 896 | if (af == AF_INET6) { | ||
| 897 | xmove_fd(xsocket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6), rcvsock); | ||
| 898 | # ifdef IPV6_RECVPKTINFO | ||
| 899 | setsockopt(rcvsock, SOL_IPV6, IPV6_RECVPKTINFO, | ||
| 900 | &const_int_1, sizeof(const_int_1)); | ||
| 901 | setsockopt(rcvsock, SOL_IPV6, IPV6_2292PKTINFO, | ||
| 902 | &const_int_1, sizeof(const_int_1)); | ||
| 903 | # else | ||
| 904 | setsockopt(rcvsock, SOL_IPV6, IPV6_PKTINFO, | ||
| 905 | &const_int_1, sizeof(const_int_1)); | ||
| 906 | # endif | ||
| 907 | } else | ||
| 908 | #endif | ||
| 909 | { | ||
| 910 | xmove_fd(xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP), rcvsock); | ||
| 911 | } | ||
| 912 | |||
| 699 | #if TRACEROUTE_SO_DEBUG | 913 | #if TRACEROUTE_SO_DEBUG |
| 700 | if (op & OPT_DEBUG) | 914 | if (op & OPT_DEBUG) |
| 701 | setsockopt(rcvsock, SOL_SOCKET, SO_DEBUG, | 915 | setsockopt(rcvsock, SOL_SOCKET, SO_DEBUG, |
| @@ -705,34 +919,45 @@ int traceroute_main(int argc UNUSED_PARAM, char **argv) | |||
| 705 | setsockopt(rcvsock, SOL_SOCKET, SO_DONTROUTE, | 919 | setsockopt(rcvsock, SOL_SOCKET, SO_DONTROUTE, |
| 706 | &const_int_1, sizeof(const_int_1)); | 920 | &const_int_1, sizeof(const_int_1)); |
| 707 | 921 | ||
| 708 | if (op & OPT_USE_ICMP) | 922 | #if ENABLE_TRACEROUTE6 |
| 709 | xmove_fd(xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP), sndsock); | 923 | if (af == AF_INET6) { |
| 710 | else | 924 | static const int two = 2; |
| 711 | xmove_fd(xsocket(AF_INET, SOCK_DGRAM, 0), sndsock); | 925 | if (setsockopt(rcvsock, SOL_RAW, IPV6_CHECKSUM, &two, sizeof(two)) < 0) |
| 926 | bb_perror_msg_and_die("setsockopt RAW_CHECKSUM"); | ||
| 927 | xmove_fd(xsocket(af, SOCK_DGRAM, 0), sndsock); | ||
| 928 | } else | ||
| 929 | #endif | ||
| 930 | { | ||
| 931 | if (op & OPT_USE_ICMP) | ||
| 932 | xmove_fd(xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP), sndsock); | ||
| 933 | else | ||
| 934 | xmove_fd(xsocket(AF_INET, SOCK_DGRAM, 0), sndsock); | ||
| 712 | #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE && defined IP_OPTIONS | 935 | #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE && defined IP_OPTIONS |
| 713 | if (lsrr > 0) { | 936 | if (lsrr > 0) { |
| 714 | unsigned char optlist[MAX_IPOPTLEN]; | 937 | unsigned char optlist[MAX_IPOPTLEN]; |
| 715 | 938 | ||
| 716 | /* final hop */ | 939 | /* final hop */ |
| 717 | gwlist[lsrr] = dest_lsa->u.sin.sin_addr.s_addr; | 940 | gwlist[lsrr] = dest_lsa->u.sin.sin_addr.s_addr; |
| 718 | ++lsrr; | 941 | ++lsrr; |
| 719 | 942 | ||
| 720 | /* force 4 byte alignment */ | 943 | /* force 4 byte alignment */ |
| 721 | optlist[0] = IPOPT_NOP; | 944 | optlist[0] = IPOPT_NOP; |
| 722 | /* loose source route option */ | 945 | /* loose source route option */ |
| 723 | optlist[1] = IPOPT_LSRR; | 946 | optlist[1] = IPOPT_LSRR; |
| 724 | i = lsrr * sizeof(gwlist[0]); | 947 | i = lsrr * sizeof(gwlist[0]); |
| 725 | optlist[2] = i + 3; | 948 | optlist[2] = i + 3; |
| 726 | /* pointer to LSRR addresses */ | 949 | /* pointer to LSRR addresses */ |
| 727 | optlist[3] = IPOPT_MINOFF; | 950 | optlist[3] = IPOPT_MINOFF; |
| 728 | memcpy(optlist + 4, gwlist, i); | 951 | memcpy(optlist + 4, gwlist, i); |
| 729 | 952 | ||
| 730 | if (setsockopt(sndsock, IPPROTO_IP, IP_OPTIONS, | 953 | if (setsockopt(sndsock, IPPROTO_IP, IP_OPTIONS, |
| 731 | (char *)optlist, i + sizeof(gwlist[0])) < 0) { | 954 | (char *)optlist, i + sizeof(gwlist[0])) < 0) { |
| 732 | bb_perror_msg_and_die("IP_OPTIONS"); | 955 | bb_perror_msg_and_die("IP_OPTIONS"); |
| 956 | } | ||
| 733 | } | 957 | } |
| 734 | } | ||
| 735 | #endif | 958 | #endif |
| 959 | } | ||
| 960 | |||
| 736 | #ifdef SO_SNDBUF | 961 | #ifdef SO_SNDBUF |
| 737 | if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, &packlen, sizeof(packlen)) < 0) { | 962 | if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, &packlen, sizeof(packlen)) < 0) { |
| 738 | bb_perror_msg_and_die("SO_SNDBUF"); | 963 | bb_perror_msg_and_die("SO_SNDBUF"); |
| @@ -759,29 +984,66 @@ int traceroute_main(int argc UNUSED_PARAM, char **argv) | |||
| 759 | 984 | ||
| 760 | outip = xzalloc(packlen); | 985 | outip = xzalloc(packlen); |
| 761 | 986 | ||
| 762 | if (op & OPT_USE_ICMP) { | 987 | ident = getpid(); |
| 763 | ident = getpid() | 0x8000; | 988 | |
| 764 | outicmp->icmp_type = ICMP_ECHO; | 989 | if (af == AF_INET) { |
| 765 | outicmp->icmp_id = htons(ident); | 990 | if (op & OPT_USE_ICMP) { |
| 766 | outdata = (struct outdata_t *)((char *)outicmp + SIZEOF_ICMP_HDR); | 991 | ident |= 0x8000; |
| 767 | } else { | 992 | outicmp->icmp_type = ICMP_ECHO; |
| 768 | outdata = (struct outdata_t *)(outudp + 1); | 993 | outicmp->icmp_id = htons(ident); |
| 994 | outdata = (struct outdata_t *)((char *)outicmp + SIZEOF_ICMP_HDR); | ||
| 995 | } else { | ||
| 996 | outdata = (struct outdata_t *)(outudp + 1); | ||
| 997 | } | ||
| 769 | } | 998 | } |
| 770 | 999 | ||
| 771 | if (op & OPT_DEVICE) /* hmm, do we need error check? */ | 1000 | if (op & OPT_DEVICE) /* hmm, do we need error check? */ |
| 772 | setsockopt_bindtodevice(sndsock, device); | 1001 | setsockopt_bindtodevice(sndsock, device); |
| 773 | 1002 | ||
| 774 | if (op & OPT_SOURCE) { | 1003 | if (op & OPT_SOURCE) { |
| 1004 | #if ENABLE_TRACEROUTE6 | ||
| 1005 | // TODO: need xdotted_and_af2sockaddr? | ||
| 1006 | len_and_sockaddr *source_lsa = xhost_and_af2sockaddr(source, 0, af); | ||
| 1007 | #else | ||
| 775 | len_and_sockaddr *source_lsa = xdotted2sockaddr(source, 0); | 1008 | len_and_sockaddr *source_lsa = xdotted2sockaddr(source, 0); |
| 776 | /* Ping does this (why?) */ | 1009 | #endif |
| 777 | if (setsockopt(sndsock, IPPROTO_IP, IP_MULTICAST_IF, | 1010 | /* Ping4 does this (why?) */ |
| 778 | &source_lsa->u.sa, source_lsa->len)) | 1011 | if (af == AF_INET) |
| 779 | bb_error_msg_and_die("can't set multicast source interface"); | 1012 | if (setsockopt(sndsock, IPPROTO_IP, IP_MULTICAST_IF, |
| 1013 | &source_lsa->u.sa, source_lsa->len)) | ||
| 1014 | bb_error_msg_and_die("can't set multicast source interface"); | ||
| 780 | //TODO: we can query source port we bound to, | 1015 | //TODO: we can query source port we bound to, |
| 781 | // and check it in replies... if we care enough | 1016 | // and check it in replies... if we care enough |
| 782 | xbind(sndsock, &source_lsa->u.sa, source_lsa->len); | 1017 | xbind(sndsock, &source_lsa->u.sa, source_lsa->len); |
| 783 | free(source_lsa); | 1018 | free(source_lsa); |
| 784 | } | 1019 | } |
| 1020 | #if ENABLE_TRACEROUTE6 | ||
| 1021 | else if (af == AF_INET6) { | ||
| 1022 | //TODO: why we don't do it for IPv4? | ||
| 1023 | len_and_sockaddr *source_lsa; | ||
| 1024 | |||
| 1025 | int probe_fd = xsocket(af, SOCK_DGRAM, 0); | ||
| 1026 | if (op & OPT_DEVICE) | ||
| 1027 | setsockopt_bindtodevice(probe_fd, device); | ||
| 1028 | set_nport(dest_lsa, htons(1025)); | ||
| 1029 | /* dummy connect. makes kernel pick source IP (and port) */ | ||
| 1030 | xconnect(probe_fd, &dest_lsa->u.sa, dest_lsa->len); | ||
| 1031 | |||
| 1032 | /* read IP and port */ | ||
| 1033 | source_lsa = get_sock_lsa(probe_fd); | ||
| 1034 | if (source_lsa == NULL) | ||
| 1035 | bb_error_msg_and_die("can't get probe addr"); | ||
| 1036 | |||
| 1037 | close(probe_fd); | ||
| 1038 | |||
| 1039 | /* bind our sockets to this IP (but not port) */ | ||
| 1040 | set_nport(source_lsa, 0); | ||
| 1041 | xbind(sndsock, &source_lsa->u.sa, source_lsa->len); | ||
| 1042 | xbind(rcvsock, &source_lsa->u.sa, source_lsa->len); | ||
| 1043 | |||
| 1044 | free(source_lsa); | ||
| 1045 | } | ||
| 1046 | #endif | ||
| 785 | 1047 | ||
| 786 | /* Revert to non-privileged user after opening sockets */ | 1048 | /* Revert to non-privileged user after opening sockets */ |
| 787 | xsetgid(getgid()); | 1049 | xsetgid(getgid()); |
| @@ -793,11 +1055,11 @@ int traceroute_main(int argc UNUSED_PARAM, char **argv) | |||
| 793 | printf(" from %s", source); | 1055 | printf(" from %s", source); |
| 794 | printf(", %d hops max, %d byte packets\n", max_ttl, packlen); | 1056 | printf(", %d hops max, %d byte packets\n", max_ttl, packlen); |
| 795 | 1057 | ||
| 1058 | from_lsa = dup_sockaddr(dest_lsa); | ||
| 1059 | lastaddr = xzalloc(dest_lsa->len); | ||
| 1060 | to = xzalloc(dest_lsa->len); | ||
| 796 | seq = 0; | 1061 | seq = 0; |
| 797 | for (ttl = first_ttl; ttl <= max_ttl; ++ttl) { | 1062 | for (ttl = first_ttl; ttl <= max_ttl; ++ttl) { |
| 798 | //TODO: make it protocol agnostic (get rid of sockaddr_in) | ||
| 799 | struct sockaddr_in from; | ||
| 800 | uint32_t lastaddr = 0; | ||
| 801 | int probe; | 1063 | int probe; |
| 802 | int unreachable = 0; /* counter */ | 1064 | int unreachable = 0; /* counter */ |
| 803 | int gotlastaddr = 0; /* flags */ | 1065 | int gotlastaddr = 0; /* flags */ |
| @@ -819,44 +1081,55 @@ int traceroute_main(int argc UNUSED_PARAM, char **argv) | |||
| 819 | send_probe(++seq, ttl); | 1081 | send_probe(++seq, ttl); |
| 820 | 1082 | ||
| 821 | first = 0; | 1083 | first = 0; |
| 822 | while ((read_len = wait_for_reply(&from)) != 0) { | 1084 | while ((read_len = wait_for_reply(from_lsa, to)) != 0) { |
| 823 | t2 = monotonic_us(); | 1085 | t2 = monotonic_us(); |
| 824 | i = packet_ok(read_len, &from, seq); | 1086 | i = packet_ok(read_len, from_lsa, to, seq); |
| 825 | /* Skip short packet */ | 1087 | /* Skip short packet */ |
| 826 | if (i == 0) | 1088 | if (i == 0) |
| 827 | continue; | 1089 | continue; |
| 1090 | |||
| 828 | if (!gotlastaddr | 1091 | if (!gotlastaddr |
| 829 | || from.sin_addr.s_addr != lastaddr | 1092 | || (memcmp(lastaddr, &from_lsa->u.sa, from_lsa->len) != 0) |
| 830 | ) { | 1093 | ) { |
| 831 | print(read_len, &from); | 1094 | print(read_len, &from_lsa->u.sa, to); |
| 832 | lastaddr = from.sin_addr.s_addr; | 1095 | memcpy(lastaddr, &from_lsa->u.sa, from_lsa->len); |
| 833 | gotlastaddr = 1; | 1096 | gotlastaddr = 1; |
| 834 | } | 1097 | } |
| 1098 | |||
| 835 | print_delta_ms(t1, t2); | 1099 | print_delta_ms(t1, t2); |
| 836 | ip = (struct ip *)recv_pkt; | 1100 | ip = (struct ip *)recv_pkt; |
| 837 | if (op & OPT_TTL_FLAG) | 1101 | |
| 838 | printf(" (%d)", ip->ip_ttl); | 1102 | if (from_lsa->u.sa.sa_family == AF_INET) |
| 839 | if (i == -2) { | 1103 | if (op & OPT_TTL_FLAG) |
| 840 | if (ip->ip_ttl <= 1) | 1104 | printf(" (%d)", ip->ip_ttl); |
| 841 | printf(" !"); | 1105 | |
| 842 | got_there = 1; | ||
| 843 | break; | ||
| 844 | } | ||
| 845 | /* time exceeded in transit */ | 1106 | /* time exceeded in transit */ |
| 846 | if (i == -1) | 1107 | if (i == -1) |
| 847 | break; | 1108 | break; |
| 848 | i--; | 1109 | i--; |
| 849 | switch (i) { | 1110 | switch (i) { |
| 1111 | #if ENABLE_TRACEROUTE6 | ||
| 1112 | case ICMP6_DST_UNREACH_NOPORT << 8: | ||
| 1113 | got_there = 1; | ||
| 1114 | break; | ||
| 1115 | #endif | ||
| 850 | case ICMP_UNREACH_PORT: | 1116 | case ICMP_UNREACH_PORT: |
| 851 | if (ip->ip_ttl <= 1) | 1117 | if (ip->ip_ttl <= 1) |
| 852 | printf(" !"); | 1118 | printf(" !"); |
| 853 | got_there = 1; | 1119 | got_there = 1; |
| 854 | break; | 1120 | break; |
| 1121 | |||
| 855 | case ICMP_UNREACH_NET: | 1122 | case ICMP_UNREACH_NET: |
| 1123 | #if ENABLE_TRACEROUTE6 && (ICMP6_DST_UNREACH_NOROUTE != ICMP_UNREACH_NET) | ||
| 1124 | case ICMP6_DST_UNREACH_NOROUTE << 8: | ||
| 1125 | #endif | ||
| 856 | printf(" !N"); | 1126 | printf(" !N"); |
| 857 | ++unreachable; | 1127 | ++unreachable; |
| 858 | break; | 1128 | break; |
| 859 | case ICMP_UNREACH_HOST: | 1129 | case ICMP_UNREACH_HOST: |
| 1130 | #if ENABLE_TRACEROUTE6 | ||
| 1131 | case ICMP6_DST_UNREACH_ADDR << 8: | ||
| 1132 | #endif | ||
| 860 | printf(" !H"); | 1133 | printf(" !H"); |
| 861 | ++unreachable; | 1134 | ++unreachable; |
| 862 | break; | 1135 | break; |
| @@ -869,6 +1142,9 @@ int traceroute_main(int argc UNUSED_PARAM, char **argv) | |||
| 869 | ++unreachable; | 1142 | ++unreachable; |
| 870 | break; | 1143 | break; |
| 871 | case ICMP_UNREACH_SRCFAIL: | 1144 | case ICMP_UNREACH_SRCFAIL: |
| 1145 | #if ENABLE_TRACEROUTE6 | ||
| 1146 | case ICMP6_DST_UNREACH_ADMIN << 8: | ||
| 1147 | #endif | ||
| 872 | printf(" !S"); | 1148 | printf(" !S"); |
| 873 | ++unreachable; | 1149 | ++unreachable; |
| 874 | break; | 1150 | break; |
| @@ -924,3 +1200,17 @@ int traceroute_main(int argc UNUSED_PARAM, char **argv) | |||
| 924 | 1200 | ||
| 925 | return 0; | 1201 | return 0; |
| 926 | } | 1202 | } |
| 1203 | |||
| 1204 | int traceroute_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
| 1205 | int traceroute_main(int argc UNUSED_PARAM, char **argv) | ||
| 1206 | { | ||
| 1207 | return common_traceroute_main(0, argv); | ||
| 1208 | } | ||
| 1209 | |||
| 1210 | #if ENABLE_TRACEROUTE6 | ||
| 1211 | int traceroute6_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
| 1212 | int traceroute6_main(int argc UNUSED_PARAM, char **argv) | ||
| 1213 | { | ||
| 1214 | return common_traceroute_main(OPT_IPV6, argv); | ||
| 1215 | } | ||
| 1216 | #endif | ||
