| /* traceroute - trace the route to "host". |
| * |
| * Copyright 2012 Madhur Verma <mad.flexi@gmail.com> |
| * Copyright 2013 Kyungwan Han <asura321@gmail.com> |
| * Copyright 2013 Bilal Qureshi <bilal.jmi@gmail.com> |
| * Copyright 2013 Ashwini Kumar <ak.ashwini1981@gmail.com> |
| * |
| * No Standard |
| |
| USE_TRACEROUTE(NEWTOY(traceroute, "<1>2i:f#<1>255=1z#<0>86400=0g*w#<0>86400=5t#<0>255=0s:q#<1>255=3p#<1>65535=33434m#<1>255=30rvndlIUF64", TOYFLAG_STAYROOT|TOYFLAG_USR|TOYFLAG_BIN)) |
| USE_TRACEROUTE(OLDTOY(traceroute6,traceroute, TOYFLAG_STAYROOT|TOYFLAG_USR|TOYFLAG_BIN)) |
| config TRACEROUTE |
| bool "traceroute" |
| default n |
| help |
| usage: traceroute [-46FUIldnvr] [-f 1ST_TTL] [-m MAXTTL] [-p PORT] [-q PROBES] |
| [-s SRC_IP] [-t TOS] [-w WAIT_SEC] [-g GATEWAY] [-i IFACE] [-z PAUSE_MSEC] HOST [BYTES] |
| |
| traceroute6 [-dnrv] [-m MAXTTL] [-p PORT] [-q PROBES][-s SRC_IP] [-t TOS] [-w WAIT_SEC] |
| [-i IFACE] HOST [BYTES] |
| |
| Trace the route to HOST |
| |
| -4,-6 Force IP or IPv6 name resolution |
| -F Set the don't fragment bit (supports IPV4 only) |
| -U Use UDP datagrams instead of ICMP ECHO (supports IPV4 only) |
| -I Use ICMP ECHO instead of UDP datagrams (supports IPV4 only) |
| -l Display the TTL value of the returned packet (supports IPV4 only) |
| -d Set SO_DEBUG options to socket |
| -n Print numeric addresses |
| -v verbose |
| -r Bypass routing tables, send directly to HOST |
| -m Max time-to-live (max number of hops)(RANGE 1 to 255) |
| -p Base UDP port number used in probes(default 33434)(RANGE 1 to 65535) |
| -q Number of probes per TTL (default 3)(RANGE 1 to 255) |
| -s IP address to use as the source address |
| -t Type-of-service in probe packets (default 0)(RANGE 0 to 255) |
| -w Time in seconds to wait for a response (default 3)(RANGE 0 to 86400) |
| -g Loose source route gateway (8 max) (supports IPV4 only) |
| -z Pause Time in milisec (default 0)(RANGE 0 to 86400) (supports IPV4 only) |
| -f Start from the 1ST_TTL hop (instead from 1)(RANGE 1 to 255) (supports IPV4 only) |
| -i Specify a network interface to operate with |
| */ |
| #define FOR_traceroute |
| #include "toys.h" |
| #include <netinet/udp.h> |
| #include <netinet/ip_icmp.h> |
| #include <netinet/ip6.h> |
| #include <netinet/icmp6.h> |
| |
| GLOBALS( |
| long max_ttl; |
| long port; |
| long ttl_probes; |
| char *src_ip; |
| long tos; |
| long wait_time; |
| struct arg_list *loose_source; |
| long pause_time; |
| long first_ttl; |
| char *iface; |
| |
| uint32_t gw_list[9]; |
| int recv_sock; |
| int snd_sock; |
| unsigned msg_len; |
| char *packet; |
| uint32_t ident; |
| int istraceroute6; |
| ) |
| |
| #ifndef SOL_IPV6 |
| # define SOL_IPV6 IPPROTO_IPV6 |
| #endif |
| |
| #define ICMP_HD_SIZE4 8 |
| #define USEC 1000000ULL |
| |
| struct payload_s { |
| uint32_t seq; |
| uint32_t ident; |
| }; |
| |
| char addr_str[INET6_ADDRSTRLEN]; |
| struct sockaddr_storage dest; |
| |
| //Compute checksum SUM of buffer P of length LEN |
| static u_int16_t in_cksum(u_int16_t *p, u_int len) |
| { |
| u_int32_t sum = 0; |
| int nwords = len >> 1; |
| |
| while (nwords-- != 0) sum += *p++; |
| if (len & 1) { |
| union { |
| u_int16_t w; |
| u_int8_t c[2]; |
| } u; |
| u.c[0] = *(u_char *) p; |
| u.c[1] = 0; |
| sum += u.w; |
| } |
| // end-around-carry |
| sum = (sum >> 16) + (sum & 0xffff); |
| sum += (sum >> 16); |
| return (~sum); |
| } |
| |
| //sends a single probe packet with sequence(SEQ) and time-to-live(TTL) |
| static void send_probe4(int seq, int ttl) |
| { |
| int res, len; |
| void *out; |
| struct payload_s *send_data4 = (struct payload_s *)(TT.packet); |
| struct icmp *send_icmp4 = (struct icmp *)(TT.packet); |
| |
| if (toys.optflags & FLAG_U) { |
| send_data4->seq = seq; |
| send_data4->ident = TT.ident; |
| ((struct sockaddr_in *)&dest)->sin_port = TT.port + seq; |
| out = send_data4; |
| } else { |
| send_icmp4->icmp_type = ICMP_ECHO; |
| send_icmp4->icmp_id = htons(TT.ident); |
| send_icmp4->icmp_seq = htons(seq); |
| send_icmp4->icmp_cksum = 0; |
| send_icmp4->icmp_cksum = in_cksum((uint16_t *) send_icmp4, TT.msg_len); |
| if (send_icmp4->icmp_cksum == 0) send_icmp4->icmp_cksum = 0xffff; |
| out = send_icmp4; |
| } |
| |
| res = setsockopt(TT.snd_sock, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)); |
| if (res < 0) perror_exit("setsockopt ttl %d", ttl); |
| |
| len = TT.msg_len; |
| res = sendto(TT.snd_sock, out, len, 0, (struct sockaddr *) &dest, |
| sizeof(struct sockaddr_in)); |
| if (res != len) perror_exit(" sendto"); |
| } |
| |
| //sends a single probe packet with sequence(SEQ) and time-to-live(TTL) |
| static void send_probe6(int seq, int ttl) |
| { |
| void *out; |
| struct payload_s *send_data6 = (struct payload_s *) (TT.packet); |
| |
| send_data6->seq = seq; |
| send_data6->ident = TT.ident; |
| ((struct sockaddr_in6 *)&dest)->sin6_port = TT.port; |
| |
| if (setsockopt(TT.snd_sock, SOL_IPV6, IPV6_UNICAST_HOPS, &ttl, |
| sizeof(ttl)) < 0) error_exit("setsockopt ttl %d", ttl); |
| |
| out = send_data6; |
| |
| if (sendto(TT.snd_sock, out, TT.msg_len, 0, |
| (struct sockaddr *) &dest, sizeof(struct sockaddr_in6)) < 0) |
| perror_exit("sendto"); |
| } |
| |
| static void set_flag_dr(int sock) |
| { |
| int set = 1; |
| if ((toys.optflags & FLAG_d) && (setsockopt(sock,SOL_SOCKET, SO_DEBUG, |
| &set, sizeof(set)) < 0)) perror_exit("SO_DEBUG failed "); |
| |
| if ((toys.optflags & FLAG_r) && (setsockopt(sock, SOL_SOCKET, SO_DONTROUTE, |
| &set, sizeof(set)) < 0)) perror_exit("SO_DONTROUTE failed "); |
| } |
| |
| static void bind_to_interface(int sock) |
| { |
| struct ifreq ifr; |
| |
| snprintf(ifr.ifr_name, IFNAMSIZ, "%s", TT.iface); |
| if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr))) |
| perror_msg("can't bind to interface %s", TT.iface); |
| } |
| |
| static void resolve_addr(char *host, int family, int type, int proto, void *sock) |
| { |
| struct addrinfo *info, hint; |
| int ret; |
| |
| memset(&hint, 0, sizeof(hint)); |
| hint.ai_family = family; |
| hint.ai_socktype = type; |
| hint.ai_protocol = proto; |
| |
| ret = getaddrinfo(host, NULL, &hint, &info); |
| if (ret || !info) error_exit("bad address: %s ", host); |
| |
| memcpy(sock, info->ai_addr, info->ai_addrlen); |
| freeaddrinfo(info); |
| } |
| |
| static void do_trace() |
| { |
| int seq, fexit, ttl, tv = TT.wait_time * 1000; |
| struct pollfd pfd[1]; |
| struct sockaddr_storage from; |
| |
| memset(&from, 0, sizeof(from)); |
| pfd[0].fd = TT.recv_sock; |
| pfd[0].events = POLLIN; |
| |
| for (ttl = TT.first_ttl; ttl <= TT.max_ttl; ++ttl) { |
| int probe, dest_reach = 0, print_verbose = 1; |
| struct timeval t1, t2; |
| struct sockaddr_storage last_addr; |
| |
| memset(&last_addr, 0, sizeof(last_addr)); |
| fexit = 0; |
| xprintf("%2d", ttl); |
| |
| for (probe = 0, seq = 0; probe < TT.ttl_probes; ++probe) { |
| int res = 0, tleft; |
| |
| fflush(NULL); |
| if (!TT.istraceroute6) |
| if (probe && (toys.optflags & FLAG_z)) usleep(TT.pause_time * 1000); |
| |
| if (!TT.istraceroute6) send_probe4(++seq, ttl); |
| else send_probe6(++seq, ttl); |
| gettimeofday(&t1, NULL); |
| t2 = t1; |
| |
| while ((tleft = (int)(tv - ((unsigned long long)(t2.tv_sec * 1000ULL |
| + t2.tv_usec/1000) - (unsigned long long)(t1.tv_sec * 1000ULL |
| + t1.tv_usec/1000)))) >= 0) { |
| unsigned delta = 0; |
| if (!(res = poll(pfd, 1, tleft))) { |
| xprintf(" *"); |
| break; |
| } |
| gettimeofday(&t2, NULL); |
| if (res < 0) { |
| if (errno != EINTR) perror_exit("poll"); |
| continue; |
| } |
| delta = (t2.tv_sec * USEC + t2.tv_usec) |
| - (t1.tv_sec * USEC + t1.tv_usec); |
| |
| if (pfd[0].revents) { |
| unsigned addrlen = sizeof(struct sockaddr_storage); |
| int rcv_len, icmp_res = 0; |
| |
| rcv_len = recvfrom(TT.recv_sock, toybuf, sizeof(toybuf), |
| MSG_DONTWAIT, (struct sockaddr *) &from, &addrlen); |
| if (rcv_len <= 0) continue; |
| |
| if (!TT.istraceroute6) { |
| int pmtu = 0; |
| struct ip *rcv_pkt = (struct ip*) toybuf; |
| struct icmp *ricmp; |
| |
| ricmp = (struct icmp *) ((void*)rcv_pkt + (rcv_pkt->ip_hl << 2)); |
| if (ricmp->icmp_code == ICMP_UNREACH_NEEDFRAG) |
| pmtu = ntohs(ricmp->icmp_nextmtu); |
| |
| if ((ricmp->icmp_type == ICMP_TIMXCEED |
| && ricmp->icmp_code == ICMP_TIMXCEED_INTRANS) |
| || ricmp->icmp_type == ICMP_UNREACH |
| || ricmp->icmp_type == ICMP_ECHOREPLY) { |
| |
| struct udphdr *hudp; |
| struct icmp *hicmp; |
| struct ip *hip = &ricmp->icmp_ip; |
| |
| if (toys.optflags & FLAG_U) { |
| hudp = (struct udphdr*) ((char*)hip + (hip->ip_hl << 2)); |
| if ((hip->ip_hl << 2) + 12 <=(rcv_len - (rcv_pkt->ip_hl << 2)) |
| && hip->ip_p == IPPROTO_UDP |
| && hudp->dest == (TT.port + seq)) |
| icmp_res = (ricmp->icmp_type == ICMP_TIMXCEED ? -1 : |
| ricmp->icmp_code); |
| } else { |
| hicmp = (struct icmp *) ((void*)hip + (hip->ip_hl << 2)); |
| if (ricmp->icmp_type == ICMP_ECHOREPLY |
| && ricmp->icmp_id == ntohs(TT.ident) |
| && ricmp->icmp_seq == ntohs(seq)) |
| icmp_res = ICMP_UNREACH_PORT; |
| else if ((hip->ip_hl << 2) + ICMP_HD_SIZE4 |
| <= (rcv_len - (rcv_pkt->ip_hl << 2)) |
| && hip->ip_p == IPPROTO_ICMP |
| && hicmp->icmp_id == htons(TT.ident) |
| && hicmp->icmp_seq == htons(seq)) |
| icmp_res = (ricmp->icmp_type == ICMP_TIMXCEED ? -1 : |
| ricmp->icmp_code); |
| } |
| } |
| if (!icmp_res) continue; |
| |
| if (addrlen > 0) { |
| if (memcmp(&((struct sockaddr_in *)&last_addr)->sin_addr, |
| &((struct sockaddr_in *)&from)->sin_addr, |
| sizeof(struct in_addr))) { |
| if (!(toys.optflags & FLAG_n)) { |
| char host[NI_MAXHOST]; |
| if (!getnameinfo((struct sockaddr *) &from, |
| sizeof(struct sockaddr_in), host, NI_MAXHOST, NULL, 0, 0)) |
| xprintf(" %s (", host); |
| else xprintf(" %s (", inet_ntoa( |
| ((struct sockaddr_in *)&from)->sin_addr)); |
| } |
| xprintf(" %s", inet_ntoa( |
| ((struct sockaddr_in *)&from)->sin_addr)); |
| if (!(toys.optflags & FLAG_n)) xprintf(")"); |
| memcpy(&last_addr, &from, sizeof(from)); |
| } |
| xprintf(" %u.%03u ms", delta / 1000, delta % 1000); |
| if (toys.optflags & FLAG_l) xprintf(" (%d)", rcv_pkt->ip_ttl); |
| if (toys.optflags & FLAG_v) { |
| xprintf(" %d bytes from %s : icmp type %d code %d\t", |
| rcv_len, inet_ntoa(((struct sockaddr_in *)&from)->sin_addr), |
| ricmp->icmp_type, ricmp->icmp_code); |
| } |
| } else xprintf("\t!H"); |
| |
| switch (icmp_res) { |
| case ICMP_UNREACH_PORT: |
| if (rcv_pkt->ip_ttl <= 1) xprintf(" !"); |
| dest_reach = 1; |
| break; |
| case ICMP_UNREACH_NET: |
| xprintf(" !N"); |
| ++fexit; |
| break; |
| case ICMP_UNREACH_HOST: |
| xprintf(" !H"); |
| ++fexit; |
| break; |
| case ICMP_UNREACH_PROTOCOL: |
| xprintf(" !P"); |
| dest_reach = 1; |
| break; |
| case ICMP_UNREACH_NEEDFRAG: |
| xprintf(" !F-%d", pmtu); |
| ++fexit; |
| break; |
| case ICMP_UNREACH_SRCFAIL: |
| xprintf(" !S"); |
| ++fexit; |
| break; |
| case ICMP_UNREACH_FILTER_PROHIB: |
| case ICMP_UNREACH_NET_PROHIB: |
| xprintf(" !A"); |
| ++fexit; |
| break; |
| case ICMP_UNREACH_HOST_PROHIB: |
| xprintf(" !C"); |
| ++fexit; |
| break; |
| case ICMP_UNREACH_HOST_PRECEDENCE: |
| xprintf(" !V"); |
| ++fexit; |
| break; |
| case ICMP_UNREACH_PRECEDENCE_CUTOFF: |
| xprintf(" !C"); |
| ++fexit; |
| break; |
| case ICMP_UNREACH_NET_UNKNOWN: |
| case ICMP_UNREACH_HOST_UNKNOWN: |
| xprintf(" !U"); |
| ++fexit; |
| break; |
| case ICMP_UNREACH_ISOLATED: |
| xprintf(" !I"); |
| ++fexit; |
| break; |
| case ICMP_UNREACH_TOSNET: |
| case ICMP_UNREACH_TOSHOST: |
| xprintf(" !T"); |
| ++fexit; |
| break; |
| default: |
| break; |
| } |
| break; |
| } else { |
| struct icmp6_hdr *ricmp = (struct icmp6_hdr *) toybuf; |
| |
| if ((ricmp->icmp6_type == ICMP6_TIME_EXCEEDED |
| && ricmp->icmp6_code == ICMP6_TIME_EXCEED_TRANSIT) |
| || ricmp->icmp6_type == ICMP6_DST_UNREACH |
| || ricmp->icmp6_type == ICMP6_ECHO_REPLY) { |
| |
| struct ip6_hdr *hip; |
| struct udphdr *hudp; |
| int hdr_next; |
| |
| hip = (struct ip6_hdr *)(ricmp + 1); |
| hudp = (struct udphdr*) (hip + 1); |
| hdr_next = hip->ip6_nxt; |
| if (hdr_next == IPPROTO_FRAGMENT) { |
| hdr_next = *(unsigned char*)hudp; |
| hudp++; |
| } |
| |
| if (hdr_next == IPPROTO_UDP) { |
| struct payload_s *pkt = (struct payload_s*)(hudp + 1); |
| if ((pkt->ident == TT.ident) && (pkt->seq == seq)) |
| icmp_res = (ricmp->icmp6_type == ICMP6_TIME_EXCEEDED) ? -1 : |
| ricmp->icmp6_code; |
| } |
| } |
| |
| if (!icmp_res) continue; |
| if (addrlen > 0) { |
| if (memcmp(&((struct sockaddr_in6 *)&last_addr)->sin6_addr, |
| &((struct sockaddr_in6 *)&from)->sin6_addr, |
| sizeof(struct in6_addr))) { |
| if (!(toys.optflags & FLAG_n)) { |
| char host[NI_MAXHOST]; |
| if (!getnameinfo((struct sockaddr *) &from, |
| sizeof(from), host, sizeof(host), NULL, 0, 0)) |
| xprintf(" %s (", host); |
| } |
| memset(addr_str, '\0', INET6_ADDRSTRLEN); |
| inet_ntop(AF_INET6, &((struct sockaddr_in6 *)&from)->sin6_addr, |
| addr_str, INET6_ADDRSTRLEN); |
| xprintf(" %s", addr_str); |
| |
| if (!(toys.optflags & FLAG_n)) xprintf(")"); |
| memcpy(&last_addr,&from,sizeof(from)); |
| } |
| |
| if (toys.optflags & FLAG_v) { |
| if(print_verbose){ |
| memset(addr_str, '\0', INET6_ADDRSTRLEN); |
| inet_ntop(AF_INET6, &((struct sockaddr_in6 *) |
| &from)->sin6_addr, addr_str, INET6_ADDRSTRLEN); |
| rcv_len -= sizeof(struct ip6_hdr); |
| xprintf(" %d bytes to %s ", rcv_len, addr_str); |
| } |
| } |
| xprintf(" %u.%03u ms", delta / 1000, delta % 1000); |
| delta = 0; |
| |
| } else xprintf("\t!H"); |
| |
| switch (icmp_res) { |
| case ICMP6_DST_UNREACH_NOPORT: |
| ++fexit; |
| dest_reach = 1; |
| break; |
| case ICMP6_DST_UNREACH_NOROUTE: |
| xprintf(" !N"); |
| ++fexit; |
| break; |
| case ICMP6_DST_UNREACH_ADDR: |
| xprintf(" !H"); |
| ++fexit; |
| break; |
| case ICMP6_DST_UNREACH_ADMIN: |
| xprintf(" !S"); |
| ++fexit; |
| break; |
| default: |
| break; |
| } |
| break; |
| } |
| } //revents |
| } |
| print_verbose = 0; |
| } |
| xputc('\n'); |
| if(!TT.istraceroute6) { |
| if (!memcmp(&((struct sockaddr_in *)&from)->sin_addr, |
| &((struct sockaddr_in *)&dest)->sin_addr, sizeof(struct in_addr)) |
| || dest_reach || (fexit && fexit >= TT.ttl_probes -1)) |
| break; |
| } else if (dest_reach || (fexit > 0 && fexit >= TT.ttl_probes -1)) break; |
| } |
| } |
| |
| void traceroute_main(void) |
| { |
| unsigned opt_len = 0, pack_size = 0, tyser = 0; |
| int lsrr = 0, set = 1; |
| |
| if(!(toys.optflags & FLAG_4) && |
| (inet_pton(AF_INET6, toys.optargs[0], (void*)&dest))) |
| toys.optflags |= FLAG_6; |
| |
| memset(&dest, 0, sizeof(dest)); |
| if (toys.optflags & FLAG_6) TT.istraceroute6 = 1; |
| else TT.istraceroute6 = toys.which->name[10] == '6'; |
| |
| if(!TT.istraceroute6 && (toys.optflags & FLAG_g)) { |
| struct arg_list *node; |
| |
| for (node = TT.loose_source; node; node = node->next, lsrr++) { |
| struct sockaddr_in sin; |
| |
| memset( &sin, 0, sizeof(sin)); |
| if (lsrr >= 8) error_exit("no more than 8 gateways"); // NGATEWAYS |
| resolve_addr(node->arg, AF_INET, SOCK_STREAM, 0, &sin); |
| TT.gw_list[lsrr] = sin.sin_addr.s_addr; |
| } |
| opt_len = (lsrr + 1) * sizeof(TT.gw_list[0]); |
| } else TT.first_ttl = 1; |
| |
| TT.msg_len = pack_size = ICMP_HD_SIZE4; //udp payload is also 8bytes |
| if (toys.optargs[1]) |
| TT.msg_len = atolx_range(toys.optargs[1], pack_size, 32768);//max packet size |
| |
| TT.recv_sock = xsocket((TT.istraceroute6 ? AF_INET6 : AF_INET), SOCK_RAW, |
| (TT.istraceroute6 ? IPPROTO_ICMPV6 : IPPROTO_ICMP)); |
| |
| if (TT.istraceroute6) { |
| int two = 2; |
| #ifdef IPV6_RECVPKTINFO |
| setsockopt(TT.recv_sock, SOL_IPV6, IPV6_RECVPKTINFO, &set, |
| sizeof(set)); |
| setsockopt(TT.recv_sock, SOL_IPV6, IPV6_2292PKTINFO, &set, |
| sizeof(set)); |
| #else |
| setsockopt(TT.recv_sock, SOL_IPV6, IPV6_PKTINFO, &set, sizeof(set)); |
| #endif |
| |
| if (setsockopt(TT.recv_sock, SOL_RAW, IPV6_CHECKSUM, &two, |
| sizeof(two)) < 0) perror_exit("setsockopt RAW_CHECKSUM"); |
| } |
| |
| set_flag_dr(TT.recv_sock); |
| |
| if (!TT.istraceroute6) { |
| if (toys.optflags & FLAG_U) |
| TT.snd_sock = xsocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); |
| else TT.snd_sock = xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP); |
| |
| if (toys.optflags & FLAG_i) bind_to_interface(TT.snd_sock); |
| |
| resolve_addr(toys.optargs[0], AF_INET, ((toys.optflags & FLAG_U) ? |
| SOCK_DGRAM : SOCK_RAW), ((toys.optflags & FLAG_U) ? IPPROTO_UDP : |
| IPPROTO_ICMP), &dest); |
| if (lsrr > 0) { |
| unsigned char optlist[MAX_IPOPTLEN]; |
| unsigned size; |
| |
| TT.gw_list[lsrr] = ((struct sockaddr_in *)&dest)->sin_addr.s_addr; |
| ++lsrr; |
| |
| optlist[0] = IPOPT_NOP; |
| optlist[1] = IPOPT_LSRR;// loose source route option |
| size = lsrr * sizeof(TT.gw_list[0]); |
| optlist[2] = size + 3; |
| optlist[3] = IPOPT_MINOFF; |
| memcpy(optlist + 4, TT.gw_list, size); |
| |
| if (setsockopt(TT.snd_sock, IPPROTO_IP, IP_OPTIONS, |
| (char *)optlist, size + sizeof(TT.gw_list[0])) < 0) |
| perror_exit("LSRR IP_OPTIONS"); |
| } |
| } else TT.snd_sock = xsocket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); |
| |
| if (setsockopt(TT.snd_sock, SOL_SOCKET, SO_SNDBUF, &TT.msg_len, |
| sizeof(TT.msg_len)) < 0) perror_exit("SO_SNDBUF failed "); |
| |
| if (!TT.istraceroute6) { |
| if ((toys.optflags & FLAG_t) && |
| setsockopt(TT.snd_sock, IPPROTO_IP, IP_TOS, &tyser, sizeof(tyser)) < 0) |
| perror_exit("IP_TOS %d failed ", TT.tos); |
| |
| #ifdef IP_DONTFRAG |
| if ((toys.optflags & FLAG_F) && |
| (setsockopt(TT.snd_sock, IPPROTO_IP, IP_DONTFRAG, &set, |
| sizeof(set)) < 0)) perror_exit("IP_DONTFRAG failed "); |
| #endif |
| } else if (setsockopt(TT.snd_sock, IPPROTO_IPV6, IPV6_TCLASS, &TT.tos, |
| sizeof(TT.tos)) < 0) perror_exit("IPV6_TCLASS %d failed ", TT.tos); |
| |
| set_flag_dr(TT.snd_sock); |
| TT.packet = xzalloc(TT.msg_len); |
| TT.ident = getpid(); |
| |
| if (!TT.istraceroute6) { |
| if (!(toys.optflags & FLAG_U)) TT.ident |= 0x8000; |
| if (toys.optflags & FLAG_s) { |
| struct sockaddr_in source; |
| |
| memset(&source, 0, sizeof(source)); |
| if (!inet_aton(TT.src_ip, &(source.sin_addr))) |
| error_exit("bad address: %s", TT.src_ip); |
| if (setsockopt(TT.snd_sock, IPPROTO_IP, IP_MULTICAST_IF, |
| (struct sockaddr*)&source, sizeof(struct sockaddr_in))) |
| perror_exit("can't set multicast source interface"); |
| if (bind(TT.snd_sock,(struct sockaddr*)&source, |
| sizeof(struct sockaddr_in)) < 0) perror_exit("bind"); |
| } |
| |
| if(TT.first_ttl > TT.max_ttl) |
| error_exit("ERROR :Range for -f is 1 to %d (max ttl)", TT.max_ttl); |
| |
| xprintf("traceroute to %s(%s)", toys.optargs[0], |
| inet_ntoa(((struct sockaddr_in *)&dest)->sin_addr)); |
| } else { |
| if (toys.optflags & FLAG_i) bind_to_interface(TT.snd_sock); |
| |
| resolve_addr(toys.optargs[0], AF_INET6, SOCK_DGRAM, IPPROTO_UDP, &dest); |
| if (toys.optflags & FLAG_s) { |
| struct sockaddr_in6 source; |
| |
| memset(&source, 0, sizeof(source)); |
| if(inet_pton(AF_INET6, TT.src_ip, &(source.sin6_addr)) <= 0) |
| error_exit("bad address: %s", TT.src_ip); |
| |
| if (bind(TT.snd_sock,(struct sockaddr*)&source, |
| sizeof(struct sockaddr_in6)) < 0) |
| error_exit("bind: Cannot assign requested address"); |
| } else { |
| struct sockaddr_in6 prb; |
| socklen_t len = sizeof(prb); |
| int p_fd = xsocket(AF_INET6, SOCK_DGRAM, 0); |
| if (toys.optflags & FLAG_i) bind_to_interface(p_fd); |
| |
| ((struct sockaddr_in6 *)&dest)->sin6_port = htons(1025); |
| if (connect(p_fd, (struct sockaddr *)&dest, sizeof(struct sockaddr_in6)) < 0) |
| perror_exit("can't connect to remote host"); |
| if(getsockname(p_fd, (struct sockaddr *)&prb, &len)) |
| error_exit("probe addr failed"); |
| close(p_fd); |
| prb.sin6_port = 0; |
| if (bind(TT.snd_sock, (struct sockaddr*)&prb, |
| sizeof(struct sockaddr_in6))) perror_exit("bind"); |
| if (bind(TT.recv_sock, (struct sockaddr*)&prb, |
| sizeof(struct sockaddr_in6))) perror_exit("bind"); |
| } |
| |
| inet_ntop(AF_INET6, &((struct sockaddr_in6 *)&dest)->sin6_addr, |
| addr_str, INET6_ADDRSTRLEN); |
| xprintf("traceroute6 to %s(%s)", toys.optargs[0], addr_str); |
| } |
| |
| if (toys.optflags & FLAG_s) xprintf(" from %s",TT.src_ip); |
| xprintf(", %ld hops max, %u byte packets\n", TT.max_ttl, TT.msg_len); |
| |
| do_trace(); |
| } |