Ignore:
Timestamp:
Feb 25, 2011, 9:26:54 PM (8 years ago)
Author:
bruno
Message:
  • Update mindi-busybox to 1.18.3 to avoid problems with the tar command which is now failing on recent versions with busybox 1.7.3
File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/2.2.9/mindi-busybox/networking/traceroute.c

    r1765 r2725  
    2323 */
    2424
    25 //#define version "1.4a12"
    26 
     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 */
    2741
    2842/*
     
    215229#include <netinet/ip.h>
    216230#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
    217238
    218239#include "libbb.h"
    219240#include "inet_common.h"
    220241
    221 
    222 /*
    223  * Definitions for internet protocol version 4.
    224  * Per RFC 791, September 1981.
    225  */
    226 #define IPVERSION 4
    227 
    228242#ifndef IPPROTO_ICMP
    229 /* Grrrr.... */
    230 #define IPPROTO_ICMP 1
     243# define IPPROTO_ICMP 1
    231244#endif
    232245#ifndef IPPROTO_IP
    233 #define IPPROTO_IP 0
    234 #endif
    235 
    236 /*
    237  * Overlay for ip header used by other protocols (tcp, udp).
    238  */
    239 struct ipovly {
    240     unsigned char  ih_x1[9];               /* (unused) */
    241     unsigned char  ih_pr;                  /* protocol */
    242     short   ih_len;                 /* protocol length */
    243     struct  in_addr ih_src;         /* source internet address */
    244     struct  in_addr ih_dst;         /* destination internet address */
     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 */
    245274};
    246 
    247 /*
    248  * UDP kernel structures and variables.
    249  */
    250 struct udpiphdr {
    251     struct  ipovly ui_i;            /* overlaid ip structure */
    252     struct  udphdr ui_u;            /* udp header */
     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 */
    253281};
    254 #define ui_next         ui_i.ih_next
    255 #define ui_prev         ui_i.ih_prev
    256 #define ui_x1           ui_i.ih_x1
    257 #define ui_pr           ui_i.ih_pr
    258 #define ui_len          ui_i.ih_len
    259 #define ui_src          ui_i.ih_src
    260 #define ui_dst          ui_i.ih_dst
    261 #define ui_sport        ui_u.uh_sport
    262 #define ui_dport        ui_u.uh_dport
    263 #define ui_ulen         ui_u.uh_ulen
    264 #define ui_sum          ui_u.uh_sum
    265 
    266 
    267 /* Host name and address list */
    268 struct hostinfo {
    269     char *name;
    270     int n;
    271     uint32_t *addrs;
    272 };
    273282
    274283/* Data section of the probe packet */
    275 struct outdata {
     284struct outdata_t {
    276285    unsigned char seq;             /* sequence number of this packet */
    277286    unsigned char ttl;             /* ttl packet left with */
    278287// UNUSED. Retaining to have the same packet size.
    279     struct timeval tv_UNUSED ATTRIBUTE_PACKED; /* time packet left */
     288    struct timeval tv_UNUSED PACKED; /* time packet left */
    280289};
    281290
    282 struct IFADDRLIST {
    283     uint32_t addr;
    284     char device[sizeof(struct ifreq)];
     291#if ENABLE_TRACEROUTE6
     292struct outdata6_t {
     293    uint32_t ident6;
     294    uint32_t seq6;
     295    struct timeval tv_UNUSED PACKED; /* time packet left */
    285296};
    286 
    287 
    288 static struct ip *outip;               /* last output (udp) packet */
    289 static struct udphdr *outudp;          /* last output (udp) packet */
    290 static struct outdata *outdata;        /* last output (udp) packet */
    291 
    292 #if ENABLE_FEATURE_TRACEROUTE_USE_ICMP
    293 static struct icmp *outicmp;           /* last output (icmp) packet */
    294 #endif
    295 
    296 static int s;                          /* receive (icmp) socket file descriptor */
    297 static int sndsock;                    /* send (udp/icmp) socket file descriptor */
    298 
    299 static int packlen;                    /* total length of packet */
    300 static int minpacket;                  /* min ip packet size */
    301 static int maxpacket = 32 * 1024;      /* max ip packet size */
    302 static int pmtu;                       /* Path MTU Discovery (RFC1191) */
    303 
    304 static char *hostname;
    305 
    306 static uint16_t ident;
    307 static uint16_t port = 32768 + 666;     /* start udp dest port # for probe packets */
    308 
    309 static int waittime = 5;               /* time to wait for response (in seconds) */
    310 static int doipcksum = 1;              /* calculate ip checksums by default */
    311 
     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) */
    312308#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
    313 static int optlen;                     /* length of ip options */
     309    int optlen;                     /* length of ip options */
    314310#else
    315311#define optlen 0
    316312#endif
    317 
    318 
    319 /* Keep in sync with getopt32 call! */
    320 #define OPT_DONT_FRAGMNT (1<<0)    /* F */
    321 #define OPT_USE_ICMP     (1<<1)    /* I */
    322 #define OPT_TTL_FLAG     (1<<2)    /* l */
    323 #define OPT_ADDR_NUM     (1<<3)    /* n */
    324 #define OPT_BYPASS_ROUTE (1<<4)    /* r */
    325 #define OPT_DEBUG        (1<<5)    /* d */
    326 #define OPT_VERBOSE      (1<<6)    /* v */
    327 #define OPT_IP_CHKSUM    (1<<7)    /* x */
    328 #define OPT_TOS          (1<<8)    /* t */
    329 #define OPT_DEVICE       (1<<9)    /* i */
    330 #define OPT_MAX_TTL      (1<<10)   /* m */
    331 #define OPT_PORT         (1<<11)   /* p */
    332 #define OPT_NPROBES      (1<<12)   /* q */
    333 #define OPT_SOURCE       (1<<13)   /* s */
    334 #define OPT_WAITTIME     (1<<14)   /* w */
    335 #define OPT_PAUSE_MS     (1<<15)   /* z */
    336 #define OPT_FIRST_TTL    (1<<16)   /* f */
    337 
    338 #if ENABLE_FEATURE_TRACEROUTE_USE_ICMP
    339 /* use icmp echo instead of udp packets */
    340 #define useicmp (option_mask32 & OPT_USE_ICMP)
    341 #endif
    342 #if ENABLE_FEATURE_TRACEROUTE_VERBOSE
    343 #define verbose (option_mask32 & OPT_VERBOSE)
    344 #endif
    345 #define nflag   (option_mask32 & OPT_ADDR_NUM)
    346 
    347 
    348 struct globals {
    349     /* last inbound (icmp) packet */
    350     unsigned char packet[512];
    351     struct sockaddr_storage whereto;        /* Who to try to reach */
    352     struct sockaddr_storage wherefrom;      /* Who we are */
     313    unsigned char recv_pkt[512];    /* last inbound (icmp) packet */
    353314#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
    354315    /* Maximum number of gateways (include room for one noop) */
     
    360321
    361322#define G (*ptr_to_globals)
    362 
    363 #define packet    (G.packet   )
    364 #define whereto   (G.whereto  )
    365 #define wherefrom (G.wherefrom)
     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 )
    366335#define gwlist    (G.gwlist   )
    367 
    368 
    369 /*
    370  * Return the interface list
    371  */
     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
    372355static int
    373 ifaddrlist(struct IFADDRLIST **ipaddrp)
    374 {
    375     enum { IFREQ_BUFSIZE = (32 * 1024) / sizeof(struct ifreq) };
    376 
    377     int fd, nipaddr;
    378 #ifdef HAVE_SOCKADDR_SA_LEN
    379     int n;
    380 #endif
    381     struct ifreq *ifrp, *ifend, *ifnext;
    382     struct sockaddr_in *addr_sin;
    383     struct IFADDRLIST *al;
    384     struct ifconf ifc;
    385     struct ifreq ifr;
    386     /* Was on stack, but 32k is a bit too much: */
    387     struct ifreq *ibuf = xmalloc(IFREQ_BUFSIZE * sizeof(ibuf[0]));
    388     struct IFADDRLIST *st_ifaddrlist;
    389 
    390     fd = xsocket(AF_INET, SOCK_DGRAM, 0);
    391 
    392     ifc.ifc_len = IFREQ_BUFSIZE * sizeof(ibuf[0]);
    393     ifc.ifc_buf = (caddr_t)ibuf;
    394 
    395     if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0
    396      || ifc.ifc_len < sizeof(struct ifreq)
    397     ) {
    398         if (errno == EINVAL)
    399             bb_error_msg_and_die(
    400                 "SIOCGIFCONF: ifreq struct too small (%u bytes)",
    401                 (unsigned)(IFREQ_BUFSIZE * sizeof(ibuf[0])));
    402         bb_perror_msg_and_die("SIOCGIFCONF");
    403     }
    404     ifrp = ibuf;
    405     ifend = (struct ifreq *)((char *)ibuf + ifc.ifc_len);
    406 
    407     nipaddr = 1 + (ifc.ifc_len / sizeof(struct ifreq));
    408     st_ifaddrlist = xzalloc(nipaddr * sizeof(struct IFADDRLIST));
    409     al = st_ifaddrlist;
    410     nipaddr = 0;
    411 
    412     for (; ifrp < ifend; ifrp = ifnext) {
    413 #ifdef HAVE_SOCKADDR_SA_LEN
    414         n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
    415         if (n < sizeof(*ifrp))
    416             ifnext = ifrp + 1;
    417         else
    418             ifnext = (struct ifreq *)((char *)ifrp + n);
    419         if (ifrp->ifr_addr.sa_family != AF_INET)
    420             continue;
    421 #else
    422         ifnext = ifrp + 1;
    423 #endif
    424         /*
    425          * Need a template to preserve address info that is
    426          * used below to locate the next entry.  (Otherwise,
    427          * SIOCGIFFLAGS stomps over it because the requests
    428          * are returned in a union.)
    429          */
    430         strncpy(ifr.ifr_name, ifrp->ifr_name, sizeof(ifr.ifr_name));
    431         if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifr) < 0) {
    432             if (errno == ENXIO)
    433                 continue;
    434             bb_perror_msg_and_die("SIOCGIFFLAGS: %.*s",
    435                 (int)sizeof(ifr.ifr_name), ifr.ifr_name);
    436         }
    437 
    438         /* Must be up */
    439         if ((ifr.ifr_flags & IFF_UP) == 0)
    440             continue;
    441 
    442         safe_strncpy(al->device, ifr.ifr_name, sizeof(ifr.ifr_name) + 1);
    443 #ifdef sun
    444         /* Ignore sun virtual interfaces */
    445         if (strchr(al->device, ':') != NULL)
    446             continue;
    447 #endif
    448         ioctl_or_perror_and_die(fd, SIOCGIFADDR, (char *)&ifr,
    449                 "SIOCGIFADDR: %s", al->device);
    450 
    451         addr_sin = (struct sockaddr_in *)&ifr.ifr_addr;
    452         al->addr = addr_sin->sin_addr.s_addr;
    453         ++al;
    454         ++nipaddr;
    455     }
    456     if (nipaddr == 0)
    457         bb_error_msg_and_die("can't find any network interfaces");
    458 
    459     free(ibuf);
    460     close(fd);
    461     *ipaddrp = st_ifaddrlist;
    462     return nipaddr;
    463 }
    464 
    465 
    466 static void
    467 setsin(struct sockaddr_in *addr_sin, uint32_t addr)
    468 {
    469     memset(addr_sin, 0, sizeof(*addr_sin));
    470 #ifdef HAVE_SOCKADDR_SA_LEN
    471     addr_sin->sin_len = sizeof(*addr_sin);
    472 #endif
    473     addr_sin->sin_family = AF_INET;
    474     addr_sin->sin_addr.s_addr = addr;
    475 }
    476 
    477 
    478 /*
    479  * Return the source address for the given destination address
    480  */
    481 static void
    482 findsaddr(const struct sockaddr_in *to, struct sockaddr_in *from)
    483 {
    484     int i, n;
    485     FILE *f;
    486     uint32_t mask;
    487     uint32_t dest, tmask;
    488     struct IFADDRLIST *al;
    489     char buf[256], tdevice[256], device[256];
    490 
    491     f = xfopen("/proc/net/route", "r");
    492 
    493     /* Find the appropriate interface */
    494     n = 0;
    495     mask = 0;
    496     device[0] = '\0';
    497     while (fgets(buf, sizeof(buf), f) != NULL) {
    498         ++n;
    499         if (n == 1 && strncmp(buf, "Iface", 5) == 0)
    500             continue;
    501         i = sscanf(buf, "%255s %x %*s %*s %*s %*s %*s %x",
    502                     tdevice, &dest, &tmask);
    503         if (i != 3)
    504             bb_error_msg_and_die("junk in buffer");
    505         if ((to->sin_addr.s_addr & tmask) == dest
    506          && (tmask > mask || mask == 0)
    507         ) {
    508             mask = tmask;
    509             strcpy(device, tdevice);
    510         }
    511     }
    512     fclose(f);
    513 
    514     if (device[0] == '\0')
    515         bb_error_msg_and_die("can't find interface");
    516 
    517     /* Get the interface address list */
    518     n = ifaddrlist(&al);
    519 
    520     /* Find our appropriate source address */
    521     for (i = n; i > 0; --i, ++al)
    522         if (strcmp(device, al->device) == 0)
    523             break;
    524     if (i <= 0)
    525         bb_error_msg_and_die("can't find interface %s", device);
    526 
    527     setsin(from, al->addr);
    528 }
    529 
    530 /*
    531 "Usage: %s [-dFIlnrvx] [-g gateway] [-i iface] [-f first_ttl]\n"
    532 "\t[-m max_ttl] [ -p port] [-q nqueries] [-s src_addr] [-t tos]\n"
    533 "\t[-w waittime] [-z pausemsecs] host [packetlen]"
    534 
    535 */
    536 
    537 static int
    538 wait_for_reply(int sock, struct sockaddr_in *fromp)
    539 {
    540     fd_set fds;
    541     struct timeval tvwait;
    542     int cc = 0;
    543     socklen_t fromlen = sizeof(*fromp);
    544 
    545     FD_ZERO(&fds);
    546     FD_SET(sock, &fds);
    547 
    548     tvwait.tv_sec = waittime;
    549     tvwait.tv_usec = 0;
    550 
    551     if (select(sock + 1, &fds, NULL, NULL, &tvwait) > 0)
    552         cc = recvfrom(sock, (char *)packet, sizeof(packet), 0,
    553                 (struct sockaddr *)fromp, &fromlen);
    554 
    555     return cc;
     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;
    556371}
    557372
     
    568383
    569384    /*
    570      *  Our algorithm is simple, using a 32 bit accumulator (sum),
    571      *  we add sequential 16 bit words to it, and at the end, fold
    572      *  back all the carry bits from the top 16 bits into the lower
    573      *  16 bits.
     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.
    574389     */
    575     while (nleft > 1)  {
     390    while (nleft > 1) {
    576391        sum += *w++;
    577392        nleft -= 2;
     
    582397        sum += *(unsigned char *)w;
    583398
    584     /*
    585      * add back carry outs from top 16 bits to low 16 bits
    586      */
     399    /* add back carry outs from top 16 bits to low 16 bits */
    587400    sum = (sum >> 16) + (sum & 0xffff);     /* add hi 16 to low 16 */
    588401    sum += (sum >> 16);                     /* add carry */
     
    591404}
    592405
    593 
    594406static void
    595407send_probe(int seq, int ttl)
    596408{
    597     int cc;
    598     struct udpiphdr *ui, *oui;
    599     struct ip tip;
    600 
    601     outip->ip_ttl = ttl;
    602     outip->ip_id = htons(ident + seq);
    603 
    604     /*
    605      * In most cases, the kernel will recalculate the ip checksum.
    606      * But we must do it anyway so that the udp checksum comes out
    607      * right.
    608      */
    609     if (doipcksum) {
    610         outip->ip_sum =
    611             in_cksum((uint16_t *)outip, sizeof(*outip) + optlen);
    612         if (outip->ip_sum == 0)
    613             outip->ip_sum = 0xffff;
    614     }
     409    int len, res;
     410    void *out;
    615411
    616412    /* Payload */
    617     outdata->seq = seq;
    618     outdata->ttl = ttl;
     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;
    619424// UNUSED: was storing gettimeofday's result there, but never ever checked it
    620     /*memcpy(&outdata->tv, tp, sizeof(outdata->tv));*/
    621 
    622 #if ENABLE_FEATURE_TRACEROUTE_USE_ICMP
    623     if (useicmp)
    624         outicmp->icmp_seq = htons(seq);
    625     else
    626 #endif
    627         outudp->dest = htons(port + seq);
    628 
    629 #if ENABLE_FEATURE_TRACEROUTE_USE_ICMP
    630     if (useicmp) {
    631         /* Always calculate checksum for icmp packets */
    632         outicmp->icmp_cksum = 0;
    633         outicmp->icmp_cksum = in_cksum((uint16_t *)outicmp,
    634             packlen - (sizeof(*outip) + optlen));
    635         if (outicmp->icmp_cksum == 0)
    636             outicmp->icmp_cksum = 0xffff;
    637     } else
    638 #endif
    639     if (doipcksum) {
    640         /* Checksum (we must save and restore ip header) */
    641         tip = *outip;
    642         ui = (struct udpiphdr *)outip;
    643         oui = (struct udpiphdr *)&tip;
    644         /* Easier to zero and put back things that are ok */
    645         memset((char *)ui, 0, sizeof(ui->ui_i));
    646         ui->ui_src = oui->ui_src;
    647         ui->ui_dst = oui->ui_dst;
    648         ui->ui_pr = oui->ui_pr;
    649         ui->ui_len = outudp->len;
    650         outudp->check = 0;
    651         outudp->check = in_cksum((uint16_t *)ui, packlen);
    652         if (outudp->check == 0)
    653             outudp->check = 0xffff;
    654         *outip = tip;
    655     }
    656 
    657 #if ENABLE_FEATURE_TRACEROUTE_VERBOSE
     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
    658441    /* XXX undocumented debugging hack */
    659442    if (verbose > 1) {
     
    680463#endif
    681464
    682 #if !defined(IP_HDRINCL) && defined(IP_TTL)
    683     if (setsockopt(sndsock, IPPROTO_IP, IP_TTL,
    684         (char *)&ttl, sizeof(ttl)) < 0) {
    685         bb_perror_msg_and_die("setsockopt ttl %d", ttl);
    686     }
    687 #endif
    688 
    689     cc = xsendto(sndsock, (char *)outip,
    690         packlen, (struct sockaddr *)&whereto, sizeof(whereto));
    691     if (cc != packlen)  {
    692         bb_info_msg("wrote %s %d chars, ret=%d", hostname, packlen, cc);
    693     }
     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);
    694492}
    695493
     
    698496 * Convert an ICMP "type" field to a printable string.
    699497 */
    700 static inline const char *
     498static const char *
    701499pr_type(unsigned char t)
    702500{
     
    708506    "Info Reply",   "Mask Request", "Mask Reply"
    709507    };
    710 
    711     if (t > 18)
     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))
    712526        return "OUT-OF-RANGE";
    713527
     
    716530#endif
    717531
     532#if !ENABLE_FEATURE_TRACEROUTE_VERBOSE
     533#define packet4_ok(read_len, from, seq) \
     534    packet4_ok(read_len, seq)
     535#endif
    718536static int
    719 packet_ok(unsigned char *buf, int cc, struct sockaddr_in *from, int seq)
    720 {
    721     struct icmp *icp;
     537packet4_ok(int read_len, const struct sockaddr_in *from, int seq)
     538{
     539    const struct icmp *icp;
    722540    unsigned char type, code;
    723541    int hlen;
    724     struct ip *ip;
    725 
    726     ip = (struct ip *) buf;
     542    const struct ip *ip;
     543
     544    ip = (struct ip *) recv_pkt;
    727545    hlen = ip->ip_hl << 2;
    728     if (cc < hlen + ICMP_MINLEN) {
     546    if (read_len < hlen + ICMP_MINLEN) {
    729547#if ENABLE_FEATURE_TRACEROUTE_VERBOSE
    730548        if (verbose)
    731             printf("packet too short (%d bytes) from %s\n", cc,
     549            printf("packet too short (%d bytes) from %s\n", read_len,
    732550                inet_ntoa(from->sin_addr));
    733551#endif
    734552        return 0;
    735553    }
    736     cc -= hlen;
    737     icp = (struct icmp *)(buf + hlen);
     554    read_len -= hlen;
     555    icp = (struct icmp *)(recv_pkt + hlen);
    738556    type = icp->icmp_type;
    739557    code = icp->icmp_code;
    740558    /* Path MTU Discovery (RFC1191) */
    741     if (code != ICMP_UNREACH_NEEDFRAG)
    742         pmtu = 0;
    743     else {
     559    pmtu = 0;
     560    if (code == ICMP_UNREACH_NEEDFRAG)
    744561        pmtu = ntohs(icp->icmp_nextmtu);
    745     }
    746     if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
    747         type == ICMP_UNREACH || type == ICMP_ECHOREPLY) {
    748         struct ip *hip;
    749         struct udphdr *up;
     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;
    750569
    751570        hip = &icp->icmp_ip;
    752571        hlen = hip->ip_hl << 2;
    753 #if ENABLE_FEATURE_TRACEROUTE_USE_ICMP
    754         if (useicmp) {
     572        if (option_mask32 & OPT_USE_ICMP) {
    755573            struct icmp *hicmp;
    756574
    757575            /* XXX */
    758             if (type == ICMP_ECHOREPLY &&
    759                 icp->icmp_id == htons(ident) &&
    760                 icp->icmp_seq == htons(seq))
    761                 return -2;
     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            }
    762582
    763583            hicmp = (struct icmp *)((unsigned char *)hip + hlen);
    764             /* XXX 8 is a magic number */
    765             if (hlen + 8 <= cc &&
    766                 hip->ip_p == IPPROTO_ICMP &&
    767                 hicmp->icmp_id == htons(ident) &&
    768                 hicmp->icmp_seq == htons(seq))
     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            ) {
    769589                return (type == ICMP_TIMXCEED ? -1 : code + 1);
    770         } else
    771 #endif
    772         {
    773             up = (struct udphdr *)((unsigned char *)hip + hlen);
    774             /* XXX 8 is a magic number */
    775             if (hlen + 12 <= cc &&
    776                 hip->ip_p == IPPROTO_UDP &&
    777                 up->source == htons(ident) &&
    778                 up->dest == htons(port + seq))
     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            ) {
    779601                return (type == ICMP_TIMXCEED ? -1 : code + 1);
     602            }
    780603        }
    781604    }
     
    787610        printf("\n%d bytes from %s to "
    788611               "%s: icmp type %d (%s) code %d\n",
    789             cc, inet_ntoa(from->sin_addr),
    790             inet_ntoa(ip->ip_dst), type, pr_type(type), icp->icmp_code);
    791         for (i = 4; i < cc; i += sizeof(*lp))
     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))
    792616            printf("%2d: x%8.8x\n", i, *lp++);
    793617    }
     
    796620}
    797621
     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# if ENABLE_FEATURE_TRACEROUTE_VERBOSE
     672    if (verbose) {
     673        unsigned char *p;
     674        char pa1[MAXHOSTNAMELEN];
     675        char pa2[MAXHOSTNAMELEN];
     676        int i;
     677
     678        p = (unsigned char *) (icp + 1);
     679
     680        printf("\n%d bytes from %s to "
     681               "%s: icmp type %d (%s) code %d\n",
     682            read_len,
     683            inet_ntop(AF_INET6, &from_lsa->u.sin6.sin6_addr, pa1, sizeof(pa1)),
     684            inet_ntop(AF_INET6, &((struct sockaddr_in6*)to)->sin6_addr, pa2, sizeof(pa2)),
     685            type, pr_type(type), icp->icmp6_code);
     686
     687        read_len -= sizeof(struct icmp6_hdr);
     688        for (i = 0; i < read_len ; i++) {
     689            if (i % 16 == 0)
     690                printf("%04x:", i);
     691            if (i % 4 == 0)
     692                bb_putchar(' ');
     693            printf("%02x", p[i]);
     694            if ((i % 16 == 15) && (i + 1 < read_len))
     695                bb_putchar('\n');
     696        }
     697        bb_putchar('\n');
     698    }
     699# endif
     700
     701    return 0;
     702}
     703#else /* !ENABLE_TRACEROUTE6 */
     704static ALWAYS_INLINE int
     705packet_ok(int read_len,
     706        len_and_sockaddr *from_lsa IF_NOT_FEATURE_TRACEROUTE_VERBOSE(UNUSED_PARAM),
     707        struct sockaddr *to UNUSED_PARAM,
     708        int seq)
     709{
     710    return packet4_ok(read_len, &from_lsa->u.sin, seq);
     711}
     712#endif
    798713
    799714/*
    800715 * Construct an Internet address representation.
    801  * If the nflag has been supplied, give
     716 * If the -n flag has been supplied, give
    802717 * numeric value, otherwise try for symbolic name.
    803718 */
    804 static inline void
    805 print_inetname(struct sockaddr_in *from)
    806 {
    807     const char *ina;
    808 
    809     ina = inet_ntoa(from->sin_addr);
    810     if (nflag)
    811         printf(" %s", ina);
    812     else {
     719static void
     720print_inetname(const struct sockaddr *from)
     721{
     722    char *ina = xmalloc_sockaddr2dotted_noport(from);
     723
     724    if (option_mask32 & OPT_ADDR_NUM) {
     725        printf("  %s", ina);
     726    } else {
    813727        char *n = NULL;
    814         if (from->sin_addr.s_addr != INADDR_ANY)
     728
     729        if (from->sa_family != AF_INET
     730         || ((struct sockaddr_in*)from)->sin_addr.s_addr != INADDR_ANY
     731        ) {
     732            /* Try to reverse resolve if it is not 0.0.0.0 */
    815733            n = xmalloc_sockaddr2host_noport((struct sockaddr*)from);
    816         printf(" %s (%s)", (n ? n : ina), ina);
     734        }
     735        printf("  %s (%s)", (n ? n : ina), ina);
    817736        free(n);
    818737    }
    819 }
    820 
    821 static inline void
    822 print(unsigned char *buf, int cc, struct sockaddr_in *from)
    823 {
    824     struct ip *ip;
    825     int hlen;
    826 
    827     ip = (struct ip *) buf;
    828     hlen = ip->ip_hl << 2;
    829     cc -= hlen;
    830 
     738    free(ina);
     739}
     740
     741static void
     742print(int read_len, const struct sockaddr *from, const struct sockaddr *to)
     743{
    831744    print_inetname(from);
    832 #if ENABLE_FEATURE_TRACEROUTE_VERBOSE
    833     if (verbose)
    834         printf(" %d bytes to %s", cc, inet_ntoa(ip->ip_dst));
    835 #endif
    836 }
    837 
    838 
    839 static struct hostinfo *
    840 gethostinfo(const char *host)
    841 {
    842     int n;
    843     struct hostent *hp;
    844     struct hostinfo *hi;
    845     char **p;
    846     uint32_t addr, *ap;
    847 
    848     hi = xzalloc(sizeof(*hi));
    849     addr = inet_addr(host);
    850     if (addr != 0xffffffff) {
    851         hi->name = xstrdup(host);
    852         hi->n = 1;
    853         hi->addrs = xzalloc(sizeof(hi->addrs[0]));
    854         hi->addrs[0] = addr;
    855         return hi;
    856     }
    857 
    858     hp = xgethostbyname(host);
    859     if (hp->h_addrtype != AF_INET || hp->h_length != 4)
    860         bb_perror_msg_and_die("bad host %s", host);
    861     hi->name = xstrdup(hp->h_name);
    862     for (n = 0, p = hp->h_addr_list; *p != NULL; ++n, ++p)
    863         continue;
    864     hi->n = n;
    865     hi->addrs = xzalloc(n * sizeof(hi->addrs[0]));
    866     for (ap = hi->addrs, p = hp->h_addr_list; *p != NULL; ++ap, ++p)
    867         memcpy(ap, *p, sizeof(*ap));
    868     return hi;
    869 }
    870 
    871 static void
    872 freehostinfo(struct hostinfo *hi)
    873 {
    874     free(hi->name);
    875     free(hi->addrs);
    876     free(hi);
    877 }
    878 
    879 #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
    880 static void
    881 getaddr(uint32_t *ap, const char *host)
    882 {
    883     struct hostinfo *hi;
    884 
    885     hi = gethostinfo(host);
    886     *ap = hi->addrs[0];
    887     freehostinfo(hi);
    888 }
    889 #endif
     745
     746    if (verbose) {
     747        char *ina = xmalloc_sockaddr2dotted_noport(to);
     748#if ENABLE_TRACEROUTE6
     749        if (to->sa_family == AF_INET6) {
     750            read_len -= sizeof(struct ip6_hdr);
     751        } else
     752#endif
     753        {
     754            read_len -= ((struct ip*)recv_pkt)->ip_hl << 2;
     755        }
     756        printf(" %d bytes to %s", read_len, ina);
     757        free(ina);
     758    }
     759}
    890760
    891761static void
     
    893763{
    894764    unsigned tt = t2p - t1p;
    895     printf("  %u.%03u ms", tt/1000, tt%1000);
    896 }
    897 
    898 int traceroute_main(int argc, char **argv);
    899 int traceroute_main(int argc, char **argv)
    900 {
    901     int code, n;
    902     unsigned char *outp;
    903     uint32_t *ap;
    904     struct sockaddr_in *from;
    905     struct sockaddr_in *to;
    906     struct hostinfo *hi;
    907     int ttl, probe, i;
    908     int seq = 0;
     765    printf("  %u.%03u ms", tt / 1000, tt % 1000);
     766}
     767
     768/*
     769 * Usage: [-dFIlnrvx] [-g gateway] [-i iface] [-f first_ttl]
     770 * [-m max_ttl] [ -p port] [-q nqueries] [-s src_addr] [-t tos]
     771 * [-w waittime] [-z pausemsecs] host [packetlen]"
     772 */
     773static int
     774common_traceroute_main(int op, char **argv)
     775{
     776    int i;
     777    int minpacket;
    909778    int tos = 0;
     779    int max_ttl = 30;
     780    int nprobes = 3;
     781    int first_ttl = 1;
     782    unsigned pausemsecs = 0;
     783    char *source;
     784    char *device;
    910785    char *tos_str;
    911     char *source;
    912     unsigned op;
    913 #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
    914     int lsrr = 0;
    915 #endif
    916     uint16_t off = 0;
    917     struct IFADDRLIST *al;
    918     char *device;
    919     int max_ttl = 30;
    920786    char *max_ttl_str;
    921787    char *port_str;
    922     int nprobes = 3;
    923788    char *nprobes_str;
    924789    char *waittime_str;
    925     unsigned pausemsecs = 0;
    926790    char *pausemsecs_str;
    927     int first_ttl = 1;
    928791    char *first_ttl_str;
    929792#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
    930793    llist_t *source_route_list = NULL;
    931 #endif
    932 
    933     PTR_TO_GLOBALS = xzalloc(sizeof(G));
    934     from = (struct sockaddr_in *)&wherefrom;
    935     to = (struct sockaddr_in *)&whereto;
    936 
    937     //opterr = 0;
    938 #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
    939     opt_complementary = "x-x:g::";
     794    int lsrr = 0;
     795#endif
     796#if ENABLE_TRACEROUTE6
     797    sa_family_t af;
    940798#else
    941     opt_complementary = "x-x";
    942 #endif
    943 
    944     op = getopt32(argv, "FIlnrdvxt:i:m:p:q:s:w:z:f:"
    945 #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
    946                     "g:"
    947 #endif
     799    enum { af = AF_INET };
     800#endif
     801    int ttl;
     802    int seq;
     803    len_and_sockaddr *from_lsa;
     804    struct sockaddr *lastaddr;
     805    struct sockaddr *to;
     806
     807    INIT_G();
     808
     809    /* minimum 1 arg */
     810    opt_complementary = "-1:x-x" IF_FEATURE_TRACEROUTE_SOURCE_ROUTE(":g::");
     811    op |= getopt32(argv, OPT_STRING
    948812        , &tos_str, &device, &max_ttl_str, &port_str, &nprobes_str
    949813        , &source, &waittime_str, &pausemsecs_str, &first_ttl_str
     
    952816#endif
    953817    );
    954 
    955     if (op & OPT_DONT_FRAGMNT)
    956         off = IP_DF;
    957     if (op & OPT_IP_CHKSUM) {
    958         doipcksum = 0;
     818    argv += optind;
     819
     820#if 0 /* IGNORED */
     821    if (op & OPT_IP_CHKSUM)
    959822        bb_error_msg("warning: ip checksums disabled");
    960     }
     823#endif
    961824    if (op & OPT_TOS)
    962825        tos = xatou_range(tos_str, 0, 255);
     
    972835         * probe (e.g., on a multi-homed host).
    973836         */
    974         if (getuid())
    975             bb_error_msg_and_die("-s %s: permission denied", source);
     837        if (getuid() != 0)
     838            bb_error_msg_and_die(bb_msg_you_must_be_root);
    976839    }
    977840    if (op & OPT_WAITTIME)
    978         waittime = xatou_range(waittime_str, 2, 24 * 60 * 60);
     841        waittime = xatou_range(waittime_str, 1, 24 * 60 * 60);
    979842    if (op & OPT_PAUSE_MS)
    980843        pausemsecs = xatou_range(pausemsecs_str, 0, 60 * 60 * 1000);
    981844    if (op & OPT_FIRST_TTL)
    982         first_ttl = xatou_range(first_ttl_str, 1, 255);
     845        first_ttl = xatou_range(first_ttl_str, 1, max_ttl);
    983846
    984847#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
    985848    if (source_route_list) {
    986         llist_t *l_sr;
    987 
    988         l_sr = source_route_list;
    989         while (l_sr) {
     849        while (source_route_list) {
     850            len_and_sockaddr *lsa;
     851
    990852            if (lsrr >= NGATEWAYS)
    991853                bb_error_msg_and_die("no more than %d gateways", NGATEWAYS);
    992             getaddr(gwlist + lsrr, l_sr->data);
     854            lsa = xhost_and_af2sockaddr(llist_pop(&source_route_list), 0, AF_INET);
     855            gwlist[lsrr] = lsa->u.sin.sin_addr.s_addr;
     856            free(lsa);
    993857            ++lsrr;
    994             l_sr = l_sr->link;
    995             free(source_route_list);
    996             source_route_list = l_sr;
    997858        }
    998859        optlen = (lsrr + 1) * sizeof(gwlist[0]);
     
    1000861#endif
    1001862
    1002     if (first_ttl > max_ttl) {
    1003         bb_error_msg_and_die(
    1004             "first ttl (%d) may not be greater than max ttl (%d)",
    1005             first_ttl, max_ttl);
    1006     }
    1007 
    1008     minpacket = sizeof(*outip) + sizeof(*outdata) + optlen;
    1009 
    1010 #if ENABLE_FEATURE_TRACEROUTE_USE_ICMP
    1011     if (useicmp)
    1012         minpacket += 8;                 /* XXX magic number */
    1013     else
    1014 #endif
    1015         minpacket += sizeof(*outudp);
    1016     packlen = minpacket;                    /* minimum sized packet */
    1017 
    1018863    /* Process destination and optional packet size */
    1019     switch (argc - optind) {
    1020 
    1021     case 2:
    1022         packlen = xatoul_range(argv[optind + 1], minpacket, maxpacket);
    1023         /* Fall through */
    1024 
    1025     case 1:
    1026         hostname = argv[optind];
    1027         hi = gethostinfo(hostname);
    1028         setsin(to, hi->addrs[0]);
    1029         if (hi->n > 1)
    1030             bb_error_msg("warning: %s has multiple addresses; using %s",
    1031                 hostname, inet_ntoa(to->sin_addr));
    1032         hostname = hi->name;
    1033         hi->name = NULL;
    1034         freehostinfo(hi);
    1035         break;
    1036 
    1037     default:
    1038         bb_show_usage();
    1039     }
     864    minpacket = sizeof(*outip) + SIZEOF_ICMP_HDR + sizeof(*outdata) + optlen;
     865    if (!(op & OPT_USE_ICMP))
     866        minpacket += sizeof(*outudp) - SIZEOF_ICMP_HDR;
     867#if ENABLE_TRACEROUTE6
     868    af = AF_UNSPEC;
     869    if (op & OPT_IPV4)
     870        af = AF_INET;
     871    if (op & OPT_IPV6)
     872        af = AF_INET6;
     873    dest_lsa = xhost_and_af2sockaddr(argv[0], port, af);
     874    af = dest_lsa->u.sa.sa_family;
     875    if (af == AF_INET6)
     876        minpacket = sizeof(struct outdata6_t);
     877#else
     878    dest_lsa = xhost2sockaddr(argv[0], port);
     879#endif
     880    packlen = minpacket;
     881    if (argv[1])
     882        packlen = xatoul_range(argv[1], minpacket, 32 * 1024);
    1040883
    1041884    /* Ensure the socket fds won't be 0, 1 or 2 */
    1042885    bb_sanitize_stdio();
    1043886
    1044     s = xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
     887#if ENABLE_TRACEROUTE6
     888    if (af == AF_INET6) {
     889        xmove_fd(xsocket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6), rcvsock);
     890# ifdef IPV6_RECVPKTINFO
     891        setsockopt(rcvsock, SOL_IPV6, IPV6_RECVPKTINFO,
     892                &const_int_1, sizeof(const_int_1));
     893        setsockopt(rcvsock, SOL_IPV6, IPV6_2292PKTINFO,
     894                &const_int_1, sizeof(const_int_1));
     895# else
     896        setsockopt(rcvsock, SOL_IPV6, IPV6_PKTINFO,
     897                &const_int_1, sizeof(const_int_1));
     898# endif
     899    } else
     900#endif
     901    {
     902        xmove_fd(xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP), rcvsock);
     903    }
    1045904
    1046905#if TRACEROUTE_SO_DEBUG
    1047906    if (op & OPT_DEBUG)
    1048         setsockopt(s, SOL_SOCKET, SO_DEBUG,
     907        setsockopt(rcvsock, SOL_SOCKET, SO_DEBUG,
    1049908                &const_int_1, sizeof(const_int_1));
    1050909#endif
    1051910    if (op & OPT_BYPASS_ROUTE)
    1052         setsockopt(s, SOL_SOCKET, SO_DONTROUTE,
     911        setsockopt(rcvsock, SOL_SOCKET, SO_DONTROUTE,
    1053912                &const_int_1, sizeof(const_int_1));
    1054913
    1055     sndsock = xsocket(AF_INET, SOCK_RAW, IPPROTO_RAW);
    1056 
    1057 #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
    1058 #if defined(IP_OPTIONS)
    1059     if (lsrr > 0) {
    1060         unsigned char optlist[MAX_IPOPTLEN];
    1061 
    1062         /* final hop */
    1063         gwlist[lsrr] = to->sin_addr.s_addr;
    1064         ++lsrr;
    1065 
    1066         /* force 4 byte alignment */
    1067         optlist[0] = IPOPT_NOP;
    1068         /* loose source route option */
    1069         optlist[1] = IPOPT_LSRR;
    1070         i = lsrr * sizeof(gwlist[0]);
    1071         optlist[2] = i + 3;
    1072         /* Pointer to LSRR addresses */
    1073         optlist[3] = IPOPT_MINOFF;
    1074         memcpy(optlist + 4, gwlist, i);
    1075 
    1076         if ((setsockopt(sndsock, IPPROTO_IP, IP_OPTIONS,
    1077             (char *)optlist, i + sizeof(gwlist[0]))) < 0) {
    1078             bb_perror_msg_and_die("IP_OPTIONS");
    1079         }
    1080     }
    1081 #endif /* IP_OPTIONS */
    1082 #endif /* CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE */
     914#if ENABLE_TRACEROUTE6
     915    if (af == AF_INET6) {
     916        static const int two = 2;
     917        if (setsockopt(rcvsock, SOL_RAW, IPV6_CHECKSUM, &two, sizeof(two)) < 0)
     918            bb_perror_msg_and_die("setsockopt RAW_CHECKSUM");
     919        xmove_fd(xsocket(af, SOCK_DGRAM, 0), sndsock);
     920    } else
     921#endif
     922    {
     923        if (op & OPT_USE_ICMP)
     924            xmove_fd(xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP), sndsock);
     925        else
     926            xmove_fd(xsocket(AF_INET, SOCK_DGRAM, 0), sndsock);
     927#if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE && defined IP_OPTIONS
     928        if (lsrr > 0) {
     929            unsigned char optlist[MAX_IPOPTLEN];
     930
     931            /* final hop */
     932            gwlist[lsrr] = dest_lsa->u.sin.sin_addr.s_addr;
     933            ++lsrr;
     934
     935            /* force 4 byte alignment */
     936            optlist[0] = IPOPT_NOP;
     937            /* loose source route option */
     938            optlist[1] = IPOPT_LSRR;
     939            i = lsrr * sizeof(gwlist[0]);
     940            optlist[2] = i + 3;
     941            /* pointer to LSRR addresses */
     942            optlist[3] = IPOPT_MINOFF;
     943            memcpy(optlist + 4, gwlist, i);
     944
     945            if (setsockopt(sndsock, IPPROTO_IP, IP_OPTIONS,
     946                    (char *)optlist, i + sizeof(gwlist[0])) < 0) {
     947                bb_perror_msg_and_die("IP_OPTIONS");
     948            }
     949        }
     950#endif
     951    }
    1083952
    1084953#ifdef SO_SNDBUF
     
    1087956    }
    1088957#endif
    1089 #ifdef IP_HDRINCL
    1090     if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, &const_int_1, sizeof(const_int_1)) < 0
    1091      && errno != ENOPROTOOPT
    1092     ) {
    1093         bb_perror_msg_and_die("IP_HDRINCL");
    1094     }
    1095 #else
    1096958#ifdef IP_TOS
    1097     if (tos_str && setsockopt(sndsock, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0) {
     959    if ((op & OPT_TOS) && setsockopt(sndsock, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0) {
    1098960        bb_perror_msg_and_die("setsockopt tos %d", tos);
    1099961    }
    1100962#endif
     963#ifdef IP_DONTFRAG
     964    if (op & OPT_DONT_FRAGMNT)
     965        setsockopt(sndsock, IPPROTO_IP, IP_DONTFRAG,
     966                &const_int_1, sizeof(const_int_1));
    1101967#endif
    1102968#if TRACEROUTE_SO_DEBUG
     
    1109975                &const_int_1, sizeof(const_int_1));
    1110976
     977    outip = xzalloc(packlen);
     978
     979    ident = getpid();
     980
     981    if (af == AF_INET) {
     982        if (op & OPT_USE_ICMP) {
     983            ident |= 0x8000;
     984            outicmp->icmp_type = ICMP_ECHO;
     985            outicmp->icmp_id = htons(ident);
     986            outdata = (struct outdata_t *)((char *)outicmp + SIZEOF_ICMP_HDR);
     987        } else {
     988            outdata = (struct outdata_t *)(outudp + 1);
     989        }
     990    }
     991
     992    if (op & OPT_DEVICE) /* hmm, do we need error check? */
     993        setsockopt_bindtodevice(sndsock, device);
     994
     995    if (op & OPT_SOURCE) {
     996#if ENABLE_TRACEROUTE6
     997// TODO: need xdotted_and_af2sockaddr?
     998        len_and_sockaddr *source_lsa = xhost_and_af2sockaddr(source, 0, af);
     999#else
     1000        len_and_sockaddr *source_lsa = xdotted2sockaddr(source, 0);
     1001#endif
     1002        /* Ping4 does this (why?) */
     1003        if (af == AF_INET)
     1004            if (setsockopt(sndsock, IPPROTO_IP, IP_MULTICAST_IF,
     1005                    &source_lsa->u.sa, source_lsa->len))
     1006                bb_error_msg_and_die("can't set multicast source interface");
     1007//TODO: we can query source port we bound to,
     1008// and check it in replies... if we care enough
     1009        xbind(sndsock, &source_lsa->u.sa, source_lsa->len);
     1010        free(source_lsa);
     1011    }
     1012#if ENABLE_TRACEROUTE6
     1013    else if (af == AF_INET6) {
     1014//TODO: why we don't do it for IPv4?
     1015        len_and_sockaddr *source_lsa;
     1016
     1017        int probe_fd = xsocket(af, SOCK_DGRAM, 0);
     1018        if (op & OPT_DEVICE)
     1019            setsockopt_bindtodevice(probe_fd, device);
     1020        set_nport(dest_lsa, htons(1025));
     1021        /* dummy connect. makes kernel pick source IP (and port) */
     1022        xconnect(probe_fd, &dest_lsa->u.sa, dest_lsa->len);
     1023        set_nport(dest_lsa, htons(port));
     1024
     1025        /* read IP and port */
     1026        source_lsa = get_sock_lsa(probe_fd);
     1027        if (source_lsa == NULL)
     1028            bb_error_msg_and_die("can't get probe addr");
     1029
     1030        close(probe_fd);
     1031
     1032        /* bind our sockets to this IP (but not port) */
     1033        set_nport(source_lsa, 0);
     1034        xbind(sndsock, &source_lsa->u.sa, source_lsa->len);
     1035        xbind(rcvsock, &source_lsa->u.sa, source_lsa->len);
     1036
     1037        free(source_lsa);
     1038    }
     1039#endif
     1040
    11111041    /* Revert to non-privileged user after opening sockets */
    11121042    xsetgid(getgid());
    11131043    xsetuid(getuid());
    11141044
    1115     outip = xzalloc(packlen);
    1116 
    1117     outip->ip_v = IPVERSION;
    1118     if (tos_str)
    1119         outip->ip_tos = tos;
    1120     outip->ip_len = htons(packlen);
    1121     outip->ip_off = htons(off);
    1122     outp = (unsigned char *)(outip + 1);
    1123     outip->ip_dst = to->sin_addr;
    1124 
    1125     outip->ip_hl = (outp - (unsigned char *)outip) >> 2;
    1126     ident = (getpid() & 0xffff) | 0x8000;
    1127 #if ENABLE_FEATURE_TRACEROUTE_USE_ICMP
    1128     if (useicmp) {
    1129         outip->ip_p = IPPROTO_ICMP;
    1130         outicmp = (struct icmp *)outp;
    1131         outicmp->icmp_type = ICMP_ECHO;
    1132         outicmp->icmp_id = htons(ident);
    1133         outdata = (struct outdata *)(outp + 8); /* XXX magic number */
    1134     } else
    1135 #endif
    1136     {
    1137         outip->ip_p = IPPROTO_UDP;
    1138         outudp = (struct udphdr *)outp;
    1139         outudp->source = htons(ident);
    1140         outudp->len = htons((uint16_t)(packlen - (sizeof(*outip) + optlen)));
    1141         outdata = (struct outdata *)(outudp + 1);
    1142     }
    1143 
    1144     /* Get the interface address list */
    1145     n = ifaddrlist(&al);
    1146 
    1147     /* Look for a specific device */
    1148     if (op & OPT_DEVICE) {
    1149         for (i = n; i > 0; --i, ++al)
    1150             if (strcmp(device, al->device) == 0)
    1151                 goto found_dev;
    1152         bb_error_msg_and_die("can't find interface %s", device);
    1153     }
    1154  found_dev:
    1155 
    1156     /* Determine our source address */
    1157     if (!(op & OPT_SOURCE)) {
    1158         /*
    1159          * If a device was specified, use the interface address.
    1160          * Otherwise, try to determine our source address.
    1161          */
    1162         if (op & OPT_DEVICE)
    1163             setsin(from, al->addr);
    1164         findsaddr(to, from);
    1165     } else {
    1166         hi = gethostinfo(source);
    1167         source = hi->name;
    1168         hi->name = NULL;
    1169         /*
    1170          * If the device was specified make sure it
    1171          * corresponds to the source address specified.
    1172          * Otherwise, use the first address (and warn if
    1173          * there are more than one).
    1174          */
    1175         if (op & OPT_DEVICE) {
    1176             for (i = hi->n, ap = hi->addrs; i > 0; --i, ++ap)
    1177                 if (*ap == al->addr)
    1178                     goto found_dev2;
    1179             bb_error_msg_and_die("%s is not on interface %s",
    1180                     source, device);
    1181  found_dev2:
    1182             setsin(from, *ap);
    1183         } else {
    1184             setsin(from, hi->addrs[0]);
    1185             if (hi->n > 1)
    1186                 bb_error_msg(
    1187             "warning: %s has multiple addresses; using %s",
    1188                     source, inet_ntoa(from->sin_addr));
    1189         }
    1190         freehostinfo(hi);
    1191     }
    1192 
    1193     outip->ip_src = from->sin_addr;
    1194 #ifndef IP_HDRINCL
    1195     xbind(sndsock, (struct sockaddr *)from, sizeof(*from));
    1196 #endif
    1197 
    1198     printf("traceroute to %s (%s)", hostname, inet_ntoa(to->sin_addr));
     1045    printf("traceroute to %s (%s)", argv[0],
     1046            xmalloc_sockaddr2dotted_noport(&dest_lsa->u.sa));
    11991047    if (op & OPT_SOURCE)
    12001048        printf(" from %s", source);
    12011049    printf(", %d hops max, %d byte packets\n", max_ttl, packlen);
    1202     fflush(stdout);
    1203 
     1050
     1051    from_lsa = dup_sockaddr(dest_lsa);
     1052    lastaddr = xzalloc(dest_lsa->len);
     1053    to = xzalloc(dest_lsa->len);
     1054    seq = 0;
    12041055    for (ttl = first_ttl; ttl <= max_ttl; ++ttl) {
    1205         uint32_t lastaddr = 0;
    1206         int gotlastaddr = 0;
     1056        int probe;
     1057        int unreachable = 0; /* counter */
     1058        int gotlastaddr = 0; /* flags */
    12071059        int got_there = 0;
    1208         int unreachable = 0;
    1209         int sentfirst = 0;
    1210 
    1211         printf("%2d ", ttl);
     1060        int first = 1;
     1061
     1062        printf("%2d", ttl);
    12121063        for (probe = 0; probe < nprobes; ++probe) {
    1213             int cc;
     1064            int read_len;
    12141065            unsigned t1;
    12151066            unsigned t2;
    12161067            struct ip *ip;
    12171068
    1218             if (sentfirst && pausemsecs > 0)
     1069            if (!first && pausemsecs > 0)
    12191070                usleep(pausemsecs * 1000);
     1071            fflush_all();
     1072
    12201073            t1 = monotonic_us();
    12211074            send_probe(++seq, ttl);
    1222             ++sentfirst;
    1223             while ((cc = wait_for_reply(s, from)) != 0) {
     1075
     1076            first = 0;
     1077            while ((read_len = wait_for_reply(from_lsa, to)) != 0) {
    12241078                t2 = monotonic_us();
    1225                 i = packet_ok(packet, cc, from, seq);
     1079                i = packet_ok(read_len, from_lsa, to, seq);
    12261080                /* Skip short packet */
    12271081                if (i == 0)
    12281082                    continue;
    1229                 if (!gotlastaddr ||
    1230                     from->sin_addr.s_addr != lastaddr) {
    1231                     print(packet, cc, from);
    1232                     lastaddr = from->sin_addr.s_addr;
    1233                     ++gotlastaddr;
     1083
     1084                if (!gotlastaddr
     1085                 || (memcmp(lastaddr, &from_lsa->u.sa, from_lsa->len) != 0)
     1086                ) {
     1087                    print(read_len, &from_lsa->u.sa, to);
     1088                    memcpy(lastaddr, &from_lsa->u.sa, from_lsa->len);
     1089                    gotlastaddr = 1;
    12341090                }
     1091
    12351092                print_delta_ms(t1, t2);
    1236                 ip = (struct ip *)packet;
    1237                 if (op & OPT_TTL_FLAG)
    1238                     printf(" (%d)", ip->ip_ttl);
    1239                 if (i == -2) {
    1240                     if (ip->ip_ttl <= 1)
    1241                         printf(" !");
    1242                     ++got_there;
    1243                     break;
    1244                 }
     1093                ip = (struct ip *)recv_pkt;
     1094
     1095                if (from_lsa->u.sa.sa_family == AF_INET)
     1096                    if (op & OPT_TTL_FLAG)
     1097                        printf(" (%d)", ip->ip_ttl);
     1098
    12451099                /* time exceeded in transit */
    12461100                if (i == -1)
    12471101                    break;
    1248                 code = i - 1;
    1249                 switch (code) {
    1250 
     1102                i--;
     1103                switch (i) {
     1104#if ENABLE_TRACEROUTE6
     1105                case ICMP6_DST_UNREACH_NOPORT << 8:
     1106                    got_there = 1;
     1107                    break;
     1108#endif
    12511109                case ICMP_UNREACH_PORT:
    12521110                    if (ip->ip_ttl <= 1)
    12531111                        printf(" !");
    1254                     ++got_there;
     1112                    got_there = 1;
    12551113                    break;
    12561114
    12571115                case ICMP_UNREACH_NET:
     1116#if ENABLE_TRACEROUTE6 && (ICMP6_DST_UNREACH_NOROUTE != ICMP_UNREACH_NET)
     1117                case ICMP6_DST_UNREACH_NOROUTE << 8:
     1118#endif
     1119                    printf(" !N");
    12581120                    ++unreachable;
    1259                     printf(" !N");
    1260                     break;
    1261 
     1121                    break;
    12621122                case ICMP_UNREACH_HOST:
     1123#if ENABLE_TRACEROUTE6
     1124                case ICMP6_DST_UNREACH_ADDR << 8:
     1125#endif
     1126                    printf(" !H");
    12631127                    ++unreachable;
    1264                     printf(" !H");
    1265                     break;
    1266 
     1128                    break;
    12671129                case ICMP_UNREACH_PROTOCOL:
    1268                     ++got_there;
    12691130                    printf(" !P");
    1270                     break;
    1271 
     1131                    got_there = 1;
     1132                    break;
    12721133                case ICMP_UNREACH_NEEDFRAG:
     1134                    printf(" !F-%d", pmtu);
    12731135                    ++unreachable;
    1274                     printf(" !F-%d", pmtu);
    1275                     break;
    1276 
     1136                    break;
    12771137                case ICMP_UNREACH_SRCFAIL:
     1138#if ENABLE_TRACEROUTE6
     1139                case ICMP6_DST_UNREACH_ADMIN << 8:
     1140#endif
     1141                    printf(" !S");
    12781142                    ++unreachable;
    1279                     printf(" !S");
    1280                     break;
    1281 
     1143                    break;
    12821144                case ICMP_UNREACH_FILTER_PROHIB:
    12831145                case ICMP_UNREACH_NET_PROHIB:   /* misuse */
     1146                    printf(" !A");
    12841147                    ++unreachable;
    1285                     printf(" !A");
    1286                     break;
    1287 
     1148                    break;
    12881149                case ICMP_UNREACH_HOST_PROHIB:
     1150                    printf(" !C");
    12891151                    ++unreachable;
     1152                    break;
     1153                case ICMP_UNREACH_HOST_PRECEDENCE:
     1154                    printf(" !V");
     1155                    ++unreachable;
     1156                    break;
     1157                case ICMP_UNREACH_PRECEDENCE_CUTOFF:
    12901158                    printf(" !C");
    1291                     break;
    1292 
    1293                 case ICMP_UNREACH_HOST_PRECEDENCE:
    12941159                    ++unreachable;
    1295                     printf(" !V");
    1296                     break;
    1297 
    1298                 case ICMP_UNREACH_PRECEDENCE_CUTOFF:
    1299                     ++unreachable;
    1300                     printf(" !C");
    1301                     break;
    1302 
     1160                    break;
    13031161                case ICMP_UNREACH_NET_UNKNOWN:
    13041162                case ICMP_UNREACH_HOST_UNKNOWN:
     1163                    printf(" !U");
    13051164                    ++unreachable;
    1306                     printf(" !U");
    1307                     break;
    1308 
     1165                    break;
    13091166                case ICMP_UNREACH_ISOLATED:
     1167                    printf(" !I");
    13101168                    ++unreachable;
    1311                     printf(" !I");
    1312                     break;
    1313 
     1169                    break;
    13141170                case ICMP_UNREACH_TOSNET:
    13151171                case ICMP_UNREACH_TOSHOST:
     1172                    printf(" !T");
    13161173                    ++unreachable;
    1317                     printf(" !T");
    1318                     break;
    1319 
     1174                    break;
    13201175                default:
     1176                    printf(" !<%d>", i);
    13211177                    ++unreachable;
    1322                     printf(" !<%d>", code);
    13231178                    break;
    13241179                }
    13251180                break;
    13261181            }
    1327             if (cc == 0)
    1328                 printf(" *");
    1329             (void)fflush(stdout);
    1330         }
    1331         putchar('\n');
    1332         if (got_there ||
    1333             (unreachable > 0 && unreachable >= nprobes - 1))
     1182            /* there was no packet at all? */
     1183            if (read_len == 0)
     1184                printf("  *");
     1185        }
     1186        bb_putchar('\n');
     1187        if (got_there
     1188         || (unreachable > 0 && unreachable >= nprobes - 1)
     1189        ) {
    13341190            break;
    1335     }
     1191        }
     1192    }
     1193
    13361194    return 0;
    13371195}
     1196
     1197int traceroute_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     1198int traceroute_main(int argc UNUSED_PARAM, char **argv)
     1199{
     1200    return common_traceroute_main(0, argv);
     1201}
     1202
     1203#if ENABLE_TRACEROUTE6
     1204int traceroute6_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     1205int traceroute6_main(int argc UNUSED_PARAM, char **argv)
     1206{
     1207    return common_traceroute_main(OPT_IPV6, argv);
     1208}
     1209#endif
Note: See TracChangeset for help on using the changeset viewer.