15d55e79bc0c6806f282903956efbe5f74c0b8d6
[oweals/busybox.git] / networking / traceroute.c
1 /*
2  * Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Busybox port by Vladimir Oleynik (C) 2005 <dzo@simtreas.ru>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that: (1) source code distributions
9  * retain the above copyright notice and this paragraph in its entirety, (2)
10  * distributions including binary code include the above copyright notice and
11  * this paragraph in its entirety in the documentation or other materials
12  * provided with the distribution, and (3) all advertising materials mentioning
13  * features or use of this software display the following acknowledgement:
14  * ``This product includes software developed by the University of California,
15  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
16  * the University nor the names of its contributors may be used to endorse
17  * or promote products derived from this software without specific prior
18  * written permission.
19  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
20  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
21  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22  */
23
24 //#define version "1.4a12"
25
26
27 /*
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  *
144  * Notes
145  * -----
146  * This program must be run by root or be setuid.  (I suggest that
147  * you *don't* make it setuid -- casual use could result in a lot
148  * of unnecessary traffic on our poor, congested nets.)
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  *
179  * I stole the idea for this program from Steve Deering.  Since
180  * the first release, I've learned that had I attended the right
181  * IETF working group meetings, I also could have stolen it from Guy
182  * Almes or Matt Mathis.  I don't know (or care) who came up with
183  * the idea first.  I envy the originators' perspicacity and I'm
184  * glad they didn't keep the idea a secret.
185  *
186  * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or
187  * enhancements to the original distribution.
188  *
189  * I've hacked up a round-trip-route version of this that works by
190  * sending a loose-source-routed udp datagram through the destination
191  * back to yourself.  Unfortunately, SO many gateways botch source
192  * routing, the thing is almost worthless.  Maybe one day...
193  *
194  *  -- Van Jacobson (van@ee.lbl.gov)
195  *     Tue Dec 20 03:50:13 PST 1988
196  */
197
198 #undef CONFIG_FEATURE_TRACEROUTE_VERBOSE
199 //#define CONFIG_FEATURE_TRACEROUTE_VERBOSE
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
205
206 #include <errno.h>
207 #include <memory.h>
208 #include <stdio.h>
209 #include <stdlib.h>
210 #include <string.h>
211 #include <unistd.h>
212 #include <fcntl.h>
213 #include <malloc.h>
214 #include <netdb.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>
229 #include <netinet/udp.h>
230 #include <netinet/ip.h>
231 #include <netinet/ip_icmp.h>
232
233 #include "busybox.h"
234
235
236 /*
237  * Definitions for internet protocol version 4.
238  * Per RFC 791, September 1981.
239  */
240 #define IPVERSION       4
241
242 /*
243  * Overlay for ip header used by other protocols (tcp, udp).
244  */
245 struct 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 */
251 };
252
253 /*
254  * UDP kernel structures and variables.
255  */
256 struct  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
271
272
273 /* Host name and address list */
274 struct hostinfo {
275         char *name;
276         int n;
277         u_int32_t *addrs;
278 };
279
280 /* Data section of the probe packet */
281 struct 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
287 struct IFADDRLIST {
288         u_int32_t addr;
289         char device[sizeof(struct ifreq)];
290 };
291
292
293 static const char route[] = "/proc/net/route";
294
295 /* last inbound (icmp) packet */
296 static u_char  packet[512] __attribute__((align (32)));
297
298 static struct ip *outip;               /* last output (udp) packet */
299 static struct udphdr *outudp;          /* last output (udp) packet */
300 static struct outdata *outdata;        /* last output (udp) packet */
301
302 #ifdef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
303 static 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) */
310 static u_int32_t gwlist[NGATEWAYS + 1];
311 #endif
312
313 static int s;                          /* receive (icmp) socket file descriptor */
314 static int sndsock;                    /* send (udp/icmp) socket file descriptor */
315
316 static struct sockaddr_storage whereto;        /* Who to try to reach */
317 static struct sockaddr_storage wherefrom;      /* Who we are */
318 static int packlen;                    /* total length of packet */
319 static int minpacket;                  /* min ip packet size */
320 static int maxpacket = 32 * 1024;      /* max ip packet size */
321 static int pmtu;                       /* Path MTU Discovery (RFC1191) */
322
323 static char *hostname;
324 static const char devnull[] = "/dev/null";
325
326 static u_short ident;
327 static u_short port = 32768 + 666;     /* start udp dest port # for probe packets */
328
329 static int waittime = 5;               /* time to wait for response (in seconds) */
330 static int nflag;                      /* print addresses numerically */
331 static int doipcksum = 1;              /* calculate ip checksums by default */
332
333 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
334 static int optlen;                     /* length of ip options */
335 #else
336 #define optlen 0
337 #endif
338
339 #ifdef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
340 static int useicmp;                    /* use icmp echo instead of udp packets */
341 #endif
342 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
343 static int verbose;
344 #endif
345
346 /*
347  * Return the interface list
348  */
349 static int
350 ifaddrlist(struct IFADDRLIST **ipaddrp)
351 {
352         int fd, nipaddr;
353 #ifdef HAVE_SOCKADDR_SA_LEN
354         int n;
355 #endif
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;
362
363         fd = socket(AF_INET, SOCK_DGRAM, 0);
364         if (fd < 0)
365                 bb_perror_msg_and_die("socket");
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");
378         }
379         ifrp = ibuf;
380         ifend = (struct ifreq *)((char *)ibuf + ifc.ifc_len);
381
382         nipaddr = 1 + (ifc.ifc_len / sizeof(struct ifreq));
383         st_ifaddrlist = xcalloc(nipaddr, sizeof(struct IFADDRLIST));
384         al = st_ifaddrlist;
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);
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;
430         }
431         if(nipaddr == 0)
432             bb_error_msg_and_die ("Can't find any network interfaces");
433         (void)close(fd);
434
435         *ipaddrp = st_ifaddrlist;
436         return nipaddr;
437 }
438
439
440 static void
441 setsin(struct sockaddr_in *addr_sin, u_int32_t addr)
442 {
443         memset(addr_sin, 0, sizeof(*addr_sin));
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 }
450
451
452 /*
453  * Return the source address for the given destination address
454  */
455 static void
456 findsaddr(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);
500 }
501
502 /*
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. */
510 static int
511 str2val(const char *str, const char *what, int mi, int ma)
512 {
513         const char *cp;
514         int val;
515         char *ep;
516
517         if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) {
518                 cp = str + 2;
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;
534 }
535
536
537 /*
538  * Subtract 2 timeval structs:  out = out - in.
539  * Out is assumed to be >= in.
540  */
541 static inline void
542 tvsub(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
552 static int
553 wait_for_reply(int sock, struct sockaddr_in *fromp, const struct timeval *tp)
554 {
555         fd_set fds;
556         struct timeval now, wait;
557         struct timezone tz;
558         int cc = 0;
559         socklen_t fromlen = sizeof(*fromp);
560
561         FD_ZERO(&fds);
562         FD_SET(sock, &fds);
563
564         wait.tv_sec = tp->tv_sec + waittime;
565         wait.tv_usec = tp->tv_usec;
566         (void)gettimeofday(&now, &tz);
567         tvsub(&wait, &now);
568
569         if (select(sock + 1, &fds, NULL, NULL, &wait) > 0)
570                 cc = recvfrom(sock, (char *)packet, sizeof(packet), 0,
571                             (struct sockaddr *)fromp, &fromlen);
572
573         return cc;
574 }
575
576 /*
577  * Checksum routine for Internet Protocol family headers (C Version)
578  */
579 static u_short
580 in_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
612 static void
613 send_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);
714         }
715 }
716
717 static inline double
718 deltaT(struct timeval *t1p, struct timeval *t2p)
719 {
720         double dt;
721
722         dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
723              (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
724         return dt;
725 }
726
727 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
728 /*
729  * Convert an ICMP "type" field to a printable string.
730  */
731 static inline const char *
732 pr_type(u_char t)
733 {
734         static const char * const ttab[] = {
735         "Echo Reply",   "ICMP 1",       "ICMP 2",       "Dest Unreachable",
736         "Source Quench", "Redirect",    "ICMP 6",       "ICMP 7",
737         "Echo",         "Router Advert", "Router Solicit", "Time Exceeded",
738         "Param Problem", "Timestamp",   "Timestamp Reply", "Info Request",
739         "Info Reply",   "Mask Request", "Mask Reply"
740         };
741
742         if (t > 18)
743                 return "OUT-OF-RANGE";
744
745         return ttab[t];
746 }
747 #endif
748
749 static int
750 packet_ok(u_char *buf, int cc, struct sockaddr_in *from, int seq)
751 {
752         struct icmp *icp;
753         u_char type, code;
754         int hlen;
755         struct ip *ip;
756
757         ip = (struct ip *) buf;
758         hlen = ip->ip_hl << 2;
759         if (cc < hlen + ICMP_MINLEN) {
760 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
761                 if (verbose)
762                         printf("packet too short (%d bytes) from %s\n", cc,
763                                 inet_ntoa(from->sin_addr));
764 #endif
765                 return 0;
766         }
767         cc -= hlen;
768         icp = (struct icmp *)(buf + hlen);
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         }
777         if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
778             type == ICMP_UNREACH || type == ICMP_ECHOREPLY) {
779                 struct ip *hip;
780                 struct udphdr *up;
781
782                 hip = &icp->icmp_ip;
783                 hlen = hip->ip_hl << 2;
784 #ifdef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
785                 if (useicmp) {
786                         struct icmp *hicmp;
787
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                 }
812         }
813 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
814         if (verbose) {
815                 int i;
816                 u_int32_t *lp = (u_int32_t *)&icp->icmp_ip;
817
818                 printf("\n%d bytes from %s to "
819                        "%s: icmp type %d (%s) code %d\n",
820                     cc, inet_ntoa(from->sin_addr),
821                     inet_ntoa(ip->ip_dst), type, pr_type(type), icp->icmp_code);
822                 for (i = 4; i < cc ; i += sizeof(*lp))
823                         printf("%2d: x%8.8x\n", i, *lp++);
824         }
825 #endif
826         return 0;
827 }
828
829
830 /*
831  * Construct an Internet address representation.
832  * If the nflag has been supplied, give
833  * numeric value, otherwise try for symbolic name.
834  */
835 static inline void
836 inetname(struct sockaddr_in *from)
837 {
838         const char *n = NULL;
839         const char *ina;
840         char name[257];
841
842         if (!nflag && from->sin_addr.s_addr != INADDR_ANY) {
843                 if(INET_rresolve(name, sizeof(name), from, 0x4000, 0xffffffff) >= 0)
844                         n = name;
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);
851 }
852
853 static inline void
854 print(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;
862
863         inetname(from);
864 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
865         if (verbose)
866                 printf(" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
867 #endif
868 }
869
870
871 static struct hostinfo *
872 gethostinfo(const char *host)
873 {
874         int n;
875         struct hostent *hp;
876         struct hostinfo *hi;
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
903 static void
904 freehostinfo(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
915 static void
916 getaddr(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
926
927 int
928 traceroute_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;
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
966
967         opterr = 0;
968 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
969         bb_opt_complementally = "x-x:g*";
970 #else
971         bb_opt_complementally = "x-x";
972 #endif
973
974         op = bb_getopt_ulflags(argc, argv, "FIlnrdvxt:i:m:p:q:s:w:z:f:"
975 #define USAGE_OP_DONT_FRAGMNT (1<<0)    /* F  */
976 #define USAGE_OP_USE_ICMP     (1<<1)    /* I  */
977 #define USAGE_OP_TTL_FLAG     (1<<2)    /* l  */
978 #define USAGE_OP_ADDR_NUM     (1<<3)    /* n  */
979 #define USAGE_OP_BYPASS_ROUTE (1<<4)    /* r  */
980 #define USAGE_OP_DEBUG        (1<<5)    /* d */
981 #define USAGE_OP_VERBOSE      (1<<6)    /* v */
982 #define USAGE_OP_IP_CHKSUM    (1<<7)    /* x */
983
984 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
985                                         "g:"
986 #endif
987         , &tos_str, &device, &max_ttl_str, &port_str, &nprobes_str,
988         &source, &waittime_str, &pausemsecs_str, &first_ttl_str
989 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
990         , &sourse_route_list
991 #endif
992         );
993
994         if(op & USAGE_OP_DONT_FRAGMNT)
995                 off = IP_DF;
996 #ifdef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
997         useicmp = op & USAGE_OP_USE_ICMP;
998 #endif
999         nflag = op & USAGE_OP_ADDR_NUM;
1000 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
1001         verbose = op &  USAGE_OP_VERBOSE;
1002 #endif
1003         if(op & USAGE_OP_IP_CHKSUM) {
1004                 doipcksum = 0;
1005                 bb_error_msg("Warning: ip checksums disabled");
1006         }
1007         if (tos_str)
1008                 tos = str2val(tos_str, "tos", 0, 255);
1009         if(max_ttl_str)
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;
1042                 }
1043                 optlen = (lsrr + 1) * sizeof(gwlist[0]);
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 */
1070
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:
1085                 bb_show_usage();
1086         }
1087
1088         cp = "icmp";
1089         if ((pe = getprotobyname(cp)) == NULL)
1090                 bb_perror_msg_and_die("unknown protocol %s", cp);
1091
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);
1096
1097         if ((s = socket(AF_INET, SOCK_RAW, pe->p_proto)) < 0)
1098                 bb_perror_msg_and_die(bb_msg_can_not_create_raw_socket);
1099
1100 #ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
1101         if (op & USAGE_OP_DEBUG)
1102                 (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&on,
1103                     sizeof(on));
1104 #endif
1105         if (op & USAGE_OP_BYPASS_ROUTE)
1106                 (void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&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
1144 #ifdef SO_SNDBUF
1145         if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&packlen,
1146             sizeof(packlen)) < 0) {
1147                 bb_perror_msg_and_die("SO_SNDBUF");
1148         }
1149 #endif
1150 #ifdef IP_HDRINCL
1151         if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
1152             sizeof(on)) < 0 && errno != ENOPROTOOPT) {
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
1162 #endif
1163 #ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
1164         if (op & USAGE_OP_DEBUG)
1165                 (void)setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, (char *)&on,
1166                     sizeof(on));
1167 #endif
1168         if (op & USAGE_OP_BYPASS_ROUTE)
1169                 (void)setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
1170                     sizeof(on));
1171
1172         /* Revert to non-privileged user after opening sockets */
1173         setgid(getgid());
1174         setuid(uid);
1175
1176         outip = (struct ip *)xcalloc(1, (unsigned)packlen);
1177
1178         outip->ip_v = IPVERSION;
1179         if (tos_str)
1180                 outip->ip_tos = tos;
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
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);
1207         }
1208
1209         /* Get the interface address list */
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));
1269         if (source)
1270                 fprintf(stderr, " from %s", source);
1271         fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, packlen);
1272         (void)fflush(stderr);
1273
1274         for (ttl = first_ttl; ttl <= max_ttl; ++ttl) {
1275                 u_int32_t lastaddr = 0;
1276                 int gotlastaddr = 0;
1277                 int got_there = 0;
1278                 int unreachable = 0;
1279                 int sentfirst = 0;
1280
1281                 printf("%2d ", ttl);
1282                 for (probe = 0; probe < nprobes; ++probe) {
1283                         int cc;
1284                         struct timeval t1, t2;
1285                         struct timezone tz;
1286                         struct ip *ip;
1287
1288                         if (sentfirst && pausemsecs > 0)
1289                                 usleep(pausemsecs * 1000);
1290                         (void)gettimeofday(&t1, &tz);
1291                         send_probe(++seq, ttl, &t1);
1292                         ++sentfirst;
1293                         while ((cc = wait_for_reply(s, from, &t1)) != 0) {
1294                                 (void)gettimeofday(&t2, &tz);
1295                                 i = packet_ok(packet, cc, from, seq);
1296                                 /* Skip short packet */
1297                                 if (i == 0)
1298                                         continue;
1299                                 if (!gotlastaddr ||
1300                                     from->sin_addr.s_addr != lastaddr) {
1301                                         print(packet, cc, from);
1302                                         lastaddr = from->sin_addr.s_addr;
1303                                         ++gotlastaddr;
1304                                 }
1305                                 printf("  %.3f ms", deltaT(&t1, &t2));
1306                                 ip = (struct ip *)packet;
1307                                 if (op & USAGE_OP_TTL_FLAG)
1308                                         printf(" (%d)", ip->ip_ttl);
1309                                 if (i == -2) {
1310                                         if (ip->ip_ttl <= 1)
1311                                                 printf(" !");
1312                                         ++got_there;
1313                                         break;
1314                                 }
1315                                 /* time exceeded in transit */
1316                                 if (i == -1)
1317                                         break;
1318                                 code = i - 1;
1319                                 switch (code) {
1320
1321                                 case ICMP_UNREACH_PORT:
1322                                         if (ip->ip_ttl <= 1)
1323                                                 printf(" !");
1324                                         ++got_there;
1325                                         break;
1326
1327                                 case ICMP_UNREACH_NET:
1328                                         ++unreachable;
1329                                         printf(" !N");
1330                                         break;
1331
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;
1396                         }
1397                         if (cc == 0)
1398                                 printf(" *");
1399                         (void)fflush(stdout);
1400                 }
1401                 putchar('\n');
1402                 if (got_there ||
1403                     (unreachable > 0 && unreachable >= nprobes - 1))
1404                         break;
1405         }
1406         return 0;
1407 }