1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256#define TRACEROUTE_SO_DEBUG 0
257
258
259
260
261
262
263
264
265
266
267
268#include <net/if.h>
269#include <arpa/inet.h>
270#include <netinet/in.h>
271#include <netinet/udp.h>
272#include <netinet/ip.h>
273#include <netinet/ip_icmp.h>
274#if ENABLE_FEATURE_IPV6
275# include <netinet/ip6.h>
276# include <netinet/icmp6.h>
277# ifndef SOL_IPV6
278# define SOL_IPV6 IPPROTO_IPV6
279# endif
280#endif
281
282#include "libbb.h"
283#include "inet_common.h"
284
285#ifndef IPPROTO_ICMP
286# define IPPROTO_ICMP 1
287#endif
288#ifndef IPPROTO_IP
289# define IPPROTO_IP 0
290#endif
291
292
293#define OPT_STRING "FIlnrdvxt:i:m:p:q:s:w:z:f:" \
294 IF_FEATURE_TRACEROUTE_SOURCE_ROUTE("g:") \
295 "4" IF_TRACEROUTE6("6")
296enum {
297 OPT_DONT_FRAGMNT = (1 << 0),
298 OPT_USE_ICMP = (1 << 1) * ENABLE_FEATURE_TRACEROUTE_USE_ICMP,
299 OPT_TTL_FLAG = (1 << 2),
300 OPT_ADDR_NUM = (1 << 3),
301 OPT_BYPASS_ROUTE = (1 << 4),
302 OPT_DEBUG = (1 << 5),
303 OPT_VERBOSE = (1 << 6) * ENABLE_FEATURE_TRACEROUTE_VERBOSE,
304 OPT_IP_CHKSUM = (1 << 7),
305 OPT_TOS = (1 << 8),
306 OPT_DEVICE = (1 << 9),
307 OPT_MAX_TTL = (1 << 10),
308 OPT_PORT = (1 << 11),
309 OPT_NPROBES = (1 << 12),
310 OPT_SOURCE = (1 << 13),
311 OPT_WAITTIME = (1 << 14),
312 OPT_PAUSE_MS = (1 << 15),
313 OPT_FIRST_TTL = (1 << 16),
314 OPT_SOURCE_ROUTE = (1 << 17) * ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE,
315 OPT_IPV4 = (1 << (17+ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE)),
316 OPT_IPV6 = (1 << (18+ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE)) * ENABLE_TRACEROUTE6,
317};
318#define verbose (option_mask32 & OPT_VERBOSE)
319
320enum {
321 SIZEOF_ICMP_HDR = 8,
322 rcvsock = 3,
323 sndsock = 4,
324};
325
326
327struct outdata_t {
328 unsigned char seq;
329 unsigned char ttl;
330
331 struct timeval tv_UNUSED PACKED;
332};
333
334#if ENABLE_TRACEROUTE6
335struct outdata6_t {
336 uint32_t ident6;
337 uint32_t seq6;
338 struct timeval tv_UNUSED PACKED;
339};
340#endif
341
342struct globals {
343 struct ip *outip;
344 struct outdata_t *outdata;
345 len_and_sockaddr *dest_lsa;
346 int packlen;
347 int pmtu;
348 uint32_t ident;
349 uint16_t port;
350 int waittime;
351#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
352 int optlen;
353#else
354#define optlen 0
355#endif
356 unsigned char recv_pkt[512];
357#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
358
359#define NGATEWAYS ((int)((MAX_IPOPTLEN - IPOPT_MINOFF - 1) / sizeof(uint32_t)))
360
361 uint32_t gwlist[NGATEWAYS + 1];
362#endif
363};
364
365#define G (*ptr_to_globals)
366#define outip (G.outip )
367#define outdata (G.outdata )
368#define dest_lsa (G.dest_lsa )
369#define packlen (G.packlen )
370#define pmtu (G.pmtu )
371#define ident (G.ident )
372#define port (G.port )
373#define waittime (G.waittime )
374#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
375# define optlen (G.optlen )
376#endif
377#define recv_pkt (G.recv_pkt )
378#define gwlist (G.gwlist )
379#define INIT_G() do { \
380 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
381 port = 32768 + 666; \
382 waittime = 5; \
383} while (0)
384
385#define outicmp ((struct icmp *)(outip + 1))
386#define outudp ((struct udphdr *)(outip + 1))
387
388
389
390static len_and_sockaddr* dup_sockaddr(const len_and_sockaddr *lsa)
391{
392 len_and_sockaddr *new_lsa = xzalloc(LSA_LEN_SIZE + lsa->len);
393 memcpy(new_lsa, lsa, LSA_LEN_SIZE + lsa->len);
394 return new_lsa;
395}
396
397
398static int
399wait_for_reply(len_and_sockaddr *from_lsa, struct sockaddr *to, unsigned *timestamp_us, int *left_ms)
400{
401 struct pollfd pfd[1];
402 int read_len = 0;
403
404 pfd[0].fd = rcvsock;
405 pfd[0].events = POLLIN;
406 if (*left_ms >= 0 && safe_poll(pfd, 1, *left_ms) > 0) {
407 unsigned t;
408
409 read_len = recv_from_to(rcvsock,
410 recv_pkt, sizeof(recv_pkt),
411 MSG_DONTWAIT,
412 &from_lsa->u.sa, to, from_lsa->len);
413 t = monotonic_us();
414 *left_ms -= (t - *timestamp_us) / 1000;
415 *timestamp_us = t;
416 }
417
418 return read_len;
419}
420
421
422
423
424static uint16_t
425in_cksum(uint16_t *addr, int len)
426{
427 int nleft = len;
428 uint16_t *w = addr;
429 uint16_t answer;
430 int sum = 0;
431
432
433
434
435
436
437
438 while (nleft > 1) {
439 sum += *w++;
440 nleft -= 2;
441 }
442
443
444 if (nleft == 1)
445 sum += *(unsigned char *)w;
446
447
448 sum = (sum >> 16) + (sum & 0xffff);
449 sum += (sum >> 16);
450 answer = ~sum;
451 return answer;
452}
453
454static void
455send_probe(int seq, int ttl)
456{
457 int len, res;
458 void *out;
459
460
461#if ENABLE_TRACEROUTE6
462 if (dest_lsa->u.sa.sa_family == AF_INET6) {
463 struct outdata6_t *pkt = (struct outdata6_t *) outip;
464 pkt->ident6 = htonl(ident);
465 pkt->seq6 = htonl(seq);
466
467 } else
468#endif
469 {
470 outdata->seq = seq;
471 outdata->ttl = ttl;
472
473
474
475 if (option_mask32 & OPT_USE_ICMP) {
476 outicmp->icmp_seq = htons(seq);
477
478
479 outicmp->icmp_cksum = 0;
480 outicmp->icmp_cksum = in_cksum((uint16_t *)outicmp,
481 packlen - (sizeof(*outip) + optlen));
482 if (outicmp->icmp_cksum == 0)
483 outicmp->icmp_cksum = 0xffff;
484 }
485 }
486
487
488#if 0
489
490 if (verbose > 1) {
491 const uint16_t *sp;
492 int nshorts, i;
493
494 sp = (uint16_t *)outip;
495 nshorts = (unsigned)packlen / sizeof(uint16_t);
496 i = 0;
497 printf("[ %d bytes", packlen);
498 while (--nshorts >= 0) {
499 if ((i++ % 8) == 0)
500 printf("\n\t");
501 printf(" %04x", ntohs(*sp));
502 sp++;
503 }
504 if (packlen & 1) {
505 if ((i % 8) == 0)
506 printf("\n\t");
507 printf(" %02x", *(unsigned char *)sp);
508 }
509 printf("]\n");
510 }
511#endif
512
513#if ENABLE_TRACEROUTE6
514 if (dest_lsa->u.sa.sa_family == AF_INET6) {
515 res = setsockopt(sndsock, SOL_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl));
516 if (res < 0)
517 bb_perror_msg_and_die("setsockopt UNICAST_HOPS %d", ttl);
518 out = outip;
519 len = packlen;
520 } else
521#endif
522 {
523#if defined IP_TTL
524 res = setsockopt(sndsock, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
525 if (res < 0)
526 bb_perror_msg_and_die("setsockopt ttl %d", ttl);
527#endif
528 out = outicmp;
529 len = packlen - sizeof(*outip);
530 if (!(option_mask32 & OPT_USE_ICMP)) {
531 out = outdata;
532 len -= sizeof(*outudp);
533 set_nport(&dest_lsa->u.sa, htons(port + seq));
534 }
535 }
536
537 res = xsendto(sndsock, out, len, &dest_lsa->u.sa, dest_lsa->len);
538 if (res != len)
539 bb_info_msg("sent %d octets, ret=%d", len, res);
540}
541
542#if ENABLE_FEATURE_TRACEROUTE_VERBOSE
543
544
545
546static const char *
547pr_type(unsigned char t)
548{
549 static const char *const ttab[] = {
550 "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable",
551 "Source Quench", "Redirect", "ICMP 6", "ICMP 7",
552 "Echo", "Router Advert", "Router Solicit", "Time Exceeded",
553 "Param Problem", "Timestamp", "Timestamp Reply", "Info Request",
554 "Info Reply", "Mask Request", "Mask Reply"
555 };
556# if ENABLE_TRACEROUTE6
557 static const char *const ttab6[] = {
558[0] "Error", "Dest Unreachable", "Packet Too Big", "Time Exceeded",
559[4] "Param Problem",
560[8] "Echo Request", "Echo Reply", "Membership Query", "Membership Report",
561[12] "Membership Reduction", "Router Solicit", "Router Advert", "Neighbor Solicit",
562[16] "Neighbor Advert", "Redirect",
563 };
564
565 if (dest_lsa->u.sa.sa_family == AF_INET6) {
566 if (t < 5)
567 return ttab6[t];
568 if (t < 128 || t > ND_REDIRECT)
569 return "OUT-OF-RANGE";
570 return ttab6[(t & 63) + 8];
571 }
572# endif
573 if (t >= ARRAY_SIZE(ttab))
574 return "OUT-OF-RANGE";
575
576 return ttab[t];
577}
578#endif
579
580#if !ENABLE_FEATURE_TRACEROUTE_VERBOSE
581#define packet4_ok(read_len, from, seq) \
582 packet4_ok(read_len, seq)
583#endif
584static int
585packet4_ok(int read_len, const struct sockaddr_in *from, int seq)
586{
587 const struct icmp *icp;
588 unsigned char type, code;
589 int hlen;
590 const struct ip *ip;
591
592 ip = (struct ip *) recv_pkt;
593 hlen = ip->ip_hl << 2;
594 if (read_len < hlen + ICMP_MINLEN) {
595#if ENABLE_FEATURE_TRACEROUTE_VERBOSE
596 if (verbose)
597 printf("packet too short (%d bytes) from %s\n", read_len,
598 inet_ntoa(from->sin_addr));
599#endif
600 return 0;
601 }
602 read_len -= hlen;
603 icp = (struct icmp *)(recv_pkt + hlen);
604 type = icp->icmp_type;
605 code = icp->icmp_code;
606
607 pmtu = 0;
608 if (code == ICMP_UNREACH_NEEDFRAG)
609 pmtu = ntohs(icp->icmp_nextmtu);
610
611 if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS)
612 || type == ICMP_UNREACH
613 || type == ICMP_ECHOREPLY
614 ) {
615 const struct ip *hip;
616 const struct udphdr *up;
617
618 hip = &icp->icmp_ip;
619 hlen = hip->ip_hl << 2;
620 if (option_mask32 & OPT_USE_ICMP) {
621 struct icmp *hicmp;
622
623
624 if (type == ICMP_ECHOREPLY
625 && icp->icmp_id == htons(ident)
626 && icp->icmp_seq == htons(seq)
627 ) {
628 return ICMP_UNREACH_PORT+1;
629 }
630
631 hicmp = (struct icmp *)((unsigned char *)hip + hlen);
632 if (hlen + SIZEOF_ICMP_HDR <= read_len
633 && hip->ip_p == IPPROTO_ICMP
634 && hicmp->icmp_id == htons(ident)
635 && hicmp->icmp_seq == htons(seq)
636 ) {
637 return (type == ICMP_TIMXCEED ? -1 : code + 1);
638 }
639 } else {
640 up = (struct udphdr *)((char *)hip + hlen);
641 if (hlen + 12 <= read_len
642 && hip->ip_p == IPPROTO_UDP
643
644
645
646
647 && up->dest == htons(port + seq)
648 ) {
649 return (type == ICMP_TIMXCEED ? -1 : code + 1);
650 }
651 }
652 }
653#if ENABLE_FEATURE_TRACEROUTE_VERBOSE
654 if (verbose) {
655 int i;
656 uint32_t *lp = (uint32_t *)&icp->icmp_ip;
657
658 printf("\n%d bytes from %s to "
659 "%s: icmp type %d (%s) code %d\n",
660 read_len, inet_ntoa(from->sin_addr),
661 inet_ntoa(ip->ip_dst),
662 type, pr_type(type), icp->icmp_code);
663 for (i = 4; i < read_len; i += sizeof(*lp))
664 printf("%2d: x%8.8x\n", i, *lp++);
665 }
666#endif
667 return 0;
668}
669
670#if ENABLE_TRACEROUTE6
671# if !ENABLE_FEATURE_TRACEROUTE_VERBOSE
672#define packet_ok(read_len, from_lsa, to, seq) \
673 packet_ok(read_len, from_lsa, seq)
674# endif
675static int
676packet_ok(int read_len, len_and_sockaddr *from_lsa,
677 struct sockaddr *to,
678 int seq)
679{
680 const struct icmp6_hdr *icp;
681 unsigned char type, code;
682
683 if (from_lsa->u.sa.sa_family == AF_INET)
684 return packet4_ok(read_len, &from_lsa->u.sin, seq);
685
686 icp = (struct icmp6_hdr *) recv_pkt;
687
688 type = icp->icmp6_type;
689 code = icp->icmp6_code;
690
691 if ((type == ICMP6_TIME_EXCEEDED && code == ICMP6_TIME_EXCEED_TRANSIT)
692 || type == ICMP6_DST_UNREACH
693 ) {
694 struct ip6_hdr *hip;
695 struct udphdr *up;
696 int nexthdr;
697
698 hip = (struct ip6_hdr *)(icp + 1);
699 up = (struct udphdr *) (hip + 1);
700 nexthdr = hip->ip6_nxt;
701
702 if (nexthdr == IPPROTO_FRAGMENT) {
703 nexthdr = *(unsigned char*)up;
704 up++;
705 }
706 if (nexthdr == IPPROTO_UDP) {
707 struct outdata6_t *pkt;
708
709 pkt = (struct outdata6_t *) (up + 1);
710
711 if (ntohl(pkt->ident6) == ident
712 && ntohl(pkt->seq6) == seq
713 ) {
714 return (type == ICMP6_TIME_EXCEEDED ? -1 : (code<<8)+1);
715 }
716 }
717 }
718
719# if ENABLE_FEATURE_TRACEROUTE_VERBOSE
720 if (verbose) {
721 unsigned char *p;
722 char pa1[MAXHOSTNAMELEN];
723 char pa2[MAXHOSTNAMELEN];
724 int i;
725
726 p = (unsigned char *) (icp + 1);
727
728 printf("\n%d bytes from %s to "
729 "%s: icmp type %d (%s) code %d\n",
730 read_len,
731 inet_ntop(AF_INET6, &from_lsa->u.sin6.sin6_addr, pa1, sizeof(pa1)),
732 inet_ntop(AF_INET6, &((struct sockaddr_in6*)to)->sin6_addr, pa2, sizeof(pa2)),
733 type, pr_type(type), icp->icmp6_code);
734
735 read_len -= sizeof(struct icmp6_hdr);
736 for (i = 0; i < read_len; i++) {
737 if (i % 16 == 0)
738 printf("%04x:", i);
739 if (i % 4 == 0)
740 bb_putchar(' ');
741 printf("%02x", p[i]);
742 if ((i % 16 == 15) && (i + 1 < read_len))
743 bb_putchar('\n');
744 }
745 bb_putchar('\n');
746 }
747# endif
748
749 return 0;
750}
751#else
752static ALWAYS_INLINE int
753packet_ok(int read_len,
754 len_and_sockaddr *from_lsa IF_NOT_FEATURE_TRACEROUTE_VERBOSE(UNUSED_PARAM),
755 struct sockaddr *to UNUSED_PARAM,
756 int seq)
757{
758 return packet4_ok(read_len, &from_lsa->u.sin, seq);
759}
760#endif
761
762
763
764
765
766
767static void
768print_inetname(const struct sockaddr *from)
769{
770 char *ina = xmalloc_sockaddr2dotted_noport(from);
771
772 if (option_mask32 & OPT_ADDR_NUM) {
773 printf(" %s", ina);
774 } else {
775 char *n = NULL;
776
777 if (from->sa_family != AF_INET
778 || ((struct sockaddr_in*)from)->sin_addr.s_addr != INADDR_ANY
779 ) {
780
781 n = xmalloc_sockaddr2host_noport((struct sockaddr*)from);
782 }
783 printf(" %s (%s)", (n ? n : ina), ina);
784 free(n);
785 }
786 free(ina);
787}
788
789static void
790print(int read_len, const struct sockaddr *from, const struct sockaddr *to)
791{
792 print_inetname(from);
793
794 if (verbose) {
795 char *ina = xmalloc_sockaddr2dotted_noport(to);
796#if ENABLE_TRACEROUTE6
797 if (to->sa_family == AF_INET6) {
798 read_len -= sizeof(struct ip6_hdr);
799 } else
800#endif
801 {
802 struct ip *ip4packet = (struct ip*)recv_pkt;
803 read_len -= ip4packet->ip_hl << 2;
804 }
805 printf(" %d bytes to %s", read_len, ina);
806 free(ina);
807 }
808}
809
810static void
811print_delta_ms(unsigned t1p, unsigned t2p)
812{
813 unsigned tt = t2p - t1p;
814 printf(" %u.%03u ms", tt / 1000, tt % 1000);
815}
816
817
818
819
820
821
822static int
823common_traceroute_main(int op, char **argv)
824{
825 int minpacket;
826 int tos = 0;
827 int max_ttl = 30;
828 int nprobes = 3;
829 int first_ttl = 1;
830 unsigned pausemsecs = 0;
831 char *source;
832 char *device;
833 char *tos_str;
834 char *max_ttl_str;
835 char *port_str;
836 char *nprobes_str;
837 char *waittime_str;
838 char *pausemsecs_str;
839 char *first_ttl_str;
840#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
841 llist_t *source_route_list = NULL;
842 int lsrr = 0;
843#endif
844#if ENABLE_TRACEROUTE6
845 sa_family_t af;
846#else
847 enum { af = AF_INET };
848#endif
849 int ttl;
850 int seq;
851 len_and_sockaddr *from_lsa;
852 struct sockaddr *lastaddr;
853 struct sockaddr *to;
854
855 INIT_G();
856
857
858 opt_complementary = "-1:x-x" IF_FEATURE_TRACEROUTE_SOURCE_ROUTE(":g::");
859 op |= getopt32(argv, OPT_STRING
860 , &tos_str, &device, &max_ttl_str, &port_str, &nprobes_str
861 , &source, &waittime_str, &pausemsecs_str, &first_ttl_str
862#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
863 , &source_route_list
864#endif
865 );
866 argv += optind;
867
868#if 0
869 if (op & OPT_IP_CHKSUM)
870 bb_error_msg("warning: ip checksums disabled");
871#endif
872 if (op & OPT_TOS)
873 tos = xatou_range(tos_str, 0, 255);
874 if (op & OPT_MAX_TTL)
875 max_ttl = xatou_range(max_ttl_str, 1, 255);
876 if (op & OPT_PORT)
877 port = xatou16(port_str);
878 if (op & OPT_NPROBES)
879 nprobes = xatou_range(nprobes_str, 1, INT_MAX);
880 if (op & OPT_SOURCE) {
881
882
883
884
885 if (getuid() != 0)
886 bb_error_msg_and_die(bb_msg_you_must_be_root);
887 }
888 if (op & OPT_WAITTIME)
889 waittime = xatou_range(waittime_str, 1, 24 * 60 * 60);
890 if (op & OPT_PAUSE_MS)
891 pausemsecs = xatou_range(pausemsecs_str, 0, 60 * 60 * 1000);
892 if (op & OPT_FIRST_TTL)
893 first_ttl = xatou_range(first_ttl_str, 1, max_ttl);
894
895#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
896 if (source_route_list) {
897 while (source_route_list) {
898 len_and_sockaddr *lsa;
899
900 if (lsrr >= NGATEWAYS)
901 bb_error_msg_and_die("no more than %d gateways", NGATEWAYS);
902 lsa = xhost_and_af2sockaddr(llist_pop(&source_route_list), 0, AF_INET);
903 gwlist[lsrr] = lsa->u.sin.sin_addr.s_addr;
904 free(lsa);
905 ++lsrr;
906 }
907 optlen = (lsrr + 1) * sizeof(gwlist[0]);
908 }
909#endif
910
911
912 minpacket = sizeof(*outip) + SIZEOF_ICMP_HDR + sizeof(*outdata) + optlen;
913 if (!(op & OPT_USE_ICMP))
914 minpacket += sizeof(*outudp) - SIZEOF_ICMP_HDR;
915#if ENABLE_TRACEROUTE6
916 af = AF_UNSPEC;
917 if (op & OPT_IPV4)
918 af = AF_INET;
919 if (op & OPT_IPV6)
920 af = AF_INET6;
921 dest_lsa = xhost_and_af2sockaddr(argv[0], port, af);
922 af = dest_lsa->u.sa.sa_family;
923 if (af == AF_INET6)
924 minpacket = sizeof(struct outdata6_t);
925#else
926 dest_lsa = xhost2sockaddr(argv[0], port);
927#endif
928 packlen = minpacket;
929 if (argv[1])
930 packlen = xatoul_range(argv[1], minpacket, 32 * 1024);
931
932
933 bb_sanitize_stdio();
934
935#if ENABLE_TRACEROUTE6
936 if (af == AF_INET6) {
937 xmove_fd(xsocket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6), rcvsock);
938# ifdef IPV6_RECVPKTINFO
939 setsockopt(rcvsock, SOL_IPV6, IPV6_RECVPKTINFO,
940 &const_int_1, sizeof(const_int_1));
941 setsockopt(rcvsock, SOL_IPV6, IPV6_2292PKTINFO,
942 &const_int_1, sizeof(const_int_1));
943# else
944 setsockopt(rcvsock, SOL_IPV6, IPV6_PKTINFO,
945 &const_int_1, sizeof(const_int_1));
946# endif
947 } else
948#endif
949 {
950 xmove_fd(xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP), rcvsock);
951 }
952
953#if TRACEROUTE_SO_DEBUG
954 if (op & OPT_DEBUG)
955 setsockopt(rcvsock, SOL_SOCKET, SO_DEBUG,
956 &const_int_1, sizeof(const_int_1));
957#endif
958 if (op & OPT_BYPASS_ROUTE)
959 setsockopt(rcvsock, SOL_SOCKET, SO_DONTROUTE,
960 &const_int_1, sizeof(const_int_1));
961
962#if ENABLE_TRACEROUTE6
963 if (af == AF_INET6) {
964 static const int two = 2;
965 if (setsockopt(rcvsock, SOL_RAW, IPV6_CHECKSUM, &two, sizeof(two)) < 0)
966 bb_perror_msg_and_die("setsockopt RAW_CHECKSUM");
967 xmove_fd(xsocket(af, SOCK_DGRAM, 0), sndsock);
968 } else
969#endif
970 {
971 if (op & OPT_USE_ICMP)
972 xmove_fd(xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP), sndsock);
973 else
974 xmove_fd(xsocket(AF_INET, SOCK_DGRAM, 0), sndsock);
975#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE && defined IP_OPTIONS
976 if (lsrr > 0) {
977 unsigned char optlist[MAX_IPOPTLEN];
978 unsigned size;
979
980
981 gwlist[lsrr] = dest_lsa->u.sin.sin_addr.s_addr;
982 ++lsrr;
983
984
985 optlist[0] = IPOPT_NOP;
986
987 optlist[1] = IPOPT_LSRR;
988 size = lsrr * sizeof(gwlist[0]);
989 optlist[2] = size + 3;
990
991 optlist[3] = IPOPT_MINOFF;
992 memcpy(optlist + 4, gwlist, size);
993
994 if (setsockopt(sndsock, IPPROTO_IP, IP_OPTIONS,
995 (char *)optlist, size + sizeof(gwlist[0])) < 0) {
996 bb_perror_msg_and_die("IP_OPTIONS");
997 }
998 }
999#endif
1000 }
1001
1002#ifdef SO_SNDBUF
1003 if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, &packlen, sizeof(packlen)) < 0) {
1004 bb_perror_msg_and_die("SO_SNDBUF");
1005 }
1006#endif
1007#ifdef IP_TOS
1008 if ((op & OPT_TOS) && setsockopt(sndsock, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0) {
1009 bb_perror_msg_and_die("setsockopt tos %d", tos);
1010 }
1011#endif
1012#ifdef IP_DONTFRAG
1013 if (op & OPT_DONT_FRAGMNT)
1014 setsockopt(sndsock, IPPROTO_IP, IP_DONTFRAG,
1015 &const_int_1, sizeof(const_int_1));
1016#endif
1017#if TRACEROUTE_SO_DEBUG
1018 if (op & OPT_DEBUG)
1019 setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
1020 &const_int_1, sizeof(const_int_1));
1021#endif
1022 if (op & OPT_BYPASS_ROUTE)
1023 setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
1024 &const_int_1, sizeof(const_int_1));
1025
1026 outip = xzalloc(packlen);
1027
1028 ident = getpid();
1029
1030 if (af == AF_INET) {
1031 if (op & OPT_USE_ICMP) {
1032 ident |= 0x8000;
1033 outicmp->icmp_type = ICMP_ECHO;
1034 outicmp->icmp_id = htons(ident);
1035 outdata = (struct outdata_t *)((char *)outicmp + SIZEOF_ICMP_HDR);
1036 } else {
1037 outdata = (struct outdata_t *)(outudp + 1);
1038 }
1039 }
1040
1041 if (op & OPT_DEVICE)
1042 setsockopt_bindtodevice(sndsock, device);
1043
1044 if (op & OPT_SOURCE) {
1045#if ENABLE_TRACEROUTE6
1046
1047 len_and_sockaddr *source_lsa = xhost_and_af2sockaddr(source, 0, af);
1048#else
1049 len_and_sockaddr *source_lsa = xdotted2sockaddr(source, 0);
1050#endif
1051
1052 if (af == AF_INET)
1053 if (setsockopt(sndsock, IPPROTO_IP, IP_MULTICAST_IF,
1054 &source_lsa->u.sa, source_lsa->len))
1055 bb_error_msg_and_die("can't set multicast source interface");
1056
1057
1058 xbind(sndsock, &source_lsa->u.sa, source_lsa->len);
1059 free(source_lsa);
1060 }
1061#if ENABLE_TRACEROUTE6
1062 else if (af == AF_INET6) {
1063
1064 len_and_sockaddr *source_lsa;
1065
1066 int probe_fd = xsocket(af, SOCK_DGRAM, 0);
1067 if (op & OPT_DEVICE)
1068 setsockopt_bindtodevice(probe_fd, device);
1069 set_nport(&dest_lsa->u.sa, htons(1025));
1070
1071 xconnect(probe_fd, &dest_lsa->u.sa, dest_lsa->len);
1072 set_nport(&dest_lsa->u.sa, htons(port));
1073
1074
1075 source_lsa = get_sock_lsa(probe_fd);
1076 if (source_lsa == NULL)
1077 bb_error_msg_and_die("can't get probe addr");
1078
1079 close(probe_fd);
1080
1081
1082 set_nport(&source_lsa->u.sa, 0);
1083 xbind(sndsock, &source_lsa->u.sa, source_lsa->len);
1084 xbind(rcvsock, &source_lsa->u.sa, source_lsa->len);
1085
1086 free(source_lsa);
1087 }
1088#endif
1089
1090
1091 xsetgid(getgid());
1092 xsetuid(getuid());
1093
1094 printf("traceroute to %s (%s)", argv[0],
1095 xmalloc_sockaddr2dotted_noport(&dest_lsa->u.sa));
1096 if (op & OPT_SOURCE)
1097 printf(" from %s", source);
1098 printf(", %d hops max, %d byte packets\n", max_ttl, packlen);
1099
1100 from_lsa = dup_sockaddr(dest_lsa);
1101 lastaddr = xzalloc(dest_lsa->len);
1102 to = xzalloc(dest_lsa->len);
1103 seq = 0;
1104 for (ttl = first_ttl; ttl <= max_ttl; ++ttl) {
1105 int probe;
1106 int unreachable = 0;
1107 int gotlastaddr = 0;
1108 int got_there = 0;
1109
1110 printf("%2d", ttl);
1111 for (probe = 0; probe < nprobes; ++probe) {
1112 int read_len;
1113 unsigned t1;
1114 unsigned t2;
1115 int left_ms;
1116 struct ip *ip;
1117
1118 fflush_all();
1119 if (probe != 0 && pausemsecs > 0)
1120 usleep(pausemsecs * 1000);
1121
1122 send_probe(++seq, ttl);
1123 t2 = t1 = monotonic_us();
1124
1125 left_ms = waittime * 1000;
1126 while ((read_len = wait_for_reply(from_lsa, to, &t2, &left_ms)) != 0) {
1127 int icmp_code;
1128
1129
1130
1131
1132 if (read_len < 0)
1133 continue;
1134 icmp_code = packet_ok(read_len, from_lsa, to, seq);
1135
1136 if (icmp_code == 0)
1137 continue;
1138
1139 if (!gotlastaddr
1140 || (memcmp(lastaddr, &from_lsa->u.sa, from_lsa->len) != 0)
1141 ) {
1142 print(read_len, &from_lsa->u.sa, to);
1143 memcpy(lastaddr, &from_lsa->u.sa, from_lsa->len);
1144 gotlastaddr = 1;
1145 }
1146
1147 print_delta_ms(t1, t2);
1148 ip = (struct ip *)recv_pkt;
1149
1150 if (from_lsa->u.sa.sa_family == AF_INET)
1151 if (op & OPT_TTL_FLAG)
1152 printf(" (%d)", ip->ip_ttl);
1153
1154
1155 if (icmp_code == -1)
1156 break;
1157 icmp_code--;
1158 switch (icmp_code) {
1159#if ENABLE_TRACEROUTE6
1160 case ICMP6_DST_UNREACH_NOPORT << 8:
1161 got_there = 1;
1162 break;
1163#endif
1164 case ICMP_UNREACH_PORT:
1165 if (ip->ip_ttl <= 1)
1166 printf(" !");
1167 got_there = 1;
1168 break;
1169
1170 case ICMP_UNREACH_NET:
1171#if ENABLE_TRACEROUTE6 && (ICMP6_DST_UNREACH_NOROUTE != ICMP_UNREACH_NET)
1172 case ICMP6_DST_UNREACH_NOROUTE << 8:
1173#endif
1174 printf(" !N");
1175 ++unreachable;
1176 break;
1177 case ICMP_UNREACH_HOST:
1178#if ENABLE_TRACEROUTE6
1179 case ICMP6_DST_UNREACH_ADDR << 8:
1180#endif
1181 printf(" !H");
1182 ++unreachable;
1183 break;
1184 case ICMP_UNREACH_PROTOCOL:
1185 printf(" !P");
1186 got_there = 1;
1187 break;
1188 case ICMP_UNREACH_NEEDFRAG:
1189 printf(" !F-%d", pmtu);
1190 ++unreachable;
1191 break;
1192 case ICMP_UNREACH_SRCFAIL:
1193#if ENABLE_TRACEROUTE6
1194 case ICMP6_DST_UNREACH_ADMIN << 8:
1195#endif
1196 printf(" !S");
1197 ++unreachable;
1198 break;
1199 case ICMP_UNREACH_FILTER_PROHIB:
1200 case ICMP_UNREACH_NET_PROHIB:
1201 printf(" !A");
1202 ++unreachable;
1203 break;
1204 case ICMP_UNREACH_HOST_PROHIB:
1205 printf(" !C");
1206 ++unreachable;
1207 break;
1208 case ICMP_UNREACH_HOST_PRECEDENCE:
1209 printf(" !V");
1210 ++unreachable;
1211 break;
1212 case ICMP_UNREACH_PRECEDENCE_CUTOFF:
1213 printf(" !C");
1214 ++unreachable;
1215 break;
1216 case ICMP_UNREACH_NET_UNKNOWN:
1217 case ICMP_UNREACH_HOST_UNKNOWN:
1218 printf(" !U");
1219 ++unreachable;
1220 break;
1221 case ICMP_UNREACH_ISOLATED:
1222 printf(" !I");
1223 ++unreachable;
1224 break;
1225 case ICMP_UNREACH_TOSNET:
1226 case ICMP_UNREACH_TOSHOST:
1227 printf(" !T");
1228 ++unreachable;
1229 break;
1230 default:
1231 printf(" !<%d>", icmp_code);
1232 ++unreachable;
1233 break;
1234 }
1235 break;
1236 }
1237
1238
1239 if (read_len == 0)
1240 printf(" *");
1241 }
1242
1243 bb_putchar('\n');
1244 if (got_there
1245 || (unreachable > 0 && unreachable >= nprobes - 1)
1246 ) {
1247 break;
1248 }
1249 }
1250
1251 return 0;
1252}
1253
1254int traceroute_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1255int traceroute_main(int argc UNUSED_PARAM, char **argv)
1256{
1257 return common_traceroute_main(0, argv);
1258}
1259
1260#if ENABLE_TRACEROUTE6
1261int traceroute6_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1262int traceroute6_main(int argc UNUSED_PARAM, char **argv)
1263{
1264 return common_traceroute_main(OPT_IPV6, argv);
1265}
1266#endif
1267