toybox/toys/pending/traceroute.c
<<
>>
Prefs
   1/* traceroute - trace the route to "host".
   2 *
   3 * Copyright 2012 Madhur Verma <mad.flexi@gmail.com>
   4 * Copyright 2013 Kyungwan Han <asura321@gmail.com>
   5 * Copyright 2013 Bilal Qureshi <bilal.jmi@gmail.com>
   6 * Copyright 2013 Ashwini Kumar <ak.ashwini1981@gmail.com>
   7 *
   8 * No Standard
   9
  10USE_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))
  11USE_TRACEROUTE(OLDTOY(traceroute6,traceroute, TOYFLAG_STAYROOT|TOYFLAG_USR|TOYFLAG_BIN))
  12config 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
  51GLOBALS(
  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
  79struct payload_s {
  80  uint32_t seq;
  81  uint32_t ident;
  82};
  83
  84char addr_str[INET6_ADDRSTRLEN];
  85struct sockaddr_storage dest;
  86
  87//Compute checksum SUM of buffer P of length LEN
  88static 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)
 110static 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)
 142static 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
 161static 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
 171static 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
 180static 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
 197static 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
 478void 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      xbind(TT.snd_sock,(struct sockaddr*)&source, sizeof(struct sockaddr_in));
 591    }
 592
 593    if(TT.first_ttl > TT.max_ttl) 
 594      error_exit("ERROR :Range for -f is 1 to %ld (max ttl)", TT.max_ttl);
 595
 596    xprintf("traceroute to %s(%s)", toys.optargs[0], 
 597           inet_ntoa(((struct sockaddr_in *)&dest)->sin_addr));
 598  } else {
 599    if (toys.optflags & FLAG_i) bind_to_interface(TT.snd_sock);
 600
 601    resolve_addr(toys.optargs[0], AF_INET6, SOCK_DGRAM, IPPROTO_UDP, &dest);
 602    if (toys.optflags & FLAG_s) {
 603      struct sockaddr_in6 source;
 604
 605      memset(&source, 0, sizeof(source));
 606      if(inet_pton(AF_INET6, TT.src_ip, &(source.sin6_addr)) <= 0)
 607        error_exit("bad address: %s", TT.src_ip);
 608
 609      xbind(TT.snd_sock,(struct sockaddr*)&source, sizeof(struct sockaddr_in6));
 610    } else {
 611      struct sockaddr_in6 prb;
 612      socklen_t len = sizeof(prb);
 613      int p_fd = xsocket(AF_INET6, SOCK_DGRAM, 0);
 614      if (toys.optflags & FLAG_i) bind_to_interface(p_fd);
 615
 616      ((struct sockaddr_in6 *)&dest)->sin6_port = htons(1025);
 617      xconnect(p_fd, (struct sockaddr *)&dest, sizeof(struct sockaddr_in6));
 618      if(getsockname(p_fd, (struct sockaddr *)&prb, &len)) 
 619        error_exit("probe addr failed");
 620      close(p_fd);
 621      prb.sin6_port = 0;
 622      xbind(TT.snd_sock, (struct sockaddr*)&prb, sizeof(struct sockaddr_in6));
 623      xbind(TT.recv_sock, (struct sockaddr*)&prb, sizeof(struct sockaddr_in6));
 624    }
 625
 626    inet_ntop(AF_INET6, &((struct sockaddr_in6 *)&dest)->sin6_addr, 
 627              addr_str, INET6_ADDRSTRLEN);
 628    xprintf("traceroute6 to %s(%s)", toys.optargs[0], addr_str);
 629  }
 630
 631  if (toys.optflags & FLAG_s) xprintf(" from %s",TT.src_ip);
 632  xprintf(", %ld hops max, %u byte packets\n", TT.max_ttl, TT.msg_len);
 633
 634  do_trace();
 635}
 636