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