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