busybox/networking/traceroute.c
<<
>>
Prefs
   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/*
  26 *      traceroute6
  27 *
  28 *      Modified for NRL 4.4BSD IPv6 release.
  29 *      07/31/96 bgp
  30 *
  31 *      Modified for Linux IPv6 by Pedro Roque <roque@di.fc.ul.pt>
  32 *      31/07/1996
  33 *
  34 *      As ICMP error messages for IPv6 now include more than 8 bytes
  35 *      UDP datagrams are now sent via an UDP socket instead of magic
  36 *      RAW socket tricks.
  37 *
  38 *      Converted to busybox applet by Leonid Lisovskiy <lly@sf.net>
  39 *      2009-11-16
  40 */
  41
  42/*
  43 * traceroute host  - trace the route ip packets follow going to "host".
  44 *
  45 * Attempt to trace the route an ip packet would follow to some
  46 * internet host.  We find out intermediate hops by launching probe
  47 * packets with a small ttl (time to live) then listening for an
  48 * icmp "time exceeded" reply from a gateway.  We start our probes
  49 * with a ttl of one and increase by one until we get an icmp "port
  50 * unreachable" (which means we got to "host") or hit a max (which
  51 * defaults to 30 hops & can be changed with the -m flag).  Three
  52 * probes (change with -q flag) are sent at each ttl setting and a
  53 * line is printed showing the ttl, address of the gateway and
  54 * round trip time of each probe.  If the probe answers come from
  55 * different gateways, the address of each responding system will
  56 * be printed.  If there is no response within a 5 sec. timeout
  57 * interval (changed with the -w flag), a "*" is printed for that
  58 * probe.
  59 *
  60 * Probe packets are UDP format.  We don't want the destination
  61 * host to process them so the destination port is set to an
  62 * unlikely value (if some clod on the destination is using that
  63 * value, it can be changed with the -p flag).
  64 *
  65 * A sample use might be:
  66 *
  67 *     [yak 71]% traceroute nis.nsf.net.
  68 *     traceroute to nis.nsf.net (35.1.1.48), 30 hops max, 56 byte packet
  69 *      1  helios.ee.lbl.gov (128.3.112.1)  19 ms  19 ms  0 ms
  70 *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  39 ms  19 ms
  71 *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  39 ms  19 ms
  72 *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  39 ms  40 ms  39 ms
  73 *      5  ccn-nerif22.Berkeley.EDU (128.32.168.22)  39 ms  39 ms  39 ms
  74 *      6  128.32.197.4 (128.32.197.4)  40 ms  59 ms  59 ms
  75 *      7  131.119.2.5 (131.119.2.5)  59 ms  59 ms  59 ms
  76 *      8  129.140.70.13 (129.140.70.13)  99 ms  99 ms  80 ms
  77 *      9  129.140.71.6 (129.140.71.6)  139 ms  239 ms  319 ms
  78 *     10  129.140.81.7 (129.140.81.7)  220 ms  199 ms  199 ms
  79 *     11  nic.merit.edu (35.1.1.48)  239 ms  239 ms  239 ms
  80 *
  81 * Note that lines 2 & 3 are the same.  This is due to a buggy
  82 * kernel on the 2nd hop system -- lbl-csam.arpa -- that forwards
  83 * packets with a zero ttl.
  84 *
  85 * A more interesting example is:
  86 *
  87 *     [yak 72]% traceroute allspice.lcs.mit.edu.
  88 *     traceroute to allspice.lcs.mit.edu (18.26.0.115), 30 hops max
  89 *      1  helios.ee.lbl.gov (128.3.112.1)  0 ms  0 ms  0 ms
  90 *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  19 ms  19 ms  19 ms
  91 *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  19 ms  19 ms
  92 *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  19 ms  39 ms  39 ms
  93 *      5  ccn-nerif22.Berkeley.EDU (128.32.168.22)  20 ms  39 ms  39 ms
  94 *      6  128.32.197.4 (128.32.197.4)  59 ms  119 ms  39 ms
  95 *      7  131.119.2.5 (131.119.2.5)  59 ms  59 ms  39 ms
  96 *      8  129.140.70.13 (129.140.70.13)  80 ms  79 ms  99 ms
  97 *      9  129.140.71.6 (129.140.71.6)  139 ms  139 ms  159 ms
  98 *     10  129.140.81.7 (129.140.81.7)  199 ms  180 ms  300 ms
  99 *     11  129.140.72.17 (129.140.72.17)  300 ms  239 ms  239 ms
 100 *     12  * * *
 101 *     13  128.121.54.72 (128.121.54.72)  259 ms  499 ms  279 ms
 102 *     14  * * *
 103 *     15  * * *
 104 *     16  * * *
 105 *     17  * * *
 106 *     18  ALLSPICE.LCS.MIT.EDU (18.26.0.115)  339 ms  279 ms  279 ms
 107 *
 108 * (I start to see why I'm having so much trouble with mail to
 109 * MIT.)  Note that the gateways 12, 14, 15, 16 & 17 hops away
 110 * either don't send ICMP "time exceeded" messages or send them
 111 * with a ttl too small to reach us.  14 - 17 are running the
 112 * MIT C Gateway code that doesn't send "time exceeded"s.  God
 113 * only knows what's going on with 12.
 114 *
 115 * The silent gateway 12 in the above may be the result of a bug in
 116 * the 4.[23]BSD network code (and its derivatives):  4.x (x <= 3)
 117 * sends an unreachable message using whatever ttl remains in the
 118 * original datagram.  Since, for gateways, the remaining ttl is
 119 * zero, the icmp "time exceeded" is guaranteed to not make it back
 120 * to us.  The behavior of this bug is slightly more interesting
 121 * when it appears on the destination system:
 122 *
 123 *      1  helios.ee.lbl.gov (128.3.112.1)  0 ms  0 ms  0 ms
 124 *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  19 ms  39 ms
 125 *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  19 ms  39 ms  19 ms
 126 *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  39 ms  40 ms  19 ms
 127 *      5  ccn-nerif35.Berkeley.EDU (128.32.168.35)  39 ms  39 ms  39 ms
 128 *      6  csgw.Berkeley.EDU (128.32.133.254)  39 ms  59 ms  39 ms
 129 *      7  * * *
 130 *      8  * * *
 131 *      9  * * *
 132 *     10  * * *
 133 *     11  * * *
 134 *     12  * * *
 135 *     13  rip.Berkeley.EDU (128.32.131.22)  59 ms !  39 ms !  39 ms !
 136 *
 137 * Notice that there are 12 "gateways" (13 is the final
 138 * destination) and exactly the last half of them are "missing".
 139 * What's really happening is that rip (a Sun-3 running Sun OS3.5)
 140 * is using the ttl from our arriving datagram as the ttl in its
 141 * icmp reply.  So, the reply will time out on the return path
 142 * (with no notice sent to anyone since icmp's aren't sent for
 143 * icmp's) until we probe with a ttl that's at least twice the path
 144 * length.  I.e., rip is really only 7 hops away.  A reply that
 145 * returns with a ttl of 1 is a clue this problem exists.
 146 * Traceroute prints a "!" after the time if the ttl is <= 1.
 147 * Since vendors ship a lot of obsolete (DEC's Ultrix, Sun 3.x) or
 148 * non-standard (HPUX) software, expect to see this problem
 149 * frequently and/or take care picking the target host of your
 150 * probes.
 151 *
 152 * Other possible annotations after the time are !H, !N, !P (got a host,
 153 * network or protocol unreachable, respectively), !S or !F (source
 154 * route failed or fragmentation needed -- neither of these should
 155 * ever occur and the associated gateway is busted if you see one).  If
 156 * almost all the probes result in some kind of unreachable, traceroute
 157 * will give up and exit.
 158 *
 159 * Notes
 160 * -----
 161 * This program must be run by root or be setuid.  (I suggest that
 162 * you *don't* make it setuid -- casual use could result in a lot
 163 * of unnecessary traffic on our poor, congested nets.)
 164 *
 165 * This program requires a kernel mod that does not appear in any
 166 * system available from Berkeley:  A raw ip socket using proto
 167 * IPPROTO_RAW must interpret the data sent as an ip datagram (as
 168 * opposed to data to be wrapped in a ip datagram).  See the README
 169 * file that came with the source to this program for a description
 170 * of the mods I made to /sys/netinet/raw_ip.c.  Your mileage may
 171 * vary.  But, again, ANY 4.x (x < 4) BSD KERNEL WILL HAVE TO BE
 172 * MODIFIED TO RUN THIS PROGRAM.
 173 *
 174 * The udp port usage may appear bizarre (well, ok, it is bizarre).
 175 * The problem is that an icmp message only contains 8 bytes of
 176 * data from the original datagram.  8 bytes is the size of a udp
 177 * header so, if we want to associate replies with the original
 178 * datagram, the necessary information must be encoded into the
 179 * udp header (the ip id could be used but there's no way to
 180 * interlock with the kernel's assignment of ip id's and, anyway,
 181 * it would have taken a lot more kernel hacking to allow this
 182 * code to set the ip id).  So, to allow two or more users to
 183 * use traceroute simultaneously, we use this task's pid as the
 184 * source port (the high bit is set to move the port number out
 185 * of the "likely" range).  To keep track of which probe is being
 186 * replied to (so times and/or hop counts don't get confused by a
 187 * reply that was delayed in transit), we increment the destination
 188 * port number before each probe.
 189 *
 190 * Don't use this as a coding example.  I was trying to find a
 191 * routing problem and this code sort-of popped out after 48 hours
 192 * without sleep.  I was amazed it ever compiled, much less ran.
 193 *
 194 * I stole the idea for this program from Steve Deering.  Since
 195 * the first release, I've learned that had I attended the right
 196 * IETF working group meetings, I also could have stolen it from Guy
 197 * Almes or Matt Mathis.  I don't know (or care) who came up with
 198 * the idea first.  I envy the originators' perspicacity and I'm
 199 * glad they didn't keep the idea a secret.
 200 *
 201 * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or
 202 * enhancements to the original distribution.
 203 *
 204 * I've hacked up a round-trip-route version of this that works by
 205 * sending a loose-source-routed udp datagram through the destination
 206 * back to yourself.  Unfortunately, SO many gateways botch source
 207 * routing, the thing is almost worthless.  Maybe one day...
 208 *
 209 *  -- Van Jacobson (van@ee.lbl.gov)
 210 *     Tue Dec 20 03:50:13 PST 1988
 211 */
 212
 213//usage:#define traceroute_trivial_usage
 214//usage:       "[-"IF_TRACEROUTE6("46")"FIldnrv] [-f 1ST_TTL] [-m MAXTTL] [-p PORT] [-q PROBES]\n"
 215//usage:       "        [-s SRC_IP] [-t TOS] [-w WAIT_SEC] [-g GATEWAY] [-i IFACE]\n"
 216//usage:       "        [-z PAUSE_MSEC] HOST [BYTES]"
 217//usage:#define traceroute_full_usage "\n\n"
 218//usage:       "Trace the route to HOST\n"
 219//usage:        IF_TRACEROUTE6(
 220//usage:     "\n        -4,-6   Force IP or IPv6 name resolution"
 221//usage:        )
 222//usage:     "\n        -F      Set the don't fragment bit"
 223//usage:     "\n        -I      Use ICMP ECHO instead of UDP datagrams"
 224//usage:     "\n        -l      Display the TTL value of the returned packet"
 225//usage:     "\n        -d      Set SO_DEBUG options to socket"
 226//usage:     "\n        -n      Print numeric addresses"
 227//usage:     "\n        -r      Bypass routing tables, send directly to HOST"
 228//usage:     "\n        -v      Verbose"
 229//usage:     "\n        -m      Max time-to-live (max number of hops)"
 230//usage:     "\n        -p      Base UDP port number used in probes"
 231//usage:     "\n                (default 33434)"
 232//usage:     "\n        -q      Number of probes per TTL (default 3)"
 233//usage:     "\n        -s      IP address to use as the source address"
 234//usage:     "\n        -t      Type-of-service in probe packets (default 0)"
 235//usage:     "\n        -w      Time in seconds to wait for a response (default 3)"
 236//usage:     "\n        -g      Loose source route gateway (8 max)"
 237//usage:
 238//usage:#define traceroute6_trivial_usage
 239//usage:       "[-dnrv] [-m MAXTTL] [-p PORT] [-q PROBES]\n"
 240//usage:       "        [-s SRC_IP] [-t TOS] [-w WAIT_SEC] [-i IFACE]\n"
 241//usage:       "        HOST [BYTES]"
 242//usage:#define traceroute6_full_usage "\n\n"
 243//usage:       "Trace the route to HOST\n"
 244//usage:     "\n        -d      Set SO_DEBUG options to socket"
 245//usage:     "\n        -n      Print numeric addresses"
 246//usage:     "\n        -r      Bypass routing tables, send directly to HOST"
 247//usage:     "\n        -v      Verbose"
 248//usage:     "\n        -m      Max time-to-live (max number of hops)"
 249//usage:     "\n        -p      Base UDP port number used in probes"
 250//usage:     "\n                (default is 33434)"
 251//usage:     "\n        -q      Number of probes per TTL (default 3)"
 252//usage:     "\n        -s      IP address to use as the source address"
 253//usage:     "\n        -t      Type-of-service in probe packets (default 0)"
 254//usage:     "\n        -w      Time in seconds to wait for a response (default 3)"
 255
 256#define TRACEROUTE_SO_DEBUG 0
 257
 258/* TODO: undefs were uncommented - ??! we have config system for that! */
 259/* probably ok to remove altogether */
 260//#undef CONFIG_FEATURE_TRACEROUTE_VERBOSE
 261//#define CONFIG_FEATURE_TRACEROUTE_VERBOSE
 262//#undef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
 263//#define CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
 264//#undef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
 265//#define CONFIG_FEATURE_TRACEROUTE_USE_ICMP
 266
 267
 268#include <net/if.h>
 269#include <arpa/inet.h>
 270#include <netinet/in.h>
 271#include <netinet/udp.h>
 272#include <netinet/ip.h>
 273#include <netinet/ip_icmp.h>
 274#if ENABLE_FEATURE_IPV6
 275# include <netinet/ip6.h>
 276# include <netinet/icmp6.h>
 277# ifndef SOL_IPV6
 278#  define SOL_IPV6 IPPROTO_IPV6
 279# endif
 280#endif
 281
 282#include "libbb.h"
 283#include "inet_common.h"
 284
 285#ifndef IPPROTO_ICMP
 286# define IPPROTO_ICMP 1
 287#endif
 288#ifndef IPPROTO_IP
 289# define IPPROTO_IP 0
 290#endif
 291
 292
 293#define OPT_STRING \
 294        "FIlnrdvxt:i:m:p:q:s:w:z:f:" \
 295        IF_FEATURE_TRACEROUTE_SOURCE_ROUTE("g:") \
 296        "4" IF_TRACEROUTE6("6")
 297enum {
 298        OPT_DONT_FRAGMNT = (1 << 0),    /* F */
 299        OPT_USE_ICMP     = (1 << 1) * ENABLE_FEATURE_TRACEROUTE_USE_ICMP, /* I */
 300        OPT_TTL_FLAG     = (1 << 2),    /* l */
 301        OPT_ADDR_NUM     = (1 << 3),    /* n */
 302        OPT_BYPASS_ROUTE = (1 << 4),    /* r */
 303        OPT_DEBUG        = (1 << 5),    /* d */
 304        OPT_VERBOSE      = (1 << 6) * ENABLE_FEATURE_TRACEROUTE_VERBOSE, /* v */
 305        OPT_IP_CHKSUM    = (1 << 7),    /* x */
 306        OPT_TOS          = (1 << 8),    /* t */
 307        OPT_DEVICE       = (1 << 9),    /* i */
 308        OPT_MAX_TTL      = (1 << 10),   /* m */
 309        OPT_PORT         = (1 << 11),   /* p */
 310        OPT_NPROBES      = (1 << 12),   /* q */
 311        OPT_SOURCE       = (1 << 13),   /* s */
 312        OPT_WAITTIME     = (1 << 14),   /* w */
 313        OPT_PAUSE_MS     = (1 << 15),   /* z */
 314        OPT_FIRST_TTL    = (1 << 16),   /* f */
 315        OPT_SOURCE_ROUTE = (1 << 17) * ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE, /* g */
 316        OPT_IPV4         = (1 << (17+ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE)),   /* 4 */
 317        OPT_IPV6         = (1 << (18+ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE)) * ENABLE_TRACEROUTE6, /* 6 */
 318};
 319#define verbose (option_mask32 & OPT_VERBOSE)
 320
 321enum {
 322        SIZEOF_ICMP_HDR = 8,
 323        rcvsock = 3, /* receive (icmp) socket file descriptor */
 324        sndsock = 4, /* send (udp/icmp) socket file descriptor */
 325};
 326
 327/* Data section of the probe packet */
 328struct outdata_t {
 329        unsigned char seq;             /* sequence number of this packet */
 330        unsigned char ttl;             /* ttl packet left with */
 331// UNUSED. Retaining to have the same packet size.
 332        struct timeval tv_UNUSED PACKED; /* time packet left */
 333};
 334
 335#if ENABLE_TRACEROUTE6
 336struct outdata6_t {
 337        uint32_t ident6;
 338        uint32_t seq6;
 339        struct timeval tv_UNUSED PACKED; /* time packet left */
 340};
 341#endif
 342
 343struct globals {
 344        struct ip *outip;
 345        struct outdata_t *outdata;
 346        len_and_sockaddr *dest_lsa;
 347        int packlen;                    /* total length of packet */
 348        int pmtu;                       /* Path MTU Discovery (RFC1191) */
 349        uint32_t ident;
 350        uint16_t port; // 32768 + 666;  /* start udp dest port # for probe packets */
 351        int waittime; // 5;             /* time to wait for response (in seconds) */
 352#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
 353        int optlen;                     /* length of ip options */
 354#else
 355#define optlen 0
 356#endif
 357        unsigned char recv_pkt[512];    /* last inbound (icmp) packet */
 358#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
 359        /* Maximum number of gateways (include room for one noop) */
 360#define NGATEWAYS ((int)((MAX_IPOPTLEN - IPOPT_MINOFF - 1) / sizeof(uint32_t)))
 361        /* loose source route gateway list (including room for final destination) */
 362        uint32_t gwlist[NGATEWAYS + 1];
 363#endif
 364};
 365
 366#define G (*ptr_to_globals)
 367#define outip     (G.outip    )
 368#define outdata   (G.outdata  )
 369#define dest_lsa  (G.dest_lsa )
 370#define packlen   (G.packlen  )
 371#define pmtu      (G.pmtu     )
 372#define ident     (G.ident    )
 373#define port      (G.port     )
 374#define waittime  (G.waittime )
 375#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
 376# define optlen   (G.optlen   )
 377#endif
 378#define recv_pkt  (G.recv_pkt )
 379#define gwlist    (G.gwlist   )
 380#define INIT_G() do { \
 381        SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
 382        port = 32768 + 666; \
 383        waittime = 5; \
 384} while (0)
 385
 386#define outicmp ((struct icmp *)(outip + 1))
 387#define outudp  ((struct udphdr *)(outip + 1))
 388
 389
 390/* libbb candidate? tftp uses this idiom too */
 391static len_and_sockaddr* dup_sockaddr(const len_and_sockaddr *lsa)
 392{
 393        len_and_sockaddr *new_lsa = xzalloc(LSA_LEN_SIZE + lsa->len);
 394        memcpy(new_lsa, lsa, LSA_LEN_SIZE + lsa->len);
 395        return new_lsa;
 396}
 397
 398
 399static int
 400wait_for_reply(len_and_sockaddr *from_lsa, struct sockaddr *to, unsigned *timestamp_us, int *left_ms)
 401{
 402        struct pollfd pfd[1];
 403        int read_len = 0;
 404
 405        pfd[0].fd = rcvsock;
 406        pfd[0].events = POLLIN;
 407        if (*left_ms >= 0 && safe_poll(pfd, 1, *left_ms) > 0) {
 408                unsigned t;
 409
 410                read_len = recv_from_to(rcvsock,
 411                                recv_pkt, sizeof(recv_pkt),
 412                                /*flags:*/ MSG_DONTWAIT,
 413                                &from_lsa->u.sa, to, from_lsa->len);
 414                t = monotonic_us();
 415                *left_ms -= (t - *timestamp_us) / 1000;
 416                *timestamp_us = t;
 417        }
 418
 419        return read_len;
 420}
 421
 422static void
 423send_probe(int seq, int ttl)
 424{
 425        int len, res;
 426        void *out;
 427
 428        /* Payload */
 429#if ENABLE_TRACEROUTE6
 430        if (dest_lsa->u.sa.sa_family == AF_INET6) {
 431                struct outdata6_t *pkt = (struct outdata6_t *) outip;
 432                pkt->ident6 = htonl(ident);
 433                pkt->seq6   = htonl(seq);
 434                /*gettimeofday(&pkt->tv, &tz);*/
 435        } else
 436#endif
 437        {
 438                outdata->seq = seq;
 439                outdata->ttl = ttl;
 440// UNUSED: was storing gettimeofday's result there, but never ever checked it
 441                /*memcpy(&outdata->tv, tp, sizeof(outdata->tv));*/
 442
 443                if (option_mask32 & OPT_USE_ICMP) {
 444                        outicmp->icmp_seq = htons(seq);
 445
 446                        /* Always calculate checksum for icmp packets */
 447                        outicmp->icmp_cksum = 0;
 448                        outicmp->icmp_cksum = inet_cksum((uint16_t *)outicmp,
 449                                                packlen - (sizeof(*outip) + optlen));
 450                        if (outicmp->icmp_cksum == 0)
 451                                outicmp->icmp_cksum = 0xffff;
 452                }
 453        }
 454
 455//BUG! verbose is (x & OPT_VERBOSE), not a counter!
 456#if 0 //ENABLE_FEATURE_TRACEROUTE_VERBOSE
 457        /* XXX undocumented debugging hack */
 458        if (verbose > 1) {
 459                const uint16_t *sp;
 460                int nshorts, i;
 461
 462                sp = (uint16_t *)outip;
 463                nshorts = (unsigned)packlen / sizeof(uint16_t);
 464                i = 0;
 465                printf("[ %d bytes", packlen);
 466                while (--nshorts >= 0) {
 467                        if ((i++ % 8) == 0)
 468                                printf("\n\t");
 469                        printf(" %04x", ntohs(*sp));
 470                        sp++;
 471                }
 472                if (packlen & 1) {
 473                        if ((i % 8) == 0)
 474                                printf("\n\t");
 475                        printf(" %02x", *(unsigned char *)sp);
 476                }
 477                printf("]\n");
 478        }
 479#endif
 480
 481#if ENABLE_TRACEROUTE6
 482        if (dest_lsa->u.sa.sa_family == AF_INET6) {
 483                res = setsockopt(sndsock, SOL_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl));
 484                if (res < 0)
 485                        bb_perror_msg_and_die("setsockopt UNICAST_HOPS %d", ttl);
 486                out = outip;
 487                len = packlen;
 488        } else
 489#endif
 490        {
 491#if defined IP_TTL
 492                res = setsockopt(sndsock, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
 493                if (res < 0)
 494                        bb_perror_msg_and_die("setsockopt ttl %d", ttl);
 495#endif
 496                out = outicmp;
 497                len = packlen - sizeof(*outip);
 498                if (!(option_mask32 & OPT_USE_ICMP)) {
 499                        out = outdata;
 500                        len -= sizeof(*outudp);
 501                        set_nport(&dest_lsa->u.sa, htons(port + seq));
 502                }
 503        }
 504
 505        res = xsendto(sndsock, out, len, &dest_lsa->u.sa, dest_lsa->len);
 506        if (res != len)
 507                bb_info_msg("sent %d octets, ret=%d", len, res);
 508}
 509
 510#if ENABLE_FEATURE_TRACEROUTE_VERBOSE
 511/*
 512 * Convert an ICMP "type" field to a printable string.
 513 */
 514static const char *
 515pr_type(unsigned char t)
 516{
 517        static const char *const ttab[] = {
 518        "Echo Reply",   "ICMP 1",       "ICMP 2",       "Dest Unreachable",
 519        "Source Quench", "Redirect",    "ICMP 6",       "ICMP 7",
 520        "Echo",         "Router Advert", "Router Solicit", "Time Exceeded",
 521        "Param Problem", "Timestamp",   "Timestamp Reply", "Info Request",
 522        "Info Reply",   "Mask Request", "Mask Reply"
 523        };
 524# if ENABLE_TRACEROUTE6
 525        static const char *const ttab6[] = {
 526[0]     "Error", "Dest Unreachable", "Packet Too Big", "Time Exceeded",
 527[4]     "Param Problem",
 528[8]     "Echo Request", "Echo Reply", "Membership Query", "Membership Report",
 529[12]    "Membership Reduction", "Router Solicit", "Router Advert", "Neighbor Solicit",
 530[16]    "Neighbor Advert", "Redirect",
 531        };
 532
 533        if (dest_lsa->u.sa.sa_family == AF_INET6) {
 534                if (t < 5)
 535                        return ttab6[t];
 536                if (t < 128 || t > ND_REDIRECT)
 537                        return "OUT-OF-RANGE";
 538                return ttab6[(t & 63) + 8];
 539        }
 540# endif
 541        if (t >= ARRAY_SIZE(ttab))
 542                return "OUT-OF-RANGE";
 543
 544        return ttab[t];
 545}
 546#endif
 547
 548#if !ENABLE_FEATURE_TRACEROUTE_VERBOSE
 549#define packet4_ok(read_len, from, seq) \
 550        packet4_ok(read_len, seq)
 551#endif
 552static int
 553packet4_ok(int read_len, const struct sockaddr_in *from, int seq)
 554{
 555        const struct icmp *icp;
 556        unsigned char type, code;
 557        int hlen;
 558        const struct ip *ip;
 559
 560        ip = (struct ip *) recv_pkt;
 561        hlen = ip->ip_hl << 2;
 562        if (read_len < hlen + ICMP_MINLEN) {
 563#if ENABLE_FEATURE_TRACEROUTE_VERBOSE
 564                if (verbose)
 565                        printf("packet too short (%d bytes) from %s\n", read_len,
 566                                inet_ntoa(from->sin_addr));
 567#endif
 568                return 0;
 569        }
 570        read_len -= hlen;
 571        icp = (struct icmp *)(recv_pkt + hlen);
 572        type = icp->icmp_type;
 573        code = icp->icmp_code;
 574        /* Path MTU Discovery (RFC1191) */
 575        pmtu = 0;
 576        if (code == ICMP_UNREACH_NEEDFRAG)
 577                pmtu = ntohs(icp->icmp_nextmtu);
 578
 579        if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS)
 580         || type == ICMP_UNREACH
 581         || type == ICMP_ECHOREPLY
 582        ) {
 583                const struct ip *hip;
 584                const struct udphdr *up;
 585
 586                hip = &icp->icmp_ip;
 587                hlen = hip->ip_hl << 2;
 588                if (option_mask32 & OPT_USE_ICMP) {
 589                        struct icmp *hicmp;
 590
 591                        /* XXX */
 592                        if (type == ICMP_ECHOREPLY
 593                         && icp->icmp_id == htons(ident)
 594                         && icp->icmp_seq == htons(seq)
 595                        ) {
 596                                return ICMP_UNREACH_PORT+1;
 597                        }
 598
 599                        hicmp = (struct icmp *)((unsigned char *)hip + hlen);
 600                        if (hlen + SIZEOF_ICMP_HDR <= read_len
 601                         && hip->ip_p == IPPROTO_ICMP
 602                         && hicmp->icmp_id == htons(ident)
 603                         && hicmp->icmp_seq == htons(seq)
 604                        ) {
 605                                return (type == ICMP_TIMXCEED ? -1 : code + 1);
 606                        }
 607                } else {
 608                        up = (struct udphdr *)((char *)hip + hlen);
 609                        if (hlen + 12 <= read_len
 610                         && hip->ip_p == IPPROTO_UDP
 611// Off: since we do not form the entire IP packet,
 612// but defer it to kernel, we can't set source port,
 613// and thus can't check it here in the reply
 614                        /* && up->source == htons(ident) */
 615                         && up->dest == htons(port + seq)
 616                        ) {
 617                                return (type == ICMP_TIMXCEED ? -1 : code + 1);
 618                        }
 619                }
 620        }
 621#if ENABLE_FEATURE_TRACEROUTE_VERBOSE
 622        if (verbose) {
 623                int i;
 624                uint32_t *lp = (uint32_t *)&icp->icmp_ip;
 625
 626                printf("\n%d bytes from %s to "
 627                       "%s: icmp type %d (%s) code %d\n",
 628                        read_len, inet_ntoa(from->sin_addr),
 629                        inet_ntoa(ip->ip_dst),
 630                        type, pr_type(type), icp->icmp_code);
 631                for (i = 4; i < read_len; i += sizeof(*lp))
 632                        printf("%2d: x%8.8x\n", i, *lp++);
 633        }
 634#endif
 635        return 0;
 636}
 637
 638#if ENABLE_TRACEROUTE6
 639# if !ENABLE_FEATURE_TRACEROUTE_VERBOSE
 640#define packet_ok(read_len, from_lsa, to, seq) \
 641        packet_ok(read_len, from_lsa, seq)
 642# endif
 643static int
 644packet_ok(int read_len, len_and_sockaddr *from_lsa,
 645                        struct sockaddr *to,
 646                        int seq)
 647{
 648        const struct icmp6_hdr *icp;
 649        unsigned char type, code;
 650
 651        if (from_lsa->u.sa.sa_family == AF_INET)
 652                return packet4_ok(read_len, &from_lsa->u.sin, seq);
 653
 654        icp = (struct icmp6_hdr *) recv_pkt;
 655
 656        type = icp->icmp6_type;
 657        code = icp->icmp6_code;
 658
 659        if ((type == ICMP6_TIME_EXCEEDED && code == ICMP6_TIME_EXCEED_TRANSIT)
 660         || type == ICMP6_DST_UNREACH
 661        ) {
 662                struct ip6_hdr *hip;
 663                struct udphdr *up;
 664                int nexthdr;
 665
 666                hip = (struct ip6_hdr *)(icp + 1);
 667                up  = (struct udphdr *) (hip + 1);
 668                nexthdr = hip->ip6_nxt;
 669
 670                if (nexthdr == IPPROTO_FRAGMENT) {
 671                        nexthdr = *(unsigned char*)up;
 672                        up++;
 673                }
 674                if (nexthdr == IPPROTO_UDP) {
 675                        struct outdata6_t *pkt;
 676
 677                        pkt = (struct outdata6_t *) (up + 1);
 678
 679                        if (ntohl(pkt->ident6) == ident
 680                         && ntohl(pkt->seq6) == seq
 681                        ) {
 682                                return (type == ICMP6_TIME_EXCEEDED ? -1 : (code<<8)+1);
 683                        }
 684                }
 685        }
 686
 687# if ENABLE_FEATURE_TRACEROUTE_VERBOSE
 688        if (verbose) {
 689                unsigned char *p;
 690                char pa1[MAXHOSTNAMELEN];
 691                char pa2[MAXHOSTNAMELEN];
 692                int i;
 693
 694                p = (unsigned char *) (icp + 1);
 695
 696                printf("\n%d bytes from %s to "
 697                       "%s: icmp type %d (%s) code %d\n",
 698                        read_len,
 699                        inet_ntop(AF_INET6, &from_lsa->u.sin6.sin6_addr, pa1, sizeof(pa1)),
 700                        inet_ntop(AF_INET6, &((struct sockaddr_in6*)to)->sin6_addr, pa2, sizeof(pa2)),
 701                        type, pr_type(type), icp->icmp6_code);
 702
 703                read_len -= sizeof(struct icmp6_hdr);
 704                for (i = 0; i < read_len; i++) {
 705                        if (i % 16 == 0)
 706                                printf("%04x:", i);
 707                        if (i % 4 == 0)
 708                                bb_putchar(' ');
 709                        printf("%02x", p[i]);
 710                        if ((i % 16 == 15) && (i + 1 < read_len))
 711                                bb_putchar('\n');
 712                }
 713                bb_putchar('\n');
 714        }
 715# endif
 716
 717        return 0;
 718}
 719#else /* !ENABLE_TRACEROUTE6 */
 720static ALWAYS_INLINE int
 721packet_ok(int read_len,
 722                len_and_sockaddr *from_lsa IF_NOT_FEATURE_TRACEROUTE_VERBOSE(UNUSED_PARAM),
 723                struct sockaddr *to UNUSED_PARAM,
 724                int seq)
 725{
 726        return packet4_ok(read_len, &from_lsa->u.sin, seq);
 727}
 728#endif
 729
 730/*
 731 * Construct an Internet address representation.
 732 * If the -n flag has been supplied, give
 733 * numeric value, otherwise try for symbolic name.
 734 */
 735static void
 736print_inetname(const struct sockaddr *from)
 737{
 738        char *ina = xmalloc_sockaddr2dotted_noport(from);
 739
 740        if (option_mask32 & OPT_ADDR_NUM) {
 741                printf("  %s", ina);
 742        } else {
 743                char *n = NULL;
 744
 745                if (from->sa_family != AF_INET
 746                 || ((struct sockaddr_in*)from)->sin_addr.s_addr != INADDR_ANY
 747                ) {
 748                        /* Try to reverse resolve if it is not 0.0.0.0 */
 749                        n = xmalloc_sockaddr2host_noport((struct sockaddr*)from);
 750                }
 751                printf("  %s (%s)", (n ? n : ina), ina);
 752                free(n);
 753        }
 754        free(ina);
 755}
 756
 757static void
 758print(int read_len, const struct sockaddr *from, const struct sockaddr *to)
 759{
 760        print_inetname(from);
 761
 762        if (verbose) {
 763                char *ina = xmalloc_sockaddr2dotted_noport(to);
 764#if ENABLE_TRACEROUTE6
 765                if (to->sa_family == AF_INET6) {
 766                        read_len -= sizeof(struct ip6_hdr);
 767                } else
 768#endif
 769                {
 770                        struct ip *ip4packet = (struct ip*)recv_pkt;
 771                        read_len -= ip4packet->ip_hl << 2;
 772                }
 773                printf(" %d bytes to %s", read_len, ina);
 774                free(ina);
 775        }
 776}
 777
 778static void
 779print_delta_ms(unsigned t1p, unsigned t2p)
 780{
 781        unsigned tt = t2p - t1p;
 782        printf("  %u.%03u ms", tt / 1000, tt % 1000);
 783}
 784
 785/*
 786 * Usage: [-dFIlnrvx] [-g gateway] [-i iface] [-f first_ttl]
 787 * [-m max_ttl] [ -p port] [-q nqueries] [-s src_addr] [-t tos]
 788 * [-w waittime] [-z pausemsecs] host [packetlen]"
 789 */
 790static int
 791common_traceroute_main(int op, char **argv)
 792{
 793        int minpacket;
 794#ifdef IP_TOS
 795        int tos = 0;
 796#endif
 797        int max_ttl = 30;
 798        int nprobes = 3;
 799        int first_ttl = 1;
 800        unsigned pausemsecs = 0;
 801        char *source;
 802        char *device;
 803        char *tos_str;
 804        char *max_ttl_str;
 805        char *port_str;
 806        char *nprobes_str;
 807        char *waittime_str;
 808        char *pausemsecs_str;
 809        char *first_ttl_str;
 810        char *dest_str;
 811#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
 812        llist_t *source_route_list = NULL;
 813        int lsrr = 0;
 814#endif
 815#if ENABLE_TRACEROUTE6
 816        sa_family_t af;
 817#else
 818        enum { af = AF_INET };
 819#endif
 820        int ttl;
 821        int seq;
 822        len_and_sockaddr *from_lsa;
 823        struct sockaddr *lastaddr;
 824        struct sockaddr *to;
 825
 826        INIT_G();
 827
 828        /* minimum 1 arg */
 829        opt_complementary = "-1:x-x" IF_FEATURE_TRACEROUTE_SOURCE_ROUTE(":g::");
 830        op |= getopt32(argv, OPT_STRING
 831                , &tos_str, &device, &max_ttl_str, &port_str, &nprobes_str
 832                , &source, &waittime_str, &pausemsecs_str, &first_ttl_str
 833#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
 834                , &source_route_list
 835#endif
 836        );
 837        argv += optind;
 838
 839#if 0 /* IGNORED */
 840        if (op & OPT_IP_CHKSUM)
 841                bb_error_msg("warning: ip checksums disabled");
 842#endif
 843#ifdef IP_TOS
 844        if (op & OPT_TOS)
 845                tos = xatou_range(tos_str, 0, 255);
 846#endif
 847        if (op & OPT_MAX_TTL)
 848                max_ttl = xatou_range(max_ttl_str, 1, 255);
 849        if (op & OPT_PORT)
 850                port = xatou16(port_str);
 851        if (op & OPT_NPROBES)
 852                nprobes = xatou_range(nprobes_str, 1, INT_MAX);
 853        if (op & OPT_SOURCE) {
 854                /*
 855                 * set the ip source address of the outbound
 856                 * probe (e.g., on a multi-homed host).
 857                 */
 858                if (getuid() != 0)
 859                        bb_error_msg_and_die(bb_msg_you_must_be_root);
 860        }
 861        if (op & OPT_WAITTIME)
 862                waittime = xatou_range(waittime_str, 1, 24 * 60 * 60);
 863        if (op & OPT_PAUSE_MS)
 864                pausemsecs = xatou_range(pausemsecs_str, 0, 60 * 60 * 1000);
 865        if (op & OPT_FIRST_TTL)
 866                first_ttl = xatou_range(first_ttl_str, 1, max_ttl);
 867
 868#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
 869        if (source_route_list) {
 870                while (source_route_list) {
 871                        len_and_sockaddr *lsa;
 872
 873                        if (lsrr >= NGATEWAYS)
 874                                bb_error_msg_and_die("no more than %d gateways", NGATEWAYS);
 875                        lsa = xhost_and_af2sockaddr(llist_pop(&source_route_list), 0, AF_INET);
 876                        gwlist[lsrr] = lsa->u.sin.sin_addr.s_addr;
 877                        free(lsa);
 878                        ++lsrr;
 879                }
 880                optlen = (lsrr + 1) * sizeof(gwlist[0]);
 881        }
 882#endif
 883
 884        /* Process destination and optional packet size */
 885        minpacket = sizeof(*outip) + SIZEOF_ICMP_HDR + sizeof(*outdata) + optlen;
 886        if (!(op & OPT_USE_ICMP))
 887                minpacket += sizeof(*outudp) - SIZEOF_ICMP_HDR;
 888#if ENABLE_TRACEROUTE6
 889        af = AF_UNSPEC;
 890        if (op & OPT_IPV4)
 891                af = AF_INET;
 892        if (op & OPT_IPV6)
 893                af = AF_INET6;
 894        dest_lsa = xhost_and_af2sockaddr(argv[0], port, af);
 895        af = dest_lsa->u.sa.sa_family;
 896        if (af == AF_INET6)
 897                minpacket = sizeof(struct outdata6_t);
 898#else
 899        dest_lsa = xhost2sockaddr(argv[0], port);
 900#endif
 901        packlen = minpacket;
 902        if (argv[1])
 903                packlen = xatoul_range(argv[1], minpacket, 32 * 1024);
 904
 905        /* Ensure the socket fds won't be 0, 1 or 2 */
 906        bb_sanitize_stdio();
 907
 908#if ENABLE_TRACEROUTE6
 909        if (af == AF_INET6) {
 910                xmove_fd(xsocket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6), rcvsock);
 911# ifdef IPV6_RECVPKTINFO
 912                setsockopt(rcvsock, SOL_IPV6, IPV6_RECVPKTINFO,
 913                                &const_int_1, sizeof(const_int_1));
 914                setsockopt(rcvsock, SOL_IPV6, IPV6_2292PKTINFO,
 915                                &const_int_1, sizeof(const_int_1));
 916# else
 917                setsockopt(rcvsock, SOL_IPV6, IPV6_PKTINFO,
 918                                &const_int_1, sizeof(const_int_1));
 919# endif
 920        } else
 921#endif
 922        {
 923                xmove_fd(xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP), rcvsock);
 924        }
 925
 926#if TRACEROUTE_SO_DEBUG
 927        if (op & OPT_DEBUG)
 928                setsockopt(rcvsock, SOL_SOCKET, SO_DEBUG,
 929                                &const_int_1, sizeof(const_int_1));
 930#endif
 931        if (op & OPT_BYPASS_ROUTE)
 932                setsockopt(rcvsock, SOL_SOCKET, SO_DONTROUTE,
 933                                &const_int_1, sizeof(const_int_1));
 934
 935#if ENABLE_TRACEROUTE6
 936        if (af == AF_INET6) {
 937                static const int two = 2;
 938                if (setsockopt(rcvsock, SOL_RAW, IPV6_CHECKSUM, &two, sizeof(two)) < 0)
 939                        bb_perror_msg_and_die("setsockopt RAW_CHECKSUM");
 940                xmove_fd(xsocket(af, SOCK_DGRAM, 0), sndsock);
 941        } else
 942#endif
 943        {
 944                if (op & OPT_USE_ICMP)
 945                        xmove_fd(xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP), sndsock);
 946                else
 947                        xmove_fd(xsocket(AF_INET, SOCK_DGRAM, 0), sndsock);
 948#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE && defined IP_OPTIONS
 949                if (lsrr > 0) {
 950                        unsigned char optlist[MAX_IPOPTLEN];
 951                        unsigned size;
 952
 953                        /* final hop */
 954                        gwlist[lsrr] = dest_lsa->u.sin.sin_addr.s_addr;
 955                        ++lsrr;
 956
 957                        /* force 4 byte alignment */
 958                        optlist[0] = IPOPT_NOP;
 959                        /* loose source route option */
 960                        optlist[1] = IPOPT_LSRR;
 961                        size = lsrr * sizeof(gwlist[0]);
 962                        optlist[2] = size + 3;
 963                        /* pointer to LSRR addresses */
 964                        optlist[3] = IPOPT_MINOFF;
 965                        memcpy(optlist + 4, gwlist, size);
 966
 967                        if (setsockopt(sndsock, IPPROTO_IP, IP_OPTIONS,
 968                                        (char *)optlist, size + sizeof(gwlist[0])) < 0) {
 969                                bb_perror_msg_and_die("IP_OPTIONS");
 970                        }
 971                }
 972#endif
 973        }
 974
 975#ifdef SO_SNDBUF
 976        if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, &packlen, sizeof(packlen)) < 0) {
 977                bb_perror_msg_and_die("SO_SNDBUF");
 978        }
 979#endif
 980#ifdef IP_TOS
 981        if ((op & OPT_TOS) && setsockopt(sndsock, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0) {
 982                bb_perror_msg_and_die("setsockopt tos %d", tos);
 983        }
 984#endif
 985#ifdef IP_DONTFRAG
 986        if (op & OPT_DONT_FRAGMNT)
 987                setsockopt(sndsock, IPPROTO_IP, IP_DONTFRAG,
 988                                &const_int_1, sizeof(const_int_1));
 989#endif
 990#if TRACEROUTE_SO_DEBUG
 991        if (op & OPT_DEBUG)
 992                setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
 993                                &const_int_1, sizeof(const_int_1));
 994#endif
 995        if (op & OPT_BYPASS_ROUTE)
 996                setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
 997                                &const_int_1, sizeof(const_int_1));
 998
 999        outip = xzalloc(packlen);
