Справочник по консольным командам Toybox для Android 12


  Ver.0.8.4     Ver.0.8.9     Pending  

Путь: Toys/Pending, команды версии: Ver.4     Ver.9


traceroute

Комментарии в файле traceroute.c :

usage: traceroute [-46FUIldnvr] [-f 1ST_TTL] [-m MAXTTL] [-p PORT] [-q PROBES]

[-s SRC_IP] [-t TOS] [-w WAIT_SEC] [-g GATEWAY] [-i IFACE] [-z PAUSE_MSEC] HOST [BYTES] traceroute6 [-dnrv] [-m MAXTTL] [-p ПОРТ] [-q PROBES][-s SRC_IP] [-t TOS] [-w WAIT_SEC] [-i IFACE] ХОСТ [БАЙТ] Отследить маршрут до HOST
  • -4,-6 Принудительное разрешение имен IP или IPv6
  • -F Установите бит «Не фрагментировать» (поддерживает только IPV4)
  • -U Используйте дейтаграммы UDP вместо ICMP ECHO (поддерживает только IPV4)
  • -I Используйте ICMP ECHO вместо дейтаграмм UDP (поддерживает только IPV4)
  • -l Отображение значения TTL возвращенного пакета (поддерживает только IPV4)
  • -d Установите параметры SO_DEBUG для сокета Печатать
  • -n числовые адреса
  • -v подробно Обходить -r таблицы маршрутизации, отправлять напрямую на HOST
  • -m Максимальное время жизни (максимальное количество переходов) (ДИАПАЗОН от 1 до 255)
  • -p Базовый номер порта UDP, используемый в зондах (по умолчанию 33434 )(ДИАПАЗОН от 1 до 65535)
  • -q Количество тестов на TTL (по умолчанию 3)(ДИАПАЗОН 1 до 255)
  • -s IP-адрес для использования в качестве адреса источника
  • -t Тип обслуживания в тестовых пакетах (по умолчанию 0)(ДИАПАЗОН 0 до 255)
  • -w Время в секунд для ожидания ответа (по умолчанию 3)(ДИАПАЗОН от 0 до 86400)
  • -g Свободный шлюз исходного маршрута (максимум 8) (поддерживает только IPV4)
  • -z Время паузы в мс (по умолчанию 0)(ДИАПАЗОН от 0 до 86400) (поддерживает только IPV4)
  • -f Начать с прыжок 1ST_TTL (вместо 1)(ДИАПАЗОН от 1 до 255) (поддерживает только IPV4)
  • -i Укажите сетевой интерфейс для работы с

  • usage: traceroute [-46FUIldnvr] [-f 1ST_TTL] [-m MAXTTL] [-p PORT] [-q PROBES]

    [-s SRC_IP] [-t TOS] [-w WAIT_SEC] [-g GATEWAY] [-i IFACE] [-z PAUSE_MSEC] HOST [BYTES] traceroute6 [-dnrv] [-m MAXTTL] [-p PORT] [-q PROBES][-s SRC_IP] [-t TOS] [-w WAIT_SEC] [-i IFACE] HOST [BYTES] Trace the route to HOST
  • -4,-6 Force IP or IPv6 name resolution
  • -F Set the don't fragment bit (supports IPV4 only)
  • -U Use UDP datagrams instead of ICMP ECHO (supports IPV4 only)
  • -I Use ICMP ECHO instead of UDP datagrams (supports IPV4 only)
  • -l Display the TTL value of the returned packet (supports IPV4 only)
  • -d Set SO_DEBUG options to socket
  • -n Print numeric addresses
  • -v verbose
  • -r Bypass routing tables, send directly to HOST
  • -m Max time-to-live (max number of hops)(RANGE 1 to 255)
  • -p Base UDP port number used in probes(default 33434)(RANGE 1 to 65535)
  • -q Number of probes per TTL (default 3)(RANGE 1 to 255)
  • -s IP address to use as the source address
  • -t Type-of-service in probe packets (default 0)(RANGE 0 to 255)
  • -w Time in seconds to wait for a response (default 3)(RANGE 0 to 86400)
  • -g Loose source route gateway (8 max) (supports IPV4 only)
  • -z Pause Time in ms (default 0)(RANGE 0 to 86400) (supports IPV4 only)
  • -f Start from the 1ST_TTL hop (instead from 1)(RANGE 1 to 255) (supports IPV4 only)
  • -i Specify a network interface to operate with

  • Исходный текст в файле traceroute.c

    #define FOR_traceroute
    #include "toys.h"
    #include <netinet/udp.h>
    #include <netinet/ip_icmp.h>
    #include <netinet/ip6.h>
    #include <netinet/icmp6.h>
    
    GLOBALS(
      long max_ttl;
      long port;
      long ttl_probes;
      char *src_ip;
      long tos;
      long wait_time;
      struct arg_list *loose_source;
      long pause_time;
      long first_ttl;
      char *iface;
    
      uint32_t gw_list[9];
      int recv_sock;
      int snd_sock;
      unsigned msg_len;
      char *packet;
      uint32_t ident;
      int istraceroute6;
    )
    
    #ifndef SOL_IPV6
    # define SOL_IPV6 IPPROTO_IPV6
    #endif
    
    #define ICMP_HD_SIZE4  8
    #define USEC           1000000ULL
    
    struct payload_s {
      uint32_t seq;
      uint32_t ident;
    };
    
    char addr_str[INET6_ADDRSTRLEN];
    struct sockaddr_storage dest;
    
    //Compute checksum SUM of buffer P of length LEN
    static u_int16_t in_cksum(u_int16_t *p, u_int len)
    {
      u_int32_t sum = 0;
      int nwords = len >> 1;
    
      while (nwords-- != 0) sum += *p++;
      if (len & 1) {
        union {
          u_int16_t w;
          u_int8_t c[2];
        } u;
        u.c[0] = *(u_char *) p;
        u.c[1] = 0;
        sum += u.w;
      }
      // end-around-carry 
      sum = (sum >> 16) + (sum & 0xffff);
      sum += (sum >> 16);
      return (~sum);
    }
    
    //sends a single probe packet with sequence(SEQ) and time-to-live(TTL)
    static void send_probe4(int seq, int ttl)
    {
      int res, len;
      void *out;
      struct payload_s *send_data4 = (struct payload_s *)(TT.packet);
      struct icmp *send_icmp4 = (struct icmp *)(TT.packet);
    
      if (toys.optflags & FLAG_U) {
        send_data4->seq = seq;
        send_data4->ident = TT.ident;
        ((struct sockaddr_in *)&dest)->sin_port = TT.port + seq;
        out = send_data4;
      } else {
        send_icmp4->icmp_type = ICMP_ECHO;
        send_icmp4->icmp_id = htons(TT.ident);
        send_icmp4->icmp_seq = htons(seq);
        send_icmp4->icmp_cksum = 0;
        send_icmp4->icmp_cksum = in_cksum((uint16_t *) send_icmp4, TT.msg_len);
        if (send_icmp4->icmp_cksum == 0) send_icmp4->icmp_cksum = 0xffff;
        out = send_icmp4;
      }
    
      res = setsockopt(TT.snd_sock, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
      if (res < 0) perror_exit("setsockopt ttl %d", ttl);
    
      len = TT.msg_len;
      res = sendto(TT.snd_sock, out, len, 0, (struct sockaddr *) &dest, 
          sizeof(struct sockaddr_in));
      if (res != len) perror_exit(" sendto");
    }
    
    //sends a single probe packet with sequence(SEQ) and time-to-live(TTL)
    static void send_probe6(int seq, int ttl)
    {
      void *out;
      struct payload_s *send_data6 = (struct payload_s *) (TT.packet);
    
      send_data6->seq = seq;
      send_data6->ident = TT.ident;
      ((struct sockaddr_in6 *)&dest)->sin6_port = TT.port;
    
      if (setsockopt(TT.snd_sock, SOL_IPV6, IPV6_UNICAST_HOPS, &ttl, 
            sizeof(ttl)) < 0) error_exit("setsockopt ttl %d", ttl);
    
      out = send_data6;
    
      if (sendto(TT.snd_sock, out, TT.msg_len, 0,
            (struct sockaddr *) &dest, sizeof(struct sockaddr_in6)) < 0)
        perror_exit("sendto");
    }
    
    static void set_flag_dr(int sock)
    {
      int set = 1;
      if ((toys.optflags & FLAG_d) && (setsockopt(sock,SOL_SOCKET, SO_DEBUG,
              &set, sizeof(set)) < 0)) perror_exit("SO_DEBUG failed ");
    
      if ((toys.optflags & FLAG_r) && (setsockopt(sock, SOL_SOCKET, SO_DONTROUTE,
              &set, sizeof(set)) < 0)) perror_exit("SO_DONTROUTE failed ");
    }
    
    static void bind_to_interface(int sock)
    {
      struct ifreq ifr;
    
      snprintf(ifr.ifr_name, IFNAMSIZ, "%s", TT.iface);
      if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)))
          perror_msg("can't bind to interface %s", TT.iface);
    }
    
    static void resolve_addr(char *host, int family, int type, int proto, void *sock)
    {
      struct addrinfo *info, hint;
      int ret;
    
      memset(&hint, 0, sizeof(hint));
      hint.ai_family = family;
      hint.ai_socktype = type;
      hint.ai_protocol = proto;
    
      ret = getaddrinfo(host, NULL, &hint, &info);
      if (ret || !info) error_exit("bad address:  %s ", host);
    
      memcpy(sock, info->ai_addr, info->ai_addrlen);
      freeaddrinfo(info);
    }
    
    static void do_trace()
    {
      int seq, fexit, ttl, tv = TT.wait_time * 1000;
      struct pollfd pfd[1];
      struct sockaddr_storage from;
    
      memset(&from, 0, sizeof(from));
      pfd[0].fd = TT.recv_sock;
      pfd[0].events = POLLIN;
    
      for (ttl = TT.first_ttl; ttl <= TT.max_ttl; ++ttl) {
        int probe, dest_reach = 0, print_verbose = 1;
        struct timeval t1, t2;
        struct sockaddr_storage last_addr;
    
        memset(&last_addr, 0, sizeof(last_addr));
        fexit = 0;
        xprintf("%2d", ttl);
    
        for (probe = 0, seq = 0; probe < TT.ttl_probes; ++probe) {
          int res = 0, tleft;
    
          fflush(NULL);
          if (!TT.istraceroute6)
            if (probe && (toys.optflags & FLAG_z)) msleep(TT.pause_time);
    
          if (!TT.istraceroute6) send_probe4(++seq, ttl);
          else send_probe6(++seq, ttl);
          gettimeofday(&t1, NULL);
          t2 = t1;
    
          while ((tleft = (int)(tv - ((unsigned long long)(t2.tv_sec * 1000ULL 
                      + t2.tv_usec/1000) - (unsigned long long)(t1.tv_sec * 1000ULL
                        + t1.tv_usec/1000)))) >= 0) {
            unsigned delta = 0;
            if (!(res = poll(pfd, 1, tleft))) { 
              xprintf("  *"); 
              break;
            }
            gettimeofday(&t2, NULL);
            if (res < 0) {
              if (errno != EINTR) perror_exit("poll");
              continue;
            }
            delta = (t2.tv_sec * USEC + t2.tv_usec)
              - (t1.tv_sec * USEC + t1.tv_usec);
    
            if (pfd[0].revents) {
              socklen_t addrlen = sizeof(struct sockaddr_storage);
              int rcv_len, icmp_res = 0;
    
              rcv_len = recvfrom(TT.recv_sock, toybuf, sizeof(toybuf),
                  MSG_DONTWAIT, (struct sockaddr *) &from, &addrlen);
              if (rcv_len <= 0) continue;
    
              if (!TT.istraceroute6) {
                int pmtu = 0;
                struct ip *rcv_pkt = (struct ip*) toybuf;
                struct icmp *ricmp;
    
                ricmp = (struct icmp *) ((char*)rcv_pkt + (rcv_pkt->ip_hl << 2));
                if (ricmp->icmp_code == ICMP_UNREACH_NEEDFRAG)
                  pmtu = ntohs(ricmp->icmp_nextmtu);
    
                if ((ricmp->icmp_type == ICMP_TIMXCEED
                      && ricmp->icmp_code == ICMP_TIMXCEED_INTRANS)
                    || ricmp->icmp_type == ICMP_UNREACH
                    || ricmp->icmp_type == ICMP_ECHOREPLY) {
    
                  struct udphdr *hudp;
                  struct icmp *hicmp;
                  struct ip *hip = &ricmp->icmp_ip;
    
                  if (toys.optflags & FLAG_U) {
                    hudp = (struct udphdr*) ((char*)hip + (hip->ip_hl << 2));
                    if ((hip->ip_hl << 2) + 12 <=(rcv_len - (rcv_pkt->ip_hl << 2))
                        && hip->ip_p == IPPROTO_UDP
                        && hudp->dest == (TT.port + seq))
                      icmp_res = (ricmp->icmp_type == ICMP_TIMXCEED ? -1 :
                          ricmp->icmp_code);
                  } else {
                    hicmp = (struct icmp *) ((char*)hip + (hip->ip_hl << 2));
                    if (ricmp->icmp_type == ICMP_ECHOREPLY 
                        && ricmp->icmp_id == ntohs(TT.ident)
                        && ricmp->icmp_seq == ntohs(seq))
                      icmp_res = ICMP_UNREACH_PORT;
                    else if ((hip->ip_hl << 2) + ICMP_HD_SIZE4 
                        <= (rcv_len - (rcv_pkt->ip_hl << 2))
                        && hip->ip_p == IPPROTO_ICMP
                        && hicmp->icmp_id == htons(TT.ident)
                        && hicmp->icmp_seq == htons(seq))
                      icmp_res = (ricmp->icmp_type == ICMP_TIMXCEED ? -1 : 
                          ricmp->icmp_code);
                  }
                }
                if (!icmp_res) continue;
    
                if (addrlen > 0) {
                  if (memcmp(&((struct sockaddr_in *)&last_addr)->sin_addr, 
                        &((struct sockaddr_in *)&from)->sin_addr, 
                        sizeof(struct in_addr))) {
                    if (!(toys.optflags & FLAG_n)) {
                      char host[NI_MAXHOST];
                      if (!getnameinfo((struct sockaddr *) &from, 
                            sizeof(struct sockaddr_in), host, NI_MAXHOST, NULL, 0, 0))
                        xprintf("  %s (", host);
                      else xprintf(" %s (", inet_ntoa(
                              ((struct sockaddr_in *)&from)->sin_addr));
                    }
                    xprintf(" %s", inet_ntoa(
                          ((struct sockaddr_in *)&from)->sin_addr));
                    if (!(toys.optflags & FLAG_n)) xprintf(")");
                    memcpy(&last_addr, &from, sizeof(from));
                  }
                  xprintf("  %u.%03u ms", delta / 1000, delta % 1000);
                  if (toys.optflags & FLAG_l) xprintf(" (%d)", rcv_pkt->ip_ttl);
                  if (toys.optflags & FLAG_v) {
                    xprintf(" %d bytes from %s : icmp type %d code %d\t",
                        rcv_len, inet_ntoa(((struct sockaddr_in *)&from)->sin_addr),
                        ricmp->icmp_type, ricmp->icmp_code);
                  }
                } else xprintf("\t!H");
    
                switch (icmp_res) {
                  case ICMP_UNREACH_PORT:
                    if (rcv_pkt->ip_ttl <= 1) xprintf(" !");
                    dest_reach = 1;
                    break;
                  case ICMP_UNREACH_NET:
                    xprintf(" !N");
                    ++fexit;
                    break;
                  case ICMP_UNREACH_HOST:
                    xprintf(" !H");
                    ++fexit;
                    break;
                  case ICMP_UNREACH_PROTOCOL:
                    xprintf(" !P");
                    dest_reach = 1;
                    break;
                  case ICMP_UNREACH_NEEDFRAG:
                    xprintf(" !F-%d", pmtu);
                    ++fexit;
                    break;
                  case ICMP_UNREACH_SRCFAIL:
                    xprintf(" !S");
                    ++fexit;
                    break;
                  case ICMP_UNREACH_FILTER_PROHIB:
                  case ICMP_UNREACH_NET_PROHIB:
                    xprintf(" !A");
                    ++fexit;
                    break;
                  case ICMP_UNREACH_HOST_PROHIB:
                    xprintf(" !C");
                    ++fexit;
                    break;
                  case ICMP_UNREACH_HOST_PRECEDENCE:
                    xprintf(" !V");
                    ++fexit;
                    break;
                  case ICMP_UNREACH_PRECEDENCE_CUTOFF:
                    xprintf(" !C");
                    ++fexit;
                    break;
                  case ICMP_UNREACH_NET_UNKNOWN:  
                  case ICMP_UNREACH_HOST_UNKNOWN:
                    xprintf(" !U");
                    ++fexit;
                    break;
                  case ICMP_UNREACH_ISOLATED:
                    xprintf(" !I");
                    ++fexit;
                    break;
                  case ICMP_UNREACH_TOSNET:
                  case ICMP_UNREACH_TOSHOST:
                    xprintf(" !T");
                    ++fexit;
                    break;
                  default:
                    break;
                }
                break;
              } else {
                struct icmp6_hdr *ricmp  = (struct icmp6_hdr *) toybuf;
    
                if ((ricmp->icmp6_type == ICMP6_TIME_EXCEEDED
                      && ricmp->icmp6_code == ICMP6_TIME_EXCEED_TRANSIT)
                    || ricmp->icmp6_type == ICMP6_DST_UNREACH
                    || ricmp->icmp6_type == ICMP6_ECHO_REPLY) {
    
                  struct ip6_hdr *hip;
                  struct udphdr *hudp;
                  int hdr_next;
    
                  hip = (struct ip6_hdr *)(ricmp + 1);
                  hudp = (struct udphdr*) (hip + 1);
                  hdr_next = hip->ip6_nxt;
                  if (hdr_next == IPPROTO_FRAGMENT) {
                    hdr_next = *(unsigned char*)hudp;
                    hudp++;
                  }
    
                  if (hdr_next == IPPROTO_UDP) {
                    struct payload_s *pkt = (struct payload_s*)(hudp + 1);
                    if ((pkt->ident == TT.ident) && (pkt->seq == seq))
                      icmp_res = (ricmp->icmp6_type == ICMP6_TIME_EXCEEDED) ? -1 :
                        ricmp->icmp6_code;
                  }
                }
    
                if (!icmp_res) continue;
                if (addrlen > 0) {
                  if (memcmp(&((struct sockaddr_in6 *)&last_addr)->sin6_addr, 
                        &((struct sockaddr_in6 *)&from)->sin6_addr, 
                        sizeof(struct in6_addr))) {
                    if (!(toys.optflags & FLAG_n)) {
                      char host[NI_MAXHOST];
                      if (!getnameinfo((struct sockaddr *) &from,
                            sizeof(from), host, sizeof(host), NULL, 0, 0))
                        xprintf("  %s (", host);
                    }
                    memset(addr_str, '\0', INET6_ADDRSTRLEN);
                    inet_ntop(AF_INET6, &((struct sockaddr_in6 *)&from)->sin6_addr,
                        addr_str, INET6_ADDRSTRLEN);
                    xprintf(" %s", addr_str);
    
                    if (!(toys.optflags & FLAG_n)) xprintf(")");
                    memcpy(&last_addr,&from,sizeof(from));
                  }
    
                  if (toys.optflags & FLAG_v) {
                    if(print_verbose){
                      memset(addr_str, '\0', INET6_ADDRSTRLEN);
                      inet_ntop(AF_INET6, &((struct sockaddr_in6 *)
                            &from)->sin6_addr, addr_str, INET6_ADDRSTRLEN);
                      rcv_len -= sizeof(struct ip6_hdr);
                      xprintf(" %d bytes to %s ", rcv_len, addr_str);
                    }
                  }
                  xprintf("  %u.%03u ms", delta / 1000, delta % 1000);
                  delta = 0;
    
                } else xprintf("\t!H");
    
                switch (icmp_res) {
                  case ICMP6_DST_UNREACH_NOPORT:
                    ++fexit;
                    dest_reach = 1;
                    break;
                  case ICMP6_DST_UNREACH_NOROUTE:
                    xprintf(" !N");
                    ++fexit;
                    break;
                  case ICMP6_DST_UNREACH_ADDR:
                    xprintf(" !H");
                    ++fexit;
                    break;
                  case ICMP6_DST_UNREACH_ADMIN:
                    xprintf(" !S");
                    ++fexit;
                    break;
                  default:
                    break;
                }
                break;
              }
            } //revents
          }
          print_verbose = 0;
        }
        xputc('\n');
        if(!TT.istraceroute6) {
          if (!memcmp(&((struct sockaddr_in *)&from)->sin_addr, 
                &((struct sockaddr_in *)&dest)->sin_addr, sizeof(struct in_addr))
              || dest_reach || (fexit && fexit >= TT.ttl_probes -1))
            break;
        } else if (dest_reach || (fexit > 0 && fexit >= TT.ttl_probes -1)) break;
      }
    }
    
    void traceroute_main(void)
    {
      unsigned pack_size = 0, tyser = 0;
      int lsrr = 0, set = 1;
      
      if(!(toys.optflags & FLAG_4) && 
          (inet_pton(AF_INET6, toys.optargs[0], &dest)))
        toys.optflags |= FLAG_6;
    
      memset(&dest, 0, sizeof(dest));
      if (toys.optflags & FLAG_6) TT.istraceroute6 = 1;
      else TT.istraceroute6 = toys.which->name[10] == '6';
    
      if(!TT.istraceroute6 && (toys.optflags & FLAG_g)) {
          struct arg_list *node;
    
          for (node = TT.loose_source; node; node = node->next, lsrr++) {
            struct sockaddr_in sin;
    
            memset( &sin, 0, sizeof(sin));
            if (lsrr >= 8) error_exit("no more than 8 gateways"); // NGATEWAYS
            resolve_addr(node->arg, AF_INET, SOCK_STREAM, 0, &sin);
            TT.gw_list[lsrr] = sin.sin_addr.s_addr;
          }
      } else TT.first_ttl = 1;
    
      TT.msg_len = pack_size = ICMP_HD_SIZE4; //udp payload is also 8bytes
      if (toys.optargs[1])
        TT.msg_len = atolx_range(toys.optargs[1], pack_size, 32768);//max packet size
    
      TT.recv_sock = xsocket((TT.istraceroute6 ? AF_INET6 : AF_INET), SOCK_RAW,
          (TT.istraceroute6 ? IPPROTO_ICMPV6 : IPPROTO_ICMP));
    
      if (TT.istraceroute6) {
        int two = 2;
    #ifdef IPV6_RECVPKTINFO
        setsockopt(TT.recv_sock, SOL_IPV6, IPV6_RECVPKTINFO, &set, 
            sizeof(set));
        setsockopt(TT.recv_sock, SOL_IPV6, IPV6_2292PKTINFO, &set, 
            sizeof(set));
    #else
        setsockopt(TT.recv_sock, SOL_IPV6, IPV6_PKTINFO, &set, sizeof(set));
    #endif
    
        if (setsockopt(TT.recv_sock, SOL_RAW, IPV6_CHECKSUM, &two, 
              sizeof(two)) < 0)  perror_exit("setsockopt RAW_CHECKSUM");
      }
    
      set_flag_dr(TT.recv_sock);
    
      if (!TT.istraceroute6) {
        if (toys.optflags & FLAG_U) 
          TT.snd_sock = xsocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
        else TT.snd_sock = xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
    
        if (toys.optflags & FLAG_i) bind_to_interface(TT.snd_sock);
    
        resolve_addr(toys.optargs[0], AF_INET, ((toys.optflags & FLAG_U) ? 
              SOCK_DGRAM : SOCK_RAW), ((toys.optflags & FLAG_U) ? IPPROTO_UDP : 
                IPPROTO_ICMP), &dest);
        if (lsrr > 0) {
          unsigned char optlist[MAX_IPOPTLEN];
          unsigned size;
    
          TT.gw_list[lsrr] = ((struct sockaddr_in *)&dest)->sin_addr.s_addr;
          ++lsrr;
    
          optlist[0] = IPOPT_NOP;
          optlist[1] = IPOPT_LSRR;// loose source route option 
          size = lsrr * sizeof(TT.gw_list[0]);
          optlist[2] = size + 3;
          optlist[3] = IPOPT_MINOFF;
          memcpy(optlist + 4, TT.gw_list, size);
    
          if (setsockopt(TT.snd_sock, IPPROTO_IP, IP_OPTIONS,
                (char *)optlist, size + sizeof(TT.gw_list[0])) < 0)
            perror_exit("LSRR IP_OPTIONS");
        }
      } else TT.snd_sock = xsocket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
    
      if (setsockopt(TT.snd_sock, SOL_SOCKET, SO_SNDBUF, &TT.msg_len, 
            sizeof(TT.msg_len)) < 0) perror_exit("SO_SNDBUF failed ");
    
      if (!TT.istraceroute6) {
        if ((toys.optflags & FLAG_t) && 
            setsockopt(TT.snd_sock, IPPROTO_IP, IP_TOS, &tyser, sizeof(tyser)) < 0)
          perror_exit("IP_TOS %ld failed ", TT.tos);
    
    #ifdef IP_DONTFRAG
        if ((toys.optflags & FLAG_F) &&
            (setsockopt(TT.snd_sock, IPPROTO_IP, IP_DONTFRAG, &set, 
                        sizeof(set)) < 0)) perror_exit("IP_DONTFRAG failed ");
    #endif
      } else if (setsockopt(TT.snd_sock, IPPROTO_IPV6, IPV6_TCLASS, &TT.tos,
            sizeof(TT.tos)) < 0) perror_exit("IPV6_TCLASS %ld failed ", TT.tos);
    
      set_flag_dr(TT.snd_sock);
      TT.packet = xzalloc(TT.msg_len);
      TT.ident = getpid();
    
      if (!TT.istraceroute6) {
        if (!(toys.optflags & FLAG_U)) TT.ident |= 0x8000;
        if (toys.optflags & FLAG_s) {
          struct sockaddr_in source;
    
          memset(&source, 0, sizeof(source));
          if (!inet_aton(TT.src_ip, &(source.sin_addr)))
            error_exit("bad address: %s", TT.src_ip);
          if (setsockopt(TT.snd_sock, IPPROTO_IP, IP_MULTICAST_IF,
                (struct sockaddr*)&source, sizeof(struct sockaddr_in)))
            perror_exit("can't set multicast source interface");
          xbind(TT.snd_sock,(struct sockaddr*)&source, sizeof(struct sockaddr_in));
        }
    
        if(TT.first_ttl > TT.max_ttl) 
          error_exit("ERROR :Range for -f is 1 to %ld (max ttl)", TT.max_ttl);
    
        xprintf("traceroute to %s(%s)", toys.optargs[0], 
               inet_ntoa(((struct sockaddr_in *)&dest)->sin_addr));
      } else {
        if (toys.optflags & FLAG_i) bind_to_interface(TT.snd_sock);
    
        resolve_addr(toys.optargs[0], AF_INET6, SOCK_DGRAM, IPPROTO_UDP, &dest);
        if (toys.optflags & FLAG_s) {
          struct sockaddr_in6 source;
    
          memset(&source, 0, sizeof(source));
          if(inet_pton(AF_INET6, TT.src_ip, &(source.sin6_addr)) <= 0)
            error_exit("bad address: %s", TT.src_ip);
    
          xbind(TT.snd_sock,(struct sockaddr*)&source, sizeof(struct sockaddr_in6));
        } else {
          struct sockaddr_in6 prb;
          socklen_t len = sizeof(prb);
          int p_fd = xsocket(AF_INET6, SOCK_DGRAM, 0);
          if (toys.optflags & FLAG_i) bind_to_interface(p_fd);
    
          ((struct sockaddr_in6 *)&dest)->sin6_port = htons(1025);
          xconnect(p_fd, (struct sockaddr *)&dest, sizeof(struct sockaddr_in6));
          if(getsockname(p_fd, (struct sockaddr *)&prb, &len)) 
            error_exit("probe addr failed");
          close(p_fd);
          prb.sin6_port = 0;
          xbind(TT.snd_sock, (struct sockaddr*)&prb, sizeof(struct sockaddr_in6));
          xbind(TT.recv_sock, (struct sockaddr*)&prb, sizeof(struct sockaddr_in6));
        }
    
        inet_ntop(AF_INET6, &((struct sockaddr_in6 *)&dest)->sin6_addr, 
                  addr_str, INET6_ADDRSTRLEN);
        xprintf("traceroute6 to %s(%s)", toys.optargs[0], addr_str);
      }
    
      if (toys.optflags & FLAG_s) xprintf(" from %s",TT.src_ip);
      xprintf(", %ld hops max, %u byte packets\n", TT.max_ttl, TT.msg_len);
    
      do_trace();
    }