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 "FIlnrdvxt:i:m:p:q:s:w:z:f:" \
 294                    IF_FEATURE_TRACEROUTE_SOURCE_ROUTE("g:") \
 295                    "4" IF_TRACEROUTE6("6")
 296enum {
 297        OPT_DONT_FRAGMNT = (1 << 0),    /* F */
 298        OPT_USE_ICMP     = (1 << 1) * ENABLE_FEATURE_TRACEROUTE_USE_ICMP, /* I */
 299        OPT_TTL_FLAG     = (1 << 2),    /* l */
 300        OPT_ADDR_NUM     = (1 << 3),    /* n */
 301        OPT_BYPASS_ROUTE = (1 << 4),    /* r */
 302        OPT_DEBUG        = (1 << 5),    /* d */
 303        OPT_VERBOSE      = (1 << 6) * ENABLE_FEATURE_TRACEROUTE_VERBOSE, /* v */
 304        OPT_IP_CHKSUM    = (1 << 7),    /* x */
 305        OPT_TOS          = (1 << 8),    /* t */
 306        OPT_DEVICE       = (1 << 9),    /* i */
 307        OPT_MAX_TTL      = (1 << 10),   /* m */
 308        OPT_PORT         = (1 << 11),   /* p */
 309        OPT_NPROBES      = (1 << 12),   /* q */
 310        OPT_SOURCE       = (1 << 13),   /* s */
 311        OPT_WAITTIME     = (1 << 14),   /* w */
 312        OPT_PAUSE_MS     = (1 << 15),   /* z */
 313        OPT_FIRST_TTL    = (1 << 16),   /* f */
 314        OPT_SOURCE_ROUTE = (1 << 17) * ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE, /* g */
 315        OPT_IPV4         = (1 << (17+ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE)),   /* 4 */
 316        OPT_IPV6         = (1 << (18+ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE)) * ENABLE_TRACEROUTE6, /* 6 */
 317};
 318#define verbose (option_mask32 & OPT_VERBOSE)
 319
 320enum {
 321        SIZEOF_ICMP_HDR = 8,
 322        rcvsock = 3, /* receive (icmp) socket file descriptor */
 323        sndsock = 4, /* send (udp/icmp) socket file descriptor */
 324};
 325
 326/* Data section of the probe packet */
 327struct outdata_t {
 328        unsigned char seq;             /* sequence number of this packet */
 329        unsigned char ttl;             /* ttl packet left with */
 330// UNUSED. Retaining to have the same packet size.
 331        struct timeval tv_UNUSED PACKED; /* time packet left */
 332};
 333
 334#if ENABLE_TRACEROUTE6
 335struct outdata6_t {
 336        uint32_t ident6;
 337        uint32_t seq6;
 338        struct timeval tv_UNUSED PACKED; /* time packet left */
 339};
 340#endif
 341
 342struct globals {
 343        struct ip *outip;
 344        struct outdata_t *outdata;
 345        len_and_sockaddr *dest_lsa;
 346        int packlen;                    /* total length of packet */
 347        int pmtu;                       /* Path MTU Discovery (RFC1191) */
 348        uint32_t ident;
 349        uint16_t port; // 32768 + 666;  /* start udp dest port # for probe packets */
 350        int waittime; // 5;             /* time to wait for response (in seconds) */
 351#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
 352        int optlen;                     /* length of ip options */
 353#else
 354#define optlen 0
 355#endif
 356        unsigned char recv_pkt[512];    /* last inbound (icmp) packet */
 357#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
 358        /* Maximum number of gateways (include room for one noop) */
 359#define NGATEWAYS ((int)((MAX_IPOPTLEN - IPOPT_MINOFF - 1) / sizeof(uint32_t)))
 360        /* loose source route gateway list (including room for final destination) */
 361        uint32_t gwlist[NGATEWAYS + 1];
 362#endif
 363};
 364
 365#define G (*ptr_to_globals)
 366#define outip     (G.outip    )
 367#define outdata   (G.outdata  )
 368#define dest_lsa  (G.dest_lsa )
 369#define packlen   (G.packlen  )
 370#define pmtu      (G.pmtu     )
 371#define ident     (G.ident    )
 372#define port      (G.port     )
 373#define waittime  (G.waittime )
 374#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
 375# define optlen   (G.optlen   )
 376#endif
 377#define recv_pkt  (G.recv_pkt )
 378#define gwlist    (G.gwlist   )
 379#define INIT_G() do { \
 380        SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
 381        port = 32768 + 666; \
 382        waittime = 5; \
 383} while (0)
 384
 385#define outicmp ((struct icmp *)(outip + 1))
 386#define outudp  ((struct udphdr *)(outip + 1))
 387
 388
 389/* libbb candidate? tftp uses this idiom too */
 390static len_and_sockaddr* dup_sockaddr(const len_and_sockaddr *lsa)
 391{
 392        len_and_sockaddr *new_lsa = xzalloc(LSA_LEN_SIZE + lsa->len);
 393        memcpy(new_lsa, lsa, LSA_LEN_SIZE + lsa->len);
 394        return new_lsa;
 395}
 396
 397
 398static int
 399wait_for_reply(len_and_sockaddr *from_lsa, struct sockaddr *to, unsigned *timestamp_us, int *left_ms)
 400{
 401        struct pollfd pfd[1];
 402        int read_len = 0;
 403
 404        pfd[0].fd = rcvsock;
 405        pfd[0].events = POLLIN;
 406        if (*left_ms >= 0 && safe_poll(pfd, 1, *left_ms) > 0) {
 407                unsigned t;
 408
 409                read_len = recv_from_to(rcvsock,
 410                                recv_pkt, sizeof(recv_pkt),
 411                                /*flags:*/ MSG_DONTWAIT,
 412                                &from_lsa->u.sa, to, from_lsa->len);
 413                t = monotonic_us();
 414                *left_ms -= (t - *timestamp_us) / 1000;
 415                *timestamp_us = t;
 416        }
 417
 418        return read_len;
 419}
 420
 421/*
 422 * Checksum routine for Internet Protocol family headers (C Version)
 423 */
 424static uint16_t
 425in_cksum(uint16_t *addr, int len)
 426{
 427        int nleft = len;
 428        uint16_t *w = addr;
 429        uint16_t answer;
 430        int sum = 0;
 431
 432        /*
 433         * Our algorithm is simple, using a 32 bit accumulator (sum),
 434         * we add sequential 16 bit words to it, and at the end, fold
 435         * back all the carry bits from the top 16 bits into the lower
 436         * 16 bits.
 437         */
 438        while (nleft > 1) {
 439                sum += *w++;
 440                nleft -= 2;
 441        }
 442
 443        /* mop up an odd byte, if necessary */
 444        if (nleft == 1)
 445                sum += *(unsigned char *)w;
 446
 447        /* add back carry outs from top 16 bits to low 16 bits */
 448        sum = (sum >> 16) + (sum & 0xffff);     /* add hi 16 to low 16 */
 449        sum += (sum >> 16);                     /* add carry */
 450        answer = ~sum;                          /* truncate to 16 bits */
 451        return answer;
 452}
 453
 454static void
 455send_probe(int seq, int ttl)
 456{
 457        int len, res;
 458        void *out;
 459
 460        /* Payload */
 461#if ENABLE_TRACEROUTE6
 462        if (dest_lsa->u.sa.sa_family == AF_INET6) {
 463                struct outdata6_t *pkt = (struct outdata6_t *) outip;
 464                pkt->ident6 = htonl(ident);
 465                pkt->seq6   = htonl(seq);
 466                /*gettimeofday(&pkt->tv, &tz);*/
 467        } else
 468#endif
 469        {
 470                outdata->seq = seq;
 471                outdata->ttl = ttl;
 472// UNUSED: was storing gettimeofday's result there, but never ever checked it
 473                /*memcpy(&outdata->tv, tp, sizeof(outdata->tv));*/
 474
 475                if (option_mask32 & OPT_USE_ICMP) {
 476                        outicmp->icmp_seq = htons(seq);
 477
 478                        /* Always calculate checksum for icmp packets */
 479                        outicmp->icmp_cksum = 0;
 480                        outicmp->icmp_cksum = in_cksum((uint16_t *)outicmp,
 481                                                packlen - (sizeof(*outip) + optlen));
 482                        if (outicmp->icmp_cksum == 0)
 483                                outicmp->icmp_cksum = 0xffff;
 484                }
 485        }
 486
 487//BUG! verbose is (x & OPT_VERBOSE), not a counter!
 488#if 0 //ENABLE_FEATURE_TRACEROUTE_VERBOSE
 489        /* XXX undocumented debugging hack */
 490        if (verbose > 1) {
 491                const uint16_t *sp;
 492                int nshorts, i;
 493
 494                sp = (uint16_t *)outip;
 495                nshorts = (unsigned)packlen / sizeof(uint16_t);
 496                i = 0;
 497                printf("[ %d bytes", packlen);
 498                while (--nshorts >= 0) {
 499                        if ((i++ % 8) == 0)
 500                                printf("\n\t");
 501                        printf(" %04x", ntohs(*sp));
 502                        sp++;
 503                }
 504                if (packlen & 1) {
 505                        if ((i % 8) == 0)
 506                                printf("\n\t");
 507                        printf(" %02x", *(unsigned char *)sp);
 508                }
 509                printf("]\n");
 510        }
 511#endif
 512
 513#if ENABLE_TRACEROUTE6
 514        if (dest_lsa->u.sa.sa_family == AF_INET6) {
 515                res = setsockopt(sndsock, SOL_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl));
 516                if (res < 0)
 517                        bb_perror_msg_and_die("setsockopt UNICAST_HOPS %d", ttl);
 518                out = outip;
 519                len = packlen;
 520        } else
 521#endif
 522        {
 523#if defined IP_TTL
 524                res = setsockopt(sndsock, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
 525                if (res < 0)
 526                        bb_perror_msg_and_die("setsockopt ttl %d", ttl);
 527#endif
 528                out = outicmp;
 529                len = packlen - sizeof(*outip);
 530                if (!(option_mask32 & OPT_USE_ICMP)) {
 531                        out = outdata;
 532                        len -= sizeof(*outudp);
 533                        set_nport(&dest_lsa->u.sa, htons(port + seq));
 534                }
 535        }
 536
 537        res = xsendto(sndsock, out, len, &dest_lsa->u.sa, dest_lsa->len);
 538        if (res != len)
 539                bb_info_msg("sent %d octets, ret=%d", len, res);
 540}
 541
 542#if ENABLE_FEATURE_TRACEROUTE_VERBOSE
 543/*
 544 * Convert an ICMP "type" field to a printable string.
 545 */
 546static const char *
 547pr_type(unsigned char t)
 548{
 549        static const char *const ttab[] = {
 550        "Echo Reply",   "ICMP 1",       "ICMP 2",       "Dest Unreachable",
 551        "Source Quench", "Redirect",    "ICMP 6",       "ICMP 7",
 552        "Echo",         "Router Advert", "Router Solicit", "Time Exceeded",
 553        "Param Problem", "Timestamp",   "Timestamp Reply", "Info Request",
 554        "Info Reply",   "Mask Request", "Mask Reply"
 555        };
 556# if ENABLE_TRACEROUTE6
 557        static const char *const ttab6[] = {
 558[0]     "Error", "Dest Unreachable", "Packet Too Big", "Time Exceeded",
 559[4]     "Param Problem",
 560[8]     "Echo Request", "Echo Reply", "Membership Query", "Membership Report",
 561[12]    "Membership Reduction", "Router Solicit", "Router Advert", "Neighbor Solicit",
 562[16]    "Neighbor Advert", "Redirect",
 563        };
 564
 565        if (dest_lsa->u.sa.sa_family == AF_INET6) {
 566                if (t < 5)
 567                        return ttab6[t];
 568                if (t < 128 || t > ND_REDIRECT)
 569                        return "OUT-OF-RANGE";
 570                return ttab6[(t & 63) + 8];
 571        }
 572# endif
 573        if (t >= ARRAY_SIZE(ttab))
 574                return "OUT-OF-RANGE";
 575
 576        return ttab[t];
 577}
 578#endif
 579
 580#if !ENABLE_FEATURE_TRACEROUTE_VERBOSE
 581#define packet4_ok(read_len, from, seq) \
 582        packet4_ok(read_len, seq)
 583#endif
 584static int
 585packet4_ok(int read_len, const struct sockaddr_in *from, int seq)
 586{
 587        const struct icmp *icp;
 588        unsigned char type, code;
 589        int hlen;
 590        const struct ip *ip;
 591
 592        ip = (struct ip *) recv_pkt;
 593        hlen = ip->ip_hl << 2;
 594        if (read_len < hlen + ICMP_MINLEN) {
 595#if ENABLE_FEATURE_TRACEROUTE_VERBOSE
 596                if (verbose)
 597                        printf("packet too short (%d bytes) from %s\n", read_len,
 598                                inet_ntoa(from->sin_addr));
 599#endif
 600                return 0;
 601        }
 602        read_len -= hlen;
 603        icp = (struct icmp *)(recv_pkt + hlen);
 604        type = icp->icmp_type;
 605        code = icp->icmp_code;
 606        /* Path MTU Discovery (RFC1191) */
 607        pmtu = 0;
 608        if (code == ICMP_UNREACH_NEEDFRAG)
 609                pmtu = ntohs(icp->icmp_nextmtu);
 610
 611        if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS)
 612         || type == ICMP_UNREACH
 613         || type == ICMP_ECHOREPLY
 614        ) {
 615                const struct ip *hip;
 616                const struct udphdr *up;
 617
 618                hip = &icp->icmp_ip;
 619                hlen = hip->ip_hl << 2;
 620                if (option_mask32 & OPT_USE_ICMP) {
 621                        struct icmp *hicmp;
 622
 623                        /* XXX */
 624                        if (type == ICMP_ECHOREPLY
 625                         && icp->icmp_id == htons(ident)
 626                         && icp->icmp_seq == htons(seq)
 627                        ) {
 628                                return ICMP_UNREACH_PORT+1;
 629                        }
 630
 631                        hicmp = (struct icmp *)((unsigned char *)hip + hlen);
 632                        if (hlen + SIZEOF_ICMP_HDR <= read_len
 633                         && hip->ip_p == IPPROTO_ICMP
 634                         && hicmp->icmp_id == htons(ident)
 635                         && hicmp->icmp_seq == htons(seq)
 636                        ) {
 637                                return (type == ICMP_TIMXCEED ? -1 : code + 1);
 638                        }
 639                } else {
 640                        up = (struct udphdr *)((char *)hip + hlen);
 641                        if (hlen + 12 <= read_len
 642                         && hip->ip_p == IPPROTO_UDP
 643// Off: since we do not form the entire IP packet,
 644// but defer it to kernel, we can't set source port,
 645// and thus can't check it here in the reply
 646                        /* && up->source == htons(ident) */
 647                         && up->dest == htons(port + seq)
 648                        ) {
 649                                return (type == ICMP_TIMXCEED ? -1 : code + 1);
 650                        }
 651                }
 652        }
 653#if ENABLE_FEATURE_TRACEROUTE_VERBOSE
 654        if (verbose) {
 655                int i;
 656                uint32_t *lp = (uint32_t *)&icp->icmp_ip;
 657
 658                printf("\n%d bytes from %s to "
 659                       "%s: icmp type %d (%s) code %d\n",
 660                        read_len, inet_ntoa(from->sin_addr),
 661                        inet_ntoa(ip->ip_dst),
 662                        type, pr_type(type), icp->icmp_code);
 663                for (i = 4; i < read_len; i += sizeof(*lp))
 664                        printf("%2d: x%8.8x\n", i, *lp++);
 665        }
 666#endif
 667        return 0;
 668}
 669
 670#if ENABLE_TRACEROUTE6
 671# if !ENABLE_FEATURE_TRACEROUTE_VERBOSE
 672#define packet_ok(read_len, from_lsa, to, seq) \
 673        packet_ok(read_len, from_lsa, seq)
 674# endif
 675static int
 676packet_ok(int read_len, len_and_sockaddr *from_lsa,
 677                        struct sockaddr *to,
 678                        int seq)
 679{
 680        const struct icmp6_hdr *icp;
 681        unsigned char type, code;
 682
 683        if (from_lsa->u.sa.sa_family == AF_INET)
 684                return packet4_ok(read_len, &from_lsa->u.sin, seq);
 685
 686        icp = (struct icmp6_hdr *) recv_pkt;
 687
 688        type = icp->icmp6_type;
 689        code = icp->icmp6_code;
 690
 691        if ((type == ICMP6_TIME_EXCEEDED && code == ICMP6_TIME_EXCEED_TRANSIT)
 692         || type == ICMP6_DST_UNREACH
 693        ) {
 694                struct ip6_hdr *hip;
 695                struct udphdr *up;
 696                int nexthdr;
 697
 698                hip = (struct ip6_hdr *)(icp + 1);
 699                up  = (struct udphdr *) (hip + 1);
 700                nexthdr = hip->ip6_nxt;
 701
 702                if (nexthdr == IPPROTO_FRAGMENT) {
 703                        nexthdr = *(unsigned char*)up;
 704                        up++;
 705                }
 706                if (nexthdr == IPPROTO_UDP) {
 707                        struct outdata6_t *pkt;
 708
 709                        pkt = (struct outdata6_t *) (up + 1);
 710
 711                        if (ntohl(pkt->ident6) == ident
 712                         && ntohl(pkt->seq6) == seq
 713                        ) {
 714                                return (type == ICMP6_TIME_EXCEEDED ? -1 : (code<<8)+1);
 715                        }
 716                }
 717        }
 718
 719# if ENABLE_FEATURE_TRACEROUTE_VERBOSE
 720        if (verbose) {
 721                unsigned char *p;
 722                char pa1[MAXHOSTNAMELEN];
 723                char pa2[MAXHOSTNAMELEN];
 724                int i;
 725
 726                p = (unsigned char *) (icp + 1);
 727
 728                printf("\n%d bytes from %s to "
 729                       "%s: icmp type %d (%s) code %d\n",
 730                        read_len,
 731                        inet_ntop(AF_INET6, &from_lsa->u.sin6.sin6_addr, pa1, sizeof(pa1)),
 732                        inet_ntop(AF_INET6, &((struct sockaddr_in6*)to)->sin6_addr, pa2, sizeof(pa2)),
 733                        type, pr_type(type), icp->icmp6_code);
 734
 735                read_len -= sizeof(struct icmp6_hdr);
 736                for (i = 0; i < read_len; i++) {
 737                        if (i % 16 == 0)
 738                                printf("%04x:", i);
 739                        if (i % 4 == 0)
 740                                bb_putchar(' ');
 741                        printf("%02x", p[i]);
 742                        if ((i % 16 == 15) && (i + 1 < read_len))
 743                                bb_putchar('\n');
 744                }
 745                bb_putchar('\n');
 746        }
 747# endif
 748
 749        return 0;
 750}
 751#else /* !ENABLE_TRACEROUTE6 */
 752static ALWAYS_INLINE int
 753packet_ok(int read_len,
 754                len_and_sockaddr *from_lsa IF_NOT_FEATURE_TRACEROUTE_VERBOSE(UNUSED_PARAM),
 755                struct sockaddr *to UNUSED_PARAM,
 756                int seq)
 757{
 758        return packet4_ok(read_len, &from_lsa->u.sin, seq);
 759}
 760#endif
 761
 762/*
 763 * Construct an Internet address representation.
 764 * If the -n flag has been supplied, give
 765 * numeric value, otherwise try for symbolic name.
 766 */
 767static void
 768print_inetname(const struct sockaddr *from)
 769{
 770        char *ina = xmalloc_sockaddr2dotted_noport(from);
 771
 772        if (option_mask32 & OPT_ADDR_NUM) {
 773                printf("  %s", ina);
 774        } else {
 775                char *n = NULL;
 776
 777                if (from->sa_family != AF_INET
 778                 || ((struct sockaddr_in*)from)->sin_addr.s_addr != INADDR_ANY
 779                ) {
 780                        /* Try to reverse resolve if it is not 0.0.0.0 */
 781                        n = xmalloc_sockaddr2host_noport((struct sockaddr*)from);
 782                }
 783                printf("  %s (%s)", (n ? n : ina), ina);
 784                free(n);
 785        }
 786        free(ina);
 787}
 788
 789static void
 790print(int read_len, const struct sockaddr *from, const struct sockaddr *to)
 791{
 792        print_inetname(from);
 793
 794        if (verbose) {
 795                char *ina = xmalloc_sockaddr2dotted_noport(to);
 796#if ENABLE_TRACEROUTE6
 797                if (to->sa_family == AF_INET6) {
 798                        read_len -= sizeof(struct ip6_hdr);
 799                } else
 800#endif
 801                {
 802                        struct ip *ip4packet = (struct ip*)recv_pkt;
 803                        read_len -= ip4packet->ip_hl << 2;
 804                }
 805                printf(" %d bytes to %s", read_len, ina);
 806                free(ina);
 807        }
 808}
 809
 810static void
 811print_delta_ms(unsigned t1p, unsigned t2p)
 812{
 813        unsigned tt = t2p - t1p;
 814        printf("  %u.%03u ms", tt / 1000, tt % 1000);
 815}
 816
 817/*
 818 * Usage: [-dFIlnrvx] [-g gateway] [-i iface] [-f first_ttl]
 819 * [-m max_ttl] [ -p port] [-q nqueries] [-s src_addr] [-t tos]
 820 * [-w waittime] [-z pausemsecs] host [packetlen]"
 821 */
 822static int
 823common_traceroute_main(int op, char **argv)
 824{
 825        int minpacket;
 826        int tos = 0;
 827        int max_ttl = 30;
 828        int nprobes = 3;
 829        int first_ttl = 1;
 830        unsigned pausemsecs = 0;
 831        char *source;
 832        char *device;
 833        char *tos_str;
 834        char *max_ttl_str;
 835        char *port_str;
 836        char *nprobes_str;
 837        char *waittime_str;
 838        char *pausemsecs_str;
 839        char *first_ttl_str;
 840#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
 841        llist_t *source_route_list = NULL;
 842        int lsrr = 0;
 843#endif
 844#if ENABLE_TRACEROUTE6
 845        sa_family_t af;
 846#else
 847        enum { af = AF_INET };
 848#endif
 849        int ttl;
 850        int seq;
 851        len_and_sockaddr *from_lsa;
 852        struct sockaddr *lastaddr;
 853        struct sockaddr *to;
 854
 855        INIT_G();
 856
 857        /* minimum 1 arg */
 858        opt_complementary = "-1:x-x" IF_FEATURE_TRACEROUTE_SOURCE_ROUTE(":g::");
 859        op |= getopt32(argv, OPT_STRING
 860                , &tos_str, &device, &max_ttl_str, &port_str, &nprobes_str
 861                , &source, &waittime_str, &pausemsecs_str, &first_ttl_str
 862#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
 863                , &source_route_list
 864#endif
 865        );
 866        argv += optind;
 867
 868#if 0 /* IGNORED */
 869        if (op & OPT_IP_CHKSUM)
 870                bb_error_msg("warning: ip checksums disabled");
 871#endif
 872        if (op & OPT_TOS)
 873                tos = xatou_range(tos_str, 0, 255);
 874        if (op & OPT_MAX_TTL)
 875                max_ttl = xatou_range(max_ttl_str, 1, 255);
 876        if (op & OPT_PORT)
 877                port = xatou16(port_str);
 878        if (op & OPT_NPROBES)
 879                nprobes = xatou_range(nprobes_str, 1, INT_MAX);
 880        if (op & OPT_SOURCE) {
 881                /*
 882                 * set the ip source address of the outbound
 883                 * probe (e.g., on a multi-homed host).
 884                 */
 885                if (getuid() != 0)
 886                        bb_error_msg_and_die(bb_msg_you_must_be_root);
 887        }
 888        if (op & OPT_WAITTIME)
 889                waittime = xatou_range(waittime_str, 1, 24 * 60 * 60);
 890        if (op & OPT_PAUSE_MS)
 891                pausemsecs = xatou_range(pausemsecs_str, 0, 60 * 60 * 1000);
 892        if (op & OPT_FIRST_TTL)
 893                first_ttl = xatou_range(first_ttl_str, 1, max_ttl);
 894
 895#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
 896        if (source_route_list) {
 897                while (source_route_list) {
 898                        len_and_sockaddr *lsa;
 899
 900                        if (lsrr >= NGATEWAYS)
 901                                bb_error_msg_and_die("no more than %d gateways", NGATEWAYS);
 902                        lsa = xhost_and_af2sockaddr(llist_pop(&source_route_list), 0, AF_INET);
 903                        gwlist[lsrr] = lsa->u.sin.sin_addr.s_addr;
 904                        free(lsa);
 905                        ++lsrr;
 906                }
 907                optlen = (lsrr + 1) * sizeof(gwlist[0]);
 908        }
 909#endif
 910
 911        /* Process destination and optional packet size */
 912        minpacket = sizeof(*outip) + SIZEOF_ICMP_HDR + sizeof(*outdata) + optlen;
 913        if (!(op & OPT_USE_ICMP))
 914                minpacket += sizeof(*outudp) - SIZEOF_ICMP_HDR;
 915#if ENABLE_TRACEROUTE6
 916        af = AF_UNSPEC;
 917        if (op & OPT_IPV4)
 918                af = AF_INET;
 919        if (op & OPT_IPV6)
 920                af = AF_INET6;
 921        dest_lsa = xhost_and_af2sockaddr(argv[0], port, af);
 922        af = dest_lsa->u.sa.sa_family;
 923        if (af == AF_INET6)
 924                minpacket = sizeof(struct outdata6_t);
 925#else
 926        dest_lsa = xhost2sockaddr(argv[0], port);
 927#endif
 928        packlen = minpacket;
 929        if (argv[1])
 930                packlen = xatoul_range(argv[1], minpacket, 32 * 1024);
 931
 932        /* Ensure the socket fds won't be 0, 1 or 2 */
 933        bb_sanitize_stdio();
 934
 935#if ENABLE_TRACEROUTE6
 936        if (af == AF_INET6) {
 937                xmove_fd(xsocket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6), rcvsock);
 938# ifdef IPV6_RECVPKTINFO
 939                setsockopt(rcvsock, SOL_IPV6, IPV6_RECVPKTINFO,
 940                                &const_int_1, sizeof(const_int_1));
 941                setsockopt(rcvsock, SOL_IPV6, IPV6_2292PKTINFO,
 942                                &const_int_1, sizeof(const_int_1));
 943# else
 944                setsockopt(rcvsock, SOL_IPV6, IPV6_PKTINFO,
 945                                &const_int_1, sizeof(const_int_1));
 946# endif
 947        } else
 948#endif
 949        {
 950                xmove_fd(xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP), rcvsock);
 951        }
 952
 953#if TRACEROUTE_SO_DEBUG
 954        if (op & OPT_DEBUG)
 955                setsockopt(rcvsock, SOL_SOCKET, SO_DEBUG,
 956                                &const_int_1, sizeof(const_int_1));
 957#endif
 958        if (op & OPT_BYPASS_ROUTE)
 959                setsockopt(rcvsock, SOL_SOCKET, SO_DONTROUTE,
 960                                &const_int_1, sizeof(const_int_1));
 961
 962#if ENABLE_TRACEROUTE6
 963        if (af == AF_INET6) {
 964                static const int two = 2;
 965                if (setsockopt(rcvsock, SOL_RAW, IPV6_CHECKSUM, &two, sizeof(two)) < 0)
 966                        bb_perror_msg_and_die("setsockopt RAW_CHECKSUM");
 967                xmove_fd(xsocket(af, SOCK_DGRAM, 0), sndsock);
 968        } else
 969#endif
 970        {
 971                if (op & OPT_USE_ICMP)
 972                        xmove_fd(xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP), sndsock);
 973                else
 974                        xmove_fd(xsocket(AF_INET, SOCK_DGRAM, 0), sndsock);
 975#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE && defined IP_OPTIONS
 976                if (lsrr > 0) {
 977                        unsigned char optlist[MAX_IPOPTLEN];
 978                        unsigned size;
 979
 980                        /* final hop */
 981                        gwlist[lsrr] = dest_lsa->u.sin.sin_addr.s_addr;
 982                        ++lsrr;
 983
 984                        /* force 4 byte alignment */
 985                        optlist[0] = IPOPT_NOP;
 986                        /* loose source route option */
 987                        optlist[1] = IPOPT_LSRR;
 988                        size = lsrr * sizeof(gwlist[0]);
 989                        optlist[2] = size + 3;
 990                        /* pointer to LSRR addresses */
 991                        optlist[3] = IPOPT_MINOFF;
 992                        memcpy(optlist + 4, gwlist, size);
 993
 994                        if (setsockopt(sndsock, IPPROTO_IP, IP_OPTIONS,
 995                                        (char *)optlist, size + sizeof(gwlist[0])) < 0) {
 996                                bb_perror_msg_and_die("IP_OPTIONS");
 997                        }
 998                }
 999#endif
