- Timestamp:
- Dec 10, 2013 4:52:28 AM (11 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/NetworkServices/NAT/pxping.c
r49782 r49861 78 78 struct pxping { 79 79 SOCKET sock4; 80 81 #if defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) 82 # define DF_WITH_IP_HDRINCL 83 int hdrincl; 84 #else 85 int df; 86 #endif 80 87 int ttl; 81 88 int tos; 82 int df;83 89 84 90 SOCKET sock6; … … 261 267 g_pxping.sock4 = sock4; 262 268 if (g_pxping.sock4 != INVALID_SOCKET) { 269 #ifdef DF_WITH_IP_HDRINCL 270 g_pxping.hdrincl = -1; 271 #else 272 g_pxping.df = -1; 273 #endif 263 274 g_pxping.ttl = -1; 264 275 g_pxping.tos = 0; 265 g_pxping.df = -1; 276 277 #ifdef RT_OS_LINUX 278 { 279 const int dont = IP_PMTUDISC_DONT; 280 status = setsockopt(sock4, IPPROTO_IP, IP_MTU_DISCOVER, 281 &dont, sizeof(dont)); 282 if (status != 0) { 283 perror("IP_MTU_DISCOVER"); 284 } 285 } 286 #endif /* RT_OS_LINUX */ 266 287 267 288 g_pxping.pmhdl4.callback = pxping_pmgr_pump; … … 415 436 struct pxping *pxping = (struct pxping *)arg; 416 437 struct ping_pcb *pcb; 438 #ifdef DF_WITH_IP_HDRINCL 439 struct ip_hdr iph_orig; 440 #endif 441 struct icmp_echo_hdr icmph_orig; 417 442 struct ip_hdr *iph; 418 443 struct icmp_echo_hdr *icmph; 419 int ttl, tos;444 int df, ttl, tos; 420 445 u32_t sum; 421 446 u16_t iphlen; 422 u16_t id, seq;423 447 int status; 424 448 449 iphlen = ip_current_header_tot_len(); 450 if (iphlen != IP_HLEN) { /* we don't do options */ 451 pbuf_free(p); 452 return; 453 } 454 425 455 iph = (/* UNCONST */ struct ip_hdr *)ip_current_header(); 426 iphlen = ip_current_header_tot_len();427 428 456 icmph = (struct icmp_echo_hdr *)p->payload; 429 430 id = icmph->id;431 seq = icmph->seqno;432 457 433 458 pcb = pxping_pcb_for_request(pxping, 0, 434 459 ipX_current_src_addr(), 435 460 ipX_current_dest_addr(), 436 i d);461 icmph->id); 437 462 if (pcb == NULL) { 438 463 pbuf_free(p); … … 442 467 pxping_pcb_debug_print(pcb); /* XXX */ 443 468 printf(" seq %d len %u ttl %d\n", 444 ntohs( seq), (unsigned int)p->tot_len,469 ntohs(icmph->seqno), (unsigned int)p->tot_len, 445 470 IPH_TTL(iph)); 446 471 447 472 ttl = IPH_TTL(iph); 448 473 if (!pcb->is_mapped) { 449 if (ttl == 1) { 450 pbuf_header(p, iphlen); /* back to IP header */ 451 icmp_time_exceeded(p, ICMP_TE_TTL); 474 if (RT_UNLIKELY(ttl == 1)) { 475 status = pbuf_header(p, iphlen); /* back to IP header */ 476 if (RT_LIKELY(status == 0)) { 477 icmp_time_exceeded(p, ICMP_TE_TTL); 478 } 452 479 pbuf_free(p); 453 480 return; … … 456 483 } 457 484 458 /* rewrite ICMP echo header */ 459 sum = (u16_t)~icmph->chksum; 460 sum += chksum_update_16(&icmph->id, pcb->host_id); 461 sum = FOLD_U32T(sum); 462 icmph->chksum = ~sum; 463 464 if (ttl != pxping->ttl) { 465 status = setsockopt(pxping->sock4, IPPROTO_IP, IP_TTL, 466 (char *)&ttl, sizeof(ttl)); 467 if (status == 0) { 468 pxping->ttl = ttl; 485 /* 486 * OS X doesn't provide a socket option to control fragmentation. 487 * Solaris doesn't provide IP_DONTFRAG on all releases we support. 488 * In this case we have to use IP_HDRINCL. We don't want to use 489 * it always since it doesn't handle fragmentation (but that's ok 490 * for DF) and Windows doesn't do automatic source address 491 * selection with IP_HDRINCL. 492 */ 493 df = (IPH_OFFSET(iph) & PP_HTONS(IP_DF)) != 0; 494 495 #ifdef DF_WITH_IP_HDRINCL 496 if (df != pxping->hdrincl) { 497 status = setsockopt(pxping->sock4, IPPROTO_IP, IP_HDRINCL, 498 &df, sizeof(df)); 499 if (RT_LIKELY(status == 0)) { 500 pxping->hdrincl = df; 469 501 } 470 502 else { 471 perror("IP_TTL"); 472 } 473 } 474 475 tos = IPH_TOS(iph); 476 if (tos != pxping->tos) { 477 status = setsockopt(pxping->sock4, IPPROTO_IP, IP_TOS, 478 (char *)&tos, sizeof(tos)); 479 if (status == 0) { 480 pxping->tos = tos; 503 perror("IP_HDRINCL"); 504 } 505 } 506 507 if (pxping->hdrincl) { 508 status = pbuf_header(p, iphlen); /* back to IP header */ 509 if (RT_UNLIKELY(status != 0)) { 510 pbuf_free(p); 511 return; 512 } 513 514 /* we will overwrite IP header, save original for ICMP errors */ 515 memcpy(&iph_orig, iph, iphlen); 516 517 if (g_proxy_options->src4 != NULL) { 518 memcpy(&iph->src, &g_proxy_options->src4->sin_addr, 519 sizeof(g_proxy_options->src4->sin_addr)); 481 520 } 482 521 else { 483 perror("IP_TOS"); 484 } 485 } 486 487 #if 0 488 #if /*defined(RT_OS_LINUX) ||*/ defined(RT_OS_SOLARIS) || defined(RT_OS_WINDOWS) 522 /* let the kernel select suitable source address */ 523 memset(&iph->src, 0, sizeof(iph->src)); 524 } 525 526 IPH_TTL_SET(iph, ttl); /* already decremented */ 527 IPH_ID_SET(iph, 0); /* kernel will set one */ 528 #ifdef RT_OS_DARWIN 529 /* wants ip_offset and ip_len fields in host order */ 530 IPH_OFFSET_SET(iph, ntohs(IPH_OFFSET(iph))); 531 IPH_LEN_SET(iph, ntohs(IPH_LEN(iph))); 532 #endif 533 IPH_CHKSUM_SET(iph, 0); /* kernel will recalculate */ 534 } 535 else /* !pxping->hdrincl */ 536 #endif /* DF_WITH_IP_HDRINCL */ 489 537 { 490 const int df_flag = IPH_OFFSET(iph) & PP_HTONS(IP_DF); 491 538 #if !defined(DF_WITH_IP_HDRINCL) 539 /* control DF flag via setsockopt(2) */ 540 #define USE_DF_OPTION(_Optname) \ 541 const int dfopt = _Optname; \ 542 const char * const dfoptname = #_Optname; 492 543 #if defined(RT_OS_LINUX) 493 const char * const dfoptname = "IP_MTU_DISCOVER"; 494 const int dfopt = IP_MTU_DISCOVER; 495 int df = df_flag ? IP_PMTUDISC_PROBE : IP_PMTUDISC_DONT; 496 #elif defined(RT_OS_SOLARIS) 497 const char * const dfoptname = "IP_DONTFRAG"; 498 const int dfopt = IP_DONTFRAG; 499 int df = !!df_flag; 544 USE_DF_OPTION(IP_MTU_DISCOVER); 545 df = df ? IP_PMTUDISC_DO : IP_PMTUDISC_DONT; 546 #elif defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD) 547 USE_DF_OPTION(IP_DONTFRAG); 500 548 #elif defined(RT_OS_WINDOWS) 501 const char * const dfoptname = "IP_DONTFRAGMENT"; 502 const int dfopt = IP_DONTFRAGMENT; 503 DWORD df = !!df_flag; 549 USE_DF_OPTION(IP_DONTFRAGMENT); 504 550 #endif 505 551 if (df != pxping->df) { 506 552 status = setsockopt(pxping->sock4, IPPROTO_IP, dfopt, 507 553 (char *)&df, sizeof(df)); 508 if ( status == 0) {554 if (RT_LIKELY(status == 0)) { 509 555 pxping->df = df; 510 556 } … … 513 559 } 514 560 } 515 } 516 #endif /* don't fragment */ 517 #endif /* 0 */ 518 519 proxy_sendto(pxping->sock4, p, 520 &pcb->peer.sin, sizeof(pcb->peer.sin)); 561 #endif /* !DF_WITH_IP_HDRINCL */ 562 563 if (ttl != pxping->ttl) { 564 status = setsockopt(pxping->sock4, IPPROTO_IP, IP_TTL, 565 (char *)&ttl, sizeof(ttl)); 566 if (RT_LIKELY(status == 0)) { 567 pxping->ttl = ttl; 568 } 569 else { 570 perror("IP_TTL"); 571 } 572 } 573 574 tos = IPH_TOS(iph); 575 if (tos != pxping->tos) { 576 status = setsockopt(pxping->sock4, IPPROTO_IP, IP_TOS, 577 (char *)&tos, sizeof(tos)); 578 if (RT_LIKELY(status == 0)) { 579 pxping->tos = tos; 580 } 581 else { 582 perror("IP_TOS"); 583 } 584 } 585 } 586 587 /* rewrite ICMP echo header */ 588 memcpy(&icmph_orig, icmph, sizeof(*icmph)); 589 sum = (u16_t)~icmph->chksum; 590 sum += chksum_update_16(&icmph->id, pcb->host_id); 591 sum = FOLD_U32T(sum); 592 icmph->chksum = ~sum; 593 594 status = proxy_sendto(pxping->sock4, p, 595 &pcb->peer.sin, sizeof(pcb->peer.sin)); 596 if (status != 0) { 597 int error = -status; 598 DPRINTF(("%s: sendto errno %d\n", __func__, error)); 599 600 #ifdef DF_WITH_IP_HDRINCL 601 if (pxping->hdrincl) { 602 /* restore original IP header */ 603 memcpy(iph, &iph_orig, iphlen); 604 } 605 else 606 #endif 607 { 608 status = pbuf_header(p, iphlen); /* back to IP header */ 609 if (RT_UNLIKELY(status != 0)) { 610 pbuf_free(p); 611 return; 612 } 613 } 614 615 /* restore original ICMP header */ 616 memcpy(icmph, &icmph_orig, sizeof(*icmph)); 617 618 /* 619 * Some ICMP errors may be generated by the kernel and we read 620 * them from the socket and forward them normally, hence the 621 * ifdefs below. 622 */ 623 switch (error) { 624 625 #if !( defined(RT_OS_SOLARIS) \ 626 || (defined(RT_OS_LINUX) && !defined(DF_WITH_IP_HDRINCL)) \ 627 ) 628 case EMSGSIZE: 629 icmp_dest_unreach(p, ICMP_DUR_FRAG); 630 break; 631 #endif 632 633 case ENETDOWN: 634 case ENETUNREACH: 635 icmp_dest_unreach(p, ICMP_DUR_NET); 636 break; 637 638 case EHOSTDOWN: 639 case EHOSTUNREACH: 640 icmp_dest_unreach(p, ICMP_DUR_HOST); 641 break; 642 } 643 } 521 644 522 645 pbuf_free(p);
Note:
See TracChangeset
for help on using the changeset viewer.