aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/usage.h13
-rw-r--r--libbb/getopt_ulflags.c17
-rw-r--r--networking/Config.in22
-rw-r--r--networking/traceroute.c1546
4 files changed, 1242 insertions, 356 deletions
diff --git a/include/usage.h b/include/usage.h
index 9227025b2..36d43cb39 100644
--- a/include/usage.h
+++ b/include/usage.h
@@ -2921,12 +2921,16 @@
2921 "hello world\n" 2921 "hello world\n"
2922 2922
2923#define traceroute_trivial_usage \ 2923#define traceroute_trivial_usage \
2924 "[-dnrv] [-m max_ttl] [-p port#] [-q nqueries]\n" \ 2924 "[-FIldnrv] [-f 1st_ttl] [-m max_ttl] [-p port#] [-q nqueries]\n" \
2925 "\t[-s src_addr] [-t tos] [-w wait] host [data size]" 2925 "\t[-s src_addr] [-t tos] [-w wait] [-g gateway] [-i iface]\n" \
2926 "\t[-z pausemsecs] host [data size]"
2926#define traceroute_full_usage \ 2927#define traceroute_full_usage \
2927 "trace the route ip packets follow going to \"host\"\n" \ 2928 "trace the route ip packets follow going to \"host\"\n" \
2928 "Options:\n" \ 2929 "Options:\n" \
2929 "\t-d\tset SO_DEBUG options to socket\n" \ 2930 "\t-F\tSet the don't fragment bit\n" \
2931 "\t-I\tUse ICMP ECHO instead of UDP datagrams\n" \
2932 "\t-l\tDisplay the ttl value of the returned packet\n" \
2933 "\t-d\tSet SO_DEBUG options to socket\n" \
2930 "\t-n\tPrint hop addresses numerically rather than symbolically\n" \ 2934 "\t-n\tPrint hop addresses numerically rather than symbolically\n" \
2931 "\t-r\tBypass the normal routing tables and send directly to a host\n" \ 2935 "\t-r\tBypass the normal routing tables and send directly to a host\n" \
2932 "\t-v\tVerbose output\n" \ 2936 "\t-v\tVerbose output\n" \
@@ -2939,7 +2943,8 @@
2939 "\t-t tos\tSet the type-of-service in probe packets to the following value\n" \ 2943 "\t-t tos\tSet the type-of-service in probe packets to the following value\n" \
2940 "\t\t(default 0)\n" \ 2944 "\t\t(default 0)\n" \
2941 "\t-w wait\tSet the time (in seconds) to wait for a response to a probe\n" \ 2945 "\t-w wait\tSet the time (in seconds) to wait for a response to a probe\n" \
2942 "\t\t(default 3 sec.)" 2946 "\t\t(default 3 sec.)\n" \
2947 "\t-g\tSpecify a loose source route gateway (8 maximum)"
2943 2948
2944 2949
2945#define true_trivial_usage \ 2950#define true_trivial_usage \
diff --git a/libbb/getopt_ulflags.c b/libbb/getopt_ulflags.c
index 44c8e1a76..58077c55f 100644
--- a/libbb/getopt_ulflags.c
+++ b/libbb/getopt_ulflags.c
@@ -113,7 +113,8 @@ const char *bb_opt_complementally
113Special characters: 113Special characters:
114 114
115 "-" A dash between two options causes the second of the two 115 "-" A dash between two options causes the second of the two
116 to be unset (and ignored) if it is given on the command line. 116 to be unset (and ignored or triggered) if it is given on
117 the command line.
117 118
118 For example: 119 For example:
119 The du applet has the options "-s" and "-d depth". If 120 The du applet has the options "-s" and "-d depth". If
@@ -128,13 +129,15 @@ Special characters:
128 129
129 char *smax_print_depth; 130 char *smax_print_depth;
130 131
131 bb_opt_complementally = "s-d:d-s"; 132 bb_opt_complementally = "s-d:d-s:x-x";
132 opt = bb_getopt_ulflags(argc, argv, "sd:", &smax_print_depth); 133 opt = bb_getopt_ulflags(argc, argv, "sd:x", &smax_print_depth);
133 134
134 if (opt & 2) { 135 if (opt & 2) {
135 max_print_depth = bb_xgetularg10_bnd(smax_print_depth, 136 max_print_depth = bb_xgetularg10_bnd(smax_print_depth,
136 0, INT_MAX); 137 0, INT_MAX);
137 } 138 }
139 if(opt & 4)
140 printf("Detected odd -x usaging\n");
138 141
139 "~" A tilde between two options, or between an option and a group 142 "~" A tilde between two options, or between an option and a group
140 of options, means that they are mutually exclusive. Unlike 143 of options, means that they are mutually exclusive. Unlike
@@ -297,6 +300,8 @@ bb_getopt_ulflags (int argc, char **argv, const char *applet_opts, ...)
297 300
298 while ((c = getopt_long (argc, argv, applet_opts, 301 while ((c = getopt_long (argc, argv, applet_opts,
299 bb_applet_long_options, NULL)) > 0) { 302 bb_applet_long_options, NULL)) > 0) {
303 unsigned long trigger;
304
300 for (on_off = complementally; on_off->opt != c; on_off++) { 305 for (on_off = complementally; on_off->opt != c; on_off++) {
301 if(!on_off->opt) 306 if(!on_off->opt)
302 bb_show_usage (); 307 bb_show_usage ();
@@ -306,8 +311,10 @@ bb_getopt_ulflags (int argc, char **argv, const char *applet_opts, ...)
306 bb_show_usage (); 311 bb_show_usage ();
307 flags |= BB_GETOPT_ERROR; 312 flags |= BB_GETOPT_ERROR;
308 } 313 }
309 flags &= ~on_off->switch_off; 314 trigger = on_off->switch_on & on_off->switch_off;
310 flags |= on_off->switch_on; 315 flags &= ~(on_off->switch_off ^ trigger);
316 flags |= on_off->switch_on ^ trigger;
317 flags ^= trigger;
311 if(on_off->list_flg) { 318 if(on_off->list_flg) {
312 *(llist_t **)(on_off->optarg) = 319 *(llist_t **)(on_off->optarg) =
313 llist_add_to(*(llist_t **)(on_off->optarg), optarg); 320 llist_add_to(*(llist_t **)(on_off->optarg), optarg);
diff --git a/networking/Config.in b/networking/Config.in
index b6f8ee65d..671d84d26 100644
--- a/networking/Config.in
+++ b/networking/Config.in
@@ -28,7 +28,7 @@ config CONFIG_FAKEIDENTD
28 bool "fakeidentd" 28 bool "fakeidentd"
29 default n 29 default n
30 help 30 help
31 fakeidentd listens to the ident port and returns a set fake 31 fakeidentd listens to the ident port and returns a set fake
32 value whatever it gets. 32 value whatever it gets.
33 33
34config CONFIG_FTPGET 34config CONFIG_FTPGET
@@ -114,7 +114,7 @@ config CONFIG_FEATURE_HTTPD_CGI
114 depends on CONFIG_HTTPD 114 depends on CONFIG_HTTPD
115 help 115 help
116 This option allows scripts and executables to be invoked 116 This option allows scripts and executables to be invoked
117 when specific urls are requested. 117 when specific urls are requested.
118 118
119config CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV 119config CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV
120 bool " Support the REMOTE_PORT environment variable for CGI" 120 bool " Support the REMOTE_PORT environment variable for CGI"
@@ -419,7 +419,7 @@ config CONFIG_NAMEIF
419 File fields are separated by space or tab. 419 File fields are separated by space or tab.
420 File format: 420 File format:
421 # Comment 421 # Comment
422 new_interface_name XX:XX:XX:XX:XX:XX 422 new_interface_name XX:XX:XX:XX:XX:XX
423 423
424config CONFIG_NC 424config CONFIG_NC
425 bool "nc" 425 bool "nc"
@@ -615,6 +615,22 @@ config CONFIG_FEATURE_TRACEROUTE_VERBOSE
615 Add some verbosity to traceroute. This includes amongst other things 615 Add some verbosity to traceroute. This includes amongst other things
616 hostnames and ICMP response types. 616 hostnames and ICMP response types.
617 617
618config CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
619 bool " Enable loose source route"
620 default n
621 depends on CONFIG_TRACEROUTE
622 help
623 Add feature for can specify a loose source route gateway
624 (8 maximum).
625
626config CONFIG_FEATURE_TRACEROUTE_USE_ICMP
627 bool " Use ICMP instead of UDP"
628 default n
629 depends on CONFIG_TRACEROUTE
630 help
631 Add feature for can use ICMP ECHO instead of UDP datagrams.
632
633
618config CONFIG_VCONFIG 634config CONFIG_VCONFIG
619 bool "vconfig" 635 bool "vconfig"
620 default n 636 default n
diff --git a/networking/traceroute.c b/networking/traceroute.c
index 628b13492..15d55e79b 100644
--- a/networking/traceroute.c
+++ b/networking/traceroute.c
@@ -1,44 +1,181 @@
1/*- 1/*
2 * Copyright (c) 1990, 1993 2 * Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000
3 * The Regents of the University of California. All rights reserved. 3 * The Regents of the University of California. All rights reserved.
4 * 4 *
5 * This code is derived from software contributed to Berkeley by 5 * Busybox port by Vladimir Oleynik (C) 2005 <dzo@simtreas.ru>
6 * Van Jacobson.
7 * 6 *
8 * Special for busybox ported by Vladimir Oleynik <dzo@simtreas.ru> 2001
9 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions 8 * modification, are permitted provided that: (1) source code distributions
11 * are met: 9 * retain the above copyright notice and this paragraph in its entirety, (2)
12 * 1. Redistributions of source code must retain the above copyright 10 * distributions including binary code include the above copyright notice and
13 * notice, this list of conditions and the following disclaimer. 11 * this paragraph in its entirety in the documentation or other materials
14 * 2. Redistributions in binary form must reproduce the above copyright 12 * provided with the distribution, and (3) all advertising materials mentioning
15 * notice, this list of conditions and the following disclaimer in the 13 * features or use of this software display the following acknowledgement:
16 * documentation and/or other materials provided with the distribution. 14 * ``This product includes software developed by the University of California,
17 * 3. Neither the name of the University nor the names of its contributors 15 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
18 * may be used to endorse or promote products derived from this software 16 * the University nor the names of its contributors may be used to endorse
19 * without specific prior written permission. 17 * or promote products derived from this software without specific prior
20 * 18 * written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 19 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */ 22 */
33 23
24//#define version "1.4a12"
25
26
34/* 27/*
35 * traceroute host - trace the route ip packets follow going to "host". 28 * traceroute host - trace the route ip packets follow going to "host".
29 *
30 * Attempt to trace the route an ip packet would follow to some
31 * internet host. We find out intermediate hops by launching probe
32 * packets with a small ttl (time to live) then listening for an
33 * icmp "time exceeded" reply from a gateway. We start our probes
34 * with a ttl of one and increase by one until we get an icmp "port
35 * unreachable" (which means we got to "host") or hit a max (which
36 * defaults to 30 hops & can be changed with the -m flag). Three
37 * probes (change with -q flag) are sent at each ttl setting and a
38 * line is printed showing the ttl, address of the gateway and
39 * round trip time of each probe. If the probe answers come from
40 * different gateways, the address of each responding system will
41 * be printed. If there is no response within a 5 sec. timeout
42 * interval (changed with the -w flag), a "*" is printed for that
43 * probe.
44 *
45 * Probe packets are UDP format. We don't want the destination
46 * host to process them so the destination port is set to an
47 * unlikely value (if some clod on the destination is using that
48 * value, it can be changed with the -p flag).
49 *
50 * A sample use might be:
51 *
52 * [yak 71]% traceroute nis.nsf.net.
53 * traceroute to nis.nsf.net (35.1.1.48), 30 hops max, 56 byte packet
54 * 1 helios.ee.lbl.gov (128.3.112.1) 19 ms 19 ms 0 ms
55 * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms
56 * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms
57 * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 39 ms
58 * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 39 ms 39 ms 39 ms
59 * 6 128.32.197.4 (128.32.197.4) 40 ms 59 ms 59 ms
60 * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 59 ms
61 * 8 129.140.70.13 (129.140.70.13) 99 ms 99 ms 80 ms
62 * 9 129.140.71.6 (129.140.71.6) 139 ms 239 ms 319 ms
63 * 10 129.140.81.7 (129.140.81.7) 220 ms 199 ms 199 ms
64 * 11 nic.merit.edu (35.1.1.48) 239 ms 239 ms 239 ms
65 *
66 * Note that lines 2 & 3 are the same. This is due to a buggy
67 * kernel on the 2nd hop system -- lbl-csam.arpa -- that forwards
68 * packets with a zero ttl.
69 *
70 * A more interesting example is:
71 *
72 * [yak 72]% traceroute allspice.lcs.mit.edu.
73 * traceroute to allspice.lcs.mit.edu (18.26.0.115), 30 hops max
74 * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms
75 * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 19 ms 19 ms
76 * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 19 ms
77 * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 19 ms 39 ms 39 ms
78 * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 20 ms 39 ms 39 ms
79 * 6 128.32.197.4 (128.32.197.4) 59 ms 119 ms 39 ms
80 * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 39 ms
81 * 8 129.140.70.13 (129.140.70.13) 80 ms 79 ms 99 ms
82 * 9 129.140.71.6 (129.140.71.6) 139 ms 139 ms 159 ms
83 * 10 129.140.81.7 (129.140.81.7) 199 ms 180 ms 300 ms
84 * 11 129.140.72.17 (129.140.72.17) 300 ms 239 ms 239 ms
85 * 12 * * *
86 * 13 128.121.54.72 (128.121.54.72) 259 ms 499 ms 279 ms
87 * 14 * * *
88 * 15 * * *
89 * 16 * * *
90 * 17 * * *
91 * 18 ALLSPICE.LCS.MIT.EDU (18.26.0.115) 339 ms 279 ms 279 ms
92 *
93 * (I start to see why I'm having so much trouble with mail to
94 * MIT.) Note that the gateways 12, 14, 15, 16 & 17 hops away
95 * either don't send ICMP "time exceeded" messages or send them
96 * with a ttl too small to reach us. 14 - 17 are running the
97 * MIT C Gateway code that doesn't send "time exceeded"s. God
98 * only knows what's going on with 12.
99 *
100 * The silent gateway 12 in the above may be the result of a bug in
101 * the 4.[23]BSD network code (and its derivatives): 4.x (x <= 3)
102 * sends an unreachable message using whatever ttl remains in the
103 * original datagram. Since, for gateways, the remaining ttl is
104 * zero, the icmp "time exceeded" is guaranteed to not make it back
105 * to us. The behavior of this bug is slightly more interesting
106 * when it appears on the destination system:
107 *
108 * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms
109 * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 39 ms
110 * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 39 ms 19 ms
111 * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 19 ms
112 * 5 ccn-nerif35.Berkeley.EDU (128.32.168.35) 39 ms 39 ms 39 ms
113 * 6 csgw.Berkeley.EDU (128.32.133.254) 39 ms 59 ms 39 ms
114 * 7 * * *
115 * 8 * * *
116 * 9 * * *
117 * 10 * * *
118 * 11 * * *
119 * 12 * * *
120 * 13 rip.Berkeley.EDU (128.32.131.22) 59 ms ! 39 ms ! 39 ms !
121 *
122 * Notice that there are 12 "gateways" (13 is the final
123 * destination) and exactly the last half of them are "missing".
124 * What's really happening is that rip (a Sun-3 running Sun OS3.5)
125 * is using the ttl from our arriving datagram as the ttl in its
126 * icmp reply. So, the reply will time out on the return path
127 * (with no notice sent to anyone since icmp's aren't sent for
128 * icmp's) until we probe with a ttl that's at least twice the path
129 * length. I.e., rip is really only 7 hops away. A reply that
130 * returns with a ttl of 1 is a clue this problem exists.
131 * Traceroute prints a "!" after the time if the ttl is <= 1.
132 * Since vendors ship a lot of obsolete (DEC's Ultrix, Sun 3.x) or
133 * non-standard (HPUX) software, expect to see this problem
134 * frequently and/or take care picking the target host of your
135 * probes.
136 *
137 * Other possible annotations after the time are !H, !N, !P (got a host,
138 * network or protocol unreachable, respectively), !S or !F (source
139 * route failed or fragmentation needed -- neither of these should
140 * ever occur and the associated gateway is busted if you see one). If
141 * almost all the probes result in some kind of unreachable, traceroute
142 * will give up and exit.
143 *
36 * Notes 144 * Notes
37 * ----- 145 * -----
38 * This program must be run by root or be setuid. (I suggest that 146 * This program must be run by root or be setuid. (I suggest that
39 * you *don't* make it setuid -- casual use could result in a lot 147 * you *don't* make it setuid -- casual use could result in a lot
40 * of unnecessary traffic on our poor, congested nets.) 148 * of unnecessary traffic on our poor, congested nets.)
41 * 149 *
150 * This program requires a kernel mod that does not appear in any
151 * system available from Berkeley: A raw ip socket using proto
152 * IPPROTO_RAW must interpret the data sent as an ip datagram (as
153 * opposed to data to be wrapped in a ip datagram). See the README
154 * file that came with the source to this program for a description
155 * of the mods I made to /sys/netinet/raw_ip.c. Your mileage may
156 * vary. But, again, ANY 4.x (x < 4) BSD KERNEL WILL HAVE TO BE
157 * MODIFIED TO RUN THIS PROGRAM.
158 *
159 * The udp port usage may appear bizarre (well, ok, it is bizarre).
160 * The problem is that an icmp message only contains 8 bytes of
161 * data from the original datagram. 8 bytes is the size of a udp
162 * header so, if we want to associate replies with the original
163 * datagram, the necessary information must be encoded into the
164 * udp header (the ip id could be used but there's no way to
165 * interlock with the kernel's assignment of ip id's and, anyway,
166 * it would have taken a lot more kernel hacking to allow this
167 * code to set the ip id). So, to allow two or more users to
168 * use traceroute simultaneously, we use this task's pid as the
169 * source port (the high bit is set to move the port number out
170 * of the "likely" range). To keep track of which probe is being
171 * replied to (so times and/or hop counts don't get confused by a
172 * reply that was delayed in transit), we increment the destination
173 * port number before each probe.
174 *
175 * Don't use this as a coding example. I was trying to find a
176 * routing problem and this code sort-of popped out after 48 hours
177 * without sleep. I was amazed it ever compiled, much less ran.
178 *
42 * I stole the idea for this program from Steve Deering. Since 179 * I stole the idea for this program from Steve Deering. Since
43 * the first release, I've learned that had I attended the right 180 * the first release, I've learned that had I attended the right
44 * IETF working group meetings, I also could have stolen it from Guy 181 * IETF working group meetings, I also could have stolen it from Guy
@@ -54,169 +191,537 @@
54 * back to yourself. Unfortunately, SO many gateways botch source 191 * back to yourself. Unfortunately, SO many gateways botch source
55 * routing, the thing is almost worthless. Maybe one day... 192 * routing, the thing is almost worthless. Maybe one day...
56 * 193 *
57 * -- Van Jacobson (van@helios.ee.lbl.gov) 194 * -- Van Jacobson (van@ee.lbl.gov)
58 * Tue Dec 20 03:50:13 PST 1988 195 * Tue Dec 20 03:50:13 PST 1988
59 */ 196 */
60 197
61#undef CONFIG_FEATURE_TRACEROUTE_VERBOSE 198#undef CONFIG_FEATURE_TRACEROUTE_VERBOSE
62//#define CONFIG_FEATURE_TRACEROUTE_VERBOSE 199//#define CONFIG_FEATURE_TRACEROUTE_VERBOSE
63#undef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG /* not in documentation man */ 200#undef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG /* not in documentation man */
201#undef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
202//#define CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
203#undef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
204//#define CONFIG_FEATURE_TRACEROUTE_USE_ICMP
64 205
65#include <stdio.h>
66#include <errno.h> 206#include <errno.h>
207#include <memory.h>
208#include <stdio.h>
67#include <stdlib.h> 209#include <stdlib.h>
68#include <string.h> 210#include <string.h>
69#include <unistd.h> 211#include <unistd.h>
70#include <sys/time.h> 212#include <fcntl.h>
71#include "inet_common.h" 213#include <malloc.h>
72#include <netdb.h> 214#include <netdb.h>
73#include <endian.h> 215#include <endian.h>
216#include <getopt.h>
217
218#include <sys/param.h>
219#include <sys/file.h>
220#include <sys/ioctl.h>
221#include <sys/socket.h>
222#include <sys/time.h> /* concession to AIX */
223#include <sys/select.h>
224#include "inet_common.h"
225
226#include <net/if.h>
227#include <netinet/in.h>
228#include <arpa/inet.h>
74#include <netinet/udp.h> 229#include <netinet/udp.h>
75#include <netinet/ip.h> 230#include <netinet/ip.h>
76#include <netinet/ip_icmp.h> 231#include <netinet/ip_icmp.h>
77 232
233#include "busybox.h"
78 234
79#define MAXPACKET 65535 /* max ip packet size */
80#ifndef MAXHOSTNAMELEN
81#define MAXHOSTNAMELEN 64
82#endif
83 235
84/* 236/*
85 * format of a (udp) probe packet. 237 * Definitions for internet protocol version 4.
238 * Per RFC 791, September 1981.
86 */ 239 */
87struct opacket { 240#define IPVERSION 4
88 struct ip ip; 241
89 struct udphdr udp; 242/*
90 u_char seq; /* sequence number of this packet */ 243 * Overlay for ip header used by other protocols (tcp, udp).
91 u_char ttl; /* ttl packet left with */ 244 */
92 struct timeval tv; /* time packet left */ 245struct ipovly {
246 u_char ih_x1[9]; /* (unused) */
247 u_char ih_pr; /* protocol */
248 short ih_len; /* protocol length */
249 struct in_addr ih_src; /* source internet address */
250 struct in_addr ih_dst; /* destination internet address */
93}; 251};
94 252
95/* 253/*
96 * Definitions for internet protocol version 4. 254 * UDP kernel structures and variables.
97 * Per RFC 791, September 1981.
98 */ 255 */
99#define IPVERSION 4 256struct udpiphdr {
257 struct ipovly ui_i; /* overlaid ip structure */
258 struct udphdr ui_u; /* udp header */
259};
260#define ui_next ui_i.ih_next
261#define ui_prev ui_i.ih_prev
262#define ui_x1 ui_i.ih_x1
263#define ui_pr ui_i.ih_pr
264#define ui_len ui_i.ih_len
265#define ui_src ui_i.ih_src
266#define ui_dst ui_i.ih_dst
267#define ui_sport ui_u.uh_sport
268#define ui_dport ui_u.uh_dport
269#define ui_ulen ui_u.uh_ulen
270#define ui_sum ui_u.uh_sum
100 271
101 272
102#include "busybox.h" 273/* Host name and address list */
274struct hostinfo {
275 char *name;
276 int n;
277 u_int32_t *addrs;
278};
279
280/* Data section of the probe packet */
281struct outdata {
282 u_char seq; /* sequence number of this packet */
283 u_char ttl; /* ttl packet left with */
284 struct timeval tv __attribute__((packed)); /* time packet left */
285};
286
287struct IFADDRLIST {
288 u_int32_t addr;
289 char device[sizeof(struct ifreq)];
290};
291
292
293static const char route[] = "/proc/net/route";
103 294
104 /* last inbound (icmp) packet */ 295/* last inbound (icmp) packet */
105static u_char packet[512] __attribute__ ((aligned)); 296static u_char packet[512] __attribute__((align (32)));
106static struct opacket *outpacket; /* last output (udp) packet */ 297
298static struct ip *outip; /* last output (udp) packet */
299static struct udphdr *outudp; /* last output (udp) packet */
300static struct outdata *outdata; /* last output (udp) packet */
301
302#ifdef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
303static struct icmp *outicmp; /* last output (icmp) packet */
304#endif
305
306#ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
307/* Maximum number of gateways (include room for one noop) */
308#define NGATEWAYS ((int)((MAX_IPOPTLEN - IPOPT_MINOFF - 1) / sizeof(u_int32_t)))
309/* loose source route gateway list (including room for final destination) */
310static u_int32_t gwlist[NGATEWAYS + 1];
311#endif
107 312
108static int s; /* receive (icmp) socket file descriptor */ 313static int s; /* receive (icmp) socket file descriptor */
109static int sndsock; /* send (udp) socket file descriptor */ 314static int sndsock; /* send (udp/icmp) socket file descriptor */
110 315
111static struct sockaddr whereto; /* Who to try to reach */ 316static struct sockaddr_storage whereto; /* Who to try to reach */
112static int datalen; /* How much data */ 317static struct sockaddr_storage wherefrom; /* Who we are */
318static int packlen; /* total length of packet */
319static int minpacket; /* min ip packet size */
320static int maxpacket = 32 * 1024; /* max ip packet size */
321static int pmtu; /* Path MTU Discovery (RFC1191) */
113 322
114static char *hostname; 323static char *hostname;
324static const char devnull[] = "/dev/null";
115 325
116static int max_ttl = 30;
117static u_short ident; 326static u_short ident;
118static u_short port = 32768+666; /* start udp dest port # for probe packets */ 327static u_short port = 32768 + 666; /* start udp dest port # for probe packets */
119 328
329static int waittime = 5; /* time to wait for response (in seconds) */
330static int nflag; /* print addresses numerically */
331static int doipcksum = 1; /* calculate ip checksums by default */
332
333#ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
334static int optlen; /* length of ip options */
335#else
336#define optlen 0
337#endif
338
339#ifdef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
340static int useicmp; /* use icmp echo instead of udp packets */
341#endif
120#ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE 342#ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
121static int verbose; 343static int verbose;
122#endif 344#endif
123static int waittime = 5; /* time to wait for response (in seconds) */
124static int nflag; /* print addresses numerically */
125 345
126/* 346/*
127 * Construct an Internet address representation. 347 * Return the interface list
128 * If the nflag has been supplied, give
129 * numeric value, otherwise try for symbolic name.
130 */ 348 */
131static inline void 349static int
132inetname(struct sockaddr_in *from) 350ifaddrlist(struct IFADDRLIST **ipaddrp)
133{ 351{
134 char *cp; 352 int fd, nipaddr;
135 static char domain[MAXHOSTNAMELEN + 1]; 353#ifdef HAVE_SOCKADDR_SA_LEN
136 char name[MAXHOSTNAMELEN + 1]; 354 int n;
137 static int first = 1; 355#endif
138 const char *ina; 356 struct ifreq *ifrp, *ifend, *ifnext;
357 struct sockaddr_in *addr_sin;
358 struct IFADDRLIST *al;
359 struct ifconf ifc;
360 struct ifreq ibuf[(32 * 1024) / sizeof(struct ifreq)], ifr;
361 struct IFADDRLIST *st_ifaddrlist;
139 362
140 if (first && !nflag) { 363 fd = socket(AF_INET, SOCK_DGRAM, 0);
141 first = 0; 364 if (fd < 0)
142 if (getdomainname(domain, MAXHOSTNAMELEN) != 0) 365 bb_perror_msg_and_die("socket");
143 domain[0] = 0; 366
367 ifc.ifc_len = sizeof(ibuf);
368 ifc.ifc_buf = (caddr_t)ibuf;
369
370 if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 ||
371 ifc.ifc_len < sizeof(struct ifreq)) {
372 if (errno == EINVAL)
373 bb_error_msg_and_die(
374 "SIOCGIFCONF: ifreq struct too small (%d bytes)",
375 sizeof(ibuf));
376 else
377 bb_perror_msg_and_die("SIOCGIFCONF");
144 } 378 }
145 cp = 0; 379 ifrp = ibuf;
146 if (!nflag && from->sin_addr.s_addr != INADDR_ANY) { 380 ifend = (struct ifreq *)((char *)ibuf + ifc.ifc_len);
147 if(INET_rresolve(name, sizeof(name), from, 0x4000, 0xffffffff) >= 0) { 381
148 if ((cp = strchr(name, '.')) && 382 nipaddr = 1 + (ifc.ifc_len / sizeof(struct ifreq));
149 !strcmp(cp + 1, domain)) 383 st_ifaddrlist = xcalloc(nipaddr, sizeof(struct IFADDRLIST));
150 *cp = 0; 384 al = st_ifaddrlist;
151 cp = (char *)name; 385 nipaddr = 0;
386
387 for (; ifrp < ifend; ifrp = ifnext) {
388#ifdef HAVE_SOCKADDR_SA_LEN
389 n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
390 if (n < sizeof(*ifrp))
391 ifnext = ifrp + 1;
392 else
393 ifnext = (struct ifreq *)((char *)ifrp + n);
394 if (ifrp->ifr_addr.sa_family != AF_INET)
395 continue;
396#else
397 ifnext = ifrp + 1;
398#endif
399 /*
400 * Need a template to preserve address info that is
401 * used below to locate the next entry. (Otherwise,
402 * SIOCGIFFLAGS stomps over it because the requests
403 * are returned in a union.)
404 */
405 strncpy(ifr.ifr_name, ifrp->ifr_name, sizeof(ifr.ifr_name));
406 if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifr) < 0) {
407 if (errno == ENXIO)
408 continue;
409 bb_perror_msg_and_die("SIOCGIFFLAGS: %.*s",
410 (int)sizeof(ifr.ifr_name), ifr.ifr_name);
152 } 411 }
412
413 /* Must be up */
414 if ((ifr.ifr_flags & IFF_UP) == 0)
415 continue;
416
417 safe_strncpy(al->device, ifr.ifr_name, sizeof(ifr.ifr_name) + 1);
418#ifdef sun
419 /* Ignore sun virtual interfaces */
420 if (strchr(al->device, ':') != NULL)
421 continue;
422#endif
423 if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0)
424 bb_perror_msg_and_die("SIOCGIFADDR: %s", al->device);
425
426 addr_sin = (struct sockaddr_in *)&ifr.ifr_addr;
427 al->addr = addr_sin->sin_addr.s_addr;
428 ++al;
429 ++nipaddr;
153 } 430 }
154 ina = inet_ntoa(from->sin_addr); 431 if(nipaddr == 0)
155 if (nflag) 432 bb_error_msg_and_die ("Can't find any network interfaces");
156 printf(" %s", ina); 433 (void)close(fd);
157 else 434
158 printf(" %s (%s)", (cp ? cp : ina), ina); 435 *ipaddrp = st_ifaddrlist;
436 return nipaddr;
159} 437}
160 438
161static inline void 439
162print(u_char *buf, int cc, struct sockaddr_in *from) 440static void
441setsin(struct sockaddr_in *addr_sin, u_int32_t addr)
163{ 442{
164 struct ip *ip; 443 memset(addr_sin, 0, sizeof(*addr_sin));
165 int hlen; 444#ifdef HAVE_SOCKADDR_SA_LEN
445 addr_sin->sin_len = sizeof(*addr_sin);
446#endif
447 addr_sin->sin_family = AF_INET;
448 addr_sin->sin_addr.s_addr = addr;
449}
166 450
167 ip = (struct ip *) buf;
168 hlen = ip->ip_hl << 2;
169 cc -= hlen;
170 451
171 inetname(from); 452/*
172#ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE 453 * Return the source address for the given destination address
173 if (verbose) 454 */
174 printf (" %d bytes to %s", cc, inet_ntoa (ip->ip_dst)); 455static void
175#endif 456findsaddr(const struct sockaddr_in *to, struct sockaddr_in *from)
457{
458 int i, n;
459 FILE *f;
460 u_int32_t mask;
461 u_int32_t dest, tmask;
462 struct IFADDRLIST *al;
463 char buf[256], tdevice[256], device[256];
464
465 f = bb_xfopen(route, "r");
466
467 /* Find the appropriate interface */
468 n = 0;
469 mask = 0;
470 device[0] = '\0';
471 while (fgets(buf, sizeof(buf), f) != NULL) {
472 ++n;
473 if (n == 1 && strncmp(buf, "Iface", 5) == 0)
474 continue;
475 if ((i = sscanf(buf, "%255s %x %*s %*s %*s %*s %*s %x",
476 tdevice, &dest, &tmask)) != 3)
477 bb_error_msg_and_die ("junk in buffer");
478 if ((to->sin_addr.s_addr & tmask) == dest &&
479 (tmask > mask || mask == 0)) {
480 mask = tmask;
481 strcpy(device, tdevice);
482 }
483 }
484 fclose(f);
485
486 if (device[0] == '\0')
487 bb_error_msg_and_die ("Can't find interface");
488
489 /* Get the interface address list */
490 n = ifaddrlist(&al);
491
492 /* Find our appropriate source address */
493 for (i = n; i > 0; --i, ++al)
494 if (strcmp(device, al->device) == 0)
495 break;
496 if (i <= 0)
497 bb_error_msg_and_die("Can't find interface %s", device);
498
499 setsin(from, al->addr);
176} 500}
177 501
178static inline double 502/*
179deltaT(struct timeval *t1p, struct timeval *t2p) 503"Usage: %s [-dFIlnrvx] [-g gateway] [-i iface] [-f first_ttl]\n"
504"\t[-m max_ttl] [ -p port] [-q nqueries] [-s src_addr] [-t tos]\n"
505"\t[-w waittime] [-z pausemsecs] host [packetlen]"
506
507*/
508
509/* String to value with optional min and max. Handles decimal and hex. */
510static int
511str2val(const char *str, const char *what, int mi, int ma)
180{ 512{
181 double dt; 513 const char *cp;
514 int val;
515 char *ep;
182 516
183 dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 + 517 if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) {
184 (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0; 518 cp = str + 2;
185 return (dt); 519 val = (int)strtol(cp, &ep, 16);
520 } else
521 val = (int)strtol(str, &ep, 10);
522 if (*ep != '\0') {
523 bb_error_msg_and_die("\"%s\" bad value for %s \n", str, what);
524 }
525 if (val < mi && mi >= 0) {
526 if (mi == 0)
527 bb_error_msg_and_die("%s must be >= %d\n", what, mi);
528 else
529 bb_error_msg_and_die("%s must be > %d\n", what, mi - 1);
530 }
531 if (val > ma && ma >= 0)
532 bb_error_msg_and_die("%s must be <= %d\n", what, ma);
533 return val;
186} 534}
187 535
188static inline int 536
189wait_for_reply(int sock, struct sockaddr_in *from, int reset_timer) 537/*
538 * Subtract 2 timeval structs: out = out - in.
539 * Out is assumed to be >= in.
540 */
541static inline void
542tvsub(struct timeval *out, struct timeval *in)
543{
544
545 if ((out->tv_usec -= in->tv_usec) < 0) {
546 --out->tv_sec;
547 out->tv_usec += 1000000;
548 }
549 out->tv_sec -= in->tv_sec;
550}
551
552static int
553wait_for_reply(int sock, struct sockaddr_in *fromp, const struct timeval *tp)
190{ 554{
191 fd_set fds; 555 fd_set fds;
192 static struct timeval wait; 556 struct timeval now, wait;
557 struct timezone tz;
193 int cc = 0; 558 int cc = 0;
194 int fromlen = sizeof (*from); 559 socklen_t fromlen = sizeof(*fromp);
195 560
196 FD_ZERO(&fds); 561 FD_ZERO(&fds);
197 FD_SET(sock, &fds); 562 FD_SET(sock, &fds);
198 if (reset_timer) { 563
199 /* 564 wait.tv_sec = tp->tv_sec + waittime;
200 * traceroute could hang if someone else has a ping 565 wait.tv_usec = tp->tv_usec;
201 * running and our ICMP reply gets dropped but we don't 566 (void)gettimeofday(&now, &tz);
202 * realize it because we keep waking up to handle those 567 tvsub(&wait, &now);
203 * other ICMP packets that keep coming in. To fix this, 568
204 * "reset_timer" will only be true if the last packet that 569 if (select(sock + 1, &fds, NULL, NULL, &wait) > 0)
205 * came in was for us or if this is the first time we're 570 cc = recvfrom(sock, (char *)packet, sizeof(packet), 0,
206 * waiting for a reply since sending out a probe. Note 571 (struct sockaddr *)fromp, &fromlen);
207 * that this takes advantage of the select() feature on 572
208 * Linux where the remaining timeout is written to the 573 return cc;
209 * struct timeval area. 574}
210 */ 575
211 wait.tv_sec = waittime; 576/*
212 wait.tv_usec = 0; 577 * Checksum routine for Internet Protocol family headers (C Version)
578 */
579static u_short
580in_cksum(u_short *addr, int len)
581{
582 int nleft = len;
583 u_short *w = addr;
584 u_short answer;
585 int sum = 0;
586
587 /*
588 * Our algorithm is simple, using a 32 bit accumulator (sum),
589 * we add sequential 16 bit words to it, and at the end, fold
590 * back all the carry bits from the top 16 bits into the lower
591 * 16 bits.
592 */
593 while (nleft > 1) {
594 sum += *w++;
595 nleft -= 2;
596 }
597
598 /* mop up an odd byte, if necessary */
599 if (nleft == 1)
600 sum += *(u_char *)w;
601
602 /*
603 * add back carry outs from top 16 bits to low 16 bits
604 */
605 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
606 sum += (sum >> 16); /* add carry */
607 answer = ~sum; /* truncate to 16 bits */
608 return answer;
609}
610
611
612static void
613send_probe(int seq, int ttl, struct timeval *tp)
614{
615 int cc;
616 struct udpiphdr *ui, *oui;
617 struct ip tip;
618
619 outip->ip_ttl = ttl;
620 outip->ip_id = htons(ident + seq);
621
622 /*
623 * In most cases, the kernel will recalculate the ip checksum.
624 * But we must do it anyway so that the udp checksum comes out
625 * right.
626 */
627 if (doipcksum) {
628 outip->ip_sum =
629 in_cksum((u_short *)outip, sizeof(*outip) + optlen);
630 if (outip->ip_sum == 0)
631 outip->ip_sum = 0xffff;
632 }
633
634 /* Payload */
635 outdata->seq = seq;
636 outdata->ttl = ttl;
637 memcpy(&outdata->tv, tp, sizeof(outdata->tv));
638
639#ifdef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
640 if (useicmp)
641 outicmp->icmp_seq = htons(seq);
642 else
643#endif
644 outudp->dest = htons(port + seq);
645
646#ifdef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
647 if (useicmp) {
648 /* Always calculate checksum for icmp packets */
649 outicmp->icmp_cksum = 0;
650 outicmp->icmp_cksum = in_cksum((u_short *)outicmp,
651 packlen - (sizeof(*outip) + optlen));
652 if (outicmp->icmp_cksum == 0)
653 outicmp->icmp_cksum = 0xffff;
654 } else
655#endif
656 if (doipcksum) {
657 /* Checksum (we must save and restore ip header) */
658 tip = *outip;
659 ui = (struct udpiphdr *)outip;
660 oui = (struct udpiphdr *)&tip;
661 /* Easier to zero and put back things that are ok */
662 memset((char *)ui, 0, sizeof(ui->ui_i));
663 ui->ui_src = oui->ui_src;
664 ui->ui_dst = oui->ui_dst;
665 ui->ui_pr = oui->ui_pr;
666 ui->ui_len = outudp->len;
667 outudp->check = 0;
668 outudp->check = in_cksum((u_short *)ui, packlen);
669 if (outudp->check == 0)
670 outudp->check = 0xffff;
671 *outip = tip;
672 }
673
674#ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
675 /* XXX undocumented debugging hack */
676 if (verbose > 1) {
677 const u_short *sp;
678 int nshorts, i;
679
680 sp = (u_short *)outip;
681 nshorts = (u_int)packlen / sizeof(u_short);
682 i = 0;
683 printf("[ %d bytes", packlen);
684 while (--nshorts >= 0) {
685 if ((i++ % 8) == 0)
686 printf("\n\t");
687 printf(" %04x", ntohs(*sp));
688 sp++;
689 }
690 if (packlen & 1) {
691 if ((i % 8) == 0)
692 printf("\n\t");
693 printf(" %02x", *(u_char *)sp);
694 }
695 printf("]\n");
696 }
697#endif
698
699#if !defined(IP_HDRINCL) && defined(IP_TTL)
700 if (setsockopt(sndsock, IPPROTO_IP, IP_TTL,
701 (char *)&ttl, sizeof(ttl)) < 0) {
702 bb_perror_msg_and_die("setsockopt ttl %d", ttl);
703 }
704#endif
705
706 cc = sendto(sndsock, (char *)outip,
707 packlen, 0, (struct sockaddr *)&whereto, sizeof(whereto));
708 if (cc < 0 || cc != packlen) {
709 if (cc < 0)
710 bb_perror_msg_and_die("sendto");
711 printf("%s: wrote %s %d chars, ret=%d\n",
712 bb_applet_name, hostname, packlen, cc);
713 (void)fflush(stdout);
213 } 714 }
715}
214 716
215 if (select(sock+1, &fds, (fd_set *)0, (fd_set *)0, &wait) > 0) 717static inline double
216 cc=recvfrom(s, (char *)packet, sizeof(packet), 0, 718deltaT(struct timeval *t1p, struct timeval *t2p)
217 (struct sockaddr *)from, &fromlen); 719{
720 double dt;
218 721
219 return(cc); 722 dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
723 (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
724 return dt;
220} 725}
221 726
222#ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE 727#ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
@@ -229,19 +734,19 @@ pr_type(u_char t)
229 static const char * const ttab[] = { 734 static const char * const ttab[] = {
230 "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable", 735 "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable",
231 "Source Quench", "Redirect", "ICMP 6", "ICMP 7", 736 "Source Quench", "Redirect", "ICMP 6", "ICMP 7",
232 "Echo", "ICMP 9", "ICMP 10", "Time Exceeded", 737 "Echo", "Router Advert", "Router Solicit", "Time Exceeded",
233 "Param Problem", "Timestamp", "Timestamp Reply", "Info Request", 738 "Param Problem", "Timestamp", "Timestamp Reply", "Info Request",
234 "Info Reply" 739 "Info Reply", "Mask Request", "Mask Reply"
235 }; 740 };
236 741
237 if(t > 16) 742 if (t > 18)
238 return("OUT-OF-RANGE"); 743 return "OUT-OF-RANGE";
239 744
240 return(ttab[t]); 745 return ttab[t];
241} 746}
242#endif 747#endif
243 748
244static inline int 749static int
245packet_ok(u_char *buf, int cc, struct sockaddr_in *from, int seq) 750packet_ok(u_char *buf, int cc, struct sockaddr_in *from, int seq)
246{ 751{
247 struct icmp *icp; 752 struct icmp *icp;
@@ -257,293 +762,646 @@ packet_ok(u_char *buf, int cc, struct sockaddr_in *from, int seq)
257 printf("packet too short (%d bytes) from %s\n", cc, 762 printf("packet too short (%d bytes) from %s\n", cc,
258 inet_ntoa(from->sin_addr)); 763 inet_ntoa(from->sin_addr));
259#endif 764#endif
260 return (0); 765 return 0;
261 } 766 }
262 cc -= hlen; 767 cc -= hlen;
263 icp = (struct icmp *)(buf + hlen); 768 icp = (struct icmp *)(buf + hlen);
264 type = icp->icmp_type; code = icp->icmp_code; 769 type = icp->icmp_type;
770 code = icp->icmp_code;
771 /* Path MTU Discovery (RFC1191) */
772 if (code != ICMP_UNREACH_NEEDFRAG)
773 pmtu = 0;
774 else {
775 pmtu = ntohs(icp->icmp_nextmtu);
776 }
265 if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) || 777 if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
266 type == ICMP_UNREACH) { 778 type == ICMP_UNREACH || type == ICMP_ECHOREPLY) {
267 struct ip *hip; 779 struct ip *hip;
268 struct udphdr *up; 780 struct udphdr *up;
269 781
270 hip = &icp->icmp_ip; 782 hip = &icp->icmp_ip;
271 hlen = hip->ip_hl << 2; 783 hlen = hip->ip_hl << 2;
272 up = (struct udphdr *)((u_char *)hip + hlen); 784#ifdef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
273 if (hlen + 12 <= cc && hip->ip_p == IPPROTO_UDP && 785 if (useicmp) {
274 up->source == htons(ident) && 786 struct icmp *hicmp;
275 up->dest == htons(port+seq)) 787
276 return (type == ICMP_TIMXCEED? -1 : code+1); 788 /* XXX */
789 if (type == ICMP_ECHOREPLY &&
790 icp->icmp_id == htons(ident) &&
791 icp->icmp_seq == htons(seq))
792 return -2;
793
794 hicmp = (struct icmp *)((u_char *)hip + hlen);
795 /* XXX 8 is a magic number */
796 if (hlen + 8 <= cc &&
797 hip->ip_p == IPPROTO_ICMP &&
798 hicmp->icmp_id == htons(ident) &&
799 hicmp->icmp_seq == htons(seq))
800 return (type == ICMP_TIMXCEED ? -1 : code + 1);
801 } else
802#endif
803 {
804 up = (struct udphdr *)((u_char *)hip + hlen);
805 /* XXX 8 is a magic number */
806 if (hlen + 12 <= cc &&
807 hip->ip_p == IPPROTO_UDP &&
808 up->source == htons(ident) &&
809 up->dest == htons(port + seq))
810 return (type == ICMP_TIMXCEED ? -1 : code + 1);
811 }
277 } 812 }
278#ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE 813#ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
279 if (verbose) { 814 if (verbose) {
280 int i; 815 int i;
281 u_long *lp = (u_long *)&icp->icmp_ip; 816 u_int32_t *lp = (u_int32_t *)&icp->icmp_ip;
282 817
283 printf("\n%d bytes from %s to %s: icmp type %d (%s) code %d\n", 818 printf("\n%d bytes from %s to "
284 cc, inet_ntoa(from->sin_addr), inet_ntoa(ip->ip_dst), 819 "%s: icmp type %d (%s) code %d\n",
285 type, pr_type(type), icp->icmp_code); 820 cc, inet_ntoa(from->sin_addr),
286 for (i = 4; i < cc ; i += sizeof(long)) 821 inet_ntoa(ip->ip_dst), type, pr_type(type), icp->icmp_code);
287 printf("%2d: x%8.8lx\n", i, *lp++); 822 for (i = 4; i < cc ; i += sizeof(*lp))
823 printf("%2d: x%8.8x\n", i, *lp++);
288 } 824 }
289#endif 825#endif
290 return(0); 826 return 0;
291} 827}
292 828
293static void /* not inline */ 829
294send_probe(int seq, int ttl) 830/*
831 * Construct an Internet address representation.
832 * If the nflag has been supplied, give
833 * numeric value, otherwise try for symbolic name.
834 */
835static inline void
836inetname(struct sockaddr_in *from)
295{ 837{
296 struct opacket *op = outpacket; 838 const char *n = NULL;
297 struct ip *ip = &op->ip; 839 const char *ina;
298 struct udphdr *up = &op->udp; 840 char name[257];
299 int i;
300 struct timezone tz;
301 841
302 ip->ip_off = 0; 842 if (!nflag && from->sin_addr.s_addr != INADDR_ANY) {
303 ip->ip_hl = sizeof(*ip) >> 2; 843 if(INET_rresolve(name, sizeof(name), from, 0x4000, 0xffffffff) >= 0)
304 ip->ip_p = IPPROTO_UDP; 844 n = name;
305 ip->ip_len = datalen;
306 ip->ip_ttl = ttl;
307 ip->ip_v = IPVERSION;
308 ip->ip_id = htons(ident+seq);
309
310 up->source = htons(ident);
311 up->dest = htons(port+seq);
312 up->len = htons((u_short)(datalen - sizeof(struct ip)));
313 up->check = 0;
314
315 op->seq = seq;
316 op->ttl = ttl;
317 (void) gettimeofday(&op->tv, &tz);
318
319 i = sendto(sndsock, (char *)outpacket, datalen, 0, &whereto,
320 sizeof(struct sockaddr));
321 if (i < 0 || i != datalen) {
322 if (i<0)
323 perror("sendto");
324 printf("traceroute: wrote %s %d chars, ret=%d\n", hostname,
325 datalen, i);
326 (void) fflush(stdout);
327 } 845 }
846 ina = inet_ntoa(from->sin_addr);
847 if (nflag)
848 printf(" %s", ina);
849 else
850 printf(" %s (%s)", (n ? n : ina), ina);
328} 851}
329 852
853static inline void
854print(u_char *buf, int cc, struct sockaddr_in *from)
855{
856 struct ip *ip;
857 int hlen;
858
859 ip = (struct ip *) buf;
860 hlen = ip->ip_hl << 2;
861 cc -= hlen;
330 862
331int 863 inetname(from);
332#ifndef CONFIG_TRACEROUTE 864#ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
333main(int argc, char *argv[]) 865 if (verbose)
334#else 866 printf(" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
335traceroute_main(int argc, char *argv[])
336#endif 867#endif
868}
869
870
871static struct hostinfo *
872gethostinfo(const char *host)
337{ 873{
338 extern char *optarg; 874 int n;
339 extern int optind;
340 struct hostent *hp; 875 struct hostent *hp;
341 struct sockaddr_in from, *to; 876 struct hostinfo *hi;
342 int ch, i, on, probe, seq, tos, ttl; 877 char **p;
878 u_int32_t addr, *ap;
879
880 hi = xcalloc(1, sizeof(*hi));
881 addr = inet_addr(host);
882 if ((int32_t)addr != -1) {
883 hi->name = bb_xstrdup(host);
884 hi->n = 1;
885 hi->addrs = xcalloc(1, sizeof(hi->addrs[0]));
886 hi->addrs[0] = addr;
887 return hi;
888 }
889
890 hp = xgethostbyname(host);
891 if (hp->h_addrtype != AF_INET || hp->h_length != 4)
892 bb_perror_msg_and_die("bad host %s", host);
893 hi->name = bb_xstrdup(hp->h_name);
894 for (n = 0, p = hp->h_addr_list; *p != NULL; ++n, ++p)
895 continue;
896 hi->n = n;
897 hi->addrs = xcalloc(n, sizeof(hi->addrs[0]));
898 for (ap = hi->addrs, p = hp->h_addr_list; *p != NULL; ++ap, ++p)
899 memcpy(ap, *p, sizeof(*ap));
900 return hi;
901}
902
903static void
904freehostinfo(struct hostinfo *hi)
905{
906 if (hi->name != NULL) {
907 free(hi->name);
908 hi->name = NULL;
909 }
910 free((char *)hi->addrs);
911 free((char *)hi);
912}
913
914#ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
915static void
916getaddr(u_int32_t *ap, const char *host)
917{
918 struct hostinfo *hi;
919
920 hi = gethostinfo(host);
921 *ap = hi->addrs[0];
922 freehostinfo(hi);
923}
924#endif
925
343 926
344 int options = 0; /* socket options */ 927int
345 char *source = 0; 928traceroute_main(int argc, char *argv[])
929{
930 int code, n;
931 char *cp;
932 u_char *outp;
933 u_int32_t *ap;
934 struct sockaddr_in *from = (struct sockaddr_in *)&wherefrom;
935 struct sockaddr_in *to = (struct sockaddr_in *)&whereto;
936 struct hostinfo *hi;
937 int on = 1;
938 struct protoent *pe;
939 int ttl, probe, i;
940 int seq = 0;
941 int tos = 0;
942 char *tos_str = NULL;
943 char *source = NULL;
944 unsigned long op;
945
946#ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
947 int lsrr = 0;
948#endif
949 u_short off = 0;
950 struct IFADDRLIST *al;
951 int uid = getuid();
952 char *device = NULL;
953 int max_ttl = 30;
954 char *max_ttl_str = NULL;
955 char *port_str = NULL;
346 int nprobes = 3; 956 int nprobes = 3;
957 char *nprobes_str = NULL;
958 char *waittime_str = NULL;
959 u_int pausemsecs = 0;
960 char *pausemsecs_str = NULL;
961 int first_ttl = 1;
962 char *first_ttl_str = NULL;
963#ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
964 llist_t *sourse_route_list = NULL;
965#endif
347 966
348 on = 1; 967 opterr = 0;
349 seq = tos = 0; 968#ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
350 to = (struct sockaddr_in *)&whereto; 969 bb_opt_complementally = "x-x:g*";
351 while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:v")) != EOF) 970#else
352 switch(ch) { 971 bb_opt_complementally = "x-x";
353 case 'd':
354#ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
355 options |= SO_DEBUG;
356#endif 972#endif
357 break; 973
358 case 'm': 974 op = bb_getopt_ulflags(argc, argv, "FIlnrdvxt:i:m:p:q:s:w:z:f:"
359 max_ttl = atoi(optarg); 975#define USAGE_OP_DONT_FRAGMNT (1<<0) /* F */
360 if (max_ttl <= 1) 976#define USAGE_OP_USE_ICMP (1<<1) /* I */
361 bb_error_msg_and_die("max ttl must be >1."); 977#define USAGE_OP_TTL_FLAG (1<<2) /* l */
362 break; 978#define USAGE_OP_ADDR_NUM (1<<3) /* n */
363 case 'n': 979#define USAGE_OP_BYPASS_ROUTE (1<<4) /* r */
364 nflag++; 980#define USAGE_OP_DEBUG (1<<5) /* d */
365 break; 981#define USAGE_OP_VERBOSE (1<<6) /* v */
366 case 'p': 982#define USAGE_OP_IP_CHKSUM (1<<7) /* x */
367 port = atoi(optarg); 983
368 if (port < 1) 984#ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
369 bb_error_msg_and_die("port must be >0."); 985 "g:"
370 break; 986#endif
371 case 'q': 987 , &tos_str, &device, &max_ttl_str, &port_str, &nprobes_str,
372 nprobes = atoi(optarg); 988 &source, &waittime_str, &pausemsecs_str, &first_ttl_str
373 if (nprobes < 1) 989#ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
374 bb_error_msg_and_die("nprobes must be >0."); 990 , &sourse_route_list
375 break; 991#endif
376 case 'r': 992 );
377 options |= SO_DONTROUTE; 993
378 break; 994 if(op & USAGE_OP_DONT_FRAGMNT)
379 case 's': 995 off = IP_DF;
380 /* 996#ifdef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
381 * set the ip source address of the outbound 997 useicmp = op & USAGE_OP_USE_ICMP;
382 * probe (e.g., on a multi-homed host). 998#endif
383 */ 999 nflag = op & USAGE_OP_ADDR_NUM;
384 source = optarg;
385 break;
386 case 't':
387 tos = atoi(optarg);
388 if (tos < 0 || tos > 255)
389 bb_error_msg_and_die("tos must be 0 to 255.");
390 break;
391 case 'v':
392#ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE 1000#ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
393 verbose++; 1001 verbose = op & USAGE_OP_VERBOSE;
394#endif 1002#endif
395 break; 1003 if(op & USAGE_OP_IP_CHKSUM) {
396 case 'w': 1004 doipcksum = 0;
397 waittime = atoi(optarg); 1005 bb_error_msg("Warning: ip checksums disabled");
398 if (waittime <= 1) 1006 }
399 bb_error_msg_and_die("wait must be >1 sec."); 1007 if (tos_str)
400 break; 1008 tos = str2val(tos_str, "tos", 0, 255);
401 default: 1009 if(max_ttl_str)
402 bb_show_usage(); 1010 max_ttl = str2val(max_ttl_str, "max ttl", 1, 255);
1011 if(port_str)
1012 port = (u_short)str2val(port_str, "port", 1, (1 << 16) - 1);
1013 if(nprobes_str)
1014 nprobes = str2val(optarg, "nprobes", 1, -1);
1015 if(source) {
1016 /*
1017 * set the ip source address of the outbound
1018 * probe (e.g., on a multi-homed host).
1019 */
1020 if (uid)
1021 bb_error_msg_and_die("-s %s: Permission denied", source);
1022 }
1023 if(waittime_str)
1024 waittime = str2val(waittime_str, "wait time", 2, 24 * 60 * 60);
1025 if(pausemsecs_str)
1026 pausemsecs = str2val(pausemsecs_str, "pause msecs", 0, 60 * 60 * 1000);
1027 if(first_ttl_str)
1028 first_ttl = str2val(first_ttl_str, "first ttl", 1, 255);
1029
1030#ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
1031 if(sourse_route_list) {
1032 llist_t *l_sr;
1033
1034 for(l_sr = sourse_route_list; l_sr; ) {
1035 if (lsrr >= NGATEWAYS)
1036 bb_error_msg_and_die("No more than %d gateways", NGATEWAYS);
1037 getaddr(gwlist + lsrr, l_sr->data);
1038 ++lsrr;
1039 l_sr = l_sr->link;
1040 free(sourse_route_list);
1041 sourse_route_list = l_sr;
403 } 1042 }
404 argc -= optind; 1043 optlen = (lsrr + 1) * sizeof(gwlist[0]);
405 argv += optind; 1044 }
1045#endif
1046
1047 if (first_ttl > max_ttl) {
1048 bb_error_msg_and_die(
1049 "first ttl (%d) may not be greater than max ttl (%d)",
1050 first_ttl, max_ttl);
1051 }
1052
1053 minpacket = sizeof(*outip) + sizeof(*outdata) + optlen;
1054
1055#ifdef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
1056 if (useicmp)
1057 minpacket += 8; /* XXX magic number */
1058 else
1059#endif
1060 minpacket += sizeof(*outudp);
1061 packlen = minpacket; /* minimum sized packet */
1062
1063 /* Process destination and optional packet size */
1064 switch (argc - optind) {
1065
1066 case 2:
1067 packlen = str2val(argv[optind + 1],
1068 "packet length", minpacket, maxpacket);
1069 /* Fall through */
406 1070
407 if (argc < 1) 1071 case 1:
1072 hostname = argv[optind];
1073 hi = gethostinfo(hostname);
1074 setsin(to, hi->addrs[0]);
1075 if (hi->n > 1)
1076 bb_error_msg(
1077 "Warning: %s has multiple addresses; using %s",
1078 hostname, inet_ntoa(to->sin_addr));
1079 hostname = hi->name;
1080 hi->name = NULL;
1081 freehostinfo(hi);
1082 break;
1083
1084 default:
408 bb_show_usage(); 1085 bb_show_usage();
1086 }
409 1087
410 setlinebuf (stdout); 1088 cp = "icmp";
411 1089 if ((pe = getprotobyname(cp)) == NULL)
412 memset(&whereto, 0, sizeof(struct sockaddr)); 1090 bb_perror_msg_and_die("unknown protocol %s", cp);
413 hp = xgethostbyname(*argv);
414 to->sin_family = hp->h_addrtype;
415 memcpy(&to->sin_addr, hp->h_addr, hp->h_length);
416 hostname = (char *)hp->h_name;
417 if (*++argv)
418 datalen = atoi(*argv);
419 if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket))
420 bb_error_msg_and_die("packet size must be 0 <= s < %d.",
421 (int)(MAXPACKET - sizeof(struct opacket)));
422 datalen += sizeof(struct opacket);
423 outpacket = (struct opacket *)xmalloc((unsigned)datalen);
424 memset(outpacket, 0, datalen);
425 outpacket->ip.ip_dst = to->sin_addr;
426 outpacket->ip.ip_tos = tos;
427 outpacket->ip.ip_v = IPVERSION;
428 outpacket->ip.ip_id = 0;
429 1091
430 ident = (getpid() & 0xffff) | 0x8000; 1092 /* Insure the socket fds won't be 0, 1 or 2 */
1093 do n = bb_xopen(devnull, O_RDONLY); while (n < 2);
1094 if (n > 2)
1095 close(n);
431 1096
432 if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) 1097 if ((s = socket(AF_INET, SOCK_RAW, pe->p_proto)) < 0)
433 bb_perror_msg_and_die(bb_msg_can_not_create_raw_socket); 1098 bb_perror_msg_and_die(bb_msg_can_not_create_raw_socket);
434 1099
435 s = create_icmp_socket();
436
437#ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG 1100#ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
438 if (options & SO_DEBUG) 1101 if (op & USAGE_OP_DEBUG)
439 (void) setsockopt(s, SOL_SOCKET, SO_DEBUG, 1102 (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&on,
440 (char *)&on, sizeof(on)); 1103 sizeof(on));
441#endif 1104#endif
442 if (options & SO_DONTROUTE) 1105 if (op & USAGE_OP_BYPASS_ROUTE)
443 (void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE, 1106 (void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
444 (char *)&on, sizeof(on)); 1107 sizeof(on));
1108
1109 sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
1110 if (sndsock < 0)
1111 bb_perror_msg_and_die(bb_msg_can_not_create_raw_socket);
1112
1113#ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
1114#if defined(IP_OPTIONS)
1115 if (lsrr > 0) {
1116 u_char optlist[MAX_IPOPTLEN];
1117
1118 cp = "ip";
1119 if ((pe = getprotobyname(cp)) == NULL)
1120 bb_perror_msg_and_die("unknown protocol");
1121
1122 /* final hop */
1123 gwlist[lsrr] = to->sin_addr.s_addr;
1124 ++lsrr;
1125
1126 /* force 4 byte alignment */
1127 optlist[0] = IPOPT_NOP;
1128 /* loose source route option */
1129 optlist[1] = IPOPT_LSRR;
1130 i = lsrr * sizeof(gwlist[0]);
1131 optlist[2] = i + 3;
1132 /* Pointer to LSRR addresses */
1133 optlist[3] = IPOPT_MINOFF;
1134 memcpy(optlist + 4, gwlist, i);
1135
1136 if ((setsockopt(sndsock, pe->p_proto, IP_OPTIONS,
1137 (char *)optlist, i + sizeof(gwlist[0]))) < 0) {
1138 bb_perror_msg_and_die("IP_OPTIONS");
1139 }
1140 }
1141#endif /* IP_OPTIONS */
1142#endif /* CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE */
1143
445#ifdef SO_SNDBUF 1144#ifdef SO_SNDBUF
446 if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen, 1145 if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&packlen,
447 sizeof(datalen)) < 0) 1146 sizeof(packlen)) < 0) {
448 bb_perror_msg_and_die("SO_SNDBUF"); 1147 bb_perror_msg_and_die("SO_SNDBUF");
1148 }
449#endif 1149#endif
450#ifdef IP_HDRINCL 1150#ifdef IP_HDRINCL
451 if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on, 1151 if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
452 sizeof(on)) < 0) 1152 sizeof(on)) < 0 && errno != ENOPROTOOPT) {
453 bb_perror_msg_and_die("IP_HDRINCL"); 1153 bb_perror_msg_and_die("IP_HDRINCL");
1154 }
1155#else
1156#ifdef IP_TOS
1157 if (tos_str && setsockopt(sndsock, IPPROTO_IP, IP_TOS,
1158 (char *)&tos, sizeof(tos)) < 0) {
1159 bb_perror_msg_and_die("setsockopt tos %d", tos);
1160 }
1161#endif
454#endif 1162#endif
455#ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG 1163#ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
456 if (options & SO_DEBUG) 1164 if (op & USAGE_OP_DEBUG)
457 (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, 1165 (void)setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, (char *)&on,
458 (char *)&on, sizeof(on)); 1166 sizeof(on));
459#endif 1167#endif
460 if (options & SO_DONTROUTE) 1168 if (op & USAGE_OP_BYPASS_ROUTE)
461 (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, 1169 (void)setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
462 (char *)&on, sizeof(on)); 1170 sizeof(on));
463 1171
464 if (source) { 1172 /* Revert to non-privileged user after opening sockets */
465 memset(&from, 0, sizeof(struct sockaddr)); 1173 setgid(getgid());
466 from.sin_family = AF_INET; 1174 setuid(uid);
467 from.sin_addr.s_addr = inet_addr(source); 1175
468 if (from.sin_addr.s_addr == -1) 1176 outip = (struct ip *)xcalloc(1, (unsigned)packlen);
469 bb_error_msg_and_die("unknown host %s", source); 1177
470 outpacket->ip.ip_src = from.sin_addr; 1178 outip->ip_v = IPVERSION;
471#ifndef IP_HDRINCL 1179 if (tos_str)
472 if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0) 1180 outip->ip_tos = tos;
473 bb_perror_msg_and_die("bind"); 1181 outip->ip_len = htons(packlen);
1182 outip->ip_off = htons(off);
1183 outp = (u_char *)(outip + 1);
1184 outip->ip_dst = to->sin_addr;
1185
1186 outip->ip_hl = (outp - (u_char *)outip) >> 2;
1187 ident = (getpid() & 0xffff) | 0x8000;
1188#ifdef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
1189 if (useicmp) {
1190 outip->ip_p = IPPROTO_ICMP;
1191
1192 outicmp = (struct icmp *)outp;
1193 outicmp->icmp_type = ICMP_ECHO;
1194 outicmp->icmp_id = htons(ident);
1195
1196 outdata = (struct outdata *)(outp + 8); /* XXX magic number */
1197 } else
474#endif 1198#endif
1199 {
1200 outip->ip_p = IPPROTO_UDP;
1201
1202 outudp = (struct udphdr *)outp;
1203 outudp->source = htons(ident);
1204 outudp->len =
1205 htons((u_short)(packlen - (sizeof(*outip) + optlen)));
1206 outdata = (struct outdata *)(outudp + 1);
475 } 1207 }
476 1208
477 fprintf(stderr, "traceroute to %s (%s)", hostname, 1209 /* Get the interface address list */
478 inet_ntoa(to->sin_addr)); 1210 n = ifaddrlist(&al);
1211
1212 /* Look for a specific device */
1213 if (device != NULL) {
1214 for (i = n; i > 0; --i, ++al)
1215 if (strcmp(device, al->device) == 0)
1216 break;
1217 if (i <= 0) {
1218 bb_error_msg_and_die("Can't find interface %s", device);
1219 }
1220 }
1221
1222 /* Determine our source address */
1223 if (source == NULL) {
1224 /*
1225 * If a device was specified, use the interface address.
1226 * Otherwise, try to determine our source address.
1227 */
1228 if (device != NULL)
1229 setsin(from, al->addr);
1230 findsaddr(to, from);
1231 } else {
1232 hi = gethostinfo(source);
1233 source = hi->name;
1234 hi->name = NULL;
1235 /*
1236 * If the device was specified make sure it
1237 * corresponds to the source address specified.
1238 * Otherwise, use the first address (and warn if
1239 * there are more than one).
1240 */
1241 if (device != NULL) {
1242 for (i = hi->n, ap = hi->addrs; i > 0; --i, ++ap)
1243 if (*ap == al->addr)
1244 break;
1245 if (i <= 0) {
1246 bb_error_msg_and_die(
1247 "%s is not on interface %s",
1248 source, device);
1249 }
1250 setsin(from, *ap);
1251 } else {
1252 setsin(from, hi->addrs[0]);
1253 if (hi->n > 1)
1254 bb_error_msg(
1255 "Warning: %s has multiple addresses; using %s",
1256 source, inet_ntoa(from->sin_addr));
1257 }
1258 freehostinfo(hi);
1259 }
1260
1261 outip->ip_src = from->sin_addr;
1262#ifndef IP_HDRINCL
1263 if (bind(sndsock, (struct sockaddr *)from, sizeof(*from)) < 0) {
1264 bb_perror_msg_and_die("bind");
1265 }
1266#endif
1267
1268 fprintf(stderr, "traceroute to %s (%s)", hostname, inet_ntoa(to->sin_addr));
479 if (source) 1269 if (source)
480 fprintf(stderr, " from %s", source); 1270 fprintf(stderr, " from %s", source);
481 fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen); 1271 fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, packlen);
1272 (void)fflush(stderr);
482 1273
483 for (ttl = 1; ttl <= max_ttl; ++ttl) { 1274 for (ttl = first_ttl; ttl <= max_ttl; ++ttl) {
484 u_long lastaddr = 0; 1275 u_int32_t lastaddr = 0;
1276 int gotlastaddr = 0;
485 int got_there = 0; 1277 int got_there = 0;
486 int unreachable = 0; 1278 int unreachable = 0;
1279 int sentfirst = 0;
487 1280
488 printf("%2d ", ttl); 1281 printf("%2d ", ttl);
489 for (probe = 0; probe < nprobes; ++probe) { 1282 for (probe = 0; probe < nprobes; ++probe) {
490 int cc, reset_timer; 1283 int cc;
491 struct timeval t1, t2; 1284 struct timeval t1, t2;
492 struct timezone tz; 1285 struct timezone tz;
493 struct ip *ip; 1286 struct ip *ip;
494 1287
495 (void) gettimeofday(&t1, &tz); 1288 if (sentfirst && pausemsecs > 0)
496 send_probe(++seq, ttl); 1289 usleep(pausemsecs * 1000);
497 reset_timer = 1; 1290 (void)gettimeofday(&t1, &tz);
498 while ((cc = wait_for_reply(s, &from, reset_timer)) != 0) { 1291 send_probe(++seq, ttl, &t1);
499 (void) gettimeofday(&t2, &tz); 1292 ++sentfirst;
500 if ((i = packet_ok(packet, cc, &from, seq))) { 1293 while ((cc = wait_for_reply(s, from, &t1)) != 0) {
501 reset_timer = 1; 1294 (void)gettimeofday(&t2, &tz);
502 if (from.sin_addr.s_addr != lastaddr) { 1295 i = packet_ok(packet, cc, from, seq);
503 print(packet, cc, &from); 1296 /* Skip short packet */
504 lastaddr = from.sin_addr.s_addr; 1297 if (i == 0)
505 } 1298 continue;
506 printf(" %g ms", deltaT(&t1, &t2)); 1299 if (!gotlastaddr ||
507 switch(i - 1) { 1300 from->sin_addr.s_addr != lastaddr) {
508 case ICMP_UNREACH_PORT: 1301 print(packet, cc, from);
509 ip = (struct ip *)packet; 1302 lastaddr = from->sin_addr.s_addr;
510 if (ip->ip_ttl <= 1) 1303 ++gotlastaddr;
511 printf(" !"); 1304 }
512 ++got_there; 1305 printf(" %.3f ms", deltaT(&t1, &t2));
513 break; 1306 ip = (struct ip *)packet;
514 case ICMP_UNREACH_NET: 1307 if (op & USAGE_OP_TTL_FLAG)
515 ++unreachable; 1308 printf(" (%d)", ip->ip_ttl);
516 printf(" !N"); 1309 if (i == -2) {
517 break; 1310 if (ip->ip_ttl <= 1)
518 case ICMP_UNREACH_HOST: 1311 printf(" !");
519 ++unreachable; 1312 ++got_there;
520 printf(" !H"); 1313 break;
521 break; 1314 }
522 case ICMP_UNREACH_PROTOCOL: 1315 /* time exceeded in transit */
523 ++got_there; 1316 if (i == -1)
524 printf(" !P"); 1317 break;
525 break; 1318 code = i - 1;
526 case ICMP_UNREACH_NEEDFRAG: 1319 switch (code) {
527 ++unreachable; 1320
528 printf(" !F"); 1321 case ICMP_UNREACH_PORT:
529 break; 1322 if (ip->ip_ttl <= 1)
530 case ICMP_UNREACH_SRCFAIL: 1323 printf(" !");
531 ++unreachable; 1324 ++got_there;
532 printf(" !S"); 1325 break;
533 break; 1326
534 } 1327 case ICMP_UNREACH_NET:
1328 ++unreachable;
1329 printf(" !N");
535 break; 1330 break;
536 } else 1331
537 reset_timer = 0; 1332 case ICMP_UNREACH_HOST:
1333 ++unreachable;
1334 printf(" !H");
1335 break;
1336
1337 case ICMP_UNREACH_PROTOCOL:
1338 ++got_there;
1339 printf(" !P");
1340 break;
1341
1342 case ICMP_UNREACH_NEEDFRAG:
1343 ++unreachable;
1344 printf(" !F-%d", pmtu);
1345 break;
1346
1347 case ICMP_UNREACH_SRCFAIL:
1348 ++unreachable;
1349 printf(" !S");
1350 break;
1351
1352 case ICMP_UNREACH_FILTER_PROHIB:
1353 case ICMP_UNREACH_NET_PROHIB: /* misuse */
1354 ++unreachable;
1355 printf(" !A");
1356 break;
1357
1358 case ICMP_UNREACH_HOST_PROHIB:
1359 ++unreachable;
1360 printf(" !C");
1361 break;
1362
1363 case ICMP_UNREACH_HOST_PRECEDENCE:
1364 ++unreachable;
1365 printf(" !V");
1366 break;
1367
1368 case ICMP_UNREACH_PRECEDENCE_CUTOFF:
1369 ++unreachable;
1370 printf(" !C");
1371 break;
1372
1373 case ICMP_UNREACH_NET_UNKNOWN:
1374 case ICMP_UNREACH_HOST_UNKNOWN:
1375 ++unreachable;
1376 printf(" !U");
1377 break;
1378
1379 case ICMP_UNREACH_ISOLATED:
1380 ++unreachable;
1381 printf(" !I");
1382 break;
1383
1384 case ICMP_UNREACH_TOSNET:
1385 case ICMP_UNREACH_TOSHOST:
1386 ++unreachable;
1387 printf(" !T");
1388 break;
1389
1390 default:
1391 ++unreachable;
1392 printf(" !<%d>", code);
1393 break;
1394 }
1395 break;
538 } 1396 }
539 if (cc == 0) 1397 if (cc == 0)
540 printf(" *"); 1398 printf(" *");
541 (void) fflush(stdout); 1399 (void)fflush(stdout);
542 } 1400 }
543 putchar('\n'); 1401 putchar('\n');
544 if (got_there || unreachable >= nprobes-1) 1402 if (got_there ||
545 return 0; 1403 (unreachable > 0 && unreachable >= nprobes - 1))
1404 break;
546 } 1405 }
547
548 return 0; 1406 return 0;
549} 1407}