1 /* traceroute - trace the route to "host". 2 * 3 * Copyright 2012 Madhur Verma <mad.flexi (at) gmail.com> 4 * Copyright 2013 Kyungwan Han <asura321 (at) gmail.com> 5 * Copyright 2013 Bilal Qureshi <bilal.jmi (at) gmail.com> 6 * Copyright 2013 Ashwini Kumar <ak.ashwini1981 (at) 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 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) 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) 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 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 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 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 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 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