summaryrefslogtreecommitdiff
path: root/networking/traceroute.c (plain)
blob: c3b9b71fa74ae33e04a76fcea4846582d754e386
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
213//usage:#define traceroute_trivial_usage
214//usage: "[-"IF_TRACEROUTE6("46")"FIldnrv] [-f 1ST_TTL] [-m MAXTTL] [-p PORT] [-q PROBES]\n"
215//usage: " [-s SRC_IP] [-t TOS] [-w WAIT_SEC] [-g GATEWAY] [-i IFACE]\n"
216//usage: " [-z PAUSE_MSEC] HOST [BYTES]"
217//usage:#define traceroute_full_usage "\n\n"
218//usage: "Trace the route to HOST\n"
219//usage: IF_TRACEROUTE6(
220//usage: "\n -4,-6 Force IP or IPv6 name resolution"
221//usage: )
222//usage: "\n -F Set the don't fragment bit"
223//usage: "\n -I Use ICMP ECHO instead of UDP datagrams"
224//usage: "\n -l Display the TTL value of the returned packet"
225//usage: "\n -d Set SO_DEBUG options to socket"
226//usage: "\n -n Print numeric addresses"
227//usage: "\n -r Bypass routing tables, send directly to HOST"
228//usage: "\n -v Verbose"
229//usage: "\n -m Max time-to-live (max number of hops)"
230//usage: "\n -p Base UDP port number used in probes"
231//usage: "\n (default 33434)"
232//usage: "\n -q Number of probes per TTL (default 3)"
233//usage: "\n -s IP address to use as the source address"
234//usage: "\n -t Type-of-service in probe packets (default 0)"
235//usage: "\n -w Time in seconds to wait for a response (default 3)"
236//usage: "\n -g Loose source route gateway (8 max)"
237//usage:
238//usage:#define traceroute6_trivial_usage
239//usage: "[-dnrv] [-m MAXTTL] [-p PORT] [-q PROBES]\n"
240//usage: " [-s SRC_IP] [-t TOS] [-w WAIT_SEC] [-i IFACE]\n"
241//usage: " HOST [BYTES]"
242//usage:#define traceroute6_full_usage "\n\n"
243//usage: "Trace the route to HOST\n"
244//usage: "\n -d Set SO_DEBUG options to socket"
245//usage: "\n -n Print numeric addresses"
246//usage: "\n -r Bypass routing tables, send directly to HOST"
247//usage: "\n -v Verbose"
248//usage: "\n -m Max time-to-live (max number of hops)"
249//usage: "\n -p Base UDP port number used in probes"
250//usage: "\n (default is 33434)"
251//usage: "\n -q Number of probes per TTL (default 3)"
252//usage: "\n -s IP address to use as the source address"
253//usage: "\n -t Type-of-service in probe packets (default 0)"
254//usage: "\n -w Time in seconds to wait for a response (default 3)"
255
256#define TRACEROUTE_SO_DEBUG 0
257
258/* TODO: undefs were uncommented - ??! we have config system for that! */
259/* probably ok to remove altogether */
260//#undef CONFIG_FEATURE_TRACEROUTE_VERBOSE
261//#define CONFIG_FEATURE_TRACEROUTE_VERBOSE
262//#undef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
263//#define CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
264//#undef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
265//#define CONFIG_FEATURE_TRACEROUTE_USE_ICMP
266
267
268#include <net/if.h>
269#include <arpa/inet.h>
270#include <netinet/in.h>
271#include <netinet/udp.h>
272#include <netinet/ip.h>
273#include <netinet/ip_icmp.h>
274#if ENABLE_FEATURE_IPV6
275# ifdef __BIONIC__
276# include "ipv6/ip6.h"
277# include "ipv6/icmp6.h"
278# else
279# include <netinet/ip6.h>
280# include <netinet/icmp6.h>
281# endif
282# ifndef SOL_IPV6
283# define SOL_IPV6 IPPROTO_IPV6
284# endif
285#endif
286
287#include "libbb.h"
288#include "inet_common.h"
289
290#ifndef IPPROTO_ICMP
291# define IPPROTO_ICMP 1
292#endif
293#ifndef IPPROTO_IP
294# define IPPROTO_IP 0
295#endif
296
297
298#define OPT_STRING \
299 "FIlnrdvxt:i:m:p:q:s:w:z:f:" \
300 IF_FEATURE_TRACEROUTE_SOURCE_ROUTE("g:") \
301 "4" IF_TRACEROUTE6("6")
302enum {
303 OPT_DONT_FRAGMNT = (1 << 0), /* F */
304 OPT_USE_ICMP = (1 << 1) * ENABLE_FEATURE_TRACEROUTE_USE_ICMP, /* I */
305 OPT_TTL_FLAG = (1 << 2), /* l */
306 OPT_ADDR_NUM = (1 << 3), /* n */
307 OPT_BYPASS_ROUTE = (1 << 4), /* r */
308 OPT_DEBUG = (1 << 5), /* d */
309 OPT_VERBOSE = (1 << 6) * ENABLE_FEATURE_TRACEROUTE_VERBOSE, /* v */
310 OPT_IP_CHKSUM = (1 << 7), /* x */
311 OPT_TOS = (1 << 8), /* t */
312 OPT_DEVICE = (1 << 9), /* i */
313 OPT_MAX_TTL = (1 << 10), /* m */
314 OPT_PORT = (1 << 11), /* p */
315 OPT_NPROBES = (1 << 12), /* q */
316 OPT_SOURCE = (1 << 13), /* s */
317 OPT_WAITTIME = (1 << 14), /* w */
318 OPT_PAUSE_MS = (1 << 15), /* z */
319 OPT_FIRST_TTL = (1 << 16), /* f */
320 OPT_SOURCE_ROUTE = (1 << 17) * ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE, /* g */
321 OPT_IPV4 = (1 << (17+ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE)), /* 4 */
322 OPT_IPV6 = (1 << (18+ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE)) * ENABLE_TRACEROUTE6, /* 6 */
323};
324#define verbose (option_mask32 & OPT_VERBOSE)
325
326enum {
327 SIZEOF_ICMP_HDR = 8,
328 rcvsock = 3, /* receive (icmp) socket file descriptor */
329 sndsock = 4, /* send (udp/icmp) socket file descriptor */
330};
331
332/* Data section of the probe packet */
333struct outdata_t {
334 unsigned char seq; /* sequence number of this packet */
335 unsigned char ttl; /* ttl packet left with */
336// UNUSED. Retaining to have the same packet size.
337 struct timeval tv_UNUSED PACKED; /* time packet left */
338};
339
340#if ENABLE_TRACEROUTE6
341struct outdata6_t {
342 uint32_t ident6;
343 uint32_t seq6;
344 struct timeval tv_UNUSED PACKED; /* time packet left */
345};
346#endif
347
348struct globals {
349 struct ip *outip;
350 struct outdata_t *outdata;
351 len_and_sockaddr *dest_lsa;
352 int packlen; /* total length of packet */
353 int pmtu; /* Path MTU Discovery (RFC1191) */
354 uint32_t ident;
355 uint16_t port; // 32768 + 666; /* start udp dest port # for probe packets */
356 int waittime; // 5; /* time to wait for response (in seconds) */
357#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
358 int optlen; /* length of ip options */
359#else
360#define optlen 0
361#endif
362 unsigned char recv_pkt[512]; /* last inbound (icmp) packet */
363#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
364 /* Maximum number of gateways (include room for one noop) */
365#define NGATEWAYS ((int)((MAX_IPOPTLEN - IPOPT_MINOFF - 1) / sizeof(uint32_t)))
366 /* loose source route gateway list (including room for final destination) */
367 uint32_t gwlist[NGATEWAYS + 1];
368#endif
369};
370
371#define G (*ptr_to_globals)
372#define outip (G.outip )
373#define outdata (G.outdata )
374#define dest_lsa (G.dest_lsa )
375#define packlen (G.packlen )
376#define pmtu (G.pmtu )
377#define ident (G.ident )
378#define port (G.port )
379#define waittime (G.waittime )
380#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
381# define optlen (G.optlen )
382#endif
383#define recv_pkt (G.recv_pkt )
384#define gwlist (G.gwlist )
385#define INIT_G() do { \
386 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
387 port = 32768 + 666; \
388 waittime = 5; \
389} while (0)
390
391#define outicmp ((struct icmp *)(outip + 1))
392#define outudp ((struct udphdr *)(outip + 1))
393
394
395/* libbb candidate? tftp uses this idiom too */
396static len_and_sockaddr* dup_sockaddr(const len_and_sockaddr *lsa)
397{
398 len_and_sockaddr *new_lsa = xzalloc(LSA_LEN_SIZE + lsa->len);
399 memcpy(new_lsa, lsa, LSA_LEN_SIZE + lsa->len);
400 return new_lsa;
401}
402
403
404static int
405wait_for_reply(len_and_sockaddr *from_lsa, struct sockaddr *to, unsigned *timestamp_us, int *left_ms)
406{
407 struct pollfd pfd[1];
408 int read_len = 0;
409
410 pfd[0].fd = rcvsock;
411 pfd[0].events = POLLIN;
412 if (*left_ms >= 0 && safe_poll(pfd, 1, *left_ms) > 0) {
413 unsigned t;
414
415 read_len = recv_from_to(rcvsock,
416 recv_pkt, sizeof(recv_pkt),
417 /*flags:*/ MSG_DONTWAIT,
418 &from_lsa->u.sa, to, from_lsa->len);
419 t = monotonic_us();
420 *left_ms -= (t - *timestamp_us) / 1000;
421 *timestamp_us = t;
422 }
423
424 return read_len;
425}
426
427static void
428send_probe(int seq, int ttl)
429{
430 int len, res;
431 void *out;
432
433 /* Payload */
434#if ENABLE_TRACEROUTE6
435 if (dest_lsa->u.sa.sa_family == AF_INET6) {
436 struct outdata6_t *pkt = (struct outdata6_t *) outip;
437 pkt->ident6 = htonl(ident);
438 pkt->seq6 = htonl(seq);
439 /*gettimeofday(&pkt->tv, &tz);*/
440 } else
441#endif
442 {
443 outdata->seq = seq;
444 outdata->ttl = ttl;
445// UNUSED: was storing gettimeofday's result there, but never ever checked it
446 /*memcpy(&outdata->tv, tp, sizeof(outdata->tv));*/
447
448 if (option_mask32 & OPT_USE_ICMP) {
449 outicmp->icmp_seq = htons(seq);
450
451 /* Always calculate checksum for icmp packets */
452 outicmp->icmp_cksum = 0;
453 outicmp->icmp_cksum = inet_cksum((uint16_t *)outicmp,
454 packlen - (sizeof(*outip) + optlen));
455 if (outicmp->icmp_cksum == 0)
456 outicmp->icmp_cksum = 0xffff;
457 }
458 }
459
460//BUG! verbose is (x & OPT_VERBOSE), not a counter!
461#if 0 //ENABLE_FEATURE_TRACEROUTE_VERBOSE
462 /* XXX undocumented debugging hack */
463 if (verbose > 1) {
464 const uint16_t *sp;
465 int nshorts, i;
466
467 sp = (uint16_t *)outip;
468 nshorts = (unsigned)packlen / sizeof(uint16_t);
469 i = 0;
470 printf("[ %d bytes", packlen);
471 while (--nshorts >= 0) {
472 if ((i++ % 8) == 0)
473 printf("\n\t");
474 printf(" %04x", ntohs(*sp));
475 sp++;
476 }
477 if (packlen & 1) {
478 if ((i % 8) == 0)
479 printf("\n\t");
480 printf(" %02x", *(unsigned char *)sp);
481 }
482 printf("]\n");
483 }
484#endif
485
486#if ENABLE_TRACEROUTE6
487 if (dest_lsa->u.sa.sa_family == AF_INET6) {
488 res = setsockopt(sndsock, SOL_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl));
489 if (res < 0)
490 bb_perror_msg_and_die("setsockopt UNICAST_HOPS %d", ttl);
491 out = outip;
492 len = packlen;
493 } else
494#endif
495 {
496#if defined IP_TTL
497 res = setsockopt(sndsock, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
498 if (res < 0)
499 bb_perror_msg_and_die("setsockopt ttl %d", ttl);
500#endif
501 out = outicmp;
502 len = packlen - sizeof(*outip);
503 if (!(option_mask32 & OPT_USE_ICMP)) {
504 out = outdata;
505 len -= sizeof(*outudp);
506 set_nport(&dest_lsa->u.sa, htons(port + seq));
507 }
508 }
509
510 res = xsendto(sndsock, out, len, &dest_lsa->u.sa, dest_lsa->len);
511 if (res != len)
512 bb_info_msg("sent %d octets, ret=%d", len, res);
513}
514
515#if ENABLE_FEATURE_TRACEROUTE_VERBOSE
516/*
517 * Convert an ICMP "type" field to a printable string.
518 */
519static const char *
520pr_type(unsigned char t)
521{
522 static const char *const ttab[] = {
523 "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable",
524 "Source Quench", "Redirect", "ICMP 6", "ICMP 7",
525 "Echo", "Router Advert", "Router Solicit", "Time Exceeded",
526 "Param Problem", "Timestamp", "Timestamp Reply", "Info Request",
527 "Info Reply", "Mask Request", "Mask Reply"
528 };
529# if ENABLE_TRACEROUTE6
530 static const char *const ttab6[] = {
531[0] "Error", "Dest Unreachable", "Packet Too Big", "Time Exceeded",
532[4] "Param Problem",
533[8] "Echo Request", "Echo Reply", "Membership Query", "Membership Report",
534[12] "Membership Reduction", "Router Solicit", "Router Advert", "Neighbor Solicit",
535[16] "Neighbor Advert", "Redirect",
536 };
537
538 if (dest_lsa->u.sa.sa_family == AF_INET6) {
539 if (t < 5)
540 return ttab6[t];
541 if (t < 128 || t > ND_REDIRECT)
542 return "OUT-OF-RANGE";
543 return ttab6[(t & 63) + 8];
544 }
545# endif
546 if (t >= ARRAY_SIZE(ttab))
547 return "OUT-OF-RANGE";
548
549 return ttab[t];
550}
551#endif
552
553#if !ENABLE_FEATURE_TRACEROUTE_VERBOSE
554#define packet4_ok(read_len, from, seq) \
555 packet4_ok(read_len, seq)
556#endif
557static int
558packet4_ok(int read_len, const struct sockaddr_in *from, int seq)
559{
560 const struct icmp *icp;
561 unsigned char type, code;
562 int hlen;
563 const struct ip *ip;
564
565 ip = (struct ip *) recv_pkt;
566 hlen = ip->ip_hl << 2;
567 if (read_len < hlen + ICMP_MINLEN) {
568#if ENABLE_FEATURE_TRACEROUTE_VERBOSE
569 if (verbose)
570 printf("packet too short (%d bytes) from %s\n", read_len,
571 inet_ntoa(from->sin_addr));
572#endif
573 return 0;
574 }
575 read_len -= hlen;
576 icp = (struct icmp *)(recv_pkt + hlen);
577 type = icp->icmp_type;
578 code = icp->icmp_code;
579 /* Path MTU Discovery (RFC1191) */
580 pmtu = 0;
581 if (code == ICMP_UNREACH_NEEDFRAG)
582 pmtu = ntohs(icp->icmp_nextmtu);
583
584 if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS)
585 || type == ICMP_UNREACH
586 || type == ICMP_ECHOREPLY
587 ) {
588 const struct ip *hip;
589 const struct udphdr *up;
590
591 hip = &icp->icmp_ip;
592 hlen = hip->ip_hl << 2;
593 if (option_mask32 & OPT_USE_ICMP) {
594 struct icmp *hicmp;
595
596 /* XXX */
597 if (type == ICMP_ECHOREPLY
598 && icp->icmp_id == htons(ident)
599 && icp->icmp_seq == htons(seq)
600 ) {
601 return ICMP_UNREACH_PORT+1;
602 }
603
604 hicmp = (struct icmp *)((unsigned char *)hip + hlen);
605 if (hlen + SIZEOF_ICMP_HDR <= read_len
606 && hip->ip_p == IPPROTO_ICMP
607 && hicmp->icmp_id == htons(ident)
608 && hicmp->icmp_seq == htons(seq)
609 ) {
610 return (type == ICMP_TIMXCEED ? -1 : code + 1);
611 }
612 } else {
613 up = (struct udphdr *)((char *)hip + hlen);
614 if (hlen + 12 <= read_len
615 && hip->ip_p == IPPROTO_UDP
616// Off: since we do not form the entire IP packet,
617// but defer it to kernel, we can't set source port,
618// and thus can't check it here in the reply
619 /* && up->source == htons(ident) */
620 && up->dest == htons(port + seq)
621 ) {
622 return (type == ICMP_TIMXCEED ? -1 : code + 1);
623 }
624 }
625 }
626#if ENABLE_FEATURE_TRACEROUTE_VERBOSE
627 if (verbose) {
628 int i;
629 uint32_t *lp = (uint32_t *)&icp->icmp_ip;
630
631 printf("\n%d bytes from %s to "
632 "%s: icmp type %d (%s) code %d\n",
633 read_len, inet_ntoa(from->sin_addr),
634 inet_ntoa(ip->ip_dst),
635 type, pr_type(type), icp->icmp_code);
636 for (i = 4; i < read_len; i += sizeof(*lp))
637 printf("%2d: x%8.8x\n", i, *lp++);
638 }
639#endif
640 return 0;
641}
642
643#if ENABLE_TRACEROUTE6
644# if !ENABLE_FEATURE_TRACEROUTE_VERBOSE
645#define packet_ok(read_len, from_lsa, to, seq) \
646 packet_ok(read_len, from_lsa, seq)
647# endif
648static int
649packet_ok(int read_len, len_and_sockaddr *from_lsa,
650 struct sockaddr *to,
651 int seq)
652{
653 const struct icmp6_hdr *icp;
654 unsigned char type, code;
655
656 if (from_lsa->u.sa.sa_family == AF_INET)
657 return packet4_ok(read_len, &from_lsa->u.sin, seq);
658
659 icp = (struct icmp6_hdr *) recv_pkt;
660
661 type = icp->icmp6_type;
662 code = icp->icmp6_code;
663
664 if ((type == ICMP6_TIME_EXCEEDED && code == ICMP6_TIME_EXCEED_TRANSIT)
665 || type == ICMP6_DST_UNREACH
666 ) {
667 struct ip6_hdr *hip;
668 struct udphdr *up;
669 int nexthdr;
670
671 hip = (struct ip6_hdr *)(icp + 1);
672 up = (struct udphdr *) (hip + 1);
673 nexthdr = hip->ip6_nxt;
674
675 if (nexthdr == IPPROTO_FRAGMENT) {
676 nexthdr = *(unsigned char*)up;
677 up++;
678 }
679 if (nexthdr == IPPROTO_UDP) {
680 struct outdata6_t *pkt;
681
682 pkt = (struct outdata6_t *) (up + 1);
683
684 if (ntohl(pkt->ident6) == ident
685 && ntohl(pkt->seq6) == seq
686 ) {
687 return (type == ICMP6_TIME_EXCEEDED ? -1 : (code<<8)+1);
688 }
689 }
690 }
691
692# if ENABLE_FEATURE_TRACEROUTE_VERBOSE
693 if (verbose) {
694 unsigned char *p;
695 char pa1[MAXHOSTNAMELEN];
696 char pa2[MAXHOSTNAMELEN];
697 int i;
698
699 p = (unsigned char *) (icp + 1);
700
701 printf("\n%d bytes from %s to "
702 "%s: icmp type %d (%s) code %d\n",
703 read_len,
704 inet_ntop(AF_INET6, &from_lsa->u.sin6.sin6_addr, pa1, sizeof(pa1)),
705 inet_ntop(AF_INET6, &((struct sockaddr_in6*)to)->sin6_addr, pa2, sizeof(pa2)),
706 type, pr_type(type), icp->icmp6_code);
707
708 read_len -= sizeof(struct icmp6_hdr);
709 for (i = 0; i < read_len; i++) {
710 if (i % 16 == 0)
711 printf("%04x:", i);
712 if (i % 4 == 0)
713 bb_putchar(' ');
714 printf("%02x", p[i]);
715 if ((i % 16 == 15) && (i + 1 < read_len))
716 bb_putchar('\n');
717 }
718 bb_putchar('\n');
719 }
720# endif
721
722 return 0;
723}
724#else /* !ENABLE_TRACEROUTE6 */
725static ALWAYS_INLINE int
726packet_ok(int read_len,
727 len_and_sockaddr *from_lsa IF_NOT_FEATURE_TRACEROUTE_VERBOSE(UNUSED_PARAM),
728 struct sockaddr *to UNUSED_PARAM,
729 int seq)
730{
731 return packet4_ok(read_len, &from_lsa->u.sin, seq);
732}
733#endif
734
735/*
736 * Construct an Internet address representation.
737 * If the -n flag has been supplied, give
738 * numeric value, otherwise try for symbolic name.
739 */
740static void
741print_inetname(const struct sockaddr *from)
742{
743 char *ina = xmalloc_sockaddr2dotted_noport(from);
744
745 if (option_mask32 & OPT_ADDR_NUM) {
746 printf(" %s", ina);
747 } else {
748 char *n = NULL;
749
750 if (from->sa_family != AF_INET
751 || ((struct sockaddr_in*)from)->sin_addr.s_addr != INADDR_ANY
752 ) {
753 /* Try to reverse resolve if it is not 0.0.0.0 */
754 n = xmalloc_sockaddr2host_noport((struct sockaddr*)from);
755 }
756 printf(" %s (%s)", (n ? n : ina), ina);
757 free(n);
758 }
759 free(ina);
760}
761
762static void
763print(int read_len, const struct sockaddr *from, const struct sockaddr *to)
764{
765 print_inetname(from);
766
767 if (verbose) {
768 char *ina = xmalloc_sockaddr2dotted_noport(to);
769#if ENABLE_TRACEROUTE6
770 if (to->sa_family == AF_INET6) {
771 read_len -= sizeof(struct ip6_hdr);
772 } else
773#endif
774 {
775 struct ip *ip4packet = (struct ip*)recv_pkt;
776 read_len -= ip4packet->ip_hl << 2;
777 }
778 printf(" %d bytes to %s", read_len, ina);
779 free(ina);
780 }
781}
782
783static void
784print_delta_ms(unsigned t1p, unsigned t2p)
785{
786 unsigned tt = t2p - t1p;
787 printf(" %u.%03u ms", tt / 1000, tt % 1000);
788}
789
790/*
791 * Usage: [-dFIlnrvx] [-g gateway] [-i iface] [-f first_ttl]
792 * [-m max_ttl] [ -p port] [-q nqueries] [-s src_addr] [-t tos]
793 * [-w waittime] [-z pausemsecs] host [packetlen]"
794 */
795static int
796common_traceroute_main(int op, char **argv)
797{
798 int minpacket;
799#ifdef IP_TOS
800 int tos = 0;
801#endif
802 int max_ttl = 30;
803 int nprobes = 3;
804 int first_ttl = 1;
805 unsigned pausemsecs = 0;
806 char *source;
807 char *device;
808 char *tos_str;
809 char *max_ttl_str;
810 char *port_str;
811 char *nprobes_str;
812 char *waittime_str;
813 char *pausemsecs_str;
814 char *first_ttl_str;
815 char *dest_str;
816#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
817 llist_t *source_route_list = NULL;
818 int lsrr = 0;
819#endif
820#if ENABLE_TRACEROUTE6
821 sa_family_t af;
822#else
823 enum { af = AF_INET };
824#endif
825 int ttl;
826 int seq;
827 len_and_sockaddr *from_lsa;
828 struct sockaddr *lastaddr;
829 struct sockaddr *to;
830
831 INIT_G();
832
833 /* minimum 1 arg */
834 opt_complementary = "-1:x-x" IF_FEATURE_TRACEROUTE_SOURCE_ROUTE(":g::");
835 op |= getopt32(argv, OPT_STRING
836 , &tos_str, &device, &max_ttl_str, &port_str, &nprobes_str
837 , &source, &waittime_str, &pausemsecs_str, &first_ttl_str
838#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
839 , &source_route_list
840#endif
841 );
842 argv += optind;
843
844#if 0 /* IGNORED */
845 if (op & OPT_IP_CHKSUM)
846 bb_error_msg("warning: ip checksums disabled");
847#endif
848#ifdef IP_TOS
849 if (op & OPT_TOS)
850 tos = xatou_range(tos_str, 0, 255);
851#endif
852 if (op & OPT_MAX_TTL)
853 max_ttl = xatou_range(max_ttl_str, 1, 255);
854 if (op & OPT_PORT)
855 port = xatou16(port_str);
856 if (op & OPT_NPROBES)
857 nprobes = xatou_range(nprobes_str, 1, INT_MAX);
858 if (op & OPT_SOURCE) {
859 /*
860 * set the ip source address of the outbound
861 * probe (e.g., on a multi-homed host).
862 */
863 if (getuid() != 0)
864 bb_error_msg_and_die("%s", bb_msg_you_must_be_root);
865 }
866 if (op & OPT_WAITTIME)
867 waittime = xatou_range(waittime_str, 1, 24 * 60 * 60);
868 if (op & OPT_PAUSE_MS)
869 pausemsecs = xatou_range(pausemsecs_str, 0, 60 * 60 * 1000);
870 if (op & OPT_FIRST_TTL)
871 first_ttl = xatou_range(first_ttl_str, 1, max_ttl);
872
873#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
874 if (source_route_list) {
875 while (source_route_list) {
876 len_and_sockaddr *lsa;
877
878 if (lsrr >= NGATEWAYS)
879 bb_error_msg_and_die("no more than %d gateways", NGATEWAYS);
880 lsa = xhost_and_af2sockaddr(llist_pop(&source_route_list), 0, AF_INET);
881 gwlist[lsrr] = lsa->u.sin.sin_addr.s_addr;
882 free(lsa);
883 ++lsrr;
884 }
885 optlen = (lsrr + 1) * sizeof(gwlist[0]);
886 }
887#endif
888
889 /* Process destination and optional packet size */
890 minpacket = sizeof(*outip) + SIZEOF_ICMP_HDR + sizeof(*outdata) + optlen;
891 if (!(op & OPT_USE_ICMP))
892 minpacket += sizeof(*outudp) - SIZEOF_ICMP_HDR;
893#if ENABLE_TRACEROUTE6
894 af = AF_UNSPEC;
895 if (op & OPT_IPV4)
896 af = AF_INET;
897 if (op & OPT_IPV6)
898 af = AF_INET6;
899 dest_lsa = xhost_and_af2sockaddr(argv[0], port, af);
900 af = dest_lsa->u.sa.sa_family;
901 if (af == AF_INET6)
902 minpacket = sizeof(struct outdata6_t);
903#else
904 dest_lsa = xhost2sockaddr(argv[0], port);
905#endif
906 packlen = minpacket;
907 if (argv[1])
908 packlen = xatoul_range(argv[1], minpacket, 32 * 1024);
909
910 /* Ensure the socket fds won't be 0, 1 or 2 */
911 bb_sanitize_stdio();
912
913#if ENABLE_TRACEROUTE6
914 if (af == AF_INET6) {
915 xmove_fd(xsocket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6), rcvsock);
916# ifdef IPV6_RECVPKTINFO
917 setsockopt(rcvsock, SOL_IPV6, IPV6_RECVPKTINFO,
918 &const_int_1, sizeof(const_int_1));
919 setsockopt(rcvsock, SOL_IPV6, IPV6_2292PKTINFO,
920 &const_int_1, sizeof(const_int_1));
921# else
922 setsockopt(rcvsock, SOL_IPV6, IPV6_PKTINFO,
923 &const_int_1, sizeof(const_int_1));
924# endif
925 } else
926#endif
927 {
928 xmove_fd(xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP), rcvsock);
929 }
930
931#if TRACEROUTE_SO_DEBUG
932 if (op & OPT_DEBUG)
933 setsockopt(rcvsock, SOL_SOCKET, SO_DEBUG,
934 &const_int_1, sizeof(const_int_1));
935#endif
936 if (op & OPT_BYPASS_ROUTE)
937 setsockopt(rcvsock, SOL_SOCKET, SO_DONTROUTE,
938 &const_int_1, sizeof(const_int_1));
939
940#if ENABLE_TRACEROUTE6
941 if (af == AF_INET6) {
942 static const int two = 2;
943 if (setsockopt(rcvsock, SOL_RAW, IPV6_CHECKSUM, &two, sizeof(two)) < 0)
944 bb_perror_msg_and_die("setsockopt RAW_CHECKSUM");
945 xmove_fd(xsocket(af, SOCK_DGRAM, 0), sndsock);
946 } else
947#endif
948 {
949 if (op & OPT_USE_ICMP)
950 xmove_fd(xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP), sndsock);
951 else
952 xmove_fd(xsocket(AF_INET, SOCK_DGRAM, 0), sndsock);
953#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE && defined IP_OPTIONS
954 if (lsrr > 0) {
955 unsigned char optlist[MAX_IPOPTLEN];
956 unsigned size;
957
958 /* final hop */
959 gwlist[lsrr] = dest_lsa->u.sin.sin_addr.s_addr;
960 ++lsrr;
961
962 /* force 4 byte alignment */
963 optlist[0] = IPOPT_NOP;
964 /* loose source route option */
965 optlist[1] = IPOPT_LSRR;
966 size = lsrr * sizeof(gwlist[0]);
967 optlist[2] = size + 3;
968 /* pointer to LSRR addresses */
969 optlist[3] = IPOPT_MINOFF;
970 memcpy(optlist + 4, gwlist, size);
971
972 if (setsockopt(sndsock, IPPROTO_IP, IP_OPTIONS,
973 (char *)optlist, size + sizeof(gwlist[0])) < 0) {
974 bb_perror_msg_and_die("IP_OPTIONS");
975 }
976 }
977#endif
978 }
979
980#ifdef SO_SNDBUF
981 if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, &packlen, sizeof(packlen)) < 0) {
982 bb_perror_msg_and_die("SO_SNDBUF");
983 }
984#endif
985#ifdef IP_TOS
986 if ((op & OPT_TOS) && setsockopt(sndsock, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0) {
987 bb_perror_msg_and_die("setsockopt tos %d", tos);
988 }
989#endif
990#ifdef IP_DONTFRAG
991 if (op & OPT_DONT_FRAGMNT)
992 setsockopt(sndsock, IPPROTO_IP, IP_DONTFRAG,
993 &const_int_1, sizeof(const_int_1));
994#endif
995#if TRACEROUTE_SO_DEBUG
996 if (op & OPT_DEBUG)
997 setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
998 &const_int_1, sizeof(const_int_1));
999#endif
1000 if (op & OPT_BYPASS_ROUTE)
1001 setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
1002 &const_int_1, sizeof(const_int_1));
1003
1004 outip = xzalloc(packlen);
1005
1006 ident = getpid();
1007
1008 if (af == AF_INET) {
1009 if (op & OPT_USE_ICMP) {
1010 ident |= 0x8000;
1011 outicmp->icmp_type = ICMP_ECHO;
1012 outicmp->icmp_id = htons(ident);
1013 outdata = (struct outdata_t *)((char *)outicmp + SIZEOF_ICMP_HDR);
1014 } else {
1015 outdata = (struct outdata_t *)(outudp + 1);
1016 }
1017 }
1018
1019 if (op & OPT_DEVICE) /* hmm, do we need error check? */
1020 setsockopt_bindtodevice(sndsock, device);
1021
1022 if (op & OPT_SOURCE) {
1023#if ENABLE_TRACEROUTE6
1024// TODO: need xdotted_and_af2sockaddr?
1025 len_and_sockaddr *source_lsa = xhost_and_af2sockaddr(source, 0, af);
1026#else
1027 len_and_sockaddr *source_lsa = xdotted2sockaddr(source, 0);
1028#endif
1029 /* Ping4 does this (why?) */
1030 if (af == AF_INET)
1031 if (setsockopt(sndsock, IPPROTO_IP, IP_MULTICAST_IF,
1032 &source_lsa->u.sa, source_lsa->len))
1033 bb_error_msg_and_die("can't set multicast source interface");
1034//TODO: we can query source port we bound to,
1035// and check it in replies... if we care enough
1036 xbind(sndsock, &source_lsa->u.sa, source_lsa->len);
1037 free(source_lsa);
1038 }
1039#if ENABLE_TRACEROUTE6
1040 else if (af == AF_INET6) {
1041//TODO: why we don't do it for IPv4?
1042 len_and_sockaddr *source_lsa;
1043
1044 int probe_fd = xsocket(af, SOCK_DGRAM, 0);
1045 if (op & OPT_DEVICE)
1046 setsockopt_bindtodevice(probe_fd, device);
1047 set_nport(&dest_lsa->u.sa, htons(1025));
1048 /* dummy connect. makes kernel pick source IP (and port) */
1049 xconnect(probe_fd, &dest_lsa->u.sa, dest_lsa->len);
1050 set_nport(&dest_lsa->u.sa, htons(port));
1051
1052 /* read IP and port */
1053 source_lsa = get_sock_lsa(probe_fd);
1054 if (source_lsa == NULL)
1055 bb_error_msg_and_die("can't get probe addr");
1056
1057 close(probe_fd);
1058
1059 /* bind our sockets to this IP (but not port) */
1060 set_nport(&source_lsa->u.sa, 0);
1061 xbind(sndsock, &source_lsa->u.sa, source_lsa->len);
1062 xbind(rcvsock, &source_lsa->u.sa, source_lsa->len);
1063
1064 free(source_lsa);
1065 }
1066#endif
1067
1068 /* Revert to non-privileged user after opening sockets */
1069 xsetgid(getgid());
1070 xsetuid(getuid());
1071
1072 dest_str = xmalloc_sockaddr2dotted_noport(&dest_lsa->u.sa);
1073 printf("traceroute to %s (%s)", argv[0], dest_str);
1074 if (ENABLE_FEATURE_CLEAN_UP) {
1075 free(dest_str);
1076 }
1077
1078 if (op & OPT_SOURCE)
1079 printf(" from %s", source);
1080 printf(", %d hops max, %d byte packets\n", max_ttl, packlen);
1081
1082 from_lsa = dup_sockaddr(dest_lsa);
1083 lastaddr = xzalloc(dest_lsa->len);
1084 to = xzalloc(dest_lsa->len);
1085 seq = 0;
1086 for (ttl = first_ttl; ttl <= max_ttl; ++ttl) {
1087 int probe;
1088 int unreachable = 0; /* counter */
1089 int gotlastaddr = 0; /* flags */
1090 int got_there = 0;
1091
1092 printf("%2d", ttl);
1093 for (probe = 0; probe < nprobes; ++probe) {
1094 int read_len;
1095 unsigned t1;
1096 unsigned t2;
1097 int left_ms;
1098 struct ip *ip;
1099
1100 fflush_all();
1101 if (probe != 0 && pausemsecs > 0)
1102 usleep(pausemsecs * 1000);
1103
1104 send_probe(++seq, ttl);
1105 t2 = t1 = monotonic_us();
1106
1107 left_ms = waittime * 1000;
1108 while ((read_len = wait_for_reply(from_lsa, to, &t2, &left_ms)) != 0) {
1109 int icmp_code;
1110
1111 /* Recv'ed a packet, or read error */
1112 /* t2 = monotonic_us() - set by wait_for_reply */
1113
1114 if (read_len < 0)
1115 continue;
1116 icmp_code = packet_ok(read_len, from_lsa, to, seq);
1117 /* Skip short packet */
1118 if (icmp_code == 0)
1119 continue;
1120
1121 if (!gotlastaddr
1122 || (memcmp(lastaddr, &from_lsa->u.sa, from_lsa->len) != 0)
1123 ) {
1124 print(read_len, &from_lsa->u.sa, to);
1125 memcpy(lastaddr, &from_lsa->u.sa, from_lsa->len);
1126 gotlastaddr = 1;
1127 }
1128
1129 print_delta_ms(t1, t2);
1130 ip = (struct ip *)recv_pkt;
1131
1132 if (from_lsa->u.sa.sa_family == AF_INET)
1133 if (op & OPT_TTL_FLAG)
1134 printf(" (%d)", ip->ip_ttl);
1135
1136 /* time exceeded in transit */
1137 if (icmp_code == -1)
1138 break;
1139 icmp_code--;
1140 switch (icmp_code) {
1141#if ENABLE_TRACEROUTE6
1142 case ICMP6_DST_UNREACH_NOPORT << 8:
1143 got_there = 1;
1144 break;
1145#endif
1146 case ICMP_UNREACH_PORT:
1147 if (ip->ip_ttl <= 1)
1148 printf(" !");
1149 got_there = 1;
1150 break;
1151
1152 case ICMP_UNREACH_NET:
1153#if ENABLE_TRACEROUTE6 && (ICMP6_DST_UNREACH_NOROUTE != ICMP_UNREACH_NET)
1154 case ICMP6_DST_UNREACH_NOROUTE << 8:
1155#endif
1156 printf(" !N");
1157 ++unreachable;
1158 break;
1159 case ICMP_UNREACH_HOST:
1160#if ENABLE_TRACEROUTE6
1161 case ICMP6_DST_UNREACH_ADDR << 8:
1162#endif
1163 printf(" !H");
1164 ++unreachable;
1165 break;
1166 case ICMP_UNREACH_PROTOCOL:
1167 printf(" !P");
1168 got_there = 1;
1169 break;
1170 case ICMP_UNREACH_NEEDFRAG:
1171 printf(" !F-%d", pmtu);
1172 ++unreachable;
1173 break;
1174 case ICMP_UNREACH_SRCFAIL:
1175#if ENABLE_TRACEROUTE6
1176 case ICMP6_DST_UNREACH_ADMIN << 8:
1177#endif
1178 printf(" !S");
1179 ++unreachable;
1180 break;
1181 case ICMP_UNREACH_FILTER_PROHIB:
1182 case ICMP_UNREACH_NET_PROHIB: /* misuse */
1183 printf(" !A");
1184 ++unreachable;
1185 break;
1186 case ICMP_UNREACH_HOST_PROHIB:
1187 printf(" !C");
1188 ++unreachable;
1189 break;
1190 case ICMP_UNREACH_HOST_PRECEDENCE:
1191 printf(" !V");
1192 ++unreachable;
1193 break;
1194 case ICMP_UNREACH_PRECEDENCE_CUTOFF:
1195 printf(" !C");
1196 ++unreachable;
1197 break;
1198 case ICMP_UNREACH_NET_UNKNOWN:
1199 case ICMP_UNREACH_HOST_UNKNOWN:
1200 printf(" !U");
1201 ++unreachable;
1202 break;
1203 case ICMP_UNREACH_ISOLATED:
1204 printf(" !I");
1205 ++unreachable;
1206 break;
1207 case ICMP_UNREACH_TOSNET:
1208 case ICMP_UNREACH_TOSHOST:
1209 printf(" !T");
1210 ++unreachable;
1211 break;
1212 default:
1213 printf(" !<%d>", icmp_code);
1214 ++unreachable;
1215 break;
1216 }
1217 break;
1218 } /* while (wait and read a packet) */
1219
1220 /* there was no packet at all? */
1221 if (read_len == 0)
1222 printf(" *");
1223 } /* for (nprobes) */
1224
1225 bb_putchar('\n');
1226 if (got_there
1227 || (unreachable > 0 && unreachable >= nprobes - 1)
1228 ) {
1229 break;
1230 }
1231 }
1232
1233 if (ENABLE_FEATURE_CLEAN_UP) {
1234 free(to);
1235 free(lastaddr);
1236 free(from_lsa);
1237 }
1238
1239 return 0;
1240}
1241
1242int traceroute_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1243int traceroute_main(int argc UNUSED_PARAM, char **argv)
1244{
1245 return common_traceroute_main(0, argv);
1246}
1247
1248#if ENABLE_TRACEROUTE6
1249int traceroute6_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1250int traceroute6_main(int argc UNUSED_PARAM, char **argv)
1251{
1252 return common_traceroute_main(OPT_IPV6, argv);
1253}
1254#endif
1255