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
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306#define TRACEROUTE_SO_DEBUG 0
307
308#include <net/if.h>
309#include <arpa/inet.h>
310#include <netinet/in.h>
311#include <netinet/udp.h>
312#include <netinet/ip.h>
313#include <netinet/ip_icmp.h>
314#if ENABLE_FEATURE_IPV6
315# include <netinet/ip6.h>
316# include <netinet/icmp6.h>
317# ifndef SOL_IPV6
318# define SOL_IPV6 IPPROTO_IPV6
319# endif
320# if defined(IPV6_PKTINFO) && !defined(IPV6_RECVPKTINFO)
321# define IPV6_RECVPKTINFO IPV6_PKTINFO
322# endif
323#endif
324
325#include "libbb.h"
326#include "inet_common.h"
327
328#ifndef IPPROTO_ICMP
329# define IPPROTO_ICMP 1
330#endif
331#ifndef IPPROTO_IP
332# define IPPROTO_IP 0
333#endif
334
335
336
337
338#ifndef SOL_RAW
339# define SOL_RAW IPPROTO_RAW
340#endif
341
342
343#define OPT_STRING \
344 "FIlnrdvt:i:m:p:q:s:w:z:f:" \
345 "4" IF_TRACEROUTE6("6")
346enum {
347 OPT_DONT_FRAGMNT = (1 << 0),
348 OPT_USE_ICMP = (1 << 1) * ENABLE_FEATURE_TRACEROUTE_USE_ICMP,
349 OPT_TTL_FLAG = (1 << 2),
350 OPT_ADDR_NUM = (1 << 3),
351 OPT_BYPASS_ROUTE = (1 << 4),
352 OPT_DEBUG = (1 << 5),
353 OPT_VERBOSE = (1 << 6) * ENABLE_FEATURE_TRACEROUTE_VERBOSE,
354 OPT_TOS = (1 << 7),
355 OPT_DEVICE = (1 << 8),
356 OPT_MAX_TTL = (1 << 9),
357 OPT_PORT = (1 << 10),
358 OPT_NPROBES = (1 << 11),
359 OPT_SOURCE = (1 << 12),
360 OPT_WAITTIME = (1 << 13),
361 OPT_PAUSE_MS = (1 << 14),
362 OPT_FIRST_TTL = (1 << 15),
363 OPT_IPV4 = (1 << 16),
364 OPT_IPV6 = (1 << 17) * ENABLE_TRACEROUTE6,
365};
366#if ENABLE_FEATURE_TRACEROUTE_VERBOSE
367# define verbose (option_mask32 & OPT_VERBOSE)
368#else
369# define verbose 0
370#endif
371
372enum {
373 SIZEOF_ICMP_HDR = 8,
374 rcvsock = 3,
375 sndsock = 4,
376};
377
378
379struct outdata_t {
380 unsigned char seq;
381 unsigned char ttl;
382
383 struct timeval tv_UNUSED PACKED;
384};
385
386#if ENABLE_TRACEROUTE6
387struct outdata6_t {
388 uint32_t ident6;
389 uint32_t seq6;
390 struct timeval tv_UNUSED PACKED;
391};
392#endif
393
394struct globals {
395
396 struct ip *outip;
397
398 struct outdata_t *outdata;
399 len_and_sockaddr *dest_lsa;
400 len_and_sockaddr *from_lsa;
401#if ENABLE_FEATURE_TRACEROUTE_VERBOSE
402 struct sockaddr *to;
403#endif
404 uint32_t ident;
405 uint16_t port;
406#if ENABLE_TRACEROUTE6
407 smallint ipv6;
408# define G_ipv6 G.ipv6
409#else
410# define G_ipv6 0
411#endif
412 int packlen;
413 int pmtu;
414 int waittime;
415 int first_ttl;
416 int nprobes;
417 int max_ttl;
418 unsigned pausemsecs;
419 unsigned char recv_pkt[512];
420};
421
422#define G (*ptr_to_globals)
423#define outip (G.outip )
424#define outdata (G.outdata )
425#define dest_lsa (G.dest_lsa )
426#define packlen (G.packlen )
427#define pmtu (G.pmtu )
428#define ident (G.ident )
429#define port (G.port )
430#define waittime (G.waittime )
431#define recv_pkt (G.recv_pkt )
432#define INIT_G() do { \
433 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
434} while (0)
435
436#define outudp ((struct udphdr *)(outip + 1))
437#define outudp6 ((struct udphdr *)(((struct ip6_hdr*)outip) + 1))
438#define outicmp ((struct icmp *)(outip + 1))
439#define outicmp6 ((struct icmp *)(((struct ip6_hdr*)outip) + 1))
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463static int
464wait_for_reply(unsigned *timestamp_us, int *left_ms)
465{
466 struct pollfd pfd[1];
467 int read_len = 0;
468
469 pfd[0].fd = rcvsock;
470 pfd[0].events = POLLIN;
471 if (*left_ms >= 0 && safe_poll(pfd, 1, *left_ms) > 0) {
472 unsigned t;
473
474#if ENABLE_FEATURE_TRACEROUTE_VERBOSE
475 read_len = recv_from_to(rcvsock,
476 recv_pkt, sizeof(recv_pkt),
477 MSG_DONTWAIT,
478 &G.from_lsa->u.sa, G.to, G.from_lsa->len);
479#else
480 read_len = recvfrom(rcvsock,
481 recv_pkt, sizeof(recv_pkt),
482 MSG_DONTWAIT,
483 &G.from_lsa->u.sa, &G.from_lsa->len);
484#endif
485 if (read_len < 0)
486 bb_simple_perror_msg_and_die("recv");
487 t = monotonic_us();
488 *left_ms -= (t - *timestamp_us) / 1000;
489 *timestamp_us = t;
490 }
491
492 return read_len;
493}
494
495static void
496send_probe(int seq, int ttl)
497{
498 int len, res;
499 void *out;
500 struct icmp *icp;
501
502
503#if ENABLE_TRACEROUTE6
504 if (G_ipv6) {
505 struct outdata6_t *pkt = (void *) outdata;
506 pkt->ident6 = ident;
507 pkt->seq6 = htonl(seq);
508
509 icp = outicmp6;
510 } else
511#endif
512 {
513 outdata->seq = seq;
514 outdata->ttl = ttl;
515
516
517 icp = outicmp;
518 }
519 out = outdata;
520 if (option_mask32 & OPT_USE_ICMP) {
521 out = icp;
522
523
524
525 icp->icmp_seq = htons(seq);
526
527 icp->icmp_cksum = 0;
528 icp->icmp_cksum = inet_cksum(
529 icp,
530 ((char*)outip + packlen) - (char*)icp
531 );
532 if (icp->icmp_cksum == 0)
533 icp->icmp_cksum = 0xffff;
534 }
535
536
537#if 0
538
539 if (verbose > 1) {
540 const uint16_t *sp;
541 int nshorts, i;
542
543 sp = (uint16_t *)outip;
544 nshorts = (unsigned)packlen / sizeof(uint16_t);
545 i = 0;
546 printf("[ %d bytes", packlen);
547 while (--nshorts >= 0) {
548 if ((i++ % 8) == 0)
549 printf("\n\t");
550 printf(" %04x", ntohs(*sp));
551 sp++;
552 }
553 if (packlen & 1) {
554 if ((i % 8) == 0)
555 printf("\n\t");
556 printf(" %02x", *(unsigned char *)sp);
557 }
558 printf("]\n");
559 }
560#endif
561
562#if ENABLE_TRACEROUTE6
563 if (G_ipv6) {
564 res = setsockopt_int(sndsock, SOL_IPV6, IPV6_UNICAST_HOPS, ttl);
565 if (res != 0)
566 bb_perror_msg_and_die("setsockopt(%s) %d", "UNICAST_HOPS", ttl);
567 } else
568#endif
569 {
570#if defined IP_TTL
571 res = setsockopt_int(sndsock, IPPROTO_IP, IP_TTL, ttl);
572 if (res != 0)
573 bb_perror_msg_and_die("setsockopt(%s) %d", "TTL", ttl);
574#endif
575 }
576
577 if (!(option_mask32 & OPT_USE_ICMP)) {
578 set_nport(&dest_lsa->u.sa, htons(port + seq));
579 }
580 len = ((char*)outip + packlen) - (char*)out;
581 res = xsendto(sndsock, out, len, &dest_lsa->u.sa, dest_lsa->len);
582 if (res != len)
583 bb_error_msg("sent %d octets, ret=%d", len, res);
584}
585
586#if ENABLE_FEATURE_TRACEROUTE_VERBOSE
587
588static const char *
589pr_type(unsigned char t)
590{
591 static const char *const ttab[] ALIGN_PTR = {
592 "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable",
593 "Source Quench", "Redirect", "ICMP 6", "ICMP 7",
594 "Echo", "Router Advert", "Router Solicit", "Time Exceeded",
595 "Param Problem", "Timestamp", "Timestamp Reply", "Info Request",
596 "Info Reply", "Mask Request", "Mask Reply"
597 };
598# if ENABLE_TRACEROUTE6
599 static const char *const ttab6[] ALIGN_PTR = {
600[0] = "Error", "Dest Unreachable", "Packet Too Big", "Time Exceeded",
601[4] = "Param Problem",
602[8] = "Echo Request", "Echo Reply", "Membership Query", "Membership Report",
603[12] = "Membership Reduction", "Router Solicit", "Router Advert", "Neighbor Solicit",
604[16] = "Neighbor Advert", "Redirect",
605 };
606
607 if (G_ipv6) {
608 if (t < 5)
609 return ttab6[t];
610 if (t < 128 || t > ND_REDIRECT)
611 return "OUT-OF-RANGE";
612 return ttab6[(t & 63) + 8];
613 }
614# endif
615 if (t >= ARRAY_SIZE(ttab))
616 return "OUT-OF-RANGE";
617
618 return ttab[t];
619}
620static int
621hexdump_if_verbose(const struct icmp *icp, int len)
622{
623 const unsigned char *p;
624 int i;
625
626 if (!verbose)
627 return 0;
628
629 printf("\n%d bytes from %s to %s: icmp type %u (%s) code %u\n",
630 len,
631 auto_string(xmalloc_sockaddr2dotted_noport(&G.from_lsa->u.sa)),
632 auto_string(xmalloc_sockaddr2dotted_noport(G.to)),
633 icp->icmp_type, pr_type(icp->icmp_type),
634 icp->icmp_code
635 );
636 p = (const void *)icp;
637 for (i = 0; i < len; i++) {
638 if (!(i & 0xf))
639 printf("\n%04x:" + (i==0), i);
640 printf(" %02x", p[i]);
641 }
642 bb_putchar('\n');
643 return 0;
644}
645#else
646# define hexdump_if_verbose(...) 0
647#endif
648
649static int
650packet4_ok(int read_len, int seq)
651{
652 const struct icmp *icp;
653 unsigned char type, code;
654 int hlen;
655 const struct ip *ip;
656
657
658
659
660
661 ip = (struct ip *) recv_pkt;
662
663 hlen = ip->ip_hl << 2;
664 if (read_len < hlen + ICMP_MINLEN) {
665 if (verbose)
666 printf("packet too short (%d bytes) from %s\n", read_len,
667 inet_ntoa(G.from_lsa->u.sin.sin_addr));
668 return 0;
669 }
670 read_len -= hlen;
671 icp = (struct icmp *)(recv_pkt + hlen);
672 type = icp->icmp_type;
673 code = icp->icmp_code;
674
675 pmtu = 0;
676 if (code == ICMP_UNREACH_NEEDFRAG)
677 pmtu = ntohs(icp->icmp_nextmtu);
678
679 if ((option_mask32 & OPT_USE_ICMP)
680 && type == ICMP_ECHOREPLY
681 && icp->icmp_seq == htons(seq)
682 ) {
683 if (icp->icmp_id != ident)
684
685 return 0;
686
687
688
689
690 return ICMP_UNREACH_PORT+1;
691 }
692
693 if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS)
694 || type == ICMP_UNREACH
695 ) {
696 const struct ip *hip;
697 const struct udphdr *up;
698
699 hip = &icp->icmp_ip;
700 hlen = hip->ip_hl << 2;
701 if (option_mask32 & OPT_USE_ICMP) {
702 struct icmp *hicmp;
703
704 hicmp = (struct icmp *)((unsigned char *)hip + hlen);
705 if (hlen + SIZEOF_ICMP_HDR <= read_len
706 && hip->ip_p == IPPROTO_ICMP
707 && hicmp->icmp_id == ident
708 && hicmp->icmp_seq == htons(seq)
709 ) {
710 return (type == ICMP_TIMXCEED ? -1 : code + 1);
711 }
712 } else {
713 up = (struct udphdr *)((char *)hip + hlen);
714 if (hlen + 12 <= read_len
715 && hip->ip_p == IPPROTO_UDP
716#if !defined(__FreeBSD__)
717
718
719
720
721 && up->dest == htons(port + seq)
722#else
723
724 && up->uh_dport == htons(port + seq)
725#endif
726 ) {
727 return (type == ICMP_TIMXCEED ? -1 : code + 1);
728 }
729 }
730 }
731
732 return hexdump_if_verbose(icp, read_len);
733}
734
735#if ENABLE_TRACEROUTE6
736
737static int
738packet6_ok(int read_len, int seq)
739{
740 const struct icmp6_hdr *icp;
741 unsigned char type, code;
742
743
744
745
746
747 if (read_len < ICMP_MINLEN) {
748 if (verbose)
749 printf("packet too short (%d bytes) from %s\n", read_len,
750 auto_string(xmalloc_sockaddr2dotted_noport(&G.from_lsa->u.sa)));
751 return 0;
752 }
753 icp = (struct icmp6_hdr *) recv_pkt;
754
755 type = icp->icmp6_type;
756 code = icp->icmp6_code;
757
758 if ((option_mask32 & OPT_USE_ICMP)
759 && type == ICMP6_ECHO_REPLY
760 && icp->icmp6_seq == htons(seq)
761 ) {
762 if (icp->icmp6_id != ident)
763
764 return 0;
765
766
767
768
769 return (ICMP6_DST_UNREACH_NOPORT << 8) + 1;
770 }
771
772 if ((type == ICMP6_TIME_EXCEEDED && code == ICMP6_TIME_EXCEED_TRANSIT)
773 || type == ICMP6_DST_UNREACH
774 ) {
775 struct ip6_hdr *hip;
776 struct udphdr *up;
777 int nexthdr;
778
779 hip = (struct ip6_hdr *)(icp + 1);
780 up = (struct udphdr *) (hip + 1);
781 nexthdr = hip->ip6_nxt;
782
783 if (nexthdr == IPPROTO_FRAGMENT) {
784 nexthdr = *(unsigned char*)up;
785 up++;
786 }
787 if (nexthdr == IPPROTO_UDP) {
788 struct outdata6_t *pkt;
789
790 pkt = (struct outdata6_t *) (up + 1);
791
792 if (pkt->ident6 == ident
793 && ntohl(pkt->seq6) == seq
794 ) {
795 return (type == ICMP6_TIME_EXCEEDED ? -1 : (code<<8)+1);
796 }
797 }
798 }
799
800 return hexdump_if_verbose((const struct icmp *)icp, read_len);
801}
802
803static int
804packet_ok(int read_len, int seq)
805{
806 if (!G_ipv6)
807 return packet4_ok(read_len, seq);
808 return packet6_ok(read_len, seq);
809}
810
811#else
812
813# define packet_ok(read_len, seq) packet4_ok(read_len, seq)
814
815#endif
816
817static void
818#if !ENABLE_FEATURE_TRACEROUTE_VERBOSE
819print(void)
820# define print(len) print()
821#else
822print(int read_len)
823#endif
824{
825 char *ina = auto_string(xmalloc_sockaddr2dotted_noport(&G.from_lsa->u.sa));
826
827 if (option_mask32 & OPT_ADDR_NUM) {
828 printf(" %s", ina);
829 } else {
830 char *n = NULL;
831 if (G_ipv6
832 || G.from_lsa->u.sin.sin_addr.s_addr != INADDR_ANY
833 ) {
834
835 n = auto_string(xmalloc_sockaddr2host_noport(&G.from_lsa->u.sa));
836 }
837 printf(" %s (%s)", (n ? n : ina), ina);
838 }
839
840#if ENABLE_FEATURE_TRACEROUTE_VERBOSE
841 if (verbose) {
842# if ENABLE_TRACEROUTE6
843
844
845
846
847
848 if (G_ipv6) {
849
850 } else
851# endif
852 {
853 struct ip *ip4packet = (struct ip*)recv_pkt;
854 read_len -= ip4packet->ip_hl << 2;
855 }
856 printf(" %d bytes to %s", read_len,
857 auto_string(xmalloc_sockaddr2dotted_noport(G.to))
858 );
859 }
860#endif
861}
862
863static void
864print_delta_ms(unsigned t1p, unsigned t2p)
865{
866 unsigned tt = t2p - t1p;
867 printf(" %u.%03u ms", tt / 1000, tt % 1000);
868}
869
870
871
872
873static NOINLINE void
874traceroute_init(int op, char **argv)
875{
876 char *source;
877 char *device;
878 char *tos_str;
879 char *max_ttl_str;
880 char *port_str;
881 char *nprobes_str;
882 char *waittime_str;
883 char *pausemsecs_str;
884 char *first_ttl_str;
885 char *dest_str;
886#if ENABLE_TRACEROUTE6
887 sa_family_t af;
888#else
889 enum { af = AF_INET };
890#endif
891
892
893 bb_sanitize_stdio();
894
895 INIT_G();
896 port = 33434;
897 waittime = 5;
898 G.first_ttl = 1;
899 G.nprobes = 3;
900 G.max_ttl = 30;
901
902 op |= getopt32(argv, "^"
903 OPT_STRING
904 "\0" "-1"
905 , &tos_str, &device, &max_ttl_str, &port_str, &nprobes_str
906 , &source, &waittime_str, &pausemsecs_str, &first_ttl_str
907 );
908 argv += optind;
909
910 if (op & OPT_MAX_TTL)
911 G.max_ttl = xatou_range(max_ttl_str, 1, 255);
912 if (op & OPT_PORT)
913 port = xatou16(port_str);
914 if (op & OPT_NPROBES)
915 G.nprobes = xatou_range(nprobes_str, 1, INT_MAX);
916 if (op & OPT_WAITTIME)
917 waittime = xatou_range(waittime_str, 1, 24 * 60 * 60);
918 if (op & OPT_PAUSE_MS)
919 G.pausemsecs = xatou_range(pausemsecs_str, 0, 60 * 60 * 1000);
920 if (op & OPT_FIRST_TTL)
921 G.first_ttl = xatou_range(first_ttl_str, 1, G.max_ttl);
922
923
924 packlen = sizeof(struct ip)
925 + sizeof(struct udphdr)
926 + sizeof(struct outdata_t);
927 if (op & OPT_USE_ICMP) {
928 packlen = sizeof(struct ip)
929 + SIZEOF_ICMP_HDR
930 + sizeof(struct outdata_t);
931 port = 0;
932 }
933#if ENABLE_TRACEROUTE6
934 af = AF_UNSPEC;
935 if (op & OPT_IPV4)
936 af = AF_INET;
937 if (op & OPT_IPV6)
938 af = AF_INET6;
939 dest_lsa = xhost_and_af2sockaddr(argv[0], port, af);
940 af = dest_lsa->u.sa.sa_family;
941
942 if (af == AF_INET6) {
943 G_ipv6 = 1;
944 packlen = sizeof(struct ip6_hdr)
945 + sizeof(struct udphdr)
946 + sizeof(struct outdata6_t);
947 if (op & OPT_USE_ICMP)
948 packlen = sizeof(struct ip6_hdr)
949 + SIZEOF_ICMP_HDR
950 + sizeof(struct outdata6_t);
951 }
952#else
953
954 dest_lsa = xhost_and_af2sockaddr(argv[0], port, AF_INET);
955#endif
956 G.from_lsa = xmemdup(dest_lsa, LSA_LEN_SIZE + dest_lsa->len);
957#if ENABLE_FEATURE_TRACEROUTE_VERBOSE
958 G.to = xzalloc(dest_lsa->len);
959#endif
960 if (argv[1])
961 packlen = xatoul_range(argv[1], packlen, 32 * 1024);
962
963 if (af == AF_INET) {
964 xmove_fd(xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP), rcvsock);
965#if ENABLE_FEATURE_TRACEROUTE_VERBOSE
966
967 setsockopt_1(rcvsock, IPPROTO_IP, IP_PKTINFO);
968#endif
969 }
970#if ENABLE_TRACEROUTE6
971 else {
972 xmove_fd(xsocket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6), rcvsock);
973# if ENABLE_FEATURE_TRACEROUTE_VERBOSE
974
975 setsockopt_1(rcvsock, SOL_IPV6, IPV6_RECVPKTINFO);
976# endif
977 }
978#endif
979#if TRACEROUTE_SO_DEBUG
980 if (op & OPT_DEBUG)
981 setsockopt_SOL_SOCKET_1(rcvsock, SO_DEBUG);
982#endif
983
984 {
985 int snd;
986 if (af == AF_INET) {
987 if (op & OPT_USE_ICMP)
988 snd = xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
989 else
990 snd = xsocket(AF_INET, SOCK_DGRAM, 0);
991 }
992#if ENABLE_TRACEROUTE6
993# if defined(__FreeBSD__)
994# define SOL_V6_OPTION SOL_IPV6
995# else
996# define SOL_V6_OPTION SOL_RAW
997# endif
998 else {
999 if (setsockopt_int(rcvsock, SOL_V6_OPTION, IPV6_CHECKSUM, 2) != 0)
1000 bb_perror_msg_and_die("setsockopt(%s)", "IPV6_CHECKSUM");
1001 if (op & OPT_USE_ICMP)
1002 snd = xsocket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
1003 else
1004 snd = xsocket(AF_INET6, SOCK_DGRAM, 0);
1005 }
1006#endif
1007 xmove_fd(snd, sndsock);
1008 }
1009
1010#ifdef SO_SNDBUF
1011 if (setsockopt_SOL_SOCKET_int(sndsock, SO_SNDBUF, packlen) != 0) {
1012 bb_perror_msg_and_die("setsockopt(%s)", "SO_SNDBUF");
1013 }
1014#endif
1015#ifdef IP_TOS
1016 if (op & OPT_TOS) {
1017 int tos = xatou_range(tos_str, 0, 255);
1018 if (setsockopt_int(sndsock, IPPROTO_IP, IP_TOS, tos) != 0)
1019 bb_perror_msg_and_die("setsockopt(%s,%d)", "TOS", tos);
1020 }
1021#endif
1022#ifdef IP_DONTFRAG
1023 if (op & OPT_DONT_FRAGMNT)
1024 setsockopt_1(sndsock, IPPROTO_IP, IP_DONTFRAG);
1025#endif
1026#if TRACEROUTE_SO_DEBUG
1027 if (op & OPT_DEBUG)
1028 setsockopt_SOL_SOCKET_1(sndsock, SO_DEBUG);
1029#endif
1030 if (op & OPT_BYPASS_ROUTE)
1031 setsockopt_SOL_SOCKET_1(sndsock, SO_DONTROUTE);
1032
1033 outip = xzalloc(packlen);
1034
1035 ident = getpid();
1036
1037
1038
1039
1040 ident = htons(ident);
1041
1042 outdata = (void*)(outudp + 1);
1043 if (af == AF_INET) {
1044 if (op & OPT_USE_ICMP) {
1045 outicmp->icmp_type = ICMP_ECHO;
1046
1047 outicmp->icmp_id = ident;
1048 outdata = (void*)((char *)outicmp + SIZEOF_ICMP_HDR);
1049 }
1050 }
1051#if ENABLE_TRACEROUTE6
1052 else {
1053 outdata = (void*)(outudp6 + 1);
1054 if (op & OPT_USE_ICMP) {
1055 outicmp6->icmp_type = ICMP6_ECHO_REQUEST;
1056
1057 outicmp6->icmp_id = ident;
1058 outdata = (void*)((char *)outicmp6 + SIZEOF_ICMP_HDR);
1059 }
1060 }
1061#endif
1062
1063 if (op & OPT_DEVICE)
1064 setsockopt_bindtodevice(sndsock, device);
1065
1066 if (op & OPT_SOURCE) {
1067#if ENABLE_TRACEROUTE6
1068
1069 len_and_sockaddr *source_lsa = xhost_and_af2sockaddr(source, 0, af);
1070#else
1071 len_and_sockaddr *source_lsa = xdotted2sockaddr(source, 0);
1072#endif
1073 if (getuid() != 0)
1074 bb_simple_error_msg_and_die(bb_msg_you_must_be_root);
1075
1076 if (af == AF_INET)
1077 if (setsockopt(sndsock, IPPROTO_IP, IP_MULTICAST_IF,
1078 &source_lsa->u.sa, source_lsa->len))
1079 bb_simple_error_msg_and_die("can't set multicast source interface");
1080
1081
1082 xbind(sndsock, &source_lsa->u.sa, source_lsa->len);
1083 if (ENABLE_FEATURE_CLEAN_UP)
1084 free(source_lsa);
1085 } else {
1086 len_and_sockaddr *source_lsa;
1087
1088 set_nport(&dest_lsa->u.sa, htons(port));
1089
1090 xconnect(sndsock, &dest_lsa->u.sa, dest_lsa->len);
1091
1092 source_lsa = get_sock_lsa(sndsock);
1093 if (source_lsa == NULL)
1094 bb_simple_perror_msg_and_die("getsockname");
1095
1096
1097 xbind(rcvsock, &source_lsa->u.sa, source_lsa->len);
1098 if (ENABLE_FEATURE_CLEAN_UP)
1099 free(source_lsa);
1100 }
1101
1102
1103 xsetgid(getgid());
1104 xsetuid(getuid());
1105
1106 dest_str = xmalloc_sockaddr2dotted_noport(&dest_lsa->u.sa);
1107 printf("traceroute to %s (%s)", argv[0], dest_str);
1108 if (ENABLE_FEATURE_CLEAN_UP)
1109 free(dest_str);
1110
1111 if (op & OPT_SOURCE)
1112 printf(" from %s", source);
1113 printf(", %d hops max, %d byte packets\n", G.max_ttl, packlen);
1114}
1115
1116static int
1117common_traceroute_main(int op, char **argv)
1118{
1119 int ttl;
1120 int seq;
1121 struct sockaddr *lastaddr;
1122
1123 traceroute_init(op, argv);
1124
1125 lastaddr = xzalloc(dest_lsa->len);
1126 seq = 0;
1127 for (ttl = G.first_ttl; ttl <= G.max_ttl; ++ttl) {
1128 int probe;
1129 int unreachable = 0;
1130 int got_there = 0;
1131
1132 printf("%2d", ttl);
1133 for (probe = 0; probe < G.nprobes; ++probe) {
1134 unsigned t1;
1135 unsigned t2;
1136 int left_ms;
1137 int read_len;
1138 int icmp_code;
1139
1140 fflush_all();
1141 if (probe != 0)
1142 msleep(G.pausemsecs);
1143
1144 send_probe(++seq, ttl);
1145
1146 t2 = t1 = monotonic_us();
1147 left_ms = waittime * 1000;
1148 for (;;) {
1149
1150
1151
1152
1153 read_len = wait_for_reply(&t2, &left_ms);
1154
1155 if (read_len == 0) {
1156 printf(" *");
1157 goto next_probe;
1158 }
1159 icmp_code = packet_ok(read_len, seq);
1160 if (icmp_code != 0)
1161 break;
1162
1163 }
1164
1165 if (probe == 0
1166 || (memcmp(lastaddr, &G.from_lsa->u.sa, G.from_lsa->len) != 0)
1167 ) {
1168 print(read_len);
1169 memcpy(lastaddr, &G.from_lsa->u.sa, G.from_lsa->len);
1170 }
1171 print_delta_ms(t1, t2);
1172 if (!G_ipv6) {
1173 if (op & OPT_TTL_FLAG) {
1174 struct ip *ip = (struct ip *)recv_pkt;
1175 printf(" (%d)", ip->ip_ttl);
1176 }
1177 }
1178
1179
1180 if (icmp_code == -1)
1181 continue;
1182
1183 icmp_code--;
1184 switch (icmp_code) {
1185#if ENABLE_TRACEROUTE6
1186 case ICMP6_DST_UNREACH_NOPORT << 8:
1187 got_there = 1;
1188 break;
1189#endif
1190 case ICMP_UNREACH_PORT: {
1191 struct ip *ip = (struct ip *)recv_pkt;
1192 if (ip->ip_ttl <= 1)
1193 printf(" !");
1194 got_there = 1;
1195 break;
1196 }
1197 case ICMP_UNREACH_NET:
1198#if ENABLE_TRACEROUTE6 && (ICMP6_DST_UNREACH_NOROUTE != ICMP_UNREACH_NET)
1199 case ICMP6_DST_UNREACH_NOROUTE << 8:
1200#endif
1201 printf(" !N");
1202 ++unreachable;
1203 break;
1204 case ICMP_UNREACH_HOST:
1205#if ENABLE_TRACEROUTE6
1206 case ICMP6_DST_UNREACH_ADDR << 8:
1207#endif
1208 printf(" !H");
1209 ++unreachable;
1210 break;
1211 case ICMP_UNREACH_PROTOCOL:
1212 printf(" !P");
1213 got_there = 1;
1214 break;
1215 case ICMP_UNREACH_NEEDFRAG:
1216 printf(" !F-%d", pmtu);
1217 ++unreachable;
1218 break;
1219 case ICMP_UNREACH_SRCFAIL:
1220#if ENABLE_TRACEROUTE6
1221 case ICMP6_DST_UNREACH_ADMIN << 8:
1222#endif
1223 printf(" !S");
1224 ++unreachable;
1225 break;
1226 case ICMP_UNREACH_FILTER_PROHIB:
1227 case ICMP_UNREACH_NET_PROHIB:
1228 printf(" !A");
1229 ++unreachable;
1230 break;
1231 case ICMP_UNREACH_HOST_PROHIB:
1232 printf(" !C");
1233 ++unreachable;
1234 break;
1235 case ICMP_UNREACH_HOST_PRECEDENCE:
1236 printf(" !V");
1237 ++unreachable;
1238 break;
1239 case ICMP_UNREACH_PRECEDENCE_CUTOFF:
1240 printf(" !C");
1241 ++unreachable;
1242 break;
1243 case ICMP_UNREACH_NET_UNKNOWN:
1244 case ICMP_UNREACH_HOST_UNKNOWN:
1245 printf(" !U");
1246 ++unreachable;
1247 break;
1248 case ICMP_UNREACH_ISOLATED:
1249 printf(" !I");
1250 ++unreachable;
1251 break;
1252 case ICMP_UNREACH_TOSNET:
1253 case ICMP_UNREACH_TOSHOST:
1254 printf(" !T");
1255 ++unreachable;
1256 break;
1257 default:
1258 printf(" !<%d>", icmp_code);
1259 ++unreachable;
1260 break;
1261 }
1262 next_probe: ;
1263 }
1264
1265 bb_putchar('\n');
1266 if (got_there
1267 || (unreachable > 0 && unreachable >= G.nprobes - 1)
1268 ) {
1269 break;
1270 }
1271 }
1272
1273 if (ENABLE_FEATURE_CLEAN_UP) {
1274#if ENABLE_FEATURE_TRACEROUTE_VERBOSE
1275 free(G.to);
1276#endif
1277 free(lastaddr);
1278 free(G.from_lsa);
1279 }
1280
1281 return 0;
1282}
1283
1284#if ENABLE_TRACEROUTE
1285int traceroute_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1286int traceroute_main(int argc UNUSED_PARAM, char **argv)
1287{
1288 return common_traceroute_main(0, argv);
1289}
1290#endif
1291
1292#if ENABLE_TRACEROUTE6
1293int traceroute6_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1294int traceroute6_main(int argc UNUSED_PARAM, char **argv)
1295{
1296 return common_traceroute_main(OPT_IPV6, argv);
1297}
1298#endif
1299