aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeonid Lisovskiy <lly.dev@gmail.com>2009-11-23 06:20:09 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2009-11-23 06:20:09 +0100
commit4c06531d5e2b053b642cea6fc4e7bc91ea4cbd26 (patch)
treed652a32a9dcc9e1acaff57bf019211068db55cdc
parent0d56568654973a522bd005616b86d4dc8c833c81 (diff)
downloadbusybox-w32-4c06531d5e2b053b642cea6fc4e7bc91ea4cbd26.tar.gz
busybox-w32-4c06531d5e2b053b642cea6fc4e7bc91ea4cbd26.tar.bz2
busybox-w32-4c06531d5e2b053b642cea6fc4e7bc91ea4cbd26.zip
traceroute6: new applet by Leonid Lisovskiy. +1562 bytes
Signed-off-by: Leonid Lisovskiy <lly.dev@gmail.com> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--include/applets.h1
-rw-r--r--include/usage.h27
-rw-r--r--networking/Config.in7
-rw-r--r--networking/traceroute.c502
4 files changed, 428 insertions, 109 deletions
diff --git a/include/applets.h b/include/applets.h
index a2d1e95a5..d1a84eeaf 100644
--- a/include/applets.h
+++ b/include/applets.h
@@ -395,6 +395,7 @@ IF_TOP(APPLET(top, _BB_DIR_USR_BIN, _BB_SUID_DROP))
395IF_TOUCH(APPLET_NOFORK(touch, touch, _BB_DIR_BIN, _BB_SUID_DROP, touch)) 395IF_TOUCH(APPLET_NOFORK(touch, touch, _BB_DIR_BIN, _BB_SUID_DROP, touch))
396IF_TR(APPLET(tr, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 396IF_TR(APPLET(tr, _BB_DIR_USR_BIN, _BB_SUID_DROP))
397IF_TRACEROUTE(APPLET(traceroute, _BB_DIR_USR_BIN, _BB_SUID_MAYBE)) 397IF_TRACEROUTE(APPLET(traceroute, _BB_DIR_USR_BIN, _BB_SUID_MAYBE))
398IF_TRACEROUTE6(APPLET(traceroute6, _BB_DIR_USR_BIN, _BB_SUID_MAYBE))
398IF_TRUE(APPLET_NOFORK(true, true, _BB_DIR_BIN, _BB_SUID_DROP, true)) 399IF_TRUE(APPLET_NOFORK(true, true, _BB_DIR_BIN, _BB_SUID_DROP, true))
399IF_TTY(APPLET(tty, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 400IF_TTY(APPLET(tty, _BB_DIR_USR_BIN, _BB_SUID_DROP))
400IF_TTYSIZE(APPLET(ttysize, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 401IF_TTYSIZE(APPLET(ttysize, _BB_DIR_USR_BIN, _BB_SUID_DROP))
diff --git a/include/usage.h b/include/usage.h
index 3ccf160bd..920f8e8c9 100644
--- a/include/usage.h
+++ b/include/usage.h
@@ -4648,17 +4648,18 @@
4648 "hello world\n" 4648 "hello world\n"
4649 4649
4650#define traceroute_trivial_usage \ 4650#define traceroute_trivial_usage \
4651 "[-FIldnrv] [-f 1st_ttl] [-m max_ttl] [-p port#] [-q nqueries]\n" \ 4651 "[-46FIldnrv] [-f 1st_ttl] [-m max_ttl] [-p port#] [-q nqueries]\n" \
4652 " [-s src_addr] [-t tos] [-w wait] [-g gateway] [-i iface]\n" \ 4652 " [-s src_addr] [-t tos] [-w wait] [-g gateway] [-i iface]\n" \
4653 " [-z pausemsecs] HOST [data size]" 4653 " [-z pausemsecs] HOST [data size]"
4654#define traceroute_full_usage "\n\n" \ 4654#define traceroute_full_usage "\n\n" \
4655 "Trace the route to HOST\n" \ 4655 "Trace the route to HOST\n" \
4656 "\nOptions:" \ 4656 "\nOptions:" \
4657 "\n -4, -6 Force IPv4 or IPv6 hostname resolution" \
4657 "\n -F Set the don't fragment bit" \ 4658 "\n -F Set the don't fragment bit" \
4658 "\n -I Use ICMP ECHO instead of UDP datagrams" \ 4659 "\n -I Use ICMP ECHO instead of UDP datagrams" \
4659 "\n -l Display the ttl value of the returned packet" \ 4660 "\n -l Display the ttl value of the returned packet" \
4660 "\n -d Set SO_DEBUG options to socket" \ 4661 "\n -d Set SO_DEBUG options to socket" \
4661 "\n -n Print hop addresses numerically rather than symbolically" \ 4662 "\n -n Print numeric addresses" \
4662 "\n -r Bypass the normal routing tables and send directly to a host" \ 4663 "\n -r Bypass the normal routing tables and send directly to a host" \
4663 "\n -v Verbose" \ 4664 "\n -v Verbose" \
4664 "\n -m max_ttl Max time-to-live (max number of hops)" \ 4665 "\n -m max_ttl Max time-to-live (max number of hops)" \
@@ -4668,9 +4669,29 @@
4668 "\n -s src_addr IP address to use as the source address" \ 4669 "\n -s src_addr IP address to use as the source address" \
4669 "\n -t tos Type-of-service in probe packets (default 0)" \ 4670 "\n -t tos Type-of-service in probe packets (default 0)" \
4670 "\n -w wait Time in seconds to wait for a response" \ 4671 "\n -w wait Time in seconds to wait for a response" \
4671 "\n (default 3 sec)" \ 4672 "\n (default 3)" \
4672 "\n -g Loose source route gateway (8 max)" \ 4673 "\n -g Loose source route gateway (8 max)" \
4673 4674
4675#define traceroute6_trivial_usage \
4676 "[-dnrv] [-m max_ttl] [-p port#] [-q nqueries]\n" \
4677 " [-s src_addr] [-t tos] [-w wait] [-i iface]\n" \
4678 " HOST [data size]"
4679#define traceroute6_full_usage "\n\n" \
4680 "Trace the route to HOST\n" \
4681 "\nOptions:" \
4682 "\n -d Set SO_DEBUG options to socket" \
4683 "\n -n Print numeric addresses" \
4684 "\n -r Bypass the normal routing tables and send directly to a host" \
4685 "\n -v Verbose" \
4686 "\n -m max_ttl Max time-to-live (max number of hops)" \
4687 "\n -p port# Base UDP port number used in probes" \
4688 "\n (default is 33434)" \
4689 "\n -q nqueries Number of probes per 'ttl' (default 3)" \
4690 "\n -s src_addr IP address to use as the source address" \
4691 "\n -t tos Type-of-service in probe packets (default 0)" \
4692 "\n -w wait Time in seconds to wait for a response" \
4693 "\n (default 3)" \
4694
4674#define true_trivial_usage \ 4695#define true_trivial_usage \
4675 "" 4696 ""
4676#define true_full_usage "\n\n" \ 4697#define true_full_usage "\n\n" \
diff --git a/networking/Config.in b/networking/Config.in
index 3d29622da..668823784 100644
--- a/networking/Config.in
+++ b/networking/Config.in
@@ -888,6 +888,13 @@ config TRACEROUTE
888 help 888 help
889 Utility to trace the route of IP packets. 889 Utility to trace the route of IP packets.
890 890
891config TRACEROUTE6
892 bool "traceroute6"
893 default n
894 depends on FEATURE_IPV6 && TRACEROUTE
895 help
896 Utility to trace the route of IPv6 packets.
897
891config FEATURE_TRACEROUTE_VERBOSE 898config FEATURE_TRACEROUTE_VERBOSE
892 bool "Enable verbose output" 899 bool "Enable verbose output"
893 default n 900 default n
diff --git a/networking/traceroute.c b/networking/traceroute.c
index d36ddee14..18a8c25d4 100644
--- a/networking/traceroute.c
+++ b/networking/traceroute.c
@@ -23,6 +23,23 @@
23 */ 23 */
24 24
25/* 25/*
26 * traceroute6
27 *
28 * Modified for NRL 4.4BSD IPv6 release.
29 * 07/31/96 bgp
30 *
31 * Modified for Linux IPv6 by Pedro Roque <roque@di.fc.ul.pt>
32 * 31/07/1996
33 *
34 * As ICMP error messages for IPv6 now include more than 8 bytes
35 * UDP datagrams are now sent via an UDP socket instead of magic
36 * RAW socket tricks.
37 *
38 * Converted to busybox applet by Leonid Lisovskiy <lly@sf.net>
39 * 2009-11-16
40 */
41
42/*
26 * traceroute host - trace the route ip packets follow going to "host". 43 * traceroute host - trace the route ip packets follow going to "host".
27 * 44 *
28 * Attempt to trace the route an ip packet would follow to some 45 * Attempt to trace the route an ip packet would follow to some
@@ -231,7 +248,8 @@
231 248
232 249
233#define OPT_STRING "FIlnrdvxt:i:m:p:q:s:w:z:f:" \ 250#define OPT_STRING "FIlnrdvxt:i:m:p:q:s:w:z:f:" \
234 IF_FEATURE_TRACEROUTE_SOURCE_ROUTE("g:") 251 IF_FEATURE_TRACEROUTE_SOURCE_ROUTE("g:") \
252 "4" IF_TRACEROUTE6("6")
235enum { 253enum {
236 OPT_DONT_FRAGMNT = (1 << 0), /* F */ 254 OPT_DONT_FRAGMNT = (1 << 0), /* F */
237 OPT_USE_ICMP = (1 << 1) * ENABLE_FEATURE_TRACEROUTE_USE_ICMP, /* I */ 255 OPT_USE_ICMP = (1 << 1) * ENABLE_FEATURE_TRACEROUTE_USE_ICMP, /* I */
@@ -250,6 +268,9 @@ enum {
250 OPT_WAITTIME = (1 << 14), /* w */ 268 OPT_WAITTIME = (1 << 14), /* w */
251 OPT_PAUSE_MS = (1 << 15), /* z */ 269 OPT_PAUSE_MS = (1 << 15), /* z */
252 OPT_FIRST_TTL = (1 << 16), /* f */ 270 OPT_FIRST_TTL = (1 << 16), /* f */
271 OPT_SOURCE_ROUTE = (1 << 17) * ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE, /* g */
272 OPT_IPV4 = (1 << (17+ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE)), /* 4 */
273 OPT_IPV6 = (1 << (18+ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE)) * ENABLE_TRACEROUTE6, /* 6 */
253}; 274};
254#define verbose (option_mask32 & OPT_VERBOSE) 275#define verbose (option_mask32 & OPT_VERBOSE)
255 276
@@ -267,13 +288,21 @@ struct outdata_t {
267 struct timeval tv_UNUSED PACKED; /* time packet left */ 288 struct timeval tv_UNUSED PACKED; /* time packet left */
268}; 289};
269 290
291#if ENABLE_TRACEROUTE6
292struct outdata6_t {
293 uint32_t ident6;
294 uint32_t seq6;
295 struct timeval tv_UNUSED PACKED; /* time packet left */
296};
297#endif
298
270struct globals { 299struct globals {
271 struct ip *outip; 300 struct ip *outip;
272 struct outdata_t *outdata; 301 struct outdata_t *outdata;
273 len_and_sockaddr *dest_lsa; 302 len_and_sockaddr *dest_lsa;
274 int packlen; /* total length of packet */ 303 int packlen; /* total length of packet */
275 int pmtu; /* Path MTU Discovery (RFC1191) */ 304 int pmtu; /* Path MTU Discovery (RFC1191) */
276 uint16_t ident; 305 uint32_t ident;
277 uint16_t port; // 32768 + 666; /* start udp dest port # for probe packets */ 306 uint16_t port; // 32768 + 666; /* start udp dest port # for probe packets */
278 int waittime; // 5; /* time to wait for response (in seconds) */ 307 int waittime; // 5; /* time to wait for response (in seconds) */
279#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE 308#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
@@ -314,18 +343,30 @@ struct globals {
314#define outudp ((struct udphdr *)(outip + 1)) 343#define outudp ((struct udphdr *)(outip + 1))
315 344
316 345
346/* libbb candidate? tftp uses this idiom too */
347static len_and_sockaddr* dup_sockaddr(const len_and_sockaddr *lsa)
348{
349 len_and_sockaddr *new_lsa = xzalloc(LSA_LEN_SIZE + lsa->len);
350 memcpy(new_lsa, lsa, LSA_LEN_SIZE + lsa->len);
351 return new_lsa;
352}
353
354
317static int 355static int
318wait_for_reply(struct sockaddr_in *fromp) 356wait_for_reply(len_and_sockaddr *from_lsa, struct sockaddr *to)
319{ 357{
320 struct pollfd pfd[1]; 358 struct pollfd pfd[1];
321 int read_len = 0; 359 int read_len = 0;
322 socklen_t fromlen = sizeof(*fromp);
323 360
324 pfd[0].fd = rcvsock; 361 pfd[0].fd = rcvsock;
325 pfd[0].events = POLLIN; 362 pfd[0].events = POLLIN;
326 if (safe_poll(pfd, 1, waittime * 1000) > 0) 363 if (safe_poll(pfd, 1, waittime * 1000) > 0) {
327 read_len = recvfrom(rcvsock, recv_pkt, sizeof(recv_pkt), 0, 364 read_len = recv_from_to(rcvsock,
328 (struct sockaddr *)fromp, &fromlen); 365 recv_pkt, sizeof(recv_pkt),
366 /*flags:*/ 0,
367 &from_lsa->u.sa, to, from_lsa->len);
368 }
369
329 return read_len; 370 return read_len;
330} 371}
331 372
@@ -369,20 +410,30 @@ send_probe(int seq, int ttl)
369 void *out; 410 void *out;
370 411
371 /* Payload */ 412 /* Payload */
372 outdata->seq = seq; 413#if ENABLE_TRACEROUTE6
373 outdata->ttl = ttl; 414 if (dest_lsa->u.sa.sa_family == AF_INET6) {
415 struct outdata6_t *pkt = (struct outdata6_t *) outip;
416 pkt->ident6 = htonl(ident);
417 pkt->seq6 = htonl(seq);
418 /*gettimeofday(&pkt->tv, &tz);*/
419 } else
420#endif
421 {
422 outdata->seq = seq;
423 outdata->ttl = ttl;
374// UNUSED: was storing gettimeofday's result there, but never ever checked it 424// UNUSED: was storing gettimeofday's result there, but never ever checked it
375 /*memcpy(&outdata->tv, tp, sizeof(outdata->tv));*/ 425 /*memcpy(&outdata->tv, tp, sizeof(outdata->tv));*/
376
377 if (option_mask32 & OPT_USE_ICMP) {
378 outicmp->icmp_seq = htons(seq);
379 426
380 /* Always calculate checksum for icmp packets */ 427 if (option_mask32 & OPT_USE_ICMP) {
381 outicmp->icmp_cksum = 0; 428 outicmp->icmp_seq = htons(seq);
382 outicmp->icmp_cksum = in_cksum((uint16_t *)outicmp, 429
383 packlen - (sizeof(*outip) + optlen)); 430 /* Always calculate checksum for icmp packets */
384 if (outicmp->icmp_cksum == 0) 431 outicmp->icmp_cksum = 0;
385 outicmp->icmp_cksum = 0xffff; 432 outicmp->icmp_cksum = in_cksum((uint16_t *)outicmp,
433 packlen - (sizeof(*outip) + optlen));
434 if (outicmp->icmp_cksum == 0)
435 outicmp->icmp_cksum = 0xffff;
436 }
386 } 437 }
387 438
388//BUG! verbose is (x & OPT_VERBOSE), not a counter! 439//BUG! verbose is (x & OPT_VERBOSE), not a counter!
@@ -411,21 +462,32 @@ send_probe(int seq, int ttl)
411 } 462 }
412#endif 463#endif
413 464
465#if ENABLE_TRACEROUTE6
466 if (dest_lsa->u.sa.sa_family == AF_INET6) {
467 res = setsockopt(sndsock, SOL_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl));
468 if (res < 0)
469 bb_perror_msg_and_die("setsockopt UNICAST_HOPS %d", ttl);
470 out = outip;
471 len = packlen;
472 } else
473#endif
474 {
414#if defined(IP_TTL) 475#if defined(IP_TTL)
415 if (setsockopt(sndsock, IPPROTO_IP, IP_TTL, 476 if (setsockopt(sndsock, IPPROTO_IP, IP_TTL,
416 (char *)&ttl, sizeof(ttl)) < 0) { 477 (char *)&ttl, sizeof(ttl)) < 0) {
417 bb_perror_msg_and_die("setsockopt ttl %d", ttl); 478 bb_perror_msg_and_die("setsockopt ttl %d", ttl);
418 } 479 }
419#endif 480#endif
420 481 len = packlen - sizeof(*outip);
421 len = packlen - sizeof(*outip); 482 if (option_mask32 & OPT_USE_ICMP)
422 if (option_mask32 & OPT_USE_ICMP) 483 out = outicmp;
423 out = outicmp; 484 else {
424 else { 485 out = outdata;
425 out = outdata; 486 len -= sizeof(*outudp);
426 len -= sizeof(*outudp); 487 set_nport(dest_lsa, htons(port + seq));
427 set_nport(dest_lsa, htons(port + seq)); 488 }
428 } 489 }
490
429 res = xsendto(sndsock, out, len, &dest_lsa->u.sa, dest_lsa->len); 491 res = xsendto(sndsock, out, len, &dest_lsa->u.sa, dest_lsa->len);
430 if (res != len) { 492 if (res != len) {
431 bb_info_msg("sent %d octets, ret=%d", len, res); 493 bb_info_msg("sent %d octets, ret=%d", len, res);
@@ -436,7 +498,7 @@ send_probe(int seq, int ttl)
436/* 498/*
437 * Convert an ICMP "type" field to a printable string. 499 * Convert an ICMP "type" field to a printable string.
438 */ 500 */
439static inline const char * 501static const char *
440pr_type(unsigned char t) 502pr_type(unsigned char t)
441{ 503{
442 static const char *const ttab[] = { 504 static const char *const ttab[] = {
@@ -446,7 +508,23 @@ pr_type(unsigned char t)
446 "Param Problem", "Timestamp", "Timestamp Reply", "Info Request", 508 "Param Problem", "Timestamp", "Timestamp Reply", "Info Request",
447 "Info Reply", "Mask Request", "Mask Reply" 509 "Info Reply", "Mask Request", "Mask Reply"
448 }; 510 };
511# if ENABLE_TRACEROUTE6
512 static const char *const ttab6[] = {
513[0] "Error", "Dest Unreachable", "Packet Too Big", "Time Exceeded",
514[4] "Param Problem",
515[8] "Echo Request", "Echo Reply", "Membership Query", "Membership Report",
516[12] "Membership Reduction", "Router Solicit", "Router Advert", "Neighbor Solicit",
517[16] "Neighbor Advert", "Redirect",
518 };
449 519
520 if (dest_lsa->u.sa.sa_family == AF_INET6) {
521 if (t < 5)
522 return ttab6[t];
523 if (t < 128 || t > ND_REDIRECT)
524 return "OUT-OF-RANGE";
525 return ttab6[(t & 63) + 8];
526 }
527# endif
450 if (t >= ARRAY_SIZE(ttab)) 528 if (t >= ARRAY_SIZE(ttab))
451 return "OUT-OF-RANGE"; 529 return "OUT-OF-RANGE";
452 530
@@ -455,11 +533,11 @@ pr_type(unsigned char t)
455#endif 533#endif
456 534
457#if !ENABLE_FEATURE_TRACEROUTE_VERBOSE 535#if !ENABLE_FEATURE_TRACEROUTE_VERBOSE
458#define packet_ok(read_len, from, seq) \ 536#define packet4_ok(read_len, from, seq) \
459 packet_ok(read_len, seq) 537 packet4_ok(read_len, seq)
460#endif 538#endif
461static int 539static int
462packet_ok(int read_len, const struct sockaddr_in *from, int seq) 540packet4_ok(int read_len, const struct sockaddr_in *from, int seq)
463{ 541{
464 const struct icmp *icp; 542 const struct icmp *icp;
465 unsigned char type, code; 543 unsigned char type, code;
@@ -502,7 +580,7 @@ packet_ok(int read_len, const struct sockaddr_in *from, int seq)
502 && icp->icmp_id == htons(ident) 580 && icp->icmp_id == htons(ident)
503 && icp->icmp_seq == htons(seq) 581 && icp->icmp_seq == htons(seq)
504 ) { 582 ) {
505 return -2; 583 return ICMP_UNREACH_PORT+1;
506 } 584 }
507 585
508 hicmp = (struct icmp *)((unsigned char *)hip + hlen); 586 hicmp = (struct icmp *)((unsigned char *)hip + hlen);
@@ -544,6 +622,98 @@ packet_ok(int read_len, const struct sockaddr_in *from, int seq)
544 return 0; 622 return 0;
545} 623}
546 624
625#if ENABLE_TRACEROUTE6
626# if !ENABLE_FEATURE_TRACEROUTE_VERBOSE
627#define packet_ok(read_len, from_lsa, to, seq) \
628 packet_ok(read_len, from_lsa, seq)
629# endif
630static int
631packet_ok(int read_len, len_and_sockaddr *from_lsa,
632 struct sockaddr *to,
633 int seq)
634{
635 const struct icmp6_hdr *icp;
636 unsigned char type, code;
637
638 if (from_lsa->u.sa.sa_family == AF_INET)
639 return packet4_ok(read_len, &from_lsa->u.sin, seq);
640
641 icp = (struct icmp6_hdr *) recv_pkt;
642
643 type = icp->icmp6_type;
644 code = icp->icmp6_code;
645
646 if ((type == ICMP6_TIME_EXCEEDED && code == ICMP6_TIME_EXCEED_TRANSIT)
647 || type == ICMP6_DST_UNREACH
648 ) {
649 struct ip6_hdr *hip;
650 struct udphdr *up;
651 int nexthdr;
652
653 hip = (struct ip6_hdr *)(icp + 1);
654 up = (struct udphdr *) (hip + 1);
655 nexthdr = hip->ip6_nxt;
656
657 if (nexthdr == IPPROTO_FRAGMENT) {
658 nexthdr = *(unsigned char*)up;
659 up++;
660 }
661 if (nexthdr == IPPROTO_UDP) {
662 struct outdata6_t *pkt;
663
664 pkt = (struct outdata6_t *) (up + 1);
665
666 if (ntohl(pkt->ident6) == ident
667 && ntohl(pkt->seq6) == seq
668 ) {
669 return (type == ICMP6_TIME_EXCEEDED ? -1 : (code<<8)+1);
670 }
671 }
672
673 }
674
675# if ENABLE_FEATURE_TRACEROUTE_VERBOSE
676 if (verbose) {
677 unsigned char *p;
678 char pa1[MAXHOSTNAMELEN];
679 char pa2[MAXHOSTNAMELEN];
680 int i;
681
682 p = (unsigned char *) (icp + 1);
683
684 printf("\n%d bytes from %s to "
685 "%s: icmp type %d (%s) code %d\n",
686 read_len,
687 inet_ntop(AF_INET6, &from_lsa->u.sin6.sin6_addr, pa1, sizeof(pa1)),
688 inet_ntop(AF_INET6, &((struct sockaddr_in6*)to)->sin6_addr, pa2, sizeof(pa2)),
689 type, pr_type(type), icp->icmp6_code);
690
691 read_len -= sizeof(struct icmp6_hdr);
692 for (i = 0; i < read_len ; i++) {
693 if (i % 16 == 0)
694 printf("%04x:", i);
695 if (i % 4 == 0)
696 bb_putchar(' ');
697 printf("%02x", p[i]);
698 if ((i % 16 == 15) && (i + 1 < read_len))
699 bb_putchar('\n');
700 }
701 bb_putchar('\n');
702 }
703# endif
704
705 return 0;
706}
707#else /* !ENABLE_TRACEROUTE6 */
708static ALWAYS_INLINE int
709packet_ok(int read_len, len_and_sockaddr *from_lsa,
710 struct sockaddr *to UNUSED_PARAM,
711 int seq)
712{
713 return packet4_ok(read_len, &from_lsa->u.sin, seq);
714}
715#endif
716
547/* 717/*
548 * Construct an Internet address representation. 718 * Construct an Internet address representation.
549 * If the -n flag has been supplied, give 719 * If the -n flag has been supplied, give
@@ -572,17 +742,22 @@ print_inetname(const struct sockaddr *from)
572} 742}
573 743
574static void 744static void
575print(int read_len, const struct sockaddr_in *from) 745print(int read_len, const struct sockaddr *from, const struct sockaddr *to)
576{ 746{
577 print_inetname((const struct sockaddr*)from); 747 print_inetname(from);
578 if (verbose) {
579 const struct ip *ip;
580 int hlen;
581 748
582 ip = (struct ip *) recv_pkt; 749 if (verbose) {
583 hlen = ip->ip_hl << 2; 750 char *ina = xmalloc_sockaddr2dotted_noport(to);
584 read_len -= hlen; 751#if ENABLE_TRACEROUTE6
585 printf(" %d bytes to %s", read_len, inet_ntoa(ip->ip_dst)); 752 if (to->sa_family == AF_INET6) {
753 read_len -= sizeof(struct ip6_hdr);
754 } else
755#endif
756 {
757 read_len -= ((struct ip*)recv_pkt)->ip_hl << 2;
758 }
759 printf(" %d bytes to %s", read_len, ina);
760 free(ina);
586 } 761 }
587} 762}
588 763
@@ -598,9 +773,8 @@ print_delta_ms(unsigned t1p, unsigned t2p)
598 * [-m max_ttl] [ -p port] [-q nqueries] [-s src_addr] [-t tos] 773 * [-m max_ttl] [ -p port] [-q nqueries] [-s src_addr] [-t tos]
599 * [-w waittime] [-z pausemsecs] host [packetlen]" 774 * [-w waittime] [-z pausemsecs] host [packetlen]"
600 */ 775 */
601 776static int
602int traceroute_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 777common_traceroute_main(int op, char **argv)
603int traceroute_main(int argc UNUSED_PARAM, char **argv)
604{ 778{
605 int i; 779 int i;
606 int minpacket; 780 int minpacket;
@@ -609,7 +783,6 @@ int traceroute_main(int argc UNUSED_PARAM, char **argv)
609 int nprobes = 3; 783 int nprobes = 3;
610 int first_ttl = 1; 784 int first_ttl = 1;
611 unsigned pausemsecs = 0; 785 unsigned pausemsecs = 0;
612 unsigned op;
613 char *source; 786 char *source;
614 char *device; 787 char *device;
615 char *tos_str; 788 char *tos_str;
@@ -623,20 +796,29 @@ int traceroute_main(int argc UNUSED_PARAM, char **argv)
623 llist_t *source_route_list = NULL; 796 llist_t *source_route_list = NULL;
624 int lsrr = 0; 797 int lsrr = 0;
625#endif 798#endif
799#if ENABLE_TRACEROUTE6
800 sa_family_t af = AF_UNSPEC;
801#else
802 enum { af = AF_INET };
803#endif
626 int ttl; 804 int ttl;
627 int seq; 805 int seq;
806 len_and_sockaddr *from_lsa;
807 struct sockaddr *lastaddr;
808 struct sockaddr *to;
628 809
629 INIT_G(); 810 INIT_G();
630 811
631 /* minimum 1 arg */ 812 /* minimum 1 arg */
632 opt_complementary = "-1:x-x" IF_FEATURE_TRACEROUTE_SOURCE_ROUTE(":g::"); 813 opt_complementary = "-1:x-x" IF_FEATURE_TRACEROUTE_SOURCE_ROUTE(":g::");
633 op = getopt32(argv, OPT_STRING 814 op |= getopt32(argv, OPT_STRING
634 , &tos_str, &device, &max_ttl_str, &port_str, &nprobes_str 815 , &tos_str, &device, &max_ttl_str, &port_str, &nprobes_str
635 , &source, &waittime_str, &pausemsecs_str, &first_ttl_str 816 , &source, &waittime_str, &pausemsecs_str, &first_ttl_str
636#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE 817#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
637 , &source_route_list 818 , &source_route_list
638#endif 819#endif
639 ); 820 );
821 argv += optind;
640 822
641#if 0 /* IGNORED */ 823#if 0 /* IGNORED */
642 if (op & OPT_IP_CHKSUM) 824 if (op & OPT_IP_CHKSUM)
@@ -681,21 +863,53 @@ int traceroute_main(int argc UNUSED_PARAM, char **argv)
681 } 863 }
682#endif 864#endif
683 865
684 minpacket = sizeof(*outip) + SIZEOF_ICMP_HDR + sizeof(*outdata) + optlen; 866#if ENABLE_TRACEROUTE6
685 if (!(op & OPT_USE_ICMP)) 867 if (op & OPT_IPV4)
686 minpacket += sizeof(*outudp) - SIZEOF_ICMP_HDR; 868 af = AF_INET;
869 if (op & OPT_IPV6) {
870 af = AF_INET6;
871 minpacket = sizeof(struct outdata6_t);
872 } else
873#endif
874 {
875 minpacket = sizeof(*outip) + SIZEOF_ICMP_HDR
876 + sizeof(*outdata) + optlen;
877 if (!(op & OPT_USE_ICMP))
878 minpacket += sizeof(*outudp) - SIZEOF_ICMP_HDR;
879 }
687 packlen = minpacket; 880 packlen = minpacket;
688 881
689 /* Process destination and optional packet size */ 882 /* Process destination and optional packet size */
690 argv += optind;
691 if (argv[1]) 883 if (argv[1])
692 packlen = xatoul_range(argv[1], minpacket, 32 * 1024); 884 packlen = xatoul_range(argv[1], minpacket, 32 * 1024);
885#if ENABLE_TRACEROUTE6
886 dest_lsa = xhost_and_af2sockaddr(argv[0], port, af);
887 af = dest_lsa->u.sa.sa_family;
888#else
693 dest_lsa = xhost2sockaddr(argv[0], port); 889 dest_lsa = xhost2sockaddr(argv[0], port);
890#endif
694 891
695 /* Ensure the socket fds won't be 0, 1 or 2 */ 892 /* Ensure the socket fds won't be 0, 1 or 2 */
696 bb_sanitize_stdio(); 893 bb_sanitize_stdio();
697 894
698 xmove_fd(xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP), rcvsock); 895#if ENABLE_TRACEROUTE6
896 if (af == AF_INET6) {
897 xmove_fd(xsocket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6), rcvsock);
898# ifdef IPV6_RECVPKTINFO
899 setsockopt(rcvsock, SOL_IPV6, IPV6_RECVPKTINFO,
900 &const_int_1, sizeof(const_int_1));
901 setsockopt(rcvsock, SOL_IPV6, IPV6_2292PKTINFO,
902 &const_int_1, sizeof(const_int_1));
903# else
904 setsockopt(rcvsock, SOL_IPV6, IPV6_PKTINFO,
905 &const_int_1, sizeof(const_int_1));
906# endif
907 } else
908#endif
909 {
910 xmove_fd(xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP), rcvsock);
911 }
912
699#if TRACEROUTE_SO_DEBUG 913#if TRACEROUTE_SO_DEBUG
700 if (op & OPT_DEBUG) 914 if (op & OPT_DEBUG)
701 setsockopt(rcvsock, SOL_SOCKET, SO_DEBUG, 915 setsockopt(rcvsock, SOL_SOCKET, SO_DEBUG,
@@ -705,34 +919,45 @@ int traceroute_main(int argc UNUSED_PARAM, char **argv)
705 setsockopt(rcvsock, SOL_SOCKET, SO_DONTROUTE, 919 setsockopt(rcvsock, SOL_SOCKET, SO_DONTROUTE,
706 &const_int_1, sizeof(const_int_1)); 920 &const_int_1, sizeof(const_int_1));
707 921
708 if (op & OPT_USE_ICMP) 922#if ENABLE_TRACEROUTE6
709 xmove_fd(xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP), sndsock); 923 if (af == AF_INET6) {
710 else 924 static const int two = 2;
711 xmove_fd(xsocket(AF_INET, SOCK_DGRAM, 0), sndsock); 925 if (setsockopt(rcvsock, SOL_RAW, IPV6_CHECKSUM, &two, sizeof(two)) < 0)
926 bb_perror_msg_and_die("setsockopt RAW_CHECKSUM");
927 xmove_fd(xsocket(af, SOCK_DGRAM, 0), sndsock);
928 } else
929#endif
930 {
931 if (op & OPT_USE_ICMP)
932 xmove_fd(xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP), sndsock);
933 else
934 xmove_fd(xsocket(AF_INET, SOCK_DGRAM, 0), sndsock);
712#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE && defined IP_OPTIONS 935#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE && defined IP_OPTIONS
713 if (lsrr > 0) { 936 if (lsrr > 0) {
714 unsigned char optlist[MAX_IPOPTLEN]; 937 unsigned char optlist[MAX_IPOPTLEN];
715 938
716 /* final hop */ 939 /* final hop */
717 gwlist[lsrr] = dest_lsa->u.sin.sin_addr.s_addr; 940 gwlist[lsrr] = dest_lsa->u.sin.sin_addr.s_addr;
718 ++lsrr; 941 ++lsrr;
719 942
720 /* force 4 byte alignment */ 943 /* force 4 byte alignment */
721 optlist[0] = IPOPT_NOP; 944 optlist[0] = IPOPT_NOP;
722 /* loose source route option */ 945 /* loose source route option */
723 optlist[1] = IPOPT_LSRR; 946 optlist[1] = IPOPT_LSRR;
724 i = lsrr * sizeof(gwlist[0]); 947 i = lsrr * sizeof(gwlist[0]);
725 optlist[2] = i + 3; 948 optlist[2] = i + 3;
726 /* pointer to LSRR addresses */ 949 /* pointer to LSRR addresses */
727 optlist[3] = IPOPT_MINOFF; 950 optlist[3] = IPOPT_MINOFF;
728 memcpy(optlist + 4, gwlist, i); 951 memcpy(optlist + 4, gwlist, i);
729 952
730 if (setsockopt(sndsock, IPPROTO_IP, IP_OPTIONS, 953 if (setsockopt(sndsock, IPPROTO_IP, IP_OPTIONS,
731 (char *)optlist, i + sizeof(gwlist[0])) < 0) { 954 (char *)optlist, i + sizeof(gwlist[0])) < 0) {
732 bb_perror_msg_and_die("IP_OPTIONS"); 955 bb_perror_msg_and_die("IP_OPTIONS");
956 }
733 } 957 }
734 }
735#endif 958#endif
959 }
960
736#ifdef SO_SNDBUF 961#ifdef SO_SNDBUF
737 if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, &packlen, sizeof(packlen)) < 0) { 962 if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, &packlen, sizeof(packlen)) < 0) {
738 bb_perror_msg_and_die("SO_SNDBUF"); 963 bb_perror_msg_and_die("SO_SNDBUF");
@@ -759,29 +984,66 @@ int traceroute_main(int argc UNUSED_PARAM, char **argv)
759 984
760 outip = xzalloc(packlen); 985 outip = xzalloc(packlen);
761 986
762 if (op & OPT_USE_ICMP) { 987 ident = getpid();
763 ident = getpid() | 0x8000; 988
764 outicmp->icmp_type = ICMP_ECHO; 989 if (af == AF_INET) {
765 outicmp->icmp_id = htons(ident); 990 if (op & OPT_USE_ICMP) {
766 outdata = (struct outdata_t *)((char *)outicmp + SIZEOF_ICMP_HDR); 991 ident |= 0x8000;
767 } else { 992 outicmp->icmp_type = ICMP_ECHO;
768 outdata = (struct outdata_t *)(outudp + 1); 993 outicmp->icmp_id = htons(ident);
994 outdata = (struct outdata_t *)((char *)outicmp + SIZEOF_ICMP_HDR);
995 } else {
996 outdata = (struct outdata_t *)(outudp + 1);
997 }
769 } 998 }
770 999
771 if (op & OPT_DEVICE) /* hmm, do we need error check? */ 1000 if (op & OPT_DEVICE) /* hmm, do we need error check? */
772 setsockopt_bindtodevice(sndsock, device); 1001 setsockopt_bindtodevice(sndsock, device);
773 1002
774 if (op & OPT_SOURCE) { 1003 if (op & OPT_SOURCE) {
1004#if ENABLE_TRACEROUTE6
1005// TODO: need xdotted_and_af2sockaddr?
1006 len_and_sockaddr *source_lsa = xhost_and_af2sockaddr(source, 0, af);
1007#else
775 len_and_sockaddr *source_lsa = xdotted2sockaddr(source, 0); 1008 len_and_sockaddr *source_lsa = xdotted2sockaddr(source, 0);
776 /* Ping does this (why?) */ 1009#endif
777 if (setsockopt(sndsock, IPPROTO_IP, IP_MULTICAST_IF, 1010 /* Ping4 does this (why?) */
778 &source_lsa->u.sa, source_lsa->len)) 1011 if (af == AF_INET)
779 bb_error_msg_and_die("can't set multicast source interface"); 1012 if (setsockopt(sndsock, IPPROTO_IP, IP_MULTICAST_IF,
1013 &source_lsa->u.sa, source_lsa->len))
1014 bb_error_msg_and_die("can't set multicast source interface");
780//TODO: we can query source port we bound to, 1015//TODO: we can query source port we bound to,
781// and check it in replies... if we care enough 1016// and check it in replies... if we care enough
782 xbind(sndsock, &source_lsa->u.sa, source_lsa->len); 1017 xbind(sndsock, &source_lsa->u.sa, source_lsa->len);
783 free(source_lsa); 1018 free(source_lsa);
784 } 1019 }
1020#if ENABLE_TRACEROUTE6
1021 else if (af == AF_INET6) {
1022//TODO: why we don't do it for IPv4?
1023 len_and_sockaddr *source_lsa;
1024
1025 int probe_fd = xsocket(af, SOCK_DGRAM, 0);
1026 if (op & OPT_DEVICE)
1027 setsockopt_bindtodevice(probe_fd, device);
1028 set_nport(dest_lsa, htons(1025));
1029 /* dummy connect. makes kernel pick source IP (and port) */
1030 xconnect(probe_fd, &dest_lsa->u.sa, dest_lsa->len);
1031
1032 /* read IP and port */
1033 source_lsa = get_sock_lsa(probe_fd);
1034 if (source_lsa == NULL)
1035 bb_error_msg_and_die("can't get probe addr");
1036
1037 close(probe_fd);
1038
1039 /* bind our sockets to this IP (but not port) */
1040 set_nport(source_lsa, 0);
1041 xbind(sndsock, &source_lsa->u.sa, source_lsa->len);
1042 xbind(rcvsock, &source_lsa->u.sa, source_lsa->len);
1043
1044 free(source_lsa);
1045 }
1046#endif
785 1047
786 /* Revert to non-privileged user after opening sockets */ 1048 /* Revert to non-privileged user after opening sockets */
787 xsetgid(getgid()); 1049 xsetgid(getgid());
@@ -793,11 +1055,11 @@ int traceroute_main(int argc UNUSED_PARAM, char **argv)
793 printf(" from %s", source); 1055 printf(" from %s", source);
794 printf(", %d hops max, %d byte packets\n", max_ttl, packlen); 1056 printf(", %d hops max, %d byte packets\n", max_ttl, packlen);
795 1057
1058 from_lsa = dup_sockaddr(dest_lsa);
1059 lastaddr = xzalloc(dest_lsa->len);
1060 to = xzalloc(dest_lsa->len);
796 seq = 0; 1061 seq = 0;
797 for (ttl = first_ttl; ttl <= max_ttl; ++ttl) { 1062 for (ttl = first_ttl; ttl <= max_ttl; ++ttl) {
798//TODO: make it protocol agnostic (get rid of sockaddr_in)
799 struct sockaddr_in from;
800 uint32_t lastaddr = 0;
801 int probe; 1063 int probe;
802 int unreachable = 0; /* counter */ 1064 int unreachable = 0; /* counter */
803 int gotlastaddr = 0; /* flags */ 1065 int gotlastaddr = 0; /* flags */
@@ -819,44 +1081,55 @@ int traceroute_main(int argc UNUSED_PARAM, char **argv)
819 send_probe(++seq, ttl); 1081 send_probe(++seq, ttl);
820 1082
821 first = 0; 1083 first = 0;
822 while ((read_len = wait_for_reply(&from)) != 0) { 1084 while ((read_len = wait_for_reply(from_lsa, to)) != 0) {
823 t2 = monotonic_us(); 1085 t2 = monotonic_us();
824 i = packet_ok(read_len, &from, seq); 1086 i = packet_ok(read_len, from_lsa, to, seq);
825 /* Skip short packet */ 1087 /* Skip short packet */
826 if (i == 0) 1088 if (i == 0)
827 continue; 1089 continue;
1090
828 if (!gotlastaddr 1091 if (!gotlastaddr
829 || from.sin_addr.s_addr != lastaddr 1092 || (memcmp(lastaddr, &from_lsa->u.sa, from_lsa->len) != 0)
830 ) { 1093 ) {
831 print(read_len, &from); 1094 print(read_len, &from_lsa->u.sa, to);
832 lastaddr = from.sin_addr.s_addr; 1095 memcpy(lastaddr, &from_lsa->u.sa, from_lsa->len);
833 gotlastaddr = 1; 1096 gotlastaddr = 1;
834 } 1097 }
1098
835 print_delta_ms(t1, t2); 1099 print_delta_ms(t1, t2);
836 ip = (struct ip *)recv_pkt; 1100 ip = (struct ip *)recv_pkt;
837 if (op & OPT_TTL_FLAG) 1101
838 printf(" (%d)", ip->ip_ttl); 1102 if (from_lsa->u.sa.sa_family == AF_INET)
839 if (i == -2) { 1103 if (op & OPT_TTL_FLAG)
840 if (ip->ip_ttl <= 1) 1104 printf(" (%d)", ip->ip_ttl);
841 printf(" !"); 1105
842 got_there = 1;
843 break;
844 }
845 /* time exceeded in transit */ 1106 /* time exceeded in transit */
846 if (i == -1) 1107 if (i == -1)
847 break; 1108 break;
848 i--; 1109 i--;
849 switch (i) { 1110 switch (i) {
1111#if ENABLE_TRACEROUTE6
1112 case ICMP6_DST_UNREACH_NOPORT << 8:
1113 got_there = 1;
1114 break;
1115#endif
850 case ICMP_UNREACH_PORT: 1116 case ICMP_UNREACH_PORT:
851 if (ip->ip_ttl <= 1) 1117 if (ip->ip_ttl <= 1)
852 printf(" !"); 1118 printf(" !");
853 got_there = 1; 1119 got_there = 1;
854 break; 1120 break;
1121
855 case ICMP_UNREACH_NET: 1122 case ICMP_UNREACH_NET:
1123#if ENABLE_TRACEROUTE6 && (ICMP6_DST_UNREACH_NOROUTE != ICMP_UNREACH_NET)
1124 case ICMP6_DST_UNREACH_NOROUTE << 8:
1125#endif
856 printf(" !N"); 1126 printf(" !N");
857 ++unreachable; 1127 ++unreachable;
858 break; 1128 break;
859 case ICMP_UNREACH_HOST: 1129 case ICMP_UNREACH_HOST:
1130#if ENABLE_TRACEROUTE6
1131 case ICMP6_DST_UNREACH_ADDR << 8:
1132#endif
860 printf(" !H"); 1133 printf(" !H");
861 ++unreachable; 1134 ++unreachable;
862 break; 1135 break;
@@ -869,6 +1142,9 @@ int traceroute_main(int argc UNUSED_PARAM, char **argv)
869 ++unreachable; 1142 ++unreachable;
870 break; 1143 break;
871 case ICMP_UNREACH_SRCFAIL: 1144 case ICMP_UNREACH_SRCFAIL:
1145#if ENABLE_TRACEROUTE6
1146 case ICMP6_DST_UNREACH_ADMIN << 8:
1147#endif
872 printf(" !S"); 1148 printf(" !S");
873 ++unreachable; 1149 ++unreachable;
874 break; 1150 break;
@@ -924,3 +1200,17 @@ int traceroute_main(int argc UNUSED_PARAM, char **argv)
924 1200
925 return 0; 1201 return 0;
926} 1202}
1203
1204int traceroute_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1205int traceroute_main(int argc UNUSED_PARAM, char **argv)
1206{
1207 return common_traceroute_main(0, argv);
1208}
1209
1210#if ENABLE_TRACEROUTE6
1211int traceroute6_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1212int traceroute6_main(int argc UNUSED_PARAM, char **argv)
1213{
1214 return common_traceroute_main(OPT_IPV6, argv);
1215}
1216#endif