10f66f451Sopenharmony_ci/* traceroute - trace the route to "host".
20f66f451Sopenharmony_ci *
30f66f451Sopenharmony_ci * Copyright 2012 Madhur Verma <mad.flexi@gmail.com>
40f66f451Sopenharmony_ci * Copyright 2013 Kyungwan Han <asura321@gmail.com>
50f66f451Sopenharmony_ci * Copyright 2013 Bilal Qureshi <bilal.jmi@gmail.com>
60f66f451Sopenharmony_ci * Copyright 2013 Ashwini Kumar <ak.ashwini1981@gmail.com>
70f66f451Sopenharmony_ci *
80f66f451Sopenharmony_ci * No Standard
90f66f451Sopenharmony_ci
100f66f451Sopenharmony_ciUSE_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))
110f66f451Sopenharmony_ciUSE_TRACEROUTE(OLDTOY(traceroute6,traceroute, TOYFLAG_STAYROOT|TOYFLAG_USR|TOYFLAG_BIN))
120f66f451Sopenharmony_ciconfig TRACEROUTE
130f66f451Sopenharmony_ci  bool "traceroute"
140f66f451Sopenharmony_ci  default n
150f66f451Sopenharmony_ci  help
160f66f451Sopenharmony_ci    usage: traceroute [-46FUIldnvr] [-f 1ST_TTL] [-m MAXTTL] [-p PORT] [-q PROBES]
170f66f451Sopenharmony_ci    [-s SRC_IP] [-t TOS] [-w WAIT_SEC] [-g GATEWAY] [-i IFACE] [-z PAUSE_MSEC] HOST [BYTES]
180f66f451Sopenharmony_ci
190f66f451Sopenharmony_ci    traceroute6 [-dnrv] [-m MAXTTL] [-p PORT] [-q PROBES][-s SRC_IP] [-t TOS] [-w WAIT_SEC]
200f66f451Sopenharmony_ci      [-i IFACE] HOST [BYTES]
210f66f451Sopenharmony_ci
220f66f451Sopenharmony_ci    Trace the route to HOST
230f66f451Sopenharmony_ci
240f66f451Sopenharmony_ci    -4,-6 Force IP or IPv6 name resolution
250f66f451Sopenharmony_ci    -F    Set the don't fragment bit (supports IPV4 only)
260f66f451Sopenharmony_ci    -U    Use UDP datagrams instead of ICMP ECHO (supports IPV4 only)
270f66f451Sopenharmony_ci    -I    Use ICMP ECHO instead of UDP datagrams (supports IPV4 only)
280f66f451Sopenharmony_ci    -l    Display the TTL value of the returned packet (supports IPV4 only)
290f66f451Sopenharmony_ci    -d    Set SO_DEBUG options to socket
300f66f451Sopenharmony_ci    -n    Print numeric addresses
310f66f451Sopenharmony_ci    -v    verbose
320f66f451Sopenharmony_ci    -r    Bypass routing tables, send directly to HOST
330f66f451Sopenharmony_ci    -m    Max time-to-live (max number of hops)(RANGE 1 to 255)
340f66f451Sopenharmony_ci    -p    Base UDP port number used in probes(default 33434)(RANGE 1 to 65535)
350f66f451Sopenharmony_ci    -q    Number of probes per TTL (default 3)(RANGE 1 to 255)
360f66f451Sopenharmony_ci    -s    IP address to use as the source address
370f66f451Sopenharmony_ci    -t    Type-of-service in probe packets (default 0)(RANGE 0 to 255)
380f66f451Sopenharmony_ci    -w    Time in seconds to wait for a response (default 3)(RANGE 0 to 86400)
390f66f451Sopenharmony_ci    -g    Loose source route gateway (8 max) (supports IPV4 only)
400f66f451Sopenharmony_ci    -z    Pause Time in ms (default 0)(RANGE 0 to 86400) (supports IPV4 only)
410f66f451Sopenharmony_ci    -f    Start from the 1ST_TTL hop (instead from 1)(RANGE 1 to 255) (supports IPV4 only)
420f66f451Sopenharmony_ci    -i    Specify a network interface to operate with
430f66f451Sopenharmony_ci*/
440f66f451Sopenharmony_ci#define FOR_traceroute
450f66f451Sopenharmony_ci#include "toys.h"
460f66f451Sopenharmony_ci#include <netinet/udp.h>
470f66f451Sopenharmony_ci#include <netinet/ip_icmp.h>
480f66f451Sopenharmony_ci#include <netinet/ip6.h>
490f66f451Sopenharmony_ci#include <netinet/icmp6.h>
500f66f451Sopenharmony_ci
510f66f451Sopenharmony_ciGLOBALS(
520f66f451Sopenharmony_ci  long max_ttl;
530f66f451Sopenharmony_ci  long port;
540f66f451Sopenharmony_ci  long ttl_probes;
550f66f451Sopenharmony_ci  char *src_ip;
560f66f451Sopenharmony_ci  long tos;
570f66f451Sopenharmony_ci  long wait_time;
580f66f451Sopenharmony_ci  struct arg_list *loose_source;
590f66f451Sopenharmony_ci  long pause_time;
600f66f451Sopenharmony_ci  long first_ttl;
610f66f451Sopenharmony_ci  char *iface;
620f66f451Sopenharmony_ci
630f66f451Sopenharmony_ci  uint32_t gw_list[9];
640f66f451Sopenharmony_ci  int recv_sock;
650f66f451Sopenharmony_ci  int snd_sock;
660f66f451Sopenharmony_ci  unsigned msg_len;
670f66f451Sopenharmony_ci  char *packet;
680f66f451Sopenharmony_ci  uint32_t ident;
690f66f451Sopenharmony_ci  int istraceroute6;
700f66f451Sopenharmony_ci)
710f66f451Sopenharmony_ci
720f66f451Sopenharmony_ci#ifndef SOL_IPV6
730f66f451Sopenharmony_ci# define SOL_IPV6 IPPROTO_IPV6
740f66f451Sopenharmony_ci#endif
750f66f451Sopenharmony_ci
760f66f451Sopenharmony_ci#define ICMP_HD_SIZE4  8
770f66f451Sopenharmony_ci#define USEC           1000000ULL
780f66f451Sopenharmony_ci
790f66f451Sopenharmony_cistruct payload_s {
800f66f451Sopenharmony_ci  uint32_t seq;
810f66f451Sopenharmony_ci  uint32_t ident;
820f66f451Sopenharmony_ci};
830f66f451Sopenharmony_ci
840f66f451Sopenharmony_cichar addr_str[INET6_ADDRSTRLEN];
850f66f451Sopenharmony_cistruct sockaddr_storage dest;
860f66f451Sopenharmony_ci
870f66f451Sopenharmony_ci//Compute checksum SUM of buffer P of length LEN
880f66f451Sopenharmony_cistatic u_int16_t in_cksum(u_int16_t *p, u_int len)
890f66f451Sopenharmony_ci{
900f66f451Sopenharmony_ci  u_int32_t sum = 0;
910f66f451Sopenharmony_ci  int nwords = len >> 1;
920f66f451Sopenharmony_ci
930f66f451Sopenharmony_ci  while (nwords-- != 0) sum += *p++;
940f66f451Sopenharmony_ci  if (len & 1) {
950f66f451Sopenharmony_ci    union {
960f66f451Sopenharmony_ci      u_int16_t w;
970f66f451Sopenharmony_ci      u_int8_t c[2];
980f66f451Sopenharmony_ci    } u;
990f66f451Sopenharmony_ci    u.c[0] = *(u_char *) p;
1000f66f451Sopenharmony_ci    u.c[1] = 0;
1010f66f451Sopenharmony_ci    sum += u.w;
1020f66f451Sopenharmony_ci  }
1030f66f451Sopenharmony_ci  // end-around-carry
1040f66f451Sopenharmony_ci  sum = (sum >> 16) + (sum & 0xffff);
1050f66f451Sopenharmony_ci  sum += (sum >> 16);
1060f66f451Sopenharmony_ci  return (~sum);
1070f66f451Sopenharmony_ci}
1080f66f451Sopenharmony_ci
1090f66f451Sopenharmony_ci//sends a single probe packet with sequence(SEQ) and time-to-live(TTL)
1100f66f451Sopenharmony_cistatic void send_probe4(int seq, int ttl)
1110f66f451Sopenharmony_ci{
1120f66f451Sopenharmony_ci  int res, len;
1130f66f451Sopenharmony_ci  void *out;
1140f66f451Sopenharmony_ci  struct payload_s *send_data4 = (struct payload_s *)(TT.packet);
1150f66f451Sopenharmony_ci  struct icmp *send_icmp4 = (struct icmp *)(TT.packet);
1160f66f451Sopenharmony_ci
1170f66f451Sopenharmony_ci  if (toys.optflags & FLAG_U) {
1180f66f451Sopenharmony_ci    send_data4->seq = seq;
1190f66f451Sopenharmony_ci    send_data4->ident = TT.ident;
1200f66f451Sopenharmony_ci    ((struct sockaddr_in *)&dest)->sin_port = TT.port + seq;
1210f66f451Sopenharmony_ci    out = send_data4;
1220f66f451Sopenharmony_ci  } else {
1230f66f451Sopenharmony_ci    send_icmp4->icmp_type = ICMP_ECHO;
1240f66f451Sopenharmony_ci    send_icmp4->icmp_id = htons(TT.ident);
1250f66f451Sopenharmony_ci    send_icmp4->icmp_seq = htons(seq);
1260f66f451Sopenharmony_ci    send_icmp4->icmp_cksum = 0;
1270f66f451Sopenharmony_ci    send_icmp4->icmp_cksum = in_cksum((uint16_t *) send_icmp4, TT.msg_len);
1280f66f451Sopenharmony_ci    if (send_icmp4->icmp_cksum == 0) send_icmp4->icmp_cksum = 0xffff;
1290f66f451Sopenharmony_ci    out = send_icmp4;
1300f66f451Sopenharmony_ci  }
1310f66f451Sopenharmony_ci
1320f66f451Sopenharmony_ci  res = setsockopt(TT.snd_sock, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
1330f66f451Sopenharmony_ci  if (res < 0) perror_exit("setsockopt ttl %d", ttl);
1340f66f451Sopenharmony_ci
1350f66f451Sopenharmony_ci  len = TT.msg_len;
1360f66f451Sopenharmony_ci  res = sendto(TT.snd_sock, out, len, 0, (struct sockaddr *) &dest,
1370f66f451Sopenharmony_ci      sizeof(struct sockaddr_in));
1380f66f451Sopenharmony_ci  if (res != len) perror_exit(" sendto");
1390f66f451Sopenharmony_ci}
1400f66f451Sopenharmony_ci
1410f66f451Sopenharmony_ci//sends a single probe packet with sequence(SEQ) and time-to-live(TTL)
1420f66f451Sopenharmony_cistatic void send_probe6(int seq, int ttl)
1430f66f451Sopenharmony_ci{
1440f66f451Sopenharmony_ci  void *out;
1450f66f451Sopenharmony_ci  struct payload_s *send_data6 = (struct payload_s *) (TT.packet);
1460f66f451Sopenharmony_ci
1470f66f451Sopenharmony_ci  send_data6->seq = seq;
1480f66f451Sopenharmony_ci  send_data6->ident = TT.ident;
1490f66f451Sopenharmony_ci  ((struct sockaddr_in6 *)&dest)->sin6_port = TT.port;
1500f66f451Sopenharmony_ci
1510f66f451Sopenharmony_ci  if (setsockopt(TT.snd_sock, SOL_IPV6, IPV6_UNICAST_HOPS, &ttl,
1520f66f451Sopenharmony_ci        sizeof(ttl)) < 0) error_exit("setsockopt ttl %d", ttl);
1530f66f451Sopenharmony_ci
1540f66f451Sopenharmony_ci  out = send_data6;
1550f66f451Sopenharmony_ci
1560f66f451Sopenharmony_ci  if (sendto(TT.snd_sock, out, TT.msg_len, 0,
1570f66f451Sopenharmony_ci        (struct sockaddr *) &dest, sizeof(struct sockaddr_in6)) < 0)
1580f66f451Sopenharmony_ci    perror_exit("sendto");
1590f66f451Sopenharmony_ci}
1600f66f451Sopenharmony_ci
1610f66f451Sopenharmony_cistatic void set_flag_dr(int sock)
1620f66f451Sopenharmony_ci{
1630f66f451Sopenharmony_ci  int set = 1;
1640f66f451Sopenharmony_ci  if ((toys.optflags & FLAG_d) && (setsockopt(sock,SOL_SOCKET, SO_DEBUG,
1650f66f451Sopenharmony_ci          &set, sizeof(set)) < 0)) perror_exit("SO_DEBUG failed ");
1660f66f451Sopenharmony_ci
1670f66f451Sopenharmony_ci  if ((toys.optflags & FLAG_r) && (setsockopt(sock, SOL_SOCKET, SO_DONTROUTE,
1680f66f451Sopenharmony_ci          &set, sizeof(set)) < 0)) perror_exit("SO_DONTROUTE failed ");
1690f66f451Sopenharmony_ci}
1700f66f451Sopenharmony_ci
1710f66f451Sopenharmony_cistatic void bind_to_interface(int sock)
1720f66f451Sopenharmony_ci{
1730f66f451Sopenharmony_ci  struct ifreq ifr;
1740f66f451Sopenharmony_ci
1750f66f451Sopenharmony_ci  snprintf(ifr.ifr_name, IFNAMSIZ, "%s", TT.iface);
1760f66f451Sopenharmony_ci  if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)))
1770f66f451Sopenharmony_ci      perror_msg("can't bind to interface %s", TT.iface);
1780f66f451Sopenharmony_ci}
1790f66f451Sopenharmony_ci
1800f66f451Sopenharmony_cistatic void resolve_addr(char *host, int family, int type, int proto, void *sock)
1810f66f451Sopenharmony_ci{
1820f66f451Sopenharmony_ci  struct addrinfo *info, hint;
1830f66f451Sopenharmony_ci  int ret;
1840f66f451Sopenharmony_ci
1850f66f451Sopenharmony_ci  memset(&hint, 0, sizeof(hint));
1860f66f451Sopenharmony_ci  hint.ai_family = family;
1870f66f451Sopenharmony_ci  hint.ai_socktype = type;
1880f66f451Sopenharmony_ci  hint.ai_protocol = proto;
1890f66f451Sopenharmony_ci
1900f66f451Sopenharmony_ci  ret = getaddrinfo(host, NULL, &hint, &info);
1910f66f451Sopenharmony_ci  if (ret || !info) error_exit("bad address:  %s ", host);
1920f66f451Sopenharmony_ci
1930f66f451Sopenharmony_ci  memcpy(sock, info->ai_addr, info->ai_addrlen);
1940f66f451Sopenharmony_ci  freeaddrinfo(info);
1950f66f451Sopenharmony_ci}
1960f66f451Sopenharmony_ci
1970f66f451Sopenharmony_cistatic void do_trace()
1980f66f451Sopenharmony_ci{
1990f66f451Sopenharmony_ci  int seq, fexit, ttl, tv = TT.wait_time * 1000;
2000f66f451Sopenharmony_ci  struct pollfd pfd[1];
2010f66f451Sopenharmony_ci  struct sockaddr_storage from;
2020f66f451Sopenharmony_ci
2030f66f451Sopenharmony_ci  memset(&from, 0, sizeof(from));
2040f66f451Sopenharmony_ci  pfd[0].fd = TT.recv_sock;
2050f66f451Sopenharmony_ci  pfd[0].events = POLLIN;
2060f66f451Sopenharmony_ci
2070f66f451Sopenharmony_ci  for (ttl = TT.first_ttl; ttl <= TT.max_ttl; ++ttl) {
2080f66f451Sopenharmony_ci    int probe, dest_reach = 0, print_verbose = 1;
2090f66f451Sopenharmony_ci    struct timeval t1, t2;
2100f66f451Sopenharmony_ci    struct sockaddr_storage last_addr;
2110f66f451Sopenharmony_ci
2120f66f451Sopenharmony_ci    memset(&last_addr, 0, sizeof(last_addr));
2130f66f451Sopenharmony_ci    fexit = 0;
2140f66f451Sopenharmony_ci    xprintf("%2d", ttl);
2150f66f451Sopenharmony_ci
2160f66f451Sopenharmony_ci    for (probe = 0, seq = 0; probe < TT.ttl_probes; ++probe) {
2170f66f451Sopenharmony_ci      int res = 0, tleft;
2180f66f451Sopenharmony_ci
2190f66f451Sopenharmony_ci      fflush(NULL);
2200f66f451Sopenharmony_ci      if (!TT.istraceroute6)
2210f66f451Sopenharmony_ci        if (probe && (toys.optflags & FLAG_z)) msleep(TT.pause_time);
2220f66f451Sopenharmony_ci
2230f66f451Sopenharmony_ci      if (!TT.istraceroute6) send_probe4(++seq, ttl);
2240f66f451Sopenharmony_ci      else send_probe6(++seq, ttl);
2250f66f451Sopenharmony_ci      gettimeofday(&t1, NULL);
2260f66f451Sopenharmony_ci      t2 = t1;
2270f66f451Sopenharmony_ci
2280f66f451Sopenharmony_ci      while ((tleft = (int)(tv - ((unsigned long long)(t2.tv_sec * 1000ULL
2290f66f451Sopenharmony_ci                  + t2.tv_usec/1000) - (unsigned long long)(t1.tv_sec * 1000ULL
2300f66f451Sopenharmony_ci                    + t1.tv_usec/1000)))) >= 0) {
2310f66f451Sopenharmony_ci        unsigned delta = 0;
2320f66f451Sopenharmony_ci        if (!(res = poll(pfd, 1, tleft))) {
2330f66f451Sopenharmony_ci          xprintf("  *");
2340f66f451Sopenharmony_ci          break;
2350f66f451Sopenharmony_ci        }
2360f66f451Sopenharmony_ci        gettimeofday(&t2, NULL);
2370f66f451Sopenharmony_ci        if (res < 0) {
2380f66f451Sopenharmony_ci          if (errno != EINTR) perror_exit("poll");
2390f66f451Sopenharmony_ci          continue;
2400f66f451Sopenharmony_ci        }
2410f66f451Sopenharmony_ci        delta = (t2.tv_sec * USEC + t2.tv_usec)
2420f66f451Sopenharmony_ci          - (t1.tv_sec * USEC + t1.tv_usec);
2430f66f451Sopenharmony_ci
2440f66f451Sopenharmony_ci        if (pfd[0].revents) {
2450f66f451Sopenharmony_ci          socklen_t addrlen = sizeof(struct sockaddr_storage);
2460f66f451Sopenharmony_ci          int rcv_len, icmp_res = 0;
2470f66f451Sopenharmony_ci
2480f66f451Sopenharmony_ci          rcv_len = recvfrom(TT.recv_sock, toybuf, sizeof(toybuf),
2490f66f451Sopenharmony_ci              MSG_DONTWAIT, (struct sockaddr *) &from, &addrlen);
2500f66f451Sopenharmony_ci          if (rcv_len <= 0) continue;
2510f66f451Sopenharmony_ci
2520f66f451Sopenharmony_ci          if (!TT.istraceroute6) {
2530f66f451Sopenharmony_ci            int pmtu = 0;
2540f66f451Sopenharmony_ci            struct ip *rcv_pkt = (struct ip*) toybuf;
2550f66f451Sopenharmony_ci            struct icmp *ricmp;
2560f66f451Sopenharmony_ci
2570f66f451Sopenharmony_ci            ricmp = (struct icmp *) ((char*)rcv_pkt + (rcv_pkt->ip_hl << 2));
2580f66f451Sopenharmony_ci            if (ricmp->icmp_code == ICMP_UNREACH_NEEDFRAG)
2590f66f451Sopenharmony_ci              pmtu = ntohs(ricmp->icmp_nextmtu);
2600f66f451Sopenharmony_ci
2610f66f451Sopenharmony_ci            if ((ricmp->icmp_type == ICMP_TIMXCEED
2620f66f451Sopenharmony_ci                  && ricmp->icmp_code == ICMP_TIMXCEED_INTRANS)
2630f66f451Sopenharmony_ci                || ricmp->icmp_type == ICMP_UNREACH
2640f66f451Sopenharmony_ci                || ricmp->icmp_type == ICMP_ECHOREPLY) {
2650f66f451Sopenharmony_ci
2660f66f451Sopenharmony_ci              struct udphdr *hudp;
2670f66f451Sopenharmony_ci              struct icmp *hicmp;
2680f66f451Sopenharmony_ci              struct ip *hip = &ricmp->icmp_ip;
2690f66f451Sopenharmony_ci
2700f66f451Sopenharmony_ci              if (toys.optflags & FLAG_U) {
2710f66f451Sopenharmony_ci                hudp = (struct udphdr*) ((char*)hip + (hip->ip_hl << 2));
2720f66f451Sopenharmony_ci                if ((hip->ip_hl << 2) + 12 <=(rcv_len - (rcv_pkt->ip_hl << 2))
2730f66f451Sopenharmony_ci                    && hip->ip_p == IPPROTO_UDP
2740f66f451Sopenharmony_ci                    && hudp->dest == (TT.port + seq))
2750f66f451Sopenharmony_ci                  icmp_res = (ricmp->icmp_type == ICMP_TIMXCEED ? -1 :
2760f66f451Sopenharmony_ci                      ricmp->icmp_code);
2770f66f451Sopenharmony_ci              } else {
2780f66f451Sopenharmony_ci                hicmp = (struct icmp *) ((char*)hip + (hip->ip_hl << 2));
2790f66f451Sopenharmony_ci                if (ricmp->icmp_type == ICMP_ECHOREPLY
2800f66f451Sopenharmony_ci                    && ricmp->icmp_id == ntohs(TT.ident)
2810f66f451Sopenharmony_ci                    && ricmp->icmp_seq == ntohs(seq))
2820f66f451Sopenharmony_ci                  icmp_res = ICMP_UNREACH_PORT;
2830f66f451Sopenharmony_ci                else if ((hip->ip_hl << 2) + ICMP_HD_SIZE4
2840f66f451Sopenharmony_ci                    <= (rcv_len - (rcv_pkt->ip_hl << 2))
2850f66f451Sopenharmony_ci                    && hip->ip_p == IPPROTO_ICMP
2860f66f451Sopenharmony_ci                    && hicmp->icmp_id == htons(TT.ident)
2870f66f451Sopenharmony_ci                    && hicmp->icmp_seq == htons(seq))
2880f66f451Sopenharmony_ci                  icmp_res = (ricmp->icmp_type == ICMP_TIMXCEED ? -1 :
2890f66f451Sopenharmony_ci                      ricmp->icmp_code);
2900f66f451Sopenharmony_ci              }
2910f66f451Sopenharmony_ci            }
2920f66f451Sopenharmony_ci            if (!icmp_res) continue;
2930f66f451Sopenharmony_ci
2940f66f451Sopenharmony_ci            if (addrlen > 0) {
2950f66f451Sopenharmony_ci              if (memcmp(&((struct sockaddr_in *)&last_addr)->sin_addr,
2960f66f451Sopenharmony_ci                    &((struct sockaddr_in *)&from)->sin_addr,
2970f66f451Sopenharmony_ci                    sizeof(struct in_addr))) {
2980f66f451Sopenharmony_ci                if (!(toys.optflags & FLAG_n)) {
2990f66f451Sopenharmony_ci                  char host[NI_MAXHOST];
3000f66f451Sopenharmony_ci                  if (!getnameinfo((struct sockaddr *) &from,
3010f66f451Sopenharmony_ci                        sizeof(struct sockaddr_in), host, NI_MAXHOST, NULL, 0, 0))
3020f66f451Sopenharmony_ci                    xprintf("  %s (", host);
3030f66f451Sopenharmony_ci                  else xprintf(" %s (", inet_ntoa(
3040f66f451Sopenharmony_ci                          ((struct sockaddr_in *)&from)->sin_addr));
3050f66f451Sopenharmony_ci                }
3060f66f451Sopenharmony_ci                xprintf(" %s", inet_ntoa(
3070f66f451Sopenharmony_ci                      ((struct sockaddr_in *)&from)->sin_addr));
3080f66f451Sopenharmony_ci                if (!(toys.optflags & FLAG_n)) xprintf(")");
3090f66f451Sopenharmony_ci                memcpy(&last_addr, &from, sizeof(from));
3100f66f451Sopenharmony_ci              }
3110f66f451Sopenharmony_ci              xprintf("  %u.%03u ms", delta / 1000, delta % 1000);
3120f66f451Sopenharmony_ci              if (toys.optflags & FLAG_l) xprintf(" (%d)", rcv_pkt->ip_ttl);
3130f66f451Sopenharmony_ci              if (toys.optflags & FLAG_v) {
3140f66f451Sopenharmony_ci                xprintf(" %d bytes from %s : icmp type %d code %d\t",
3150f66f451Sopenharmony_ci                    rcv_len, inet_ntoa(((struct sockaddr_in *)&from)->sin_addr),
3160f66f451Sopenharmony_ci                    ricmp->icmp_type, ricmp->icmp_code);
3170f66f451Sopenharmony_ci              }
3180f66f451Sopenharmony_ci            } else xprintf("\t!H");
3190f66f451Sopenharmony_ci
3200f66f451Sopenharmony_ci            switch (icmp_res) {
3210f66f451Sopenharmony_ci              case ICMP_UNREACH_PORT:
3220f66f451Sopenharmony_ci                if (rcv_pkt->ip_ttl <= 1) xprintf(" !");
3230f66f451Sopenharmony_ci                dest_reach = 1;
3240f66f451Sopenharmony_ci                break;
3250f66f451Sopenharmony_ci              case ICMP_UNREACH_NET:
3260f66f451Sopenharmony_ci                xprintf(" !N");
3270f66f451Sopenharmony_ci                ++fexit;
3280f66f451Sopenharmony_ci                break;
3290f66f451Sopenharmony_ci              case ICMP_UNREACH_HOST:
3300f66f451Sopenharmony_ci                xprintf(" !H");
3310f66f451Sopenharmony_ci                ++fexit;
3320f66f451Sopenharmony_ci                break;
3330f66f451Sopenharmony_ci              case ICMP_UNREACH_PROTOCOL:
3340f66f451Sopenharmony_ci                xprintf(" !P");
3350f66f451Sopenharmony_ci                dest_reach = 1;
3360f66f451Sopenharmony_ci                break;
3370f66f451Sopenharmony_ci              case ICMP_UNREACH_NEEDFRAG:
3380f66f451Sopenharmony_ci                xprintf(" !F-%d", pmtu);
3390f66f451Sopenharmony_ci                ++fexit;
3400f66f451Sopenharmony_ci                break;
3410f66f451Sopenharmony_ci              case ICMP_UNREACH_SRCFAIL:
3420f66f451Sopenharmony_ci                xprintf(" !S");
3430f66f451Sopenharmony_ci                ++fexit;
3440f66f451Sopenharmony_ci                break;
3450f66f451Sopenharmony_ci              case ICMP_UNREACH_FILTER_PROHIB:
3460f66f451Sopenharmony_ci              case ICMP_UNREACH_NET_PROHIB:
3470f66f451Sopenharmony_ci                xprintf(" !A");
3480f66f451Sopenharmony_ci                ++fexit;
3490f66f451Sopenharmony_ci                break;
3500f66f451Sopenharmony_ci              case ICMP_UNREACH_HOST_PROHIB:
3510f66f451Sopenharmony_ci                xprintf(" !C");
3520f66f451Sopenharmony_ci                ++fexit;
3530f66f451Sopenharmony_ci                break;
3540f66f451Sopenharmony_ci              case ICMP_UNREACH_HOST_PRECEDENCE:
3550f66f451Sopenharmony_ci                xprintf(" !V");
3560f66f451Sopenharmony_ci                ++fexit;
3570f66f451Sopenharmony_ci                break;
3580f66f451Sopenharmony_ci              case ICMP_UNREACH_PRECEDENCE_CUTOFF:
3590f66f451Sopenharmony_ci                xprintf(" !C");
3600f66f451Sopenharmony_ci                ++fexit;
3610f66f451Sopenharmony_ci                break;
3620f66f451Sopenharmony_ci              case ICMP_UNREACH_NET_UNKNOWN:
3630f66f451Sopenharmony_ci              case ICMP_UNREACH_HOST_UNKNOWN:
3640f66f451Sopenharmony_ci                xprintf(" !U");
3650f66f451Sopenharmony_ci                ++fexit;
3660f66f451Sopenharmony_ci                break;
3670f66f451Sopenharmony_ci              case ICMP_UNREACH_ISOLATED:
3680f66f451Sopenharmony_ci                xprintf(" !I");
3690f66f451Sopenharmony_ci                ++fexit;
3700f66f451Sopenharmony_ci                break;
3710f66f451Sopenharmony_ci              case ICMP_UNREACH_TOSNET:
3720f66f451Sopenharmony_ci              case ICMP_UNREACH_TOSHOST:
3730f66f451Sopenharmony_ci                xprintf(" !T");
3740f66f451Sopenharmony_ci                ++fexit;
3750f66f451Sopenharmony_ci                break;
3760f66f451Sopenharmony_ci              default:
3770f66f451Sopenharmony_ci                break;
3780f66f451Sopenharmony_ci            }
3790f66f451Sopenharmony_ci            break;
3800f66f451Sopenharmony_ci          } else {
3810f66f451Sopenharmony_ci            struct icmp6_hdr *ricmp  = (struct icmp6_hdr *) toybuf;
3820f66f451Sopenharmony_ci
3830f66f451Sopenharmony_ci            if ((ricmp->icmp6_type == ICMP6_TIME_EXCEEDED
3840f66f451Sopenharmony_ci                  && ricmp->icmp6_code == ICMP6_TIME_EXCEED_TRANSIT)
3850f66f451Sopenharmony_ci                || ricmp->icmp6_type == ICMP6_DST_UNREACH
3860f66f451Sopenharmony_ci                || ricmp->icmp6_type == ICMP6_ECHO_REPLY) {
3870f66f451Sopenharmony_ci
3880f66f451Sopenharmony_ci              struct ip6_hdr *hip;
3890f66f451Sopenharmony_ci              struct udphdr *hudp;
3900f66f451Sopenharmony_ci              int hdr_next;
3910f66f451Sopenharmony_ci
3920f66f451Sopenharmony_ci              hip = (struct ip6_hdr *)(ricmp + 1);
3930f66f451Sopenharmony_ci              hudp = (struct udphdr*) (hip + 1);
3940f66f451Sopenharmony_ci              hdr_next = hip->ip6_nxt;
3950f66f451Sopenharmony_ci              if (hdr_next == IPPROTO_FRAGMENT) {
3960f66f451Sopenharmony_ci                hdr_next = *(unsigned char*)hudp;
3970f66f451Sopenharmony_ci                hudp++;
3980f66f451Sopenharmony_ci              }
3990f66f451Sopenharmony_ci
4000f66f451Sopenharmony_ci              if (hdr_next == IPPROTO_UDP) {
4010f66f451Sopenharmony_ci                struct payload_s *pkt = (struct payload_s*)(hudp + 1);
4020f66f451Sopenharmony_ci                if ((pkt->ident == TT.ident) && (pkt->seq == seq))
4030f66f451Sopenharmony_ci                  icmp_res = (ricmp->icmp6_type == ICMP6_TIME_EXCEEDED) ? -1 :
4040f66f451Sopenharmony_ci                    ricmp->icmp6_code;
4050f66f451Sopenharmony_ci              }
4060f66f451Sopenharmony_ci            }
4070f66f451Sopenharmony_ci
4080f66f451Sopenharmony_ci            if (!icmp_res) continue;
4090f66f451Sopenharmony_ci            if (addrlen > 0) {
4100f66f451Sopenharmony_ci              if (memcmp(&((struct sockaddr_in6 *)&last_addr)->sin6_addr,
4110f66f451Sopenharmony_ci                    &((struct sockaddr_in6 *)&from)->sin6_addr,
4120f66f451Sopenharmony_ci                    sizeof(struct in6_addr))) {
4130f66f451Sopenharmony_ci                if (!(toys.optflags & FLAG_n)) {
4140f66f451Sopenharmony_ci                  char host[NI_MAXHOST];
4150f66f451Sopenharmony_ci                  if (!getnameinfo((struct sockaddr *) &from,
4160f66f451Sopenharmony_ci                        sizeof(from), host, sizeof(host), NULL, 0, 0))
4170f66f451Sopenharmony_ci                    xprintf("  %s (", host);
4180f66f451Sopenharmony_ci                }
4190f66f451Sopenharmony_ci                memset(addr_str, '\0', INET6_ADDRSTRLEN);
4200f66f451Sopenharmony_ci                inet_ntop(AF_INET6, &((struct sockaddr_in6 *)&from)->sin6_addr,
4210f66f451Sopenharmony_ci                    addr_str, INET6_ADDRSTRLEN);
4220f66f451Sopenharmony_ci                xprintf(" %s", addr_str);
4230f66f451Sopenharmony_ci
4240f66f451Sopenharmony_ci                if (!(toys.optflags & FLAG_n)) xprintf(")");
4250f66f451Sopenharmony_ci                memcpy(&last_addr,&from,sizeof(from));
4260f66f451Sopenharmony_ci              }
4270f66f451Sopenharmony_ci
4280f66f451Sopenharmony_ci              if (toys.optflags & FLAG_v) {
4290f66f451Sopenharmony_ci                if(print_verbose){
4300f66f451Sopenharmony_ci                  memset(addr_str, '\0', INET6_ADDRSTRLEN);
4310f66f451Sopenharmony_ci                  inet_ntop(AF_INET6, &((struct sockaddr_in6 *)
4320f66f451Sopenharmony_ci                        &from)->sin6_addr, addr_str, INET6_ADDRSTRLEN);
4330f66f451Sopenharmony_ci                  rcv_len -= sizeof(struct ip6_hdr);
4340f66f451Sopenharmony_ci                  xprintf(" %d bytes to %s ", rcv_len, addr_str);
4350f66f451Sopenharmony_ci                }
4360f66f451Sopenharmony_ci              }
4370f66f451Sopenharmony_ci              xprintf("  %u.%03u ms", delta / 1000, delta % 1000);
4380f66f451Sopenharmony_ci              delta = 0;
4390f66f451Sopenharmony_ci
4400f66f451Sopenharmony_ci            } else xprintf("\t!H");
4410f66f451Sopenharmony_ci
4420f66f451Sopenharmony_ci            switch (icmp_res) {
4430f66f451Sopenharmony_ci              case ICMP6_DST_UNREACH_NOPORT:
4440f66f451Sopenharmony_ci                ++fexit;
4450f66f451Sopenharmony_ci                dest_reach = 1;
4460f66f451Sopenharmony_ci                break;
4470f66f451Sopenharmony_ci              case ICMP6_DST_UNREACH_NOROUTE:
4480f66f451Sopenharmony_ci                xprintf(" !N");
4490f66f451Sopenharmony_ci                ++fexit;
4500f66f451Sopenharmony_ci                break;
4510f66f451Sopenharmony_ci              case ICMP6_DST_UNREACH_ADDR:
4520f66f451Sopenharmony_ci                xprintf(" !H");
4530f66f451Sopenharmony_ci                ++fexit;
4540f66f451Sopenharmony_ci                break;
4550f66f451Sopenharmony_ci              case ICMP6_DST_UNREACH_ADMIN:
4560f66f451Sopenharmony_ci                xprintf(" !S");
4570f66f451Sopenharmony_ci                ++fexit;
4580f66f451Sopenharmony_ci                break;
4590f66f451Sopenharmony_ci              default:
4600f66f451Sopenharmony_ci                break;
4610f66f451Sopenharmony_ci            }
4620f66f451Sopenharmony_ci            break;
4630f66f451Sopenharmony_ci          }
4640f66f451Sopenharmony_ci        } //revents
4650f66f451Sopenharmony_ci      }
4660f66f451Sopenharmony_ci      print_verbose = 0;
4670f66f451Sopenharmony_ci    }
4680f66f451Sopenharmony_ci    xputc('\n');
4690f66f451Sopenharmony_ci    if(!TT.istraceroute6) {
4700f66f451Sopenharmony_ci      if (!memcmp(&((struct sockaddr_in *)&from)->sin_addr,
4710f66f451Sopenharmony_ci            &((struct sockaddr_in *)&dest)->sin_addr, sizeof(struct in_addr))
4720f66f451Sopenharmony_ci          || dest_reach || (fexit && fexit >= TT.ttl_probes -1))
4730f66f451Sopenharmony_ci        break;
4740f66f451Sopenharmony_ci    } else if (dest_reach || (fexit > 0 && fexit >= TT.ttl_probes -1)) break;
4750f66f451Sopenharmony_ci  }
4760f66f451Sopenharmony_ci}
4770f66f451Sopenharmony_ci
4780f66f451Sopenharmony_civoid traceroute_main(void)
4790f66f451Sopenharmony_ci{
4800f66f451Sopenharmony_ci  unsigned pack_size = 0, tyser = 0;
4810f66f451Sopenharmony_ci  int lsrr = 0, set = 1;
4820f66f451Sopenharmony_ci
4830f66f451Sopenharmony_ci  if(!(toys.optflags & FLAG_4) &&
4840f66f451Sopenharmony_ci      (inet_pton(AF_INET6, toys.optargs[0], &dest)))
4850f66f451Sopenharmony_ci    toys.optflags |= FLAG_6;
4860f66f451Sopenharmony_ci
4870f66f451Sopenharmony_ci  memset(&dest, 0, sizeof(dest));
4880f66f451Sopenharmony_ci  if (toys.optflags & FLAG_6) TT.istraceroute6 = 1;
4890f66f451Sopenharmony_ci  else TT.istraceroute6 = toys.which->name[10] == '6';
4900f66f451Sopenharmony_ci
4910f66f451Sopenharmony_ci  if(!TT.istraceroute6 && (toys.optflags & FLAG_g)) {
4920f66f451Sopenharmony_ci      struct arg_list *node;
4930f66f451Sopenharmony_ci
4940f66f451Sopenharmony_ci      for (node = TT.loose_source; node; node = node->next, lsrr++) {
4950f66f451Sopenharmony_ci        struct sockaddr_in sin;
4960f66f451Sopenharmony_ci
4970f66f451Sopenharmony_ci        memset( &sin, 0, sizeof(sin));
4980f66f451Sopenharmony_ci        if (lsrr >= 8) error_exit("no more than 8 gateways"); // NGATEWAYS
4990f66f451Sopenharmony_ci        resolve_addr(node->arg, AF_INET, SOCK_STREAM, 0, &sin);
5000f66f451Sopenharmony_ci        TT.gw_list[lsrr] = sin.sin_addr.s_addr;
5010f66f451Sopenharmony_ci      }
5020f66f451Sopenharmony_ci  } else TT.first_ttl = 1;
5030f66f451Sopenharmony_ci
5040f66f451Sopenharmony_ci  TT.msg_len = pack_size = ICMP_HD_SIZE4; //udp payload is also 8bytes
5050f66f451Sopenharmony_ci  if (toys.optargs[1])
5060f66f451Sopenharmony_ci    TT.msg_len = atolx_range(toys.optargs[1], pack_size, 32768);//max packet size
5070f66f451Sopenharmony_ci
5080f66f451Sopenharmony_ci  TT.recv_sock = xsocket((TT.istraceroute6 ? AF_INET6 : AF_INET), SOCK_RAW,
5090f66f451Sopenharmony_ci      (TT.istraceroute6 ? IPPROTO_ICMPV6 : IPPROTO_ICMP));
5100f66f451Sopenharmony_ci
5110f66f451Sopenharmony_ci  if (TT.istraceroute6) {
5120f66f451Sopenharmony_ci    int two = 2;
5130f66f451Sopenharmony_ci#ifdef IPV6_RECVPKTINFO
5140f66f451Sopenharmony_ci    setsockopt(TT.recv_sock, SOL_IPV6, IPV6_RECVPKTINFO, &set,
5150f66f451Sopenharmony_ci        sizeof(set));
5160f66f451Sopenharmony_ci    setsockopt(TT.recv_sock, SOL_IPV6, IPV6_2292PKTINFO, &set,
5170f66f451Sopenharmony_ci        sizeof(set));
5180f66f451Sopenharmony_ci#else
5190f66f451Sopenharmony_ci    setsockopt(TT.recv_sock, SOL_IPV6, IPV6_PKTINFO, &set, sizeof(set));
5200f66f451Sopenharmony_ci#endif
5210f66f451Sopenharmony_ci
5220f66f451Sopenharmony_ci    if (setsockopt(TT.recv_sock, SOL_RAW, IPV6_CHECKSUM, &two,
5230f66f451Sopenharmony_ci          sizeof(two)) < 0)  perror_exit("setsockopt RAW_CHECKSUM");
5240f66f451Sopenharmony_ci  }
5250f66f451Sopenharmony_ci
5260f66f451Sopenharmony_ci  set_flag_dr(TT.recv_sock);
5270f66f451Sopenharmony_ci
5280f66f451Sopenharmony_ci  if (!TT.istraceroute6) {
5290f66f451Sopenharmony_ci    if (toys.optflags & FLAG_U)
5300f66f451Sopenharmony_ci      TT.snd_sock = xsocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
5310f66f451Sopenharmony_ci    else TT.snd_sock = xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
5320f66f451Sopenharmony_ci
5330f66f451Sopenharmony_ci    if (toys.optflags & FLAG_i) bind_to_interface(TT.snd_sock);
5340f66f451Sopenharmony_ci
5350f66f451Sopenharmony_ci    resolve_addr(toys.optargs[0], AF_INET, ((toys.optflags & FLAG_U) ?
5360f66f451Sopenharmony_ci          SOCK_DGRAM : SOCK_RAW), ((toys.optflags & FLAG_U) ? IPPROTO_UDP :
5370f66f451Sopenharmony_ci            IPPROTO_ICMP), &dest);
5380f66f451Sopenharmony_ci    if (lsrr > 0) {
5390f66f451Sopenharmony_ci      unsigned char optlist[MAX_IPOPTLEN];
5400f66f451Sopenharmony_ci      unsigned size;
5410f66f451Sopenharmony_ci
5420f66f451Sopenharmony_ci      TT.gw_list[lsrr] = ((struct sockaddr_in *)&dest)->sin_addr.s_addr;
5430f66f451Sopenharmony_ci      ++lsrr;
5440f66f451Sopenharmony_ci
5450f66f451Sopenharmony_ci      optlist[0] = IPOPT_NOP;
5460f66f451Sopenharmony_ci      optlist[1] = IPOPT_LSRR;// loose source route option
5470f66f451Sopenharmony_ci      size = lsrr * sizeof(TT.gw_list[0]);
5480f66f451Sopenharmony_ci      optlist[2] = size + 3;
5490f66f451Sopenharmony_ci      optlist[3] = IPOPT_MINOFF;
5500f66f451Sopenharmony_ci      memcpy(optlist + 4, TT.gw_list, size);
5510f66f451Sopenharmony_ci
5520f66f451Sopenharmony_ci      if (setsockopt(TT.snd_sock, IPPROTO_IP, IP_OPTIONS,
5530f66f451Sopenharmony_ci            (char *)optlist, size + sizeof(TT.gw_list[0])) < 0)
5540f66f451Sopenharmony_ci        perror_exit("LSRR IP_OPTIONS");
5550f66f451Sopenharmony_ci    }
5560f66f451Sopenharmony_ci  } else TT.snd_sock = xsocket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
5570f66f451Sopenharmony_ci
5580f66f451Sopenharmony_ci  if (setsockopt(TT.snd_sock, SOL_SOCKET, SO_SNDBUF, &TT.msg_len,
5590f66f451Sopenharmony_ci        sizeof(TT.msg_len)) < 0) perror_exit("SO_SNDBUF failed ");
5600f66f451Sopenharmony_ci
5610f66f451Sopenharmony_ci  if (!TT.istraceroute6) {
5620f66f451Sopenharmony_ci    if ((toys.optflags & FLAG_t) &&
5630f66f451Sopenharmony_ci        setsockopt(TT.snd_sock, IPPROTO_IP, IP_TOS, &tyser, sizeof(tyser)) < 0)
5640f66f451Sopenharmony_ci      perror_exit("IP_TOS %ld failed ", TT.tos);
5650f66f451Sopenharmony_ci
5660f66f451Sopenharmony_ci#ifdef IP_DONTFRAG
5670f66f451Sopenharmony_ci    if ((toys.optflags & FLAG_F) &&
5680f66f451Sopenharmony_ci        (setsockopt(TT.snd_sock, IPPROTO_IP, IP_DONTFRAG, &set,
5690f66f451Sopenharmony_ci                    sizeof(set)) < 0)) perror_exit("IP_DONTFRAG failed ");
5700f66f451Sopenharmony_ci#endif
5710f66f451Sopenharmony_ci  } else if (setsockopt(TT.snd_sock, IPPROTO_IPV6, IPV6_TCLASS, &TT.tos,
5720f66f451Sopenharmony_ci        sizeof(TT.tos)) < 0) perror_exit("IPV6_TCLASS %ld failed ", TT.tos);
5730f66f451Sopenharmony_ci
5740f66f451Sopenharmony_ci  set_flag_dr(TT.snd_sock);
5750f66f451Sopenharmony_ci  TT.packet = xzalloc(TT.msg_len);
5760f66f451Sopenharmony_ci  TT.ident = getpid();
5770f66f451Sopenharmony_ci
5780f66f451Sopenharmony_ci  if (!TT.istraceroute6) {
5790f66f451Sopenharmony_ci    if (!(toys.optflags & FLAG_U)) TT.ident |= 0x8000;
5800f66f451Sopenharmony_ci    if (toys.optflags & FLAG_s) {
5810f66f451Sopenharmony_ci      struct sockaddr_in source;
5820f66f451Sopenharmony_ci
5830f66f451Sopenharmony_ci      memset(&source, 0, sizeof(source));
5840f66f451Sopenharmony_ci      if (!inet_aton(TT.src_ip, &(source.sin_addr)))
5850f66f451Sopenharmony_ci        error_exit("bad address: %s", TT.src_ip);
5860f66f451Sopenharmony_ci      if (setsockopt(TT.snd_sock, IPPROTO_IP, IP_MULTICAST_IF,
5870f66f451Sopenharmony_ci            (struct sockaddr*)&source, sizeof(struct sockaddr_in)))
5880f66f451Sopenharmony_ci        perror_exit("can't set multicast source interface");
5890f66f451Sopenharmony_ci      xbind(TT.snd_sock,(struct sockaddr*)&source, sizeof(struct sockaddr_in));
5900f66f451Sopenharmony_ci    }
5910f66f451Sopenharmony_ci
5920f66f451Sopenharmony_ci    if(TT.first_ttl > TT.max_ttl)
5930f66f451Sopenharmony_ci      error_exit("ERROR :Range for -f is 1 to %ld (max ttl)", TT.max_ttl);
5940f66f451Sopenharmony_ci
5950f66f451Sopenharmony_ci    xprintf("traceroute to %s(%s)", toys.optargs[0],
5960f66f451Sopenharmony_ci           inet_ntoa(((struct sockaddr_in *)&dest)->sin_addr));
5970f66f451Sopenharmony_ci  } else {
5980f66f451Sopenharmony_ci    if (toys.optflags & FLAG_i) bind_to_interface(TT.snd_sock);
5990f66f451Sopenharmony_ci
6000f66f451Sopenharmony_ci    resolve_addr(toys.optargs[0], AF_INET6, SOCK_DGRAM, IPPROTO_UDP, &dest);
6010f66f451Sopenharmony_ci    if (toys.optflags & FLAG_s) {
6020f66f451Sopenharmony_ci      struct sockaddr_in6 source;
6030f66f451Sopenharmony_ci
6040f66f451Sopenharmony_ci      memset(&source, 0, sizeof(source));
6050f66f451Sopenharmony_ci      if(inet_pton(AF_INET6, TT.src_ip, &(source.sin6_addr)) <= 0)
6060f66f451Sopenharmony_ci        error_exit("bad address: %s", TT.src_ip);
6070f66f451Sopenharmony_ci
6080f66f451Sopenharmony_ci      xbind(TT.snd_sock,(struct sockaddr*)&source, sizeof(struct sockaddr_in6));
6090f66f451Sopenharmony_ci    } else {
6100f66f451Sopenharmony_ci      struct sockaddr_in6 prb;
6110f66f451Sopenharmony_ci      socklen_t len = sizeof(prb);
6120f66f451Sopenharmony_ci      int p_fd = xsocket(AF_INET6, SOCK_DGRAM, 0);
6130f66f451Sopenharmony_ci      if (toys.optflags & FLAG_i) bind_to_interface(p_fd);
6140f66f451Sopenharmony_ci
6150f66f451Sopenharmony_ci      ((struct sockaddr_in6 *)&dest)->sin6_port = htons(1025);
6160f66f451Sopenharmony_ci      xconnect(p_fd, (struct sockaddr *)&dest, sizeof(struct sockaddr_in6));
6170f66f451Sopenharmony_ci      if(getsockname(p_fd, (struct sockaddr *)&prb, &len))
6180f66f451Sopenharmony_ci        error_exit("probe addr failed");
6190f66f451Sopenharmony_ci      close(p_fd);
6200f66f451Sopenharmony_ci      prb.sin6_port = 0;
6210f66f451Sopenharmony_ci      xbind(TT.snd_sock, (struct sockaddr*)&prb, sizeof(struct sockaddr_in6));
6220f66f451Sopenharmony_ci      xbind(TT.recv_sock, (struct sockaddr*)&prb, sizeof(struct sockaddr_in6));
6230f66f451Sopenharmony_ci    }
6240f66f451Sopenharmony_ci
6250f66f451Sopenharmony_ci    inet_ntop(AF_INET6, &((struct sockaddr_in6 *)&dest)->sin6_addr,
6260f66f451Sopenharmony_ci              addr_str, INET6_ADDRSTRLEN);
6270f66f451Sopenharmony_ci    xprintf("traceroute6 to %s(%s)", toys.optargs[0], addr_str);
6280f66f451Sopenharmony_ci  }
6290f66f451Sopenharmony_ci
6300f66f451Sopenharmony_ci  if (toys.optflags & FLAG_s) xprintf(" from %s",TT.src_ip);
6310f66f451Sopenharmony_ci  xprintf(", %ld hops max, %u byte packets\n", TT.max_ttl, TT.msg_len);
6320f66f451Sopenharmony_ci
6330f66f451Sopenharmony_ci  do_trace();
6340f66f451Sopenharmony_ci}
635