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