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