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