VirtualBox

Changeset 49249 in vbox for trunk


Ignore:
Timestamp:
Oct 23, 2013 4:53:22 AM (11 years ago)
Author:
vboxsync
Message:

Finish DNS proxy code and hook it in.

Location:
trunk/src/VBox/NetworkServices/NAT
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/NetworkServices/NAT/Makefile.kmk

    r49119 r49249  
    5858    pxtcp.c \
    5959    pxudp.c \
     60    pxdns.c \
    6061    fwtcp.c \
    6162    fwudp.c \
  • trunk/src/VBox/NetworkServices/NAT/VBoxNetLwipNAT.cpp

    r49210 r49249  
    193193    STDMETHOD(HandleEvent)(VBoxEventType_T aEventType, IEvent *pEvent);
    194194
     195    const char **getHostNameservers();
     196
    195197    RTSEMEVENT hSemSVC;
    196198    /* Only for debug needs, by default NAT service should load rules from SVC
     
    375377            strHostAddr.setNull();
    376378            strGuestAddr.setNull();
     379            break;
     380        }
     381
     382        case VBoxEventType_OnHostNameResolutionConfigurationChange:
     383        {
     384            const char **ppcszNameServers = getHostNameservers();
     385            err_t error;
     386
     387            error = tcpip_callback_with_block(pxdns_set_nameservers,
     388                                              ppcszNameServers,
     389                                              /* :block */ 0);
     390            if (error != ERR_OK && ppcszNameServers != NULL)
     391            {
     392                RTMemFree(ppcszNameServers);
     393            }
    377394            break;
    378395        }
     
    765782    m_src6.sin6_len = sizeof(m_src6);
    766783#endif
     784    m_ProxyOptions.nameservers = NULL;
    767785
    768786    m_LwipNetIf.name[0] = 'N';
     
    10431061    }
    10441062
     1063    m_ProxyOptions.nameservers = getHostNameservers();
     1064
    10451065    /* end of COM initialization */
    10461066
     
    10671087    LogFlowFuncLeaveRC(rc);
    10681088    return rc;
     1089}
     1090
     1091
     1092const char **VBoxNetLwipNAT::getHostNameservers()
     1093{
     1094    HRESULT hrc;
     1095
     1096    if (m_host.isNull())
     1097    {
     1098        return NULL;
     1099    }
     1100
     1101    com::SafeArray<BSTR> aNameServers;
     1102    hrc = m_host->COMGETTER(NameServers)(ComSafeArrayAsOutParam(aNameServers));
     1103    if (FAILED(hrc))
     1104    {
     1105        return NULL;
     1106    }
     1107
     1108    const size_t cNameServers = aNameServers.size();
     1109    if (cNameServers == 0)
     1110    {
     1111        return NULL;
     1112    }
     1113
     1114    const char **ppcszNameServers =
     1115        (const char **)RTMemAllocZ(sizeof(char *) * (cNameServers + 1));
     1116    if (ppcszNameServers == NULL)
     1117    {
     1118        return NULL;
     1119    }
     1120
     1121    size_t idxLast = 0;
     1122    for (size_t i = 0; i < cNameServers; ++i)
     1123    {
     1124        com::Utf8Str strNameServer(aNameServers[i]);
     1125        ppcszNameServers[idxLast] = RTStrDup(strNameServer.c_str());
     1126        if (ppcszNameServers[idxLast] != NULL)
     1127        {
     1128            ++idxLast;
     1129        }
     1130    }
     1131
     1132    if (idxLast == 0)
     1133    {
     1134        RTMemFree(ppcszNameServers);
     1135        return NULL;
     1136    }
     1137
     1138    return ppcszNameServers;
    10691139}
    10701140
  • trunk/src/VBox/NetworkServices/NAT/proxy.c

    r49016 r49249  
    3535static SOCKET proxy_create_socket(int, int);
    3636
    37 volatile const struct proxy_options *g_proxy_options;
     37volatile struct proxy_options *g_proxy_options;
    3838static sys_thread_t pollmgr_tid;
    3939
     
    4646 */
    4747void
    48 proxy_init(struct netif *proxy_netif, const struct proxy_options *opts)
     48proxy_init(struct netif *proxy_netif, struct proxy_options *opts)
    4949{
    5050    int status;
     
    8383
    8484    portfwd_init();
     85
     86    pxdns_init(proxy_netif);
    8587
    8688    pollmgr_tid = sys_thread_new("pollmgr_thread",
  • trunk/src/VBox/NetworkServices/NAT/proxy.h

    r49149 r49249  
    3737    const struct sockaddr_in6 *src6;
    3838    const struct ip4_lomap_desc *lomap_desc;
     39    const char **nameservers;
    3940};
    4041
    41 extern volatile const struct proxy_options *g_proxy_options;
     42extern volatile struct proxy_options *g_proxy_options;
    4243extern struct netif *g_proxy_netif;
    4344
    44 void proxy_init(struct netif *, const struct proxy_options *);
     45void proxy_init(struct netif *, struct proxy_options *);
    4546SOCKET proxy_connected_socket(int, int, ipX_addr_t *, u16_t);
    4647SOCKET proxy_bound_socket(int, int, struct sockaddr *);
     
    6970void pxudp_init(void);
    7071
     72/* pxdns.c */
     73err_t pxdns_init(struct netif *);
     74void pxdns_set_nameservers(void *);
     75
    7176
    7277#if defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS) || defined(RT_OS_WINDOWS)
  • trunk/src/VBox/NetworkServices/NAT/pxdns.c

    r49016 r49249  
    3434 * DEALINGS IN THE SOFTWARE.
    3535 */
     36#include "winutils.h"
     37
    3638#include "proxy.h"
    3739#include "proxy_pollmgr.h"
     
    4143#include "lwip/udp.h"
    4244
     45#ifndef RT_OS_WINDOWS
    4346#include <sys/poll.h>
    4447#include <sys/socket.h>
    4548#include <netinet/in.h>
     49#include <netdb.h>
     50#else
     51#include "winpoll.h"
     52#endif
    4653
    4754#include <string.h>
     55
     56
     57union sockaddr_inet {
     58    struct sockaddr sa;
     59    struct sockaddr_in sin;
     60    struct sockaddr_in6 sin6;
     61};
    4862
    4963
     
    5569 */
    5670struct pxdns {
    57     struct pollmgr_handler pmhdl;
    58 
    59     struct udp_pcb *pcb4;       /* lwIP doesn't support listening for */
    60     struct udp_pcb *pcb6;       /*  both IPv4 and IPv6 on single pcb. */
    61 
    62     SOCKET sock;
     71    SOCKET sock4;
     72    SOCKET sock6;
     73
     74    struct pollmgr_handler pmhdl4;
     75    struct pollmgr_handler pmhdl6;
     76
     77    struct udp_pcb *pcb4;
     78    struct udp_pcb *pcb6;
     79
     80    size_t generation;
     81    size_t nresolvers;
     82    union sockaddr_inet *resolvers;
    6383
    6484    u16_t id;
    65 
    66     /* XXX: TODO: support multiple, support IPv6 */
    67     struct sockaddr_in resolver_sin;
    68     socklen_t resolver_sinlen;
    6985
    7086    sys_mutex_t lock;
     
    92108
    93109    /**
    94      * XXX: TODO: to test rexmit code, rexmit to the same resolver
    95      * multiple times; to be replaced with trying the next resolver.
    96      */
    97     size_t rexmit_count;
     110     * pxdns::generation used for this request
     111     */
     112    size_t generation;
     113
     114    /**
     115     * Current index into pxdns::resolvers
     116     */
     117    size_t residx;
    98118
    99119    /**
     
    142162};
    143163
     164
     165static void pxdns_create_resolver_sockaddrs(struct pxdns *pxdns,
     166                                            const char **nameservers);
    144167
    145168static void pxdns_recv4(void *arg, struct udp_pcb *pcb, struct pbuf *p,
     
    176199    LWIP_UNUSED_ARG(proxy_netif);
    177200
    178     pxdns->pmhdl.callback = pxdns_pmgr_pump;
    179     pxdns->pmhdl.data = (void *)pxdns;
    180     pxdns->pmhdl.slot = -1;
     201    pxdns->pmhdl4.callback = pxdns_pmgr_pump;
     202    pxdns->pmhdl4.data = (void *)pxdns;
     203    pxdns->pmhdl4.slot = -1;
     204
     205    pxdns->pmhdl6.callback = pxdns_pmgr_pump;
     206    pxdns->pmhdl6.data = (void *)pxdns;
     207    pxdns->pmhdl6.slot = -1;
    181208
    182209    pxdns->pcb4 = udp_new();
     
    197224    }
    198225
    199     error = udp_bind_ip6(pxdns->pcb4, IP6_ADDR_ANY, 53);
     226    error = udp_bind_ip6(pxdns->pcb6, IP6_ADDR_ANY, 53);
    200227    if (error != ERR_OK) {
    201228        goto err_cleanup_pcb;
     
    205232    udp_recv_ip6(pxdns->pcb6, pxdns_recv6, pxdns);
    206233
    207     pxdns->sock = socket(AF_INET, SOCK_DGRAM, 0);
    208     if (pxdns->sock == INVALID_SOCKET) {
     234    pxdns->sock4 = socket(AF_INET, SOCK_DGRAM, 0);
     235    if (pxdns->sock4 == INVALID_SOCKET) {
    209236        goto err_cleanup_pcb;
    210237    }
    211238
    212     /* XXX: TODO: support multiple, support IPv6 */
    213     pxdns->resolver_sin.sin_family = AF_INET;
    214     pxdns->resolver_sin.sin_addr.s_addr = PP_HTONL(0x7f000001); /* XXX */
    215     pxdns->resolver_sin.sin_port = PP_HTONS(53);
    216 #if HAVE_SA_LEN
    217     pxdns->resolver_sin.sin_len =
    218 #endif
    219         pxdns->resolver_sinlen = sizeof(pxdns->resolver_sin);
     239    pxdns->sock6 = socket(AF_INET6, SOCK_DGRAM, 0);
     240    if (pxdns->sock6 == INVALID_SOCKET) {
     241        /* it's ok if the host doesn't support IPv6 */
     242        /* XXX: TODO: log */
     243    }
     244
     245    pxdns->generation = 0;
     246    pxdns->nresolvers = 0;
     247    pxdns->resolvers = NULL;
     248    pxdns_create_resolver_sockaddrs(pxdns, g_proxy_options->nameservers);
    220249
    221250    sys_mutex_new(&pxdns->lock);
     
    223252    pxdns->timeout_slot = 0;
    224253
    225     /* XXX: assumes pollmgr thread is not running yet */
    226     pollmgr_add(&pxdns->pmhdl, pxdns->sock, POLLIN);
     254    /* NB: assumes pollmgr thread is not running yet */
     255    pollmgr_add(&pxdns->pmhdl4, pxdns->sock4, POLLIN);
     256    if (pxdns->sock6 != INVALID_SOCKET) {
     257        pollmgr_add(&pxdns->pmhdl6, pxdns->sock6, POLLIN);
     258    }
    227259
    228260    sys_timeout(1 * 1000, pxdns_timer, pxdns);
     
    241273
    242274    return error;
     275}
     276
     277
     278/**
     279 * lwIP thread callback to set the new list of nameservers.
     280 */
     281void
     282pxdns_set_nameservers(void *arg)
     283{
     284    const char **nameservers = (const char **)arg;
     285
     286    if (g_proxy_options->nameservers != NULL) {
     287        RTMemFree(g_proxy_options->nameservers);
     288    }
     289    g_proxy_options->nameservers = nameservers;
     290
     291    pxdns_create_resolver_sockaddrs(&g_pxdns, nameservers);
     292}
     293
     294
     295/**
     296 * Use this list of nameservers to resolve guest requests.
     297 *
     298 * Runs on lwIP thread, so no new queries or retramsmits compete with
     299 * it for the use of the existing list of resolvers (to be replaced).
     300 */
     301static void
     302pxdns_create_resolver_sockaddrs(struct pxdns *pxdns, const char **nameservers)
     303{
     304    /*
     305     * XXX: TODO: Windows supports getaddrinfo(), including execution
     306     * on older version of Windows where runtime tricks hide the gory
     307     * compatibility details.
     308     *
     309     * http://msdn.microsoft.com/en-us/library/windows/desktop/ms738520%28v=vs.85%29.aspx
     310     */
     311#ifndef RT_OS_WINDOWS
     312    struct addrinfo hints;
     313#endif
     314    union sockaddr_inet *resolvers;
     315    size_t nnames, nresolvers;
     316    const char **p;
     317    int status;
     318
     319    resolvers = NULL;
     320    nresolvers = 0;
     321
     322    if (nameservers == NULL) {
     323        goto update_resolvers;
     324    }
     325
     326    nnames = 0;
     327    for (p = nameservers; *p != NULL; ++p) {
     328        ++nnames;
     329    }
     330
     331    if (nnames == 0) {
     332        goto update_resolvers;
     333    }
     334
     335    resolvers = (union sockaddr_inet *)calloc(sizeof(resolvers[0]), nnames);
     336    if (resolvers == NULL) {
     337        nresolvers = 0;
     338        goto update_resolvers;
     339    }
     340
     341#ifndef RT_OS_WINDOWS
     342    memset(&hints, 0, sizeof(hints));
     343    hints.ai_family = AF_UNSPEC;
     344    hints.ai_socktype = SOCK_DGRAM;
     345    hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;
     346
     347    for (p = nameservers; *p != NULL; ++p) {
     348        const char *name = *p;
     349        struct addrinfo *ai;
     350        status = getaddrinfo(name, /* "domain" */ "53", &hints, &ai);
     351        if (status != 0) {
     352            /* XXX: log failed resolution */
     353            continue;
     354        }
     355
     356        if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) {
     357            /* XXX: log unsupported address family */
     358            freeaddrinfo(ai);
     359            continue;
     360        }
     361
     362        if (ai->ai_addrlen > sizeof(resolvers[nresolvers])) {
     363            /* XXX: log */
     364            freeaddrinfo(ai);
     365            continue;
     366        }
     367
     368        if (ai->ai_family == AF_INET6 && pxdns->sock6 == INVALID_SOCKET) {
     369            /* no IPv6 support on the host, can't use this resolver */
     370            freeaddrinfo(ai);
     371            continue;
     372        }
     373
     374        memcpy(&resolvers[nresolvers], ai->ai_addr, ai->ai_addrlen);
     375        freeaddrinfo(ai);
     376        ++nresolvers;
     377    }
     378#endif  /* RT_OS_WINDOWS */
     379
     380    if (nresolvers == 0) {
     381        if (resolvers != NULL) {
     382            free(resolvers);
     383        }
     384        resolvers = NULL;
     385    }
     386
     387  update_resolvers:
     388    ++pxdns->generation;
     389    if (pxdns->resolvers != NULL) {
     390        free(pxdns->resolvers);
     391    }
     392    pxdns->resolvers = resolvers;
     393    pxdns->nresolvers = nresolvers;
    243394}
    244395
     
    447598    int sent;
    448599
     600    if (pxdns->nresolvers == 0) {
     601        /* nothing we can do */
     602        pbuf_free(p);
     603        return;
     604    }
     605
    449606    req = calloc(1, sizeof(struct request) - 1 + p->tot_len);
    450607    if (req == NULL) {
     608        pbuf_free(p);
    451609        return;
    452610    }
     
    466624    memcpy(req->data, &req->id, sizeof(u16_t));
    467625
    468     /* XXX */
    469     req->rexmit_count = 1;
    470 
     626    /* resolver to forward to */
     627    req->generation = pxdns->generation;
     628    req->residx = 0;
     629
     630    /* prepare for relaying the reply back to guest */
    471631    req->msg_reply.type = TCPIP_MSG_CALLBACK_STATIC;
    472632    req->msg_reply.sem = NULL;
     
    480640
    481641    sent = pxdns_forward_outbound(pxdns, req);
    482     while (!sent) {
     642    if (!sent) {
    483643        sent = pxdns_rexmit(pxdns, req);
    484644    }
     
    490650
    491651
     652/**
     653 * Forward request to the req::residx resolver in the pxdns::resolvers
     654 * array of upstream resolvers.
     655 *
     656 * Returns 1 on success, 0 on failure.
     657 */
    492658static int
    493659pxdns_forward_outbound(struct pxdns *pxdns, struct request *req)
    494660{
     661    union sockaddr_inet *resolver;
    495662    ssize_t nsent;
    496663
    497     DPRINTF2(("%s: req %p\n", __func__, (void *)req));
    498 
    499     nsent = sendto(pxdns->sock, req->data, req->size, 0,
    500                    (struct sockaddr *)&pxdns->resolver_sin,
    501                    pxdns->resolver_sinlen);
     664    DPRINTF2(("%s: req %p: sending to resolver #%lu\n",
     665              __func__, (void *)req, (unsigned long)req->residx));
     666
     667    LWIP_ASSERT1(req->generation == pxdns->generation);
     668    LWIP_ASSERT1(req->residx < pxdns->nresolvers);
     669    resolver = &pxdns->resolvers[req->residx];
     670
     671    if (resolver->sa.sa_family == AF_INET) {
     672        nsent = sendto(pxdns->sock4, req->data, req->size, 0,
     673                       &resolver->sa, sizeof(resolver->sin));
     674       
     675    }
     676    else if (resolver->sa.sa_family == AF_INET6) {
     677        if (pxdns->sock6 != INVALID_SOCKET) {
     678            nsent = sendto(pxdns->sock6, req->data, req->size, 0,
     679                           &resolver->sa, sizeof(resolver->sin6));
     680        }
     681        else {
     682            /* shouldn't happen, we should have weeded out IPv6 resolvers */
     683            return 0;
     684        }
     685    }
     686    else {
     687        /* shouldn't happen, we should have weeded out unsupported families */
     688        return 0;
     689    }
    502690
    503691    if ((size_t)nsent == req->size) {
     
    506694
    507695    if (nsent < 0) {
    508         perror("dnsproxy");
    509     }
    510     else if ((size_t)nsent != req->size) {
    511         DPRINTF(("%s: sent only %lu of %lu\n",
    512                  __func__, (unsigned long)nsent, (unsigned long)req->size));
     696        DPRINTF2(("%s: send: errno %d\n", __func__, errno));
     697    }
     698    else {
     699        DPRINTF2(("%s: sent only %lu of %lu\n",
     700                  __func__, (unsigned long)nsent, (unsigned long)req->size));
    513701    }
    514702    return 0; /* not sent, caller will retry as necessary */
     
    516704
    517705
     706/**
     707 * Forward request to the next resolver in the pxdns::resolvers array
     708 * of upstream resolvers if there are any left.
     709 */
    518710static int
    519711pxdns_rexmit(struct pxdns *pxdns, struct request *req)
    520712{
    521     DPRINTF2(("%s: req %p: rexmit count %lu\n",
    522               __func__, (void *)req, (unsigned long)req->rexmit_count));
    523 
    524     /* XXX: TODO: use the next resolver instead */
    525     if (req->rexmit_count == 0) {
     713    int sent;
     714
     715    if (/* __predict_false */ req->generation != pxdns->generation) {
     716        DPRINTF2(("%s: req %p: generation %lu != pxdns generation %lu\n",
     717                  __func__, (void *)req,
     718                  (unsigned long)req->generation,
     719                  (unsigned long)pxdns->generation));
    526720        return 0;
    527721    }
    528     --req->rexmit_count;
    529 
    530     return pxdns_forward_outbound(pxdns, req);
     722
     723    LWIP_ASSERT1(req->residx < pxdns->nresolvers);
     724    do {
     725        if (++req->residx == pxdns->nresolvers) {
     726            return 0;
     727        }
     728
     729        sent = pxdns_forward_outbound(pxdns, req);
     730    } while (!sent);
     731
     732    return 1;
    531733}
    532734
     
    542744
    543745    pxdns = (struct pxdns *)handler->data;
    544     LWIP_ASSERT1(handler == &pxdns->pmhdl);
    545     LWIP_ASSERT1(fd = pxdns->sock);
    546     LWIP_UNUSED_ARG(fd);
     746    LWIP_ASSERT1(handler == &pxdns->pmhdl4 || handler == &pxdns->pmhdl6);
     747    LWIP_ASSERT1(fd == (handler == &pxdns->pmhdl4 ? pxdns->sock4 : pxdns->sock6));
    547748
    548749    if (revents & ~(POLLIN|POLLERR)) {
     
    556757        int status;
    557758
    558         status = getsockopt(pxdns->sock, SOL_SOCKET,
     759        status = getsockopt(fd, SOL_SOCKET,
    559760                            SO_ERROR, &sockerr, &optlen);
    560761        if (status < 0) {
    561762            DPRINTF(("%s: sock %d: SO_ERROR failed with errno %d\n",
    562                      __func__, pxdns->sock, errno));
     763                     __func__, fd, errno));
    563764        }
    564765        else {
    565766            DPRINTF(("%s: sock %d: errno %d\n",
    566                      __func__, pxdns->sock, sockerr));
     767                     __func__, fd, sockerr));
    567768        }
    568769    }
     
    573774
    574775
    575     nread = recv(pxdns->sock, pollmgr_udpbuf, sizeof(pollmgr_udpbuf), 0);
     776    nread = recv(fd, pollmgr_udpbuf, sizeof(pollmgr_udpbuf), 0);
    576777    if (nread < 0) {
    577778        perror(__func__);
     
    585786        return POLLIN;
    586787    }
     788
     789    /* XXX: shall we proxy back RCODE=Refused responses? */
    587790
    588791    memcpy(&id, pollmgr_udpbuf, sizeof(id));
     
    594797    }
    595798
    596     DPRINTF2(("%s: reply for req=%p: client id %d -> id %d\n",
    597               __func__, (void *)req, req->client_id, req->id));
     799    DPRINTF2(("%s: reply for req=%p: id %d -> client id %d\n",
     800              __func__, (void *)req, req->id, req->client_id));
    598801
    599802    req->reply = pbuf_alloc(PBUF_RAW, nread, PBUF_RAM);
     
    629832                       ipX_2_ip(&req->client_addr), req->client_port);
    630833    if (error != ERR_OK) {
    631         DPRINTF(("%s: udp_sendto err %d\n",
     834        DPRINTF(("%s: udp_sendto err %s\n",
    632835                 __func__, proxy_lwip_strerr(error)));
    633836    }
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