aboutsummaryrefslogtreecommitdiff
path: root/toys/pending/traceroute.c
diff options
context:
space:
mode:
authorAshwini Sharma <ak.ashwini1981@gmail.com>2013-12-23 07:15:13 -0600
committerAshwini Sharma <ak.ashwini1981@gmail.com>2013-12-23 07:15:13 -0600
commit25c1f3a967347c0a3b3e565b358b0e06b3f90225 (patch)
treeeef3c2a78b5fcbdbe756f68bd079d9c753761e0c /toys/pending/traceroute.c
parentafba5b8efdf1bac2c02ca787840a2be053c800f7 (diff)
downloadtoybox-25c1f3a967347c0a3b3e565b358b0e06b3f90225.tar.gz
IPv6 support is added into traceroute command.
traceroute6 is made as an old toy of traceroute.
Diffstat (limited to 'toys/pending/traceroute.c')
-rw-r--r--toys/pending/traceroute.c598
1 files changed, 398 insertions, 200 deletions
diff --git a/toys/pending/traceroute.c b/toys/pending/traceroute.c
index 832bda5e..a0cf00c3 100644
--- a/toys/pending/traceroute.c
+++ b/toys/pending/traceroute.c
@@ -2,25 +2,30 @@
*
* 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.ashwini@gmail.com>
*
* 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 @@ config TRACEROUTE
-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 <netinet/udp.h>
#include <netinet/ip_icmp.h>
+#include <netinet/ip6.h>
+#include <netinet/icmp6.h>
GLOBALS(
long max_ttl;
@@ -49,29 +58,33 @@ GLOBALS(
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 @@ static u_int16_t in_cksum(u_int16_t *p, u_int len)
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)
+{
+ 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 *rp, *info, hint;
+ 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 @@ static void do_trace()
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 @@ static void do_trace()
|| 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';
- for (node = TT.loose_source; node; node = node->next, lsrr++) {
- struct sockaddr_in sin;
+ if(!TT.istraceroute6 && (toys.optflags & FLAG_g)) {
+ struct arg_list *node;
- 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]);
- }
+ for (node = TT.loose_source; node; node = node->next, lsrr++) {
+ struct sockaddr_in sin;
- pack_size = sizeof(struct ip) + opt_len;
- pack_size += (toys.optflags & FLAG_U) ? sizeof(struct udphdr)
- + sizeof(struct payload_s) : ICMP_HD_SIZE;
+ 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 = get_int_value(toys.optargs[1], pack_size, 32768);//max packet 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 (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);
-
- resolve_addr(toys.optargs[0], ((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] = 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");
+ 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");
}
- if (setsockopt(TT.snd_sock, SOL_SOCKET, SO_SNDBUF, &TT.msg_len, sizeof(TT.msg_len)) < 0)
- perror_exit("SO_SNDBUF failed ");
+ 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.optflags & FLAG_t) &&
- setsockopt(TT.snd_sock, IPPROTO_IP, IP_TOS, &tyser, sizeof(tyser)) < 0)
- perror_exit("IP_TOS %d failed ", TT.tos);
+ 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 ");
+ 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);
- 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 ");
+ 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");
+ }
- TT.packet = xmalloc(TT.msg_len);
- TT.ident = getpid();
+ if(TT.first_ttl > TT.max_ttl)
+ error_exit("ERROR :Range for -f is 1 to %d (max ttl)", TT.max_ttl);
- 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);
+ 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(TT.first_ttl > TT.max_ttl)
- error_exit("ERROR :Range for -f is 1 to %d (max ttl)", TT.max_ttl);
+ 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);
- 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();
}