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 milisec (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 unsigned 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