Patch from dlively (whoever that is, see bug 591) to fix
[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
325 static u_short ident;
326 static u_short port = 32768 + 666;     /* start udp dest port # for probe packets */
327
328 static int waittime = 5;               /* time to wait for response (in seconds) */
329 static int nflag;                      /* print addresses numerically */
330 static int doipcksum = 1;              /* calculate ip checksums by default */
331
332 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
333 static int optlen;                     /* length of ip options */
334 #else
335 #define optlen 0
336 #endif
337
338 #ifdef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
339 static int useicmp;                    /* use icmp echo instead of udp packets */
340 #endif
341 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
342 static int verbose;
343 #endif
344
345 /*
346  * Return the interface list
347  */
348 static int
349 ifaddrlist(struct IFADDRLIST **ipaddrp)
350 {
351         int fd, nipaddr;
352 #ifdef HAVE_SOCKADDR_SA_LEN
353         int n;
354 #endif
355         struct ifreq *ifrp, *ifend, *ifnext;
356         struct sockaddr_in *addr_sin;
357         struct IFADDRLIST *al;
358         struct ifconf ifc;
359         struct ifreq ibuf[(32 * 1024) / sizeof(struct ifreq)], ifr;
360         struct IFADDRLIST *st_ifaddrlist;
361
362         fd = socket(AF_INET, SOCK_DGRAM, 0);
363         if (fd < 0)
364                 bb_perror_msg_and_die("socket");
365
366         ifc.ifc_len = sizeof(ibuf);
367         ifc.ifc_buf = (caddr_t)ibuf;
368
369         if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 ||
370             ifc.ifc_len < sizeof(struct ifreq)) {
371                 if (errno == EINVAL)
372                         bb_error_msg_and_die(
373                             "SIOCGIFCONF: ifreq struct too small (%d bytes)",
374                             sizeof(ibuf));
375                 else
376                         bb_perror_msg_and_die("SIOCGIFCONF");
377         }
378         ifrp = ibuf;
379         ifend = (struct ifreq *)((char *)ibuf + ifc.ifc_len);
380
381         nipaddr = 1 + (ifc.ifc_len / sizeof(struct ifreq));
382         st_ifaddrlist = xcalloc(nipaddr, sizeof(struct IFADDRLIST));
383         al = st_ifaddrlist;
384         nipaddr = 0;
385
386         for (; ifrp < ifend; ifrp = ifnext) {
387 #ifdef HAVE_SOCKADDR_SA_LEN
388                 n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
389                 if (n < sizeof(*ifrp))
390                         ifnext = ifrp + 1;
391                 else
392                         ifnext = (struct ifreq *)((char *)ifrp + n);
393                 if (ifrp->ifr_addr.sa_family != AF_INET)
394                         continue;
395 #else
396                 ifnext = ifrp + 1;
397 #endif
398                 /*
399                  * Need a template to preserve address info that is
400                  * used below to locate the next entry.  (Otherwise,
401                  * SIOCGIFFLAGS stomps over it because the requests
402                  * are returned in a union.)
403                  */
404                 strncpy(ifr.ifr_name, ifrp->ifr_name, sizeof(ifr.ifr_name));
405                 if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifr) < 0) {
406                         if (errno == ENXIO)
407                                 continue;
408                         bb_perror_msg_and_die("SIOCGIFFLAGS: %.*s",
409                             (int)sizeof(ifr.ifr_name), ifr.ifr_name);
410                 }
411
412                 /* Must be up */
413                 if ((ifr.ifr_flags & IFF_UP) == 0)
414                         continue;
415
416                 safe_strncpy(al->device, ifr.ifr_name, sizeof(ifr.ifr_name) + 1);
417 #ifdef sun
418                 /* Ignore sun virtual interfaces */
419                 if (strchr(al->device, ':') != NULL)
420                         continue;
421 #endif
422                 if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0)
423                         bb_perror_msg_and_die("SIOCGIFADDR: %s", al->device);
424
425                 addr_sin = (struct sockaddr_in *)&ifr.ifr_addr;
426                 al->addr = addr_sin->sin_addr.s_addr;
427                 ++al;
428                 ++nipaddr;
429         }
430         if(nipaddr == 0)
431             bb_error_msg_and_die ("Can't find any network interfaces");
432         (void)close(fd);
433
434         *ipaddrp = st_ifaddrlist;
435         return nipaddr;
436 }
437
438
439 static void
440 setsin(struct sockaddr_in *addr_sin, u_int32_t addr)
441 {
442         memset(addr_sin, 0, sizeof(*addr_sin));
443 #ifdef HAVE_SOCKADDR_SA_LEN
444         addr_sin->sin_len = sizeof(*addr_sin);
445 #endif
446         addr_sin->sin_family = AF_INET;
447         addr_sin->sin_addr.s_addr = addr;
448 }
449
450
451 /*
452  * Return the source address for the given destination address
453  */
454 static void
455 findsaddr(const struct sockaddr_in *to, struct sockaddr_in *from)
456 {
457         int i, n;
458         FILE *f;
459         u_int32_t mask;
460         u_int32_t dest, tmask;
461         struct IFADDRLIST *al;
462         char buf[256], tdevice[256], device[256];
463
464         f = bb_xfopen(route, "r");
465
466         /* Find the appropriate interface */
467         n = 0;
468         mask = 0;
469         device[0] = '\0';
470         while (fgets(buf, sizeof(buf), f) != NULL) {
471                 ++n;
472                 if (n == 1 && strncmp(buf, "Iface", 5) == 0)
473                         continue;
474                 if ((i = sscanf(buf, "%255s %x %*s %*s %*s %*s %*s %x",
475                     tdevice, &dest, &tmask)) != 3)
476                         bb_error_msg_and_die ("junk in buffer");
477                 if ((to->sin_addr.s_addr & tmask) == dest &&
478                     (tmask > mask || mask == 0)) {
479                         mask = tmask;
480                         strcpy(device, tdevice);
481                 }
482         }
483         fclose(f);
484
485         if (device[0] == '\0')
486                 bb_error_msg_and_die ("Can't find interface");
487
488         /* Get the interface address list */
489         n = ifaddrlist(&al);
490
491         /* Find our appropriate source address */
492         for (i = n; i > 0; --i, ++al)
493                 if (strcmp(device, al->device) == 0)
494                         break;
495         if (i <= 0)
496                 bb_error_msg_and_die("Can't find interface %s", device);
497
498         setsin(from, al->addr);
499 }
500
501 /*
502 "Usage: %s [-dFIlnrvx] [-g gateway] [-i iface] [-f first_ttl]\n"
503 "\t[-m max_ttl] [ -p port] [-q nqueries] [-s src_addr] [-t tos]\n"
504 "\t[-w waittime] [-z pausemsecs] host [packetlen]"
505
506 */
507
508 /* String to value with optional min and max. Handles decimal and hex. */
509 static int
510 str2val(const char *str, const char *what, int mi, int ma)
511 {
512         const char *cp;
513         int val;
514         char *ep;
515
516         if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) {
517                 cp = str + 2;
518                 val = (int)strtol(cp, &ep, 16);
519         } else
520                 val = (int)strtol(str, &ep, 10);
521         if (*ep != '\0') {
522                 bb_error_msg_and_die("\"%s\" bad value for %s \n", str, what);
523         }
524         if (val < mi && mi >= 0) {
525                 if (mi == 0)
526                         bb_error_msg_and_die("%s must be >= %d\n", what, mi);
527                 else
528                         bb_error_msg_and_die("%s must be > %d\n", what, mi - 1);
529         }
530         if (val > ma && ma >= 0)
531                 bb_error_msg_and_die("%s must be <= %d\n", what, ma);
532         return val;
533 }
534
535
536 /*
537  * Subtract 2 timeval structs:  out = out - in.
538  * Out is assumed to be >= in.
539  */
540 static inline void
541 tvsub(struct timeval *out, struct timeval *in)
542 {
543
544         if ((out->tv_usec -= in->tv_usec) < 0)   {
545                 --out->tv_sec;
546                 out->tv_usec += 1000000;
547         }
548         out->tv_sec -= in->tv_sec;
549 }
550
551 static int
552 wait_for_reply(int sock, struct sockaddr_in *fromp, const struct timeval *tp)
553 {
554         fd_set fds;
555         struct timeval now, wait;
556         struct timezone tz;
557         int cc = 0;
558         socklen_t fromlen = sizeof(*fromp);
559
560         FD_ZERO(&fds);
561         FD_SET(sock, &fds);
562
563         wait.tv_sec = tp->tv_sec + waittime;
564         wait.tv_usec = tp->tv_usec;
565         (void)gettimeofday(&now, &tz);
566         tvsub(&wait, &now);
567
568         if (select(sock + 1, &fds, NULL, NULL, &wait) > 0)
569                 cc = recvfrom(sock, (char *)packet, sizeof(packet), 0,
570                             (struct sockaddr *)fromp, &fromlen);
571
572         return cc;
573 }
574
575 /*
576  * Checksum routine for Internet Protocol family headers (C Version)
577  */
578 static u_short
579 in_cksum(u_short *addr, int len)
580 {
581         int nleft = len;
582         u_short *w = addr;
583         u_short answer;
584         int sum = 0;
585
586         /*
587          *  Our algorithm is simple, using a 32 bit accumulator (sum),
588          *  we add sequential 16 bit words to it, and at the end, fold
589          *  back all the carry bits from the top 16 bits into the lower
590          *  16 bits.
591          */
592         while (nleft > 1)  {
593                 sum += *w++;
594                 nleft -= 2;
595         }
596
597         /* mop up an odd byte, if necessary */
598         if (nleft == 1)
599                 sum += *(u_char *)w;
600
601         /*
602          * add back carry outs from top 16 bits to low 16 bits
603          */
604         sum = (sum >> 16) + (sum & 0xffff);     /* add hi 16 to low 16 */
605         sum += (sum >> 16);                     /* add carry */
606         answer = ~sum;                          /* truncate to 16 bits */
607         return answer;
608 }
609
610
611 static void
612 send_probe(int seq, int ttl, struct timeval *tp)
613 {
614         int cc;
615         struct udpiphdr *ui, *oui;
616         struct ip tip;
617
618         outip->ip_ttl = ttl;
619         outip->ip_id = htons(ident + seq);
620
621         /*
622          * In most cases, the kernel will recalculate the ip checksum.
623          * But we must do it anyway so that the udp checksum comes out
624          * right.
625          */
626         if (doipcksum) {
627                 outip->ip_sum =
628                     in_cksum((u_short *)outip, sizeof(*outip) + optlen);
629                 if (outip->ip_sum == 0)
630                         outip->ip_sum = 0xffff;
631         }
632
633         /* Payload */
634         outdata->seq = seq;
635         outdata->ttl = ttl;
636         memcpy(&outdata->tv, tp, sizeof(outdata->tv));
637
638 #ifdef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
639         if (useicmp)
640                 outicmp->icmp_seq = htons(seq);
641         else
642 #endif
643                 outudp->dest = htons(port + seq);
644
645 #ifdef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
646         if (useicmp) {
647                 /* Always calculate checksum for icmp packets */
648                 outicmp->icmp_cksum = 0;
649                 outicmp->icmp_cksum = in_cksum((u_short *)outicmp,
650                     packlen - (sizeof(*outip) + optlen));
651                 if (outicmp->icmp_cksum == 0)
652                         outicmp->icmp_cksum = 0xffff;
653         } else
654 #endif
655                if (doipcksum) {
656                 /* Checksum (we must save and restore ip header) */
657                 tip = *outip;
658                 ui = (struct udpiphdr *)outip;
659                 oui = (struct udpiphdr *)&tip;
660                 /* Easier to zero and put back things that are ok */
661                 memset((char *)ui, 0, sizeof(ui->ui_i));
662                 ui->ui_src = oui->ui_src;
663                 ui->ui_dst = oui->ui_dst;
664                 ui->ui_pr = oui->ui_pr;
665                 ui->ui_len = outudp->len;
666                 outudp->check = 0;
667                 outudp->check = in_cksum((u_short *)ui, packlen);
668                 if (outudp->check == 0)
669                         outudp->check = 0xffff;
670                 *outip = tip;
671         }
672
673 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
674         /* XXX undocumented debugging hack */
675         if (verbose > 1) {
676                 const u_short *sp;
677                 int nshorts, i;
678
679                 sp = (u_short *)outip;
680                 nshorts = (u_int)packlen / sizeof(u_short);
681                 i = 0;
682                 printf("[ %d bytes", packlen);
683                 while (--nshorts >= 0) {
684                         if ((i++ % 8) == 0)
685                                 printf("\n\t");
686                         printf(" %04x", ntohs(*sp));
687                         sp++;
688                 }
689                 if (packlen & 1) {
690                         if ((i % 8) == 0)
691                                 printf("\n\t");
692                         printf(" %02x", *(u_char *)sp);
693                 }
694                 printf("]\n");
695         }
696 #endif
697
698 #if !defined(IP_HDRINCL) && defined(IP_TTL)
699         if (setsockopt(sndsock, IPPROTO_IP, IP_TTL,
700             (char *)&ttl, sizeof(ttl)) < 0) {
701                 bb_perror_msg_and_die("setsockopt ttl %d", ttl);
702         }
703 #endif
704
705         cc = sendto(sndsock, (char *)outip,
706             packlen, 0, (struct sockaddr *)&whereto, sizeof(whereto));
707         if (cc < 0 || cc != packlen)  {
708                 if (cc < 0)
709                         bb_perror_msg_and_die("sendto");
710                 printf("%s: wrote %s %d chars, ret=%d\n",
711                     bb_applet_name, hostname, packlen, cc);
712                 (void)fflush(stdout);
713         }
714 }
715
716 static inline double
717 deltaT(struct timeval *t1p, struct timeval *t2p)
718 {
719         double dt;
720
721         dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
722              (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
723         return dt;
724 }
725
726 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
727 /*
728  * Convert an ICMP "type" field to a printable string.
729  */
730 static inline const char *
731 pr_type(u_char t)
732 {
733         static const char * const ttab[] = {
734         "Echo Reply",   "ICMP 1",       "ICMP 2",       "Dest Unreachable",
735         "Source Quench", "Redirect",    "ICMP 6",       "ICMP 7",
736         "Echo",         "Router Advert", "Router Solicit", "Time Exceeded",
737         "Param Problem", "Timestamp",   "Timestamp Reply", "Info Request",
738         "Info Reply",   "Mask Request", "Mask Reply"
739         };
740
741         if (t > 18)
742                 return "OUT-OF-RANGE";
743
744         return ttab[t];
745 }
746 #endif
747
748 static int
749 packet_ok(u_char *buf, int cc, struct sockaddr_in *from, int seq)
750 {
751         struct icmp *icp;
752         u_char type, code;
753         int hlen;
754         struct ip *ip;
755
756         ip = (struct ip *) buf;
757         hlen = ip->ip_hl << 2;
758         if (cc < hlen + ICMP_MINLEN) {
759 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
760                 if (verbose)
761                         printf("packet too short (%d bytes) from %s\n", cc,
762                                 inet_ntoa(from->sin_addr));
763 #endif
764                 return 0;
765         }
766         cc -= hlen;
767         icp = (struct icmp *)(buf + hlen);
768         type = icp->icmp_type;
769         code = icp->icmp_code;
770         /* Path MTU Discovery (RFC1191) */
771         if (code != ICMP_UNREACH_NEEDFRAG)
772                 pmtu = 0;
773         else {
774                 pmtu = ntohs(icp->icmp_nextmtu);
775         }
776         if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
777             type == ICMP_UNREACH || type == ICMP_ECHOREPLY) {
778                 struct ip *hip;
779                 struct udphdr *up;
780
781                 hip = &icp->icmp_ip;
782                 hlen = hip->ip_hl << 2;
783 #ifdef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
784                 if (useicmp) {
785                         struct icmp *hicmp;
786
787                         /* XXX */
788                         if (type == ICMP_ECHOREPLY &&
789                             icp->icmp_id == htons(ident) &&
790                             icp->icmp_seq == htons(seq))
791                                 return -2;
792
793                         hicmp = (struct icmp *)((u_char *)hip + hlen);
794                         /* XXX 8 is a magic number */
795                         if (hlen + 8 <= cc &&
796                             hip->ip_p == IPPROTO_ICMP &&
797                             hicmp->icmp_id == htons(ident) &&
798                             hicmp->icmp_seq == htons(seq))
799                                 return (type == ICMP_TIMXCEED ? -1 : code + 1);
800                 } else
801 #endif
802                       {
803                         up = (struct udphdr *)((u_char *)hip + hlen);
804                         /* XXX 8 is a magic number */
805                         if (hlen + 12 <= cc &&
806                             hip->ip_p == IPPROTO_UDP &&
807                             up->source == htons(ident) &&
808                             up->dest == htons(port + seq))
809                                 return (type == ICMP_TIMXCEED ? -1 : code + 1);
810                 }
811         }
812 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
813         if (verbose) {
814                 int i;
815                 u_int32_t *lp = (u_int32_t *)&icp->icmp_ip;
816
817                 printf("\n%d bytes from %s to "
818                        "%s: icmp type %d (%s) code %d\n",
819                     cc, inet_ntoa(from->sin_addr),
820                     inet_ntoa(ip->ip_dst), type, pr_type(type), icp->icmp_code);
821                 for (i = 4; i < cc ; i += sizeof(*lp))
822                         printf("%2d: x%8.8x\n", i, *lp++);
823         }
824 #endif
825         return 0;
826 }
827
828
829 /*
830  * Construct an Internet address representation.
831  * If the nflag has been supplied, give
832  * numeric value, otherwise try for symbolic name.
833  */
834 static inline void
835 inetname(struct sockaddr_in *from)
836 {
837         const char *n = NULL;
838         const char *ina;
839         char name[257];
840
841         if (!nflag && from->sin_addr.s_addr != INADDR_ANY) {
842                 if(INET_rresolve(name, sizeof(name), from, 0x4000, 0xffffffff) >= 0)
843                         n = name;
844         }
845         ina = inet_ntoa(from->sin_addr);
846         if (nflag)
847                 printf(" %s", ina);
848         else
849                 printf(" %s (%s)", (n ? n : ina), ina);
850 }
851
852 static inline void
853 print(u_char *buf, int cc, struct sockaddr_in *from)
854 {
855         struct ip *ip;
856         int hlen;
857
858         ip = (struct ip *) buf;
859         hlen = ip->ip_hl << 2;
860         cc -= hlen;
861
862         inetname(from);
863 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
864         if (verbose)
865                 printf(" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
866 #endif
867 }
868
869
870 static struct hostinfo *
871 gethostinfo(const char *host)
872 {
873         int n;
874         struct hostent *hp;
875         struct hostinfo *hi;
876         char **p;
877         u_int32_t addr, *ap;
878
879         hi = xcalloc(1, sizeof(*hi));
880         addr = inet_addr(host);
881         if ((int32_t)addr != -1) {
882                 hi->name = bb_xstrdup(host);
883                 hi->n = 1;
884                 hi->addrs = xcalloc(1, sizeof(hi->addrs[0]));
885                 hi->addrs[0] = addr;
886                 return hi;
887         }
888
889         hp = xgethostbyname(host);
890         if (hp->h_addrtype != AF_INET || hp->h_length != 4)
891                 bb_perror_msg_and_die("bad host %s", host);
892         hi->name = bb_xstrdup(hp->h_name);
893         for (n = 0, p = hp->h_addr_list; *p != NULL; ++n, ++p)
894                 continue;
895         hi->n = n;
896         hi->addrs = xcalloc(n, sizeof(hi->addrs[0]));
897         for (ap = hi->addrs, p = hp->h_addr_list; *p != NULL; ++ap, ++p)
898                 memcpy(ap, *p, sizeof(*ap));
899         return hi;
900 }
901
902 static void
903 freehostinfo(struct hostinfo *hi)
904 {
905         if (hi->name != NULL) {
906                 free(hi->name);
907                 hi->name = NULL;
908         }
909         free((char *)hi->addrs);
910         free((char *)hi);
911 }
912
913 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
914 static void
915 getaddr(u_int32_t *ap, const char *host)
916 {
917         struct hostinfo *hi;
918
919         hi = gethostinfo(host);
920         *ap = hi->addrs[0];
921         freehostinfo(hi);
922 }
923 #endif
924
925
926 int
927 traceroute_main(int argc, char *argv[])
928 {
929         int code, n;
930         char *cp;
931         u_char *outp;
932         u_int32_t *ap;
933         struct sockaddr_in *from = (struct sockaddr_in *)&wherefrom;
934         struct sockaddr_in *to = (struct sockaddr_in *)&whereto;
935         struct hostinfo *hi;
936         int on = 1;
937         struct protoent *pe;
938         int ttl, probe, i;
939         int seq = 0;
940         int tos = 0;
941         char *tos_str = NULL;
942         char *source = NULL;
943         unsigned long op;
944
945 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
946         int lsrr = 0;
947 #endif
948         u_short off = 0;
949         struct IFADDRLIST *al;
950         int uid = getuid();
951         char *device = NULL;
952         int max_ttl = 30;
953         char *max_ttl_str = NULL;
954         char *port_str = NULL;
955         int nprobes = 3;
956         char *nprobes_str = NULL;
957         char *waittime_str = NULL;
958         u_int pausemsecs = 0;
959         char *pausemsecs_str = NULL;
960         int first_ttl = 1;
961         char *first_ttl_str = NULL;
962 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
963         llist_t *sourse_route_list = NULL;
964 #endif
965
966         opterr = 0;
967 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
968         bb_opt_complementally = "x-x:g::";
969 #else
970         bb_opt_complementally = "x-x";
971 #endif
972
973         op = bb_getopt_ulflags(argc, argv, "FIlnrdvxt:i:m:p:q:s:w:z:f:"
974 #define USAGE_OP_DONT_FRAGMNT (1<<0)    /* F  */
975 #define USAGE_OP_USE_ICMP     (1<<1)    /* I  */
976 #define USAGE_OP_TTL_FLAG     (1<<2)    /* l  */
977 #define USAGE_OP_ADDR_NUM     (1<<3)    /* n  */
978 #define USAGE_OP_BYPASS_ROUTE (1<<4)    /* r  */
979 #define USAGE_OP_DEBUG        (1<<5)    /* d */
980 #define USAGE_OP_VERBOSE      (1<<6)    /* v */
981 #define USAGE_OP_IP_CHKSUM    (1<<7)    /* x */
982
983 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
984                                         "g:"
985 #endif
986         , &tos_str, &device, &max_ttl_str, &port_str, &nprobes_str,
987         &source, &waittime_str, &pausemsecs_str, &first_ttl_str
988 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
989         , &sourse_route_list
990 #endif
991         );
992
993         if(op & USAGE_OP_DONT_FRAGMNT)
994                 off = IP_DF;
995 #ifdef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
996         useicmp = op & USAGE_OP_USE_ICMP;
997 #endif
998         nflag = op & USAGE_OP_ADDR_NUM;
999 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
1000         verbose = op &  USAGE_OP_VERBOSE;
1001 #endif
1002         if(op & USAGE_OP_IP_CHKSUM) {
1003                 doipcksum = 0;
1004                 bb_error_msg("Warning: ip checksums disabled");
1005         }
1006         if (tos_str)
1007                 tos = str2val(tos_str, "tos", 0, 255);
1008         if(max_ttl_str)
1009                 max_ttl = str2val(max_ttl_str, "max ttl", 1, 255);
1010         if(port_str)
1011                 port = (u_short)str2val(port_str, "port", 1, (1 << 16) - 1);
1012         if(nprobes_str)
1013                 nprobes = str2val(optarg, "nprobes", 1, -1);
1014         if(source) {
1015             /*
1016              * set the ip source address of the outbound
1017              * probe (e.g., on a multi-homed host).
1018              */
1019              if (uid)
1020                 bb_error_msg_and_die("-s %s: Permission denied", source);
1021         }
1022         if(waittime_str)
1023                 waittime = str2val(waittime_str, "wait time", 2, 24 * 60 * 60);
1024         if(pausemsecs_str)
1025                 pausemsecs = str2val(pausemsecs_str, "pause msecs", 0, 60 * 60 * 1000);
1026         if(first_ttl_str)
1027                 first_ttl = str2val(first_ttl_str, "first ttl", 1, 255);
1028
1029 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
1030         if(sourse_route_list) {
1031                 llist_t *l_sr;
1032
1033                 for(l_sr = sourse_route_list; l_sr; ) {
1034                         if (lsrr >= NGATEWAYS)
1035                                 bb_error_msg_and_die("No more than %d gateways", NGATEWAYS);
1036                         getaddr(gwlist + lsrr, l_sr->data);
1037                         ++lsrr;
1038                         l_sr = l_sr->link;
1039                         free(sourse_route_list);
1040                         sourse_route_list = l_sr;
1041                 }
1042                 optlen = (lsrr + 1) * sizeof(gwlist[0]);
1043         }
1044 #endif
1045
1046         if (first_ttl > max_ttl) {
1047                 bb_error_msg_and_die(
1048                     "first ttl (%d) may not be greater than max ttl (%d)",
1049                     first_ttl, max_ttl);
1050         }
1051
1052         minpacket = sizeof(*outip) + sizeof(*outdata) + optlen;
1053
1054 #ifdef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
1055         if (useicmp)
1056                 minpacket += 8;                 /* XXX magic number */
1057         else
1058 #endif
1059                 minpacket += sizeof(*outudp);
1060         packlen = minpacket;                    /* minimum sized packet */
1061
1062         /* Process destination and optional packet size */
1063         switch (argc - optind) {
1064
1065         case 2:
1066                 packlen = str2val(argv[optind + 1],
1067                     "packet length", minpacket, maxpacket);
1068                 /* Fall through */
1069
1070         case 1:
1071                 hostname = argv[optind];
1072                 hi = gethostinfo(hostname);
1073                 setsin(to, hi->addrs[0]);
1074                 if (hi->n > 1)
1075                         bb_error_msg(
1076                     "Warning: %s has multiple addresses; using %s",
1077                                 hostname, inet_ntoa(to->sin_addr));
1078                 hostname = hi->name;
1079                 hi->name = NULL;
1080                 freehostinfo(hi);
1081                 break;
1082
1083         default:
1084                 bb_show_usage();
1085         }
1086
1087         cp = "icmp";
1088         if ((pe = getprotobyname(cp)) == NULL)
1089                 bb_perror_msg_and_die("unknown protocol %s", cp);
1090
1091         /* Insure the socket fds won't be 0, 1 or 2 */
1092         do n = bb_xopen(bb_dev_null, O_RDONLY); while (n < 2);
1093         if (n > 2)
1094                 close(n);
1095
1096         if ((s = socket(AF_INET, SOCK_RAW, pe->p_proto)) < 0)
1097                 bb_perror_msg_and_die(bb_msg_can_not_create_raw_socket);
1098
1099 #ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
1100         if (op & USAGE_OP_DEBUG)
1101                 (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&on,
1102                     sizeof(on));
1103 #endif
1104         if (op & USAGE_OP_BYPASS_ROUTE)
1105                 (void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
1106                     sizeof(on));
1107
1108         sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
1109         if (sndsock < 0)
1110                 bb_perror_msg_and_die(bb_msg_can_not_create_raw_socket);
1111
1112 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
1113 #if defined(IP_OPTIONS)
1114         if (lsrr > 0) {
1115                 u_char optlist[MAX_IPOPTLEN];
1116
1117                 cp = "ip";
1118                 if ((pe = getprotobyname(cp)) == NULL)
1119                         bb_perror_msg_and_die("unknown protocol");
1120
1121                 /* final hop */
1122                 gwlist[lsrr] = to->sin_addr.s_addr;
1123                 ++lsrr;
1124
1125                 /* force 4 byte alignment */
1126                 optlist[0] = IPOPT_NOP;
1127                 /* loose source route option */
1128                 optlist[1] = IPOPT_LSRR;
1129                 i = lsrr * sizeof(gwlist[0]);
1130                 optlist[2] = i + 3;
1131                 /* Pointer to LSRR addresses */
1132                 optlist[3] = IPOPT_MINOFF;
1133                 memcpy(optlist + 4, gwlist, i);
1134
1135                 if ((setsockopt(sndsock, pe->p_proto, IP_OPTIONS,
1136                     (char *)optlist, i + sizeof(gwlist[0]))) < 0) {
1137                         bb_perror_msg_and_die("IP_OPTIONS");
1138                     }
1139         }
1140 #endif /* IP_OPTIONS */
1141 #endif /* CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE */
1142
1143 #ifdef SO_SNDBUF
1144         if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&packlen,
1145             sizeof(packlen)) < 0) {
1146                 bb_perror_msg_and_die("SO_SNDBUF");
1147         }
1148 #endif
1149 #ifdef IP_HDRINCL
1150         if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
1151             sizeof(on)) < 0 && errno != ENOPROTOOPT) {
1152                 bb_perror_msg_and_die("IP_HDRINCL");
1153         }
1154 #else
1155 #ifdef IP_TOS
1156         if (tos_str && setsockopt(sndsock, IPPROTO_IP, IP_TOS,
1157             (char *)&tos, sizeof(tos)) < 0) {
1158                 bb_perror_msg_and_die("setsockopt tos %d", tos);
1159         }
1160 #endif
1161 #endif
1162 #ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
1163         if (op & USAGE_OP_DEBUG)
1164                 (void)setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, (char *)&on,
1165                     sizeof(on));
1166 #endif
1167         if (op & USAGE_OP_BYPASS_ROUTE)
1168                 (void)setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
1169                     sizeof(on));
1170
1171         /* Revert to non-privileged user after opening sockets */
1172         setgid(getgid());
1173         setuid(uid);
1174
1175         outip = (struct ip *)xcalloc(1, (unsigned)packlen);
1176
1177         outip->ip_v = IPVERSION;
1178         if (tos_str)
1179                 outip->ip_tos = tos;
1180         outip->ip_len = htons(packlen);
1181         outip->ip_off = htons(off);
1182         outp = (u_char *)(outip + 1);
1183         outip->ip_dst = to->sin_addr;
1184
1185         outip->ip_hl = (outp - (u_char *)outip) >> 2;
1186         ident = (getpid() & 0xffff) | 0x8000;
1187 #ifdef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
1188         if (useicmp) {
1189                 outip->ip_p = IPPROTO_ICMP;
1190
1191                 outicmp = (struct icmp *)outp;
1192                 outicmp->icmp_type = ICMP_ECHO;
1193                 outicmp->icmp_id = htons(ident);
1194
1195                 outdata = (struct outdata *)(outp + 8); /* XXX magic number */
1196         } else
1197 #endif
1198                {
1199                 outip->ip_p = IPPROTO_UDP;
1200
1201                 outudp = (struct udphdr *)outp;
1202                 outudp->source = htons(ident);
1203                 outudp->len =
1204                     htons((u_short)(packlen - (sizeof(*outip) + optlen)));
1205                 outdata = (struct outdata *)(outudp + 1);
1206         }
1207
1208         /* Get the interface address list */
1209         n = ifaddrlist(&al);
1210
1211         /* Look for a specific device */
1212         if (device != NULL) {
1213                 for (i = n; i > 0; --i, ++al)
1214                         if (strcmp(device, al->device) == 0)
1215                                 break;
1216                 if (i <= 0) {
1217                         bb_error_msg_and_die("Can't find interface %s", device);
1218                 }
1219         }
1220
1221         /* Determine our source address */
1222         if (source == NULL) {
1223                 /*
1224                  * If a device was specified, use the interface address.
1225                  * Otherwise, try to determine our source address.
1226                  */
1227                 if (device != NULL)
1228                         setsin(from, al->addr);
1229                 findsaddr(to, from);
1230         } else {
1231                 hi = gethostinfo(source);
1232                 source = hi->name;
1233                 hi->name = NULL;
1234                 /*
1235                  * If the device was specified make sure it
1236                  * corresponds to the source address specified.
1237                  * Otherwise, use the first address (and warn if
1238                  * there are more than one).
1239                  */
1240                 if (device != NULL) {
1241                         for (i = hi->n, ap = hi->addrs; i > 0; --i, ++ap)
1242                                 if (*ap == al->addr)
1243                                         break;
1244                         if (i <= 0) {
1245                                 bb_error_msg_and_die(
1246                                     "%s is not on interface %s",
1247                                     source, device);
1248                         }
1249                         setsin(from, *ap);
1250                 } else {
1251                         setsin(from, hi->addrs[0]);
1252                         if (hi->n > 1)
1253                                 bb_error_msg(
1254                         "Warning: %s has multiple addresses; using %s",
1255                                     source, inet_ntoa(from->sin_addr));
1256                 }
1257                 freehostinfo(hi);
1258         }
1259
1260         outip->ip_src = from->sin_addr;
1261 #ifndef IP_HDRINCL
1262         if (bind(sndsock, (struct sockaddr *)from, sizeof(*from)) < 0) {
1263                 bb_perror_msg_and_die("bind");
1264         }
1265 #endif
1266
1267         fprintf(stderr, "traceroute to %s (%s)", hostname, inet_ntoa(to->sin_addr));
1268         if (source)
1269                 fprintf(stderr, " from %s", source);
1270         fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, packlen);
1271         (void)fflush(stderr);
1272
1273         for (ttl = first_ttl; ttl <= max_ttl; ++ttl) {
1274                 u_int32_t lastaddr = 0;
1275                 int gotlastaddr = 0;
1276                 int got_there = 0;
1277                 int unreachable = 0;
1278                 int sentfirst = 0;
1279
1280                 printf("%2d ", ttl);
1281                 for (probe = 0; probe < nprobes; ++probe) {
1282                         int cc;
1283                         struct timeval t1, t2;
1284                         struct timezone tz;
1285                         struct ip *ip;
1286
1287                         if (sentfirst && pausemsecs > 0)
1288                                 usleep(pausemsecs * 1000);
1289                         (void)gettimeofday(&t1, &tz);
1290                         send_probe(++seq, ttl, &t1);
1291                         ++sentfirst;
1292                         while ((cc = wait_for_reply(s, from, &t1)) != 0) {
1293                                 (void)gettimeofday(&t2, &tz);
1294                                 i = packet_ok(packet, cc, from, seq);
1295                                 /* Skip short packet */
1296                                 if (i == 0)
1297                                         continue;
1298                                 if (!gotlastaddr ||
1299                                     from->sin_addr.s_addr != lastaddr) {
1300                                         print(packet, cc, from);
1301                                         lastaddr = from->sin_addr.s_addr;
1302                                         ++gotlastaddr;
1303                                 }
1304                                 printf("  %.3f ms", deltaT(&t1, &t2));
1305                                 ip = (struct ip *)packet;
1306                                 if (op & USAGE_OP_TTL_FLAG)
1307                                         printf(" (%d)", ip->ip_ttl);
1308                                 if (i == -2) {
1309                                         if (ip->ip_ttl <= 1)
1310                                                 printf(" !");
1311                                         ++got_there;
1312                                         break;
1313                                 }
1314                                 /* time exceeded in transit */
1315                                 if (i == -1)
1316                                         break;
1317                                 code = i - 1;
1318                                 switch (code) {
1319
1320                                 case ICMP_UNREACH_PORT:
1321                                         if (ip->ip_ttl <= 1)
1322                                                 printf(" !");
1323                                         ++got_there;
1324                                         break;
1325
1326                                 case ICMP_UNREACH_NET:
1327                                         ++unreachable;
1328                                         printf(" !N");
1329                                         break;
1330
1331                                 case ICMP_UNREACH_HOST:
1332                                         ++unreachable;
1333                                         printf(" !H");
1334                                         break;
1335
1336                                 case ICMP_UNREACH_PROTOCOL:
1337                                         ++got_there;
1338                                         printf(" !P");
1339                                         break;
1340
1341                                 case ICMP_UNREACH_NEEDFRAG:
1342                                         ++unreachable;
1343                                         printf(" !F-%d", pmtu);
1344                                         break;
1345
1346                                 case ICMP_UNREACH_SRCFAIL:
1347                                         ++unreachable;
1348                                         printf(" !S");
1349                                         break;
1350
1351                                 case ICMP_UNREACH_FILTER_PROHIB:
1352                                 case ICMP_UNREACH_NET_PROHIB:   /* misuse */
1353                                         ++unreachable;
1354                                         printf(" !A");
1355                                         break;
1356
1357                                 case ICMP_UNREACH_HOST_PROHIB:
1358                                         ++unreachable;
1359                                         printf(" !C");
1360                                         break;
1361
1362                                 case ICMP_UNREACH_HOST_PRECEDENCE:
1363                                         ++unreachable;
1364                                         printf(" !V");
1365                                         break;
1366
1367                                 case ICMP_UNREACH_PRECEDENCE_CUTOFF:
1368                                         ++unreachable;
1369                                         printf(" !C");
1370                                         break;
1371
1372                                 case ICMP_UNREACH_NET_UNKNOWN:
1373                                 case ICMP_UNREACH_HOST_UNKNOWN:
1374                                         ++unreachable;
1375                                         printf(" !U");
1376                                         break;
1377
1378                                 case ICMP_UNREACH_ISOLATED:
1379                                         ++unreachable;
1380                                         printf(" !I");
1381                                         break;
1382
1383                                 case ICMP_UNREACH_TOSNET:
1384                                 case ICMP_UNREACH_TOSHOST:
1385                                         ++unreachable;
1386                                         printf(" !T");
1387                                         break;
1388
1389                                 default:
1390                                         ++unreachable;
1391                                         printf(" !<%d>", code);
1392                                         break;
1393                                 }
1394                                 break;
1395                         }
1396                         if (cc == 0)
1397                                 printf(" *");
1398                         (void)fflush(stdout);
1399                 }
1400                 putchar('\n');
1401                 if (got_there ||
1402                     (unreachable > 0 && unreachable >= nprobes - 1))
1403                         break;
1404         }
1405         return 0;
1406 }