~siretart/ubuntu/raring/virtualbox-ose/bug.1101867

« back to all changes in this revision

Viewing changes to src/VBox/Devices/Network/slirp/slirp.c

  • Committer: Bazaar Package Importer
  • Author(s): Felix Geyer
  • Date: 2011-01-30 23:27:25 UTC
  • mfrom: (0.3.12 upstream)
  • Revision ID: james.westby@ubuntu.com-20110130232725-2ouajjd2ggdet0zd
Tags: 4.0.2-dfsg-1ubuntu1
* Merge from Debian unstable, remaining changes:
  - Add Apport hook.
    - debian/virtualbox-ose.files/source_virtualbox-ose.py
    - debian/virtualbox-ose.install
  - Drop *-source packages.
* Drop ubuntu-01-fix-build-gcc45.patch, fixed upstream.
* Drop ubuntu-02-as-needed.patch, added to the Debian package.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* $Id: slirp.c $ */
 
1
/* $Id: slirp.c 35346 2010-12-27 16:13:13Z vboxsync $ */
2
2
/** @file
3
3
 * NAT - slirp glue.
4
4
 */
47
47
#endif
48
48
 
49
49
#include <VBox/err.h>
50
 
#include <VBox/pdmdrv.h>
 
50
#include <VBox/vmm/pdmdrv.h>
51
51
#include <iprt/assert.h>
52
52
#include <iprt/file.h>
53
53
#ifndef RT_OS_WINDOWS
285
285
    ret = pData->pfGetAdaptersAddresses(AF_INET, 0, NULL /* reserved */, pAdapterAddr, &size);
286
286
    if (ret != ERROR_BUFFER_OVERFLOW)
287
287
    {
288
 
        LogRel(("NAT: error %lu occurred on capacity detection operation\n", ret));
 
288
        Log(("NAT: error %lu occurred on capacity detection operation\n", ret));
289
289
        return -1;
290
290
    }
291
291
    if (size == 0)
292
292
    {
293
 
        LogRel(("NAT: Win socket API returns non capacity\n"));
 
293
        Log(("NAT: Win socket API returns non capacity\n"));
294
294
        return -1;
295
295
    }
296
296
 
297
297
    pAdapterAddr = RTMemAllocZ(size);
298
298
    if (!pAdapterAddr)
299
299
    {
300
 
        LogRel(("NAT: No memory available \n"));
 
300
        Log(("NAT: No memory available\n"));
301
301
        return -1;
302
302
    }
303
303
    ret = pData->pfGetAdaptersAddresses(AF_INET, 0, NULL /* reserved */, pAdapterAddr, &size);
304
304
    if (ret != ERROR_SUCCESS)
305
305
    {
306
 
        LogRel(("NAT: error %lu occurred on fetching adapters info\n", ret));
 
306
        Log(("NAT: error %lu occurred on fetching adapters info\n", ret));
307
307
        RTMemFree(pAdapterAddr);
308
308
        return -1;
309
309
    }
329
329
            pDns = RTMemAllocZ(sizeof(struct dns_entry));
330
330
            if (!pDns)
331
331
            {
332
 
                LogRel(("NAT: Can't allocate buffer for DNS entry\n"));
 
332
                Log(("NAT: Can't allocate buffer for DNS entry\n"));
333
333
                RTMemFree(pAdapterAddr);
334
334
                return VERR_NO_MEMORY;
335
335
            }
336
336
 
337
 
            LogRel(("NAT: adding %R[IP4] to DNS server list\n", &InAddr));
 
337
            Log(("NAT: adding %R[IP4] to DNS server list\n", &InAddr));
338
338
            if ((InAddr.s_addr & RT_H2N_U32_C(IN_CLASSA_NET)) == RT_N2H_U32_C(INADDR_LOOPBACK & IN_CLASSA_NET))
339
339
                pDns->de_addr.s_addr = RT_H2N_U32(RT_N2H_U32(pData->special_addr.s_addr) | CTL_ALIAS);
