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