diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2020-12-12 16:38:43 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2020-12-12 18:09:45 +0100 |
commit | 3978adc4458eccfcd3720a6ec1199b255156e344 (patch) | |
tree | 955421d7fda3cc2a5b3c78de75ef3968d2a7a6d1 | |
parent | ef2366cdca45941f943f4970ac57a4008181fca9 (diff) | |
download | busybox-w32-3978adc4458eccfcd3720a6ec1199b255156e344.tar.gz busybox-w32-3978adc4458eccfcd3720a6ec1199b255156e344.tar.bz2 busybox-w32-3978adc4458eccfcd3720a6ec1199b255156e344.zip |
traceroute: fix traceroute6 -I (icmp mode)
function old new delta
common_traceroute_main 3530 3544 +14
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | networking/traceroute.c | 206 |
1 files changed, 135 insertions, 71 deletions
diff --git a/networking/traceroute.c b/networking/traceroute.c index 7dde10524..ddde922bf 100644 --- a/networking/traceroute.c +++ b/networking/traceroute.c | |||
@@ -414,9 +414,32 @@ struct globals { | |||
414 | waittime = 5; \ | 414 | waittime = 5; \ |
415 | } while (0) | 415 | } while (0) |
416 | 416 | ||
417 | #define outicmp ((struct icmp *)(outip + 1)) | 417 | #define outudp ((struct udphdr *)(outip + 1)) |
418 | #define outudp ((struct udphdr *)(outip + 1)) | 418 | #define outudp6 ((struct udphdr *)(((struct ip6_hdr*)outip) + 1)) |
419 | 419 | #define outicmp ((struct icmp *)(outip + 1)) | |
420 | #define outicmp6 ((struct icmp *)(((struct ip6_hdr*)outip) + 1)) | ||
421 | /* NB: for icmp echo, IPv4 and IPv6 fields are the same size and offset: | ||
422 | * struct icmp: | ||
423 | * uint8_t icmp_type; | ||
424 | * uint8_t icmp_code; | ||
425 | * uint16_t icmp_cksum; | ||
426 | * uint16_t icmp_id; | ||
427 | * uint16_t icmp_seq; | ||
428 | * struct icmp6_hdr: | ||
429 | * uint8_t icmp6_type; | ||
430 | * uint8_t icmp6_code; | ||
431 | * uint16_t icmp6_cksum; | ||
432 | * uint16_t icmp6_id; | ||
433 | * uint16_t icmp6_seq; | ||
434 | * therefore both outicmp and outicmp6 are pointers to *IPv4* icmp struct. | ||
435 | * SIZEOF_ICMP_HDR == 8 is the same for both, as well. | ||
436 | * However, values of these pointers are not the same (since IPv6 IP header is larger), | ||
437 | * and icmp_type constants are not the same: | ||
438 | * #define ICMP_ECHO 8 | ||
439 | * #define ICMP_ECHOREPLY 0 | ||
440 | * #define ICMP6_ECHO_REQUEST 128 | ||
441 | * #define ICMP6_ECHO_REPLY 129 | ||
442 | */ | ||
420 | 443 | ||
421 | static int | 444 | static int |
422 | wait_for_reply(len_and_sockaddr *from_lsa, struct sockaddr *to, unsigned *timestamp_us, int *left_ms) | 445 | wait_for_reply(len_and_sockaddr *from_lsa, struct sockaddr *to, unsigned *timestamp_us, int *left_ms) |
@@ -446,14 +469,16 @@ send_probe(int seq, int ttl) | |||
446 | { | 469 | { |
447 | int len, res; | 470 | int len, res; |
448 | void *out; | 471 | void *out; |
472 | struct icmp *icp; | ||
449 | 473 | ||
450 | /* Payload */ | 474 | /* Payload */ |
451 | #if ENABLE_TRACEROUTE6 | 475 | #if ENABLE_TRACEROUTE6 |
452 | if (dest_lsa->u.sa.sa_family == AF_INET6) { | 476 | if (dest_lsa->u.sa.sa_family == AF_INET6) { |
453 | struct outdata6_t *pkt = (struct outdata6_t *) outdata; | 477 | struct outdata6_t *pkt = (void *) outdata; |
454 | pkt->ident6 = htonl(ident); | 478 | pkt->ident6 = htonl(ident); |
455 | pkt->seq6 = htonl(seq); | 479 | pkt->seq6 = htonl(seq); |
456 | /*gettimeofday(&pkt->tv, &tz);*/ | 480 | /*gettimeofday(&pkt->tv, &tz);*/ |
481 | icp = outicmp6; | ||
457 | } else | 482 | } else |
458 | #endif | 483 | #endif |
459 | { | 484 | { |
@@ -461,19 +486,23 @@ send_probe(int seq, int ttl) | |||
461 | outdata->ttl = ttl; | 486 | outdata->ttl = ttl; |
462 | // UNUSED: was storing gettimeofday's result there, but never ever checked it | 487 | // UNUSED: was storing gettimeofday's result there, but never ever checked it |
463 | /*memcpy(&outdata->tv, tp, sizeof(outdata->tv));*/ | 488 | /*memcpy(&outdata->tv, tp, sizeof(outdata->tv));*/ |
464 | 489 | icp = outicmp; | |
465 | if (option_mask32 & OPT_USE_ICMP) { | 490 | } |
466 | outicmp->icmp_seq = htons(seq); | 491 | out = outdata; |
467 | 492 | if (option_mask32 & OPT_USE_ICMP) { | |
468 | /* Always calculate checksum for icmp packets */ | 493 | out = icp; |
469 | outicmp->icmp_cksum = 0; | 494 | /*icp->icmp_type = ICMP[6]_ECHO; - already set */ |
470 | outicmp->icmp_cksum = inet_cksum( | 495 | /*icp->icmp_code = 0; - already set */ |
471 | outicmp, | 496 | /*icp->icmp_id = ident; - already set */ |
472 | ((char*)outip + packlen) - (char*)outicmp | 497 | icp->icmp_seq = htons(seq); |
473 | ); | 498 | /* Always calculate checksum for icmp packets */ |
474 | if (outicmp->icmp_cksum == 0) | 499 | icp->icmp_cksum = 0; |
475 | outicmp->icmp_cksum = 0xffff; | 500 | icp->icmp_cksum = inet_cksum( |
476 | } | 501 | icp, |
502 | ((char*)outip + packlen) - (char*)icp | ||
503 | ); | ||
504 | if (icp->icmp_cksum == 0) | ||
505 | icp->icmp_cksum = 0xffff; | ||
477 | } | 506 | } |
478 | 507 | ||
479 | //BUG! verbose is (x & OPT_VERBOSE), not a counter! | 508 | //BUG! verbose is (x & OPT_VERBOSE), not a counter! |
@@ -502,7 +531,6 @@ send_probe(int seq, int ttl) | |||
502 | } | 531 | } |
503 | #endif | 532 | #endif |
504 | 533 | ||
505 | out = outdata; | ||
506 | #if ENABLE_TRACEROUTE6 | 534 | #if ENABLE_TRACEROUTE6 |
507 | if (dest_lsa->u.sa.sa_family == AF_INET6) { | 535 | if (dest_lsa->u.sa.sa_family == AF_INET6) { |
508 | res = setsockopt_int(sndsock, SOL_IPV6, IPV6_UNICAST_HOPS, ttl); | 536 | res = setsockopt_int(sndsock, SOL_IPV6, IPV6_UNICAST_HOPS, ttl); |
@@ -516,8 +544,6 @@ send_probe(int seq, int ttl) | |||
516 | if (res != 0) | 544 | if (res != 0) |
517 | bb_perror_msg_and_die("setsockopt(%s) %d", "TTL", ttl); | 545 | bb_perror_msg_and_die("setsockopt(%s) %d", "TTL", ttl); |
518 | #endif | 546 | #endif |
519 | if (option_mask32 & OPT_USE_ICMP) | ||
520 | out = outicmp; | ||
521 | } | 547 | } |
522 | 548 | ||
523 | if (!(option_mask32 & OPT_USE_ICMP)) { | 549 | if (!(option_mask32 & OPT_USE_ICMP)) { |
@@ -579,7 +605,12 @@ packet4_ok(int read_len, const struct sockaddr_in *from, int seq) | |||
579 | int hlen; | 605 | int hlen; |
580 | const struct ip *ip; | 606 | const struct ip *ip; |
581 | 607 | ||
608 | /* NB: reads from (AF_INET, SOCK_RAW, IPPROTO_ICMP) socket | ||
609 | * return the entire IP packet (IOW: they do not strip IP header). | ||
610 | * This differs from (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6) sockets!? | ||
611 | */ | ||
582 | ip = (struct ip *) recv_pkt; | 612 | ip = (struct ip *) recv_pkt; |
613 | |||
583 | hlen = ip->ip_hl << 2; | 614 | hlen = ip->ip_hl << 2; |
584 | if (read_len < hlen + ICMP_MINLEN) { | 615 | if (read_len < hlen + ICMP_MINLEN) { |
585 | #if ENABLE_FEATURE_TRACEROUTE_VERBOSE | 616 | #if ENABLE_FEATURE_TRACEROUTE_VERBOSE |
@@ -598,9 +629,20 @@ packet4_ok(int read_len, const struct sockaddr_in *from, int seq) | |||
598 | if (code == ICMP_UNREACH_NEEDFRAG) | 629 | if (code == ICMP_UNREACH_NEEDFRAG) |
599 | pmtu = ntohs(icp->icmp_nextmtu); | 630 | pmtu = ntohs(icp->icmp_nextmtu); |
600 | 631 | ||
632 | if ((option_mask32 & OPT_USE_ICMP) | ||
633 | && type == ICMP_ECHOREPLY | ||
634 | && icp->icmp_id == htons(ident) | ||
635 | && icp->icmp_seq == htons(seq) | ||
636 | ) { | ||
637 | /* In UDP mode, when we reach the machine, we (usually) | ||
638 | * would get "port unreachable" - in ICMP we got "echo reply". | ||
639 | * Simulate "port unreachable" for caller: | ||
640 | */ | ||
641 | return ICMP_UNREACH_PORT+1; | ||
642 | } | ||
643 | |||
601 | if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) | 644 | if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) |
602 | || type == ICMP_UNREACH | 645 | || type == ICMP_UNREACH |
603 | || type == ICMP_ECHOREPLY | ||
604 | ) { | 646 | ) { |
605 | const struct ip *hip; | 647 | const struct ip *hip; |
606 | const struct udphdr *up; | 648 | const struct udphdr *up; |
@@ -610,14 +652,6 @@ packet4_ok(int read_len, const struct sockaddr_in *from, int seq) | |||
610 | if (option_mask32 & OPT_USE_ICMP) { | 652 | if (option_mask32 & OPT_USE_ICMP) { |
611 | struct icmp *hicmp; | 653 | struct icmp *hicmp; |
612 | 654 | ||
613 | /* XXX */ | ||
614 | if (type == ICMP_ECHOREPLY | ||
615 | && icp->icmp_id == htons(ident) | ||
616 | && icp->icmp_seq == htons(seq) | ||
617 | ) { | ||
618 | return ICMP_UNREACH_PORT+1; | ||
619 | } | ||
620 | |||
621 | hicmp = (struct icmp *)((unsigned char *)hip + hlen); | 655 | hicmp = (struct icmp *)((unsigned char *)hip + hlen); |
622 | if (hlen + SIZEOF_ICMP_HDR <= read_len | 656 | if (hlen + SIZEOF_ICMP_HDR <= read_len |
623 | && hip->ip_p == IPPROTO_ICMP | 657 | && hip->ip_p == IPPROTO_ICMP |
@@ -648,6 +682,7 @@ packet4_ok(int read_len, const struct sockaddr_in *from, int seq) | |||
648 | printf("\n%d bytes from %s to " | 682 | printf("\n%d bytes from %s to " |
649 | "%s: icmp type %d (%s) code %d\n", | 683 | "%s: icmp type %d (%s) code %d\n", |
650 | read_len, inet_ntoa(from->sin_addr), | 684 | read_len, inet_ntoa(from->sin_addr), |
685 | //BUG: inet_ntoa() returns static buf! x2 is NONO! | ||
651 | inet_ntoa(ip->ip_dst), | 686 | inet_ntoa(ip->ip_dst), |
652 | type, pr_type(type), icp->icmp_code); | 687 | type, pr_type(type), icp->icmp_code); |
653 | for (i = 4; i < read_len; i += sizeof(*lp)) | 688 | for (i = 4; i < read_len; i += sizeof(*lp)) |
@@ -673,11 +708,27 @@ packet_ok(int read_len, len_and_sockaddr *from_lsa, | |||
673 | if (from_lsa->u.sa.sa_family == AF_INET) | 708 | if (from_lsa->u.sa.sa_family == AF_INET) |
674 | return packet4_ok(read_len, &from_lsa->u.sin, seq); | 709 | return packet4_ok(read_len, &from_lsa->u.sin, seq); |
675 | 710 | ||
711 | /* NB: reads from (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6) socket | ||
712 | * return only ICMP packet (IOW: they strip IPv6 header). | ||
713 | * This differs from (AF_INET, SOCK_RAW, IPPROTO_ICMP) sockets!? | ||
714 | */ | ||
676 | icp = (struct icmp6_hdr *) recv_pkt; | 715 | icp = (struct icmp6_hdr *) recv_pkt; |
677 | 716 | ||
678 | type = icp->icmp6_type; | 717 | type = icp->icmp6_type; |
679 | code = icp->icmp6_code; | 718 | code = icp->icmp6_code; |
680 | 719 | ||
720 | if ((option_mask32 & OPT_USE_ICMP) | ||
721 | && type == ICMP6_ECHO_REPLY | ||
722 | && icp->icmp6_id == htons(ident) | ||
723 | && icp->icmp6_seq == htons(seq) | ||
724 | ) { | ||
725 | /* In UDP mode, when we reach the machine, we (usually) | ||
726 | * would get "port unreachable" - in ICMP we got "echo reply". | ||
727 | * Simulate "port unreachable" for caller: | ||
728 | */ | ||
729 | return (ICMP6_DST_UNREACH_NOPORT << 8) + 1; | ||
730 | } | ||
731 | |||
681 | if ((type == ICMP6_TIME_EXCEEDED && code == ICMP6_TIME_EXCEED_TRANSIT) | 732 | if ((type == ICMP6_TIME_EXCEEDED && code == ICMP6_TIME_EXCEED_TRANSIT) |
682 | || type == ICMP6_DST_UNREACH | 733 | || type == ICMP6_DST_UNREACH |
683 | ) { | 734 | ) { |
@@ -787,8 +838,13 @@ print(int read_len, const struct sockaddr *from, const struct sockaddr *to) | |||
787 | if (verbose) { | 838 | if (verbose) { |
788 | char *ina = xmalloc_sockaddr2dotted_noport(to); | 839 | char *ina = xmalloc_sockaddr2dotted_noport(to); |
789 | #if ENABLE_TRACEROUTE6 | 840 | #if ENABLE_TRACEROUTE6 |
841 | /* NB: reads from (AF_INET, SOCK_RAW, IPPROTO_ICMP) socket | ||
842 | * return the entire IP packet (IOW: they do not strip IP header). | ||
843 | * Reads from (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6) do strip IPv6 | ||
844 | * header and return only ICMP6 packet. Weird. | ||
845 | */ | ||
790 | if (to->sa_family == AF_INET6) { | 846 | if (to->sa_family == AF_INET6) { |
791 | read_len -= sizeof(struct ip6_hdr); | 847 | /* read_len -= sizeof(struct ip6_hdr); - WRONG! */ |
792 | } else | 848 | } else |
793 | #endif | 849 | #endif |
794 | { | 850 | { |
@@ -844,6 +900,9 @@ common_traceroute_main(int op, char **argv) | |||
844 | struct sockaddr *lastaddr; | 900 | struct sockaddr *lastaddr; |
845 | struct sockaddr *to; | 901 | struct sockaddr *to; |
846 | 902 | ||
903 | /* Ensure the socket fds won't be 0, 1 or 2 */ | ||
904 | bb_sanitize_stdio(); | ||
905 | |||
847 | INIT_G(); | 906 | INIT_G(); |
848 | 907 | ||
849 | op |= getopt32(argv, "^" | 908 | op |= getopt32(argv, "^" |
@@ -885,12 +944,14 @@ common_traceroute_main(int op, char **argv) | |||
885 | 944 | ||
886 | /* Process destination and optional packet size */ | 945 | /* Process destination and optional packet size */ |
887 | minpacket = sizeof(struct ip) | 946 | minpacket = sizeof(struct ip) |
888 | + SIZEOF_ICMP_HDR | 947 | + sizeof(struct udphdr) |
889 | + sizeof(struct outdata_t); | 948 | + sizeof(struct outdata_t); |
890 | if (!(op & OPT_USE_ICMP)) | 949 | if (op & OPT_USE_ICMP) { |
891 | minpacket = sizeof(struct ip) | 950 | minpacket = sizeof(struct ip) |
892 | + sizeof(struct udphdr) | 951 | + SIZEOF_ICMP_HDR |
893 | + sizeof(struct outdata_t); | 952 | + sizeof(struct outdata_t); |
953 | port = 0; /* on ICMP6 sockets, sendto(ipv6.nonzero_port) throws EINVAL */ | ||
954 | } | ||
894 | #if ENABLE_TRACEROUTE6 | 955 | #if ENABLE_TRACEROUTE6 |
895 | af = AF_UNSPEC; | 956 | af = AF_UNSPEC; |
896 | if (op & OPT_IPV4) | 957 | if (op & OPT_IPV4) |
@@ -899,10 +960,15 @@ common_traceroute_main(int op, char **argv) | |||
899 | af = AF_INET6; | 960 | af = AF_INET6; |
900 | dest_lsa = xhost_and_af2sockaddr(argv[0], port, af); | 961 | dest_lsa = xhost_and_af2sockaddr(argv[0], port, af); |
901 | af = dest_lsa->u.sa.sa_family; | 962 | af = dest_lsa->u.sa.sa_family; |
902 | if (af == AF_INET6) | 963 | if (af == AF_INET6) { |
903 | minpacket = sizeof(struct ip6_hdr) | 964 | minpacket = sizeof(struct ip6_hdr) |
904 | + sizeof(struct udphdr) | 965 | + sizeof(struct udphdr) |
905 | + sizeof(struct outdata6_t); | 966 | + sizeof(struct outdata6_t); |
967 | if (op & OPT_USE_ICMP) | ||
968 | minpacket = sizeof(struct ip6_hdr) | ||
969 | + SIZEOF_ICMP_HDR | ||
970 | + sizeof(struct outdata6_t); | ||
971 | } | ||
906 | #else | 972 | #else |
907 | dest_lsa = xhost2sockaddr(argv[0], port); | 973 | dest_lsa = xhost2sockaddr(argv[0], port); |
908 | #endif | 974 | #endif |
@@ -910,13 +976,10 @@ common_traceroute_main(int op, char **argv) | |||
910 | if (argv[1]) | 976 | if (argv[1]) |
911 | packlen = xatoul_range(argv[1], minpacket, 32 * 1024); | 977 | packlen = xatoul_range(argv[1], minpacket, 32 * 1024); |
912 | 978 | ||
913 | /* Ensure the socket fds won't be 0, 1 or 2 */ | ||
914 | bb_sanitize_stdio(); | ||
915 | |||
916 | #if ENABLE_TRACEROUTE6 | 979 | #if ENABLE_TRACEROUTE6 |
917 | if (af == AF_INET6) { | 980 | if (af == AF_INET6) { |
918 | xmove_fd(xsocket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6), rcvsock); | 981 | xmove_fd(xsocket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6), rcvsock); |
919 | setsockopt_1(rcvsock, SOL_IPV6, IPV6_RECVPKTINFO); | 982 | setsockopt_1(rcvsock, SOL_IPV6, IPV6_RECVPKTINFO); //why? |
920 | } else | 983 | } else |
921 | #endif | 984 | #endif |
922 | { | 985 | { |
@@ -934,7 +997,10 @@ common_traceroute_main(int op, char **argv) | |||
934 | if (af == AF_INET6) { | 997 | if (af == AF_INET6) { |
935 | if (setsockopt_int(rcvsock, SOL_RAW, IPV6_CHECKSUM, 2) != 0) | 998 | if (setsockopt_int(rcvsock, SOL_RAW, IPV6_CHECKSUM, 2) != 0) |
936 | bb_perror_msg_and_die("setsockopt(%s)", "IPV6_CHECKSUM"); | 999 | bb_perror_msg_and_die("setsockopt(%s)", "IPV6_CHECKSUM"); |
937 | xmove_fd(xsocket(af, SOCK_DGRAM, 0), sndsock); | 1000 | if (op & OPT_USE_ICMP) |
1001 | xmove_fd(xsocket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6), sndsock); | ||
1002 | else | ||
1003 | xmove_fd(xsocket(AF_INET6, SOCK_DGRAM, 0), sndsock); | ||
938 | } else | 1004 | } else |
939 | #endif | 1005 | #endif |
940 | { | 1006 | { |
@@ -943,6 +1009,7 @@ common_traceroute_main(int op, char **argv) | |||
943 | else | 1009 | else |
944 | xmove_fd(xsocket(AF_INET, SOCK_DGRAM, 0), sndsock); | 1010 | xmove_fd(xsocket(AF_INET, SOCK_DGRAM, 0), sndsock); |
945 | } | 1011 | } |
1012 | //TODO xmove_fd to here! | ||
946 | 1013 | ||
947 | #ifdef SO_SNDBUF | 1014 | #ifdef SO_SNDBUF |
948 | if (setsockopt_SOL_SOCKET_int(sndsock, SO_SNDBUF, packlen) != 0) { | 1015 | if (setsockopt_SOL_SOCKET_int(sndsock, SO_SNDBUF, packlen) != 0) { |
@@ -970,21 +1037,25 @@ common_traceroute_main(int op, char **argv) | |||
970 | ident = getpid(); | 1037 | ident = getpid(); |
971 | 1038 | ||
972 | if (!ENABLE_TRACEROUTE6 || af == AF_INET) { | 1039 | if (!ENABLE_TRACEROUTE6 || af == AF_INET) { |
1040 | outdata = (void*)(outudp + 1); | ||
973 | if (op & OPT_USE_ICMP) { | 1041 | if (op & OPT_USE_ICMP) { |
974 | ident |= 0x8000; | 1042 | ident |= 0x8000; |
975 | outicmp->icmp_type = ICMP_ECHO; | 1043 | outicmp->icmp_type = ICMP_ECHO; |
1044 | /*outicmp->icmp_code = 0; - set by xzalloc */ | ||
976 | outicmp->icmp_id = htons(ident); | 1045 | outicmp->icmp_id = htons(ident); |
977 | outdata = (struct outdata_t *)((char *)outicmp + SIZEOF_ICMP_HDR); | 1046 | outdata = (void*)((char *)outicmp + SIZEOF_ICMP_HDR); |
978 | } else { | ||
979 | outdata = (struct outdata_t *)(outudp + 1); | ||
980 | } | 1047 | } |
981 | } | 1048 | } |
982 | #if ENABLE_TRACEROUTE6 | 1049 | #if ENABLE_TRACEROUTE6 |
983 | if (af == AF_INET6) { | 1050 | if (af == AF_INET6) { |
984 | outdata = (void*)((char*)outip | 1051 | outdata = (void*)(outudp6 + 1); |
985 | + sizeof(struct ip6_hdr) | 1052 | if (op & OPT_USE_ICMP) { |
986 | + sizeof(struct udphdr) | 1053 | ident |= 0x8000; |
987 | ); | 1054 | outicmp6->icmp_type = ICMP6_ECHO_REQUEST; |
1055 | /*outicmp->icmp_code = 0; - set by xzalloc */ | ||
1056 | outicmp6->icmp_id = htons(ident); | ||
1057 | outdata = (void*)((char *)outicmp6 + SIZEOF_ICMP_HDR); | ||
1058 | } | ||
988 | } | 1059 | } |
989 | #endif | 1060 | #endif |
990 | 1061 | ||
@@ -1013,26 +1084,16 @@ common_traceroute_main(int op, char **argv) | |||
1013 | //TODO: why we don't do it for IPv4? | 1084 | //TODO: why we don't do it for IPv4? |
1014 | len_and_sockaddr *source_lsa; | 1085 | len_and_sockaddr *source_lsa; |
1015 | 1086 | ||
1016 | int probe_fd = xsocket(af, SOCK_DGRAM, 0); | ||
1017 | if (op & OPT_DEVICE) | ||
1018 | setsockopt_bindtodevice(probe_fd, device); | ||
1019 | set_nport(&dest_lsa->u.sa, htons(1025)); | ||
1020 | /* dummy connect. makes kernel pick source IP (and port) */ | ||
1021 | xconnect(probe_fd, &dest_lsa->u.sa, dest_lsa->len); | ||
1022 | set_nport(&dest_lsa->u.sa, htons(port)); | 1087 | set_nport(&dest_lsa->u.sa, htons(port)); |
1023 | 1088 | /* Connect makes kernel pick source IP and port */ | |
1024 | /* read IP and port */ | 1089 | xconnect(sndsock, &dest_lsa->u.sa, dest_lsa->len); |
1025 | source_lsa = get_sock_lsa(probe_fd); | 1090 | /* Read IP and port */ |
1091 | source_lsa = get_sock_lsa(sndsock); | ||
1026 | if (source_lsa == NULL) | 1092 | if (source_lsa == NULL) |
1027 | bb_simple_error_msg_and_die("can't get probe addr"); | 1093 | bb_simple_error_msg_and_die("can't get probe addr"); |
1028 | 1094 | /* bind our recv socket to this IP (but not port) */ | |
1029 | close(probe_fd); | ||
1030 | |||
1031 | /* bind our sockets to this IP (but not port) */ | ||
1032 | set_nport(&source_lsa->u.sa, 0); | 1095 | set_nport(&source_lsa->u.sa, 0); |
1033 | xbind(sndsock, &source_lsa->u.sa, source_lsa->len); | ||
1034 | xbind(rcvsock, &source_lsa->u.sa, source_lsa->len); | 1096 | xbind(rcvsock, &source_lsa->u.sa, source_lsa->len); |
1035 | |||
1036 | free(source_lsa); | 1097 | free(source_lsa); |
1037 | } | 1098 | } |
1038 | #endif | 1099 | #endif |
@@ -1067,10 +1128,9 @@ common_traceroute_main(int op, char **argv) | |||
1067 | unsigned t1; | 1128 | unsigned t1; |
1068 | unsigned t2; | 1129 | unsigned t2; |
1069 | int left_ms; | 1130 | int left_ms; |
1070 | struct ip *ip; | ||
1071 | 1131 | ||
1072 | fflush_all(); | 1132 | fflush_all(); |
1073 | if (probe != 0 && pausemsecs > 0) | 1133 | if (probe != 0) |
1074 | msleep(pausemsecs); | 1134 | msleep(pausemsecs); |
1075 | 1135 | ||
1076 | send_probe(++seq, ttl); | 1136 | send_probe(++seq, ttl); |
@@ -1099,15 +1159,18 @@ common_traceroute_main(int op, char **argv) | |||
1099 | } | 1159 | } |
1100 | 1160 | ||
1101 | print_delta_ms(t1, t2); | 1161 | print_delta_ms(t1, t2); |
1102 | ip = (struct ip *)recv_pkt; | ||
1103 | 1162 | ||
1104 | if (from_lsa->u.sa.sa_family == AF_INET) | 1163 | if (from_lsa->u.sa.sa_family == AF_INET) { |
1105 | if (op & OPT_TTL_FLAG) | 1164 | if (op & OPT_TTL_FLAG) { |
1165 | struct ip *ip = (struct ip *)recv_pkt; | ||
1106 | printf(" (%d)", ip->ip_ttl); | 1166 | printf(" (%d)", ip->ip_ttl); |
1167 | } | ||
1168 | } | ||
1107 | 1169 | ||
1108 | /* time exceeded in transit */ | 1170 | /* Got a "time exceeded in transit" icmp message? */ |
1109 | if (icmp_code == -1) | 1171 | if (icmp_code == -1) |
1110 | break; | 1172 | break; |
1173 | |||
1111 | icmp_code--; | 1174 | icmp_code--; |
1112 | switch (icmp_code) { | 1175 | switch (icmp_code) { |
1113 | #if ENABLE_TRACEROUTE6 | 1176 | #if ENABLE_TRACEROUTE6 |
@@ -1115,12 +1178,13 @@ common_traceroute_main(int op, char **argv) | |||
1115 | got_there = 1; | 1178 | got_there = 1; |
1116 | break; | 1179 | break; |
1117 | #endif | 1180 | #endif |
1118 | case ICMP_UNREACH_PORT: | 1181 | case ICMP_UNREACH_PORT: { |
1182 | struct ip *ip = (struct ip *)recv_pkt; | ||
1119 | if (ip->ip_ttl <= 1) | 1183 | if (ip->ip_ttl <= 1) |
1120 | printf(" !"); | 1184 | printf(" !"); |
1121 | got_there = 1; | 1185 | got_there = 1; |
1122 | break; | 1186 | break; |
1123 | 1187 | } | |
1124 | case ICMP_UNREACH_NET: | 1188 | case ICMP_UNREACH_NET: |
1125 | #if ENABLE_TRACEROUTE6 && (ICMP6_DST_UNREACH_NOROUTE != ICMP_UNREACH_NET) | 1189 | #if ENABLE_TRACEROUTE6 && (ICMP6_DST_UNREACH_NOROUTE != ICMP_UNREACH_NET) |
1126 | case ICMP6_DST_UNREACH_NOROUTE << 8: | 1190 | case ICMP6_DST_UNREACH_NOROUTE << 8: |