340
340
            else
369
369
                pDomain = RTMemAllocZ(sizeof(struct dns_domain_entry));
370
370
                if (!pDomain)
371
371
                {
372
 
                    LogRel(("NAT: not enough memory\n"));
 
372
                    Log(("NAT: not enough memory\n"));
373
373
                    RTStrFree(pszSuffix);
374
374
                    RTMemFree(pAdapterAddr);
375
375
                    return VERR_NO_MEMORY;
376
376
                }
377
377
                pDomain->dd_pszDomain = pszSuffix;
378
 
                LogRel(("NAT: adding domain name %s to search list\n", pDomain->dd_pszDomain));
 
378
                Log(("NAT: adding domain name %s to search list\n", pDomain->dd_pszDomain));
379
379
                LIST_INSERT_HEAD(&pData->pDomainList, pDomain, dd_list);
380
380
            }
381
381
        }
420
420
    char buff2[256];
421
421
    RTFILE f;
422
422
    int cNameserversFound = 0;
423
 
    int fWarnTooManyDnsServers = 0;
 
423
    bool fWarnTooManyDnsServers = false;
424
424
    struct in_addr tmp_addr;
425
425
    int rc;
426
426
    size_t bytes;
473
473
    {
474
474
        struct dns_entry *pDns = NULL;
475
475
        if (   cNameserversFound == 4
476
 
            && fWarnTooManyDnsServers == 0
 
476
            && !fWarnTooManyDnsServers
477
477
            && sscanf(buff, "nameserver%*[ \t]%255s", buff2) == 1)
478
478
        {
479
 
            fWarnTooManyDnsServers = 1;
 
479
            fWarnTooManyDnsServers = true;
480
480
            LogRel(("NAT: too many nameservers registered.\n"));
481
481
        }
482
482
        if (   sscanf(buff, "nameserver%*[ \t]%255s", buff2) == 1
489
489
            pDns = RTMemAllocZ(sizeof (struct dns_entry));
490
490
            if (!pDns)
491
491
            {
492
 
                LogRel(("can't alloc memory for DNS entry\n"));
 
492
                Log(("can't alloc memory for DNS entry\n"));
493
493
                return -1;
494
494
            }
495
495
 
523
523
                pDomain = RTMemAllocZ(sizeof(struct dns_domain_entry));
524
524
                if (!pDomain)
525
525
                {
526
 
                    LogRel(("NAT: not enought memory to add domain list\n"));
 
526
                    Log(("NAT: not enought memory to add domain list\n"));
527
527
                    return VERR_NO_MEMORY;
528
528
                }
529
529
                pDomain->dd_pszDomain = RTStrDup(tok);
530
 
                LogRel(("NAT: adding domain name %s to search list\n", pDomain->dd_pszDomain));
 
530
                Log(("NAT: adding domain name %s to search list\n", pDomain->dd_pszDomain));
531
531
                LIST_INSERT_HEAD(&pData->pDomainList, pDomain, dd_list);
532
532
            }
533
533
        }
616
616
    rc = bootp_dhcp_init(pData);
617
617
    if (rc != 0)
618
618
    {
619
 
        LogRel(("NAT: DHCP server initialization was failed\n"));
 
619
        Log(("NAT: DHCP server initialization was failed\n"));
620
620
        return VINF_NAT_DNS;
621
621
    }
622
622
    debug_init();
643
643
    }
644
644
    if (i32AliasMode & ~(PKT_ALIAS_LOG|PKT_ALIAS_SAME_PORTS|PKT_ALIAS_PROXY_ONLY))
645
645
    {
646
 
        LogRel(("NAT: alias mode %x is ignored\n", i32AliasMode));
 
646
        Log(("NAT: alias mode %x is ignored\n", i32AliasMode));
647
647
        i32AliasMode = 0;
648
648
    }
649
649
    pData->i32AliasMode = i32AliasMode;
654
654
        pData->proxy_alias = LibAliasInit(pData, NULL);
