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