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