1000
1001        ident = getpid();
1002
1003        if (af == AF_INET) {
1004                if (op & OPT_USE_ICMP) {
1005                        ident |= 0x8000;
1006                        outicmp->icmp_type = ICMP_ECHO;
1007                        outicmp->icmp_id = htons(ident);
1008                        outdata = (struct outdata_t *)((char *)outicmp + SIZEOF_ICMP_HDR);
1009                } else {
1010                        outdata = (struct outdata_t *)(outudp + 1);
1011                }
1012        }
1013
1014        if (op & OPT_DEVICE) /* hmm, do we need error check? */
1015                setsockopt_bindtodevice(sndsock, device);
1016
1017        if (op & OPT_SOURCE) {
1018#if ENABLE_TRACEROUTE6
1019// TODO: need xdotted_and_af2sockaddr?
1020                len_and_sockaddr *source_lsa = xhost_and_af2sockaddr(source, 0, af);
1021#else
1022                len_and_sockaddr *source_lsa = xdotted2sockaddr(source, 0);
1023#endif
1024                /* Ping4 does this (why?) */
1025                if (af == AF_INET)
1026                        if (setsockopt(sndsock, IPPROTO_IP, IP_MULTICAST_IF,
1027                                        &source_lsa->u.sa, source_lsa->len))
1028                                bb_error_msg_and_die("can't set multicast source interface");
1029//TODO: we can query source port we bound to,
1030// and check it in replies... if we care enough
1031                xbind(sndsock, &source_lsa->u.sa, source_lsa->len);
1032                free(source_lsa);
1033        }
1034#if ENABLE_TRACEROUTE6
1035        else if (af == AF_INET6) {
1036//TODO: why we don't do it for IPv4?
1037                len_and_sockaddr *source_lsa;
1038
1039                int probe_fd = xsocket(af, SOCK_DGRAM, 0);
1040                if (op & OPT_DEVICE)
1041                        setsockopt_bindtodevice(probe_fd, device);
1042                set_nport(&dest_lsa->u.sa, htons(1025));
1043                /* dummy connect. makes kernel pick source IP (and port) */
1044                xconnect(probe_fd, &dest_lsa->u.sa, dest_lsa->len);
1045                set_nport(&dest_lsa->u.sa, htons(port));
1046
1047                /* read IP and port */
1048                source_lsa = get_sock_lsa(probe_fd);
1049                if (source_lsa == NULL)
1050                        bb_error_msg_and_die("can't get probe addr");
1051
1052                close(probe_fd);
1053
1054                /* bind our sockets to this IP (but not port) */
1055                set_nport(&source_lsa->u.sa, 0);
1056                xbind(sndsock, &source_lsa->u.sa, source_lsa->len);
1057                xbind(rcvsock, &source_lsa->u.sa, source_lsa->len);
1058
1059                free(source_lsa);
1060        }
1061#endif
1062
1063        /* Revert to non-privileged user after opening sockets */
1064        xsetgid(getgid());
1065        xsetuid(getuid());
1066
1067        dest_str = xmalloc_sockaddr2dotted_noport(&dest_lsa->u.sa);
1068        printf("traceroute to %s (%s)", argv[0], dest_str);
1069        if (ENABLE_FEATURE_CLEAN_UP) {
1070                free(dest_str);
1071        }
1072
1073        if (op & OPT_SOURCE)
1074                printf(" from %s", source);
1075        printf(", %d hops max, %d byte packets\n", max_ttl, packlen);
1076
1077        from_lsa = dup_sockaddr(dest_lsa);
1078        lastaddr = xzalloc(dest_lsa->len);
1079        to = xzalloc(dest_lsa->len);
1080        seq = 0;
1081        for (ttl = first_ttl; ttl <= max_ttl; ++ttl) {
1082                int probe;
1083                int unreachable = 0; /* counter */
1084                int gotlastaddr = 0; /* flags */
1085                int got_there = 0;
1086
1087                printf("%2d", ttl);
1088                for (probe = 0; probe < nprobes; ++probe) {
1089                        int read_len;
1090                        unsigned t1;
1091                        unsigned t2;
1092                        int left_ms;
1093                        struct ip *ip;
1094
1095                        fflush_all();
1096                        if (probe != 0 && pausemsecs > 0)
1097                                usleep(pausemsecs * 1000);
1098
1099                        send_probe(++seq, ttl);
1100                        t2 = t1 = monotonic_us();
1101
1102                        left_ms = waittime * 1000;
1103                        while ((read_len = wait_for_reply(from_lsa, to, &t2, &left_ms)) != 0) {
1104                                int icmp_code;
1105
1106                                /* Recv'ed a packet, or read error */
1107                                /* t2 = monotonic_us() - set by wait_for_reply */
1108
1109                                if (read_len < 0)
1110                                        continue;
1111                                icmp_code = packet_ok(read_len, from_lsa, to, seq);
1112                                /* Skip short packet */
1113                                if (icmp_code == 0)
1114                                        continue;
1115
1116                                if (!gotlastaddr
1117                                 || (memcmp(lastaddr, &from_lsa->u.sa, from_lsa->len) != 0)
1118                                ) {
1119                                        print(read_len, &from_lsa->u.sa, to);
1120                                        memcpy(lastaddr, &from_lsa->u.sa, from_lsa->len);
1121                                        gotlastaddr = 1;
1122                                }
1123
1124                                print_delta_ms(t1, t2);
1125                                ip = (struct ip *)recv_pkt;
1126
1127                                if (from_lsa->u.sa.sa_family == AF_INET)
1128                                        if (op & OPT_TTL_FLAG)
1129                                                printf(" (%d)", ip->ip_ttl);
1130
1131                                /* time exceeded in transit */
1132                                if (icmp_code == -1)
1133                                        break;
1134                                icmp_code--;
1135                                switch (icmp_code) {
1136#if ENABLE_TRACEROUTE6
1137                                case ICMP6_DST_UNREACH_NOPORT << 8:
1138                                        got_there = 1;
1139                                        break;
1140#endif
1141                                case ICMP_UNREACH_PORT:
1142                                        if (ip->ip_ttl <= 1)
1143                                                printf(" !");
1144                                        got_there = 1;
1145                                        break;
1146
1147                                case ICMP_UNREACH_NET:
1148#if ENABLE_TRACEROUTE6 && (ICMP6_DST_UNREACH_NOROUTE != ICMP_UNREACH_NET)
1149                                case ICMP6_DST_UNREACH_NOROUTE << 8:
1150#endif
1151                                        printf(" !N");
1152                                        ++unreachable;
1153                                        break;
1154                                case ICMP_UNREACH_HOST:
1155#if ENABLE_TRACEROUTE6
1156                                case ICMP6_DST_UNREACH_ADDR << 8:
1157#endif
1158                                        printf(" !H");
1159                                        ++unreachable;
1160                                        break;
1161                                case ICMP_UNREACH_PROTOCOL:
1162                                        printf(" !P");
1163                                        got_there = 1;
1164                                        break;
1165                                case ICMP_UNREACH_NEEDFRAG:
1166                                        printf(" !F-%d", pmtu);
1167                                        ++unreachable;
1168                                        break;
1169                                case ICMP_UNREACH_SRCFAIL:
1170#if ENABLE_TRACEROUTE6
1171                                case ICMP6_DST_UNREACH_ADMIN << 8:
1172#endif
1173                                        printf(" !S");
1174                                        ++unreachable;
1175                                        break;
1176                                case ICMP_UNREACH_FILTER_PROHIB:
1177                                case ICMP_UNREACH_NET_PROHIB:   /* misuse */
1178                                        printf(" !A");
1179                                        ++unreachable;
1180                                        break;
1181                                case ICMP_UNREACH_HOST_PROHIB:
1182                                        printf(" !C");
1183                                        ++unreachable;
1184                                        break;
1185                                case ICMP_UNREACH_HOST_PRECEDENCE:
1186                                        printf(" !V");
1187                                        ++unreachable;
1188                                        break;
1189                                case ICMP_UNREACH_PRECEDENCE_CUTOFF:
1190                                        printf(" !C");
1191                                        ++unreachable;
1192                                        break;
1193                                case ICMP_UNREACH_NET_UNKNOWN:
1194                                case ICMP_UNREACH_HOST_UNKNOWN:
1195                                        printf(" !U");
1196                                        ++unreachable;
1197                                        break;
1198                                case ICMP_UNREACH_ISOLATED:
1199                                        printf(" !I");
1200                                        ++unreachable;
1201                                        break;
1202                                case ICMP_UNREACH_TOSNET:
1203                                case ICMP_UNREACH_TOSHOST:
1204                                        printf(" !T");
1205                                        ++unreachable;
1206                                        break;
1207                                default:
1208                                        printf(" !<%d>", icmp_code);
1209                                        ++unreachable;
1210                                        break;
1211                                }
1212                                break;
1213                        } /* while (wait and read a packet) */
1214
1215                        /* there was no packet at all? */
1216                        if (read_len == 0)
1217                                printf("  *");
1218                } /* for (nprobes) */
1219
1220                bb_putchar('\n');
1221                if (got_there
1222                 || (unreachable > 0 && unreachable >= nprobes - 1)
1223                ) {
1224                        break;
1225                }
1226        }
1227
1228        if (ENABLE_FEATURE_CLEAN_UP) {
1229                free(to);
1230                free(lastaddr);
1231                free(from_lsa);
1232        }
1233
1234        return 0;
1235}
1236
1237int traceroute_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1238int traceroute_main(int argc UNUSED_PARAM, char **argv)
1239{
1240        return common_traceroute_main(0, argv);
1241}
1242
1243#if ENABLE_TRACEROUTE6
1244int traceroute6_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1245int traceroute6_main(int argc UNUSED_PARAM, char **argv)
1246{
1247        return common_traceroute_main(OPT_IPV6, argv);
1248}
1249#endif
1250