dhcpd: write lease file on exit
[oweals/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 static void
422 send_probe(int seq, int ttl)
423 {
424         int len, res;
425         void *out;
426
427         /* Payload */
428 #if ENABLE_TRACEROUTE6
429         if (dest_lsa->u.sa.sa_family == AF_INET6) {
430                 struct outdata6_t *pkt = (struct outdata6_t *) outip;
431                 pkt->ident6 = htonl(ident);
432                 pkt->seq6   = htonl(seq);
433                 /*gettimeofday(&pkt->tv, &tz);*/
434         } else
435 #endif
436         {
437                 outdata->seq = seq;
438                 outdata->ttl = ttl;
439 // UNUSED: was storing gettimeofday's result there, but never ever checked it
440                 /*memcpy(&outdata->tv, tp, sizeof(outdata->tv));*/
441
442                 if (option_mask32 & OPT_USE_ICMP) {
443                         outicmp->icmp_seq = htons(seq);
444
445                         /* Always calculate checksum for icmp packets */
446                         outicmp->icmp_cksum = 0;
447                         outicmp->icmp_cksum = inet_cksum((uint16_t *)outicmp,
448                                                 packlen - (sizeof(*outip) + optlen));
449                         if (outicmp->icmp_cksum == 0)
450                                 outicmp->icmp_cksum = 0xffff;
451                 }
452         }
453
454 //BUG! verbose is (x & OPT_VERBOSE), not a counter!
455 #if 0 //ENABLE_FEATURE_TRACEROUTE_VERBOSE
456         /* XXX undocumented debugging hack */
457         if (verbose > 1) {
458                 const uint16_t *sp;
459                 int nshorts, i;
460
461                 sp = (uint16_t *)outip;
462                 nshorts = (unsigned)packlen / sizeof(uint16_t);
463                 i = 0;
464                 printf("[ %d bytes", packlen);
465                 while (--nshorts >= 0) {
466                         if ((i++ % 8) == 0)
467                                 printf("\n\t");
468                         printf(" %04x", ntohs(*sp));
469                         sp++;
470                 }
471                 if (packlen & 1) {
472                         if ((i % 8) == 0)
473                                 printf("\n\t");
474                         printf(" %02x", *(unsigned char *)sp);
475                 }
476                 printf("]\n");
477         }
478 #endif
479
480 #if ENABLE_TRACEROUTE6
481         if (dest_lsa->u.sa.sa_family == AF_INET6) {
482                 res = setsockopt(sndsock, SOL_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl));
483                 if (res < 0)
484                         bb_perror_msg_and_die("setsockopt UNICAST_HOPS %d", ttl);
485                 out = outip;
486                 len = packlen;
487         } else
488 #endif
489         {
490 #if defined IP_TTL
491                 res = setsockopt(sndsock, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
492                 if (res < 0)
493                         bb_perror_msg_and_die("setsockopt ttl %d", ttl);
494 #endif
495                 out = outicmp;
496                 len = packlen - sizeof(*outip);
497                 if (!(option_mask32 & OPT_USE_ICMP)) {
498                         out = outdata;
499                         len -= sizeof(*outudp);
500                         set_nport(&dest_lsa->u.sa, htons(port + seq));
501                 }
502         }
503
504         res = xsendto(sndsock, out, len, &dest_lsa->u.sa, dest_lsa->len);
505         if (res != len)
506                 bb_info_msg("sent %d octets, ret=%d", len, res);
507 }
508
509 #if ENABLE_FEATURE_TRACEROUTE_VERBOSE
510 /*
511  * Convert an ICMP "type" field to a printable string.
512  */
513 static const char *
514 pr_type(unsigned char t)
515 {
516         static const char *const ttab[] = {
517         "Echo Reply",   "ICMP 1",       "ICMP 2",       "Dest Unreachable",
518         "Source Quench", "Redirect",    "ICMP 6",       "ICMP 7",
519         "Echo",         "Router Advert", "Router Solicit", "Time Exceeded",
520         "Param Problem", "Timestamp",   "Timestamp Reply", "Info Request",
521         "Info Reply",   "Mask Request", "Mask Reply"
522         };
523 # if ENABLE_TRACEROUTE6
524         static const char *const ttab6[] = {
525 [0]     "Error", "Dest Unreachable", "Packet Too Big", "Time Exceeded",
526 [4]     "Param Problem",
527 [8]     "Echo Request", "Echo Reply", "Membership Query", "Membership Report",
528 [12]    "Membership Reduction", "Router Solicit", "Router Advert", "Neighbor Solicit",
529 [16]    "Neighbor Advert", "Redirect",
530         };
531
532         if (dest_lsa->u.sa.sa_family == AF_INET6) {
533                 if (t < 5)
534                         return ttab6[t];
535                 if (t < 128 || t > ND_REDIRECT)
536                         return "OUT-OF-RANGE";
537                 return ttab6[(t & 63) + 8];
538         }
539 # endif
540         if (t >= ARRAY_SIZE(ttab))
541                 return "OUT-OF-RANGE";
542
543         return ttab[t];
544 }
545 #endif
546
547 #if !ENABLE_FEATURE_TRACEROUTE_VERBOSE
548 #define packet4_ok(read_len, from, seq) \
549         packet4_ok(read_len, seq)
550 #endif
551 static int
552 packet4_ok(int read_len, const struct sockaddr_in *from, int seq)
553 {
554         const struct icmp *icp;
555         unsigned char type, code;
556         int hlen;
557         const struct ip *ip;
558
559         ip = (struct ip *) recv_pkt;
560         hlen = ip->ip_hl << 2;
561         if (read_len < hlen + ICMP_MINLEN) {
562 #if ENABLE_FEATURE_TRACEROUTE_VERBOSE
563                 if (verbose)
564                         printf("packet too short (%d bytes) from %s\n", read_len,
565                                 inet_ntoa(from->sin_addr));
566 #endif
567                 return 0;
568         }
569         read_len -= hlen;
570         icp = (struct icmp *)(recv_pkt + hlen);
571         type = icp->icmp_type;
572         code = icp->icmp_code;
573         /* Path MTU Discovery (RFC1191) */
574         pmtu = 0;
575         if (code == ICMP_UNREACH_NEEDFRAG)
576                 pmtu = ntohs(icp->icmp_nextmtu);
577
578         if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS)
579          || type == ICMP_UNREACH
580          || type == ICMP_ECHOREPLY
581         ) {
582                 const struct ip *hip;
583                 const struct udphdr *up;
584
585                 hip = &icp->icmp_ip;
586                 hlen = hip->ip_hl << 2;
587                 if (option_mask32 & OPT_USE_ICMP) {
588                         struct icmp *hicmp;
589
590                         /* XXX */
591                         if (type == ICMP_ECHOREPLY
592                          && icp->icmp_id == htons(ident)
593                          && icp->icmp_seq == htons(seq)
594                         ) {
595                                 return ICMP_UNREACH_PORT+1;
596                         }
597
598                         hicmp = (struct icmp *)((unsigned char *)hip + hlen);
599                         if (hlen + SIZEOF_ICMP_HDR <= read_len
600                          && hip->ip_p == IPPROTO_ICMP
601                          && hicmp->icmp_id == htons(ident)
602                          && hicmp->icmp_seq == htons(seq)
603                         ) {
604                                 return (type == ICMP_TIMXCEED ? -1 : code + 1);
605                         }
606                 } else {
607                         up = (struct udphdr *)((char *)hip + hlen);
608                         if (hlen + 12 <= read_len
609                          && hip->ip_p == IPPROTO_UDP
610 // Off: since we do not form the entire IP packet,
611 // but defer it to kernel, we can't set source port,
612 // and thus can't check it here in the reply
613                         /* && up->source == htons(ident) */
614                          && up->dest == htons(port + seq)
615                         ) {
616                                 return (type == ICMP_TIMXCEED ? -1 : code + 1);
617                         }
618                 }
619         }
620 #if ENABLE_FEATURE_TRACEROUTE_VERBOSE
621         if (verbose) {
622                 int i;
623                 uint32_t *lp = (uint32_t *)&icp->icmp_ip;
624
625                 printf("\n%d bytes from %s to "
626                        "%s: icmp type %d (%s) code %d\n",
627                         read_len, inet_ntoa(from->sin_addr),
628                         inet_ntoa(ip->ip_dst),
629                         type, pr_type(type), icp->icmp_code);
630                 for (i = 4; i < read_len; i += sizeof(*lp))
631                         printf("%2d: x%8.8x\n", i, *lp++);
632         }
633 #endif
634         return 0;
635 }
636
637 #if ENABLE_TRACEROUTE6
638 # if !ENABLE_FEATURE_TRACEROUTE_VERBOSE
639 #define packet_ok(read_len, from_lsa, to, seq) \
640         packet_ok(read_len, from_lsa, seq)
641 # endif
642 static int
643 packet_ok(int read_len, len_and_sockaddr *from_lsa,
644                         struct sockaddr *to,
645                         int seq)
646 {
647         const struct icmp6_hdr *icp;
648         unsigned char type, code;
649
650         if (from_lsa->u.sa.sa_family == AF_INET)
651                 return packet4_ok(read_len, &from_lsa->u.sin, seq);
652
653         icp = (struct icmp6_hdr *) recv_pkt;
654
655         type = icp->icmp6_type;
656         code = icp->icmp6_code;
657
658         if ((type == ICMP6_TIME_EXCEEDED && code == ICMP6_TIME_EXCEED_TRANSIT)
659          || type == ICMP6_DST_UNREACH
660         ) {
661                 struct ip6_hdr *hip;
662                 struct udphdr *up;
663                 int nexthdr;
664
665                 hip = (struct ip6_hdr *)(icp + 1);
666                 up  = (struct udphdr *) (hip + 1);
667                 nexthdr = hip->ip6_nxt;
668
669                 if (nexthdr == IPPROTO_FRAGMENT) {
670                         nexthdr = *(unsigned char*)up;
671                         up++;
672                 }
673                 if (nexthdr == IPPROTO_UDP) {
674                         struct outdata6_t *pkt;
675
676                         pkt = (struct outdata6_t *) (up + 1);
677
678                         if (ntohl(pkt->ident6) == ident
679                          && ntohl(pkt->seq6) == seq
680                         ) {
681                                 return (type == ICMP6_TIME_EXCEEDED ? -1 : (code<<8)+1);
682                         }
683                 }
684         }
685
686 # if ENABLE_FEATURE_TRACEROUTE_VERBOSE
687         if (verbose) {
688                 unsigned char *p;
689                 char pa1[MAXHOSTNAMELEN];
690                 char pa2[MAXHOSTNAMELEN];
691                 int i;
692
693                 p = (unsigned char *) (icp + 1);
694
695                 printf("\n%d bytes from %s to "
696                        "%s: icmp type %d (%s) code %d\n",
697                         read_len,
698                         inet_ntop(AF_INET6, &from_lsa->u.sin6.sin6_addr, pa1, sizeof(pa1)),
699                         inet_ntop(AF_INET6, &((struct sockaddr_in6*)to)->sin6_addr, pa2, sizeof(pa2)),
700                         type, pr_type(type), icp->icmp6_code);
701
702                 read_len -= sizeof(struct icmp6_hdr);
703                 for (i = 0; i < read_len; i++) {
704                         if (i % 16 == 0)
705                                 printf("%04x:", i);
706                         if (i % 4 == 0)
707                                 bb_putchar(' ');
708                         printf("%02x", p[i]);
709                         if ((i % 16 == 15) && (i + 1 < read_len))
710                                 bb_putchar('\n');
711                 }
712                 bb_putchar('\n');
713         }
714 # endif
715
716         return 0;
717 }
718 #else /* !ENABLE_TRACEROUTE6 */
719 static ALWAYS_INLINE int
720 packet_ok(int read_len,
721                 len_and_sockaddr *from_lsa IF_NOT_FEATURE_TRACEROUTE_VERBOSE(UNUSED_PARAM),
722                 struct sockaddr *to UNUSED_PARAM,
723                 int seq)
724 {
725         return packet4_ok(read_len, &from_lsa->u.sin, seq);
726 }
727 #endif
728
729 /*
730  * Construct an Internet address representation.
731  * If the -n flag has been supplied, give
732  * numeric value, otherwise try for symbolic name.
733  */
734 static void
735 print_inetname(const struct sockaddr *from)
736 {
737         char *ina = xmalloc_sockaddr2dotted_noport(from);
738
739         if (option_mask32 & OPT_ADDR_NUM) {
740                 printf("  %s", ina);
741         } else {
742                 char *n = NULL;
743
744                 if (from->sa_family != AF_INET
745                  || ((struct sockaddr_in*)from)->sin_addr.s_addr != INADDR_ANY
746                 ) {
747                         /* Try to reverse resolve if it is not 0.0.0.0 */
748                         n = xmalloc_sockaddr2host_noport((struct sockaddr*)from);
749                 }
750                 printf("  %s (%s)", (n ? n : ina), ina);
751                 free(n);
752         }
753         free(ina);
754 }
755
756 static void
757 print(int read_len, const struct sockaddr *from, const struct sockaddr *to)
758 {
759         print_inetname(from);
760
761         if (verbose) {
762                 char *ina = xmalloc_sockaddr2dotted_noport(to);
763 #if ENABLE_TRACEROUTE6
764                 if (to->sa_family == AF_INET6) {
765                         read_len -= sizeof(struct ip6_hdr);
766                 } else
767 #endif
768                 {
769                         struct ip *ip4packet = (struct ip*)recv_pkt;
770                         read_len -= ip4packet->ip_hl << 2;
771                 }
772                 printf(" %d bytes to %s", read_len, ina);
773                 free(ina);
774         }
775 }
776
777 static void
778 print_delta_ms(unsigned t1p, unsigned t2p)
779 {
780         unsigned tt = t2p - t1p;
781         printf("  %u.%03u ms", tt / 1000, tt % 1000);
782 }
783
784 /*
785  * Usage: [-dFIlnrvx] [-g gateway] [-i iface] [-f first_ttl]
786  * [-m max_ttl] [ -p port] [-q nqueries] [-s src_addr] [-t tos]
787  * [-w waittime] [-z pausemsecs] host [packetlen]"
788  */
789 static int
790 common_traceroute_main(int op, char **argv)
791 {
792         int minpacket;
793         int tos = 0;
794         int max_ttl = 30;
795         int nprobes = 3;
796         int first_ttl = 1;
797         unsigned pausemsecs = 0;
798         char *source;
799         char *device;
800         char *tos_str;
801         char *max_ttl_str;
802         char *port_str;
803         char *nprobes_str;
804         char *waittime_str;
805         char *pausemsecs_str;
806         char *first_ttl_str;
807 #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
808         llist_t *source_route_list = NULL;
809         int lsrr = 0;
810 #endif
811 #if ENABLE_TRACEROUTE6
812         sa_family_t af;
813 #else
814         enum { af = AF_INET };
815 #endif
816         int ttl;
817         int seq;
818         len_and_sockaddr *from_lsa;
819         struct sockaddr *lastaddr;
820         struct sockaddr *to;
821
822         INIT_G();
823
824         /* minimum 1 arg */
825         opt_complementary = "-1:x-x" IF_FEATURE_TRACEROUTE_SOURCE_ROUTE(":g::");
826         op |= getopt32(argv, OPT_STRING
827                 , &tos_str, &device, &max_ttl_str, &port_str, &nprobes_str
828                 , &source, &waittime_str, &pausemsecs_str, &first_ttl_str
829 #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
830                 , &source_route_list
831 #endif
832         );
833         argv += optind;
834
835 #if 0 /* IGNORED */
836         if (op & OPT_IP_CHKSUM)
837                 bb_error_msg("warning: ip checksums disabled");
838 #endif
839         if (op & OPT_TOS)
840                 tos = xatou_range(tos_str, 0, 255);
841         if (op & OPT_MAX_TTL)
842                 max_ttl = xatou_range(max_ttl_str, 1, 255);
843         if (op & OPT_PORT)
844                 port = xatou16(port_str);
845         if (op & OPT_NPROBES)
846                 nprobes = xatou_range(nprobes_str, 1, INT_MAX);
847         if (op & OPT_SOURCE) {
848                 /*
849                  * set the ip source address of the outbound
850                  * probe (e.g., on a multi-homed host).
851                  */
852                 if (getuid() != 0)
853                         bb_error_msg_and_die(bb_msg_you_must_be_root);
854         }
855         if (op & OPT_WAITTIME)
856                 waittime = xatou_range(waittime_str, 1, 24 * 60 * 60);
857         if (op & OPT_PAUSE_MS)
858                 pausemsecs = xatou_range(pausemsecs_str, 0, 60 * 60 * 1000);
859         if (op & OPT_FIRST_TTL)
860                 first_ttl = xatou_range(first_ttl_str, 1, max_ttl);
861
862 #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
863         if (source_route_list) {
864                 while (source_route_list) {
865                         len_and_sockaddr *lsa;
866
867                         if (lsrr >= NGATEWAYS)
868                                 bb_error_msg_and_die("no more than %d gateways", NGATEWAYS);
869                         lsa = xhost_and_af2sockaddr(llist_pop(&source_route_list), 0, AF_INET);
870                         gwlist[lsrr] = lsa->u.sin.sin_addr.s_addr;
871                         free(lsa);
872                         ++lsrr;
873                 }
874                 optlen = (lsrr + 1) * sizeof(gwlist[0]);
875         }
876 #endif
877
878         /* Process destination and optional packet size */
879         minpacket = sizeof(*outip) + SIZEOF_ICMP_HDR + sizeof(*outdata) + optlen;
880         if (!(op & OPT_USE_ICMP))
881                 minpacket += sizeof(*outudp) - SIZEOF_ICMP_HDR;
882 #if ENABLE_TRACEROUTE6
883         af = AF_UNSPEC;
884         if (op & OPT_IPV4)
885                 af = AF_INET;
886         if (op & OPT_IPV6)
887                 af = AF_INET6;
888         dest_lsa = xhost_and_af2sockaddr(argv[0], port, af);
889         af = dest_lsa->u.sa.sa_family;
890         if (af == AF_INET6)
891                 minpacket = sizeof(struct outdata6_t);
892 #else
893         dest_lsa = xhost2sockaddr(argv[0], port);
894 #endif
895         packlen = minpacket;
896         if (argv[1])
897                 packlen = xatoul_range(argv[1], minpacket, 32 * 1024);
898
899         /* Ensure the socket fds won't be 0, 1 or 2 */
900         bb_sanitize_stdio();
901
902 #if ENABLE_TRACEROUTE6
903         if (af == AF_INET6) {
904                 xmove_fd(xsocket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6), rcvsock);
905 # ifdef IPV6_RECVPKTINFO
906                 setsockopt(rcvsock, SOL_IPV6, IPV6_RECVPKTINFO,
907                                 &const_int_1, sizeof(const_int_1));
908                 setsockopt(rcvsock, SOL_IPV6, IPV6_2292PKTINFO,
909                                 &const_int_1, sizeof(const_int_1));
910 # else
911                 setsockopt(rcvsock, SOL_IPV6, IPV6_PKTINFO,
912                                 &const_int_1, sizeof(const_int_1));
913 # endif
914         } else
915 #endif
916         {
917                 xmove_fd(xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP), rcvsock);
918         }
919
920 #if TRACEROUTE_SO_DEBUG
921         if (op & OPT_DEBUG)
922                 setsockopt(rcvsock, SOL_SOCKET, SO_DEBUG,
923                                 &const_int_1, sizeof(const_int_1));
924 #endif
925         if (op & OPT_BYPASS_ROUTE)
926                 setsockopt(rcvsock, SOL_SOCKET, SO_DONTROUTE,
927                                 &const_int_1, sizeof(const_int_1));
928
929 #if ENABLE_TRACEROUTE6
930         if (af == AF_INET6) {
931                 static const int two = 2;
932                 if (setsockopt(rcvsock, SOL_RAW, IPV6_CHECKSUM, &two, sizeof(two)) < 0)
933                         bb_perror_msg_and_die("setsockopt RAW_CHECKSUM");
934                 xmove_fd(xsocket(af, SOCK_DGRAM, 0), sndsock);
935         } else
936 #endif
937         {
938                 if (op & OPT_USE_ICMP)
939                         xmove_fd(xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP), sndsock);
940                 else
941                         xmove_fd(xsocket(AF_INET, SOCK_DGRAM, 0), sndsock);
942 #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE && defined IP_OPTIONS
943                 if (lsrr > 0) {
944                         unsigned char optlist[MAX_IPOPTLEN];
945                         unsigned size;
946
947                         /* final hop */
948                         gwlist[lsrr] = dest_lsa->u.sin.sin_addr.s_addr;
949                         ++lsrr;
950
951                         /* force 4 byte alignment */
952                         optlist[0] = IPOPT_NOP;
953                         /* loose source route option */
954                         optlist[1] = IPOPT_LSRR;
955                         size = lsrr * sizeof(gwlist[0]);
956                         optlist[2] = size + 3;
957                         /* pointer to LSRR addresses */
958                         optlist[3] = IPOPT_MINOFF;
959                         memcpy(optlist + 4, gwlist, size);
960
961                         if (setsockopt(sndsock, IPPROTO_IP, IP_OPTIONS,
962                                         (char *)optlist, size + sizeof(gwlist[0])) < 0) {
963                                 bb_perror_msg_and_die("IP_OPTIONS");
964                         }
965                 }
966 #endif
967         }
968
969 #ifdef SO_SNDBUF
970         if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, &packlen, sizeof(packlen)) < 0) {
971                 bb_perror_msg_and_die("SO_SNDBUF");
972         }
973 #endif
974 #ifdef IP_TOS
975         if ((op & OPT_TOS) && setsockopt(sndsock, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0) {
976                 bb_perror_msg_and_die("setsockopt tos %d", tos);
977         }
978 #endif
979 #ifdef IP_DONTFRAG
980         if (op & OPT_DONT_FRAGMNT)
981                 setsockopt(sndsock, IPPROTO_IP, IP_DONTFRAG,
982                                 &const_int_1, sizeof(const_int_1));
983 #endif
984 #if TRACEROUTE_SO_DEBUG
985         if (op & OPT_DEBUG)
986                 setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
987                                 &const_int_1, sizeof(const_int_1));
988 #endif
989         if (op & OPT_BYPASS_ROUTE)
990                 setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
991                                 &const_int_1, sizeof(const_int_1));
992
993         outip = xzalloc(packlen);
994
995         ident = getpid();
996
997         if (af == AF_INET) {
998                 if (op & OPT_USE_ICMP) {
999                         ident |= 0x8000;
1000                         outicmp->icmp_type = ICMP_ECHO;
1001                         outicmp->icmp_id = htons(ident);
1002                         outdata = (struct outdata_t *)((char *)outicmp + SIZEOF_ICMP_HDR);
1003                 } else {
1004                         outdata = (struct outdata_t *)(outudp + 1);
1005                 }
1006         }
1007
1008         if (op & OPT_DEVICE) /* hmm, do we need error check? */
1009                 setsockopt_bindtodevice(sndsock, device);
1010
1011         if (op & OPT_SOURCE) {
1012 #if ENABLE_TRACEROUTE6
1013 // TODO: need xdotted_and_af2sockaddr?
1014                 len_and_sockaddr *source_lsa = xhost_and_af2sockaddr(source, 0, af);
1015 #else
1016                 len_and_sockaddr *source_lsa = xdotted2sockaddr(source, 0);
1017 #endif
1018                 /* Ping4 does this (why?) */
1019                 if (af == AF_INET)
1020                         if (setsockopt(sndsock, IPPROTO_IP, IP_MULTICAST_IF,
1021                                         &source_lsa->u.sa, source_lsa->len))
1022                                 bb_error_msg_and_die("can't set multicast source interface");
1023 //TODO: we can query source port we bound to,
1024 // and check it in replies... if we care enough
1025                 xbind(sndsock, &source_lsa->u.sa, source_lsa->len);
1026                 free(source_lsa);
1027         }
1028 #if ENABLE_TRACEROUTE6
1029         else if (af == AF_INET6) {
1030 //TODO: why we don't do it for IPv4?
1031                 len_and_sockaddr *source_lsa;
1032
1033                 int probe_fd = xsocket(af, SOCK_DGRAM, 0);
1034                 if (op & OPT_DEVICE)
1035                         setsockopt_bindtodevice(probe_fd, device);
1036                 set_nport(&dest_lsa->u.sa, htons(1025));
1037                 /* dummy connect. makes kernel pick source IP (and port) */
1038                 xconnect(probe_fd, &dest_lsa->u.sa, dest_lsa->len);
1039                 set_nport(&dest_lsa->u.sa, htons(port));
1040
1041                 /* read IP and port */
1042                 source_lsa = get_sock_lsa(probe_fd);
1043                 if (source_lsa == NULL)
1044                         bb_error_msg_and_die("can't get probe addr");
1045
1046                 close(probe_fd);
1047
1048                 /* bind our sockets to this IP (but not port) */
1049                 set_nport(&source_lsa->u.sa, 0);
1050                 xbind(sndsock, &source_lsa->u.sa, source_lsa->len);
1051                 xbind(rcvsock, &source_lsa->u.sa, source_lsa->len);
1052
1053                 free(source_lsa);
1054         }
1055 #endif
1056
1057         /* Revert to non-privileged user after opening sockets */
1058         xsetgid(getgid());
1059         xsetuid(getuid());
1060
1061         printf("traceroute to %s (%s)", argv[0],
1062                         xmalloc_sockaddr2dotted_noport(&dest_lsa->u.sa));
1063         if (op & OPT_SOURCE)
1064                 printf(" from %s", source);
1065         printf(", %d hops max, %d byte packets\n", max_ttl, packlen);
1066
1067         from_lsa = dup_sockaddr(dest_lsa);
1068         lastaddr = xzalloc(dest_lsa->len);
1069         to = xzalloc(dest_lsa->len);
1070         seq = 0;
1071         for (ttl = first_ttl; ttl <= max_ttl; ++ttl) {
1072                 int probe;
1073                 int unreachable = 0; /* counter */
1074                 int gotlastaddr = 0; /* flags */
1075                 int got_there = 0;
1076
1077                 printf("%2d", ttl);
1078                 for (probe = 0; probe < nprobes; ++probe) {
1079                         int read_len;
1080                         unsigned t1;
1081                         unsigned t2;
1082                         int left_ms;
1083                         struct ip *ip;
1084
1085                         fflush_all();
1086                         if (probe != 0 && pausemsecs > 0)
1087                                 usleep(pausemsecs * 1000);
1088
1089                         send_probe(++seq, ttl);
1090                         t2 = t1 = monotonic_us();
1091
1092                         left_ms = waittime * 1000;
1093                         while ((read_len = wait_for_reply(from_lsa, to, &t2, &left_ms)) != 0) {
1094                                 int icmp_code;
1095
1096                                 /* Recv'ed a packet, or read error */
1097                                 /* t2 = monotonic_us() - set by wait_for_reply */
1098
1099                                 if (read_len < 0)
1100                                         continue;
1101                                 icmp_code = packet_ok(read_len, from_lsa, to, seq);
1102                                 /* Skip short packet */
1103                                 if (icmp_code == 0)
1104                                         continue;
1105
1106                                 if (!gotlastaddr
1107                                  || (memcmp(lastaddr, &from_lsa->u.sa, from_lsa->len) != 0)
1108                                 ) {
1109                                         print(read_len, &from_lsa->u.sa, to);
1110                                         memcpy(lastaddr, &from_lsa->u.sa, from_lsa->len);
1111                                         gotlastaddr = 1;
1112                                 }
1113
1114                                 print_delta_ms(t1, t2);
1115                                 ip = (struct ip *)recv_pkt;
1116
1117                                 if (from_lsa->u.sa.sa_family == AF_INET)
1118                                         if (op & OPT_TTL_FLAG)
1119                                                 printf(" (%d)", ip->ip_ttl);
1120
1121                                 /* time exceeded in transit */
1122                                 if (icmp_code == -1)
1123                                         break;
1124                                 icmp_code--;
1125                                 switch (icmp_code) {
1126 #if ENABLE_TRACEROUTE6
1127                                 case ICMP6_DST_UNREACH_NOPORT << 8:
1128                                         got_there = 1;
1129                                         break;
1130 #endif
1131                                 case ICMP_UNREACH_PORT:
1132                                         if (ip->ip_ttl <= 1)
1133                                                 printf(" !");
1134                                         got_there = 1;
1135                                         break;
1136
1137                                 case ICMP_UNREACH_NET:
1138 #if ENABLE_TRACEROUTE6 && (ICMP6_DST_UNREACH_NOROUTE != ICMP_UNREACH_NET)
1139                                 case ICMP6_DST_UNREACH_NOROUTE << 8:
1140 #endif
1141                                         printf(" !N");
1142                                         ++unreachable;
1143                                         break;
1144                                 case ICMP_UNREACH_HOST:
1145 #if ENABLE_TRACEROUTE6
1146                                 case ICMP6_DST_UNREACH_ADDR << 8:
1147 #endif
1148                                         printf(" !H");
1149                                         ++unreachable;
1150                                         break;
1151                                 case ICMP_UNREACH_PROTOCOL:
1152                                         printf(" !P");
1153                                         got_there = 1;
1154                                         break;
1155                                 case ICMP_UNREACH_NEEDFRAG:
1156                                         printf(" !F-%d", pmtu);
1157                                         ++unreachable;
1158                                         break;
1159                                 case ICMP_UNREACH_SRCFAIL:
1160 #if ENABLE_TRACEROUTE6
1161                                 case ICMP6_DST_UNREACH_ADMIN << 8:
1162 #endif
1163                                         printf(" !S");
1164                                         ++unreachable;
1165                                         break;
1166                                 case ICMP_UNREACH_FILTER_PROHIB:
1167                                 case ICMP_UNREACH_NET_PROHIB:   /* misuse */
1168                                         printf(" !A");
1169                                         ++unreachable;
1170                                         break;
1171                                 case ICMP_UNREACH_HOST_PROHIB:
1172                                         printf(" !C");
1173                                         ++unreachable;
1174                                         break;
1175                                 case ICMP_UNREACH_HOST_PRECEDENCE:
1176                                         printf(" !V");
1177                                         ++unreachable;
1178                                         break;
1179                                 case ICMP_UNREACH_PRECEDENCE_CUTOFF:
1180                                         printf(" !C");
1181                                         ++unreachable;
1182                                         break;
1183                                 case ICMP_UNREACH_NET_UNKNOWN:
1184                                 case ICMP_UNREACH_HOST_UNKNOWN:
1185                                         printf(" !U");
1186                                         ++unreachable;
1187                                         break;
1188                                 case ICMP_UNREACH_ISOLATED:
1189                                         printf(" !I");
1190                                         ++unreachable;
1191                                         break;
1192                                 case ICMP_UNREACH_TOSNET:
1193                                 case ICMP_UNREACH_TOSHOST:
1194                                         printf(" !T");
1195                                         ++unreachable;
1196                                         break;
1197                                 default:
1198                                         printf(" !<%d>", icmp_code);
1199                                         ++unreachable;
1200                                         break;
1201                                 }
1202                                 break;
1203                         } /* while (wait and read a packet) */
1204
1205                         /* there was no packet at all? */
1206                         if (read_len == 0)
1207                                 printf("  *");
1208                 } /* for (nprobes) */
1209
1210                 bb_putchar('\n');
1211                 if (got_there
1212                  || (unreachable > 0 && unreachable >= nprobes - 1)
1213                 ) {
1214                         break;
1215                 }
1216         }
1217
1218         return 0;
1219 }
1220
1221 int traceroute_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1222 int traceroute_main(int argc UNUSED_PARAM, char **argv)
1223 {
1224         return common_traceroute_main(0, argv);
1225 }
1226
1227 #if ENABLE_TRACEROUTE6
1228 int traceroute6_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1229 int traceroute6_main(int argc UNUSED_PARAM, char **argv)
1230 {
1231         return common_traceroute_main(OPT_IPV6, argv);
1232 }
1233 #endif