# HG changeset patch # User Ashwini Sharma # Date 1387804513 21600 # Node ID f10898e637ea6867a20105610ef08bb528054aba # Parent faf7117c448919aaa1d0fee459fd58269fc83c23 IPv6 support is added into traceroute command. traceroute6 is made as an old toy of traceroute. diff -r faf7117c4489 -r f10898e637ea toys/pending/traceroute.c --- a/toys/pending/traceroute.c Mon Dec 23 06:49:38 2013 -0600 +++ b/toys/pending/traceroute.c Mon Dec 23 07:15:13 2013 -0600 @@ -2,25 +2,30 @@ * * Copyright 2012 Madhur Verma * Copyright 2013 Kyungwan Han + * Copyright 2013 Bilal Qureshi + * Copyright 2013 Ashwini Kumar * * No Standard -USE_TRACEROUTE(NEWTOY(traceroute, "<1>2f#<1>255=1z#<0>86400=0g*w#<0>86400=5t#<0>255=0s:q#<1>255=3p#<1>65535=33434m#<1>255=30rvndlIUF64", TOYFLAG_USR|TOYFLAG_BIN)) - +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, OPTSTR_traceroute, TOYFLAG_STAYROOT|TOYFLAG_USR|TOYFLAG_BIN)) config TRACEROUTE bool "traceroute" - default n + default y help - usage: traceroute [-FUIldnvr] [-f 1ST_TTL] [-m MAXTTL] [-p PORT] [-q PROBES] + 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 - -F Set the don't fragment bit - -U Use UDP datagrams instead of ICMP ECHO - -I Use ICMP ECHO instead of UDP datagrams - -l Display the TTL value of the returned packet - -f Start from the 1ST_TTL hop (instead from 1)(RANGE 1 to 255) + -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 @@ -31,13 +36,17 @@ -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) - -z Pause Time in milisec (default 0)(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 #include +#include +#include GLOBALS( long max_ttl; @@ -49,29 +58,33 @@ 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; - struct ip *packet; - uint32_t gw_list[9]; + char *packet; uint32_t ident; + int istraceroute6; ) +#ifndef SOL_IPV6 +# define SOL_IPV6 IPPROTO_IPV6 +#endif -#define ICMP_HD_SIZE 8 -#define send_icmp ((struct icmp *)(TT.packet + 1)) -#define send_udp ((struct udphdr *)(TT.packet + 1)) +#define ICMP_HD_SIZE4 8 +#define USEC 1000000ULL struct payload_s { - unsigned char seq; - unsigned char ttl; - struct timeval tv; + uint32_t seq; + uint32_t ident; }; -static struct payload_s *send_data; -static struct sockaddr_in dest, from; +char addr_str[INET6_ADDRSTRLEN]; +struct sockaddr_storage dest; -// Computes and returns checksum SUM of buffer P of length LEN +//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; @@ -93,94 +106,131 @@ return (~sum); } -/* - * sends a single probe packet with sequence SEQ and - * time-to-live TTL - */ -static void send_probe(int seq, int ttl) +//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_data->seq = seq; - send_data->ttl = ttl; - dest.sin_port = TT.port + seq; + send_data4->seq = seq; + send_data4->ident = TT.ident; + ((struct sockaddr_in *)&dest)->sin_port = TT.port + seq; + out = send_data4; } else { - send_icmp->icmp_seq = htons(seq); - send_icmp->icmp_cksum = 0; - send_icmp->icmp_cksum = in_cksum((uint16_t *) send_icmp, TT.msg_len - sizeof(struct ip)); - if (send_icmp->icmp_cksum == 0) send_icmp->icmp_cksum = 0xffff; + 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); - if (toys.optflags & FLAG_U) { - out = send_data; - len = sizeof(struct payload_s); - } else { - out = send_icmp; - len = TT.msg_len - sizeof(struct ip); - } - res = sendto(TT.snd_sock, out, len, 0, (struct sockaddr *) &dest, sizeof(dest)); + 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"); } -static void resolve_addr(char *host, int type, int proto, struct sockaddr_in *sock) +//sends a single probe packet with sequence(SEQ) and time-to-live(TTL) +static void send_probe6(int seq, int ttl) { - struct addrinfo *rp, *info, hint; + 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 = AF_INET; + hint.ai_family = family; hint.ai_socktype = type; hint.ai_protocol = proto; ret = getaddrinfo(host, NULL, &hint, &info); - if (ret || !info) perror_exit("bad address: %s ", host); + if (ret || !info) error_exit("bad address: %s ", host); - for (rp = info; rp; rp = rp->ai_next) { - if (rp->ai_addrlen == sizeof(struct sockaddr_in)) { - memcpy(sock, rp->ai_addr, rp->ai_addrlen); - break; - } - } - freeaddrinfo(info); - if (!rp) perror_exit("Resolve failed "); + 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; + int probe, dest_reach = 0, print_verbose = 1; struct timeval t1, t2; - struct sockaddr_in last; + struct sockaddr_storage last_addr; - memset(&last, 0, sizeof(last)); + memset(&last_addr, 0, sizeof(last_addr)); fexit = 0; - printf("%2d", ttl); + xprintf("%2d", ttl); for (probe = 0, seq = 0; probe < TT.ttl_probes; ++probe) { int res = 0, tleft; fflush(NULL); - if (probe && (toys.optflags & FLAG_z)) usleep(TT.pause_time * 1000); + if (!TT.istraceroute6) + if (probe && (toys.optflags & FLAG_z)) usleep(TT.pause_time * 1000); - send_probe(++seq, ttl); + 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) { - if (!(res = poll(pfd, 1, tleft))) { - printf(" *"); + unsigned delta = 0; + if (!(res = poll(pfd, 1, tleft))) { + xprintf(" *"); break; } gettimeofday(&t2, NULL); @@ -188,18 +238,21 @@ 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(from); - struct ip *rcv_pkt = (struct ip*) toybuf; - int rcv_len, pmtu = 0; + unsigned addrlen = sizeof(struct sockaddr_storage); + int rcv_len, icmp_res = 0; - rcv_len = recvfrom(TT.recv_sock, rcv_pkt, sizeof(toybuf), + rcv_len = recvfrom(TT.recv_sock, toybuf, sizeof(toybuf), MSG_DONTWAIT, (struct sockaddr *) &from, &addrlen); if (rcv_len <= 0) continue; - else { + + if (!TT.istraceroute6) { + int pmtu = 0; + struct ip *rcv_pkt = (struct ip*) toybuf; struct icmp *ricmp; - int icmp_res = 0; ricmp = (struct icmp *) ((void*)rcv_pkt + (rcv_pkt->ip_hl << 2)); if (ricmp->icmp_code == ICMP_UNREACH_NEEDFRAG) @@ -210,234 +263,379 @@ || ricmp->icmp_type == ICMP_UNREACH || ricmp->icmp_type == ICMP_ECHOREPLY) { - struct ip *hip; struct udphdr *hudp; struct icmp *hicmp; + struct ip *hip = &ricmp->icmp_ip; - hip = &ricmp->icmp_ip; if (toys.optflags & FLAG_U) { - hudp = (struct udphdr*) (hip + (hip->ip_hl << 2)); - if ((hip->ip_hl << 2) + 12 <= (rcv_len - (rcv_pkt->ip_hl << 2)) + 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 == htons(TT.port + seq)) - icmp_res = (ricmp->icmp_type == ICMP_TIMXCEED ?-1 : ricmp->icmp_code); + && 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 == htons(TT.ident) - && ricmp->icmp_seq == htons(seq)) + if (ricmp->icmp_type == ICMP_ECHOREPLY + && ricmp->icmp_id == ntohs(TT.ident) + && ricmp->icmp_seq == ntohs(seq)) icmp_res = ICMP_UNREACH_PORT; - - if ((hip->ip_hl << 2) + ICMP_HD_SIZE <= (rcv_len - (rcv_pkt->ip_hl << 2)) + 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); + icmp_res = (ricmp->icmp_type == ICMP_TIMXCEED ? -1 : + ricmp->icmp_code); } } if (!icmp_res) continue; if (addrlen > 0) { - unsigned delta = (t2.tv_sec * 1000000ULL + t2.tv_usec) - - (t1.tv_sec * 1000000ULL + t1.tv_usec); - - if (memcmp(&last.sin_addr, &from.sin_addr, sizeof(struct in_addr))) { + 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(from), host, NI_MAXHOST, NULL, 0, 0)) - printf(" %s (", host); - else printf(" %s (", inet_ntoa(from.sin_addr)); + 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)); } - printf(" %s", inet_ntoa(from.sin_addr)); - if (!(toys.optflags & FLAG_n) ) printf(")"); - last = from; + xprintf(" %s", inet_ntoa( + ((struct sockaddr_in *)&from)->sin_addr)); + if (!(toys.optflags & FLAG_n)) xprintf(")"); + memcpy(&last_addr, &from, sizeof(from)); } - printf(" %u.%03u ms", delta / 1000, delta % 1000); - if (toys.optflags & FLAG_l) printf(" (%d)", rcv_pkt->ip_ttl); + xprintf(" %u.%03u ms", delta / 1000, delta % 1000); + if (toys.optflags & FLAG_l) xprintf(" (%d)", rcv_pkt->ip_ttl); if (toys.optflags & FLAG_v) { - printf(" %d bytes from %s : icmp type %d code %d\t", - rcv_len, inet_ntoa(from.sin_addr), + 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 printf("\t!H"); + } else xprintf("\t!H"); switch (icmp_res) { case ICMP_UNREACH_PORT: - if (rcv_pkt->ip_ttl <= 1) printf(" !"); + if (rcv_pkt->ip_ttl <= 1) xprintf(" !"); dest_reach = 1; break; case ICMP_UNREACH_NET: - printf(" !N"); + xprintf(" !N"); ++fexit; break; case ICMP_UNREACH_HOST: - printf(" !H"); + xprintf(" !H"); ++fexit; break; case ICMP_UNREACH_PROTOCOL: - printf(" !P"); + xprintf(" !P"); dest_reach = 1; break; case ICMP_UNREACH_NEEDFRAG: - printf(" !F-%d", pmtu); + xprintf(" !F-%d", pmtu); ++fexit; break; case ICMP_UNREACH_SRCFAIL: - printf(" !S"); + xprintf(" !S"); ++fexit; break; case ICMP_UNREACH_FILTER_PROHIB: case ICMP_UNREACH_NET_PROHIB: - printf(" !A"); + xprintf(" !A"); ++fexit; break; case ICMP_UNREACH_HOST_PROHIB: - printf(" !C"); + xprintf(" !C"); ++fexit; break; case ICMP_UNREACH_HOST_PRECEDENCE: - printf(" !V"); + xprintf(" !V"); ++fexit; break; case ICMP_UNREACH_PRECEDENCE_CUTOFF: - printf(" !C"); + xprintf(" !C"); ++fexit; break; case ICMP_UNREACH_NET_UNKNOWN: case ICMP_UNREACH_HOST_UNKNOWN: - printf(" !U"); + xprintf(" !U"); ++fexit; break; case ICMP_UNREACH_ISOLATED: - printf(" !I"); + xprintf(" !I"); ++fexit; break; case ICMP_UNREACH_TOSNET: case ICMP_UNREACH_TOSHOST: - printf(" !T"); + 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 (!memcmp(&from.sin_addr, &dest.sin_addr, sizeof(struct in_addr)) - || dest_reach || (fexit >= TT.ttl_probes -1)) - break; + 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, tyser = 0; - int set = 1, lsrr = 0; + 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; - if (toys.optflags & FLAG_g) { - struct arg_list *node; + 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; - 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 - memset( &sin, 0, sizeof(sin)); - if (lsrr >= 8) error_exit("no more than 8 gateways"); // NGATEWAYS - resolve_addr(node->arg, SOCK_STREAM, 0, &sin); - TT.gw_list[lsrr] = sin.sin_addr.s_addr; - } - opt_len = (lsrr + 1) * sizeof(TT.gw_list[0]); + 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"); } - pack_size = sizeof(struct ip) + opt_len; - pack_size += (toys.optflags & FLAG_U) ? sizeof(struct udphdr) - + sizeof(struct payload_s) : ICMP_HD_SIZE; + 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); - if (toys.optargs[1]) - TT.msg_len = get_int_value(toys.optargs[1], pack_size, 32768);//max packet size + 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); - TT.msg_len = (TT.msg_len < pack_size) ? pack_size : TT.msg_len; - TT.recv_sock = xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP); - if (toys.optflags & FLAG_d - && (setsockopt(TT.recv_sock, SOL_SOCKET, SO_DEBUG, &set, sizeof(set)) < 0)) - perror_exit("SO_DEBUG failed "); - if (toys.optflags & FLAG_r - && (setsockopt(TT.recv_sock, SOL_SOCKET, SO_DONTROUTE, &set, sizeof(set)) < 0)) - perror_exit("SO_DONTROUTE failed "); + 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 (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 (!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(); - resolve_addr(toys.optargs[0], ((toys.optflags & FLAG_U) ? SOCK_DGRAM : SOCK_RAW), - ((toys.optflags & FLAG_U) ? IPPROTO_UDP : IPPROTO_ICMP), &dest); + if (!TT.istraceroute6) { + if (!(toys.optflags & FLAG_U)) TT.ident |= 0x8000; + if (toys.optflags & FLAG_s) { + struct sockaddr_in source; - if (lsrr > 0) { - unsigned char optlist[MAX_IPOPTLEN]; - unsigned size; + 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"); + } - TT.gw_list[lsrr] = dest.sin_addr.s_addr; - ++lsrr; + 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; - 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); + 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); - if (setsockopt(TT.snd_sock, IPPROTO_IP, IP_OPTIONS, - (char *)optlist, size + sizeof(TT.gw_list[0])) < 0) - perror_exit("LSRR IP_OPTIONS"); + ((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 (setsockopt(TT.snd_sock, SOL_SOCKET, SO_SNDBUF, &TT.msg_len, sizeof(TT.msg_len)) < 0) - perror_exit("SO_SNDBUF failed "); - - 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 - - if ((toys.optflags & FLAG_d) - && (setsockopt(TT.snd_sock, SOL_SOCKET, SO_DEBUG, &set, sizeof(set)) < 0)) - perror_exit("SO_DEBUG failed "); - if ((toys.optflags & FLAG_r) && - (setsockopt(TT.snd_sock, SOL_SOCKET, SO_DONTROUTE, &set, sizeof(set)) < 0)) - perror_exit("SO_DONTROUTE failed "); - - - TT.packet = xmalloc(TT.msg_len); - TT.ident = getpid(); + 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); - if (toys.optflags & FLAG_U) send_data = (struct payload_s *) (send_udp + 1); - else { - TT.ident |= 0x8000; - send_icmp->icmp_type = ICMP_ECHO; - send_icmp->icmp_id = htons(TT.ident); - } - if (toys.optflags & FLAG_s) { - struct sockaddr_in *source = xzalloc(sizeof(struct sockaddr_in)); - inet_aton(TT.src_ip, &source->sin_addr); - if (setsockopt(TT.snd_sock, IPPROTO_IP, IP_MULTICAST_IF, - (struct sockaddr*)source, sizeof(*source))) - perror_exit("can't set multicast source interface"); - if (bind(TT.snd_sock,(struct sockaddr*)source, sizeof(*source))) - perror_exit("bind"); - free(source); - } - - if(TT.first_ttl > TT.max_ttl) - error_exit("ERROR :Range for -f is 1 to %d (max ttl)", TT.max_ttl); - - printf("traceroute to %s(%s)", toys.optargs[0], inet_ntoa(dest.sin_addr)); - if (toys.optflags & FLAG_s) printf(" from %s", TT.src_ip); - printf(", %ld hops max, %u byte packets\n", TT.max_ttl, TT.msg_len); - do_trace(); }