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)) msleep(TT.pause_time);
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 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  } else TT.first_ttl = 1;
503
504  TT.msg_len = pack_size = ICMP_HD_SIZE4; //udp payload is also 8bytes
505  if (toys.optargs[1])
506    TT.msg_len = atolx_range(toys.optargs[1], pack_size, 32768);//max packet size
507
508  TT.recv_sock = xsocket((TT.istraceroute6 ? AF_INET6 : AF_INET), SOCK_RAW,
509      (TT.istraceroute6 ? IPPROTO_ICMPV6 : IPPROTO_ICMP));
510
511  if (TT.istraceroute6) {
512    int two = 2;
513#ifdef IPV6_RECVPKTINFO
514    setsockopt(TT.recv_sock, SOL_IPV6, IPV6_RECVPKTINFO, &set,
515        sizeof(set));
516    setsockopt(TT.recv_sock, SOL_IPV6, IPV6_2292PKTINFO, &set,
517        sizeof(set));
518#else
519    setsockopt(TT.recv_sock, SOL_IPV6, IPV6_PKTINFO, &set, sizeof(set));
520#endif
521
522    if (setsockopt(TT.recv_sock, SOL_RAW, IPV6_CHECKSUM, &two,
523          sizeof(two)) < 0)  perror_exit("setsockopt RAW_CHECKSUM");
524  }
525
526  set_flag_dr(TT.recv_sock);
527
528  if (!TT.istraceroute6) {
529    if (toys.optflags & FLAG_U)
530      TT.snd_sock = xsocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
531    else TT.snd_sock = xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
532
533    if (toys.optflags & FLAG_i) bind_to_interface(TT.snd_sock);
534
535    resolve_addr(toys.optargs[0], AF_INET, ((toys.optflags & FLAG_U) ?
536          SOCK_DGRAM : SOCK_RAW), ((toys.optflags & FLAG_U) ? IPPROTO_UDP :
537            IPPROTO_ICMP), &dest);
538    if (lsrr > 0) {
539      unsigned char optlist[MAX_IPOPTLEN];
540      unsigned size;
541
542      TT.gw_list[lsrr] = ((struct sockaddr_in *)&dest)->sin_addr.s_addr;
543      ++lsrr;
544
545      optlist[0] = IPOPT_NOP;
546      optlist[1] = IPOPT_LSRR;// loose source route option
547      size = lsrr * sizeof(TT.gw_list[0]);
548      optlist[2] = size + 3;
549      optlist[3] = IPOPT_MINOFF;
550      memcpy(optlist + 4, TT.gw_list, size);
551
552      if (setsockopt(TT.snd_sock, IPPROTO_IP, IP_OPTIONS,
553            (char *)optlist, size + sizeof(TT.gw_list[0])) < 0)
554        perror_exit("LSRR IP_OPTIONS");
555    }
556  } else TT.snd_sock = xsocket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
557
558  if (setsockopt(TT.snd_sock, SOL_SOCKET, SO_SNDBUF, &TT.msg_len,
559        sizeof(TT.msg_len)) < 0) perror_exit("SO_SNDBUF failed ");
560
561  if (!TT.istraceroute6) {
562    if ((toys.optflags & FLAG_t) &&
563        setsockopt(TT.snd_sock, IPPROTO_IP, IP_TOS, &tyser, sizeof(tyser)) < 0)
564      perror_exit("IP_TOS %ld failed ", TT.tos);
565
566#ifdef IP_DONTFRAG
567    if ((toys.optflags & FLAG_F) &&
568        (setsockopt(TT.snd_sock, IPPROTO_IP, IP_DONTFRAG, &set,
569                    sizeof(set)) < 0)) perror_exit("IP_DONTFRAG failed ");
570#endif
571  } else if (setsockopt(TT.snd_sock, IPPROTO_IPV6, IPV6_TCLASS, &TT.tos,
572        sizeof(TT.tos)) < 0) perror_exit("IPV6_TCLASS %ld failed ", TT.tos);
573
574  set_flag_dr(TT.snd_sock);
575  TT.packet = xzalloc(TT.msg_len);
576  TT.ident = getpid();
577
578  if (!TT.istraceroute6) {
579    if (!(toys.optflags & FLAG_U)) TT.ident |= 0x8000;
580    if (toys.optflags & FLAG_s) {
581      struct sockaddr_in source;
582
583      memset(&source, 0, sizeof(source));
584      if (!inet_aton(TT.src_ip, &(source.sin_addr)))
585        error_exit("bad address: %s", TT.src_ip);
586      if (setsockopt(TT.snd_sock, IPPROTO_IP, IP_MULTICAST_IF,
587            (struct sockaddr*)&source, sizeof(struct sockaddr_in)))
588        perror_exit("can't set multicast source interface");
589      xbind(TT.snd_sock,(struct sockaddr*)&source, sizeof(struct sockaddr_in));
590    }
591
592    if(TT.first_ttl > TT.max_ttl)
593      error_exit("ERROR :Range for -f is 1 to %ld (max ttl)", TT.max_ttl);
594
595    xprintf("traceroute to %s(%s)", toys.optargs[0],
596           inet_ntoa(((struct sockaddr_in *)&dest)->sin_addr));
597  } else {
598    if (toys.optflags & FLAG_i) bind_to_interface(TT.snd_sock);
599
600    resolve_addr(toys.optargs[0], AF_INET6, SOCK_DGRAM, IPPROTO_UDP, &dest);
601    if (toys.optflags & FLAG_s) {
602      struct sockaddr_in6 source;
603
604      memset(&source, 0, sizeof(source));
605      if(inet_pton(AF_INET6, TT.src_ip, &(source.sin6_addr)) <= 0)
606        error_exit("bad address: %s", TT.src_ip);
607
608      xbind(TT.snd_sock,(struct sockaddr*)&source, sizeof(struct sockaddr_in6));
609    } else {
610      struct sockaddr_in6 prb;
611      socklen_t len = sizeof(prb);
612      int p_fd = xsocket(AF_INET6, SOCK_DGRAM, 0);
613      if (toys.optflags & FLAG_i) bind_to_interface(p_fd);
614
615      ((struct sockaddr_in6 *)&dest)->sin6_port = htons(1025);
616      xconnect(p_fd, (struct sockaddr *)&dest, sizeof(struct sockaddr_in6));
617      if(getsockname(p_fd, (struct sockaddr *)&prb, &len))
618        error_exit("probe addr failed");
619      close(p_fd);
620      prb.sin6_port = 0;
621      xbind(TT.snd_sock, (struct sockaddr*)&prb, sizeof(struct sockaddr_in6));
622      xbind(TT.recv_sock, (struct sockaddr*)&prb, sizeof(struct sockaddr_in6));
623    }
624
625    inet_ntop(AF_INET6, &((struct sockaddr_in6 *)&dest)->sin6_addr,
626              addr_str, INET6_ADDRSTRLEN);
627    xprintf("traceroute6 to %s(%s)", toys.optargs[0], addr_str);
628  }
629
630  if (toys.optflags & FLAG_s) xprintf(" from %s",TT.src_ip);
631  xprintf(", %ld hops max, %u byte packets\n", TT.max_ttl, TT.msg_len);
632
633  do_trace();
634}
635