diff options
-rw-r--r-- | networking/traceroute.c | 105 |
1 files changed, 41 insertions, 64 deletions
diff --git a/networking/traceroute.c b/networking/traceroute.c index e6afdd8b9..cf2b3cc64 100644 --- a/networking/traceroute.c +++ b/networking/traceroute.c | |||
@@ -413,7 +413,6 @@ struct globals { | |||
413 | #define port (G.port ) | 413 | #define port (G.port ) |
414 | #define waittime (G.waittime ) | 414 | #define waittime (G.waittime ) |
415 | #define recv_pkt (G.recv_pkt ) | 415 | #define recv_pkt (G.recv_pkt ) |
416 | #define gwlist (G.gwlist ) | ||
417 | #define INIT_G() do { \ | 416 | #define INIT_G() do { \ |
418 | SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ | 417 | SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ |
419 | } while (0) | 418 | } while (0) |
@@ -683,12 +682,15 @@ packet4_ok(int read_len, int seq) | |||
683 | int i; | 682 | int i; |
684 | uint32_t *lp = (uint32_t *)&icp->icmp_ip; | 683 | uint32_t *lp = (uint32_t *)&icp->icmp_ip; |
685 | 684 | ||
686 | printf("\n%d bytes from %s", | 685 | printf("\n%d bytes from %s to %s: icmp type %d (%s) code %d\n", |
687 | read_len, inet_ntoa(G.from_lsa->u.sin.sin_addr)); | 686 | read_len, |
688 | /* Two separate printf() because inet_ntoa() returns static string */ | 687 | /* inet_ntoa(G.from_lsa->u.sin.sin_addr) - two calls of inet_ntoa() |
689 | printf(" to %s: icmp type %d (%s) code %d\n", | 688 | * are unsafe (use the same buffer), using this instead: |
689 | */ | ||
690 | auto_string(xmalloc_sockaddr2dotted_noport(&G.from_lsa->u.sa)), | ||
690 | inet_ntoa(ip->ip_dst), | 691 | inet_ntoa(ip->ip_dst), |
691 | type, pr_type(type), icp->icmp_code); | 692 | type, pr_type(type), icp->icmp_code |
693 | ); | ||
692 | for (i = 4; i < read_len; i += sizeof(*lp)) | 694 | for (i = 4; i < read_len; i += sizeof(*lp)) |
693 | printf("%2d: x%8.8x\n", i, *lp++); | 695 | printf("%2d: x%8.8x\n", i, *lp++); |
694 | } | 696 | } |
@@ -756,19 +758,16 @@ packet6_ok(int read_len, int seq) | |||
756 | # if ENABLE_FEATURE_TRACEROUTE_VERBOSE | 758 | # if ENABLE_FEATURE_TRACEROUTE_VERBOSE |
757 | if (verbose) { | 759 | if (verbose) { |
758 | unsigned char *p; | 760 | unsigned char *p; |
759 | char pa[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff") + 4]; | ||
760 | int i; | 761 | int i; |
761 | 762 | ||
762 | p = (unsigned char *) (icp + 1); | 763 | p = (unsigned char *) (icp + 1); |
763 | 764 | ||
764 | printf("\n%d bytes from %s", | 765 | printf("\n%d bytes from %s to %s: icmp type %d (%s) code %d\n", |
765 | read_len, | 766 | read_len, |
766 | inet_ntop(AF_INET6, &G.from_lsa->u.sin6.sin6_addr, pa, sizeof(pa))); | 767 | auto_string(xmalloc_sockaddr2dotted_noport(&G.from_lsa->u.sa)), |
767 | /* Two printf() instead of one - reuse string constants */ | 768 | auto_string(xmalloc_sockaddr2dotted_noport(G.to)), |
768 | printf(" to %s: icmp type %d (%s) code %d\n", | 769 | type, pr_type(type), icp->icmp6_code |
769 | inet_ntop(AF_INET6, &((struct sockaddr_in6*)G.to)->sin6_addr, pa, sizeof(pa)), | 770 | ); |
770 | type, pr_type(type), icp->icmp6_code); | ||
771 | |||
772 | read_len -= sizeof(struct icmp6_hdr); | 771 | read_len -= sizeof(struct icmp6_hdr); |
773 | for (i = 0; i < read_len; i++) { | 772 | for (i = 0; i < read_len; i++) { |
774 | if (i % 16 == 0) | 773 | if (i % 16 == 0) |
@@ -796,55 +795,36 @@ packet_ok(int read_len, int seq) | |||
796 | 795 | ||
797 | #else /* !ENABLE_TRACEROUTE6 */ | 796 | #else /* !ENABLE_TRACEROUTE6 */ |
798 | 797 | ||
799 | static ALWAYS_INLINE int | 798 | # define packet_ok(read_len, seq) packet4_ok(read_len, seq) |
800 | packet_ok(int read_len, int seq) | ||
801 | { | ||
802 | return packet4_ok(read_len, seq); | ||
803 | } | ||
804 | 799 | ||
805 | #endif | 800 | #endif |
806 | 801 | ||
807 | /* | ||
808 | * Construct an Internet address representation. | ||
809 | * If the -n flag has been supplied, give | ||
810 | * numeric value, otherwise try for symbolic name. | ||
811 | */ | ||
812 | static void | 802 | static void |
813 | print_inetname(const struct sockaddr *from) | 803 | print(int read_len) |
814 | { | 804 | { |
815 | char *ina = xmalloc_sockaddr2dotted_noport(from); | 805 | char *ina = auto_string(xmalloc_sockaddr2dotted_noport(&G.from_lsa->u.sa)); |
816 | 806 | ||
817 | if (option_mask32 & OPT_ADDR_NUM) { | 807 | if (option_mask32 & OPT_ADDR_NUM) { |
818 | printf(" %s", ina); | 808 | printf(" %s", ina); |
819 | } else { | 809 | } else { |
820 | char *n = NULL; | 810 | char *n = NULL; |
821 | 811 | if (G.from_lsa->u.sa.sa_family != AF_INET | |
822 | if (from->sa_family != AF_INET | 812 | || G.from_lsa->u.sin.sin_addr.s_addr != INADDR_ANY |
823 | || ((struct sockaddr_in*)from)->sin_addr.s_addr != INADDR_ANY | ||
824 | ) { | 813 | ) { |
825 | /* Try to reverse resolve if it is not 0.0.0.0 */ | 814 | /* Try to reverse resolve if it is not 0.0.0.0 */ |
826 | n = xmalloc_sockaddr2host_noport((struct sockaddr*)from); | 815 | n = auto_string(xmalloc_sockaddr2host_noport(&G.from_lsa->u.sa)); |
827 | } | 816 | } |
828 | printf(" %s (%s)", (n ? n : ina), ina); | 817 | printf(" %s (%s)", (n ? n : ina), ina); |
829 | free(n); | ||
830 | } | 818 | } |
831 | free(ina); | ||
832 | } | ||
833 | |||
834 | static void | ||
835 | print(int read_len) | ||
836 | { | ||
837 | print_inetname(&G.from_lsa->u.sa); | ||
838 | 819 | ||
839 | if (verbose) { | 820 | if (verbose) { |
840 | char *ina = xmalloc_sockaddr2dotted_noport(G.to); | ||
841 | #if ENABLE_TRACEROUTE6 | 821 | #if ENABLE_TRACEROUTE6 |
842 | /* NB: reads from (AF_INET, SOCK_RAW, IPPROTO_ICMP) socket | 822 | /* NB: reads from (AF_INET, SOCK_RAW, IPPROTO_ICMP) socket |
843 | * return the entire IP packet (IOW: they do not strip IP header). | 823 | * return the entire IP packet (IOW: they do not strip IP header). |
844 | * Reads from (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6) do strip IPv6 | 824 | * Reads from (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6) do strip IPv6 |
845 | * header and return only ICMP6 packet. Weird. | 825 | * header and return only ICMP6 packet. Weird. |
846 | */ | 826 | */ |
847 | if (G.to->sa_family == AF_INET6) { | 827 | if (G.from_lsa->u.sa.sa_family == AF_INET6) { |
848 | /* read_len -= sizeof(struct ip6_hdr); - WRONG! */ | 828 | /* read_len -= sizeof(struct ip6_hdr); - WRONG! */ |
849 | } else | 829 | } else |
850 | #endif | 830 | #endif |
@@ -852,8 +832,9 @@ print(int read_len) | |||
852 | struct ip *ip4packet = (struct ip*)recv_pkt; | 832 | struct ip *ip4packet = (struct ip*)recv_pkt; |
853 | read_len -= ip4packet->ip_hl << 2; | 833 | read_len -= ip4packet->ip_hl << 2; |
854 | } | 834 | } |
855 | printf(" %d bytes to %s", read_len, ina); | 835 | printf(" %d bytes to %s", read_len, |
856 | free(ina); | 836 | auto_string(xmalloc_sockaddr2dotted_noport(G.to)) |
837 | ); | ||
857 | } | 838 | } |
858 | } | 839 | } |
859 | 840 | ||
@@ -870,10 +851,6 @@ print_delta_ms(unsigned t1p, unsigned t2p) | |||
870 | static NOINLINE void | 851 | static NOINLINE void |
871 | traceroute_init(int op, char **argv) | 852 | traceroute_init(int op, char **argv) |
872 | { | 853 | { |
873 | int minpacket; | ||
874 | #ifdef IP_TOS | ||
875 | int tos = 0; | ||
876 | #endif | ||
877 | char *source; | 854 | char *source; |
878 | char *device; | 855 | char *device; |
879 | char *tos_str; | 856 | char *tos_str; |
@@ -912,10 +889,6 @@ traceroute_init(int op, char **argv) | |||
912 | if (op & OPT_IP_CHKSUM) | 889 | if (op & OPT_IP_CHKSUM) |
913 | bb_error_msg("warning: ip checksums disabled"); | 890 | bb_error_msg("warning: ip checksums disabled"); |
914 | #endif | 891 | #endif |
915 | #ifdef IP_TOS | ||
916 | if (op & OPT_TOS) | ||
917 | tos = xatou_range(tos_str, 0, 255); | ||
918 | #endif | ||
919 | if (op & OPT_MAX_TTL) | 892 | if (op & OPT_MAX_TTL) |
920 | G.max_ttl = xatou_range(max_ttl_str, 1, 255); | 893 | G.max_ttl = xatou_range(max_ttl_str, 1, 255); |
921 | if (op & OPT_PORT) | 894 | if (op & OPT_PORT) |
@@ -930,11 +903,11 @@ traceroute_init(int op, char **argv) | |||
930 | G.first_ttl = xatou_range(first_ttl_str, 1, G.max_ttl); | 903 | G.first_ttl = xatou_range(first_ttl_str, 1, G.max_ttl); |
931 | 904 | ||
932 | /* Process destination and optional packet size */ | 905 | /* Process destination and optional packet size */ |
933 | minpacket = sizeof(struct ip) | 906 | packlen = sizeof(struct ip) |
934 | + sizeof(struct udphdr) | 907 | + sizeof(struct udphdr) |
935 | + sizeof(struct outdata_t); | 908 | + sizeof(struct outdata_t); |
936 | if (op & OPT_USE_ICMP) { | 909 | if (op & OPT_USE_ICMP) { |
937 | minpacket = sizeof(struct ip) | 910 | packlen = sizeof(struct ip) |
938 | + SIZEOF_ICMP_HDR | 911 | + SIZEOF_ICMP_HDR |
939 | + sizeof(struct outdata_t); | 912 | + sizeof(struct outdata_t); |
940 | port = 0; /* on ICMP6 sockets, sendto(ipv6.nonzero_port) throws EINVAL */ | 913 | port = 0; /* on ICMP6 sockets, sendto(ipv6.nonzero_port) throws EINVAL */ |
@@ -948,11 +921,11 @@ traceroute_init(int op, char **argv) | |||
948 | dest_lsa = xhost_and_af2sockaddr(argv[0], port, af); | 921 | dest_lsa = xhost_and_af2sockaddr(argv[0], port, af); |
949 | af = dest_lsa->u.sa.sa_family; | 922 | af = dest_lsa->u.sa.sa_family; |
950 | if (af == AF_INET6) { | 923 | if (af == AF_INET6) { |
951 | minpacket = sizeof(struct ip6_hdr) | 924 | packlen = sizeof(struct ip6_hdr) |
952 | + sizeof(struct udphdr) | 925 | + sizeof(struct udphdr) |
953 | + sizeof(struct outdata6_t); | 926 | + sizeof(struct outdata6_t); |
954 | if (op & OPT_USE_ICMP) | 927 | if (op & OPT_USE_ICMP) |
955 | minpacket = sizeof(struct ip6_hdr) | 928 | packlen = sizeof(struct ip6_hdr) |
956 | + SIZEOF_ICMP_HDR | 929 | + SIZEOF_ICMP_HDR |
957 | + sizeof(struct outdata6_t); | 930 | + sizeof(struct outdata6_t); |
958 | } | 931 | } |
@@ -961,19 +934,20 @@ traceroute_init(int op, char **argv) | |||
961 | #endif | 934 | #endif |
962 | G.from_lsa = xmemdup(dest_lsa, LSA_LEN_SIZE + dest_lsa->len); | 935 | G.from_lsa = xmemdup(dest_lsa, LSA_LEN_SIZE + dest_lsa->len); |
963 | G.to = xzalloc(dest_lsa->len); | 936 | G.to = xzalloc(dest_lsa->len); |
964 | |||
965 | packlen = minpacket; | ||
966 | if (argv[1]) | 937 | if (argv[1]) |
967 | packlen = xatoul_range(argv[1], minpacket, 32 * 1024); | 938 | packlen = xatoul_range(argv[1], packlen, 32 * 1024); |
968 | 939 | ||
969 | #if ENABLE_TRACEROUTE6 | 940 | #if ENABLE_TRACEROUTE6 |
970 | if (af == AF_INET6) { | 941 | if (af == AF_INET6) { |
971 | xmove_fd(xsocket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6), rcvsock); | 942 | xmove_fd(xsocket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6), rcvsock); |
972 | setsockopt_1(rcvsock, SOL_IPV6, IPV6_RECVPKTINFO); //why? | 943 | /* want recvmsg to report target local address (for -v) */ |
944 | setsockopt_1(rcvsock, SOL_IPV6, IPV6_RECVPKTINFO); | ||
973 | } else | 945 | } else |
974 | #endif | 946 | #endif |
975 | { | 947 | { |
976 | xmove_fd(xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP), rcvsock); | 948 | xmove_fd(xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP), rcvsock); |
949 | /* want recvmsg to report target local address (for -v) */ | ||
950 | setsockopt_1(rcvsock, IPPROTO_IP, IP_PKTINFO); | ||
977 | } | 951 | } |
978 | 952 | ||
979 | #if TRACEROUTE_SO_DEBUG | 953 | #if TRACEROUTE_SO_DEBUG |
@@ -1010,8 +984,10 @@ traceroute_init(int op, char **argv) | |||
1010 | } | 984 | } |
1011 | #endif | 985 | #endif |
1012 | #ifdef IP_TOS | 986 | #ifdef IP_TOS |
1013 | if ((op & OPT_TOS) && setsockopt_int(sndsock, IPPROTO_IP, IP_TOS, tos) != 0) { | 987 | if (op & OPT_TOS) { |
1014 | bb_perror_msg_and_die("setsockopt(%s) %d", "TOS", tos); | 988 | int tos = xatou_range(tos_str, 0, 255); |
989 | if (setsockopt_int(sndsock, IPPROTO_IP, IP_TOS, tos) != 0) | ||
990 | bb_perror_msg_and_die("setsockopt(%s,%d)", "TOS", tos); | ||
1015 | } | 991 | } |
1016 | #endif | 992 | #endif |
1017 | #ifdef IP_DONTFRAG | 993 | #ifdef IP_DONTFRAG |
@@ -1070,7 +1046,8 @@ traceroute_init(int op, char **argv) | |||
1070 | //TODO: we can query source port we bound to, | 1046 | //TODO: we can query source port we bound to, |
1071 | // and check it in replies... if we care enough | 1047 | // and check it in replies... if we care enough |
1072 | xbind(sndsock, &source_lsa->u.sa, source_lsa->len); | 1048 | xbind(sndsock, &source_lsa->u.sa, source_lsa->len); |
1073 | free(source_lsa); | 1049 | if (ENABLE_FEATURE_CLEAN_UP) |
1050 | free(source_lsa); | ||
1074 | } | 1051 | } |
1075 | #if ENABLE_TRACEROUTE6 | 1052 | #if ENABLE_TRACEROUTE6 |
1076 | else if (af == AF_INET6) { | 1053 | else if (af == AF_INET6) { |
@@ -1087,7 +1064,8 @@ traceroute_init(int op, char **argv) | |||
1087 | /* bind our recv socket to this IP (but not port) */ | 1064 | /* bind our recv socket to this IP (but not port) */ |
1088 | set_nport(&source_lsa->u.sa, 0); | 1065 | set_nport(&source_lsa->u.sa, 0); |
1089 | xbind(rcvsock, &source_lsa->u.sa, source_lsa->len); | 1066 | xbind(rcvsock, &source_lsa->u.sa, source_lsa->len); |
1090 | free(source_lsa); | 1067 | if (ENABLE_FEATURE_CLEAN_UP) |
1068 | free(source_lsa); | ||
1091 | } | 1069 | } |
1092 | #endif | 1070 | #endif |
1093 | 1071 | ||
@@ -1097,9 +1075,8 @@ traceroute_init(int op, char **argv) | |||
1097 | 1075 | ||
1098 | dest_str = xmalloc_sockaddr2dotted_noport(&dest_lsa->u.sa); | 1076 | dest_str = xmalloc_sockaddr2dotted_noport(&dest_lsa->u.sa); |
1099 | printf("traceroute to %s (%s)", argv[0], dest_str); | 1077 | printf("traceroute to %s (%s)", argv[0], dest_str); |
1100 | if (ENABLE_FEATURE_CLEAN_UP) { | 1078 | if (ENABLE_FEATURE_CLEAN_UP) |
1101 | free(dest_str); | 1079 | free(dest_str); |
1102 | } | ||
1103 | 1080 | ||
1104 | if (op & OPT_SOURCE) | 1081 | if (op & OPT_SOURCE) |
1105 | printf(" from %s", source); | 1082 | printf(" from %s", source); |