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