1 /* vi: set sw=4 ts=4: */
2 /*
3  * Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000
4  *      The Regents of the University of California.  All rights reserved.
5  *
6  * Busybox port by Vladimir Oleynik (C) 2005 <dzo@simtreas.ru>
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that: (1) source code distributions
10  * retain the above copyright notice and this paragraph in its entirety, (2)
11  * distributions including binary code include the above copyright notice and
12  * this paragraph in its entirety in the documentation or other materials
13  * provided with the distribution, and (3) all advertising materials mentioning
14  * features or use of this software display the following acknowledgement:
15  * ''This product includes software developed by the University of California,
16  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
17  * the University nor the names of its contributors may be used to endorse
18  * or promote products derived from this software without specific prior
19  * written permission.
20  * THIS SOFTWARE IS PROVIDED ''AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
21  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
22  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
23  */
24 
25 /*
26  *	traceroute6
27  *
28  *      Modified for NRL 4.4BSD IPv6 release.
29  *      07/31/96 bgp
30  *
31  *	Modified for Linux IPv6 by Pedro Roque <roque@di.fc.ul.pt>
32  *	31/07/1996
33  *
34  *	As ICMP error messages for IPv6 now include more than 8 bytes
35  *	UDP datagrams are now sent via an UDP socket instead of magic
36  *	RAW socket tricks.
37  *
38  *	Converted to busybox applet by Leonid Lisovskiy <lly@sf.net>
39  *	2009-11-16
40  */
41 
42 /*
43  * traceroute host  - trace the route ip packets follow going to "host".
44  *
45  * Attempt to trace the route an ip packet would follow to some
46  * internet host.  We find out intermediate hops by launching probe
47  * packets with a small ttl (time to live) then listening for an
48  * icmp "time exceeded" reply from a gateway.  We start our probes
49  * with a ttl of one and increase by one until we get an icmp "port
50  * unreachable" (which means we got to "host") or hit a max (which
51  * defaults to 30 hops & can be changed with the -m flag).  Three
52  * probes (change with -q flag) are sent at each ttl setting and a
53  * line is printed showing the ttl, address of the gateway and
54  * round trip time of each probe.  If the probe answers come from
55  * different gateways, the address of each responding system will
56  * be printed.  If there is no response within a 5 sec. timeout
57  * interval (changed with the -w flag), a "*" is printed for that
58  * probe.
59  *
60  * Probe packets are UDP format.  We don't want the destination
61  * host to process them so the destination port is set to an
62  * unlikely value (if some clod on the destination is using that
63  * value, it can be changed with the -p flag).
64  *
65  * A sample use might be:
66  *
67  *     [yak 71]% traceroute nis.nsf.net.
68  *     traceroute to nis.nsf.net (35.1.1.48), 30 hops max, 56 byte packet
69  *      1  helios.ee.lbl.gov (128.3.112.1)  19 ms  19 ms  0 ms
70  *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  39 ms  19 ms
71  *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  39 ms  19 ms
72  *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  39 ms  40 ms  39 ms
73  *      5  ccn-nerif22.Berkeley.EDU (128.32.168.22)  39 ms  39 ms  39 ms
74  *      6  128.32.197.4 (128.32.197.4)  40 ms  59 ms  59 ms
75  *      7  131.119.2.5 (131.119.2.5)  59 ms  59 ms  59 ms
76  *      8  129.140.70.13 (129.140.70.13)  99 ms  99 ms  80 ms
77  *      9  129.140.71.6 (129.140.71.6)  139 ms  239 ms  319 ms
78  *     10  129.140.81.7 (129.140.81.7)  220 ms  199 ms  199 ms
79  *     11  nic.merit.edu (35.1.1.48)  239 ms  239 ms  239 ms
80  *
81  * Note that lines 2 & 3 are the same.  This is due to a buggy
82  * kernel on the 2nd hop system -- lbl-csam.arpa -- that forwards
83  * packets with a zero ttl.
84  *
85  * A more interesting example is:
86  *
87  *     [yak 72]% traceroute allspice.lcs.mit.edu.
88  *     traceroute to allspice.lcs.mit.edu (18.26.0.115), 30 hops max
89  *      1  helios.ee.lbl.gov (128.3.112.1)  0 ms  0 ms  0 ms
90  *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  19 ms  19 ms  19 ms
91  *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  19 ms  19 ms
92  *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  19 ms  39 ms  39 ms
93  *      5  ccn-nerif22.Berkeley.EDU (128.32.168.22)  20 ms  39 ms  39 ms
94  *      6  128.32.197.4 (128.32.197.4)  59 ms  119 ms  39 ms
95  *      7  131.119.2.5 (131.119.2.5)  59 ms  59 ms  39 ms
96  *      8  129.140.70.13 (129.140.70.13)  80 ms  79 ms  99 ms
97  *      9  129.140.71.6 (129.140.71.6)  139 ms  139 ms  159 ms
98  *     10  129.140.81.7 (129.140.81.7)  199 ms  180 ms  300 ms
99  *     11  129.140.72.17 (129.140.72.17)  300 ms  239 ms  239 ms
100  *     12  * * *
101  *     13  128.121.54.72 (128.121.54.72)  259 ms  499 ms  279 ms
102  *     14  * * *
103  *     15  * * *
104  *     16  * * *
105  *     17  * * *
106  *     18  ALLSPICE.LCS.MIT.EDU (18.26.0.115)  339 ms  279 ms  279 ms
107  *
108  * (I start to see why I'm having so much trouble with mail to
109  * MIT.)  Note that the gateways 12, 14, 15, 16 & 17 hops away
110  * either don't send ICMP "time exceeded" messages or send them
111  * with a ttl too small to reach us.  14 - 17 are running the
112  * MIT C Gateway code that doesn't send "time exceeded"s.  God
113  * only knows what's going on with 12.
114  *
115  * The silent gateway 12 in the above may be the result of a bug in
116  * the 4.[23]BSD network code (and its derivatives):  4.x (x <= 3)
117  * sends an unreachable message using whatever ttl remains in the
118  * original datagram.  Since, for gateways, the remaining ttl is
119  * zero, the icmp "time exceeded" is guaranteed to not make it back
120  * to us.  The behavior of this bug is slightly more interesting
121  * when it appears on the destination system:
122  *
123  *      1  helios.ee.lbl.gov (128.3.112.1)  0 ms  0 ms  0 ms
124  *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  19 ms  39 ms
125  *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  19 ms  39 ms  19 ms
126  *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  39 ms  40 ms  19 ms
127  *      5  ccn-nerif35.Berkeley.EDU (128.32.168.35)  39 ms  39 ms  39 ms
128  *      6  csgw.Berkeley.EDU (128.32.133.254)  39 ms  59 ms  39 ms
129  *      7  * * *
130  *      8  * * *
131  *      9  * * *
132  *     10  * * *
133  *     11  * * *
134  *     12  * * *
135  *     13  rip.Berkeley.EDU (128.32.131.22)  59 ms !  39 ms !  39 ms !
136  *
137  * Notice that there are 12 "gateways" (13 is the final
138  * destination) and exactly the last half of them are "missing".
139  * What's really happening is that rip (a Sun-3 running Sun OS3.5)
140  * is using the ttl from our arriving datagram as the ttl in its
141  * icmp reply.  So, the reply will time out on the return path
142  * (with no notice sent to anyone since icmp's aren't sent for
143  * icmp's) until we probe with a ttl that's at least twice the path
144  * length.  I.e., rip is really only 7 hops away.  A reply that
145  * returns with a ttl of 1 is a clue this problem exists.
146  * Traceroute prints a "!" after the time if the ttl is <= 1.
147  * Since vendors ship a lot of obsolete (DEC's Ultrix, Sun 3.x) or
148  * non-standard (HPUX) software, expect to see this problem
149  * frequently and/or take care picking the target host of your
150  * probes.
151  *
152  * Other possible annotations after the time are !H, !N, !P (got a host,
153  * network or protocol unreachable, respectively), !S or !F (source
154  * route failed or fragmentation needed -- neither of these should
155  * ever occur and the associated gateway is busted if you see one).  If
156  * almost all the probes result in some kind of unreachable, traceroute
157  * will give up and exit.
158  *
159  * Notes
160  * -----
161  * This program must be run by root or be setuid.  (I suggest that
162  * you *don't* make it setuid -- casual use could result in a lot
163  * of unnecessary traffic on our poor, congested nets.)
164  *
165  * This program requires a kernel mod that does not appear in any
166  * system available from Berkeley:  A raw ip socket using proto
167  * IPPROTO_RAW must interpret the data sent as an ip datagram (as
168  * opposed to data to be wrapped in a ip datagram).  See the README
169  * file that came with the source to this program for a description
170  * of the mods I made to /sys/netinet/raw_ip.c.  Your mileage may
171  * vary.  But, again, ANY 4.x (x < 4) BSD KERNEL WILL HAVE TO BE
172  * MODIFIED TO RUN THIS PROGRAM.
173  *
174  * The udp port usage may appear bizarre (well, ok, it is bizarre).
175  * The problem is that an icmp message only contains 8 bytes of
176  * data from the original datagram.  8 bytes is the size of a udp
177  * header so, if we want to associate replies with the original
178  * datagram, the necessary information must be encoded into the
179  * udp header (the ip id could be used but there's no way to
180  * interlock with the kernel's assignment of ip id's and, anyway,
181  * it would have taken a lot more kernel hacking to allow this
182  * code to set the ip id).  So, to allow two or more users to
183  * use traceroute simultaneously, we use this task's pid as the
184  * source port (the high bit is set to move the port number out
185  * of the "likely" range).  To keep track of which probe is being
186  * replied to (so times and/or hop counts don't get confused by a
187  * reply that was delayed in transit), we increment the destination
188  * port number before each probe.
189  *
190  * Don't use this as a coding example.  I was trying to find a
191  * routing problem and this code sort-of popped out after 48 hours
192  * without sleep.  I was amazed it ever compiled, much less ran.
193  *
194  * I stole the idea for this program from Steve Deering.  Since
195  * the first release, I've learned that had I attended the right
196  * IETF working group meetings, I also could have stolen it from Guy
197  * Almes or Matt Mathis.  I don't know (or care) who came up with
198  * the idea first.  I envy the originators' perspicacity and I'm
199  * glad they didn't keep the idea a secret.
200  *
201  * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or
202  * enhancements to the original distribution.
203  *
204  * I've hacked up a round-trip-route version of this that works by
205  * sending a loose-source-routed udp datagram through the destination
206  * back to yourself.  Unfortunately, SO many gateways botch source
207  * routing, the thing is almost worthless.  Maybe one day...
208  *
209  *  -- Van Jacobson (van@ee.lbl.gov)
210  *     Tue Dec 20 03:50:13 PST 1988
211  */
212 //config:config TRACEROUTE
213 //config:	bool "traceroute (11 kb)"
214 //config:	default y
215 //config:	help
216 //config:	Utility to trace the route of IP packets.
217 //config:
218 //config:config TRACEROUTE6
219 //config:	bool "traceroute6 (13 kb)"
220 //config:	default y
221 //config:	depends on FEATURE_IPV6
222 //config:	help
223 //config:	Utility to trace the route of IPv6 packets.
224 //config:
225 //config:config FEATURE_TRACEROUTE_VERBOSE
226 //config:	bool "Enable verbose output"
227 //config:	default y
228 //config:	depends on TRACEROUTE || TRACEROUTE6
229 //config:	help
230 //config:	Add some verbosity to traceroute. This includes among other things
231 //config:	hostnames and ICMP response types.
232 //config:
233 //config:config FEATURE_TRACEROUTE_USE_ICMP
234 //config:	bool "Enable -I option (use ICMP instead of UDP)"
235 //config:	default y
236 //config:	depends on TRACEROUTE || TRACEROUTE6
237 
238 /* Needs socket(AF_INET, SOCK_RAW, IPPROTO_ICMP), therefore BB_SUID_MAYBE: */
239 //applet:IF_TRACEROUTE(APPLET(traceroute, BB_DIR_USR_BIN, BB_SUID_MAYBE))
240 //applet:IF_TRACEROUTE6(APPLET(traceroute6, BB_DIR_USR_BIN, BB_SUID_MAYBE))
241 
242 //kbuild:lib-$(CONFIG_TRACEROUTE) += traceroute.o
243 //kbuild:lib-$(CONFIG_TRACEROUTE6) += traceroute.o
244 
245 //usage:#define traceroute_trivial_usage
246 //usage:       "[-"IF_TRACEROUTE6("46")IF_FEATURE_TRACEROUTE_USE_ICMP("I")"Flnrv] [-f 1ST_TTL] [-m MAXTTL] [-q PROBES] [-p PORT]\n"
247 //usage:       "	[-t TOS] [-w WAIT_SEC] [-s SRC_IP] [-i IFACE]\n"
248 //usage:       "	[-z PAUSE_MSEC] HOST [BYTES]"
249 //usage:#define traceroute_full_usage "\n\n"
250 //usage:       "Trace the route to HOST\n"
251 //usage:	IF_TRACEROUTE6(
252 //usage:     "\n	-4,-6	Force IP or IPv6 name resolution"
253 //usage:	)
254 //usage:     "\n	-F	Set don't fragment bit"
255 //usage:	IF_FEATURE_TRACEROUTE_USE_ICMP(
256 //usage:     "\n	-I	Use ICMP ECHO instead of UDP datagrams"
257 //usage:	)
258 //usage:     "\n	-l	Display TTL value of the returned packet"
259 //Currently disabled (TRACEROUTE_SO_DEBUG==0)
260 ////usage:     "\n	-d	Set SO_DEBUG options to socket"
261 //usage:     "\n	-n	Print numeric addresses"
262 //usage:     "\n	-r	Bypass routing tables, send directly to HOST"
263 //usage:	IF_FEATURE_TRACEROUTE_VERBOSE(
264 //usage:     "\n	-v	Verbose"
265 //usage:	)
266 //usage:     "\n	-f N	First number of hops (default 1)"
267 //usage:     "\n	-m N	Max number of hops"
268 //usage:     "\n	-q N	Number of probes per hop (default 3)"
269 //usage:     "\n	-p N	Base UDP port number used in probes"
270 //usage:     "\n		(default 33434)"
271 //usage:     "\n	-s IP	Source address"
272 //usage:     "\n	-i IFACE Source interface"
273 //usage:     "\n	-t N	Type-of-service in probe packets (default 0)"
274 //usage:     "\n	-w SEC	Wait for a response (default 3)"
275 //usage:     "\n	-z MSEC	Wait before each send"
276 //usage:
277 //usage:#define traceroute6_trivial_usage
278 //usage:       "[-"IF_FEATURE_TRACEROUTE_USE_ICMP("I")"nrv] [-f 1ST_TTL] [-m MAXTTL] [-q PROBES] [-p PORT]\n"
279 //usage:       "	[-t TOS] [-w WAIT_SEC] [-s SRC_IP] [-i IFACE]\n"
280 //usage:       "	[-z PAUSE_MSEC] HOST [BYTES]"
281 //usage:#define traceroute6_full_usage "\n\n"
282 //usage:       "Trace the route to HOST\n"
283 ////NOP?     "\n	-F	Set don't fragment bit"
284 //usage:	IF_FEATURE_TRACEROUTE_USE_ICMP(
285 //usage:     "\n	-I	Use ICMP ECHO instead of UDP datagrams"
286 //usage:	)
287 ////NOP:     "\n	-l	Display TTL value of the returned packet"
288 //Currently disabled (TRACEROUTE_SO_DEBUG==0)
289 ////usage:     "\n	-d	Set SO_DEBUG options to socket"
290 //usage:     "\n	-n	Print numeric addresses"
291 //usage:     "\n	-r	Bypass routing tables, send directly to HOST"
292 //usage:	IF_FEATURE_TRACEROUTE_VERBOSE(
293 //usage:     "\n	-v	Verbose"
294 //usage:	)
295 //usage:     "\n	-f N	First number of hops (default 1)"
296 //usage:     "\n	-m N	Max number of hops"
297 //usage:     "\n	-q N	Number of probes per hop (default 3)"
298 //usage:     "\n	-p N	Base UDP port number used in probes"
299 //usage:     "\n		(default 33434)"
300 //usage:     "\n	-s IP	Source address"
301 //usage:     "\n	-i IFACE Source interface"
302 //usage:     "\n	-t N	Type-of-service in probe packets (default 0)"
303 //usage:     "\n	-w SEC	Wait for a response (default 3)"
304 //usage:     "\n	-z MSEC	Wait before each send"
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 /* Some operating systems, like GNU/Hurd, don't define SOL_RAW, but do have
335  * IPPROTO_RAW. Since the IPPROTO definitions are also valid to use for
336  * setsockopt (and take the same value as their corresponding SOL definitions,
337  * if they exist), we can just fall back on IPPROTO_RAW. */
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")
346 enum {
347 	OPT_DONT_FRAGMNT = (1 << 0),    /* F */
348 	OPT_USE_ICMP     = (1 << 1) * ENABLE_FEATURE_TRACEROUTE_USE_ICMP, /* I */
349 	OPT_TTL_FLAG     = (1 << 2),    /* l */
350 	OPT_ADDR_NUM     = (1 << 3),    /* n */
351 	OPT_BYPASS_ROUTE = (1 << 4),    /* r */
352 	OPT_DEBUG        = (1 << 5),    /* d */
353 	OPT_VERBOSE      = (1 << 6) * ENABLE_FEATURE_TRACEROUTE_VERBOSE, /* v */
354 	OPT_TOS          = (1 << 7),    /* t */
355 	OPT_DEVICE       = (1 << 8),    /* i */
356 	OPT_MAX_TTL      = (1 << 9),    /* m */
357 	OPT_PORT         = (1 << 10),   /* p */
358 	OPT_NPROBES      = (1 << 11),   /* q */
359 	OPT_SOURCE       = (1 << 12),   /* s */
360 	OPT_WAITTIME     = (1 << 13),   /* w */
361 	OPT_PAUSE_MS     = (1 << 14),   /* z */
362 	OPT_FIRST_TTL    = (1 << 15),   /* f */
363 	OPT_IPV4         = (1 << 16),   /* 4 */
364 	OPT_IPV6         = (1 << 17) * ENABLE_TRACEROUTE6, /* 6 */
365 };
366 #if ENABLE_FEATURE_TRACEROUTE_VERBOSE
367 # define verbose (option_mask32 & OPT_VERBOSE)
368 #else
369 # define verbose 0
370 #endif
371 
372 enum {
373 	SIZEOF_ICMP_HDR = 8,
374 	rcvsock = 3, /* receive (icmp) socket file descriptor */
375 	sndsock = 4, /* send (udp/icmp) socket file descriptor */
376 };
377 
378 /* Data section of the probe packet */
379 struct outdata_t {
380 	unsigned char seq;             /* sequence number of this packet */
381 	unsigned char ttl;             /* ttl packet left with */
382 // UNUSED. Retaining to have the same packet size.
383 	struct timeval tv_UNUSED PACKED; /* time packet left */
384 };
385 
386 #if ENABLE_TRACEROUTE6
387 struct outdata6_t {
388 	uint32_t ident6;
389 	uint32_t seq6;
390 	struct timeval tv_UNUSED PACKED; /* time packet left */
391 };
392 #endif
393 
394 struct globals {
395 	/* Pointer to entire malloced IP packet, "packlen" bytes long: */
396 	struct ip *outip;
397 	/* Pointer to ICMP or UDP payload (not header): */
398 	struct outdata_t *outdata;
399 	len_and_sockaddr *dest_lsa;
400 	len_and_sockaddr *from_lsa;	/* response came from this address */
401 #if ENABLE_FEATURE_TRACEROUTE_VERBOSE
402 	struct sockaddr *to; 		/* response came to this (local) address */
403 #endif
404 	uint32_t ident;
405 	uint16_t port;                  /* start udp dest port # for probe packets */
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;                    /* total length of packet */
413 	int pmtu;                       /* Path MTU Discovery (RFC1191) */
414 	int waittime;                   /* time to wait for response (in seconds) */
415 	int first_ttl;
416 	int nprobes;
417 	int max_ttl;
418 	unsigned pausemsecs;
419 	unsigned char recv_pkt[512];    /* last inbound (icmp) packet */
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 /* NB: for icmp echo, IPv4 and IPv6 fields are the same size and offset:
441  * struct icmp:
442  *	uint8_t  icmp_type;
443  *	uint8_t  icmp_code;
444  *	uint16_t icmp_cksum;
445  *	uint16_t icmp_id;
446  *	uint16_t icmp_seq;
447  * struct icmp6_hdr:
448  *	uint8_t  icmp6_type;
449  *	uint8_t  icmp6_code;
450  *	uint16_t icmp6_cksum;
451  *	uint16_t icmp6_id;
452  *	uint16_t icmp6_seq;
453  * therefore both outicmp and outicmp6 are pointers to *IPv4* icmp struct.
454  * SIZEOF_ICMP_HDR == 8 is the same for both, as well.
455  * However, values of these pointers are not the same (since IPv6 IP header is larger),
456  * and icmp_type constants are not the same:
457  * #define ICMP_ECHO               8
458  * #define ICMP_ECHOREPLY          0
459  * #define ICMP6_ECHO_REQUEST    128
460  * #define ICMP6_ECHO_REPLY      129
461  */
462 
463 static int
wait_for_reply(unsigned * timestamp_us,int * left_ms)464 wait_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 				/*flags:*/ 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 				/*flags:*/ 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 
495 static void
send_probe(int seq,int ttl)496 send_probe(int seq, int ttl)
497 {
498 	int len, res;
499 	void *out;
500 	struct icmp *icp;
501 
502 	/* Payload */
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 		/*xgettimeofday(&pkt->tv);*/
509 		icp = outicmp6;
510 	} else
511 #endif
512 	{
513 		outdata->seq = seq;
514 		outdata->ttl = ttl;
515 // UNUSED: was storing gettimeofday's result there, but never ever checked it
516 		/*memcpy(&outdata->tv, tp, sizeof(outdata->tv));*/
517 		icp = outicmp;
518 	}
519 	out = outdata;
520 	if (option_mask32 & OPT_USE_ICMP) {
521 		out = icp;
522 		/*icp->icmp_type = ICMP[6]_ECHO; - already set */
523 		/*icp->icmp_code = 0; - already set */
524 		/*icp->icmp_id = ident; - already set */
525 		icp->icmp_seq = htons(seq);
526 		/* Always calculate checksum for icmp packets */
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 //BUG! verbose is (x & OPT_VERBOSE), not a counter!
537 #if 0 //ENABLE_FEATURE_TRACEROUTE_VERBOSE
538 	/* XXX undocumented debugging hack */
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 /* Convert an ICMP "type" field to a printable string */
588 static const char *
pr_type(unsigned char t)589 pr_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 }
620 static int
hexdump_if_verbose(const struct icmp * icp,int len)621 hexdump_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 
649 static int
packet4_ok(int read_len,int seq)650 packet4_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 	/* NB: reads from (AF_INET, SOCK_RAW, IPPROTO_ICMP) socket
658 	 * return the entire IP packet (IOW: they do not strip IP header).
659 	 * This differs from (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6) sockets!?
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 	/* Path MTU Discovery (RFC1191) */
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 			/* reply to another ping/traceroute from this box? */
685 			return 0; /* ignore, silently */
686 		/* In UDP mode, when we reach the machine, we (usually)
687 		 * would get "port unreachable" - in ICMP we got "echo reply".
688 		 * Simulate "port unreachable" for caller:
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 // Disabled source check: since we do not form the entire IP packet,
718 // but defer it to kernel, we can't set source port,
719 // and thus can't check it here in the reply
720 			/* && up->source == ident */
721 			 && up->dest == htons(port + seq)
722 #else
723 			/* && up->uh_sport == ident */
724 			 && up->uh_dport == htons(port + seq)
725 #endif
726 			) {
727 				return (type == ICMP_TIMXCEED ? -1 : code + 1);
728 			}
729 		}
730 	}
731 	/* testcase: traceroute -vI 127.0.0.1 (sees its own echo requests) */
732 	return hexdump_if_verbose(icp, read_len);
733 }
734 
735 #if ENABLE_TRACEROUTE6
736 
737 static int
packet6_ok(int read_len,int seq)738 packet6_ok(int read_len, int seq)
739 {
740 	const struct icmp6_hdr *icp;
741 	unsigned char type, code;
742 
743 	/* NB: reads from (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6) socket
744 	 * return only ICMP packet (IOW: they strip IPv6 header).
745 	 * This differs from (AF_INET, SOCK_RAW, IPPROTO_ICMP) sockets!?
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 			/* reply to another ping/traceroute from this box? */
764 			return 0; /* ignore, silently */
765 		/* In UDP mode, when we reach the machine, we (usually)
766 		 * would get "port unreachable" - in ICMP we got "echo reply".
767 		 * Simulate "port unreachable" for caller:
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 	/* cast is safe since the beginning of icmp4 and icmp6 layouts match */
800 	return hexdump_if_verbose((const struct icmp *)icp, read_len);
801 }
802 
803 static int
packet_ok(int read_len,int seq)804 packet_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 /* !ENABLE_TRACEROUTE6 */
812 
813 # define packet_ok(read_len, seq) packet4_ok(read_len, seq)
814 
815 #endif
816 
817 static void
818 #if !ENABLE_FEATURE_TRACEROUTE_VERBOSE
print(void)819 print(void)
820 # define print(len) print()
821 #else
822 print(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 			/* Reverse resolve if IPV6 or not 0.0.0.0 */
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 		/* NB: reads from (AF_INET, SOCK_RAW, IPPROTO_ICMP) socket
844 		 * return the entire IP packet (IOW: they do not strip IP header).
845 		 * Reads from (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6) do strip IPv6
846 		 * header and return only ICMP6 packet. Weird.
847 		 */
848 		if (G_ipv6) {
849 			/* read_len -= sizeof(struct ip6_hdr); - WRONG! */
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 
863 static void
print_delta_ms(unsigned t1p,unsigned t2p)864 print_delta_ms(unsigned t1p, unsigned t2p)
865 {
866 	unsigned tt = t2p - t1p;
867 	printf("  %u.%03u ms", tt / 1000, tt % 1000);
868 }
869 
870 /* Keeping init code in a separate (not inlined!) function
871  * for stack use reduction and better register allocation in main loop.
872  */
873 static NOINLINE void
traceroute_init(int op,char ** argv)874 traceroute_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 	/* Ensure the socket fds won't be 0, 1 or 2 */
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" /* minimum 1 arg */
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 	/* Process destination and optional packet size */
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; /* on ICMP6 sockets, sendto(ipv6.nonzero_port) throws EINVAL! */
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 //TODO: make sure af == AF_INET[6]? (FEATURE_UNIX_LOCAL=y allows "local:/PATH" to be translated to AF_UNIX)
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 	/* accept only IPv4 addresses */
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 		/* want recvmsg to report target local address (for -v) */
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 		/* want recvmsg to report target local address (for -v) */
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 	/* we can use native-endian ident, but other Unix ping/traceroute
1037 	 * utils use *big-endian pid*, and e.g. ping on our machine may be
1038 	 * *not* from busybox, idents may collide. Follow the convention:
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 			/*outicmp->icmp_code = 0; - set by xzalloc */
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 			/*outicmp->icmp_code = 0; - set by xzalloc */
1057 			outicmp6->icmp_id = ident;
1058 			outdata = (void*)((char *)outicmp6 + SIZEOF_ICMP_HDR);
1059 		}
1060 	}
1061 #endif
1062 
1063 	if (op & OPT_DEVICE) /* hmm, do we need error check? */
1064 		setsockopt_bindtodevice(sndsock, device);
1065 
1066 	if (op & OPT_SOURCE) {
1067 #if ENABLE_TRACEROUTE6
1068 // TODO: need xdotted_and_af2sockaddr?
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 		/* Ping4 does this (why?) */
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 //TODO: we can query source port we bound to,
1081 // and check it in replies... if we care enough
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 		/* Connect makes kernel pick source IP (and port if UDP) */
1090 		xconnect(sndsock, &dest_lsa->u.sa, dest_lsa->len);
1091 		/* Read IP and port */
1092 		source_lsa = get_sock_lsa(sndsock);
1093 		if (source_lsa == NULL)
1094 			bb_simple_perror_msg_and_die("getsockname");
1095 		/* bind our recv ICMP socket to this IP (but not port, ICMP has no ports) */
1096 		//set_nport(&source_lsa->u.sa, 0); - paranoia, seems to work without this for both ipv4 and ipv6
1097 		xbind(rcvsock, &source_lsa->u.sa, source_lsa->len);
1098 		if (ENABLE_FEATURE_CLEAN_UP)
1099 			free(source_lsa);
1100 	}
1101 
1102 	/* Revert to non-privileged user after opening sockets */
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 
1116 static int
common_traceroute_main(int op,char ** argv)1117 common_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; /* counter */
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 				/* NB: wait_for_reply() fills "G.from_lsa" and "G.to" with
1150 				 * "where it came from" and "what local address it arrived to"
1151 				 * addresses. Sets t2 = monotonic_us(), updates left_ms.
1152 				 */
1153 				read_len = wait_for_reply(&t2, &left_ms);
1154 
1155 				if (read_len == 0) { /* there was no packet at all? */
1156 					printf("  *");
1157 					goto next_probe;
1158 				}
1159 				icmp_code = packet_ok(read_len, seq);
1160 				if (icmp_code != 0)
1161 					break; /* got a good response */
1162 				/* unrecognized type/code or too short, back to recv */
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 			/* Got a "time exceeded in transit" icmp message? */
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:   /* misuse */
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 		} /* for (nprobes) */
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
1285 int traceroute_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
traceroute_main(int argc UNUSED_PARAM,char ** argv)1286 int traceroute_main(int argc UNUSED_PARAM, char **argv)
1287 {
1288 	return common_traceroute_main(0, argv);
1289 }
1290 #endif
1291 
1292 #if ENABLE_TRACEROUTE6
1293 int traceroute6_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
traceroute6_main(int argc UNUSED_PARAM,char ** argv)1294 int traceroute6_main(int argc UNUSED_PARAM, char **argv)
1295 {
1296 	return common_traceroute_main(OPT_IPV6, argv);
1297 }
1298 #endif
1299