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