655
655
        if (pData->proxy_alias == NULL)
656
656
        {
657
 
            LogRel(("NAT: LibAlias default rule wasn't initialized\n"));
 
657
            Log(("NAT: LibAlias default rule wasn't initialized\n"));
658
658
            AssertMsgFailed(("NAT: LibAlias default rule wasn't initialized\n"));
659
659
        }
660
660
        flags = LibAliasSetMode(pData->proxy_alias, 0, 0);
790
790
#ifdef RT_OS_WINDOWS
791
791
    WSACleanup();
792
792
#endif
 
793
#ifndef VBOX_WITH_SLIRP_BSD_SBUF
793
794
#ifdef LOG_ENABLED
794
795
    Log(("\n"
795
796
         "NAT statistics\n"
805
806
         "\n"
806
807
         "\n"));
807
808
#endif
 
809
#endif
808
810
    RTMemFree(pData);
809
811
}
810
812
 
937
939
         * Set for writing if we are connected, can send more, and
938
940
         * we have something to send
939
941
         */
940
 
        if (CONN_CANFSEND(so) && so->so_rcv.sb_cc)
 
942
        if (CONN_CANFSEND(so) && SBUF_LEN(&so->so_rcv))
941
943
        {
942
944
            STAM_COUNTER_INC(&pData->StatTCPHot);
943
945
            TCP_ENGAGE_EVENT1(so, writefds);
947
949
         * Set for reading (and urgent data) if we are connected, can
948
950
         * receive more, and we have room for it XXX /2 ?
949
951
         */
950
 
        if (CONN_CANFRCV(so) && (so->so_snd.sb_cc < (so->so_snd.sb_datalen/2)))
 
952
        /* @todo: vvl - check which predicat here will be more useful here in rerm of new sbufs. */
 
953
        if (CONN_CANFRCV(so) && (SBUF_LEN(&so->so_snd) < (SBUF_SIZE(&so->so_snd)/2)))
951
954
        {
952
955
            STAM_COUNTER_INC(&pData->StatTCPHot);
953
956
            TCP_ENGAGE_EVENT2(so, readfds, xfds);
1192
1195
                    TCP_OUTPUT(pData, sototcpcb(so));
1193
1196
                else
1194
1197
                {
1195
 
                    Log2(("%R[natsock] errno %d:%s\n", so, errno, strerror(errno)));
 
1198
                    Log2(("%R[natsock] errno %d (%s)\n", so, errno, strerror(errno)));
1196
1199
                    break;
1197
1200
                }
1198
1201
            }
1383
1386
AssertCompileSize(struct arphdr, 28);
1384
1387
 
1385
1388
/**
1386
 
 * @note This function will free m! 
 
1389
 * @note This function will free m!
1387
1390
 */
1388
1391
static void arp_input(PNATState pData, struct mbuf *m)
1389
1392
{
1412
1415
            mr->m_data += ETH_HLEN;
1413
1416
            rah = mtod(mr, struct arphdr *);
1414
1417
            mr->m_len = sizeof(struct arphdr);
1415
 
            Assert(mr);
1416
1418
            memcpy(reh->h_source, eh->h_source, ETH_ALEN); /* XXX: if_encap will swap src and dst*/
1417
1419
            if (   0
1418
1420
#ifdef VBOX_WITH_NAT_SERVICE
1488
1490
    m->m_len = cbBuf;
1489
1491
    if (cbBuf < ETH_HLEN)
1490
1492
    {
1491
 
        LogRel(("NAT: packet having size %d has been ignored\n", m->m_len));
 
1493
        Log(("NAT: packet having size %d has been ignored\n", m->m_len));
1492
1494
        m_freem(pData, m);
1493
1495
        return;
1494
1496
    }
1541
1543
{
1542
1544
    struct ethhdr *eh;
1543
1545
    uint8_t *buf = NULL;
 
1546
    uint8_t *mbuf = NULL;
1544
1547
    size_t mlen = 0;
1545
1548
    STAM_PROFILE_START(&pData->StatIF_encap, a);
1546
1549
 
1548
1551
    m->m_data -= ETH_HLEN;
1549
1552
    m->m_len += ETH_HLEN;
1550
1553
    eh = mtod(m, struct ethhdr *);
 
1554
    mlen = m->m_len;
1551
1555
 
1552
1556
    if (memcmp(eh->h_source, special_ethaddr, ETH_ALEN) != 0)
1553
1557
    {
1561
1565
            goto done;
1562
1566
        }
1563
1567
    }
1564
 
    mlen = m_length(m, NULL);
1565
 
    buf = RTMemAlloc(mlen);
1566
 
    if (!buf)
 
1568
    /*
 
1569
     * we're processing the chain, that isn't not expected.
 
1570
     */
 
1571
    Assert((!m->m_next));
 
1572
    if (m->m_next)
1567
1573
    {
1568
 
        LogRel(("NAT: Can't alloc memory for outgoing buffer\n"));
 
1574
        Log(("NAT: if_encap's recived the chain, dropping...\n"));
1569
1575
        m_freem(pData, m);
1570
1576
        goto done;
1571
1577
    }
 
1578
    mbuf = mtod(m, uint8_t *);
1572
1579
    eh->h_proto = RT_H2N_U16(eth_proto);
1573
 
    m_copydata(m, 0, mlen, (char *)buf);
1574
1580
    if (flags & ETH_ENCAP_URG)
1575
 
        slirp_urg_output(pData->pvUser, m, buf, mlen);
 
1581
        slirp_urg_output(pData->pvUser, m, mbuf, mlen);
1576
1582
    else
1577
 
        slirp_output(pData->pvUser, m, buf, mlen);
 
1583
        slirp_output(pData->pvUser, m, mbuf, mlen);
1578
1584
done:
1579
1585
    STAM_PROFILE_STOP(&pData->StatIF_encap, a);
1580
1586
}
1649
1655
        }
1650
1656
 
1651
1657
#if !defined(VBOX_WITH_NAT_SERVICE)
1652
 
        if (rule->guest_addr.s_addr != guest_addr)
 
1658
        if (   rule->guest_addr.s_addr != guest_addr
 
1659
            && rule->guest_addr.s_addr != INADDR_ANY)
1653
1660
            continue;
 
1661
        if (rule->guest_addr.s_addr == INADDR_ANY)
 
1662
            rule->guest_addr.s_addr = guest_addr;
1654
1663
#endif
1655
1664
 
1656
1665
        LogRel(("NAT: set redirect %s host port %d => guest port %d @ %R[IP4]\n",
1657
 
               (rule->proto == IPPROTO_UDP?"UDP":"TCP"),
1658
 
               rule->host_port, rule->guest_port, &guest_addr));
 
1666
               rule->proto == IPPROTO_UDP ? "UDP" : "TCP", rule->host_port, rule->guest_port, &guest_addr));
