VirtualBox

Ignore:
Timestamp:
Sep 16, 2015 3:36:31 PM (9 years ago)
Author:
vboxsync
Message:

NAT: rewrite handling of port-forwarding.

The most interesting part is handling of wildcard guest address
(0.0.0.0) for which we are supposed to guess the real guest IP. For
TCP we delay the decision until new connection come and the we can use
the current guess for each new connection. For UDP things are
trickier. For now we set the current guess as the destination on
first incoming packet, but that doesn't handle changes of the guest
address or outgoing packets. This needs more thought.

Location:
trunk/src/VBox/Devices/Network/slirp
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Network/slirp/bootp.c

    r57181 r57784  
    363363
    364364    dhcp_create_msg(pData, bp, m, DHCPACK);
     365    slirp_update_guest_addr_guess(pData, bc->addr.s_addr, "DHCP ACK");
    365366    offReply = dhcp_do_ack_offer(pData, m, bc, fDhcpRequest);
    366367    return offReply;
  • trunk/src/VBox/Devices/Network/slirp/libslirp.h

    r56292 r57784  
    6363
    6464void slirp_input(PNATState pData, struct mbuf *m, size_t cbBuf);
    65 void slirp_set_ethaddr_and_activate_port_forwarding(PNATState pData, const uint8_t *ethaddr, uint32_t GuestIP);
    6665
    6766/* you must provide the following functions: */
     
    7372void slirp_post_sent(PNATState pData, void *pvArg);
    7473
     74void slirp_update_guest_addr_guess(PNATState pData, uint32_t guess, const char *msg);
     75
    7576int slirp_add_redirect(PNATState pData, int is_udp, struct in_addr host_addr,
    7677                int host_port, struct in_addr guest_addr,
    77                 int guest_port, const uint8_t *);
     78                int guest_port);
    7879int slirp_remove_redirect(PNATState pData, int is_udp, struct in_addr host_addr,
    7980                int host_port, struct in_addr guest_addr,
  • trunk/src/VBox/Devices/Network/slirp/slirp.c

    r57739 r57784  
    261261    DO_LOG_NAT_SOCK((so), proto, (winevent), r_fdset, w_fdset, x_fdset)
    262262
    263 static void activate_port_forwarding(PNATState, const uint8_t *pEther);
    264 
    265263static const uint8_t special_ethaddr[6] =
    266264{
     
    477475    if (!pData->fUseHostResolverPermanent)
    478476        slirpInitializeDnsSettings(pData);
    479 
    480     if (LIST_EMPTY(&pData->arp_cache))
    481         return;
    482 
    483     LIST_FOREACH(ac, &pData->arp_cache, list)
    484     {
    485         activate_port_forwarding(pData, ac->ether);
    486     }
    487477}
    488478
     
    498488
    499489    slirpReleaseDnsSettings(pData);
    500 
    501     /*
    502      *  Clear the active state of port-forwarding rules to force
    503      *  re-setup on restoration of communications.
    504      */
    505     LIST_FOREACH(rule, &pData->port_forward_rule_head, list)
    506     {
    507         rule->activated = 0;
    508     }
    509     pData->cRedirectionsActive = 0;
    510490
    511491    link_up = 0;
     
    13191299    if_encap(pData, ETH_P_ARP, pMbufResponse, ETH_ENCAP_URG);
    13201300}
     1301
    13211302/**
    13221303 * @note This function will free m!
     
    13411322                || CTL_CHECK(ip4TargetAddress, CTL_ALIAS)
    13421323                || CTL_CHECK(ip4TargetAddress, CTL_TFTP))
     1324            {
     1325                slirp_update_guest_addr_guess(pData, *(uint32_t *)pARPHeader->ar_sip, "arp request");
    13431326                arp_output(pData, pEtherHeader->h_source, pARPHeader, ip4TargetAddress);
     1327                break;
     1328            }
    13441329
    13451330            /* Gratuitous ARP */
    1346             if (  *(uint32_t *)pARPHeader->ar_sip == *(uint32_t *)pARPHeader->ar_tip
    1347                 && memcmp(pARPHeader->ar_tha, broadcast_ethaddr, ETH_ALEN) == 0
     1331            if (   *(uint32_t *)pARPHeader->ar_sip == *(uint32_t *)pARPHeader->ar_tip
     1332                && (   memcmp(pARPHeader->ar_tha, zerro_ethaddr, ETH_ALEN) == 0
     1333                    || memcmp(pARPHeader->ar_tha, broadcast_ethaddr, ETH_ALEN) == 0)
    13481334                && memcmp(pEtherHeader->h_dest, broadcast_ethaddr, ETH_ALEN) == 0)
    13491335            {
    1350                 /* We've received an announce about address assignment,
    1351                  * let's do an ARP cache update
    1352                  */
    1353                 static bool fGratuitousArpReported;
    1354                 if (!fGratuitousArpReported)
    1355                 {
    1356                     LogRel(("NAT: Gratuitous ARP [IP:%RTnaipv4, ether:%RTmac]\n",
    1357                             *(uint32_t *)pARPHeader->ar_sip, pARPHeader->ar_sha));
    1358                     fGratuitousArpReported = true;
    1359                 }
     1336                LogRel2(("NAT: gratuitous ARP from %RTnaipv4 at %RTmac\n",
     1337                         *(uint32_t *)pARPHeader->ar_sip, pARPHeader->ar_sha));
     1338                slirp_update_guest_addr_guess(pData, *(uint32_t *)pARPHeader->ar_sip, "gratuitous arp");
    13601339                slirp_arp_cache_update_or_add(pData, *(uint32_t *)pARPHeader->ar_sip, &pARPHeader->ar_sha[0]);
    13611340            }
     
    14281407            break;
    14291408    }
    1430 
    1431     if (pData->cRedirectionsActive != pData->cRedirectionsStored)
    1432         activate_port_forwarding(pData, au8Ether);
    14331409}
    14341410
     
    14981474}
    14991475
    1500 /**
    1501  * Still we're using dhcp server leasing to map ether to IP
    1502  * @todo  see rt_lookup_in_cache
    1503  */
    1504 static uint32_t find_guest_ip(PNATState pData, const uint8_t *eth_addr)
    1505 {
    1506     uint32_t ip = INADDR_ANY;
    1507     int rc;
    1508 
    1509     if (eth_addr == NULL)
    1510         return INADDR_ANY;
    1511 
    1512     if (   memcmp(eth_addr, zerro_ethaddr, ETH_ALEN) == 0
    1513         || memcmp(eth_addr, broadcast_ethaddr, ETH_ALEN) == 0)
    1514         return INADDR_ANY;
    1515 
    1516     rc = slirp_arp_lookup_ip_by_ether(pData, eth_addr, &ip);
    1517     if (RT_SUCCESS(rc))
    1518         return ip;
    1519 
    1520     bootp_cache_lookup_ip_by_ether(pData, eth_addr, &ip);
    1521     /* ignore return code, ip will be set to INADDR_ANY on error */
    1522     return ip;
    1523 }
    1524 
    1525 /**
    1526  * We need check if we've activated port forwarding
    1527  * for specific machine ... that of course relates to
    1528  * service mode
    1529  * @todo finish this for service case
    1530  */
    1531 static void activate_port_forwarding(PNATState pData, const uint8_t *h_source)
    1532 {
    1533     struct port_forward_rule *rule, *tmp;
    1534     const uint8_t *pu8EthSource = h_source;
    1535 
    1536     /* check mac here */
    1537     LIST_FOREACH_SAFE(rule, &pData->port_forward_rule_head, list, tmp)
    1538     {
    1539         struct socket *so;
    1540         struct sockaddr sa;
    1541         struct sockaddr_in *psin;
    1542         socklen_t socketlen;
    1543         int rc;
    1544         uint32_t guest_addr; /* need to understand if we already give address to guest */
    1545 
    1546         if (rule->activated)
    1547             continue;
    1548 
    1549         guest_addr = find_guest_ip(pData, pu8EthSource);
    1550         if (guest_addr == INADDR_ANY)
    1551         {
    1552             /* the address wasn't granted */
    1553             return;
    1554         }
    1555 
    1556         if (   rule->guest_addr.s_addr != guest_addr
    1557             && rule->guest_addr.s_addr != INADDR_ANY)
    1558             continue;
    1559         if (rule->guest_addr.s_addr == INADDR_ANY)
    1560             rule->guest_addr.s_addr = guest_addr;
    1561 
    1562         LogRel(("NAT: set redirect %s host %RTnaipv4:%d => guest %RTnaipv4:%d\n",
     1476
     1477void
     1478slirp_update_guest_addr_guess(PNATState pData, uint32_t guess, const char *msg)
     1479{
     1480    Assert(msg != NULL);
     1481
     1482    if (pData->guest_addr_guess.s_addr == guess)
     1483    {
     1484        LogRel2(("NAT: guest address guess %RTnaipv4 re-confirmed by %s\n",
     1485                 pData->guest_addr_guess.s_addr, msg));
     1486        return;
     1487    }
     1488
     1489    if (pData->guest_addr_guess.s_addr == INADDR_ANY)
     1490    {
     1491        pData->guest_addr_guess.s_addr = guess;
     1492        LogRel(("NAT: guest address guess set to %RTnaipv4 by %s\n",
     1493                pData->guest_addr_guess.s_addr, msg));
     1494        return;
     1495    }
     1496    else
     1497    {
     1498        LogRel(("NAT: guest address guess changed from %RTnaipv4 to %RTnaipv4 by %s\n",
     1499                pData->guest_addr_guess.s_addr, guess, msg));
     1500        pData->guest_addr_guess.s_addr = guess;
     1501        return;
     1502    }
     1503}
     1504
     1505
     1506static struct port_forward_rule *
     1507slirp_find_redirect(PNATState pData,
     1508                    int is_udp,
     1509                    struct in_addr host_addr, int host_port,
     1510                    struct in_addr guest_addr, int guest_port)
     1511{
     1512    struct port_forward_rule *rule;
     1513    uint16_t proto = (is_udp ? IPPROTO_UDP : IPPROTO_TCP);
     1514
     1515    LIST_FOREACH(rule, &pData->port_forward_rule_head, list)
     1516    {
     1517        if (   rule->proto == proto
     1518            && rule->host_port == host_port
     1519            && rule->bind_ip.s_addr == host_addr.s_addr
     1520            && rule->guest_port == guest_port
     1521            && rule->guest_addr.s_addr == guest_addr.s_addr)
     1522        {
     1523            return rule;
     1524        }
     1525    }
     1526
     1527    return NULL;
     1528}
     1529
     1530
     1531int slirp_add_redirect(PNATState pData, int is_udp, struct in_addr host_addr, int host_port,
     1532                struct in_addr guest_addr, int guest_port)
     1533{
     1534    struct port_forward_rule *rule;
     1535
     1536    rule = slirp_find_redirect(pData, is_udp, host_addr, host_port, guest_addr, guest_port);
     1537    if (rule != NULL) /* rule has been already registered */
     1538    {
     1539        /* XXX: this shouldn't happen */
     1540        return 0;
     1541    }
     1542
     1543    rule = RTMemAllocZ(sizeof(struct port_forward_rule));
     1544    if (rule == NULL)
     1545        return 1;
     1546
     1547    rule->proto = (is_udp ? IPPROTO_UDP : IPPROTO_TCP);
     1548    rule->bind_ip.s_addr = host_addr.s_addr;
     1549    rule->host_port = host_port;
     1550    rule->guest_addr.s_addr = guest_addr.s_addr;
     1551    rule->guest_port = guest_port;
     1552
     1553    if (rule->proto == IPPROTO_UDP)
     1554        rule->so = udp_listen(pData, rule->bind_ip.s_addr, RT_H2N_U16(rule->host_port),
     1555                              rule->guest_addr.s_addr, RT_H2N_U16(rule->guest_port), 0);
     1556    else
     1557        rule->so = solisten(pData, rule->bind_ip.s_addr, RT_H2N_U16(rule->host_port),
     1558                            rule->guest_addr.s_addr, RT_H2N_U16(rule->guest_port), 0);
     1559
     1560    if (rule->so == NULL)
     1561    {
     1562        LogRel(("NAT: failed to redirect %s %RTnaipv4:%d -> %RTnaipv4:%d\n",
    15631563                rule->proto == IPPROTO_UDP ? "UDP" : "TCP",
    15641564                rule->bind_ip.s_addr, rule->host_port,
    15651565                guest_addr, rule->guest_port));
    1566 
    1567         if (rule->proto == IPPROTO_UDP)
    1568             so = udp_listen(pData, rule->bind_ip.s_addr, RT_H2N_U16(rule->host_port), guest_addr,
    1569                             RT_H2N_U16(rule->guest_port), 0);
    1570         else
    1571             so = solisten(pData, rule->bind_ip.s_addr, RT_H2N_U16(rule->host_port), guest_addr,
    1572                           RT_H2N_U16(rule->guest_port), 0);
    1573 
    1574         if (so == NULL)
    1575             goto remove_port_forwarding;
    1576 
    1577         psin = (struct sockaddr_in *)&sa;
    1578         psin->sin_family = AF_INET;
    1579         psin->sin_port = 0;
    1580         psin->sin_addr.s_addr = INADDR_ANY;
    1581         socketlen = sizeof(struct sockaddr);
    1582 
    1583         rc = getsockname(so->s, &sa, &socketlen);
    1584         if (rc < 0 || sa.sa_family != AF_INET)
    1585             goto remove_port_forwarding;
    1586 
    1587         rule->activated = 1;
    1588         rule->so = so;
    1589         pData->cRedirectionsActive++;
    1590         continue;
    1591 
    1592     remove_port_forwarding:
    1593         LogRel(("NAT: failed to redirect %s %RTnaipv4:%d => %RTnaipv4:%d\n",
    1594                 (rule->proto == IPPROTO_UDP ? "UDP" : "TCP"),
    1595                 rule->bind_ip.s_addr, rule->host_port,
    1596                 guest_addr, rule->guest_port));
    1597         LIST_REMOVE(rule, list);
    1598         pData->cRedirectionsStored--;
    15991566        RTMemFree(rule);
    1600     }
    1601 }
    1602 
    1603 /**
    1604  * Changes in 3.1 instead of opening new socket do the following:
    1605  * gain more information:
    1606  *  1. bind IP
    1607  *  2. host port
    1608  *  3. guest port
    1609  *  4. proto
    1610  *  5. guest MAC address
    1611  * the guest's MAC address is rather important for service, but we easily
    1612  * could get it from VM configuration in DrvNAT or Service, the idea is activating
    1613  * corresponding port-forwarding
    1614  */
    1615 int slirp_add_redirect(PNATState pData, int is_udp, struct in_addr host_addr, int host_port,
    1616                 struct in_addr guest_addr, int guest_port, const uint8_t *ethaddr)
    1617 {
    1618     struct port_forward_rule *rule = NULL;
    1619     LIST_FOREACH(rule, &pData->port_forward_rule_head, list)
    1620     {
    1621         if (   rule->proto == (is_udp ? IPPROTO_UDP : IPPROTO_TCP)
    1622             && rule->host_port == host_port
    1623             && rule->bind_ip.s_addr == host_addr.s_addr
    1624             && rule->guest_port == guest_port
    1625             && rule->guest_addr.s_addr == guest_addr.s_addr
    1626             )
    1627             return 0; /* rule has been already registered */
    1628     }
    1629 
    1630     rule = RTMemAllocZ(sizeof(struct port_forward_rule));
    1631     if (rule == NULL)
    16321567        return 1;
    1633 
    1634     rule->proto = (is_udp ? IPPROTO_UDP : IPPROTO_TCP);
    1635     rule->host_port = host_port;
    1636     rule->guest_port = guest_port;
    1637     rule->guest_addr.s_addr = guest_addr.s_addr;
    1638     rule->bind_ip.s_addr = host_addr.s_addr;
     1568    }
     1569
     1570    LogRel(("NAT: set redirect %s %RTnaipv4:%d -> %RTnaipv4:%d\n",
     1571            rule->proto == IPPROTO_UDP ? "UDP" : "TCP",
     1572            rule->bind_ip.s_addr, rule->host_port,
     1573            guest_addr, rule->guest_port));
     1574
    16391575    LIST_INSERT_HEAD(&pData->port_forward_rule_head, rule, list);
    1640     pData->cRedirectionsStored++;
    1641     /* activate port-forwarding if guest has already got assigned IP */
    1642     if (   ethaddr
    1643         && memcmp(ethaddr, zerro_ethaddr, ETH_ALEN))
    1644         activate_port_forwarding(pData, ethaddr);
    16451576    return 0;
    16461577}
     1578
    16471579
    16481580int slirp_remove_redirect(PNATState pData, int is_udp, struct in_addr host_addr, int host_port,
    16491581                struct in_addr guest_addr, int guest_port)
    16501582{
    1651     struct port_forward_rule *rule = NULL;
    1652     LIST_FOREACH(rule, &pData->port_forward_rule_head, list)
    1653     {
    1654         if (   rule->proto == (is_udp ? IPPROTO_UDP : IPPROTO_TCP)
    1655             && rule->host_port == host_port
    1656             && rule->guest_port == guest_port
    1657             && rule->bind_ip.s_addr == host_addr.s_addr
    1658             && rule->guest_addr.s_addr == guest_addr.s_addr
    1659             && rule->activated)
    1660         {
    1661             LogRel(("NAT: remove redirect %s host %RTnaipv4:%d => guest %RTnaipv4:%d\n",
    1662                     rule->proto == IPPROTO_UDP ? "UDP" : "TCP",
    1663                     rule->bind_ip.s_addr, rule->host_port,
    1664                     guest_addr.s_addr, rule->guest_port));
    1665 
    1666             if (is_udp)
    1667                 udp_detach(pData, rule->so);
    1668             else
    1669                 tcp_close(pData, sototcpcb(rule->so));
    1670             LIST_REMOVE(rule, list);
    1671             RTMemFree(rule);
    1672             pData->cRedirectionsStored--;
    1673             break;
    1674         }
    1675 
    1676     }
     1583    struct port_forward_rule *rule;
     1584
     1585    rule = slirp_find_redirect(pData, is_udp, host_addr, host_port, guest_addr, guest_port);
     1586    if (rule == NULL)
     1587    {
     1588        LogRel(("NAT: unable to find redirect %s %RTnaipv4:%d -> %RTnaipv4:%d\n",
     1589                rule->proto == IPPROTO_UDP ? "UDP" : "TCP",
     1590                rule->bind_ip.s_addr, rule->host_port,
     1591                guest_addr.s_addr, rule->guest_port));
     1592        return 0;
     1593    }
     1594
     1595    LogRel(("NAT: remove redirect %s %RTnaipv4:%d -> %RTnaipv4:%d\n",
     1596            rule->proto == IPPROTO_UDP ? "UDP" : "TCP",
     1597            rule->bind_ip.s_addr, rule->host_port,
     1598            guest_addr.s_addr, rule->guest_port));
     1599
     1600    if (rule->so != NULL)
     1601    {
     1602        if (is_udp)
     1603            udp_detach(pData, rule->so);
     1604        else
     1605            tcp_close(pData, sototcpcb(rule->so));
     1606    }
     1607
     1608    LIST_REMOVE(rule, list);
     1609    RTMemFree(rule);
    16771610    return 0;
    16781611}
    16791612
    1680 void slirp_set_ethaddr_and_activate_port_forwarding(PNATState pData, const uint8_t *ethaddr, uint32_t GuestIP)
    1681 {
    1682     memcpy(client_ethaddr, ethaddr, ETH_ALEN);
    1683     if (GuestIP != INADDR_ANY)
    1684     {
    1685         slirp_arp_cache_update_or_add(pData, GuestIP, ethaddr);
    1686         activate_port_forwarding(pData, ethaddr);
    1687     }
    1688 }
    16891613
    16901614#if defined(RT_OS_WINDOWS)
  • trunk/src/VBox/Devices/Network/slirp/slirp_state.h

    r57739 r57784  
    139139    struct in_addr alias_addr;
    140140    struct in_addr special_addr;
     141    struct in_addr guest_addr_guess;
    141142
    142143    int tcp_rcvspace;
     
    298299    RTCRITSECTRW CsRwHandlerChain;
    299300    struct port_forward_rule_list port_forward_rule_head;
    300     int cRedirectionsActive;
    301     int cRedirectionsStored;
    302301    struct arp_cache_head arp_cache;
    303302    /* libalis modules' handlers*/
  • trunk/src/VBox/Devices/Network/slirp/tcp_subr.c

    r56292 r57784  
    477477    LogFlowFunc(("ENTER: inso = %R[natsock]\n", inso));
    478478
     479    if (   inso->so_laddr.s_addr == INADDR_ANY /* delayed port-forwarding? */
     480        && pData->guest_addr_guess.s_addr == INADDR_ANY)
     481    {
     482        LogRel2(("NAT: port-forward: guest address unknown for %R[natsock]\n", inso));
     483        closesocket(accept(inso->s, NULL, NULL));
     484        if (inso->so_state & SS_FACCEPTONCE)
     485            tcp_close(pData, sototcpcb(inso));
     486        return;
     487    }
     488
    479489    /*
    480490     * If it's an SS_ACCEPTONCE socket, no need to socreate()
     
    503513    }
    504514
     515    if (so->so_laddr.s_addr == INADDR_ANY)
     516    {
     517        LogRel2(("NAT: port-forward: using %RTnaipv4 for %R[natsock]\n",
     518                 pData->guest_addr_guess.s_addr, inso));
     519        so->so_laddr = pData->guest_addr_guess;
     520    }
     521
    505522    (void) tcp_mss(pData, sototcpcb(so), 0);
    506523
  • trunk/src/VBox/Devices/Network/slirp/udp.c

    r57738 r57784  
    464464                 so, (long)m, addr->sin_addr.s_addr));
    465465
     466    if (so->so_laddr.s_addr == INADDR_ANY)
     467    {
     468        if (pData->guest_addr_guess.s_addr != INADDR_ANY)
     469        {
     470            LogRel2(("NAT: port-forward: using %RTnaipv4 for %R[natsock]\n",
     471                     pData->guest_addr_guess.s_addr, so));
     472            so->so_laddr = pData->guest_addr_guess;
     473        }
     474        else
     475        {
     476            LogRel2(("NAT: port-forward: guest address unknown for %R[natsock]\n", so));
     477            m_freem(pData, m);
     478            return 0;
     479        }
     480    }
     481
    466482    saddr = *addr;
    467483    if ((so->so_faddr.s_addr & RT_H2N_U32(pData->netmask)) == pData->special_addr.s_addr)
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette