Magellan Linux

Annotation of /trunk/mkinitrd-magellan/busybox/networking/traceroute.c

Parent Directory Parent Directory | Revision Log Revision Log


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