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