1659
1667
 
1660
1668
        if (rule->proto == IPPROTO_UDP)
1661
1669
            so = udp_listen(pData, rule->bind_ip.s_addr, RT_H2N_U16(rule->host_port), guest_addr,
1695
1703
 
1696
1704
        so->so_la = lib;
1697
1705
        rule->activated = 1;
 
1706
        rule->so = so;
1698
1707
        pData->cRedirectionsActive++;
1699
1708
        continue;
1700
1709
 
1719
1728
 * could get it from VM configuration in DrvNAT or Service, the idea is activating
1720
1729
 * corresponding port-forwarding
1721
1730
 */
1722
 
int slirp_redir(PNATState pData, int is_udp, struct in_addr host_addr, int host_port,
 
1731
int slirp_add_redirect(PNATState pData, int is_udp, struct in_addr host_addr, int host_port,
1723
1732
                struct in_addr guest_addr, int guest_port, const uint8_t *ethaddr)
1724
1733
{
1725
1734
    struct port_forward_rule *rule = NULL;
1726
 
    Assert(memcmp(ethaddr, zerro_ethaddr, ETH_ALEN) == 0);
 
1735
    Assert(ethaddr);
 
1736
    LIST_FOREACH(rule, &pData->port_forward_rule_head, list)
 
1737
    {
 
1738
        if (   rule->proto == (is_udp ? IPPROTO_UDP : IPPROTO_TCP)
 
1739
            && rule->host_port == host_port
 
1740
            && rule->bind_ip.s_addr == host_addr.s_addr
 
1741
            && rule->guest_port == guest_port
 
1742
#ifndef VBOX_WITH_NAT_SERVICE
 
1743
            && rule->guest_addr.s_addr == guest_addr.s_addr
 
1744
#endif
 
1745
            )
 
1746
                return 0; /* rule has been already registered */
 
1747
    }
1727
1748
 
1728
1749
    rule = RTMemAllocZ(sizeof(struct port_forward_rule));
1729
1750
    if (rule == NULL)
1740
1761
    /* @todo add mac address */
1741
1762
    LIST_INSERT_HEAD(&pData->port_forward_rule_head, rule, list);
1742
1763
    pData->cRedirectionsStored++;
 
1764
    /* activate port-forwarding if guest has already got assigned IP */
 
1765
    if (memcmp(ethaddr, zerro_ethaddr, ETH_ALEN))
 
1766
        activate_port_forwarding(pData, ethaddr);
 
1767
    return 0;
 
1768
}
 
1769
 
 
1770
int slirp_remove_redirect(PNATState pData, int is_udp, struct in_addr host_addr, int host_port,
 
1771
                struct in_addr guest_addr, int guest_port)
 
1772
{
 
1773
    struct port_forward_rule *rule = NULL;
 
1774
    LIST_FOREACH(rule, &pData->port_forward_rule_head, list)
 
1775
    {
 
1776
        if (   rule->proto == (is_udp ? IPPROTO_UDP : IPPROTO_TCP)
 
1777
            && rule->host_port == host_port
 
1778
            && rule->guest_port == guest_port
 
1779
            && rule->bind_ip.s_addr == host_addr.s_addr
 
1780
#ifndef VBOX_WITH_NAT_SERVICE
 
1781
            && rule->guest_addr.s_addr == guest_addr.s_addr
 
1782
#endif
 
1783
            && rule->activated)
 
1784
        {
 
1785
            LogRel(("NAT: remove redirect %s host port %d => guest port %d @ %R[IP4]\n",
 
1786
                   rule->proto == IPPROTO_UDP ? "UDP" : "TCP", rule->host_port, rule->guest_port, &guest_addr));
 
1787
 
 
1788
            LibAliasUninit(rule->so->so_la);
 
1789
            if (is_udp)
 
1790
                udp_detach(pData, rule->so);
 
1791
            else
 
1792
                tcp_close(pData, sototcpcb(rule->so));
 
1793
            LIST_REMOVE(rule, list);
 
1794
            RTMemFree(rule);
 
1795
            pData->cRedirectionsStored--;
 
1796
            break;
 
1797
        }
 
1798
 
 
1799
    }
1743
1800
    return 0;
1744
1801
}
1745
1802
 
1808
1865
 
1809
1866
void slirp_set_dhcp_TFTP_prefix(PNATState pData, const char *tftpPrefix)
1810
1867
{
1811
 
    Log2(("tftp_prefix:%s\n", tftpPrefix));
 
1868
    Log2(("tftp_prefix: %s\n", tftpPrefix));
1812
1869
    tftp_prefix = tftpPrefix;
1813
1870
}
1814
1871
 
1815
1872
void slirp_set_dhcp_TFTP_bootfile(PNATState pData, const char *bootFile)
1816
1873
{
1817
 
    Log2(("bootFile:%s\n", bootFile));
 
1874
    Log2(("bootFile: %s\n", bootFile));
1818
1875
    bootp_filename = bootFile;
1819
1876
}
1820
1877
 
1821
1878
void slirp_set_dhcp_next_server(PNATState pData, const char *next_server)
1822
1879
{
1823
 
    Log2(("next_server:%s\n", next_server));
 
1880
    Log2(("next_server: %s\n", next_server));
1824
1881
    if (next_server == NULL)
1825
1882
        pData->tftp_server.s_addr = RT_H2N_U32(RT_N2H_U32(pData->special_addr.s_addr) | CTL_TFTP);
1826
1883
    else
1942
1999
    m = m_getcl(pData, M_NOWAIT, MT_HEADER, M_PKTHDR);
1943
2000
    if (m == NULL)
1944
2001
    {
1945
 
        LogRel(("NAT: Can't alloc mbuf for ARP request\n"));
 
2002
        Log(("NAT: Can't alloc mbuf for ARP request\n"));
1946
2003
        return;
1947
2004
    }
1948
2005
    ehdr = mtod(m, struct ethhdr *);
1996
2053
    ac = RTMemAllocZ(sizeof(struct arp_cache_entry));
1997
2054
    if (ac == NULL)
1998
2055
    {
1999
 
        LogRel(("NAT: Can't allocate arp cache entry\n"));
 
2056
        Log(("NAT: Can't allocate arp cache entry\n"));
2000
2057
        return;
2001
2058
    }
2002
2059
    ac->ip = ip;
2011
2068
        LogRel(("NAT: mtu(%d) is out of range (20;16000] mtu forcely assigned to 1500\n", mtu));
2012
2069
        mtu = 1500;
2013
2070
    }
 
2071
    /* MTU is maximum transition unit on */
2014
2072
    if_mtu =
2015
2073
    if_mru = mtu;
2016
2074
}
 
2075
 
 
2076
/**
 
2077
 * Info handler.
 
2078
 */
 
2079
void slirp_info(PNATState pData, PCDBGFINFOHLP pHlp, const char *pszArgs)
 
2080
{
 
2081
    struct socket *so, *so_next;
 
2082
    struct arp_cache_entry *ac;
 
2083
    struct port_forward_rule *rule;
 
2084
 
 
2085
    pHlp->pfnPrintf(pHlp, "NAT parameters: MTU=%d\n", if_mtu);
 
2086
    pHlp->pfnPrintf(pHlp, "NAT TCP ports:\n");
 
2087
    QSOCKET_FOREACH(so, so_next, tcp)
 
2088
    /* { */
 
2089
        pHlp->pfnPrintf(pHlp, " %R[natsock]\n", so);
 
2090
    }
 
2091
 
 
2092
    pHlp->pfnPrintf(pHlp, "NAT UDP ports:\n");
 
2093
    QSOCKET_FOREACH(so, so_next, udp)
 
2094
    /* { */
 
2095
        pHlp->pfnPrintf(pHlp, " %R[natsock]\n", so);
 
2096
    }
 
2097
 
 
2098
    pHlp->pfnPrintf(pHlp, "NAT ARP cache:\n");
 
2099
    LIST_FOREACH(ac, &pData->arp_cache, list)
 
2100
    {
 
2101
        pHlp->pfnPrintf(pHlp, " %R[IP4] %R[ether]\n", &ac->ip, &ac->ether);
 
2102
    }
 
2103
 
 
2104
    pHlp->pfnPrintf(pHlp, "NAT rules:\n");
 
2105
    LIST_FOREACH(rule, &pData->port_forward_rule_head, list)
 
2106
    {
 
2107
        pHlp->pfnPrintf(pHlp, " %s %d => %R[IP4]:%d %c\n",
 
2108
                        rule->proto == IPPROTO_UDP ? "UDP" : "TCP",
 
2109
                        rule->host_port, &rule->guest_addr.s_addr, rule->guest_port,
 
2110
                        rule->activated ? ' ' : '*');
 
2111
    }
 
2112
}