Home | History | Annotate | Download | only in pending
      1 /* traceroute - trace the route to "host".
      2  *
      3  * Copyright 2012 Madhur Verma <mad.flexi (at) gmail.com>
      4  * Copyright 2013 Kyungwan Han <asura321 (at) gmail.com>
      5  * Copyright 2013 Bilal Qureshi <bilal.jmi (at) gmail.com>
      6  * Copyright 2013 Ashwini Kumar <ak.ashwini1981 (at) gmail.com>
      7  *
      8  * No Standard
      9 
     10 USE_TRACEROUTE(NEWTOY(traceroute, "<1>2i:f#<1>255=1z#<0>86400=0g*w#<0>86400=5t#<0>255=0s:q#<1>255=3p#<1>65535=33434m#<1>255=30rvndlIUF64", TOYFLAG_STAYROOT|TOYFLAG_USR|TOYFLAG_BIN))
     11 USE_TRACEROUTE(OLDTOY(traceroute6,traceroute, TOYFLAG_STAYROOT|TOYFLAG_USR|TOYFLAG_BIN))
     12 config TRACEROUTE
     13   bool "traceroute"
     14   default n
     15   help
     16     usage: traceroute [-46FUIldnvr] [-f 1ST_TTL] [-m MAXTTL] [-p PORT] [-q PROBES]
     17     [-s SRC_IP] [-t TOS] [-w WAIT_SEC] [-g GATEWAY] [-i IFACE] [-z PAUSE_MSEC] HOST [BYTES]
     18 
     19     traceroute6 [-dnrv] [-m MAXTTL] [-p PORT] [-q PROBES][-s SRC_IP] [-t TOS] [-w WAIT_SEC]
     20       [-i IFACE] HOST [BYTES]
     21 
     22     Trace the route to HOST
     23 
     24     -4,-6 Force IP or IPv6 name resolution
     25     -F    Set the don't fragment bit (supports IPV4 only)
     26     -U    Use UDP datagrams instead of ICMP ECHO (supports IPV4 only)
     27     -I    Use ICMP ECHO instead of UDP datagrams (supports IPV4 only)
     28     -l    Display the TTL value of the returned packet (supports IPV4 only)
     29     -d    Set SO_DEBUG options to socket
     30     -n    Print numeric addresses
     31     -v    verbose
     32     -r    Bypass routing tables, send directly to HOST
     33     -m    Max time-to-live (max number of hops)(RANGE 1 to 255)
     34     -p    Base UDP port number used in probes(default 33434)(RANGE 1 to 65535)
     35     -q    Number of probes per TTL (default 3)(RANGE 1 to 255)
     36     -s    IP address to use as the source address
     37     -t    Type-of-service in probe packets (default 0)(RANGE 0 to 255)
     38     -w    Time in seconds to wait for a response (default 3)(RANGE 0 to 86400)
     39     -g    Loose source route gateway (8 max) (supports IPV4 only)
     40     -z    Pause Time in ms (default 0)(RANGE 0 to 86400) (supports IPV4 only)
     41     -f    Start from the 1ST_TTL hop (instead from 1)(RANGE 1 to 255) (supports IPV4 only)
     42     -i    Specify a network interface to operate with
     43 */
     44 #define FOR_traceroute
     45 #include "toys.h"
     46 #include <netinet/udp.h>
     47 #include <netinet/ip_icmp.h>
     48 #include <netinet/ip6.h>
     49 #include <netinet/icmp6.h>
     50 
     51 GLOBALS(
     52   long max_ttl;
     53   long port;
     54   long ttl_probes;
     55   char *src_ip;
     56   long tos;
     57   long wait_time;
     58   struct arg_list *loose_source;
     59   long pause_time;
     60   long first_ttl;
     61   char *iface;
     62 
     63   uint32_t gw_list[9];
     64   int recv_sock;
     65   int snd_sock;
     66   unsigned msg_len;
     67   char *packet;
     68   uint32_t ident;
     69   int istraceroute6;
     70 )
     71 
     72 #ifndef SOL_IPV6
     73 # define SOL_IPV6 IPPROTO_IPV6
     74 #endif
     75 
     76 #define ICMP_HD_SIZE4  8
     77 #define USEC           1000000ULL
     78 
     79 struct payload_s {
     80   uint32_t seq;
     81   uint32_t ident;
     82 };
     83 
     84 char addr_str[INET6_ADDRSTRLEN];
     85 struct sockaddr_storage dest;
     86 
     87 //Compute checksum SUM of buffer P of length LEN
     88 static u_int16_t in_cksum(u_int16_t *p, u_int len)
     89 {
     90   u_int32_t sum = 0;
     91   int nwords = len >> 1;
     92 
     93   while (nwords-- != 0) sum += *p++;
     94   if (len & 1) {
     95     union {
     96       u_int16_t w;
     97       u_int8_t c[2];
     98     } u;
     99     u.c[0] = *(u_char *) p;
    100     u.c[1] = 0;
    101     sum += u.w;
    102   }
    103   // end-around-carry
    104   sum = (sum >> 16) + (sum & 0xffff);
    105   sum += (sum >> 16);
    106   return (~sum);
    107 }
    108 
    109 //sends a single probe packet with sequence(SEQ) and time-to-live(TTL)
    110 static void send_probe4(int seq, int ttl)
    111 {
    112   int res, len;
    113   void *out;
    114   struct payload_s *send_data4 = (struct payload_s *)(TT.packet);
    115   struct icmp *send_icmp4 = (struct icmp *)(TT.packet);
    116 
    117   if (toys.optflags & FLAG_U) {
    118     send_data4->seq = seq;
    119     send_data4->ident = TT.ident;
    120     ((struct sockaddr_in *)&dest)->sin_port = TT.port + seq;
    121     out = send_data4;
    122   } else {
    123     send_icmp4->icmp_type = ICMP_ECHO;
    124     send_icmp4->icmp_id = htons(TT.ident);
    125     send_icmp4->icmp_seq = htons(seq);
    126     send_icmp4->icmp_cksum = 0;
    127     send_icmp4->icmp_cksum = in_cksum((uint16_t *) send_icmp4, TT.msg_len);
    128     if (send_icmp4->icmp_cksum == 0) send_icmp4->icmp_cksum = 0xffff;
    129     out = send_icmp4;
    130   }
    131 
    132   res = setsockopt(TT.snd_sock, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
    133   if (res < 0) perror_exit("setsockopt ttl %d", ttl);
    134 
    135   len = TT.msg_len;
    136   res = sendto(TT.snd_sock, out, len, 0, (struct sockaddr *) &dest,
    137       sizeof(struct sockaddr_in));
    138   if (res != len) perror_exit(" sendto");
    139 }
    140 
    141 //sends a single probe packet with sequence(SEQ) and time-to-live(TTL)
    142 static void send_probe6(int seq, int ttl)
    143 {
    144   void *out;
    145   struct payload_s *send_data6 = (struct payload_s *) (TT.packet);
    146 
    147   send_data6->seq = seq;
    148   send_data6->ident = TT.ident;
    149   ((struct sockaddr_in6 *)&dest)->sin6_port = TT.port;
    150 
    151   if (setsockopt(TT.snd_sock, SOL_IPV6, IPV6_UNICAST_HOPS, &ttl,
    152         sizeof(ttl)) < 0) error_exit("setsockopt ttl %d", ttl);
    153 
    154   out = send_data6;
    155 
    156   if (sendto(TT.snd_sock, out, TT.msg_len, 0,
    157         (struct sockaddr *) &dest, sizeof(struct sockaddr_in6)) < 0)
    158     perror_exit("sendto");
    159 }
    160 
    161 static void set_flag_dr(int sock)
    162 {
    163   int set = 1;
    164   if ((toys.optflags & FLAG_d) && (setsockopt(sock,SOL_SOCKET, SO_DEBUG,
    165           &set, sizeof(set)) < 0)) perror_exit("SO_DEBUG failed ");
    166 
    167   if ((toys.optflags & FLAG_r) && (setsockopt(sock, SOL_SOCKET, SO_DONTROUTE,
    168           &set, sizeof(set)) < 0)) perror_exit("SO_DONTROUTE failed ");
    169 }
    170 
    171 static void bind_to_interface(int sock)
    172 {
    173   struct ifreq ifr;
    174 
    175   snprintf(ifr.ifr_name, IFNAMSIZ, "%s", TT.iface);
    176   if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)))
    177       perror_msg("can't bind to interface %s", TT.iface);
    178 }
    179 
    180 static void resolve_addr(char *host, int family, int type, int proto, void *sock)
    181 {
    182   struct addrinfo *info, hint;
    183   int ret;
    184 
    185   memset(&hint, 0, sizeof(hint));
    186   hint.ai_family = family;
    187   hint.ai_socktype = type;
    188   hint.ai_protocol = proto;
    189 
    190   ret = getaddrinfo(host, NULL, &hint, &info);
    191   if (ret || !info) error_exit("bad address:  %s ", host);
    192 
    193   memcpy(sock, info->ai_addr, info->ai_addrlen);
    194   freeaddrinfo(info);
    195 }
    196 
    197 static void do_trace()
    198 {
    199   int seq, fexit, ttl, tv = TT.wait_time * 1000;
    200   struct pollfd pfd[1];
    201   struct sockaddr_storage from;
    202 
    203   memset(&from, 0, sizeof(from));
    204   pfd[0].fd = TT.recv_sock;
    205   pfd[0].events = POLLIN;
    206 
    207   for (ttl = TT.first_ttl; ttl <= TT.max_ttl; ++ttl) {
    208     int probe, dest_reach = 0, print_verbose = 1;
    209     struct timeval t1, t2;
    210     struct sockaddr_storage last_addr;
    211 
    212     memset(&last_addr, 0, sizeof(last_addr));
    213     fexit = 0;
    214     xprintf("%2d", ttl);
    215 
    216     for (probe = 0, seq = 0; probe < TT.ttl_probes; ++probe) {
    217       int res = 0, tleft;
    218 
    219       fflush(NULL);
    220       if (!TT.istraceroute6)
    221         if (probe && (toys.optflags & FLAG_z)) usleep(TT.pause_time * 1000);
    222 
    223       if (!TT.istraceroute6) send_probe4(++seq, ttl);
    224       else send_probe6(++seq, ttl);
    225       gettimeofday(&t1, NULL);
    226       t2 = t1;
    227 
    228       while ((tleft = (int)(tv - ((unsigned long long)(t2.tv_sec * 1000ULL
    229                   + t2.tv_usec/1000) - (unsigned long long)(t1.tv_sec * 1000ULL
    230                     + t1.tv_usec/1000)))) >= 0) {
    231         unsigned delta = 0;
    232         if (!(res = poll(pfd, 1, tleft))) {
    233           xprintf("  *");
    234           break;
    235         }
    236         gettimeofday(&t2, NULL);
    237         if (res < 0) {
    238           if (errno != EINTR) perror_exit("poll");
    239           continue;
    240         }
    241         delta = (t2.tv_sec * USEC + t2.tv_usec)
    242           - (t1.tv_sec * USEC + t1.tv_usec);
    243 
    244         if (pfd[0].revents) {
    245           socklen_t addrlen = sizeof(struct sockaddr_storage);
    246           int rcv_len, icmp_res = 0;
    247 
    248           rcv_len = recvfrom(TT.recv_sock, toybuf, sizeof(toybuf),
    249               MSG_DONTWAIT, (struct sockaddr *) &from, &addrlen);
    250           if (rcv_len <= 0) continue;
    251 
    252           if (!TT.istraceroute6) {
    253             int pmtu = 0;
    254             struct ip *rcv_pkt = (struct ip*) toybuf;
    255             struct icmp *ricmp;
    256 
    257             ricmp = (struct icmp *) ((char*)rcv_pkt + (rcv_pkt->ip_hl << 2));
    258             if (ricmp->icmp_code == ICMP_UNREACH_NEEDFRAG)
    259               pmtu = ntohs(ricmp->icmp_nextmtu);
    260 
    261             if ((ricmp->icmp_type == ICMP_TIMXCEED
    262                   && ricmp->icmp_code == ICMP_TIMXCEED_INTRANS)
    263                 || ricmp->icmp_type == ICMP_UNREACH
    264                 || ricmp->icmp_type == ICMP_ECHOREPLY) {
    265 
    266               struct udphdr *hudp;
    267               struct icmp *hicmp;
    268               struct ip *hip = &ricmp->icmp_ip;
    269 
    270               if (toys.optflags & FLAG_U) {
    271                 hudp = (struct udphdr*) ((char*)hip + (hip->ip_hl << 2));
    272                 if ((hip->ip_hl << 2) + 12 <=(rcv_len - (rcv_pkt->ip_hl << 2))
    273                     && hip->ip_p == IPPROTO_UDP
    274                     && hudp->dest == (TT.port + seq))
    275                   icmp_res = (ricmp->icmp_type == ICMP_TIMXCEED ? -1 :
    276                       ricmp->icmp_code);
    277               } else {
    278                 hicmp = (struct icmp *) ((char*)hip + (hip->ip_hl << 2));
    279                 if (ricmp->icmp_type == ICMP_ECHOREPLY
    280                     && ricmp->icmp_id == ntohs(TT.ident)
    281                     && ricmp->icmp_seq == ntohs(seq))
    282                   icmp_res = ICMP_UNREACH_PORT;
    283                 else if ((hip->ip_hl << 2) + ICMP_HD_SIZE4
    284                     <= (rcv_len - (rcv_pkt->ip_hl << 2))
    285                     && hip->ip_p == IPPROTO_ICMP
    286                     && hicmp->icmp_id == htons(TT.ident)
    287                     && hicmp->icmp_seq == htons(seq))
    288                   icmp_res = (ricmp->icmp_type == ICMP_TIMXCEED ? -1 :
    289                       ricmp->icmp_code);
    290               }
    291             }
    292             if (!icmp_res) continue;
    293 
    294             if (addrlen > 0) {
    295               if (memcmp(&((struct sockaddr_in *)&last_addr)->sin_addr,
    296                     &((struct sockaddr_in *)&from)->sin_addr,
    297                     sizeof(struct in_addr))) {
    298                 if (!(toys.optflags & FLAG_n)) {
    299                   char host[NI_MAXHOST];
    300                   if (!getnameinfo((struct sockaddr *) &from,
    301                         sizeof(struct sockaddr_in), host, NI_MAXHOST, NULL, 0, 0))
    302                     xprintf("  %s (", host);
    303                   else xprintf(" %s (", inet_ntoa(
    304                           ((struct sockaddr_in *)&from)->sin_addr));
    305                 }
    306                 xprintf(" %s", inet_ntoa(
    307                       ((struct sockaddr_in *)&from)->sin_addr));
    308                 if (!(toys.optflags & FLAG_n)) xprintf(")");
    309                 memcpy(&last_addr, &from, sizeof(from));
    310               }
    311               xprintf("  %u.%03u ms", delta / 1000, delta % 1000);
    312               if (toys.optflags & FLAG_l) xprintf(" (%d)", rcv_pkt->ip_ttl);
    313               if (toys.optflags & FLAG_v) {
    314                 xprintf(" %d bytes from %s : icmp type %d code %d\t",
    315                     rcv_len, inet_ntoa(((struct sockaddr_in *)&from)->sin_addr),
    316                     ricmp->icmp_type, ricmp->icmp_code);
    317               }
    318             } else xprintf("\t!H");
    319 
    320             switch (icmp_res) {
    321               case ICMP_UNREACH_PORT:
    322                 if (rcv_pkt->ip_ttl <= 1) xprintf(" !");
    323                 dest_reach = 1;
    324                 break;
    325               case ICMP_UNREACH_NET:
    326                 xprintf(" !N");
    327                 ++fexit;
    328                 break;
    329               case ICMP_UNREACH_HOST:
    330                 xprintf(" !H");
    331                 ++fexit;
    332                 break;
    333               case ICMP_UNREACH_PROTOCOL:
    334                 xprintf(" !P");
    335                 dest_reach = 1;
    336                 break;
    337               case ICMP_UNREACH_NEEDFRAG:
    338                 xprintf(" !F-%d", pmtu);
    339                 ++fexit;
    340                 break;
    341               case ICMP_UNREACH_SRCFAIL:
    342                 xprintf(" !S");
    343                 ++fexit;
    344                 break;
    345               case ICMP_UNREACH_FILTER_PROHIB:
    346               case ICMP_UNREACH_NET_PROHIB:
    347                 xprintf(" !A");
    348                 ++fexit;
    349                 break;
    350               case ICMP_UNREACH_HOST_PROHIB:
    351                 xprintf(" !C");
    352                 ++fexit;
    353                 break;
    354               case ICMP_UNREACH_HOST_PRECEDENCE:
    355                 xprintf(" !V");
    356                 ++fexit;
    357                 break;
    358               case ICMP_UNREACH_PRECEDENCE_CUTOFF:
    359                 xprintf(" !C");
    360                 ++fexit;
    361                 break;
    362               case ICMP_UNREACH_NET_UNKNOWN:
    363               case ICMP_UNREACH_HOST_UNKNOWN:
    364                 xprintf(" !U");
    365                 ++fexit;
    366                 break;
    367               case ICMP_UNREACH_ISOLATED:
    368                 xprintf(" !I");
    369                 ++fexit;
    370                 break;
    371               case ICMP_UNREACH_TOSNET:
    372               case ICMP_UNREACH_TOSHOST:
    373                 xprintf(" !T");
    374                 ++fexit;
    375                 break;
    376               default:
    377                 break;
    378             }
    379             break;
    380           } else {
    381             struct icmp6_hdr *ricmp  = (struct icmp6_hdr *) toybuf;
    382 
    383             if ((ricmp->icmp6_type == ICMP6_TIME_EXCEEDED
    384                   && ricmp->icmp6_code == ICMP6_TIME_EXCEED_TRANSIT)
    385                 || ricmp->icmp6_type == ICMP6_DST_UNREACH
    386                 || ricmp->icmp6_type == ICMP6_ECHO_REPLY) {
    387 
    388               struct ip6_hdr *hip;
    389               struct udphdr *hudp;
    390               int hdr_next;
    391 
    392               hip = (struct ip6_hdr *)(ricmp + 1);
    393               hudp = (struct udphdr*) (hip + 1);
    394               hdr_next = hip->ip6_nxt;
    395               if (hdr_next == IPPROTO_FRAGMENT) {
    396                 hdr_next = *(unsigned char*)hudp;
    397                 hudp++;
    398               }
    399 
    400               if (hdr_next == IPPROTO_UDP) {
    401                 struct payload_s *pkt = (struct payload_s*)(hudp + 1);
    402                 if ((pkt->ident == TT.ident) && (pkt->seq == seq))
    403                   icmp_res = (ricmp->icmp6_type == ICMP6_TIME_EXCEEDED) ? -1 :
    404                     ricmp->icmp6_code;
    405               }
    406             }
    407 
    408             if (!icmp_res) continue;
    409             if (addrlen > 0) {
    410               if (memcmp(&((struct sockaddr_in6 *)&last_addr)->sin6_addr,
    411                     &((struct sockaddr_in6 *)&from)->sin6_addr,
    412                     sizeof(struct in6_addr))) {
    413                 if (!(toys.optflags & FLAG_n)) {
    414                   char host[NI_MAXHOST];
    415                   if (!getnameinfo((struct sockaddr *) &from,
    416                         sizeof(from), host, sizeof(host), NULL, 0, 0))
    417                     xprintf("  %s (", host);
    418                 }
    419                 memset(addr_str, '\0', INET6_ADDRSTRLEN);
    420                 inet_ntop(AF_INET6, &((struct sockaddr_in6 *)&from)->sin6_addr,
    421                     addr_str, INET6_ADDRSTRLEN);
    422                 xprintf(" %s", addr_str);
    423 
    424                 if (!(toys.optflags & FLAG_n)) xprintf(")");
    425                 memcpy(&last_addr,&from,sizeof(from));
    426               }
    427 
    428               if (toys.optflags & FLAG_v) {
    429                 if(print_verbose){
    430                   memset(addr_str, '\0', INET6_ADDRSTRLEN);
    431                   inet_ntop(AF_INET6, &((struct sockaddr_in6 *)
    432                         &from)->sin6_addr, addr_str, INET6_ADDRSTRLEN);
    433                   rcv_len -= sizeof(struct ip6_hdr);
    434                   xprintf(" %d bytes to %s ", rcv_len, addr_str);
    435                 }
    436               }
    437               xprintf("  %u.%03u ms", delta / 1000, delta % 1000);
    438               delta = 0;
    439 
    440             } else xprintf("\t!H");
    441 
    442             switch (icmp_res) {
    443               case ICMP6_DST_UNREACH_NOPORT:
    444                 ++fexit;
    445                 dest_reach = 1;
    446                 break;
    447               case ICMP6_DST_UNREACH_NOROUTE:
    448                 xprintf(" !N");
    449                 ++fexit;
    450                 break;
    451               case ICMP6_DST_UNREACH_ADDR:
    452                 xprintf(" !H");
    453                 ++fexit;
    454                 break;
    455               case ICMP6_DST_UNREACH_ADMIN:
    456                 xprintf(" !S");
    457                 ++fexit;
    458                 break;
    459               default:
    460                 break;
    461             }
    462             break;
    463           }
    464         } //revents
    465       }
    466       print_verbose = 0;
    467     }
    468     xputc('\n');
    469     if(!TT.istraceroute6) {
    470       if (!memcmp(&((struct sockaddr_in *)&from)->sin_addr,
    471             &((struct sockaddr_in *)&dest)->sin_addr, sizeof(struct in_addr))
    472           || dest_reach || (fexit && fexit >= TT.ttl_probes -1))
    473         break;
    474     } else if (dest_reach || (fexit > 0 && fexit >= TT.ttl_probes -1)) break;
    475   }
    476 }
    477 
    478 void traceroute_main(void)
    479 {
    480   unsigned opt_len = 0, pack_size = 0, tyser = 0;
    481   int lsrr = 0, set = 1;
    482 
    483   if(!(toys.optflags & FLAG_4) &&
    484       (inet_pton(AF_INET6, toys.optargs[0], &dest)))
    485     toys.optflags |= FLAG_6;
    486 
    487   memset(&dest, 0, sizeof(dest));
    488   if (toys.optflags & FLAG_6) TT.istraceroute6 = 1;
    489   else TT.istraceroute6 = toys.which->name[10] == '6';
    490 
    491   if(!TT.istraceroute6 && (toys.optflags & FLAG_g)) {
    492       struct arg_list *node;
    493 
    494       for (node = TT.loose_source; node; node = node->next, lsrr++) {
    495         struct sockaddr_in sin;
    496 
    497         memset( &sin, 0, sizeof(sin));
    498         if (lsrr >= 8) error_exit("no more than 8 gateways"); // NGATEWAYS
    499         resolve_addr(node->arg, AF_INET, SOCK_STREAM, 0, &sin);
    500         TT.gw_list[lsrr] = sin.sin_addr.s_addr;
    501       }
    502       opt_len = (lsrr + 1) * sizeof(TT.gw_list[0]);
    503   } else TT.first_ttl = 1;
    504 
    505   TT.msg_len = pack_size = ICMP_HD_SIZE4; //udp payload is also 8bytes
    506   if (toys.optargs[1])
    507     TT.msg_len = atolx_range(toys.optargs[1], pack_size, 32768);//max packet size
    508 
    509   TT.recv_sock = xsocket((TT.istraceroute6 ? AF_INET6 : AF_INET), SOCK_RAW,
    510       (TT.istraceroute6 ? IPPROTO_ICMPV6 : IPPROTO_ICMP));
    511 
    512   if (TT.istraceroute6) {
    513     int two = 2;
    514 #ifdef IPV6_RECVPKTINFO
    515     setsockopt(TT.recv_sock, SOL_IPV6, IPV6_RECVPKTINFO, &set,
    516         sizeof(set));
    517     setsockopt(TT.recv_sock, SOL_IPV6, IPV6_2292PKTINFO, &set,
    518         sizeof(set));
    519 #else
    520     setsockopt(TT.recv_sock, SOL_IPV6, IPV6_PKTINFO, &set, sizeof(set));
    521 #endif
    522 
    523     if (setsockopt(TT.recv_sock, SOL_RAW, IPV6_CHECKSUM, &two,
    524           sizeof(two)) < 0)  perror_exit("setsockopt RAW_CHECKSUM");
    525   }
    526 
    527   set_flag_dr(TT.recv_sock);
    528 
    529   if (!TT.istraceroute6) {
    530     if (toys.optflags & FLAG_U)
    531       TT.snd_sock = xsocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    532     else TT.snd_sock = xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
    533 
    534     if (toys.optflags & FLAG_i) bind_to_interface(TT.snd_sock);
    535 
    536     resolve_addr(toys.optargs[0], AF_INET, ((toys.optflags & FLAG_U) ?
    537           SOCK_DGRAM : SOCK_RAW), ((toys.optflags & FLAG_U) ? IPPROTO_UDP :
    538             IPPROTO_ICMP), &dest);
    539     if (lsrr > 0) {
    540       unsigned char optlist[MAX_IPOPTLEN];
    541       unsigned size;
    542 
    543       TT.gw_list[lsrr] = ((struct sockaddr_in *)&dest)->sin_addr.s_addr;
    544       ++lsrr;
    545 
    546       optlist[0] = IPOPT_NOP;
    547       optlist[1] = IPOPT_LSRR;// loose source route option
    548       size = lsrr * sizeof(TT.gw_list[0]);
    549       optlist[2] = size + 3;
    550       optlist[3] = IPOPT_MINOFF;
    551       memcpy(optlist + 4, TT.gw_list, size);
    552 
    553       if (setsockopt(TT.snd_sock, IPPROTO_IP, IP_OPTIONS,
    554             (char *)optlist, size + sizeof(TT.gw_list[0])) < 0)
    555         perror_exit("LSRR IP_OPTIONS");
    556     }
    557   } else TT.snd_sock = xsocket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
    558 
    559   if (setsockopt(TT.snd_sock, SOL_SOCKET, SO_SNDBUF, &TT.msg_len,
    560         sizeof(TT.msg_len)) < 0) perror_exit("SO_SNDBUF failed ");
    561 
    562   if (!TT.istraceroute6) {
    563     if ((toys.optflags & FLAG_t) &&
    564         setsockopt(TT.snd_sock, IPPROTO_IP, IP_TOS, &tyser, sizeof(tyser)) < 0)
    565       perror_exit("IP_TOS %ld failed ", TT.tos);
    566 
    567 #ifdef IP_DONTFRAG
    568     if ((toys.optflags & FLAG_F) &&
    569         (setsockopt(TT.snd_sock, IPPROTO_IP, IP_DONTFRAG, &set,
    570                     sizeof(set)) < 0)) perror_exit("IP_DONTFRAG failed ");
    571 #endif
    572   } else if (setsockopt(TT.snd_sock, IPPROTO_IPV6, IPV6_TCLASS, &TT.tos,
    573         sizeof(TT.tos)) < 0) perror_exit("IPV6_TCLASS %ld failed ", TT.tos);
    574 
    575   set_flag_dr(TT.snd_sock);
    576   TT.packet = xzalloc(TT.msg_len);
    577   TT.ident = getpid();
    578 
    579   if (!TT.istraceroute6) {
    580     if (!(toys.optflags & FLAG_U)) TT.ident |= 0x8000;
    581     if (toys.optflags & FLAG_s) {
    582       struct sockaddr_in source;
    583 
    584       memset(&source, 0, sizeof(source));
    585       if (!inet_aton(TT.src_ip, &(source.sin_addr)))
    586         error_exit("bad address: %s", TT.src_ip);
    587       if (setsockopt(TT.snd_sock, IPPROTO_IP, IP_MULTICAST_IF,
    588             (struct sockaddr*)&source, sizeof(struct sockaddr_in)))
    589         perror_exit("can't set multicast source interface");
    590       if (bind(TT.snd_sock,(struct sockaddr*)&source,
    591             sizeof(struct sockaddr_in)) < 0) perror_exit("bind");
    592     }
    593 
    594     if(TT.first_ttl > TT.max_ttl)
    595       error_exit("ERROR :Range for -f is 1 to %ld (max ttl)", TT.max_ttl);
    596 
    597     xprintf("traceroute to %s(%s)", toys.optargs[0],
    598            inet_ntoa(((struct sockaddr_in *)&dest)->sin_addr));
    599   } else {
    600     if (toys.optflags & FLAG_i) bind_to_interface(TT.snd_sock);
    601 
    602     resolve_addr(toys.optargs[0], AF_INET6, SOCK_DGRAM, IPPROTO_UDP, &dest);
    603     if (toys.optflags & FLAG_s) {
    604       struct sockaddr_in6 source;
    605 
    606       memset(&source, 0, sizeof(source));
    607       if(inet_pton(AF_INET6, TT.src_ip, &(source.sin6_addr)) <= 0)
    608         error_exit("bad address: %s", TT.src_ip);
    609 
    610       if (bind(TT.snd_sock,(struct sockaddr*)&source,
    611             sizeof(struct sockaddr_in6)) < 0)
    612         error_exit("bind: Cannot assign requested address");
    613     } else {
    614       struct sockaddr_in6 prb;
    615       socklen_t len = sizeof(prb);
    616       int p_fd = xsocket(AF_INET6, SOCK_DGRAM, 0);
    617       if (toys.optflags & FLAG_i) bind_to_interface(p_fd);
    618 
    619       ((struct sockaddr_in6 *)&dest)->sin6_port = htons(1025);
    620       if (connect(p_fd, (struct sockaddr *)&dest, sizeof(struct sockaddr_in6)) < 0)
    621         perror_exit("can't connect to remote host");
    622       if(getsockname(p_fd, (struct sockaddr *)&prb, &len))
    623         error_exit("probe addr failed");
    624       close(p_fd);
    625       prb.sin6_port = 0;
    626       if (bind(TT.snd_sock, (struct sockaddr*)&prb,
    627             sizeof(struct sockaddr_in6))) perror_exit("bind");
    628       if (bind(TT.recv_sock, (struct sockaddr*)&prb,
    629             sizeof(struct sockaddr_in6))) perror_exit("bind");
    630     }
    631 
    632     inet_ntop(AF_INET6, &((struct sockaddr_in6 *)&dest)->sin6_addr,
    633               addr_str, INET6_ADDRSTRLEN);
    634     xprintf("traceroute6 to %s(%s)", toys.optargs[0], addr_str);
    635   }
    636 
    637   if (toys.optflags & FLAG_s) xprintf(" from %s",TT.src_ip);
    638   xprintf(", %ld hops max, %u byte packets\n", TT.max_ttl, TT.msg_len);
    639 
    640   do_trace();
    641 }
    642