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