Changeset 2725 in MondoRescue for branches/2.2.9/mindi-busybox/networking/traceroute.c
- Timestamp:
- Feb 25, 2011, 9:26:54 PM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/2.2.9/mindi-busybox/networking/traceroute.c
r1765 r2725 23 23 */ 24 24 25 //#define version "1.4a12" 26 25 /* 26 * traceroute6 27 * 28 * Modified for NRL 4.4BSD IPv6 release. 29 * 07/31/96 bgp 30 * 31 * Modified for Linux IPv6 by Pedro Roque <roque@di.fc.ul.pt> 32 * 31/07/1996 33 * 34 * As ICMP error messages for IPv6 now include more than 8 bytes 35 * UDP datagrams are now sent via an UDP socket instead of magic 36 * RAW socket tricks. 37 * 38 * Converted to busybox applet by Leonid Lisovskiy <lly@sf.net> 39 * 2009-11-16 40 */ 27 41 28 42 /* … … 215 229 #include <netinet/ip.h> 216 230 #include <netinet/ip_icmp.h> 231 #if ENABLE_FEATURE_IPV6 232 # include <netinet/ip6.h> 233 # include <netinet/icmp6.h> 234 # ifndef SOL_IPV6 235 # define SOL_IPV6 IPPROTO_IPV6 236 # endif 237 #endif 217 238 218 239 #include "libbb.h" 219 240 #include "inet_common.h" 220 241 221 222 /*223 * Definitions for internet protocol version 4.224 * Per RFC 791, September 1981.225 */226 #define IPVERSION 4227 228 242 #ifndef IPPROTO_ICMP 229 /* Grrrr.... */ 230 #define IPPROTO_ICMP 1 243 # define IPPROTO_ICMP 1 231 244 #endif 232 245 #ifndef IPPROTO_IP 233 #define IPPROTO_IP 0 234 #endif 235 236 /* 237 * Overlay for ip header used by other protocols (tcp, udp). 238 */ 239 struct ipovly { 240 unsigned char ih_x1[9]; /* (unused) */ 241 unsigned char ih_pr; /* protocol */ 242 short ih_len; /* protocol length */ 243 struct in_addr ih_src; /* source internet address */ 244 struct in_addr ih_dst; /* destination internet address */ 246 # define IPPROTO_IP 0 247 #endif 248 249 250 #define OPT_STRING "FIlnrdvxt:i:m:p:q:s:w:z:f:" \ 251 IF_FEATURE_TRACEROUTE_SOURCE_ROUTE("g:") \ 252 "4" IF_TRACEROUTE6("6") 253 enum { 254 OPT_DONT_FRAGMNT = (1 << 0), /* F */ 255 OPT_USE_ICMP = (1 << 1) * ENABLE_FEATURE_TRACEROUTE_USE_ICMP, /* I */ 256 OPT_TTL_FLAG = (1 << 2), /* l */ 257 OPT_ADDR_NUM = (1 << 3), /* n */ 258 OPT_BYPASS_ROUTE = (1 << 4), /* r */ 259 OPT_DEBUG = (1 << 5), /* d */ 260 OPT_VERBOSE = (1 << 6) * ENABLE_FEATURE_TRACEROUTE_VERBOSE, /* v */ 261 OPT_IP_CHKSUM = (1 << 7), /* x */ 262 OPT_TOS = (1 << 8), /* t */ 263 OPT_DEVICE = (1 << 9), /* i */ 264 OPT_MAX_TTL = (1 << 10), /* m */ 265 OPT_PORT = (1 << 11), /* p */ 266 OPT_NPROBES = (1 << 12), /* q */ 267 OPT_SOURCE = (1 << 13), /* s */ 268 OPT_WAITTIME = (1 << 14), /* w */ 269 OPT_PAUSE_MS = (1 << 15), /* z */ 270 OPT_FIRST_TTL = (1 << 16), /* f */ 271 OPT_SOURCE_ROUTE = (1 << 17) * ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE, /* g */ 272 OPT_IPV4 = (1 << (17+ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE)), /* 4 */ 273 OPT_IPV6 = (1 << (18+ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE)) * ENABLE_TRACEROUTE6, /* 6 */ 245 274 }; 246 247 /* 248 * UDP kernel structures and variables. 249 */ 250 struct udpiphdr { 251 struct ipovly ui_i; /* overlaid ip structure */ 252 struct udphdr ui_u; /* udp header */ 275 #define verbose (option_mask32 & OPT_VERBOSE) 276 277 enum { 278 SIZEOF_ICMP_HDR = 8, 279 rcvsock = 3, /* receive (icmp) socket file descriptor */ 280 sndsock = 4, /* send (udp/icmp) socket file descriptor */ 253 281 }; 254 #define ui_next ui_i.ih_next255 #define ui_prev ui_i.ih_prev256 #define ui_x1 ui_i.ih_x1257 #define ui_pr ui_i.ih_pr258 #define ui_len ui_i.ih_len259 #define ui_src ui_i.ih_src260 #define ui_dst ui_i.ih_dst261 #define ui_sport ui_u.uh_sport262 #define ui_dport ui_u.uh_dport263 #define ui_ulen ui_u.uh_ulen264 #define ui_sum ui_u.uh_sum265 266 267 /* Host name and address list */268 struct hostinfo {269 char *name;270 int n;271 uint32_t *addrs;272 };273 282 274 283 /* Data section of the probe packet */ 275 struct outdata {284 struct outdata_t { 276 285 unsigned char seq; /* sequence number of this packet */ 277 286 unsigned char ttl; /* ttl packet left with */ 278 287 // UNUSED. Retaining to have the same packet size. 279 struct timeval tv_UNUSED ATTRIBUTE_PACKED; /* time packet left */288 struct timeval tv_UNUSED PACKED; /* time packet left */ 280 289 }; 281 290 282 struct IFADDRLIST { 283 uint32_t addr; 284 char device[sizeof(struct ifreq)]; 291 #if ENABLE_TRACEROUTE6 292 struct outdata6_t { 293 uint32_t ident6; 294 uint32_t seq6; 295 struct timeval tv_UNUSED PACKED; /* time packet left */ 285 296 }; 286 287 288 static struct ip *outip; /* last output (udp) packet */ 289 static struct udphdr *outudp; /* last output (udp) packet */ 290 static struct outdata *outdata; /* last output (udp) packet */ 291 292 #if ENABLE_FEATURE_TRACEROUTE_USE_ICMP 293 static struct icmp *outicmp; /* last output (icmp) packet */ 294 #endif 295 296 static int s; /* receive (icmp) socket file descriptor */ 297 static int sndsock; /* send (udp/icmp) socket file descriptor */ 298 299 static int packlen; /* total length of packet */ 300 static int minpacket; /* min ip packet size */ 301 static int maxpacket = 32 * 1024; /* max ip packet size */ 302 static int pmtu; /* Path MTU Discovery (RFC1191) */ 303 304 static char *hostname; 305 306 static uint16_t ident; 307 static uint16_t port = 32768 + 666; /* start udp dest port # for probe packets */ 308 309 static int waittime = 5; /* time to wait for response (in seconds) */ 310 static int doipcksum = 1; /* calculate ip checksums by default */ 311 297 #endif 298 299 struct globals { 300 struct ip *outip; 301 struct outdata_t *outdata; 302 len_and_sockaddr *dest_lsa; 303 int packlen; /* total length of packet */ 304 int pmtu; /* Path MTU Discovery (RFC1191) */ 305 uint32_t ident; 306 uint16_t port; // 32768 + 666; /* start udp dest port # for probe packets */ 307 int waittime; // 5; /* time to wait for response (in seconds) */ 312 308 #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE 313 staticint optlen; /* length of ip options */309 int optlen; /* length of ip options */ 314 310 #else 315 311 #define optlen 0 316 312 #endif 317 318 319 /* Keep in sync with getopt32 call! */ 320 #define OPT_DONT_FRAGMNT (1<<0) /* F */ 321 #define OPT_USE_ICMP (1<<1) /* I */ 322 #define OPT_TTL_FLAG (1<<2) /* l */ 323 #define OPT_ADDR_NUM (1<<3) /* n */ 324 #define OPT_BYPASS_ROUTE (1<<4) /* r */ 325 #define OPT_DEBUG (1<<5) /* d */ 326 #define OPT_VERBOSE (1<<6) /* v */ 327 #define OPT_IP_CHKSUM (1<<7) /* x */ 328 #define OPT_TOS (1<<8) /* t */ 329 #define OPT_DEVICE (1<<9) /* i */ 330 #define OPT_MAX_TTL (1<<10) /* m */ 331 #define OPT_PORT (1<<11) /* p */ 332 #define OPT_NPROBES (1<<12) /* q */ 333 #define OPT_SOURCE (1<<13) /* s */ 334 #define OPT_WAITTIME (1<<14) /* w */ 335 #define OPT_PAUSE_MS (1<<15) /* z */ 336 #define OPT_FIRST_TTL (1<<16) /* f */ 337 338 #if ENABLE_FEATURE_TRACEROUTE_USE_ICMP 339 /* use icmp echo instead of udp packets */ 340 #define useicmp (option_mask32 & OPT_USE_ICMP) 341 #endif 342 #if ENABLE_FEATURE_TRACEROUTE_VERBOSE 343 #define verbose (option_mask32 & OPT_VERBOSE) 344 #endif 345 #define nflag (option_mask32 & OPT_ADDR_NUM) 346 347 348 struct globals { 349 /* last inbound (icmp) packet */ 350 unsigned char packet[512]; 351 struct sockaddr_storage whereto; /* Who to try to reach */ 352 struct sockaddr_storage wherefrom; /* Who we are */ 313 unsigned char recv_pkt[512]; /* last inbound (icmp) packet */ 353 314 #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE 354 315 /* Maximum number of gateways (include room for one noop) */ … … 360 321 361 322 #define G (*ptr_to_globals) 362 363 #define packet (G.packet ) 364 #define whereto (G.whereto ) 365 #define wherefrom (G.wherefrom) 323 #define outip (G.outip ) 324 #define outdata (G.outdata ) 325 #define dest_lsa (G.dest_lsa ) 326 #define packlen (G.packlen ) 327 #define pmtu (G.pmtu ) 328 #define ident (G.ident ) 329 #define port (G.port ) 330 #define waittime (G.waittime ) 331 #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE 332 # define optlen (G.optlen ) 333 #endif 334 #define recv_pkt (G.recv_pkt ) 366 335 #define gwlist (G.gwlist ) 367 368 369 /* 370 * Return the interface list 371 */ 336 #define INIT_G() do { \ 337 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ 338 port = 32768 + 666; \ 339 waittime = 5; \ 340 } while (0) 341 342 #define outicmp ((struct icmp *)(outip + 1)) 343 #define outudp ((struct udphdr *)(outip + 1)) 344 345 346 /* libbb candidate? tftp uses this idiom too */ 347 static len_and_sockaddr* dup_sockaddr(const len_and_sockaddr *lsa) 348 { 349 len_and_sockaddr *new_lsa = xzalloc(LSA_LEN_SIZE + lsa->len); 350 memcpy(new_lsa, lsa, LSA_LEN_SIZE + lsa->len); 351 return new_lsa; 352 } 353 354 372 355 static int 373 ifaddrlist(struct IFADDRLIST **ipaddrp) 374 { 375 enum { IFREQ_BUFSIZE = (32 * 1024) / sizeof(struct ifreq) }; 376 377 int fd, nipaddr; 378 #ifdef HAVE_SOCKADDR_SA_LEN 379 int n; 380 #endif 381 struct ifreq *ifrp, *ifend, *ifnext; 382 struct sockaddr_in *addr_sin; 383 struct IFADDRLIST *al; 384 struct ifconf ifc; 385 struct ifreq ifr; 386 /* Was on stack, but 32k is a bit too much: */ 387 struct ifreq *ibuf = xmalloc(IFREQ_BUFSIZE * sizeof(ibuf[0])); 388 struct IFADDRLIST *st_ifaddrlist; 389 390 fd = xsocket(AF_INET, SOCK_DGRAM, 0); 391 392 ifc.ifc_len = IFREQ_BUFSIZE * sizeof(ibuf[0]); 393 ifc.ifc_buf = (caddr_t)ibuf; 394 395 if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 396 || ifc.ifc_len < sizeof(struct ifreq) 397 ) { 398 if (errno == EINVAL) 399 bb_error_msg_and_die( 400 "SIOCGIFCONF: ifreq struct too small (%u bytes)", 401 (unsigned)(IFREQ_BUFSIZE * sizeof(ibuf[0]))); 402 bb_perror_msg_and_die("SIOCGIFCONF"); 403 } 404 ifrp = ibuf; 405 ifend = (struct ifreq *)((char *)ibuf + ifc.ifc_len); 406 407 nipaddr = 1 + (ifc.ifc_len / sizeof(struct ifreq)); 408 st_ifaddrlist = xzalloc(nipaddr * sizeof(struct IFADDRLIST)); 409 al = st_ifaddrlist; 410 nipaddr = 0; 411 412 for (; ifrp < ifend; ifrp = ifnext) { 413 #ifdef HAVE_SOCKADDR_SA_LEN 414 n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name); 415 if (n < sizeof(*ifrp)) 416 ifnext = ifrp + 1; 417 else 418 ifnext = (struct ifreq *)((char *)ifrp + n); 419 if (ifrp->ifr_addr.sa_family != AF_INET) 420 continue; 421 #else 422 ifnext = ifrp + 1; 423 #endif 424 /* 425 * Need a template to preserve address info that is 426 * used below to locate the next entry. (Otherwise, 427 * SIOCGIFFLAGS stomps over it because the requests 428 * are returned in a union.) 429 */ 430 strncpy(ifr.ifr_name, ifrp->ifr_name, sizeof(ifr.ifr_name)); 431 if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifr) < 0) { 432 if (errno == ENXIO) 433 continue; 434 bb_perror_msg_and_die("SIOCGIFFLAGS: %.*s", 435 (int)sizeof(ifr.ifr_name), ifr.ifr_name); 436 } 437 438 /* Must be up */ 439 if ((ifr.ifr_flags & IFF_UP) == 0) 440 continue; 441 442 safe_strncpy(al->device, ifr.ifr_name, sizeof(ifr.ifr_name) + 1); 443 #ifdef sun 444 /* Ignore sun virtual interfaces */ 445 if (strchr(al->device, ':') != NULL) 446 continue; 447 #endif 448 ioctl_or_perror_and_die(fd, SIOCGIFADDR, (char *)&ifr, 449 "SIOCGIFADDR: %s", al->device); 450 451 addr_sin = (struct sockaddr_in *)&ifr.ifr_addr; 452 al->addr = addr_sin->sin_addr.s_addr; 453 ++al; 454 ++nipaddr; 455 } 456 if (nipaddr == 0) 457 bb_error_msg_and_die("can't find any network interfaces"); 458 459 free(ibuf); 460 close(fd); 461 *ipaddrp = st_ifaddrlist; 462 return nipaddr; 463 } 464 465 466 static void 467 setsin(struct sockaddr_in *addr_sin, uint32_t addr) 468 { 469 memset(addr_sin, 0, sizeof(*addr_sin)); 470 #ifdef HAVE_SOCKADDR_SA_LEN 471 addr_sin->sin_len = sizeof(*addr_sin); 472 #endif 473 addr_sin->sin_family = AF_INET; 474 addr_sin->sin_addr.s_addr = addr; 475 } 476 477 478 /* 479 * Return the source address for the given destination address 480 */ 481 static void 482 findsaddr(const struct sockaddr_in *to, struct sockaddr_in *from) 483 { 484 int i, n; 485 FILE *f; 486 uint32_t mask; 487 uint32_t dest, tmask; 488 struct IFADDRLIST *al; 489 char buf[256], tdevice[256], device[256]; 490 491 f = xfopen("/proc/net/route", "r"); 492 493 /* Find the appropriate interface */ 494 n = 0; 495 mask = 0; 496 device[0] = '\0'; 497 while (fgets(buf, sizeof(buf), f) != NULL) { 498 ++n; 499 if (n == 1 && strncmp(buf, "Iface", 5) == 0) 500 continue; 501 i = sscanf(buf, "%255s %x %*s %*s %*s %*s %*s %x", 502 tdevice, &dest, &tmask); 503 if (i != 3) 504 bb_error_msg_and_die("junk in buffer"); 505 if ((to->sin_addr.s_addr & tmask) == dest 506 && (tmask > mask || mask == 0) 507 ) { 508 mask = tmask; 509 strcpy(device, tdevice); 510 } 511 } 512 fclose(f); 513 514 if (device[0] == '\0') 515 bb_error_msg_and_die("can't find interface"); 516 517 /* Get the interface address list */ 518 n = ifaddrlist(&al); 519 520 /* Find our appropriate source address */ 521 for (i = n; i > 0; --i, ++al) 522 if (strcmp(device, al->device) == 0) 523 break; 524 if (i <= 0) 525 bb_error_msg_and_die("can't find interface %s", device); 526 527 setsin(from, al->addr); 528 } 529 530 /* 531 "Usage: %s [-dFIlnrvx] [-g gateway] [-i iface] [-f first_ttl]\n" 532 "\t[-m max_ttl] [ -p port] [-q nqueries] [-s src_addr] [-t tos]\n" 533 "\t[-w waittime] [-z pausemsecs] host [packetlen]" 534 535 */ 536 537 static int 538 wait_for_reply(int sock, struct sockaddr_in *fromp) 539 { 540 fd_set fds; 541 struct timeval tvwait; 542 int cc = 0; 543 socklen_t fromlen = sizeof(*fromp); 544 545 FD_ZERO(&fds); 546 FD_SET(sock, &fds); 547 548 tvwait.tv_sec = waittime; 549 tvwait.tv_usec = 0; 550 551 if (select(sock + 1, &fds, NULL, NULL, &tvwait) > 0) 552 cc = recvfrom(sock, (char *)packet, sizeof(packet), 0, 553 (struct sockaddr *)fromp, &fromlen); 554 555 return cc; 356 wait_for_reply(len_and_sockaddr *from_lsa, struct sockaddr *to) 357 { 358 struct pollfd pfd[1]; 359 int read_len = 0; 360 361 pfd[0].fd = rcvsock; 362 pfd[0].events = POLLIN; 363 if (safe_poll(pfd, 1, waittime * 1000) > 0) { 364 read_len = recv_from_to(rcvsock, 365 recv_pkt, sizeof(recv_pkt), 366 /*flags:*/ 0, 367 &from_lsa->u.sa, to, from_lsa->len); 368 } 369 370 return read_len; 556 371 } 557 372 … … 568 383 569 384 /* 570 * 571 * 572 * 573 * 385 * Our algorithm is simple, using a 32 bit accumulator (sum), 386 * we add sequential 16 bit words to it, and at the end, fold 387 * back all the carry bits from the top 16 bits into the lower 388 * 16 bits. 574 389 */ 575 while (nleft > 1) 390 while (nleft > 1) { 576 391 sum += *w++; 577 392 nleft -= 2; … … 582 397 sum += *(unsigned char *)w; 583 398 584 /* 585 * add back carry outs from top 16 bits to low 16 bits 586 */ 399 /* add back carry outs from top 16 bits to low 16 bits */ 587 400 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ 588 401 sum += (sum >> 16); /* add carry */ … … 591 404 } 592 405 593 594 406 static void 595 407 send_probe(int seq, int ttl) 596 408 { 597 int cc; 598 struct udpiphdr *ui, *oui; 599 struct ip tip; 600 601 outip->ip_ttl = ttl; 602 outip->ip_id = htons(ident + seq); 603 604 /* 605 * In most cases, the kernel will recalculate the ip checksum. 606 * But we must do it anyway so that the udp checksum comes out 607 * right. 608 */ 609 if (doipcksum) { 610 outip->ip_sum = 611 in_cksum((uint16_t *)outip, sizeof(*outip) + optlen); 612 if (outip->ip_sum == 0) 613 outip->ip_sum = 0xffff; 614 } 409 int len, res; 410 void *out; 615 411 616 412 /* Payload */ 617 outdata->seq = seq; 618 outdata->ttl = ttl; 413 #if ENABLE_TRACEROUTE6 414 if (dest_lsa->u.sa.sa_family == AF_INET6) { 415 struct outdata6_t *pkt = (struct outdata6_t *) outip; 416 pkt->ident6 = htonl(ident); 417 pkt->seq6 = htonl(seq); 418 /*gettimeofday(&pkt->tv, &tz);*/ 419 } else 420 #endif 421 { 422 outdata->seq = seq; 423 outdata->ttl = ttl; 619 424 // UNUSED: was storing gettimeofday's result there, but never ever checked it 620 /*memcpy(&outdata->tv, tp, sizeof(outdata->tv));*/ 621 622 #if ENABLE_FEATURE_TRACEROUTE_USE_ICMP 623 if (useicmp) 624 outicmp->icmp_seq = htons(seq); 625 else 626 #endif 627 outudp->dest = htons(port + seq); 628 629 #if ENABLE_FEATURE_TRACEROUTE_USE_ICMP 630 if (useicmp) { 631 /* Always calculate checksum for icmp packets */ 632 outicmp->icmp_cksum = 0; 633 outicmp->icmp_cksum = in_cksum((uint16_t *)outicmp, 634 packlen - (sizeof(*outip) + optlen)); 635 if (outicmp->icmp_cksum == 0) 636 outicmp->icmp_cksum = 0xffff; 637 } else 638 #endif 639 if (doipcksum) { 640 /* Checksum (we must save and restore ip header) */ 641 tip = *outip; 642 ui = (struct udpiphdr *)outip; 643 oui = (struct udpiphdr *)&tip; 644 /* Easier to zero and put back things that are ok */ 645 memset((char *)ui, 0, sizeof(ui->ui_i)); 646 ui->ui_src = oui->ui_src; 647 ui->ui_dst = oui->ui_dst; 648 ui->ui_pr = oui->ui_pr; 649 ui->ui_len = outudp->len; 650 outudp->check = 0; 651 outudp->check = in_cksum((uint16_t *)ui, packlen); 652 if (outudp->check == 0) 653 outudp->check = 0xffff; 654 *outip = tip; 655 } 656 657 #if ENABLE_FEATURE_TRACEROUTE_VERBOSE 425 /*memcpy(&outdata->tv, tp, sizeof(outdata->tv));*/ 426 427 if (option_mask32 & OPT_USE_ICMP) { 428 outicmp->icmp_seq = htons(seq); 429 430 /* Always calculate checksum for icmp packets */ 431 outicmp->icmp_cksum = 0; 432 outicmp->icmp_cksum = in_cksum((uint16_t *)outicmp, 433 packlen - (sizeof(*outip) + optlen)); 434 if (outicmp->icmp_cksum == 0) 435 outicmp->icmp_cksum = 0xffff; 436 } 437 } 438 439 //BUG! verbose is (x & OPT_VERBOSE), not a counter! 440 #if 0 //ENABLE_FEATURE_TRACEROUTE_VERBOSE 658 441 /* XXX undocumented debugging hack */ 659 442 if (verbose > 1) { … … 680 463 #endif 681 464 682 #if !defined(IP_HDRINCL) && defined(IP_TTL) 683 if (setsockopt(sndsock, IPPROTO_IP, IP_TTL, 684 (char *)&ttl, sizeof(ttl)) < 0) { 685 bb_perror_msg_and_die("setsockopt ttl %d", ttl); 686 } 687 #endif 688 689 cc = xsendto(sndsock, (char *)outip, 690 packlen, (struct sockaddr *)&whereto, sizeof(whereto)); 691 if (cc != packlen) { 692 bb_info_msg("wrote %s %d chars, ret=%d", hostname, packlen, cc); 693 } 465 #if ENABLE_TRACEROUTE6 466 if (dest_lsa->u.sa.sa_family == AF_INET6) { 467 res = setsockopt(sndsock, SOL_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)); 468 if (res < 0) 469 bb_perror_msg_and_die("setsockopt UNICAST_HOPS %d", ttl); 470 out = outip; 471 len = packlen; 472 } else 473 #endif 474 { 475 #if defined IP_TTL 476 res = setsockopt(sndsock, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)); 477 if (res < 0) 478 bb_perror_msg_and_die("setsockopt ttl %d", ttl); 479 #endif 480 out = outicmp; 481 len = packlen - sizeof(*outip); 482 if (!(option_mask32 & OPT_USE_ICMP)) { 483 out = outdata; 484 len -= sizeof(*outudp); 485 set_nport(dest_lsa, htons(port + seq)); 486 } 487 } 488 489 res = xsendto(sndsock, out, len, &dest_lsa->u.sa, dest_lsa->len); 490 if (res != len) 491 bb_info_msg("sent %d octets, ret=%d", len, res); 694 492 } 695 493 … … 698 496 * Convert an ICMP "type" field to a printable string. 699 497 */ 700 static inlineconst char *498 static const char * 701 499 pr_type(unsigned char t) 702 500 { … … 708 506 "Info Reply", "Mask Request", "Mask Reply" 709 507 }; 710 711 if (t > 18) 508 # if ENABLE_TRACEROUTE6 509 static const char *const ttab6[] = { 510 [0] "Error", "Dest Unreachable", "Packet Too Big", "Time Exceeded", 511 [4] "Param Problem", 512 [8] "Echo Request", "Echo Reply", "Membership Query", "Membership Report", 513 [12] "Membership Reduction", "Router Solicit", "Router Advert", "Neighbor Solicit", 514 [16] "Neighbor Advert", "Redirect", 515 }; 516 517 if (dest_lsa->u.sa.sa_family == AF_INET6) { 518 if (t < 5) 519 return ttab6[t]; 520 if (t < 128 || t > ND_REDIRECT) 521 return "OUT-OF-RANGE"; 522 return ttab6[(t & 63) + 8]; 523 } 524 # endif 525 if (t >= ARRAY_SIZE(ttab)) 712 526 return "OUT-OF-RANGE"; 713 527 … … 716 530 #endif 717 531 532 #if !ENABLE_FEATURE_TRACEROUTE_VERBOSE 533 #define packet4_ok(read_len, from, seq) \ 534 packet4_ok(read_len, seq) 535 #endif 718 536 static int 719 packet _ok(unsigned char *buf, int cc,struct sockaddr_in *from, int seq)720 { 721 struct icmp *icp;537 packet4_ok(int read_len, const struct sockaddr_in *from, int seq) 538 { 539 const struct icmp *icp; 722 540 unsigned char type, code; 723 541 int hlen; 724 struct ip *ip;725 726 ip = (struct ip *) buf;542 const struct ip *ip; 543 544 ip = (struct ip *) recv_pkt; 727 545 hlen = ip->ip_hl << 2; 728 if ( cc< hlen + ICMP_MINLEN) {546 if (read_len < hlen + ICMP_MINLEN) { 729 547 #if ENABLE_FEATURE_TRACEROUTE_VERBOSE 730 548 if (verbose) 731 printf("packet too short (%d bytes) from %s\n", cc,549 printf("packet too short (%d bytes) from %s\n", read_len, 732 550 inet_ntoa(from->sin_addr)); 733 551 #endif 734 552 return 0; 735 553 } 736 cc-= hlen;737 icp = (struct icmp *)( buf+ hlen);554 read_len -= hlen; 555 icp = (struct icmp *)(recv_pkt + hlen); 738 556 type = icp->icmp_type; 739 557 code = icp->icmp_code; 740 558 /* Path MTU Discovery (RFC1191) */ 741 if (code != ICMP_UNREACH_NEEDFRAG) 742 pmtu = 0; 743 else { 559 pmtu = 0; 560 if (code == ICMP_UNREACH_NEEDFRAG) 744 561 pmtu = ntohs(icp->icmp_nextmtu); 745 } 746 if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) || 747 type == ICMP_UNREACH || type == ICMP_ECHOREPLY) { 748 struct ip *hip; 749 struct udphdr *up; 562 563 if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) 564 || type == ICMP_UNREACH 565 || type == ICMP_ECHOREPLY 566 ) { 567 const struct ip *hip; 568 const struct udphdr *up; 750 569 751 570 hip = &icp->icmp_ip; 752 571 hlen = hip->ip_hl << 2; 753 #if ENABLE_FEATURE_TRACEROUTE_USE_ICMP 754 if (useicmp) { 572 if (option_mask32 & OPT_USE_ICMP) { 755 573 struct icmp *hicmp; 756 574 757 575 /* XXX */ 758 if (type == ICMP_ECHOREPLY && 759 icp->icmp_id == htons(ident) && 760 icp->icmp_seq == htons(seq)) 761 return -2; 576 if (type == ICMP_ECHOREPLY 577 && icp->icmp_id == htons(ident) 578 && icp->icmp_seq == htons(seq) 579 ) { 580 return ICMP_UNREACH_PORT+1; 581 } 762 582 763 583 hicmp = (struct icmp *)((unsigned char *)hip + hlen); 764 /* XXX 8 is a magic number */765 if (hlen + 8 <= cc &&766 hip->ip_p == IPPROTO_ICMP &&767 hicmp->icmp_id == htons(ident) &&768 hicmp->icmp_seq == htons(seq))584 if (hlen + SIZEOF_ICMP_HDR <= read_len 585 && hip->ip_p == IPPROTO_ICMP 586 && hicmp->icmp_id == htons(ident) 587 && hicmp->icmp_seq == htons(seq) 588 ) { 769 589 return (type == ICMP_TIMXCEED ? -1 : code + 1); 770 } else 771 #endif 772 { 773 up = (struct udphdr *)((unsigned char *)hip + hlen); 774 /* XXX 8 is a magic number */ 775 if (hlen + 12 <= cc && 776 hip->ip_p == IPPROTO_UDP && 777 up->source == htons(ident) && 778 up->dest == htons(port + seq)) 590 } 591 } else { 592 up = (struct udphdr *)((char *)hip + hlen); 593 if (hlen + 12 <= read_len 594 && hip->ip_p == IPPROTO_UDP 595 // Off: since we do not form the entire IP packet, 596 // but defer it to kernel, we can't set source port, 597 // and thus can't check it here in the reply 598 /* && up->source == htons(ident) */ 599 && up->dest == htons(port + seq) 600 ) { 779 601 return (type == ICMP_TIMXCEED ? -1 : code + 1); 602 } 780 603 } 781 604 } … … 787 610 printf("\n%d bytes from %s to " 788 611 "%s: icmp type %d (%s) code %d\n", 789 cc, inet_ntoa(from->sin_addr), 790 inet_ntoa(ip->ip_dst), type, pr_type(type), icp->icmp_code); 791 for (i = 4; i < cc; i += sizeof(*lp)) 612 read_len, inet_ntoa(from->sin_addr), 613 inet_ntoa(ip->ip_dst), 614 type, pr_type(type), icp->icmp_code); 615 for (i = 4; i < read_len; i += sizeof(*lp)) 792 616 printf("%2d: x%8.8x\n", i, *lp++); 793 617 } … … 796 620 } 797 621 622 #if ENABLE_TRACEROUTE6 623 # if !ENABLE_FEATURE_TRACEROUTE_VERBOSE 624 #define packet_ok(read_len, from_lsa, to, seq) \ 625 packet_ok(read_len, from_lsa, seq) 626 # endif 627 static int 628 packet_ok(int read_len, len_and_sockaddr *from_lsa, 629 struct sockaddr *to, 630 int seq) 631 { 632 const struct icmp6_hdr *icp; 633 unsigned char type, code; 634 635 if (from_lsa->u.sa.sa_family == AF_INET) 636 return packet4_ok(read_len, &from_lsa->u.sin, seq); 637 638 icp = (struct icmp6_hdr *) recv_pkt; 639 640 type = icp->icmp6_type; 641 code = icp->icmp6_code; 642 643 if ((type == ICMP6_TIME_EXCEEDED && code == ICMP6_TIME_EXCEED_TRANSIT) 644 || type == ICMP6_DST_UNREACH 645 ) { 646 struct ip6_hdr *hip; 647 struct udphdr *up; 648 int nexthdr; 649 650 hip = (struct ip6_hdr *)(icp + 1); 651 up = (struct udphdr *) (hip + 1); 652 nexthdr = hip->ip6_nxt; 653 654 if (nexthdr == IPPROTO_FRAGMENT) { 655 nexthdr = *(unsigned char*)up; 656 up++; 657 } 658 if (nexthdr == IPPROTO_UDP) { 659 struct outdata6_t *pkt; 660 661 pkt = (struct outdata6_t *) (up + 1); 662 663 if (ntohl(pkt->ident6) == ident 664 && ntohl(pkt->seq6) == seq 665 ) { 666 return (type == ICMP6_TIME_EXCEEDED ? -1 : (code<<8)+1); 667 } 668 } 669 } 670 671 # if ENABLE_FEATURE_TRACEROUTE_VERBOSE 672 if (verbose) { 673 unsigned char *p; 674 char pa1[MAXHOSTNAMELEN]; 675 char pa2[MAXHOSTNAMELEN]; 676 int i; 677 678 p = (unsigned char *) (icp + 1); 679 680 printf("\n%d bytes from %s to " 681 "%s: icmp type %d (%s) code %d\n", 682 read_len, 683 inet_ntop(AF_INET6, &from_lsa->u.sin6.sin6_addr, pa1, sizeof(pa1)), 684 inet_ntop(AF_INET6, &((struct sockaddr_in6*)to)->sin6_addr, pa2, sizeof(pa2)), 685 type, pr_type(type), icp->icmp6_code); 686 687 read_len -= sizeof(struct icmp6_hdr); 688 for (i = 0; i < read_len ; i++) { 689 if (i % 16 == 0) 690 printf("%04x:", i); 691 if (i % 4 == 0) 692 bb_putchar(' '); 693 printf("%02x", p[i]); 694 if ((i % 16 == 15) && (i + 1 < read_len)) 695 bb_putchar('\n'); 696 } 697 bb_putchar('\n'); 698 } 699 # endif 700 701 return 0; 702 } 703 #else /* !ENABLE_TRACEROUTE6 */ 704 static ALWAYS_INLINE int 705 packet_ok(int read_len, 706 len_and_sockaddr *from_lsa IF_NOT_FEATURE_TRACEROUTE_VERBOSE(UNUSED_PARAM), 707 struct sockaddr *to UNUSED_PARAM, 708 int seq) 709 { 710 return packet4_ok(read_len, &from_lsa->u.sin, seq); 711 } 712 #endif 798 713 799 714 /* 800 715 * Construct an Internet address representation. 801 * If the nflag has been supplied, give716 * If the -n flag has been supplied, give 802 717 * numeric value, otherwise try for symbolic name. 803 718 */ 804 static inline void 805 print_inetname(struct sockaddr_in *from) 806 { 807 const char *ina; 808 809 ina = inet_ntoa(from->sin_addr); 810 if (nflag) 811 printf(" %s", ina); 812 else { 719 static void 720 print_inetname(const struct sockaddr *from) 721 { 722 char *ina = xmalloc_sockaddr2dotted_noport(from); 723 724 if (option_mask32 & OPT_ADDR_NUM) { 725 printf(" %s", ina); 726 } else { 813 727 char *n = NULL; 814 if (from->sin_addr.s_addr != INADDR_ANY) 728 729 if (from->sa_family != AF_INET 730 || ((struct sockaddr_in*)from)->sin_addr.s_addr != INADDR_ANY 731 ) { 732 /* Try to reverse resolve if it is not 0.0.0.0 */ 815 733 n = xmalloc_sockaddr2host_noport((struct sockaddr*)from); 816 printf(" %s (%s)", (n ? n : ina), ina); 734 } 735 printf(" %s (%s)", (n ? n : ina), ina); 817 736 free(n); 818 737 } 819 } 820 821 static inline void 822 print(unsigned char *buf, int cc, struct sockaddr_in *from) 823 { 824 struct ip *ip; 825 int hlen; 826 827 ip = (struct ip *) buf; 828 hlen = ip->ip_hl << 2; 829 cc -= hlen; 830 738 free(ina); 739 } 740 741 static void 742 print(int read_len, const struct sockaddr *from, const struct sockaddr *to) 743 { 831 744 print_inetname(from); 832 #if ENABLE_FEATURE_TRACEROUTE_VERBOSE 833 if (verbose) 834 printf(" %d bytes to %s", cc, inet_ntoa(ip->ip_dst)); 835 #endif 836 } 837 838 839 static struct hostinfo * 840 gethostinfo(const char *host) 841 { 842 int n; 843 struct hostent *hp; 844 struct hostinfo *hi; 845 char **p; 846 uint32_t addr, *ap; 847 848 hi = xzalloc(sizeof(*hi)); 849 addr = inet_addr(host); 850 if (addr != 0xffffffff) { 851 hi->name = xstrdup(host); 852 hi->n = 1; 853 hi->addrs = xzalloc(sizeof(hi->addrs[0])); 854 hi->addrs[0] = addr; 855 return hi; 856 } 857 858 hp = xgethostbyname(host); 859 if (hp->h_addrtype != AF_INET || hp->h_length != 4) 860 bb_perror_msg_and_die("bad host %s", host); 861 hi->name = xstrdup(hp->h_name); 862 for (n = 0, p = hp->h_addr_list; *p != NULL; ++n, ++p) 863 continue; 864 hi->n = n; 865 hi->addrs = xzalloc(n * sizeof(hi->addrs[0])); 866 for (ap = hi->addrs, p = hp->h_addr_list; *p != NULL; ++ap, ++p) 867 memcpy(ap, *p, sizeof(*ap)); 868 return hi; 869 } 870 871 static void 872 freehostinfo(struct hostinfo *hi) 873 { 874 free(hi->name); 875 free(hi->addrs); 876 free(hi); 877 } 878 879 #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE 880 static void 881 getaddr(uint32_t *ap, const char *host) 882 { 883 struct hostinfo *hi; 884 885 hi = gethostinfo(host); 886 *ap = hi->addrs[0]; 887 freehostinfo(hi); 888 } 889 #endif 745 746 if (verbose) { 747 char *ina = xmalloc_sockaddr2dotted_noport(to); 748 #if ENABLE_TRACEROUTE6 749 if (to->sa_family == AF_INET6) { 750 read_len -= sizeof(struct ip6_hdr); 751 } else 752 #endif 753 { 754 read_len -= ((struct ip*)recv_pkt)->ip_hl << 2; 755 } 756 printf(" %d bytes to %s", read_len, ina); 757 free(ina); 758 } 759 } 890 760 891 761 static void … … 893 763 { 894 764 unsigned tt = t2p - t1p; 895 printf(" %u.%03u ms", tt/1000, tt%1000); 896 } 897 898 int traceroute_main(int argc, char **argv); 899 int traceroute_main(int argc, char **argv) 900 { 901 int code, n; 902 unsigned char *outp; 903 uint32_t *ap; 904 struct sockaddr_in *from; 905 struct sockaddr_in *to; 906 struct hostinfo *hi; 907 int ttl, probe, i; 908 int seq = 0; 765 printf(" %u.%03u ms", tt / 1000, tt % 1000); 766 } 767 768 /* 769 * Usage: [-dFIlnrvx] [-g gateway] [-i iface] [-f first_ttl] 770 * [-m max_ttl] [ -p port] [-q nqueries] [-s src_addr] [-t tos] 771 * [-w waittime] [-z pausemsecs] host [packetlen]" 772 */ 773 static int 774 common_traceroute_main(int op, char **argv) 775 { 776 int i; 777 int minpacket; 909 778 int tos = 0; 779 int max_ttl = 30; 780 int nprobes = 3; 781 int first_ttl = 1; 782 unsigned pausemsecs = 0; 783 char *source; 784 char *device; 910 785 char *tos_str; 911 char *source;912 unsigned op;913 #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE914 int lsrr = 0;915 #endif916 uint16_t off = 0;917 struct IFADDRLIST *al;918 char *device;919 int max_ttl = 30;920 786 char *max_ttl_str; 921 787 char *port_str; 922 int nprobes = 3;923 788 char *nprobes_str; 924 789 char *waittime_str; 925 unsigned pausemsecs = 0;926 790 char *pausemsecs_str; 927 int first_ttl = 1;928 791 char *first_ttl_str; 929 792 #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE 930 793 llist_t *source_route_list = NULL; 931 #endif 932 933 PTR_TO_GLOBALS = xzalloc(sizeof(G)); 934 from = (struct sockaddr_in *)&wherefrom; 935 to = (struct sockaddr_in *)&whereto; 936 937 //opterr = 0; 938 #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE 939 opt_complementary = "x-x:g::"; 794 int lsrr = 0; 795 #endif 796 #if ENABLE_TRACEROUTE6 797 sa_family_t af; 940 798 #else 941 opt_complementary = "x-x"; 942 #endif 943 944 op = getopt32(argv, "FIlnrdvxt:i:m:p:q:s:w:z:f:" 945 #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE 946 "g:" 947 #endif 799 enum { af = AF_INET }; 800 #endif 801 int ttl; 802 int seq; 803 len_and_sockaddr *from_lsa; 804 struct sockaddr *lastaddr; 805 struct sockaddr *to; 806 807 INIT_G(); 808 809 /* minimum 1 arg */ 810 opt_complementary = "-1:x-x" IF_FEATURE_TRACEROUTE_SOURCE_ROUTE(":g::"); 811 op |= getopt32(argv, OPT_STRING 948 812 , &tos_str, &device, &max_ttl_str, &port_str, &nprobes_str 949 813 , &source, &waittime_str, &pausemsecs_str, &first_ttl_str … … 952 816 #endif 953 817 ); 954 955 if (op & OPT_DONT_FRAGMNT) 956 off = IP_DF; 957 if (op & OPT_IP_CHKSUM) { 958 doipcksum = 0; 818 argv += optind; 819 820 #if 0 /* IGNORED */ 821 if (op & OPT_IP_CHKSUM) 959 822 bb_error_msg("warning: ip checksums disabled"); 960 } 823 #endif 961 824 if (op & OPT_TOS) 962 825 tos = xatou_range(tos_str, 0, 255); … … 972 835 * probe (e.g., on a multi-homed host). 973 836 */ 974 if (getuid() )975 bb_error_msg_and_die( "-s %s: permission denied", source);837 if (getuid() != 0) 838 bb_error_msg_and_die(bb_msg_you_must_be_root); 976 839 } 977 840 if (op & OPT_WAITTIME) 978 waittime = xatou_range(waittime_str, 2, 24 * 60 * 60);841 waittime = xatou_range(waittime_str, 1, 24 * 60 * 60); 979 842 if (op & OPT_PAUSE_MS) 980 843 pausemsecs = xatou_range(pausemsecs_str, 0, 60 * 60 * 1000); 981 844 if (op & OPT_FIRST_TTL) 982 first_ttl = xatou_range(first_ttl_str, 1, 255);845 first_ttl = xatou_range(first_ttl_str, 1, max_ttl); 983 846 984 847 #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE 985 848 if (source_route_list) { 986 llist_t *l_sr; 987 988 l_sr = source_route_list; 989 while (l_sr) { 849 while (source_route_list) { 850 len_and_sockaddr *lsa; 851 990 852 if (lsrr >= NGATEWAYS) 991 853 bb_error_msg_and_die("no more than %d gateways", NGATEWAYS); 992 getaddr(gwlist + lsrr, l_sr->data); 854 lsa = xhost_and_af2sockaddr(llist_pop(&source_route_list), 0, AF_INET); 855 gwlist[lsrr] = lsa->u.sin.sin_addr.s_addr; 856 free(lsa); 993 857 ++lsrr; 994 l_sr = l_sr->link;995 free(source_route_list);996 source_route_list = l_sr;997 858 } 998 859 optlen = (lsrr + 1) * sizeof(gwlist[0]); … … 1000 861 #endif 1001 862 1002 if (first_ttl > max_ttl) {1003 bb_error_msg_and_die(1004 "first ttl (%d) may not be greater than max ttl (%d)",1005 first_ttl, max_ttl);1006 }1007 1008 minpacket = sizeof(*outip) + sizeof(*outdata) + optlen;1009 1010 #if ENABLE_FEATURE_TRACEROUTE_USE_ICMP1011 if (useicmp)1012 minpacket += 8; /* XXX magic number */1013 else1014 #endif1015 minpacket += sizeof(*outudp);1016 packlen = minpacket; /* minimum sized packet */1017 1018 863 /* Process destination and optional packet size */ 1019 switch (argc - optind) { 1020 1021 case 2: 1022 packlen = xatoul_range(argv[optind + 1], minpacket, maxpacket); 1023 /* Fall through */ 1024 1025 case 1: 1026 hostname = argv[optind]; 1027 hi = gethostinfo(hostname); 1028 setsin(to, hi->addrs[0]); 1029 if (hi->n > 1) 1030 bb_error_msg("warning: %s has multiple addresses; using %s", 1031 hostname, inet_ntoa(to->sin_addr)); 1032 hostname = hi->name; 1033 hi->name = NULL; 1034 freehostinfo(hi); 1035 break; 1036 1037 default: 1038 bb_show_usage(); 1039 } 864 minpacket = sizeof(*outip) + SIZEOF_ICMP_HDR + sizeof(*outdata) + optlen; 865 if (!(op & OPT_USE_ICMP)) 866 minpacket += sizeof(*outudp) - SIZEOF_ICMP_HDR; 867 #if ENABLE_TRACEROUTE6 868 af = AF_UNSPEC; 869 if (op & OPT_IPV4) 870 af = AF_INET; 871 if (op & OPT_IPV6) 872 af = AF_INET6; 873 dest_lsa = xhost_and_af2sockaddr(argv[0], port, af); 874 af = dest_lsa->u.sa.sa_family; 875 if (af == AF_INET6) 876 minpacket = sizeof(struct outdata6_t); 877 #else 878 dest_lsa = xhost2sockaddr(argv[0], port); 879 #endif 880 packlen = minpacket; 881 if (argv[1]) 882 packlen = xatoul_range(argv[1], minpacket, 32 * 1024); 1040 883 1041 884 /* Ensure the socket fds won't be 0, 1 or 2 */ 1042 885 bb_sanitize_stdio(); 1043 886 1044 s = xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP); 887 #if ENABLE_TRACEROUTE6 888 if (af == AF_INET6) { 889 xmove_fd(xsocket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6), rcvsock); 890 # ifdef IPV6_RECVPKTINFO 891 setsockopt(rcvsock, SOL_IPV6, IPV6_RECVPKTINFO, 892 &const_int_1, sizeof(const_int_1)); 893 setsockopt(rcvsock, SOL_IPV6, IPV6_2292PKTINFO, 894 &const_int_1, sizeof(const_int_1)); 895 # else 896 setsockopt(rcvsock, SOL_IPV6, IPV6_PKTINFO, 897 &const_int_1, sizeof(const_int_1)); 898 # endif 899 } else 900 #endif 901 { 902 xmove_fd(xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP), rcvsock); 903 } 1045 904 1046 905 #if TRACEROUTE_SO_DEBUG 1047 906 if (op & OPT_DEBUG) 1048 setsockopt( s, SOL_SOCKET, SO_DEBUG,907 setsockopt(rcvsock, SOL_SOCKET, SO_DEBUG, 1049 908 &const_int_1, sizeof(const_int_1)); 1050 909 #endif 1051 910 if (op & OPT_BYPASS_ROUTE) 1052 setsockopt( s, SOL_SOCKET, SO_DONTROUTE,911 setsockopt(rcvsock, SOL_SOCKET, SO_DONTROUTE, 1053 912 &const_int_1, sizeof(const_int_1)); 1054 913 1055 sndsock = xsocket(AF_INET, SOCK_RAW, IPPROTO_RAW); 1056 1057 #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE 1058 #if defined(IP_OPTIONS) 1059 if (lsrr > 0) { 1060 unsigned char optlist[MAX_IPOPTLEN]; 1061 1062 /* final hop */ 1063 gwlist[lsrr] = to->sin_addr.s_addr; 1064 ++lsrr; 1065 1066 /* force 4 byte alignment */ 1067 optlist[0] = IPOPT_NOP; 1068 /* loose source route option */ 1069 optlist[1] = IPOPT_LSRR; 1070 i = lsrr * sizeof(gwlist[0]); 1071 optlist[2] = i + 3; 1072 /* Pointer to LSRR addresses */ 1073 optlist[3] = IPOPT_MINOFF; 1074 memcpy(optlist + 4, gwlist, i); 1075 1076 if ((setsockopt(sndsock, IPPROTO_IP, IP_OPTIONS, 1077 (char *)optlist, i + sizeof(gwlist[0]))) < 0) { 1078 bb_perror_msg_and_die("IP_OPTIONS"); 1079 } 1080 } 1081 #endif /* IP_OPTIONS */ 1082 #endif /* CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE */ 914 #if ENABLE_TRACEROUTE6 915 if (af == AF_INET6) { 916 static const int two = 2; 917 if (setsockopt(rcvsock, SOL_RAW, IPV6_CHECKSUM, &two, sizeof(two)) < 0) 918 bb_perror_msg_and_die("setsockopt RAW_CHECKSUM"); 919 xmove_fd(xsocket(af, SOCK_DGRAM, 0), sndsock); 920 } else 921 #endif 922 { 923 if (op & OPT_USE_ICMP) 924 xmove_fd(xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP), sndsock); 925 else 926 xmove_fd(xsocket(AF_INET, SOCK_DGRAM, 0), sndsock); 927 #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE && defined IP_OPTIONS 928 if (lsrr > 0) { 929 unsigned char optlist[MAX_IPOPTLEN]; 930 931 /* final hop */ 932 gwlist[lsrr] = dest_lsa->u.sin.sin_addr.s_addr; 933 ++lsrr; 934 935 /* force 4 byte alignment */ 936 optlist[0] = IPOPT_NOP; 937 /* loose source route option */ 938 optlist[1] = IPOPT_LSRR; 939 i = lsrr * sizeof(gwlist[0]); 940 optlist[2] = i + 3; 941 /* pointer to LSRR addresses */ 942 optlist[3] = IPOPT_MINOFF; 943 memcpy(optlist + 4, gwlist, i); 944 945 if (setsockopt(sndsock, IPPROTO_IP, IP_OPTIONS, 946 (char *)optlist, i + sizeof(gwlist[0])) < 0) { 947 bb_perror_msg_and_die("IP_OPTIONS"); 948 } 949 } 950 #endif 951 } 1083 952 1084 953 #ifdef SO_SNDBUF … … 1087 956 } 1088 957 #endif 1089 #ifdef IP_HDRINCL1090 if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, &const_int_1, sizeof(const_int_1)) < 01091 && errno != ENOPROTOOPT1092 ) {1093 bb_perror_msg_and_die("IP_HDRINCL");1094 }1095 #else1096 958 #ifdef IP_TOS 1097 if ( tos_str&& setsockopt(sndsock, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0) {959 if ((op & OPT_TOS) && setsockopt(sndsock, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0) { 1098 960 bb_perror_msg_and_die("setsockopt tos %d", tos); 1099 961 } 1100 962 #endif 963 #ifdef IP_DONTFRAG 964 if (op & OPT_DONT_FRAGMNT) 965 setsockopt(sndsock, IPPROTO_IP, IP_DONTFRAG, 966 &const_int_1, sizeof(const_int_1)); 1101 967 #endif 1102 968 #if TRACEROUTE_SO_DEBUG … … 1109 975 &const_int_1, sizeof(const_int_1)); 1110 976 977 outip = xzalloc(packlen); 978 979 ident = getpid(); 980 981 if (af == AF_INET) { 982 if (op & OPT_USE_ICMP) { 983 ident |= 0x8000; 984 outicmp->icmp_type = ICMP_ECHO; 985 outicmp->icmp_id = htons(ident); 986 outdata = (struct outdata_t *)((char *)outicmp + SIZEOF_ICMP_HDR); 987 } else { 988 outdata = (struct outdata_t *)(outudp + 1); 989 } 990 } 991 992 if (op & OPT_DEVICE) /* hmm, do we need error check? */ 993 setsockopt_bindtodevice(sndsock, device); 994 995 if (op & OPT_SOURCE) { 996 #if ENABLE_TRACEROUTE6 997 // TODO: need xdotted_and_af2sockaddr? 998 len_and_sockaddr *source_lsa = xhost_and_af2sockaddr(source, 0, af); 999 #else 1000 len_and_sockaddr *source_lsa = xdotted2sockaddr(source, 0); 1001 #endif 1002 /* Ping4 does this (why?) */ 1003 if (af == AF_INET) 1004 if (setsockopt(sndsock, IPPROTO_IP, IP_MULTICAST_IF, 1005 &source_lsa->u.sa, source_lsa->len)) 1006 bb_error_msg_and_die("can't set multicast source interface"); 1007 //TODO: we can query source port we bound to, 1008 // and check it in replies... if we care enough 1009 xbind(sndsock, &source_lsa->u.sa, source_lsa->len); 1010 free(source_lsa); 1011 } 1012 #if ENABLE_TRACEROUTE6 1013 else if (af == AF_INET6) { 1014 //TODO: why we don't do it for IPv4? 1015 len_and_sockaddr *source_lsa; 1016 1017 int probe_fd = xsocket(af, SOCK_DGRAM, 0); 1018 if (op & OPT_DEVICE) 1019 setsockopt_bindtodevice(probe_fd, device); 1020 set_nport(dest_lsa, htons(1025)); 1021 /* dummy connect. makes kernel pick source IP (and port) */ 1022 xconnect(probe_fd, &dest_lsa->u.sa, dest_lsa->len); 1023 set_nport(dest_lsa, htons(port)); 1024 1025 /* read IP and port */ 1026 source_lsa = get_sock_lsa(probe_fd); 1027 if (source_lsa == NULL) 1028 bb_error_msg_and_die("can't get probe addr"); 1029 1030 close(probe_fd); 1031 1032 /* bind our sockets to this IP (but not port) */ 1033 set_nport(source_lsa, 0); 1034 xbind(sndsock, &source_lsa->u.sa, source_lsa->len); 1035 xbind(rcvsock, &source_lsa->u.sa, source_lsa->len); 1036 1037 free(source_lsa); 1038 } 1039 #endif 1040 1111 1041 /* Revert to non-privileged user after opening sockets */ 1112 1042 xsetgid(getgid()); 1113 1043 xsetuid(getuid()); 1114 1044 1115 outip = xzalloc(packlen); 1116 1117 outip->ip_v = IPVERSION; 1118 if (tos_str) 1119 outip->ip_tos = tos; 1120 outip->ip_len = htons(packlen); 1121 outip->ip_off = htons(off); 1122 outp = (unsigned char *)(outip + 1); 1123 outip->ip_dst = to->sin_addr; 1124 1125 outip->ip_hl = (outp - (unsigned char *)outip) >> 2; 1126 ident = (getpid() & 0xffff) | 0x8000; 1127 #if ENABLE_FEATURE_TRACEROUTE_USE_ICMP 1128 if (useicmp) { 1129 outip->ip_p = IPPROTO_ICMP; 1130 outicmp = (struct icmp *)outp; 1131 outicmp->icmp_type = ICMP_ECHO; 1132 outicmp->icmp_id = htons(ident); 1133 outdata = (struct outdata *)(outp + 8); /* XXX magic number */ 1134 } else 1135 #endif 1136 { 1137 outip->ip_p = IPPROTO_UDP; 1138 outudp = (struct udphdr *)outp; 1139 outudp->source = htons(ident); 1140 outudp->len = htons((uint16_t)(packlen - (sizeof(*outip) + optlen))); 1141 outdata = (struct outdata *)(outudp + 1); 1142 } 1143 1144 /* Get the interface address list */ 1145 n = ifaddrlist(&al); 1146 1147 /* Look for a specific device */ 1148 if (op & OPT_DEVICE) { 1149 for (i = n; i > 0; --i, ++al) 1150 if (strcmp(device, al->device) == 0) 1151 goto found_dev; 1152 bb_error_msg_and_die("can't find interface %s", device); 1153 } 1154 found_dev: 1155 1156 /* Determine our source address */ 1157 if (!(op & OPT_SOURCE)) { 1158 /* 1159 * If a device was specified, use the interface address. 1160 * Otherwise, try to determine our source address. 1161 */ 1162 if (op & OPT_DEVICE) 1163 setsin(from, al->addr); 1164 findsaddr(to, from); 1165 } else { 1166 hi = gethostinfo(source); 1167 source = hi->name; 1168 hi->name = NULL; 1169 /* 1170 * If the device was specified make sure it 1171 * corresponds to the source address specified. 1172 * Otherwise, use the first address (and warn if 1173 * there are more than one). 1174 */ 1175 if (op & OPT_DEVICE) { 1176 for (i = hi->n, ap = hi->addrs; i > 0; --i, ++ap) 1177 if (*ap == al->addr) 1178 goto found_dev2; 1179 bb_error_msg_and_die("%s is not on interface %s", 1180 source, device); 1181 found_dev2: 1182 setsin(from, *ap); 1183 } else { 1184 setsin(from, hi->addrs[0]); 1185 if (hi->n > 1) 1186 bb_error_msg( 1187 "warning: %s has multiple addresses; using %s", 1188 source, inet_ntoa(from->sin_addr)); 1189 } 1190 freehostinfo(hi); 1191 } 1192 1193 outip->ip_src = from->sin_addr; 1194 #ifndef IP_HDRINCL 1195 xbind(sndsock, (struct sockaddr *)from, sizeof(*from)); 1196 #endif 1197 1198 printf("traceroute to %s (%s)", hostname, inet_ntoa(to->sin_addr)); 1045 printf("traceroute to %s (%s)", argv[0], 1046 xmalloc_sockaddr2dotted_noport(&dest_lsa->u.sa)); 1199 1047 if (op & OPT_SOURCE) 1200 1048 printf(" from %s", source); 1201 1049 printf(", %d hops max, %d byte packets\n", max_ttl, packlen); 1202 fflush(stdout); 1203 1050 1051 from_lsa = dup_sockaddr(dest_lsa); 1052 lastaddr = xzalloc(dest_lsa->len); 1053 to = xzalloc(dest_lsa->len); 1054 seq = 0; 1204 1055 for (ttl = first_ttl; ttl <= max_ttl; ++ttl) { 1205 uint32_t lastaddr = 0; 1206 int gotlastaddr = 0; 1056 int probe; 1057 int unreachable = 0; /* counter */ 1058 int gotlastaddr = 0; /* flags */ 1207 1059 int got_there = 0; 1208 int unreachable = 0; 1209 int sentfirst = 0; 1210 1211 printf("%2d ", ttl); 1060 int first = 1; 1061 1062 printf("%2d", ttl); 1212 1063 for (probe = 0; probe < nprobes; ++probe) { 1213 int cc;1064 int read_len; 1214 1065 unsigned t1; 1215 1066 unsigned t2; 1216 1067 struct ip *ip; 1217 1068 1218 if ( sentfirst && pausemsecs > 0)1069 if (!first && pausemsecs > 0) 1219 1070 usleep(pausemsecs * 1000); 1071 fflush_all(); 1072 1220 1073 t1 = monotonic_us(); 1221 1074 send_probe(++seq, ttl); 1222 ++sentfirst; 1223 while ((cc = wait_for_reply(s, from)) != 0) { 1075 1076 first = 0; 1077 while ((read_len = wait_for_reply(from_lsa, to)) != 0) { 1224 1078 t2 = monotonic_us(); 1225 i = packet_ok( packet, cc, from, seq);1079 i = packet_ok(read_len, from_lsa, to, seq); 1226 1080 /* Skip short packet */ 1227 1081 if (i == 0) 1228 1082 continue; 1229 if (!gotlastaddr || 1230 from->sin_addr.s_addr != lastaddr) { 1231 print(packet, cc, from); 1232 lastaddr = from->sin_addr.s_addr; 1233 ++gotlastaddr; 1083 1084 if (!gotlastaddr 1085 || (memcmp(lastaddr, &from_lsa->u.sa, from_lsa->len) != 0) 1086 ) { 1087 print(read_len, &from_lsa->u.sa, to); 1088 memcpy(lastaddr, &from_lsa->u.sa, from_lsa->len); 1089 gotlastaddr = 1; 1234 1090 } 1091 1235 1092 print_delta_ms(t1, t2); 1236 ip = (struct ip *)packet; 1237 if (op & OPT_TTL_FLAG) 1238 printf(" (%d)", ip->ip_ttl); 1239 if (i == -2) { 1240 if (ip->ip_ttl <= 1) 1241 printf(" !"); 1242 ++got_there; 1243 break; 1244 } 1093 ip = (struct ip *)recv_pkt; 1094 1095 if (from_lsa->u.sa.sa_family == AF_INET) 1096 if (op & OPT_TTL_FLAG) 1097 printf(" (%d)", ip->ip_ttl); 1098 1245 1099 /* time exceeded in transit */ 1246 1100 if (i == -1) 1247 1101 break; 1248 code = i - 1; 1249 switch (code) { 1250 1102 i--; 1103 switch (i) { 1104 #if ENABLE_TRACEROUTE6 1105 case ICMP6_DST_UNREACH_NOPORT << 8: 1106 got_there = 1; 1107 break; 1108 #endif 1251 1109 case ICMP_UNREACH_PORT: 1252 1110 if (ip->ip_ttl <= 1) 1253 1111 printf(" !"); 1254 ++got_there;1112 got_there = 1; 1255 1113 break; 1256 1114 1257 1115 case ICMP_UNREACH_NET: 1116 #if ENABLE_TRACEROUTE6 && (ICMP6_DST_UNREACH_NOROUTE != ICMP_UNREACH_NET) 1117 case ICMP6_DST_UNREACH_NOROUTE << 8: 1118 #endif 1119 printf(" !N"); 1258 1120 ++unreachable; 1259 printf(" !N"); 1260 break; 1261 1121 break; 1262 1122 case ICMP_UNREACH_HOST: 1123 #if ENABLE_TRACEROUTE6 1124 case ICMP6_DST_UNREACH_ADDR << 8: 1125 #endif 1126 printf(" !H"); 1263 1127 ++unreachable; 1264 printf(" !H"); 1265 break; 1266 1128 break; 1267 1129 case ICMP_UNREACH_PROTOCOL: 1268 ++got_there;1269 1130 printf(" !P"); 1270 break;1271 1131 got_there = 1; 1132 break; 1272 1133 case ICMP_UNREACH_NEEDFRAG: 1134 printf(" !F-%d", pmtu); 1273 1135 ++unreachable; 1274 printf(" !F-%d", pmtu); 1275 break; 1276 1136 break; 1277 1137 case ICMP_UNREACH_SRCFAIL: 1138 #if ENABLE_TRACEROUTE6 1139 case ICMP6_DST_UNREACH_ADMIN << 8: 1140 #endif 1141 printf(" !S"); 1278 1142 ++unreachable; 1279 printf(" !S"); 1280 break; 1281 1143 break; 1282 1144 case ICMP_UNREACH_FILTER_PROHIB: 1283 1145 case ICMP_UNREACH_NET_PROHIB: /* misuse */ 1146 printf(" !A"); 1284 1147 ++unreachable; 1285 printf(" !A"); 1286 break; 1287 1148 break; 1288 1149 case ICMP_UNREACH_HOST_PROHIB: 1150 printf(" !C"); 1289 1151 ++unreachable; 1152 break; 1153 case ICMP_UNREACH_HOST_PRECEDENCE: 1154 printf(" !V"); 1155 ++unreachable; 1156 break; 1157 case ICMP_UNREACH_PRECEDENCE_CUTOFF: 1290 1158 printf(" !C"); 1291 break;1292 1293 case ICMP_UNREACH_HOST_PRECEDENCE:1294 1159 ++unreachable; 1295 printf(" !V"); 1296 break; 1297 1298 case ICMP_UNREACH_PRECEDENCE_CUTOFF: 1299 ++unreachable; 1300 printf(" !C"); 1301 break; 1302 1160 break; 1303 1161 case ICMP_UNREACH_NET_UNKNOWN: 1304 1162 case ICMP_UNREACH_HOST_UNKNOWN: 1163 printf(" !U"); 1305 1164 ++unreachable; 1306 printf(" !U"); 1307 break; 1308 1165 break; 1309 1166 case ICMP_UNREACH_ISOLATED: 1167 printf(" !I"); 1310 1168 ++unreachable; 1311 printf(" !I"); 1312 break; 1313 1169 break; 1314 1170 case ICMP_UNREACH_TOSNET: 1315 1171 case ICMP_UNREACH_TOSHOST: 1172 printf(" !T"); 1316 1173 ++unreachable; 1317 printf(" !T"); 1318 break; 1319 1174 break; 1320 1175 default: 1176 printf(" !<%d>", i); 1321 1177 ++unreachable; 1322 printf(" !<%d>", code);1323 1178 break; 1324 1179 } 1325 1180 break; 1326 1181 } 1327 if (cc == 0) 1328 printf(" *"); 1329 (void)fflush(stdout); 1330 } 1331 putchar('\n'); 1332 if (got_there || 1333 (unreachable > 0 && unreachable >= nprobes - 1)) 1182 /* there was no packet at all? */ 1183 if (read_len == 0) 1184 printf(" *"); 1185 } 1186 bb_putchar('\n'); 1187 if (got_there 1188 || (unreachable > 0 && unreachable >= nprobes - 1) 1189 ) { 1334 1190 break; 1335 } 1191 } 1192 } 1193 1336 1194 return 0; 1337 1195 } 1196 1197 int traceroute_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 1198 int traceroute_main(int argc UNUSED_PARAM, char **argv) 1199 { 1200 return common_traceroute_main(0, argv); 1201 } 1202 1203 #if ENABLE_TRACEROUTE6 1204 int traceroute6_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 1205 int traceroute6_main(int argc UNUSED_PARAM, char **argv) 1206 { 1207 return common_traceroute_main(OPT_IPV6, argv); 1208 } 1209 #endif
Note:
See TracChangeset
for help on using the changeset viewer.