1000        }
1001
1002#ifdef SO_SNDBUF
1003        if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, &packlen, sizeof(packlen)) < 0) {
1004                bb_perror_msg_and_die("SO_SNDBUF");
1005        }
1006#endif
1007#ifdef IP_TOS
1008        if ((op & OPT_TOS) && setsockopt(sndsock, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0) {
1009                bb_perror_msg_and_die("setsockopt tos %d", tos);
1010        }
1011#endif
1012#ifdef IP_DONTFRAG
1013        if (op & OPT_DONT_FRAGMNT)
1014                setsockopt(sndsock, IPPROTO_IP, IP_DONTFRAG,
1015                                &const_int_1, sizeof(const_int_1));
1016#endif
1017#if TRACEROUTE_SO_DEBUG
1018        if (op & OPT_DEBUG)
1019                setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
1020                                &const_int_1, sizeof(const_int_1));
1021#endif
1022        if (op & OPT_BYPASS_ROUTE)
1023                setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
1024                                &const_int_1, sizeof(const_int_1));
1025
1026        outip = xzalloc(packlen);
1027
1028        ident = getpid();
1029
1030        if (af == AF_INET) {
1031                if (op & OPT_USE_ICMP) {
1032                        ident |= 0x8000;
1033                        outicmp->icmp_type = ICMP_ECHO;
1034                        outicmp->icmp_id = htons(ident);
1035                        outdata = (struct outdata_t *)((char *)outicmp + SIZEOF_ICMP_HDR);
1036                } else {
1037                        outdata = (struct outdata_t *)(outudp + 1);
1038                }
1039        }
1040
1041        if (op & OPT_DEVICE) /* hmm, do we need error check? */
1042                setsockopt_bindtodevice(sndsock, device);
1043
1044        if (op & OPT_SOURCE) {
1045#if ENABLE_TRACEROUTE6
1046// TODO: need xdotted_and_af2sockaddr?
1047                len_and_sockaddr *source_lsa = xhost_and_af2sockaddr(source, 0, af);
1048#else
1049                len_and_sockaddr *source_lsa = xdotted2sockaddr(source, 0);
1050#endif
1051                /* Ping4 does this (why?) */
1052                if (af == AF_INET)
1053                        if (setsockopt(sndsock, IPPROTO_IP, IP_MULTICAST_IF,
1054                                        &source_lsa->u.sa, source_lsa->len))
1055                                bb_error_msg_and_die("can't set multicast source interface");
1056//TODO: we can query source port we bound to,
1057// and check it in replies... if we care enough
1058                xbind(sndsock, &source_lsa->u.sa, source_lsa->len);
1059                free(source_lsa);
1060        }
1061#if ENABLE_TRACEROUTE6
1062        else if (af == AF_INET6) {
1063//TODO: why we don't do it for IPv4?
1064                len_and_sockaddr *source_lsa;
1065
1066                int probe_fd = xsocket(af, SOCK_DGRAM, 0);
1067                if (op & OPT_DEVICE)
1068                        setsockopt_bindtodevice(probe_fd, device);
1069                set_nport(&dest_lsa->u.sa, htons(1025));
1070                /* dummy connect. makes kernel pick source IP (and port) */
1071                xconnect(probe_fd, &dest_lsa->u.sa, dest_lsa->len);
1072                set_nport(&dest_lsa->u.sa, htons(port));
1073
1074                /* read IP and port */
1075                source_lsa = get_sock_lsa(probe_fd);
1076                if (source_lsa == NULL)
1077                        bb_error_msg_and_die("can't get probe addr");
1078
1079                close(probe_fd);
1080
1081                /* bind our sockets to this IP (but not port) */
1082                set_nport(&source_lsa->u.sa, 0);
1083                xbind(sndsock, &source_lsa->u.sa, source_lsa->len);
1084                xbind(rcvsock, &source_lsa->u.sa, source_lsa->len);
1085
1086                free(source_lsa);
1087        }
1088#endif
1089
1090        /* Revert to non-privileged user after opening sockets */
1091        xsetgid(getgid());
1092        xsetuid(getuid());
1093
1094        printf("traceroute to %s (%s)", argv[0],
1095                        xmalloc_sockaddr2dotted_noport(&dest_lsa->u.sa));
1096        if (op & OPT_SOURCE)
1097                printf(" from %s", source);
1098        printf(", %d hops max, %d byte packets\n", max_ttl, packlen);
1099
1100        from_lsa = dup_sockaddr(dest_lsa);
1101        lastaddr = xzalloc(dest_lsa->len);
1102        to = xzalloc(dest_lsa->len);
1103        seq = 0;
1104        for (ttl = first_ttl; ttl <= max_ttl; ++ttl) {
1105                int probe;
1106                int unreachable = 0; /* counter */
1107                int gotlastaddr = 0; /* flags */
1108                int got_there = 0;
1109
1110                printf("%2d", ttl);
1111                for (probe = 0; probe < nprobes; ++probe) {
1112                        int read_len;
1113                        unsigned t1;
1114                        unsigned t2;
1115                        int left_ms;
1116                        struct ip *ip;
1117
1118                        fflush_all();
1119                        if (probe != 0 && pausemsecs > 0)
1120                                usleep(pausemsecs * 1000);
1121
1122                        send_probe(++seq, ttl);
1123                        t2 = t1 = monotonic_us();
1124
1125                        left_ms = waittime * 1000;
1126                        while ((read_len = wait_for_reply(from_lsa, to, &t2, &left_ms)) != 0) {
1127                                int icmp_code;
1128
1129                                /* Recv'ed a packet, or read error */
1130                                /* t2 = monotonic_us() - set by wait_for_reply */
1131
1132                                if (read_len < 0)
1133                                        continue;
1134                                icmp_code = packet_ok(read_len, from_lsa, to, seq);
1135                                /* Skip short packet */
1136                                if (icmp_code == 0)
1137                                        continue;
1138
1139                                if (!gotlastaddr
1140                                 || (memcmp(lastaddr, &from_lsa->u.sa, from_lsa->len) != 0)
1141                                ) {
1142                                        print(read_len, &from_lsa->u.sa, to);
1143                                        memcpy(lastaddr, &from_lsa->u.sa, from_lsa->len);
1144                                        gotlastaddr = 1;
1145                                }
1146
1147                                print_delta_ms(t1, t2);
1148                                ip = (struct ip *)recv_pkt;
1149
1150                                if (from_lsa->u.sa.sa_family == AF_INET)
1151                                        if (op & OPT_TTL_FLAG)
1152                                                printf(" (%d)", ip->ip_ttl);
1153
1154                                /* time exceeded in transit */
1155                                if (icmp_code == -1)
1156                                        break;
1157                                icmp_code--;
1158                                switch (icmp_code) {
1159#if ENABLE_TRACEROUTE6
1160                                case ICMP6_DST_UNREACH_NOPORT << 8:
1161                                        got_there = 1;
1162                                        break;
1163#endif
1164                                case ICMP_UNREACH_PORT:
1165                                        if (ip->ip_ttl <= 1)
1166                                                printf(" !");
1167                                        got_there = 1;
1168                                        break;
1169
1170                                case ICMP_UNREACH_NET:
1171#if ENABLE_TRACEROUTE6 && (ICMP6_DST_UNREACH_NOROUTE != ICMP_UNREACH_NET)
1172                                case ICMP6_DST_UNREACH_NOROUTE << 8:
1173#endif
1174                                        printf(" !N");
1175                                        ++unreachable;
1176                                        break;
1177                                case ICMP_UNREACH_HOST:
1178#if ENABLE_TRACEROUTE6
1179                                case ICMP6_DST_UNREACH_ADDR << 8:
1180#endif
1181                                        printf(" !H");
1182                                        ++unreachable;
1183                                        break;
1184                                case ICMP_UNREACH_PROTOCOL:
1185                                        printf(" !P");
1186                                        got_there = 1;
1187                                        break;
1188                                case ICMP_UNREACH_NEEDFRAG:
1189                                        printf(" !F-%d", pmtu);
1190                                        ++unreachable;
1191                                        break;
1192                                case ICMP_UNREACH_SRCFAIL:
1193#if ENABLE_TRACEROUTE6
1194                                case ICMP6_DST_UNREACH_ADMIN << 8:
1195#endif
1196                                        printf(" !S");
1197                                        ++unreachable;
1198                                        break;
1199                                case ICMP_UNREACH_FILTER_PROHIB:
1200                                case ICMP_UNREACH_NET_PROHIB:   /* misuse */
1201                                        printf(" !A");
1202                                        ++unreachable;
1203                                        break;
1204                                case ICMP_UNREACH_HOST_PROHIB:
1205                                        printf(" !C");
1206                                        ++unreachable;
1207                                        break;
1208                                case ICMP_UNREACH_HOST_PRECEDENCE:
1209                                        printf(" !V");
1210                                        ++unreachable;
1211                                        break;
1212                                case ICMP_UNREACH_PRECEDENCE_CUTOFF:
1213                                        printf(" !C");
1214                                        ++unreachable;
1215                                        break;
1216                                case ICMP_UNREACH_NET_UNKNOWN:
1217                                case ICMP_UNREACH_HOST_UNKNOWN:
1218                                        printf(" !U");
1219                                        ++unreachable;
1220                                        break;
1221                                case ICMP_UNREACH_ISOLATED:
1222                                        printf(" !I");
1223                                        ++unreachable;
1224                                        break;
1225                                case ICMP_UNREACH_TOSNET:
1226                                case ICMP_UNREACH_TOSHOST:
1227                                        printf(" !T");
1228                                        ++unreachable;
1229                                        break;
1230                                default:
1231                                        printf(" !<%d>", icmp_code);
1232                                        ++unreachable;
1233                                        break;
1234                                }
1235                                break;
1236                        } /* while (wait and read a packet) */
1237
1238                        /* there was no packet at all? */
1239                        if (read_len == 0)
1240                                printf("  *");
1241                } /* for (nprobes) */
1242
1243                bb_putchar('\n');
1244                if (got_there
1245                 || (unreachable > 0 && unreachable >= nprobes - 1)
1246                ) {
1247                        break;
1248                }
1249        }
1250
1251        return 0;
1252}
1253
1254int traceroute_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1255int traceroute_main(int argc UNUSED_PARAM, char **argv)
1256{
1257        return common_traceroute_main(0, argv);
1258}
1259
1260#if ENABLE_TRACEROUTE6
1261int traceroute6_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1262int traceroute6_main(int argc UNUSED_PARAM, char **argv)
1263{
1264        return common_traceroute_main(OPT_IPV6, argv);
1265}
1266#endif
1267