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