~ubuntu-branches/ubuntu/raring/virtualbox-ose/raring

« 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: 2009-12-18 16:44:29 UTC
  • mfrom: (0.3.3 upstream) (0.4.6 squeeze)
  • Revision ID: james.westby@ubuntu.com-20091218164429-jd34ccexpv5na11a
Tags: 3.1.2-dfsg-1ubuntu1
* Merge from Debian unstable (LP: #498219), remaining changes:
  - Disable update action
    - debian/patches/u01-disable-update-action.dpatch
  - VirtualBox should go in Accessories, not in System tools (LP: #288590)
    - debian/virtualbox-ose-qt.files/virtualbox-ose.desktop
  - Add Apport hook
    - debian/virtualbox-ose.files/source_virtualbox-ose.py
    - debian/virtualbox-ose.install
  - Add Launchpad integration
    - debian/control
    - debian/lpi-bug.xpm
    - debian/patches/u02-lp-integration.dpatch
* Fixes the following bugs:
  - Kernel module fails to build with Linux >= 2.6.32 (LP: #474625)
  - X.Org drivers need to be rebuilt against X-Server 1.7 (LP: #495935)
  - The *-source packages try to build the kernel modules even though the
    kernel headers aren't available (LP: #473334)
* Replace *-source packages with transitional packages for *-dkms.
* Adapt u01-disable-update-action.dpatch and u02-lp-integration.dpatch for
  new upstream version.

Show diffs side-by-side

added added

removed removed

Lines of Context:
6
6
#include <VBox/err.h>
7
7
#include <VBox/pdmdrv.h>
8
8
#include <iprt/assert.h>
 
9
#include <iprt/file.h>
9
10
#ifndef RT_OS_WINDOWS
10
11
# include <sys/ioctl.h>
11
12
# include <poll.h>
14
15
# define _WINSOCK2API_
15
16
# include <IPHlpApi.h>
16
17
#endif
17
 
#ifdef VBOX_WITH_SLIRP_ALIAS
18
 
# include <alias.h>
19
 
#endif
 
18
#include <alias.h>
20
19
 
21
20
#if !defined(RT_OS_WINDOWS)
22
21
 
23
22
#  define DO_ENGAGE_EVENT1(so, fdset, label)                        \
24
23
    do {                                                            \
25
24
        if (    so->so_poll_index != -1                             \
26
 
             && so->s == polls[so->so_poll_index].fd) {             \
27
 
             polls[so->so_poll_index].events |= N_(fdset ## _poll); \
28
 
             break; /* out of this loop */                          \
 
25
            && so->s == polls[so->so_poll_index].fd) {              \
 
26
            polls[so->so_poll_index].events |= N_(fdset ## _poll);  \
 
27
            break; /* out of this loop */                           \
29
28
        }                                                           \
30
29
        AssertRelease(poll_index < (nfds));                         \
31
30
        AssertRelease(poll_index >= 0 && poll_index < (nfds));      \
34
33
        polls[poll_index].events = N_(fdset ## _poll);              \
35
34
        polls[poll_index].revents = 0;                              \
36
35
        poll_index++;                                               \
37
 
    } while(0)
38
 
 
39
 
 
40
 
#  define DO_ENGAGE_EVENT2(so, fdset1, fdset2, label)           \
41
 
    do {                                                        \
42
 
        if (    so->so_poll_index != -1                         \
43
 
             && so->s == polls[so->so_poll_index].fd) {         \
44
 
             polls[so->so_poll_index].events |=                 \
45
 
                 N_(fdset1 ## _poll) | N_(fdset1 ## _poll);     \
46
 
             break; /* out of this loop */                      \
47
 
        }                                                       \
48
 
        AssertRelease(poll_index < (nfds));                     \
49
 
        polls[poll_index].fd = (so)->s;                         \
50
 
        (so)->so_poll_index = poll_index;                       \
51
 
        polls[poll_index].events =                              \
52
 
            N_(fdset1 ## _poll) | N_(fdset1 ## _poll);          \
53
 
        poll_index++;                                           \
54
 
    } while(0)
 
36
    } while (0)
 
37
 
 
38
 
 
39
#  define DO_ENGAGE_EVENT2(so, fdset1, fdset2, label)               \
 
40
    do {                                                            \
 
41
        if (    so->so_poll_index != -1                             \
 
42
            && so->s == polls[so->so_poll_index].fd) {              \
 
43
            polls[so->so_poll_index].events |=                      \
 
44
                N_(fdset1 ## _poll) | N_(fdset1 ## _poll);          \
 
45
            break; /* out of this loop */                           \
 
46
        }                                                           \
 
47
        AssertRelease(poll_index < (nfds));                         \
 
48
        polls[poll_index].fd = (so)->s;                             \
 
49
        (so)->so_poll_index = poll_index;                           \
 
50
        polls[poll_index].events =                                  \
 
51
            N_(fdset1 ## _poll) | N_(fdset1 ## _poll);              \
 
52
        poll_index++;                                               \
 
53
    } while (0)
55
54
 
56
55
#  define DO_POLL_EVENTS(rc, error, so, events, label) do {} while (0)
57
56
 
58
 
#  define DO_CHECK_FD_SET(so, events, fdset) (  ((so)->so_poll_index != -1)                                     \
59
 
                                                && ((so)->so_poll_index <= ndfs)                                \
60
 
                                                && ((so)->s == polls[so->so_poll_index].fd)                     \
61
 
                                                && (polls[(so)->so_poll_index].revents & N_(fdset ## _poll)))
62
 
#  define DO_UNIX_CHECK_FD_SET(so, events, fdset ) DO_CHECK_FD_SET((so), (events), fdset) /*specific for Unix API */
63
 
#  define DO_WIN_CHECK_FD_SET(so, events, fdset ) 0 /* specific for Windows Winsock API */
 
57
#  define DO_CHECK_FD_SET(so, events, fdset)                        \
 
58
      (   ((so)->so_poll_index != -1)                               \
 
59
       && ((so)->so_poll_index <= ndfs)                             \
 
60
       && ((so)->s == polls[so->so_poll_index].fd)                  \
 
61
       && (polls[(so)->so_poll_index].revents & N_(fdset ## _poll)))
 
62
 
 
63
   /* specific for Unix API */
 
64
#  define DO_UNIX_CHECK_FD_SET(so, events, fdset ) DO_CHECK_FD_SET((so), (events), fdset) 
 
65
   /* specific for Windows Winsock API */
 
66
#  define DO_WIN_CHECK_FD_SET(so, events, fdset ) 0 
64
67
 
65
68
# ifndef RT_OS_WINDOWS
66
69
 
84
87
    } while (0)
85
88
# else /* !RT_OS_WINDOWS */
86
89
#  define DO_WIN_CHECK_FD_SET(so, events, fdset ) DO_CHECK_FD_SET((so), (events), fdset)
87
 
#  define ICMP_ENGAGE_EVENT(so, fdset) do {} while(0)
 
90
#  define ICMP_ENGAGE_EVENT(so, fdset) do {} while (0)
88
91
#endif /* RT_OS_WINDOWS */
89
92
 
90
93
#else /* defined(RT_OS_WINDOWS) */
93
96
 * On Windows, we will be notified by IcmpSendEcho2() when the response arrives.
94
97
 * So no call to WSAEventSelect necessary.
95
98
 */
96
 
# define ICMP_ENGAGE_EVENT(so, fdset)                do {} while(0)
 
99
# define ICMP_ENGAGE_EVENT(so, fdset)                do {} while (0)
97
100
 
98
101
# define DO_ENGAGE_EVENT1(so, fdset1, label)                                                    \
99
102
    do {                                                                                        \
105
108
            LogRel(("WSAEventSelect (" #label ") error %d (so=%x, socket=%s, event=%x)\n",      \
106
109
                        error, (so), (so)->s, VBOX_SOCKET_EVENT));                              \
107
110
        }                                                                                       \
108
 
    } while(0);                                                                                 \
 
111
    } while (0);                                                                                 \
109
112
    CONTINUE(label)
110
113
 
111
114
# define DO_ENGAGE_EVENT2(so, fdset1, fdset2, label) \
190
193
 
191
194
#define LOG_NAT_SOCK(so, proto, winevent, r_fdset, w_fdset, x_fdset) DO_LOG_NAT_SOCK((so), proto, (winevent), r_fdset, w_fdset, x_fdset)
192
195
 
 
196
static void activate_port_forwarding(PNATState, const uint8_t *pEther);
 
197
 
193
198
static const uint8_t special_ethaddr[6] =
194
199
{
195
200
    0x52, 0x54, 0x00, 0x12, 0x35, 0x00
210
215
                               struct in_addr *pdns_addr,
211
216
                               const char **ppszDomain)
212
217
{
213
 
    /* Get amount of memory required for operation */
214
218
    ULONG flags = GAA_FLAG_INCLUDE_PREFIX; /*GAA_FLAG_INCLUDE_ALL_INTERFACES;*/ /* all interfaces registered in NDIS */
215
 
    PIP_ADAPTER_ADDRESSES addresses = NULL;
216
 
    PIP_ADAPTER_ADDRESSES addr = NULL;
217
 
    PIP_ADAPTER_DNS_SERVER_ADDRESS dns = NULL;
218
 
    ULONG size = 0;
 
219
    PIP_ADAPTER_ADDRESSES pAdapterAddr = NULL;
 
220
    PIP_ADAPTER_ADDRESSES pAddr = NULL;
 
221
    PIP_ADAPTER_DNS_SERVER_ADDRESS pDnsAddr = NULL;
 
222
    ULONG size;
219
223
    int wlen = 0;
220
 
    char *suffix;
221
 
    struct dns_entry *da = NULL;
222
 
    struct dns_domain_entry *dd = NULL;
 
224
    char *pszSuffix;
 
225
    struct dns_domain_entry *pDomain = NULL;
223
226
    ULONG ret = ERROR_SUCCESS;
224
227
 
225
228
    /* @todo add SKIPing flags to get only required information */
226
229
 
227
 
    ret = pData->pfGetAdaptersAddresses(AF_INET, 0, NULL /* reserved */, addresses, &size);
 
230
    /* determine size of buffer */
 
231
    size = 0;
 
232
    ret = pData->pfGetAdaptersAddresses(AF_INET, 0, NULL /* reserved */, pAdapterAddr, &size);
228
233
    if (ret != ERROR_BUFFER_OVERFLOW)
229
234
    {
230
235
        LogRel(("NAT: error %lu occurred on capacity detection operation\n", ret));
231
236
        return -1;
232
237
    }
233
 
 
234
238
    if (size == 0)
235
239
    {
236
240
        LogRel(("NAT: Win socket API returns non capacity\n"));
237
241
        return -1;
238
242
    }
239
243
 
240
 
    addresses = RTMemAllocZ(size);
241
 
    if (addresses == NULL)
 
244
    pAdapterAddr = RTMemAllocZ(size);
 
245
    if (!pAdapterAddr)
242
246
    {
243
247
        LogRel(("NAT: No memory available \n"));
244
248
        return -1;
245
249
    }
246
 
 
247
 
    ret = pData->pfGetAdaptersAddresses(AF_INET, 0, NULL /* reserved */, addresses, &size);
 
250
    ret = pData->pfGetAdaptersAddresses(AF_INET, 0, NULL /* reserved */, pAdapterAddr, &size);
248
251
    if (ret != ERROR_SUCCESS)
249
252
    {
250
253
        LogRel(("NAT: error %lu occurred on fetching adapters info\n", ret));
251
 
        RTMemFree(addresses);
 
254
        RTMemFree(pAdapterAddr);
252
255
        return -1;
253
256
    }
254
 
    addr = addresses;
255
 
    while(addr != NULL)
 
257
 
 
258
    for (pAddr = pAdapterAddr; pAddr != NULL; pAddr = pAddr->Next)
256
259
    {
257
260
        int found;
258
 
        if (addr->OperStatus != IfOperStatusUp)
259
 
            goto next;
260
 
        dns = addr->FirstDnsServerAddress;
261
 
        while (dns != NULL)
 
261
        if (pAddr->OperStatus != IfOperStatusUp)
 
262
            continue;
 
263
 
 
264
        for (pDnsAddr = pAddr->FirstDnsServerAddress; pDnsAddr != NULL; pDnsAddr = pDnsAddr->Next)
262
265
        {
263
 
            struct sockaddr *saddr = dns->Address.lpSockaddr;
264
 
            if (saddr->sa_family != AF_INET)
265
 
                goto next_dns;
 
266
            struct sockaddr *SockAddr = pDnsAddr->Address.lpSockaddr;
 
267
            struct in_addr  InAddr;
 
268
            struct dns_entry *pDns;
 
269
 
 
270
            if (SockAddr->sa_family != AF_INET)
 
271
                continue;
 
272
 
 
273
            InAddr = ((struct sockaddr_in *)SockAddr)->sin_addr;
 
274
 
266
275
            /* add dns server to list */
267
 
            da = RTMemAllocZ(sizeof(struct dns_entry));
268
 
            if (da == NULL)
 
276
            pDns = RTMemAllocZ(sizeof(struct dns_entry));
 
277
            if (!pDns)
269
278
            {
270
279
                LogRel(("NAT: Can't allocate buffer for DNS entry\n"));
271
 
                RTMemFree(addresses);
 
280
                RTMemFree(pAdapterAddr);
272
281
                return VERR_NO_MEMORY;
273
282
            }
274
 
            LogRel(("NAT: adding %R[IP4] to DNS server list\n", &((struct sockaddr_in *)saddr)->sin_addr));
275
 
            if ((((struct sockaddr_in *)saddr)->sin_addr.s_addr & htonl(IN_CLASSA_NET)) == ntohl(INADDR_LOOPBACK & IN_CLASSA_NET)) {
276
 
                da->de_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_ALIAS);
277
 
            }
 
283
 
 
284
            LogRel(("NAT: adding %R[IP4] to DNS server list\n", &InAddr));
 
285
            if ((InAddr.s_addr & htonl(IN_CLASSA_NET)) == ntohl(INADDR_LOOPBACK & IN_CLASSA_NET))
 
286
                pDns->de_addr.s_addr = htonl(ntohl(pData->special_addr.s_addr) | CTL_ALIAS);
278
287
            else
 
288
                pDns->de_addr.s_addr = InAddr.s_addr;
 
289
 
 
290
            TAILQ_INSERT_HEAD(&pData->pDnsList, pDns, de_list);
 
291
 
 
292
            if (pAddr->DnsSuffix == NULL)
 
293
                continue;
 
294
 
 
295
            /* uniq */
 
296
            RTUtf16ToUtf8(pAddr->DnsSuffix, &pszSuffix);
 
297
            if (!pszSuffix || strlen(pszSuffix) == 0)
279
298
            {
280
 
                da->de_addr.s_addr = ((struct sockaddr_in *)saddr)->sin_addr.s_addr;
281
 
            }
282
 
            TAILQ_INSERT_HEAD(&pData->dns_list_head, da, de_list);
283
 
 
284
 
            if (addr->DnsSuffix == NULL)
285
 
                goto next_dns;
286
 
 
287
 
            /*uniq*/
288
 
            RTUtf16ToUtf8(addr->DnsSuffix, &suffix);
289
 
 
290
 
            if (!suffix || strlen(suffix) == 0) {
291
 
                RTStrFree(suffix);
292
 
                goto next_dns;
 
299
                RTStrFree(pszSuffix);
 
300
                continue;
293
301
            }
294
302
 
295
303
            found = 0;
296
 
            LIST_FOREACH(dd, &pData->dns_domain_list_head, dd_list)
 
304
            LIST_FOREACH(pDomain, &pData->pDomainList, dd_list)
297
305
            {
298
 
                if (   dd->dd_pszDomain != NULL
299
 
                    && strcmp(dd->dd_pszDomain, suffix) == 0)
 
306
                if (   pDomain->dd_pszDomain != NULL
 
307
                    && strcmp(pDomain->dd_pszDomain, pszSuffix) == 0)
300
308
                {
301
309
                    found = 1;
302
 
                    RTStrFree(suffix);
 
310
                    RTStrFree(pszSuffix);
303
311
                    break;
304
312
                }
305
313
            }
306
 
            if (found == 0)
 
314
            if (!found)
307
315
            {
308
 
                dd = RTMemAllocZ(sizeof(struct dns_domain_entry));
309
 
                if (dd == NULL)
 
316
                pDomain = RTMemAllocZ(sizeof(struct dns_domain_entry));
 
317
                if (!pDomain)
310
318
                {
311
319
                    LogRel(("NAT: not enough memory\n"));
312
 
                    RTStrFree(suffix);
313
 
                    RTMemFree(addresses);
 
320
                    RTStrFree(pszSuffix);
 
321
                    RTMemFree(pAdapterAddr);
314
322
                    return VERR_NO_MEMORY;
315
323
                }
316
 
                dd->dd_pszDomain = suffix;
317
 
                LogRel(("NAT: adding domain name %s to search list\n", dd->dd_pszDomain));
318
 
                LIST_INSERT_HEAD(&pData->dns_domain_list_head, dd, dd_list);
 
324
                pDomain->dd_pszDomain = pszSuffix;
 
325
                LogRel(("NAT: adding domain name %s to search list\n", pDomain->dd_pszDomain));
 
326
                LIST_INSERT_HEAD(&pData->pDomainList, pDomain, dd_list);
319
327
            }
320
 
        next_dns:
321
 
            dns = dns->Next;
322
328
        }
323
 
    next:
324
 
        addr = addr->Next;
325
329
    }
326
 
    RTMemFree(addresses);
 
330
    RTMemFree(pAdapterAddr);
327
331
    return 0;
328
332
}
329
333
 
330
334
#else /* !RT_OS_WINDOWS */
331
335
 
 
336
static int RTFileGets(RTFILE File, void *pvBuf, size_t cbBufSize, size_t *pcbRead)
 
337
{
 
338
    size_t cbRead;
 
339
    char bTest;
 
340
    int rc = VERR_NO_MEMORY;
 
341
    char *pu8Buf = (char *)pvBuf;
 
342
    *pcbRead = 0;
 
343
 
 
344
    while (   RT_SUCCESS(rc = RTFileRead(File, &bTest, 1, &cbRead))
 
345
           && (pu8Buf - (char *)pvBuf) < cbBufSize)
 
346
    {
 
347
        if (cbRead == 0)
 
348
            return VERR_EOF;
 
349
 
 
350
        if (bTest == '\r' || bTest == '\n')
 
351
        {
 
352
            *pu8Buf = 0;
 
353
            return VINF_SUCCESS;
 
354
        }
 
355
        *pu8Buf = bTest;
 
356
         pu8Buf++;
 
357
        (*pcbRead)++;
 
358
    }
 
359
    return rc;
 
360
}
 
361
 
332
362
static int get_dns_addr_domain(PNATState pData, bool fVerbose,
333
363
                               struct in_addr *pdns_addr,
334
364
                               const char **ppszDomain)
335
365
{
336
366
    char buff[512];
337
367
    char buff2[256];
338
 
    FILE *f = NULL;
 
368
    RTFILE f;
339
369
    int found = 0;
340
370
    struct in_addr tmp_addr;
 
371
    int rc;
 
372
    size_t bytes;
341
373
 
342
374
#ifdef RT_OS_OS2
343
375
    /* Try various locations. */
344
376
    char *etc = getenv("ETC");
345
377
    if (etc)
346
378
    {
347
 
        snprintf(buff, sizeof(buff), "%s/RESOLV2", etc);
348
 
        f = fopen(buff, "rt");
349
 
    }
350
 
    if (!f)
351
 
    {
352
 
        snprintf(buff, sizeof(buff), "%s/RESOLV2", _PATH_ETC);
353
 
        f = fopen(buff, "rt");
354
 
    }
355
 
    if (!f)
356
 
    {
357
 
        snprintf(buff, sizeof(buff), "%s/resolv.conf", _PATH_ETC);
358
 
        f = fopen(buff, "rt");
359
 
    }
360
 
#else
361
 
#ifndef DEBUG_vvl
362
 
    f = fopen("/etc/resolv.conf", "r");
363
 
#else
 
379
        RTStrmPrintf(buff, sizeof(buff), "%s/RESOLV2", etc);
 
380
        rc = RTFileOpen(&f, buff, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
 
381
    }
 
382
    if (RT_FAILURE(rc))
 
383
    {
 
384
        RTStrmPrintf(buff, sizeof(buff), "%s/RESOLV2", _PATH_ETC);
 
385
        rc = RTFileOpen(&f, buff, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
 
386
    }
 
387
    if (RT_FAILURE(rc))
 
388
    {
 
389
        RTStrmPrintf(buff, sizeof(buff), "%s/resolv.conf", _PATH_ETC);
 
390
        rc = RTFileOpen(&f, buff, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
 
391
    }
 
392
#else
 
393
# ifndef DEBUG_vvl
 
394
    rc = RTFileOpen(&f, "/etc/resolv.conf", RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
 
395
# else
364
396
    char *home = getenv("HOME");
365
 
    snprintf(buff, sizeof(buff), "%s/resolv.conf", home);
366
 
    f = fopen(buff, "r");
367
 
    if (f != NULL)
 
397
    RTStrPrintf(buff, sizeof(buff), "%s/resolv.conf", home);
 
398
    rc = RTFileOpen(&f, buff, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
 
399
    if (RT_SUCCESS(rc))
368
400
    {
369
401
        Log(("NAT: DNS we're using %s\n", buff));
370
402
    }
371
403
    else
372
404
    {
373
 
        f = fopen("/etc/resolv.conf", "r");
 
405
        rc = RTFileOpen(&f, "/etc/resolv.conf", RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
374
406
        Log(("NAT: DNS we're using %s\n", buff));
375
407
    }
376
 
#endif
377
 
#endif
378
 
    if (!f)
 
408
# endif
 
409
#endif
 
410
    if (RT_FAILURE(rc))
379
411
        return -1;
380
412
 
381
413
    if (ppszDomain)
382
414
        *ppszDomain = NULL;
383
 
    Log(("nat: DNS Servers:\n"));
384
 
    while (fgets(buff, 512, f) != NULL)
 
415
 
 
416
    Log(("NAT: DNS Servers:\n"));
 
417
    while (    RT_SUCCESS(rc = RTFileGets(f, buff, 512, &bytes))
 
418
            && rc != VERR_EOF)
385
419
    {
386
 
        struct dns_entry *da = NULL;
 
420
        struct dns_entry *pDns = NULL;
387
421
        if (sscanf(buff, "nameserver%*[ \t]%256s", buff2) == 1)
388
422
        {
389
423
            if (!inet_aton(buff2, &tmp_addr))
390
424
                continue;
391
 
            /*localhost mask */
392
 
            da = RTMemAllocZ(sizeof (struct dns_entry));
393
 
            if (da == NULL)
 
425
 
 
426
            /* localhost mask */
 
427
            pDns = RTMemAllocZ(sizeof (struct dns_entry));
 
428
            if (!pDns)
394
429
            {
395
430
                LogRel(("can't alloc memory for DNS entry\n"));
396
431
                return -1;
397
432
            }
398
 
            /*check */
399
 
            da->de_addr.s_addr = tmp_addr.s_addr;
400
 
            if ((da->de_addr.s_addr & htonl(IN_CLASSA_NET)) == ntohl(INADDR_LOOPBACK & IN_CLASSA_NET)) {
401
 
                da->de_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_ALIAS);
 
433
 
 
434
            /* check */
 
435
            pDns->de_addr.s_addr = tmp_addr.s_addr;
 
436
            if ((pDns->de_addr.s_addr & htonl(IN_CLASSA_NET)) == ntohl(INADDR_LOOPBACK & IN_CLASSA_NET))
 
437
            {
 
438
                pDns->de_addr.s_addr = htonl(ntohl(pData->special_addr.s_addr) | CTL_ALIAS);
402
439
            }
403
 
            TAILQ_INSERT_HEAD(&pData->dns_list_head, da, de_list);
 
440
            TAILQ_INSERT_HEAD(&pData->pDnsList, pDns, de_list);
404
441
            found++;
405
442
        }
406
443
        if ((!strncmp(buff, "domain", 6) || !strncmp(buff, "search", 6)))
407
444
        {
408
445
            char *tok;
409
446
            char *saveptr;
410
 
            struct dns_domain_entry *dd = NULL;
 
447
            struct dns_domain_entry *pDomain = NULL;
411
448
            int found = 0;
412
449
            tok = strtok_r(&buff[6], " \t\n", &saveptr);
413
 
            LIST_FOREACH(dd, &pData->dns_domain_list_head, dd_list)
 
450
            LIST_FOREACH(pDomain, &pData->pDomainList, dd_list)
414
451
            {
415
 
                if (    tok != NULL
416
 
                     && strcmp(tok, dd->dd_pszDomain) == 0)
 
452
                if (   tok != NULL
 
453
                    && strcmp(tok, pDomain->dd_pszDomain) == 0)
417
454
                {
418
455
                    found = 1;
419
456
                    break;
420
457
                }
421
458
            }
422
 
            if (tok != NULL && found == 0) {
423
 
                dd = RTMemAllocZ(sizeof(struct dns_domain_entry));
424
 
                if (dd == NULL)
 
459
            if (tok != NULL && found == 0)
 
460
            {
 
461
                pDomain = RTMemAllocZ(sizeof(struct dns_domain_entry));
 
462
                if (!pDomain)
425
463
                {
426
464
                    LogRel(("NAT: not enought memory to add domain list\n"));
427
465
                    return VERR_NO_MEMORY;
428
466
                }
429
 
                dd->dd_pszDomain = RTStrDup(tok);
430
 
                LogRel(("NAT: adding domain name %s to search list\n", dd->dd_pszDomain));
431
 
                LIST_INSERT_HEAD(&pData->dns_domain_list_head, dd, dd_list);
 
467
                pDomain->dd_pszDomain = RTStrDup(tok);
 
468
                LogRel(("NAT: adding domain name %s to search list\n", pDomain->dd_pszDomain));
 
469
                LIST_INSERT_HEAD(&pData->pDomainList, pDomain, dd_list);
432
470
            }
433
471
        }
434
472
    }
435
 
    fclose(f);
 
473
    RTFileClose(f);
436
474
    if (!found)
437
475
        return -1;
438
476
    return 0;
442
480
 
443
481
static int slirp_init_dns_list(PNATState pData)
444
482
{
445
 
    TAILQ_INIT(&pData->dns_list_head);
446
 
    LIST_INIT(&pData->dns_domain_list_head);
 
483
    TAILQ_INIT(&pData->pDnsList);
 
484
    LIST_INIT(&pData->pDomainList);
447
485
    return get_dns_addr_domain(pData, true, NULL, NULL);
448
486
}
449
487
 
450
488
static void slirp_release_dns_list(PNATState pData)
451
489
{
452
 
    struct dns_entry *de = NULL;
453
 
    struct dns_domain_entry *dd = NULL;
454
 
    while(!TAILQ_EMPTY(&pData->dns_list_head)) {
455
 
        de = TAILQ_FIRST(&pData->dns_list_head);
456
 
        TAILQ_REMOVE(&pData->dns_list_head, de, de_list);
457
 
        RTMemFree(de);
 
490
    struct dns_entry *pDns = NULL;
 
491
    struct dns_domain_entry *pDomain = NULL;
 
492
 
 
493
    while (!TAILQ_EMPTY(&pData->pDnsList))
 
494
    {
 
495
        pDns = TAILQ_FIRST(&pData->pDnsList);
 
496
        TAILQ_REMOVE(&pData->pDnsList, pDns, de_list);
 
497
        RTMemFree(pDns);
458
498
    }
459
 
    while(!LIST_EMPTY(&pData->dns_domain_list_head)) {
460
 
        dd = LIST_FIRST(&pData->dns_domain_list_head);
461
 
        LIST_REMOVE(dd, dd_list);
462
 
        if (dd->dd_pszDomain != NULL)
463
 
            RTStrFree(dd->dd_pszDomain);
464
 
        RTMemFree(dd);
 
499
 
 
500
    while (!LIST_EMPTY(&pData->pDomainList))
 
501
    {
 
502
        pDomain = LIST_FIRST(&pData->pDomainList);
 
503
        LIST_REMOVE(pDomain, dd_list);
 
504
        if (pDomain->dd_pszDomain != NULL)
 
505
            RTStrFree(pDomain->dd_pszDomain);
 
506
        RTMemFree(pDomain);
465
507
    }
466
508
}
467
509
 
472
514
 
473
515
#ifndef VBOX_WITH_NAT_SERVICE
474
516
int slirp_init(PNATState *ppData, const char *pszNetAddr, uint32_t u32Netmask,
475
 
               bool fPassDomain, void *pvUser)
 
517
               bool fPassDomain, bool fUseHostResolver, void *pvUser)
476
518
#else
477
519
int slirp_init(PNATState *ppData, uint32_t u32NetAddr, uint32_t u32Netmask,
478
520
               bool fPassDomain, void *pvUser)
487
529
    if (u32Netmask & 0x1f)
488
530
        /* CTL is x.x.x.15, bootp passes up to 16 IPs (15..31) */
489
531
        return VERR_INVALID_PARAMETER;
490
 
    pData->fPassDomain = fPassDomain;
 
532
    pData->fPassDomain = !fUseHostResolver ? fPassDomain : false;
 
533
    pData->use_host_resolver = fUseHostResolver;
491
534
    pData->pvUser = pvUser;
492
535
    pData->netmask = u32Netmask;
493
536
 
513
556
 
514
557
    link_up = 1;
515
558
 
 
559
    rc = bootp_dhcp_init(pData);
 
560
    if (rc != 0)
 
561
    {
 
562
        LogRel(("NAT: DHCP server initialization was failed\n"));
 
563
        return VINF_NAT_DNS;
 
564
    }
516
565
    debug_init();
517
566
    if_init(pData);
518
567
    ip_init(pData);
519
568
    icmp_init(pData);
520
569
 
521
570
    /* Initialise mbufs *after* setting the MTU */
 
571
#ifndef VBOX_WITH_SLIRP_BSD_MBUF
522
572
    m_init(pData);
 
573
#else
 
574
    mbuf_init(pData);
 
575
#endif
523
576
 
524
577
#ifndef VBOX_WITH_NAT_SERVICE
525
 
    inet_aton(pszNetAddr, &special_addr);
 
578
    inet_aton(pszNetAddr, &pData->special_addr);
526
579
#else
527
 
    special_addr.s_addr = u32NetAddr;
 
580
    pData->special_addr.s_addr = u32NetAddr;
528
581
#endif
529
 
#ifdef VBOX_WITHOUT_SLIRP_CLIENT_ETHER
530
582
    pData->slirp_ethaddr = &special_ethaddr[0];
531
 
#endif
532
 
    alias_addr.s_addr = special_addr.s_addr | htonl(CTL_ALIAS);
 
583
    alias_addr.s_addr = pData->special_addr.s_addr | htonl(CTL_ALIAS);
533
584
    /* @todo: add ability to configure this staff */
534
585
 
535
586
    /* set default addresses */
536
587
    inet_aton("127.0.0.1", &loopback_addr);
537
 
    if (slirp_init_dns_list(pData) < 0)
538
 
        fNATfailed = 1;
 
588
    if (!pData->use_host_resolver)
 
589
    {
 
590
        if (slirp_init_dns_list(pData) < 0)
 
591
            fNATfailed = 1;
539
592
 
540
 
    dnsproxy_init(pData);
 
593
        dnsproxy_init(pData);
 
594
    }
541
595
 
542
596
    getouraddr(pData);
543
 
 
544
 
#ifdef VBOX_WITH_SLIRP_ALIAS
545
597
    {
546
598
        int flags = 0;
547
599
        struct in_addr proxy_addr;
552
604
            AssertMsgFailed(("NAT: LibAlias default rule wasn't initialized\n"));
553
605
        }
554
606
        flags = LibAliasSetMode(pData->proxy_alias, 0, 0);
 
607
#ifndef NO_FW_PUNCH
 
608
        flags |= PKT_ALIAS_PUNCH_FW;
 
609
#endif
555
610
        flags |= PKT_ALIAS_LOG; /* set logging */
556
611
        flags = LibAliasSetMode(pData->proxy_alias, flags, ~0);
557
 
        proxy_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_ALIAS);
 
612
        proxy_addr.s_addr = htonl(ntohl(pData->special_addr.s_addr) | CTL_ALIAS);
558
613
        LibAliasSetAddress(pData->proxy_alias, proxy_addr);
559
614
        ftp_alias_load(pData);
560
615
        nbt_alias_load(pData);
561
 
 
 
616
        if (pData->use_host_resolver)
 
617
            dns_alias_load(pData);
562
618
    }
563
 
#endif
564
619
    return fNATfailed ? VINF_NAT_DNS : VINF_SUCCESS;
565
620
}
566
621
 
570
625
void slirp_register_statistics(PNATState pData, PPDMDRVINS pDrvIns)
571
626
{
572
627
#ifdef VBOX_WITH_STATISTICS
573
 
# define COUNTER(name, type, units, dsc)                            \
574
 
    do {                                                            \
575
 
        PDMDrvHlpSTAMRegisterF(pDrvIns,                             \
576
 
                               &pData->Stat ## name,                \
577
 
                               type,                                \
578
 
                               STAMVISIBILITY_ALWAYS,               \
579
 
                               units,                               \
580
 
                               dsc,                                 \
581
 
                               "/Drivers/NAT%u/" #name,             \
582
 
                               pDrvIns->iInstance);                 \
583
 
    } while (0)
584
 
 
585
 
# define PROFILE_COUNTER(name, dsc)     COUNTER(name, STAMTYPE_PROFILE, STAMUNIT_TICKS_PER_CALL, dsc)
586
 
# define COUNTING_COUNTER(name, dsc)    COUNTER(name, STAMTYPE_COUNTER, STAMUNIT_COUNT,          dsc)
587
 
 
 
628
# define PROFILE_COUNTER(name, dsc)     REGISTER_COUNTER(name, pData, STAMTYPE_PROFILE, STAMUNIT_TICKS_PER_CALL, dsc)
 
629
# define COUNTING_COUNTER(name, dsc)    REGISTER_COUNTER(name, pData, STAMTYPE_COUNTER, STAMUNIT_COUNT,          dsc)
588
630
# include "counters.h"
589
 
 
590
631
# undef COUNTER
591
 
# undef PROFILE_COUNTER
592
 
# undef COUNTING_COUNTER
593
632
/** @todo register statistics for the variables dumped by:
594
633
 *  ipstats(pData); tcpstats(pData); udpstats(pData); icmpstats(pData);
595
634
 *  mbufstats(pData); sockstats(pData); */
602
641
void slirp_deregister_statistics(PNATState pData, PPDMDRVINS pDrvIns)
603
642
{
604
643
#ifdef VBOX_WITH_STATISTICS
605
 
# define PROFILE_COUNTER(name, dsc)     PDMDrvHlpSTAMDeregister(pDrvIns, &pData->Stat ## name)
606
 
# define COUNTING_COUNTER(name, dsc)    PDMDrvHlpSTAMDeregister(pDrvIns, &pData->Stat ## name)
607
 
 
 
644
# define PROFILE_COUNTER(name, dsc)     DEREGISTER_COUNTER(name, pData)
 
645
# define COUNTING_COUNTER(name, dsc)    DEREGISTER_COUNTER(name, pData)
608
646
# include "counters.h"
609
 
 
610
 
# undef COUNTING_COUNTER
611
 
# undef PROFILE_COUNTER
612
647
#endif /* VBOX_WITH_STATISTICS */
613
648
}
614
649
 
617
652
 */
618
653
void slirp_link_up(PNATState pData)
619
654
{
 
655
    struct arp_cache_entry *ac;
620
656
    link_up = 1;
 
657
 
 
658
    if (LIST_EMPTY(&pData->arp_cache))
 
659
        return;
 
660
 
 
661
    LIST_FOREACH(ac, &pData->arp_cache, list)
 
662
    {
 
663
        activate_port_forwarding(pData, ac->ether);
 
664
    }
621
665
}
622
666
 
623
667
/**
626
670
void slirp_link_down(PNATState pData)
627
671
{
628
672
    struct socket *so;
 
673
    struct port_forward_rule *rule;
629
674
 
630
675
    while ((so = tcb.so_next) != &tcb)
631
676
    {
638
683
    while ((so = udb.so_next) != &udb)
639
684
        udp_detach(pData, so);
640
685
 
 
686
    /*
 
687
     *  Clear the active state of port-forwarding rules to force
 
688
     *  re-setup on restoration of communications.
 
689
     */
 
690
    LIST_FOREACH(rule, &pData->port_forward_rule_head, list)
 
691
    {
 
692
        rule->activated = 0;
 
693
    }
 
694
    pData->cRedirectionsActive = 0;
 
695
 
641
696
    link_up = 0;
642
697
}
643
698
 
650
705
    pData->pfIcmpCloseHandle(pData->icmp_socket.sh);
651
706
    FreeLibrary(pData->hmIcmpLibrary);
652
707
    RTMemFree(pData->pvIcmpBuffer);
653
 
# else
 
708
#else
654
709
    closesocket(pData->icmp_socket.s);
655
710
#endif
656
711
 
658
713
    slirp_release_dns_list(pData);
659
714
    ftp_alias_unload(pData);
660
715
    nbt_alias_unload(pData);
661
 
#ifdef VBOX_WITH_SLIRP_ALIAS
662
 
    while(!LIST_EMPTY(&instancehead))
 
716
    if (pData->use_host_resolver)
 
717
        dns_alias_unload(pData);
 
718
    while (!LIST_EMPTY(&instancehead))
663
719
    {
664
720
        struct libalias *la = LIST_FIRST(&instancehead);
665
721
        /* libalias do all clean up */
666
722
        LibAliasUninit(la);
667
723
    }
668
 
#endif
669
 
    while(!LIST_EMPTY(&pData->arp_cache))
 
724
    while (!LIST_EMPTY(&pData->arp_cache))
670
725
    {
671
726
        struct arp_cache_entry *ac = LIST_FIRST(&pData->arp_cache);
672
727
        LIST_REMOVE(ac, list);
673
728
        RTMemFree(ac);
674
729
    }
 
730
    bootp_dhcp_fini(pData);
 
731
    m_fini(pData);
675
732
#ifdef RT_OS_WINDOWS
676
733
    WSACleanup();
677
734
#endif
696
753
 
697
754
#define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
698
755
#define CONN_CANFRCV(so)  (((so)->so_state & (SS_FCANTRCVMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
699
 
#define UPD_NFDS(x)       do { if (nfds < (x)) nfds = (x); } while (0)
700
756
 
701
757
/*
702
758
 * curtime kept to an accuracy of 1ms
746
802
    do_slowtimo = 0;
747
803
    if (!link_up)
748
804
        goto done;
 
805
 
749
806
    /*
750
807
     * *_slowtimo needs calling if there are IP fragments
751
808
     * in the fragment queue, or there are TCP connections active
761
818
            if (!TAILQ_EMPTY(&ipq[i]))
762
819
            {
763
820
                do_slowtimo = 1;
 
821
                slirp_arm_slow_timer(pData->pvUser);
764
822
                break;
765
823
            }
766
824
        }
775
833
#if !defined(RT_OS_WINDOWS)
776
834
        so->so_poll_index = -1;
777
835
#endif
 
836
        if (pData->fmbuf_water_line == 1)
 
837
        {
 
838
            if (mbuf_alloced < pData->mbuf_water_line_limit/2)
 
839
            {
 
840
                pData->fmbuf_water_warn_sent = 0;
 
841
                pData->fmbuf_water_line = 0;
 
842
            }
 
843
#ifndef RT_OS_WINDOWS
 
844
            poll_index = 0;
 
845
#endif
 
846
            goto done;
 
847
        }
778
848
        STAM_COUNTER_INC(&pData->StatTCP);
779
849
 
780
850
        /*
783
853
        if (    time_fasttimo == 0
784
854
                && so->so_tcpcb != NULL
785
855
                && so->so_tcpcb->t_flags & TF_DELACK)
 
856
        {
786
857
            time_fasttimo = curtime; /* Flag when we want a fasttimo */
 
858
            slirp_arm_fast_timer(pData->pvUser);
 
859
        }
787
860
 
788
861
        /*
789
862
         * NOFDREF can include still connecting to local-host,
843
916
    QSOCKET_FOREACH(so, so_next, udp)
844
917
    /* { */
845
918
 
 
919
        if (pData->fmbuf_water_line == 1)
 
920
        {
 
921
            if (mbuf_alloced < pData->mbuf_water_line_limit/2)
 
922
            {
 
923
                pData->fmbuf_water_line = 0;
 
924
                pData->fmbuf_water_warn_sent = 0;
 
925
            }
 
926
#ifndef RT_OS_WINDOWS
 
927
            poll_index = 0;
 
928
#endif
 
929
            goto done;
 
930
        }
846
931
        STAM_COUNTER_INC(&pData->StatUDP);
847
932
#if !defined(RT_OS_WINDOWS)
848
933
        so->so_poll_index = -1;
868
953
                CONTINUE_NO_UNLOCK(udp);
869
954
            }
870
955
            else
 
956
            {
871
957
                do_slowtimo = 1; /* Let socket expire */
 
958
                slirp_arm_slow_timer(pData->pvUser);
 
959
            }
872
960
        }
873
961
 
874
962
        /*
968
1056
     */
969
1057
    QSOCKET_FOREACH(so, so_next, tcp)
970
1058
    /* { */
 
1059
        if (pData->fmbuf_water_line == 1)
 
1060
        {
 
1061
            if (mbuf_alloced < pData->mbuf_water_line_limit/2)
 
1062
            {
 
1063
                pData->fmbuf_water_line = 0;
 
1064
                pData->fmbuf_water_warn_sent = 0;
 
1065
            }
 
1066
            goto done;
 
1067
        }
971
1068
 
972
1069
#ifdef VBOX_WITH_SLIRP_MT
973
1070
        if (   so->so_state & SS_NOFDREF
1256
1353
     */
1257
1354
     QSOCKET_FOREACH(so, so_next, udp)
1258
1355
     /* { */
 
1356
        if (pData->fmbuf_water_line == 1)
 
1357
        {
 
1358
            if (mbuf_alloced < pData->mbuf_water_line_limit/2)
 
1359
            {
 
1360
                pData->fmbuf_water_line = 0;
 
1361
                pData->fmbuf_water_warn_sent = 0;
 
1362
            }
 
1363
            goto done;
 
1364
        }
1259
1365
#ifdef VBOX_WITH_SLIRP_MT
1260
1366
        if (   so->so_state & SS_NOFDREF
1261
1367
            && so->so_deleted == 1)
1298
1404
    }
1299
1405
 
1300
1406
done:
1301
 
#ifndef VBOX_WITH_SLIRP_MT
 
1407
#if 0
1302
1408
    /*
1303
1409
     * See if we can start outputting
1304
1410
     */
1309
1415
    STAM_PROFILE_STOP(&pData->StatPoll, a);
1310
1416
}
1311
1417
 
1312
 
#ifndef VBOX_WITHOUT_SLIRP_CLIENT_ETHER
1313
 
#define ETH_ALEN        6
1314
 
#define ETH_HLEN        14
1315
 
 
1316
 
#define ARPOP_REQUEST   1               /* ARP request                  */
1317
 
#define ARPOP_REPLY     2               /* ARP reply                    */
1318
 
 
1319
 
struct ethhdr
1320
 
{
1321
 
    unsigned char   h_dest[ETH_ALEN];           /* destination eth addr */
1322
 
    unsigned char   h_source[ETH_ALEN];         /* source ether addr    */
1323
 
    unsigned short  h_proto;                    /* packet type ID field */
1324
 
};
1325
 
AssertCompileSize(struct ethhdr, 14);
1326
 
#endif
1327
1418
 
1328
1419
struct arphdr
1329
1420
{
1359
1450
    htip = ntohl(*(uint32_t*)ah->ar_tip);
1360
1451
    tip = *(uint32_t*)ah->ar_tip;
1361
1452
 
1362
 
    mr = m_get(pData);
1363
 
#ifdef VBOX_WITHOUT_SLIRP_CLIENT_ETHER
1364
 
    reh = mtod(mr, struct ethhdr *);
1365
 
    memcpy(reh->h_source, eh->h_source, ETH_ALEN); /* XXX: if_encap will swap src and dst*/
1366
 
    Log4(("NAT: arp:%R[ether]->%R[ether]\n",
1367
 
        reh->h_source, reh->h_dest));
1368
 
    Log4(("NAT: arp: %R[IP4]\n", &tip));
1369
 
#endif
1370
 
    mr->m_data += if_maxlinkhdr;
1371
 
    mr->m_len = sizeof(struct arphdr);
1372
 
    rah = mtod(mr, struct arphdr *);
1373
 
 
1374
1453
    ar_op = ntohs(ah->ar_op);
1375
 
    switch(ar_op)
 
1454
    switch (ar_op)
1376
1455
    {
1377
1456
        case ARPOP_REQUEST:
 
1457
#ifndef VBOX_WITH_SLIRP_BSD_MBUF
 
1458
            mr = m_get(pData);
 
1459
 
 
1460
            reh = mtod(mr, struct ethhdr *);
 
1461
            memcpy(reh->h_source, eh->h_source, ETH_ALEN); /* XXX: if_encap will swap src and dst*/
 
1462
            Log4(("NAT: arp:%R[ether]->%R[ether]\n",
 
1463
                reh->h_source, reh->h_dest));
 
1464
            Log4(("NAT: arp: %R[IP4]\n", &tip));
 
1465
 
 
1466
            mr->m_data += if_maxlinkhdr;
 
1467
            mr->m_len = sizeof(struct arphdr);
 
1468
            rah = mtod(mr, struct arphdr *);
 
1469
#else
 
1470
            mr = m_getcl(pData, M_NOWAIT, MT_HEADER, M_PKTHDR);
 
1471
            reh = mtod(mr, struct ethhdr *);
 
1472
            mr->m_data += ETH_HLEN;
 
1473
            rah = mtod(mr, struct arphdr *);
 
1474
            mr->m_len = sizeof(struct arphdr);
 
1475
            Assert(mr);
 
1476
            memcpy(reh->h_source, eh->h_source, ETH_ALEN); /* XXX: if_encap will swap src and dst*/
 
1477
#endif
1378
1478
#ifdef VBOX_WITH_NAT_SERVICE
1379
 
            if (tip == special_addr.s_addr) goto arp_ok;
 
1479
            if (tip == pData->special_addr.s_addr)
 
1480
                goto arp_ok;
1380
1481
#endif
1381
 
            if ((htip & pData->netmask) == ntohl(special_addr.s_addr))
 
1482
            if ((htip & pData->netmask) == ntohl(pData->special_addr.s_addr))
1382
1483
            {
1383
1484
                if (   CTL_CHECK(htip, CTL_DNS)
1384
1485
                    || CTL_CHECK(htip, CTL_ALIAS)
1391
1492
                        goto arp_ok;
1392
1493
                    }
1393
1494
                }
 
1495
                m_free(pData, m);
 
1496
                m_free(pData, mr);
1394
1497
                return;
1395
 
        arp_ok:
 
1498
 
 
1499
         arp_ok:
1396
1500
                rah->ar_hrd = htons(1);
1397
1501
                rah->ar_pro = htons(ETH_P_IP);
1398
1502
                rah->ar_hln = ETH_ALEN;
1412
1516
                memcpy(rah->ar_sip, ah->ar_tip, 4);
1413
1517
                memcpy(rah->ar_tha, ah->ar_sha, ETH_ALEN);
1414
1518
                memcpy(rah->ar_tip, ah->ar_sip, 4);
1415
 
                if_encap(pData, ETH_P_ARP, mr);
 
1519
                if_encap(pData, ETH_P_ARP, mr, ETH_ENCAP_URG);
1416
1520
                m_free(pData, m);
1417
1521
            }
 
1522
            /* Gratuitous ARP */
 
1523
            if (  *(uint32_t *)ah->ar_sip == *(uint32_t *)ah->ar_tip
 
1524
                && memcmp(ah->ar_tha, broadcast_ethaddr, ETH_ALEN) == 0
 
1525
                && memcmp(eh->h_dest, broadcast_ethaddr, ETH_ALEN) == 0)
 
1526
            {
 
1527
                /* we've received anounce about address asignment
 
1528
                 * Let's do ARP cache update
 
1529
                 */
 
1530
                if (slirp_arp_cache_update(pData, *(uint32_t *)ah->ar_tip, &eh->h_dest[0]) == 0)
 
1531
                {
 
1532
                    m_free(pData, mr);
 
1533
                    m_free(pData, m);
 
1534
                    break;
 
1535
                }
 
1536
                slirp_arp_cache_add(pData, *(uint32_t *)ah->ar_tip, &eh->h_dest[0]);
 
1537
            }
1418
1538
            break;
 
1539
 
1419
1540
        case ARPOP_REPLY:
1420
 
        {
1421
 
            struct arp_cache_entry *ac = NULL;
1422
 
            if (slirp_update_arp_cache(pData, *(uint32_t *)ah->ar_sip, ah->ar_sha) == 0)
 
1541
            if (slirp_arp_cache_update(pData, *(uint32_t *)ah->ar_sip, &ah->ar_sha[0]) == 0)
1423
1542
            {
1424
1543
                m_free(pData, m);
1425
1544
                break;
1426
1545
            }
1427
 
            ac = RTMemAllocZ(sizeof(struct arp_cache_entry));
1428
 
            if (ac == NULL)
1429
 
            {
1430
 
                LogRel(("NAT: Can't allocate arp cache entry\n"));
1431
 
                m_free(pData, m);
1432
 
                return;
1433
 
            }
1434
 
            ac->ip = *(uint32_t *)ah->ar_sip;
1435
 
            memcpy(ac->ether, ah->ar_sha, ETH_ALEN);
1436
 
            LIST_INSERT_HEAD(&pData->arp_cache, ac, list);
1437
 
        }
1438
 
        break;
 
1546
            slirp_arp_cache_add(pData, *(uint32_t *)ah->ar_sip, ah->ar_sha);
 
1547
            m_free(pData, m);
 
1548
            break;
 
1549
 
1439
1550
        default:
1440
1551
            break;
1441
1552
    }
1442
1553
}
1443
1554
 
 
1555
#ifdef VBOX_WITH_SLIRP_BSD_MBUF
1444
1556
void slirp_input(PNATState pData, const uint8_t *pkt, int pkt_len)
 
1557
#else
 
1558
void slirp_input(PNATState pData, void *pvArg)
 
1559
#endif
1445
1560
{
1446
1561
    struct mbuf *m;
1447
1562
    int proto;
1448
1563
    static bool fWarnedIpv6;
 
1564
#ifdef VBOX_WITH_SLIRP_BSD_MBUF
1449
1565
    struct ethhdr *eh = (struct ethhdr*)pkt;
 
1566
    int size = 0;
 
1567
#else
 
1568
    struct ethhdr *eh;
 
1569
#endif
 
1570
    uint8_t au8Ether[ETH_ALEN];
1450
1571
 
 
1572
#ifndef VBOX_WITH_SLIRP_BSD_MBUF
 
1573
    m = (struct mbuf *)pvArg;
 
1574
    if (m->m_len < ETH_HLEN)
 
1575
    {
 
1576
        LogRel(("NAT: packet having size %d has been ingnored\n", m->m_len));
 
1577
        m_free(pData, m);
 
1578
        return;
 
1579
    }
 
1580
    eh = mtod(m, struct ethhdr *);
 
1581
    proto = ntohs(eh->h_proto);
 
1582
#else
1451
1583
    Log2(("NAT: slirp_input %d\n", pkt_len));
1452
1584
    if (pkt_len < ETH_HLEN)
1453
1585
    {
1455
1587
        return;
1456
1588
    }
1457
1589
    Log4(("NAT: in:%R[ether]->%R[ether]\n", &eh->h_source, &eh->h_dest));
1458
 
#ifdef VBOX_WITHOUT_SLIRP_CLIENT_ETHER
 
1590
 
1459
1591
    if (memcmp(eh->h_source, special_ethaddr, ETH_ALEN) == 0)
1460
1592
    {
1461
1593
        /* @todo vasily: add ether logging routine in debug.c */
1463
1595
        RTMemFree((void *)pkt);
1464
1596
        return;
1465
1597
    }
1466
 
#endif
1467
 
 
1468
 
    m = m_get(pData);
 
1598
 
 
1599
    if (pkt_len < MSIZE)
 
1600
        size = MCLBYTES;
 
1601
    else if (pkt_len < MCLBYTES)
 
1602
        size = MCLBYTES;
 
1603
    else if (pkt_len < MJUM9BYTES)
 
1604
        size = MJUM9BYTES;
 
1605
    else if (pkt_len < MJUM16BYTES)
 
1606
        size = MJUM16BYTES;
 
1607
    else
 
1608
        AssertMsgFailed(("Unsupported size"));
 
1609
 
 
1610
    m = m_getjcl(pData, M_NOWAIT, MT_HEADER, M_PKTHDR, size);
1469
1611
    if (!m)
1470
1612
    {
1471
1613
        LogRel(("NAT: can't allocate new mbuf\n"));
 
1614
        RTMemFree((void *)pkt);
1472
1615
        return;
1473
1616
    }
1474
1617
 
1475
 
    /* Note: we add to align the IP header */
1476
 
 
1477
 
    if (M_FREEROOM(m) < pkt_len)
1478
 
       m_inc(m, pkt_len);
1479
 
 
1480
1618
    m->m_len = pkt_len ;
1481
1619
    memcpy(m->m_data, pkt, pkt_len);
1482
 
 
1483
1620
    proto = ntohs(*(uint16_t *)(pkt + 12));
 
1621
#endif
 
1622
    /* Note: we add to align the IP header */
 
1623
 
 
1624
    memcpy(au8Ether, eh->h_source, ETH_ALEN);
 
1625
 
1484
1626
    switch(proto)
1485
1627
    {
1486
1628
        case ETH_P_ARP:
1487
1629
            arp_input(pData, m);
1488
1630
            break;
 
1631
 
1489
1632
        case ETH_P_IP:
1490
1633
            /* Update time. Important if the network is very quiet, as otherwise
1491
1634
             * the first outgoing connection gets an incorrect timestamp. */
1492
1635
            updtime(pData);
1493
1636
            m_adj(m, ETH_HLEN);
 
1637
#ifdef VBOX_WITH_SLIRP_BSD_MBUF
 
1638
            M_ASSERTPKTHDR(m);
 
1639
            m->m_pkthdr.header = mtod(m, void *);
 
1640
#endif
 
1641
#if 1
 
1642
            if (   pData->fmbuf_water_line
 
1643
                && pData->fmbuf_water_warn_sent == 0
 
1644
                && (curtime - pData->tsmbuf_water_warn_sent) > 500)
 
1645
            {
 
1646
                icmp_error(pData, m, ICMP_SOURCEQUENCH, 0, 0, "Out of resources!!!");
 
1647
                pData->fmbuf_water_warn_sent = 1;
 
1648
                pData->tsmbuf_water_warn_sent = curtime;
 
1649
            }
 
1650
#endif
1494
1651
            ip_input(pData, m);
1495
1652
            break;
 
1653
 
1496
1654
        case ETH_P_IPV6:
1497
1655
            m_free(pData, m);
1498
1656
            if (!fWarnedIpv6)
1501
1659
                fWarnedIpv6 = true;
1502
1660
            }
1503
1661
            break;
 
1662
 
1504
1663
        default:
1505
1664
            Log(("NAT: Unsupported protocol %x\n", proto));
1506
1665
            m_free(pData, m);
1507
1666
            break;
1508
1667
    }
 
1668
 
 
1669
    if (pData->cRedirectionsActive != pData->cRedirectionsStored)
 
1670
        activate_port_forwarding(pData, au8Ether);
 
1671
 
 
1672
#ifdef VBOX_WITH_SLIRP_BSD_MBUF
1509
1673
    RTMemFree((void *)pkt);
 
1674
#endif
1510
1675
}
1511
1676
 
1512
1677
/* output the IP packet to the ethernet device */
1513
 
void if_encap(PNATState pData, uint16_t eth_proto, struct mbuf *m)
 
1678
void if_encap(PNATState pData, uint16_t eth_proto, struct mbuf *m, int flags)
1514
1679
{
1515
1680
    struct ethhdr *eh;
1516
1681
    uint8_t *buf = NULL;
 
1682
    size_t mlen = 0;
 
1683
    STAM_PROFILE_START(&pData->StatIF_encap, a);
1517
1684
 
 
1685
#ifndef VBOX_WITH_SLIRP_BSD_MBUF
1518
1686
    m->m_data -= if_maxlinkhdr;
1519
1687
    m->m_len += ETH_HLEN;
1520
1688
    eh = mtod(m, struct ethhdr *);
1524
1692
        LogRel(("NAT: ethernet detects corruption of the packet"));
1525
1693
        AssertMsgFailed(("!!Ethernet frame corrupted!!"));
1526
1694
    }
 
1695
#else
 
1696
    M_ASSERTPKTHDR(m);
 
1697
    m->m_data -= ETH_HLEN;
 
1698
    m->m_len += ETH_HLEN;
 
1699
    eh = mtod(m, struct ethhdr *);
 
1700
#endif
1527
1701
 
1528
 
#ifndef VBOX_WITHOUT_SLIRP_CLIENT_ETHER
1529
 
    memcpy(eh->h_dest, client_ethaddr, ETH_ALEN);
1530
 
    memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 1);
1531
 
    /* XXX: not correct */
1532
 
    eh->h_source[5] = CTL_ALIAS;
1533
 
#else
1534
1702
    if (memcmp(eh->h_source, special_ethaddr, ETH_ALEN) != 0)
1535
1703
    {
1536
1704
        memcpy(eh->h_dest, eh->h_source, ETH_ALEN);
1542
1710
            goto done;
1543
1711
        }
1544
1712
    }
1545
 
#endif
1546
 
    eh->h_proto = htons(eth_proto);
1547
 
#if 0
1548
 
    slirp_output(pData->pvUser, m, mtod(m, uint8_t *), m->m_len);
 
1713
#ifndef VBOX_WITH_SLIRP_BSD_MBUF
 
1714
    mlen = m->m_len;
1549
1715
#else
1550
 
    buf = RTMemAlloc(1600);
 
1716
    mlen = m_length(m, NULL);
 
1717
    buf = RTMemAlloc(mlen);
1551
1718
    if (buf == NULL)
1552
1719
    {
1553
1720
        LogRel(("NAT: Can't alloc memory for outgoing buffer\n"));
1554
1721
        goto done;
1555
1722
    }
1556
 
    memcpy(buf, mtod(m, uint8_t *), m->m_len);
1557
 
    slirp_output(pData->pvUser, NULL, buf, m->m_len);
 
1723
#endif
 
1724
    eh->h_proto = htons(eth_proto);
 
1725
#ifdef VBOX_WITH_SLIRP_BSD_MBUF
 
1726
    m_copydata(m, 0, mlen, (char *)buf);
 
1727
#else
 
1728
    if (flags & ETH_ENCAP_URG)
 
1729
        slirp_urg_output(pData->pvUser, m, mtod(m, const uint8_t *), mlen);
 
1730
    else
 
1731
        slirp_output(pData->pvUser, m, mtod(m, const uint8_t *), mlen);
 
1732
#endif
1558
1733
done:
 
1734
    STAM_PROFILE_STOP(&pData->StatIF_encap, a);
 
1735
#ifdef VBOX_WITH_SLIRP_BSD_MBUF
1559
1736
    m_free(pData, m);
1560
1737
#endif
1561
1738
}
1562
1739
 
 
1740
/**
 
1741
 * Still we're using dhcp server leasing to map ether to IP
 
1742
 * @todo  see rt_lookup_in_cache
 
1743
 */
 
1744
static uint32_t find_guest_ip(PNATState pData, const uint8_t *eth_addr)
 
1745
{
 
1746
    uint32_t ip = INADDR_ANY;
 
1747
    int rc;
 
1748
 
 
1749
    if (eth_addr == NULL)
 
1750
        return INADDR_ANY;
 
1751
 
 
1752
    if (   memcmp(eth_addr, zerro_ethaddr, ETH_ALEN) == 0
 
1753
        || memcmp(eth_addr, broadcast_ethaddr, ETH_ALEN) == 0)
 
1754
        return INADDR_ANY;
 
1755
 
 
1756
    rc = slirp_arp_lookup_ip_by_ether(pData, eth_addr, &ip);
 
1757
    if (RT_SUCCESS(rc))
 
1758
        return ip;
 
1759
 
 
1760
    bootp_cache_lookup_ip_by_ether(pData, eth_addr, &ip);
 
1761
    /* ignore return code, ip will be set to INADDR_ANY on error */
 
1762
    return ip;
 
1763
}
 
1764
 
 
1765
/**
 
1766
 * We need check if we've activated port forwarding
 
1767
 * for specific machine ... that of course relates to
 
1768
 * service mode
 
1769
 * @todo finish this for service case
 
1770
 */
 
1771
static void activate_port_forwarding(PNATState pData, const uint8_t *h_source)
 
1772
{
 
1773
    struct port_forward_rule *rule;
 
1774
 
 
1775
    /* check mac here */
 
1776
    LIST_FOREACH(rule, &pData->port_forward_rule_head, list)
 
1777
    {
 
1778
        struct socket *so;
 
1779
        struct alias_link *link;
 
1780
        struct libalias *lib;
 
1781
        int flags;
 
1782
        struct sockaddr sa;
 
1783
        struct sockaddr_in *psin;
 
1784
        socklen_t socketlen;
 
1785
        struct in_addr alias;
 
1786
        int rc;
 
1787
        uint32_t guest_addr; /* need to understand if we already give address to guest */
 
1788
 
 
1789
        if (rule->activated)
 
1790
            continue;
 
1791
 
 
1792
#ifdef VBOX_WITH_NAT_SERVICE
 
1793
        if (memcmp(rule->mac_address, h_source, ETH_ALEN) != 0)
 
1794
            continue; /*not right mac, @todo: it'd be better do the list port forwarding per mac */
 
1795
        guest_addr = find_guest_ip(pData, h_source);
 
1796
#else
 
1797
#if 0
 
1798
        if (memcmp(client_ethaddr, h_source, ETH_ALEN) != 0)
 
1799
            continue;
 
1800
#endif
 
1801
        guest_addr = find_guest_ip(pData, h_source);
 
1802
#endif
 
1803
        if (guest_addr == INADDR_ANY)
 
1804
        {
 
1805
            /* the address wasn't granted */
 
1806
            return;
 
1807
        }
 
1808
 
 
1809
#if !defined(VBOX_WITH_NAT_SERVICE)
 
1810
        if (rule->guest_addr.s_addr != guest_addr)
 
1811
            continue;
 
1812
#endif
 
1813
 
 
1814
        LogRel(("NAT: set redirect %s host port %d => guest port %d @ %R[IP4]\n",
 
1815
               (rule->proto == IPPROTO_UDP?"UDP":"TCP"),
 
1816
               rule->host_port, rule->guest_port, &guest_addr));
 
1817
 
 
1818
        if (rule->proto == IPPROTO_UDP)
 
1819
            so = udp_listen(pData, rule->bind_ip.s_addr, htons(rule->host_port), guest_addr,
 
1820
                            htons(rule->guest_port), 0);
 
1821
        else
 
1822
            so = solisten(pData, rule->bind_ip.s_addr, htons(rule->host_port), guest_addr,
 
1823
                          htons(rule->guest_port), 0);
 
1824
 
 
1825
        if (so == NULL)
 
1826
            goto remove_port_forwarding;
 
1827
 
 
1828
        psin = (struct sockaddr_in *)&sa;
 
1829
        psin->sin_family = AF_INET;
 
1830
        psin->sin_port = 0;
 
1831
        psin->sin_addr.s_addr = INADDR_ANY;
 
1832
        socketlen = sizeof(struct sockaddr);
 
1833
 
 
1834
        rc = getsockname(so->s, &sa, &socketlen);
 
1835
        if (rc < 0 || sa.sa_family != AF_INET)
 
1836
            goto remove_port_forwarding;
 
1837
 
 
1838
        psin = (struct sockaddr_in *)&sa;
 
1839
 
 
1840
        lib = LibAliasInit(pData, NULL);
 
1841
        flags = LibAliasSetMode(lib, 0, 0);
 
1842
        flags |= PKT_ALIAS_LOG; /* set logging */
 
1843
        flags |= PKT_ALIAS_REVERSE; /* set logging */
 
1844
        flags = LibAliasSetMode(lib, flags, ~0);
 
1845
 
 
1846
        alias.s_addr =  htonl(ntohl(guest_addr) | CTL_ALIAS);
 
1847
        link = LibAliasRedirectPort(lib, psin->sin_addr, htons(rule->host_port),
 
1848
                                    alias, htons(rule->guest_port),
 
1849
                                    pData->special_addr,  -1, /* not very clear for now */
 
1850
                                    rule->proto);
 
1851
        if (!link)
 
1852
            goto remove_port_forwarding;
 
1853
 
 
1854
        so->so_la = lib;
 
1855
        rule->activated = 1;
 
1856
        pData->cRedirectionsActive++;
 
1857
        continue;
 
1858
 
 
1859
    remove_port_forwarding:
 
1860
        LogRel(("NAT: failed to redirect %s %d => %d\n",
 
1861
                (rule->proto == IPPROTO_UDP?"UDP":"TCP"), rule->host_port, rule->guest_port));
 
1862
        LIST_REMOVE(rule, list);
 
1863
        pData->cRedirectionsStored--;
 
1864
        RTMemFree(rule);
 
1865
    }
 
1866
}
 
1867
 
 
1868
/**
 
1869
 * Changes in 3.1 instead of opening new socket do the following:
 
1870
 * gain more information:
 
1871
 *  1. bind IP
 
1872
 *  2. host port
 
1873
 *  3. guest port
 
1874
 *  4. proto
 
1875
 *  5. guest MAC address
 
1876
 * the guest's MAC address is rather important for service, but we easily
 
1877
 * could get it from VM configuration in DrvNAT or Service, the idea is activating
 
1878
 * corresponding port-forwarding
 
1879
 */
1563
1880
int slirp_redir(PNATState pData, int is_udp, struct in_addr host_addr, int host_port,
1564
 
                struct in_addr guest_addr, int guest_port)
 
1881
                struct in_addr guest_addr, int guest_port, const uint8_t *ethaddr)
1565
1882
{
1566
 
    struct socket *so;
1567
 
#ifdef VBOX_WITH_SLIRP_ALIAS
1568
 
    struct alias_link *link;
1569
 
    struct libalias *lib;
1570
 
    int flags;
1571
 
    struct sockaddr sa;
1572
 
    struct sockaddr_in *psin;
1573
 
    socklen_t socketlen;
1574
 
    struct in_addr alias;
1575
 
    int rc;
1576
 
#endif
1577
 
    Log2(("NAT: set redirect %s hp:%d gp:%d\n", (is_udp?"UDP":"TCP"), host_port, guest_port));
1578
 
    if (is_udp)
1579
 
    {
1580
 
        so = udp_listen(pData, host_addr.s_addr, htons(host_port), guest_addr.s_addr,
1581
 
                        htons(guest_port), 0);
1582
 
    }
1583
 
    else
1584
 
    {
1585
 
        so = solisten(pData, host_addr.s_addr, htons(host_port), guest_addr.s_addr,
1586
 
                      htons(guest_port), 0);
1587
 
    }
1588
 
    if (so == NULL)
1589
 
    {
1590
 
        return -1;
1591
 
    }
1592
 
#ifndef VBOX_WITH_SLIRP_ALIAS
1593
 
    Log2(("NAT: redirecting socket %R[natsock]\n", so));
1594
 
    return (so != NULL ? 0 : -1);
1595
 
#else
1596
 
 
1597
 
    psin = (struct sockaddr_in *)&sa;
1598
 
    psin->sin_family = AF_INET;
1599
 
    psin->sin_port = 0;
1600
 
    psin->sin_addr.s_addr = INADDR_ANY;
1601
 
    socketlen = sizeof(struct sockaddr);
1602
 
 
1603
 
    rc = getsockname(so->s, &sa, &socketlen);
1604
 
    if (rc < 0 || sa.sa_family != AF_INET)
1605
 
    {
1606
 
        Log(("NAT: can't get socket's name\n"));
1607
 
        return 1;
1608
 
    }
1609
 
 
1610
 
    psin = (struct sockaddr_in *)&sa;
1611
 
 
1612
 
#if 1
1613
 
    lib = LibAliasInit(pData, NULL);
1614
 
    flags = LibAliasSetMode(lib, 0, 0);
1615
 
    flags |= PKT_ALIAS_LOG; /* set logging */
1616
 
    flags |= PKT_ALIAS_REVERSE; /* set logging */
1617
 
    flags = LibAliasSetMode(lib, flags, ~0);
1618
 
#else
1619
 
    lib = LIST_FIRST(&instancehead);
1620
 
#endif
1621
 
 
1622
 
    alias.s_addr =  htonl(ntohl(guest_addr.s_addr) | CTL_ALIAS);
1623
 
    link = LibAliasRedirectPort(lib, psin->sin_addr, htons(host_port),
1624
 
        alias, htons(guest_port),
1625
 
        special_addr,  -1, /* not very clear for now*/
1626
 
        (is_udp ? IPPROTO_UDP : IPPROTO_TCP));
1627
 
    if (link == NULL)
1628
 
    {
1629
 
        Log(("NAT: can't create redirect\n"));
1630
 
        return 1;
1631
 
    }
1632
 
    so->so_la = lib;
1633
 
 
 
1883
    struct port_forward_rule *rule = NULL;
 
1884
    Assert(memcmp(ethaddr, zerro_ethaddr, ETH_ALEN) == 0);
 
1885
 
 
1886
    rule = RTMemAllocZ(sizeof(struct port_forward_rule));
 
1887
    if (rule == NULL)
 
1888
        return 1;
 
1889
 
 
1890
    rule->proto = (is_udp ? IPPROTO_UDP : IPPROTO_TCP);
 
1891
    rule->host_port = host_port;
 
1892
    rule->guest_port = guest_port;
 
1893
#ifndef VBOX_WITH_NAT_SERVICE
 
1894
    rule->guest_addr.s_addr = guest_addr.s_addr;
 
1895
#endif
 
1896
    rule->bind_ip.s_addr = host_addr.s_addr;
 
1897
    memcpy(rule->mac_address, ethaddr, ETH_ALEN);
 
1898
    /* @todo add mac address */
 
1899
    LIST_INSERT_HEAD(&pData->port_forward_rule_head, rule, list);
 
1900
    pData->cRedirectionsStored++;
1634
1901
    return 0;
1635
 
#endif
1636
1902
}
1637
1903
 
1638
1904
int slirp_add_exec(PNATState pData, int do_pty, const char *args, int addr_low_byte,
1639
 
                  int guest_port)
 
1905
                   int guest_port)
1640
1906
{
1641
1907
    return add_exec(&exec_list, do_pty, (char *)args,
1642
1908
                    addr_low_byte, htons(guest_port));
1643
1909
}
1644
1910
 
1645
 
void slirp_set_ethaddr(PNATState pData, const uint8_t *ethaddr)
 
1911
void slirp_set_ethaddr_and_activate_port_forwarding(PNATState pData, const uint8_t *ethaddr, uint32_t GuestIP)
1646
1912
{
1647
 
#ifndef VBOX_WITHOUT_SLIRP_CLIENT_ETHER
 
1913
#ifndef VBOX_WITH_NAT_SERVICE
1648
1914
    memcpy(client_ethaddr, ethaddr, ETH_ALEN);
1649
1915
#endif
 
1916
    if (GuestIP != INADDR_ANY)
 
1917
    {
 
1918
        slirp_arp_cache_update_or_add(pData, GuestIP, ethaddr);
 
1919
        activate_port_forwarding(pData, ethaddr);
 
1920
    }
1650
1921
}
1651
1922
 
1652
1923
#if defined(RT_OS_WINDOWS)
1700
1971
}
1701
1972
#endif
1702
1973
 
1703
 
uint16_t slirp_get_service(int proto, uint16_t dport, uint16_t sport)
1704
 
{
1705
 
    uint16_t hdport, hsport, service;
1706
 
    hdport = ntohs(dport);
1707
 
    hsport = ntohs(sport);
1708
 
    Log2(("proto: %d, dport: %d sport: %d\n", proto, hdport, hsport));
1709
 
    service = 0;
1710
 
#if 0
1711
 
    /* Always return 0 here */
1712
 
    switch (hdport)
1713
 
    {
1714
 
        case 500:
1715
 
                if (hsport != 500) /* vpnc by default try operate in src:500/dst:500 mode*/
1716
 
                /* Not sure why this make Cisco VPN client's connection more stable,
1717
 
                 * at least on some servers
1718
 
                 */
1719
 
                    service = sport;
1720
 
        break;
1721
 
    }
1722
 
#endif
1723
 
    Log2(("service : %d\n", service));
1724
 
    return htons(service);
1725
 
}
1726
 
 
1727
1974
void slirp_set_dhcp_TFTP_prefix(PNATState pData, const char *tftpPrefix)
1728
1975
{
1729
1976
    Log2(("tftp_prefix:%s\n", tftpPrefix));
1740
1987
{
1741
1988
    Log2(("next_server:%s\n", next_server));
1742
1989
    if (next_server == NULL)
1743
 
        pData->tftp_server.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_TFTP);
 
1990
        pData->tftp_server.s_addr = htonl(ntohl(pData->special_addr.s_addr) | CTL_TFTP);
1744
1991
    else
1745
1992
        inet_aton(next_server, &pData->tftp_server);
1746
1993
}
1757
2004
 
1758
2005
void slirp_set_dhcp_dns_proxy(PNATState pData, bool fDNSProxy)
1759
2006
{
1760
 
    Log2(("NAT: DNS proxy switched %s\n", (fDNSProxy ? "on" : "off")));
1761
 
    pData->use_dns_proxy = fDNSProxy;
 
2007
    if (!pData->use_host_resolver)
 
2008
    {
 
2009
        Log2(("NAT: DNS proxy switched %s\n", (fDNSProxy ? "on" : "off")));
 
2010
        pData->use_dns_proxy = fDNSProxy;
 
2011
    }
 
2012
    else
 
2013
        LogRel(("NAT: Host Resolver conflicts with DNS proxy, the last one was forcely ignored\n"));
1762
2014
}
1763
2015
 
1764
 
#define CHECK_ARG(name, val, lim_min, lim_max)                                  \
1765
 
do {                                                                            \
1766
 
    if ((val) < (lim_min) || (val) > (lim_max))                                 \
1767
 
    {                                                                           \
1768
 
        LogRel(("NAT: (" #name ":%d) has been ignored, "                        \
1769
 
            "because out of range (%d, %d)\n", (val), (lim_min), (lim_max)));   \
1770
 
        return;                                                                 \
1771
 
    }                                                                           \
1772
 
    else                                                                        \
1773
 
    {                                                                           \
1774
 
        LogRel(("NAT: (" #name ":%d)\n", (val)));                               \
1775
 
    }                                                                           \
1776
 
} while (0)
 
2016
#define CHECK_ARG(name, val, lim_min, lim_max)                                      \
 
2017
    do {                                                                            \
 
2018
        if ((val) < (lim_min) || (val) > (lim_max))                                 \
 
2019
        {                                                                           \
 
2020
            LogRel(("NAT: (" #name ":%d) has been ignored, "                        \
 
2021
                "because out of range (%d, %d)\n", (val), (lim_min), (lim_max)));   \
 
2022
            return;                                                                 \
 
2023
        }                                                                           \
 
2024
        else                                                                        \
 
2025
            LogRel(("NAT: (" #name ":%d)\n", (val)));                               \
 
2026
    } while (0)
1777
2027
 
1778
2028
/* don't allow user set less 8kB and more than 1M values */
1779
2029
#define _8K_1M_CHECK_ARG(name, val) CHECK_ARG(name, (val), 8, 1024)
1798
2048
    tcp_sndspace = kilobytes * _1K;
1799
2049
}
1800
2050
 
 
2051
/*
 
2052
 * Looking for Ether by ip in ARP-cache
 
2053
 * Note: it´s responsible of caller to allocate buffer for result
 
2054
 * @returns iprt status code
 
2055
 */
 
2056
int slirp_arp_lookup_ether_by_ip(PNATState pData, uint32_t ip, uint8_t *ether)
 
2057
{
 
2058
    struct arp_cache_entry *ac;
 
2059
 
 
2060
    if (ether == NULL)
 
2061
        return VERR_INVALID_PARAMETER;
 
2062
 
 
2063
    if (LIST_EMPTY(&pData->arp_cache))
 
2064
        return VERR_NOT_FOUND;
 
2065
 
 
2066
    LIST_FOREACH(ac, &pData->arp_cache, list)
 
2067
    {
 
2068
        if (ac->ip == ip)
 
2069
        {
 
2070
            memcpy(ether, ac->ether, ETH_ALEN);
 
2071
            return VINF_SUCCESS;
 
2072
        }
 
2073
    }
 
2074
    return VERR_NOT_FOUND;
 
2075
}
 
2076
 
 
2077
/*
 
2078
 * Looking for IP by Ether in ARP-cache
 
2079
 * Note: it´s responsible of caller to allocate buffer for result
 
2080
 * @returns 0 - if found, 1 - otherwise
 
2081
 */
 
2082
int slirp_arp_lookup_ip_by_ether(PNATState pData, const uint8_t *ether, uint32_t *ip)
 
2083
{
 
2084
    struct arp_cache_entry *ac;
 
2085
    *ip = INADDR_ANY;
 
2086
 
 
2087
    if (LIST_EMPTY(&pData->arp_cache))
 
2088
        return VERR_NOT_FOUND;
 
2089
 
 
2090
    LIST_FOREACH(ac, &pData->arp_cache, list)
 
2091
    {
 
2092
        if (memcmp(ether, ac->ether, ETH_ALEN) == 0)
 
2093
        {
 
2094
            *ip = ac->ip;
 
2095
            return VINF_SUCCESS;
 
2096
        }
 
2097
    }
 
2098
    return VERR_NOT_FOUND;
 
2099
}
 
2100
 
1801
2101
void slirp_arp_who_has(PNATState pData, uint32_t dst)
1802
2102
{
1803
2103
    struct mbuf *m;
1804
2104
    struct ethhdr *ehdr;
1805
2105
    struct arphdr *ahdr;
1806
2106
 
 
2107
#ifndef VBOX_WITH_SLIRP_BSD_MBUF
1807
2108
    m = m_get(pData);
 
2109
#else
 
2110
    m = m_getcl(pData, M_NOWAIT, MT_HEADER, M_PKTHDR);
 
2111
#endif
1808
2112
    if (m == NULL)
1809
2113
    {
1810
2114
        LogRel(("NAT: Can't alloc mbuf for ARP request\n"));
1819
2123
    ahdr->ar_pln = 4;
1820
2124
    ahdr->ar_op = htons(ARPOP_REQUEST);
1821
2125
    memcpy(ahdr->ar_sha, special_ethaddr, ETH_ALEN);
1822
 
    *(uint32_t *)ahdr->ar_sip = htonl(ntohl(special_addr.s_addr) | CTL_ALIAS);
 
2126
    *(uint32_t *)ahdr->ar_sip = htonl(ntohl(pData->special_addr.s_addr) | CTL_ALIAS);
1823
2127
    memset(ahdr->ar_tha, 0xff, ETH_ALEN); /*broadcast*/
1824
2128
    *(uint32_t *)ahdr->ar_tip = dst;
 
2129
#ifndef VBOX_WITH_SLIRP_BSD_MBUF
1825
2130
    m->m_data += if_maxlinkhdr;
1826
2131
    m->m_len = sizeof(struct arphdr);
1827
 
    if_encap(pData, ETH_P_ARP, m);
1828
 
    LogRel(("NAT: ARP request sent\n"));
1829
 
}
 
2132
#else
 
2133
    /* warn!!! should falls in mbuf minimal size */
 
2134
    m->m_len = sizeof(struct arphdr) + ETH_HLEN;
 
2135
#endif
 
2136
    if_encap(pData, ETH_P_ARP, m, ETH_ENCAP_URG);
 
2137
}
 
2138
 
 
2139
int slirp_arp_cache_update_or_add(PNATState pData, uint32_t dst, const uint8_t *mac)
 
2140
{
 
2141
    if (slirp_arp_cache_update(pData, dst, mac))
 
2142
        slirp_arp_cache_add(pData, dst, mac);
 
2143
 
 
2144
    return 0;
 
2145
}
 
2146
 
1830
2147
/* updates the arp cache
1831
2148
 * @returns 0 - if has found and updated
1832
2149
 *          1 - if hasn't found.
1833
2150
 */
1834
 
int slirp_update_arp_cache(PNATState pData, uint32_t dst, const uint8_t *mac)
 
2151
int slirp_arp_cache_update(PNATState pData, uint32_t dst, const uint8_t *mac)
1835
2152
{
1836
2153
    struct arp_cache_entry *ac;
1837
2154
    LIST_FOREACH(ac, &pData->arp_cache, list)
1844
2161
    }
1845
2162
    return 1;
1846
2163
}
 
2164
 
 
2165
void slirp_arp_cache_add(PNATState pData, uint32_t ip, const uint8_t *ether)
 
2166
{
 
2167
    struct arp_cache_entry *ac = NULL;
 
2168
    ac = RTMemAllocZ(sizeof(struct arp_cache_entry));
 
2169
    if (ac == NULL)
 
2170
    {
 
2171
        LogRel(("NAT: Can't allocate arp cache entry\n"));
 
2172
        return;
 
2173
    }
 
2174
    ac->ip = ip;
 
2175
    memcpy(ac->ether, ether, ETH_ALEN);
 
2176
    LIST_INSERT_HEAD(&pData->arp_cache, ac, list);
 
2177
}
 
2178
 
 
2179
#ifdef VBOX_WITH_SLIRP_BSD_MBUF
 
2180
void slirp_set_mtu(PNATState pData, int mtu)
 
2181
{
 
2182
    if (mtu < 20 || mtu >= 16000)
 
2183
    {
 
2184
        LogRel(("NAT: mtu(%d) is out of range (20;16000] mtu forcely assigned to 1500\n", mtu));
 
2185
        mtu = 1500;
 
2186
    }
 
2187
    if_mtu =
 
2188
    if_mru = mtu;
 
2189
}
 
2190
#endif