VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/DrvNATlibslirp.cpp@ 107606

最後變更 在這個檔案從107606是 107549,由 vboxsync 提交於 2 月 前

Devices/Network: fix errant comma. bugref:10268

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 61.8 KB
 
1/* $Id: DrvNATlibslirp.cpp 107549 2025-01-08 23:52:49Z vboxsync $ */
2/** @file
3 * DrvNATlibslirp - NATlibslirp network transport driver.
4 */
5
6/*
7 * Copyright (C) 2022-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.alldomusa.eu.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#define LOG_GROUP LOG_GROUP_DRV_NAT
33#define RTNET_INCL_IN_ADDR
34#include "VBoxDD.h"
35
36#ifdef RT_OS_WINDOWS
37# include <iprt/win/winsock2.h>
38# include <iprt/win/ws2tcpip.h>
39# include "winutils.h"
40# define inet_aton(x, y) inet_pton(2, x, y)
41# define AF_INET6 23
42#endif
43
44#include <libslirp.h>
45
46#include <VBox/vmm/dbgf.h>
47#include <VBox/vmm/pdmdrv.h>
48#include <VBox/vmm/pdmnetifs.h>
49#include <VBox/vmm/pdmnetinline.h>
50
51#ifndef RT_OS_WINDOWS
52# include <unistd.h>
53# include <fcntl.h>
54# include <poll.h>
55# include <errno.h>
56#endif
57
58#ifdef RT_OS_FREEBSD
59# include <netinet/in.h>
60#endif
61
62#include <iprt/asm.h>
63#include <iprt/assert.h>
64#include <iprt/critsect.h>
65#include <iprt/cidr.h>
66#include <iprt/file.h>
67#include <iprt/mem.h>
68#include <iprt/net.h>
69#include <iprt/pipe.h>
70#include <iprt/string.h>
71#include <iprt/stream.h>
72#include <iprt/time.h>
73#include <iprt/uuid.h>
74
75#include <iprt/asm.h>
76
77#include <iprt/semaphore.h>
78#include <iprt/req.h>
79#ifdef RT_OS_DARWIN
80# include <SystemConfiguration/SystemConfiguration.h>
81# include <CoreFoundation/CoreFoundation.h>
82#endif
83
84#define COUNTERS_INIT
85#include "slirp/counters.h"
86#include "slirp/resolv_conf_parser.h"
87
88
89/*********************************************************************************************************************************
90* Defined Constants And Macros *
91*********************************************************************************************************************************/
92#define DRVNAT_MAXFRAMESIZE (16 * 1024)
93#define DRVNAT_DEFAULT_TIMEOUT (3600*1000)
94#define MAX_IP_ADDRESS_STR_LEN_W_NULL 16
95
96#define GET_EXTRADATA(pdrvins, node, name, rc, type, type_name, var) \
97 do { \
98 (rc) = (pdrvins)->pHlpR3->pfnCFGMQuery ## type((node), name, &(var)); \
99 if (RT_FAILURE((rc)) && (rc) != VERR_CFGM_VALUE_NOT_FOUND) \
100 return PDMDrvHlpVMSetError((pdrvins), (rc), RT_SRC_POS, \
101 N_("NAT#%d: configuration query for \"" name "\" " #type_name " failed"), \
102 (pdrvins)->iInstance); \
103 } while (0)
104
105#define GET_ED_STRICT(pdrvins, node, name, rc, type, type_name, var) \
106 do { \
107 (rc) = (pdrvins)->pHlpR3->pfnCFGMQuery ## type((node), name, &(var)); \
108 if (RT_FAILURE((rc))) \
109 return PDMDrvHlpVMSetError((pdrvins), (rc), RT_SRC_POS, \
110 N_("NAT#%d: configuration query for \"" name "\" " #type_name " failed"), \
111 (pdrvins)->iInstance); \
112 } while (0)
113
114#define GET_EXTRADATA_N(pdrvins, node, name, rc, type, type_name, var, var_size) \
115 do { \
116 (rc) = (pdrvins)->pHlpR3->pfnCFGMQuery ## type((node), name, &(var), var_size); \
117 if (RT_FAILURE((rc)) && (rc) != VERR_CFGM_VALUE_NOT_FOUND) \
118 return PDMDrvHlpVMSetError((pdrvins), (rc), RT_SRC_POS, \
119 N_("NAT#%d: configuration query for \"" name "\" " #type_name " failed"), \
120 (pdrvins)->iInstance); \
121 } while (0)
122
123#define GET_BOOL(rc, pdrvins, node, name, var) \
124 GET_EXTRADATA(pdrvins, node, name, (rc), Bool, bolean, (var))
125#define GET_STRING(rc, pdrvins, node, name, var, var_size) \
126 GET_EXTRADATA_N(pdrvins, node, name, (rc), String, string, (var), (var_size))
127#define GET_STRING_ALLOC(rc, pdrvins, node, name, var) \
128 GET_EXTRADATA(pdrvins, node, name, (rc), StringAlloc, string, (var))
129#define GET_S32(rc, pdrvins, node, name, var) \
130 GET_EXTRADATA(pdrvins, node, name, (rc), S32, int, (var))
131#define GET_S32_STRICT(rc, pdrvins, node, name, var) \
132 GET_ED_STRICT(pdrvins, node, name, (rc), S32, int, (var))
133
134#define DO_GET_IP(rc, node, instance, status, x) \
135 do { \
136 char sz##x[32]; \
137 GET_STRING((rc), (node), (instance), #x, sz ## x[0], sizeof(sz ## x)); \
138 if (rc != VERR_CFGM_VALUE_NOT_FOUND) \
139 (status) = inet_aton(sz ## x, &x); \
140 } while (0)
141
142#define GETIP_DEF(rc, node, instance, x, def) \
143 do \
144 { \
145 int status = 0; \
146 DO_GET_IP((rc), (node), (instance), status, x); \
147 if (status == 0 || rc == VERR_CFGM_VALUE_NOT_FOUND) \
148 x.s_addr = def; \
149 } while (0)
150
151
152/*********************************************************************************************************************************
153* Structures and Typedefs *
154*********************************************************************************************************************************/
155/** Slirp Timer */
156typedef struct slirpTimer
157{
158 struct slirpTimer *next;
159 int64_t uTimeExpire;
160 SlirpTimerCb pHandler;
161 void *opaque;
162} SlirpTimer;
163
164/**
165 * Main state of Libslirp NAT
166 */
167typedef struct SlirpState
168{
169 unsigned int nsock;
170
171 Slirp *pSlirp;
172 struct pollfd *polls;
173
174 /** Num Polls (not bytes) */
175 unsigned int uPollCap = 0;
176
177 SlirpTimer *pTimerHead;
178 bool fPassDomain;
179} SlirpState;
180typedef SlirpState *pSlirpState;
181
182/**
183 * NAT network transport driver instance data.
184 *
185 * @implements PDMINETWORKUP
186 */
187typedef struct DRVNAT
188{
189 /** The network interface. */
190 PDMINETWORKUP INetworkUp;
191 /** The network NAT Engine configuration. */
192 PDMINETWORKNATCONFIG INetworkNATCfg;
193 /** The port we're attached to. */
194 PPDMINETWORKDOWN pIAboveNet;
195 /** The network config of the port we're attached to. */
196 PPDMINETWORKCONFIG pIAboveConfig;
197 /** Pointer to the driver instance. */
198 PPDMDRVINS pDrvIns;
199 /** Link state */
200 PDMNETWORKLINKSTATE enmLinkState;
201 /** NAT state */
202 pSlirpState pNATState;
203 /** TFTP directory prefix. */
204 char *pszTFTPPrefix;
205 /** Boot file name to provide in the DHCP server response. */
206 char *pszBootFile;
207 /** tftp server name to provide in the DHCP server response. */
208 char *pszNextServer;
209 /** Polling thread. */
210 PPDMTHREAD pSlirpThread;
211 /** Queue for NAT-thread-external events. */
212 RTREQQUEUE hSlirpReqQueue;
213 /** The guest IP for port-forwarding. */
214 uint32_t GuestIP;
215 /** Link state set when the VM is suspended. */
216 PDMNETWORKLINKSTATE enmLinkStateWant;
217
218#ifndef RT_OS_WINDOWS
219 /** The write end of the control pipe. */
220 RTPIPE hPipeWrite;
221 /** The read end of the control pipe. */
222 RTPIPE hPipeRead;
223#else
224 /* wakeup socket pair for NAT thread */
225 SOCKET pWakeupSockPair[2];
226#endif
227 /* count of bytes sent to notify NAT thread */
228 volatile uint64_t cbWakeupNotifs;
229
230#define DRV_PROFILE_COUNTER(name, dsc) STAMPROFILE Stat ## name
231#define DRV_COUNTING_COUNTER(name, dsc) STAMCOUNTER Stat ## name
232#include "slirp/counters.h"
233 /** thread delivering packets for receiving by the guest */
234 PPDMTHREAD pRecvThread;
235 /** event to wakeup the guest receive thread */
236 RTSEMEVENT EventRecv;
237 /** Receive Req queue (deliver packets to the guest) */
238 RTREQQUEUE hRecvReqQueue;
239
240 /** makes access to device func RecvAvail and Recv atomical. */
241 RTCRITSECT DevAccessLock;
242 /** Number of in-flight packets. */
243 volatile uint32_t cPkts;
244
245 /** Transmit lock taken by BeginXmit and released by EndXmit. */
246 RTCRITSECT XmitLock;
247
248#ifdef RT_OS_DARWIN
249 /* Handle of the DNS watcher runloop source. */
250 CFRunLoopSourceRef hRunLoopSrcDnsWatcher;
251#endif
252} DRVNAT;
253AssertCompileMemberAlignment(DRVNAT, StatNATRecvWakeups, 8);
254/** Pointer to the NAT driver instance data. */
255typedef DRVNAT *PDRVNAT;
256
257
258/*********************************************************************************************************************************
259* Internal Functions *
260*********************************************************************************************************************************/
261static void drvNATNotifyNATThread(PDRVNAT pThis, const char *pszWho);
262static void drvNAT_UpdateTimeout(uint32_t *uTimeout, void *opaque);
263static void drvNAT_CheckTimeout(void *opaque);
264static DECLCALLBACK(int) drvNAT_AddPollCb(int iFd, int iEvents, void *opaque);
265static DECLCALLBACK(int64_t) drvNAT_ClockGetNsCb(void *opaque);
266static DECLCALLBACK(int) drvNAT_GetREventsCb(int idx, void *opaque);
267static DECLCALLBACK(int) drvNATNotifyApplyPortForwardCommand(PDRVNAT pThis, bool fRemove,
268 bool fUdp, const char *pHostIp,
269 uint16_t u16HostPort, const char *pGuestIp, uint16_t u16GuestPort);
270
271
272
273/*
274 * PDM Function Implementations
275 */
276
277/**
278 * @callback_method_impl{FNPDMTHREADDRV}
279 *
280 * Queues guest process received packet. Triggered by drvNATRecvWakeup.
281 */
282static DECLCALLBACK(int) drvNATRecv(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
283{
284 PDRVNAT pThis = PDMINS_2_DATA(pDrvIns, PDRVNAT);
285
286 if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
287 return VINF_SUCCESS;
288
289 while (pThread->enmState == PDMTHREADSTATE_RUNNING)
290 {
291 RTReqQueueProcess(pThis->hRecvReqQueue, 0);
292 if (ASMAtomicReadU32(&pThis->cPkts) == 0)
293 RTSemEventWait(pThis->EventRecv, RT_INDEFINITE_WAIT);
294 }
295 return VINF_SUCCESS;
296}
297
298/**
299 * @callback_method_impl{FNPDMTHREADWAKEUPDRV}
300 */
301static DECLCALLBACK(int) drvNATRecvWakeup(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
302{
303 RT_NOREF(pThread);
304 PDRVNAT pThis = PDMINS_2_DATA(pDrvIns, PDRVNAT);
305 int rc;
306 rc = RTSemEventSignal(pThis->EventRecv);
307
308 STAM_COUNTER_INC(&pThis->StatNATRecvWakeups);
309 return VINF_SUCCESS;
310}
311
312/**
313 * @brief Processes incoming packet (to guest).
314 *
315 * @param pThis Pointer to DRVNAT state for current context.
316 * @param pBuf Pointer to packet buffer.
317 * @param cb Size of packet in buffer.
318 *
319 * @thread NAT
320 */
321static DECLCALLBACK(void) drvNATRecvWorker(PDRVNAT pThis, void *pBuf, size_t cb)
322{
323 int rc;
324 STAM_PROFILE_START(&pThis->StatNATRecv, a);
325
326 rc = RTCritSectEnter(&pThis->DevAccessLock);
327 AssertRC(rc);
328
329 STAM_PROFILE_START(&pThis->StatNATRecvWait, b);
330 rc = pThis->pIAboveNet->pfnWaitReceiveAvail(pThis->pIAboveNet, RT_INDEFINITE_WAIT);
331 STAM_PROFILE_STOP(&pThis->StatNATRecvWait, b);
332
333 if (RT_SUCCESS(rc))
334 {
335 rc = pThis->pIAboveNet->pfnReceive(pThis->pIAboveNet, pBuf, cb);
336 AssertRC(rc);
337 RTMemFree(pBuf);
338 pBuf = NULL;
339 }
340 else if ( rc != VERR_TIMEOUT
341 && rc != VERR_INTERRUPTED)
342 {
343 AssertRC(rc);
344 }
345
346 rc = RTCritSectLeave(&pThis->DevAccessLock);
347 AssertRC(rc);
348 ASMAtomicDecU32(&pThis->cPkts);
349 drvNATNotifyNATThread(pThis, "drvNATRecvWorker");
350 STAM_PROFILE_STOP(&pThis->StatNATRecv, a);
351}
352
353/**
354 * Frees a S/G buffer allocated by drvNATNetworkUp_AllocBuf.
355 *
356 * @param pThis Pointer to the NAT instance.
357 * @param pSgBuf The S/G buffer to free.
358 *
359 * @thread NAT
360 */
361static void drvNATFreeSgBuf(PDRVNAT pThis, PPDMSCATTERGATHER pSgBuf)
362{
363 RT_NOREF(pThis);
364 Assert((pSgBuf->fFlags & PDMSCATTERGATHER_FLAGS_MAGIC_MASK) == PDMSCATTERGATHER_FLAGS_MAGIC);
365 pSgBuf->fFlags = 0;
366 if (pSgBuf->pvAllocator)
367 {
368 Assert(!pSgBuf->pvUser);
369 RTMemFree(pSgBuf->aSegs[0].pvSeg);
370 }
371 else if (pSgBuf->pvUser)
372 {
373 RTMemFree(pSgBuf->aSegs[0].pvSeg);
374 pSgBuf->aSegs[0].pvSeg = NULL;
375 RTMemFree(pSgBuf->pvUser);
376 pSgBuf->pvUser = NULL;
377 }
378 RTMemFree(pSgBuf);
379}
380
381/**
382 * Worker function for drvNATSend().
383 *
384 * @param pThis Pointer to the NAT instance.
385 * @param pSgBuf The scatter/gather buffer.
386 * @thread NAT
387 */
388static DECLCALLBACK(void) drvNATSendWorker(PDRVNAT pThis, PPDMSCATTERGATHER pSgBuf)
389{
390 LogFlowFunc(("pThis=%p pSgBuf=%p\n", pThis, pSgBuf));
391
392 if (pThis->enmLinkState == PDMNETWORKLINKSTATE_UP)
393 {
394 const uint8_t *m = static_cast<const uint8_t*>(pSgBuf->pvAllocator);
395 if (m)
396 {
397 /*
398 * A normal frame.
399 */
400 LogFlowFunc(("m=%p\n", m));
401 slirp_input(pThis->pNATState->pSlirp, (uint8_t const *)pSgBuf->pvAllocator, (int)pSgBuf->cbUsed);
402 }
403 else
404 {
405 /*
406 * M_EXT buf, need to segment it.
407 */
408
409 uint8_t const *pbFrame = (uint8_t const *)pSgBuf->aSegs[0].pvSeg;
410 PCPDMNETWORKGSO pGso = (PCPDMNETWORKGSO)pSgBuf->pvUser;
411 /* Do not attempt to segment frames with invalid GSO parameters. */
412 if (PDMNetGsoIsValid((const PDMNETWORKGSO *)pGso, sizeof(*pGso), pSgBuf->cbUsed))
413 {
414 uint32_t const cSegs = PDMNetGsoCalcSegmentCount(pGso, pSgBuf->cbUsed);
415 Assert(cSegs > 1);
416 for (uint32_t iSeg = 0; iSeg < cSegs; iSeg++)
417 {
418 void *pvSeg;
419 pvSeg = RTMemAlloc(DRVNAT_MAXFRAMESIZE);
420
421 uint32_t cbPayload, cbHdrs;
422 uint32_t offPayload = PDMNetGsoCarveSegment(pGso, pbFrame, pSgBuf->cbUsed,
423 iSeg, cSegs, (uint8_t *)pvSeg, &cbHdrs, &cbPayload);
424 memcpy((uint8_t *)pvSeg + cbHdrs, pbFrame + offPayload, cbPayload);
425
426 slirp_input(pThis->pNATState->pSlirp, (uint8_t const *)pvSeg, cbPayload + cbHdrs);
427 RTMemFree(pvSeg);
428 }
429 }
430 }
431 }
432
433 LogFlowFunc(("leave\n"));
434 drvNATFreeSgBuf(pThis, pSgBuf);
435}
436
437/**
438 * @interface_method_impl{PDMINETWORKUP,pfnBeginXmit}
439 */
440static DECLCALLBACK(int) drvNATNetworkUp_BeginXmit(PPDMINETWORKUP pInterface, bool fOnWorkerThread)
441{
442 RT_NOREF(fOnWorkerThread);
443 PDRVNAT pThis = RT_FROM_MEMBER(pInterface, DRVNAT, INetworkUp);
444 int rc = RTCritSectTryEnter(&pThis->XmitLock);
445 if (RT_FAILURE(rc))
446 {
447 /** @todo Kick the worker thread when we have one... */
448 rc = VERR_TRY_AGAIN;
449 }
450 LogFlowFunc(("Beginning xmit...\n"));
451 return rc;
452}
453
454/**
455 * @interface_method_impl{PDMINETWORKUP,pfnAllocBuf}
456 */
457static DECLCALLBACK(int) drvNATNetworkUp_AllocBuf(PPDMINETWORKUP pInterface, size_t cbMin,
458 PCPDMNETWORKGSO pGso, PPPDMSCATTERGATHER ppSgBuf)
459{
460 PDRVNAT pThis = RT_FROM_MEMBER(pInterface, DRVNAT, INetworkUp);
461 Assert(RTCritSectIsOwner(&pThis->XmitLock));
462
463 LogFlowFuncEnter();
464
465 /*
466 * Drop the incoming frame if the NAT thread isn't running.
467 */
468 if (pThis->pSlirpThread->enmState != PDMTHREADSTATE_RUNNING)
469 {
470 Log(("drvNATNetowrkUp_AllocBuf: returns VERR_NET_DOWN\n"));
471 return VERR_NET_DOWN;
472 }
473
474 /*
475 * Allocate a scatter/gather buffer and an mbuf.
476 */
477 PPDMSCATTERGATHER pSgBuf = (PPDMSCATTERGATHER)RTMemAllocZ(sizeof(PDMSCATTERGATHER));
478 if (!pSgBuf)
479 return VERR_NO_MEMORY;
480 if (!pGso)
481 {
482 /*
483 * Drop the frame if it is too big.
484 */
485 if (cbMin >= DRVNAT_MAXFRAMESIZE)
486 {
487 Log(("drvNATNetowrkUp_AllocBuf: drops over-sized frame (%u bytes), returns VERR_INVALID_PARAMETER\n",
488 cbMin));
489 RTMemFree(pSgBuf);
490 return VERR_INVALID_PARAMETER;
491 }
492
493 pSgBuf->pvUser = NULL;
494 pSgBuf->aSegs[0].cbSeg = RT_ALIGN_Z(cbMin, 128);
495 pSgBuf->aSegs[0].pvSeg = RTMemAlloc(pSgBuf->aSegs[0].cbSeg);
496 pSgBuf->pvAllocator = pSgBuf->aSegs[0].pvSeg;
497
498 if (!pSgBuf->pvAllocator)
499 {
500 RTMemFree(pSgBuf);
501 return VERR_TRY_AGAIN;
502 }
503 }
504 else
505 {
506 /*
507 * Drop the frame if its segment is too big.
508 */
509 if (pGso->cbHdrsTotal + pGso->cbMaxSeg >= DRVNAT_MAXFRAMESIZE)
510 {
511 Log(("drvNATNetowrkUp_AllocBuf: drops over-sized frame (%u bytes), returns VERR_INVALID_PARAMETER\n",
512 pGso->cbHdrsTotal + pGso->cbMaxSeg));
513 RTMemFree(pSgBuf);
514 return VERR_INVALID_PARAMETER;
515 }
516
517 pSgBuf->pvUser = RTMemDup(pGso, sizeof(*pGso));
518 pSgBuf->pvAllocator = NULL;
519
520 pSgBuf->aSegs[0].cbSeg = RT_ALIGN_Z(cbMin, 128);
521 pSgBuf->aSegs[0].pvSeg = RTMemAlloc(pSgBuf->aSegs[0].cbSeg);
522 if (!pSgBuf->pvUser || !pSgBuf->aSegs[0].pvSeg)
523 {
524 RTMemFree(pSgBuf->aSegs[0].pvSeg);
525 RTMemFree(pSgBuf->pvUser);
526 RTMemFree(pSgBuf);
527 return VERR_TRY_AGAIN;
528 }
529 }
530
531 /*
532 * Initialize the S/G buffer and return.
533 */
534 pSgBuf->fFlags = PDMSCATTERGATHER_FLAGS_MAGIC | PDMSCATTERGATHER_FLAGS_OWNER_1;
535 pSgBuf->cbUsed = 0;
536 pSgBuf->cbAvailable = pSgBuf->aSegs[0].cbSeg;
537 pSgBuf->cSegs = 1;
538
539 *ppSgBuf = pSgBuf;
540 return VINF_SUCCESS;
541}
542
543/**
544 * @interface_method_impl{PDMINETWORKUP,pfnFreeBuf}
545 */
546static DECLCALLBACK(int) drvNATNetworkUp_FreeBuf(PPDMINETWORKUP pInterface, PPDMSCATTERGATHER pSgBuf)
547{
548 PDRVNAT pThis = RT_FROM_MEMBER(pInterface, DRVNAT, INetworkUp);
549 Assert(RTCritSectIsOwner(&pThis->XmitLock));
550 drvNATFreeSgBuf(pThis, pSgBuf);
551 return VINF_SUCCESS;
552}
553
554/**
555 * @interface_method_impl{PDMINETWORKUP,pfnSendBuf}
556 */
557static DECLCALLBACK(int) drvNATNetworkUp_SendBuf(PPDMINETWORKUP pInterface, PPDMSCATTERGATHER pSgBuf, bool fOnWorkerThread)
558{
559 RT_NOREF(fOnWorkerThread);
560 PDRVNAT pThis = RT_FROM_MEMBER(pInterface, DRVNAT, INetworkUp);
561 Assert((pSgBuf->fFlags & PDMSCATTERGATHER_FLAGS_OWNER_MASK) == PDMSCATTERGATHER_FLAGS_OWNER_1);
562 Assert(RTCritSectIsOwner(&pThis->XmitLock));
563
564 LogFlowFunc(("enter\n"));
565
566 int rc;
567 if (pThis->pSlirpThread->enmState == PDMTHREADSTATE_RUNNING)
568 {
569 rc = RTReqQueueCallEx(pThis->hSlirpReqQueue, NULL /*ppReq*/, 0 /*cMillies*/, RTREQFLAGS_VOID | RTREQFLAGS_NO_WAIT,
570 (PFNRT)drvNATSendWorker, 2, pThis, pSgBuf);
571 if (RT_SUCCESS(rc))
572 {
573 drvNATNotifyNATThread(pThis, "drvNATNetworkUp_SendBuf");
574 LogFlowFunc(("leave success\n"));
575 return VINF_SUCCESS;
576 }
577
578 rc = VERR_NET_NO_BUFFER_SPACE;
579 }
580 else
581 rc = VERR_NET_DOWN;
582 drvNATFreeSgBuf(pThis, pSgBuf);
583 LogFlowFunc(("leave rc=%Rrc\n", rc));
584 return rc;
585}
586
587/**
588 * @interface_method_impl{PDMINETWORKUP,pfnEndXmit}
589 */
590static DECLCALLBACK(void) drvNATNetworkUp_EndXmit(PPDMINETWORKUP pInterface)
591{
592 PDRVNAT pThis = RT_FROM_MEMBER(pInterface, DRVNAT, INetworkUp);
593 RTCritSectLeave(&pThis->XmitLock);
594}
595
596/**
597 * Get the NAT thread out of poll/WSAWaitForMultipleEvents
598 */
599static void drvNATNotifyNATThread(PDRVNAT pThis, const char *pszWho)
600{
601 RT_NOREF(pszWho);
602 int rc = 0;
603#ifndef RT_OS_WINDOWS
604 /* kick poll() */
605 size_t cbIgnored;
606 rc = RTPipeWrite(pThis->hPipeWrite, "", 1, &cbIgnored);
607 if (RT_SUCCESS(rc))
608 {
609 /* Count how many bites we send down the socket */
610 ASMAtomicIncU64(&pThis->cbWakeupNotifs);
611 }
612#else
613 int cbWritten = send(pThis->pWakeupSockPair[0], "", 1, NULL);
614 if (cbWritten == SOCKET_ERROR)
615 {
616 Log4(("Notify NAT Thread Error %d\n", WSAGetLastError()));
617 }
618 else
619 {
620 /* Count how many bites we send down the socket */
621 ASMAtomicIncU64(&pThis->cbWakeupNotifs);
622 }
623#endif
624 AssertRC(rc);
625}
626
627/**
628 * @interface_method_impl{PDMINETWORKUP,pfnSetPromiscuousMode}
629 */
630static DECLCALLBACK(void) drvNATNetworkUp_SetPromiscuousMode(PPDMINETWORKUP pInterface, bool fPromiscuous)
631{
632 RT_NOREF(pInterface, fPromiscuous);
633 LogFlow(("drvNATNetworkUp_SetPromiscuousMode: fPromiscuous=%d\n", fPromiscuous));
634 /* nothing to do */
635}
636
637/**
638 * Worker function for drvNATNetworkUp_NotifyLinkChanged().
639 * @thread "NAT" thread.
640 *
641 * @param pThis Pointer to DRVNAT state for current context.
642 * @param enmLinkState Enum value of link state.
643 *
644 * @thread NAT
645 */
646static DECLCALLBACK(void) drvNATNotifyLinkChangedWorker(PDRVNAT pThis, PDMNETWORKLINKSTATE enmLinkState)
647{
648 pThis->enmLinkState = pThis->enmLinkStateWant = enmLinkState;
649 switch (enmLinkState)
650 {
651 case PDMNETWORKLINKSTATE_UP:
652 LogRel(("NAT: Link up\n"));
653 break;
654
655 case PDMNETWORKLINKSTATE_DOWN:
656 case PDMNETWORKLINKSTATE_DOWN_RESUME:
657 LogRel(("NAT: Link down\n"));
658 break;
659
660 default:
661 AssertMsgFailed(("drvNATNetworkUp_NotifyLinkChanged: unexpected link state %d\n", enmLinkState));
662 }
663}
664
665/**
666 * Notification on link status changes.
667 *
668 * @param pInterface Pointer to the interface structure containing the called function pointer.
669 * @param enmLinkState The new link state.
670 *
671 * @thread EMT
672 */
673static DECLCALLBACK(void) drvNATNetworkUp_NotifyLinkChanged(PPDMINETWORKUP pInterface, PDMNETWORKLINKSTATE enmLinkState)
674{
675 PDRVNAT pThis = RT_FROM_MEMBER(pInterface, DRVNAT, INetworkUp);
676
677 LogFlow(("drvNATNetworkUp_NotifyLinkChanged: enmLinkState=%d\n", enmLinkState));
678
679 /* Don't queue new requests if the NAT thread is not running (e.g. paused,
680 * stopping), otherwise we would deadlock. Memorize the change. */
681 if (pThis->pSlirpThread->enmState != PDMTHREADSTATE_RUNNING)
682 {
683 pThis->enmLinkStateWant = enmLinkState;
684 return;
685 }
686
687 PRTREQ pReq;
688 int rc = RTReqQueueCallEx(pThis->hSlirpReqQueue, &pReq, 0 /*cMillies*/, RTREQFLAGS_VOID,
689 (PFNRT)drvNATNotifyLinkChangedWorker, 2, pThis, enmLinkState);
690 if (rc == VERR_TIMEOUT)
691 {
692 drvNATNotifyNATThread(pThis, "drvNATNetworkUp_NotifyLinkChanged");
693 rc = RTReqWait(pReq, RT_INDEFINITE_WAIT);
694 AssertRC(rc);
695 }
696 else
697 AssertRC(rc);
698 RTReqRelease(pReq);
699}
700
701/**
702 * NAT thread handling the slirp stuff.
703 *
704 * The slirp implementation is single-threaded so we execute this enginre in a
705 * dedicated thread. We take care that this thread does not become the
706 * bottleneck: If the guest wants to send, a request is enqueued into the
707 * hSlirpReqQueue and handled asynchronously by this thread. If this thread
708 * wants to deliver packets to the guest, it enqueues a request into
709 * hRecvReqQueue which is later handled by the Recv thread.
710 *
711 * @param pDrvIns Pointer to PDM driver context.
712 * @param pThread Pointer to calling thread context.
713 *
714 * @returns VBox status code
715 *
716 * @thread NAT
717 */
718static DECLCALLBACK(int) drvNATAsyncIoThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
719{
720 PDRVNAT pThis = PDMINS_2_DATA(pDrvIns, PDRVNAT);
721#ifdef RT_OS_WINDOWS
722 drvNAT_AddPollCb(pThis->pWakeupSockPair[1], SLIRP_POLL_IN | SLIRP_POLL_HUP, pThis);
723 pThis->pNATState->polls[0].fd = pThis->pWakeupSockPair[1];
724#else
725 unsigned int cPollNegRet = 0;
726 drvNAT_AddPollCb(RTPipeToNative(pThis->hPipeRead), SLIRP_POLL_IN | SLIRP_POLL_HUP, pThis);
727 pThis->pNATState->polls[0].fd = RTPipeToNative(pThis->hPipeRead);
728 pThis->pNATState->polls[0].events = POLLRDNORM | POLLPRI | POLLRDBAND;
729 pThis->pNATState->polls[0].revents = 0;
730#endif /* !RT_OS_WINDOWS */
731
732 LogFlow(("drvNATAsyncIoThread: pThis=%p\n", pThis));
733
734 if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
735 return VINF_SUCCESS;
736
737 if (pThis->enmLinkStateWant != pThis->enmLinkState)
738 drvNATNotifyLinkChangedWorker(pThis, pThis->enmLinkStateWant);
739
740 /*
741 * Polling loop.
742 */
743 while (pThread->enmState == PDMTHREADSTATE_RUNNING)
744 {
745 /*
746 * To prevent concurrent execution of sending/receiving threads
747 */
748
749 uint32_t uTimeout = DRVNAT_DEFAULT_TIMEOUT;
750 pThis->pNATState->nsock = 1;
751
752 slirp_pollfds_fill(pThis->pNATState->pSlirp, &uTimeout, drvNAT_AddPollCb /* SlirpAddPollCb */, pThis /* opaque */);
753 drvNAT_UpdateTimeout(&uTimeout, pThis);
754
755#ifdef RT_OS_WINDOWS
756 int cChangedFDs = WSAPoll(pThis->pNATState->polls, pThis->pNATState->nsock, uTimeout /* timeout */);
757 /* Note: This must be called IMMEDIATELY after WSAPoll. */
758 int error = WSAGetLastError();
759#else
760 int cChangedFDs = poll(pThis->pNATState->polls, pThis->pNATState->nsock, uTimeout /* timeout */);
761#endif
762 if (cChangedFDs < 0)
763 {
764#ifdef RT_OS_WINDOWS
765 LogRel(("NAT: RTWinPoll returned error=%Rrc (cChangedFDs=%d)\n", error, cChangedFDs));
766 Log4(("NAT: NSOCK = %d\n", pThis->pNATState->nsock));
767#else
768 if (errno == EINTR)
769 {
770 Log2(("NAT: signal was caught while sleep on poll\n"));
771 /* No error, just process all outstanding requests but don't wait */
772 cChangedFDs = 0;
773 }
774 else if (cPollNegRet++ > 128)
775 {
776 LogRel(("NAT: Poll returns (%s) suppressed %d\n", strerror(errno), cPollNegRet));
777 cPollNegRet = 0;
778 }
779#endif
780 }
781
782 Log4(("%s: poll\n", __FUNCTION__));
783 slirp_pollfds_poll(pThis->pNATState->pSlirp, cChangedFDs < 0, drvNAT_GetREventsCb /* SlirpGetREventsCb */, pThis /* opaque */);
784
785 if (pThis->pNATState->polls[0].revents & (POLLRDNORM|POLLPRI|POLLRDBAND)) /* POLLPRI won't be seen with WSAPoll. */
786 {
787 /* drain the pipe
788 *
789 * Note! drvNATSend decoupled so we don't know how many times
790 * device's thread sends before we've entered multiplex,
791 * so to avoid false alarm drain pipe here to the very end
792 */
793 char ch[1024];
794 size_t cbRead;
795 uint64_t cbWakeupNotifs = ASMAtomicReadU64(&pThis->cbWakeupNotifs);
796#ifdef RT_OS_WINDOWS
797 cbRead = recv(pThis->pWakeupSockPair[1], &ch[0], RT_MIN(cbWakeupNotifs, 1024), NULL);
798#else
799 RTPipeRead(pThis->hPipeRead, &ch[0], RT_MIN(cbWakeupNotifs, 1024), &cbRead);
800#endif
801 ASMAtomicSubU64(&pThis->cbWakeupNotifs, cbRead);
802 }
803
804 /* process _all_ outstanding requests but don't wait */
805 RTReqQueueProcess(pThis->hSlirpReqQueue, 0);
806 drvNAT_CheckTimeout(pThis);
807 }
808
809 return VINF_SUCCESS;
810}
811
812/**
813 * Unblock the send thread so it can respond to a state change.
814 *
815 * @returns VBox status code.
816 * @param pDrvIns The pcnet device instance.
817 * @param pThread The send thread.
818 *
819 * @thread ?
820 */
821static DECLCALLBACK(int) drvNATAsyncIoWakeup(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
822{
823 RT_NOREF(pThread);
824 PDRVNAT pThis = PDMINS_2_DATA(pDrvIns, PDRVNAT);
825
826 drvNATNotifyNATThread(pThis, "drvNATAsyncIoWakeup");
827 return VINF_SUCCESS;
828}
829
830/**
831 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
832 */
833static DECLCALLBACK(void *) drvNATQueryInterface(PPDMIBASE pInterface, const char *pszIID)
834{
835 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
836 PDRVNAT pThis = PDMINS_2_DATA(pDrvIns, PDRVNAT);
837
838 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
839 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKUP, &pThis->INetworkUp);
840 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKNATCONFIG, &pThis->INetworkNATCfg);
841 return NULL;
842}
843
844/**
845 * Info handler.
846 *
847 * @param pDrvIns The PDM driver context.
848 * @param pHlp ....
849 * @param pszArgs Unused.
850 *
851 * @thread any
852 */
853static DECLCALLBACK(void) drvNATInfo(PPDMDRVINS pDrvIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
854{
855 RT_NOREF(pszArgs);
856 PDRVNAT pThis = PDMINS_2_DATA(pDrvIns, PDRVNAT);
857 pHlp->pfnPrintf(pHlp, "libslirp Connection Info:\n");
858 pHlp->pfnPrintf(pHlp, slirp_connection_info(pThis->pNATState->pSlirp));
859 pHlp->pfnPrintf(pHlp, "libslirp Neighbor Info:\n");
860 pHlp->pfnPrintf(pHlp, slirp_neighbor_info(pThis->pNATState->pSlirp));
861 pHlp->pfnPrintf(pHlp, "libslirp Version String: %s \n", slirp_version_string());
862}
863
864/**
865 * Sets up the redirectors.
866 *
867 * @returns VBox status code.
868 * @param uInstance ?
869 * @param pThis ?
870 * @param pCfg The configuration handle.
871 * @param pNetwork Unused.
872 *
873 * @thread ?
874 */
875static int drvNATConstructRedir(unsigned iInstance, PDRVNAT pThis, PCFGMNODE pCfg, PRTNETADDRIPV4 pNetwork)
876{
877 /** @todo r=jack: rewrite to support IPv6? */
878 PPDMDRVINS pDrvIns = pThis->pDrvIns;
879 PCPDMDRVHLPR3 pHlp = pDrvIns->pHlpR3;
880
881 RT_NOREF(pNetwork); /** @todo figure why pNetwork isn't used */
882
883 PCFGMNODE pPFTree = pHlp->pfnCFGMGetChild(pCfg, "PortForwarding");
884 if (pPFTree == NULL)
885 return VINF_SUCCESS;
886
887 /*
888 * Enumerate redirections.
889 */
890 for (PCFGMNODE pNode = pHlp->pfnCFGMGetFirstChild(pPFTree); pNode; pNode = pHlp->pfnCFGMGetNextChild(pNode))
891 {
892 /*
893 * Validate the port forwarding config.
894 */
895 if (!pHlp->pfnCFGMAreValuesValid(pNode, "Name\0Protocol\0UDP\0HostPort\0GuestPort\0GuestIP\0BindIP\0"))
896 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES,
897 N_("Unknown configuration in port forwarding"));
898
899 /* protocol type */
900 bool fUDP;
901 char szProtocol[32];
902 int rc;
903 GET_STRING(rc, pDrvIns, pNode, "Protocol", szProtocol[0], sizeof(szProtocol));
904 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
905 {
906 fUDP = false;
907 GET_BOOL(rc, pDrvIns, pNode, "UDP", fUDP);
908 }
909 else if (RT_SUCCESS(rc))
910 {
911 if (!RTStrICmp(szProtocol, "TCP"))
912 fUDP = false;
913 else if (!RTStrICmp(szProtocol, "UDP"))
914 fUDP = true;
915 else
916 return PDMDrvHlpVMSetError(pDrvIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
917 N_("NAT#%d: Invalid configuration value for \"Protocol\": \"%s\""),
918 iInstance, szProtocol);
919 }
920 else
921 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
922 N_("NAT#%d: configuration query for \"Protocol\" failed"),
923 iInstance);
924 /* host port */
925 int32_t iHostPort;
926 GET_S32_STRICT(rc, pDrvIns, pNode, "HostPort", iHostPort);
927
928 /* guest port */
929 int32_t iGuestPort;
930 GET_S32_STRICT(rc, pDrvIns, pNode, "GuestPort", iGuestPort);
931
932 /** @todo r=jack: why are we using IP INADD_ANY for port forward when FE does not do so. */
933 /* host address ("BindIP" name is rather unfortunate given "HostPort" to go with it) */
934 char mHostIp[MAX_IP_ADDRESS_STR_LEN_W_NULL];
935 RT_ZERO(mHostIp);
936 // GETIP_DEF(rc, pDrvIns, pNode, mHostIp, INADDR_ANY);
937 GET_STRING(rc, pDrvIns, pNode, "BindIP", mHostIp[0], sizeof(mHostIp));
938
939 /* guest address */
940 char mGuestIp[MAX_IP_ADDRESS_STR_LEN_W_NULL];
941 RT_ZERO(mGuestIp);
942 // GETIP_DEF(rc, pDrvIns, pNode, mGuestIp, INADDR_ANY);
943 GET_STRING(rc, pDrvIns, pNode, "GuestIP", mGuestIp[0], sizeof(mGuestIp));
944
945 LogRelMax(256, ("Preconfigured port forward rule discovered on startup: "
946 "fUdp=%d, pHostIp=%s, u16HostPort=%u, pGuestIp=%s, u16GuestPort=%u\n",
947 RT_BOOL(fUDP), mHostIp, iHostPort, mGuestIp, iGuestPort));
948
949 /*
950 * Apply port forward.
951 */
952 if (drvNATNotifyApplyPortForwardCommand(pThis, false /* fRemove */, fUDP,
953 mHostIp, iHostPort, mGuestIp, iGuestPort) < 0)
954 return PDMDrvHlpVMSetError(pThis->pDrvIns, VERR_NAT_REDIR_SETUP, RT_SRC_POS,
955 N_("NAT#%d: configuration error: failed to set up "
956 "redirection of %d to %d. Probably a conflict with "
957 "existing services or other rules"), iInstance, iHostPort,
958 iGuestPort);
959 } /* for each redir rule */
960
961 return VINF_SUCCESS;
962}
963
964/**
965 * Applies port forwarding between guest and host.
966 *
967 * @param pThis Pointer to DRVNAT state for current context.
968 * @param fRemove Flag to remove port forward instead of create.
969 * @param fUdp Flag specifying if UDP. If false, TCP.
970 * @param pHostIp String of host IP address.
971 * @param u16HostPort Host port to forward to.
972 * @param pGuestIp String of guest IP address.
973 * @param u16GuestPort Guest port to forward.
974 *
975 * @thread ?
976 */
977static DECLCALLBACK(int) drvNATNotifyApplyPortForwardCommand(PDRVNAT pThis, bool fRemove,
978 bool fUdp, const char *pHostIp,
979 uint16_t u16HostPort, const char *pGuestIp, uint16_t u16GuestPort)
980{
981 /** @todo r=jack:
982 * - rewrite for IPv6
983 * - do we want to lock the guestIp to the VMs IP?
984 */
985 struct in_addr guestIp, hostIp;
986 int rc = VINF_SUCCESS;
987
988 if ( pHostIp == NULL
989 || inet_aton(pHostIp, &hostIp) == 0)
990 hostIp.s_addr = INADDR_ANY;
991
992 if ( pGuestIp == NULL
993 || inet_aton(pGuestIp, &guestIp) == 0)
994 guestIp.s_addr = pThis->GuestIP;
995
996 if (fRemove)
997 rc = slirp_remove_hostfwd(pThis->pNATState->pSlirp, fUdp, hostIp, u16HostPort);
998 else
999 rc = slirp_add_hostfwd(pThis->pNATState->pSlirp, fUdp, hostIp,
1000 u16HostPort, guestIp, u16GuestPort);
1001
1002 if (rc < 0)
1003 {
1004 LogRelFunc(("Port forward modify FAIL! Details: fRemove=%d, fUdp=%d, pHostIp=%s, u16HostPort=%u, pGuestIp=%s, u16GuestPort=%u\n",
1005 RT_BOOL(fRemove), RT_BOOL(fUdp), pHostIp, u16HostPort, pGuestIp, u16GuestPort));
1006
1007 return PDMDrvHlpVMSetError(pThis->pDrvIns, VERR_NAT_REDIR_SETUP, RT_SRC_POS,
1008 N_("NAT#%d: configuration error: failed to set up "
1009 "redirection of %d to %d. Probably a conflict with "
1010 "existing services or other rules"), pThis->pDrvIns->iInstance, u16HostPort, u16GuestPort);
1011 }
1012
1013 return rc;
1014}
1015
1016/**
1017 * @interface_method_impl{PDMINETWORKNATCONFIG,pfnRedirectRuleCommand}
1018 */
1019static DECLCALLBACK(int) drvNATNetworkNatConfigRedirect(PPDMINETWORKNATCONFIG pInterface, bool fRemove,
1020 bool fUdp, const char *pHostIp, uint16_t u16HostPort,
1021 const char *pGuestIp, uint16_t u16GuestPort)
1022{
1023 LogRelMax(256, ("New port forwarded added: "
1024 "fRemove=%d, fUdp=%d, pHostIp=%s, u16HostPort=%u, pGuestIp=%s, u16GuestPort=%u\n",
1025 RT_BOOL(fRemove), RT_BOOL(fUdp), pHostIp, u16HostPort, pGuestIp, u16GuestPort));
1026 PDRVNAT pThis = RT_FROM_MEMBER(pInterface, DRVNAT, INetworkNATCfg);
1027 /* Execute the command directly if the VM is not running. */
1028 int rc;
1029 if (pThis->pSlirpThread->enmState != PDMTHREADSTATE_RUNNING)
1030 rc = drvNATNotifyApplyPortForwardCommand(pThis, fRemove, fUdp, pHostIp,
1031 u16HostPort, pGuestIp,u16GuestPort);
1032 else
1033 {
1034 PRTREQ pReq;
1035 rc = RTReqQueueCallEx(pThis->hSlirpReqQueue, &pReq, 0 /*cMillies*/, RTREQFLAGS_VOID,
1036 (PFNRT)drvNATNotifyApplyPortForwardCommand, 7, pThis, fRemove,
1037 fUdp, pHostIp, u16HostPort, pGuestIp, u16GuestPort);
1038 if (rc == VERR_TIMEOUT)
1039 {
1040 drvNATNotifyNATThread(pThis, "drvNATNetworkNatConfigRedirect");
1041 rc = RTReqWait(pReq, RT_INDEFINITE_WAIT);
1042 AssertRC(rc);
1043 }
1044 else
1045 AssertRC(rc);
1046
1047 RTReqRelease(pReq);
1048 }
1049 return rc;
1050}
1051
1052/**
1053 * @interface_method_impl{PDMINETWORKNATCONFIG,pfnNotifyDnsChanged}
1054 */
1055static DECLCALLBACK(void) drvNATNotifyDnsChanged(PPDMINETWORKNATCONFIG pInterface, PCPDMINETWORKNATDNSCONFIG pDnsConf)
1056{
1057 PDRVNAT const pThis = RT_FROM_MEMBER(pInterface, DRVNAT, INetworkNATCfg);
1058 SlirpState * const pNATState = pThis->pNATState;
1059 AssertReturnVoid(pNATState);
1060 AssertReturnVoid(pNATState->pSlirp);
1061
1062 if (!pNATState->fPassDomain)
1063 return;
1064
1065 LogRel(("NAT: DNS settings changed, triggering update\n"));
1066
1067 if (pDnsConf->szDomainName[0] == '\0')
1068 slirp_set_vdomainname(pNATState->pSlirp, NULL);
1069 else
1070 slirp_set_vdomainname(pNATState->pSlirp, pDnsConf->szDomainName);
1071
1072 slirp_set_vdnssearch(pNATState->pSlirp, pDnsConf->papszSearchDomains);
1073 /** @todo Convert the papszNameServers entries to IP address and tell about
1074 * the first IPv4 and IPv6 ones. */
1075}
1076
1077
1078/*
1079 * Libslirp Utility Functions
1080 */
1081/**
1082 * Update the timeout field in given list of Slirp timers.
1083 *
1084 * @param uTimeout Pointer to timeout value.
1085 * @param opaque Pointer to NAT State context.
1086 *
1087 * @thread ?
1088 */
1089static void drvNAT_UpdateTimeout(uint32_t *uTimeout, void *opaque)
1090{
1091 PDRVNAT pThis = (PDRVNAT)opaque;
1092 Assert(pThis);
1093
1094 int64_t currTime = drvNAT_ClockGetNsCb(pThis) / (1000 * 1000);
1095 SlirpTimer *pCurrent = pThis->pNATState->pTimerHead;
1096 while (pCurrent != NULL)
1097 {
1098 if (pCurrent->uTimeExpire != 0)
1099 {
1100 int64_t diff = pCurrent->uTimeExpire - currTime;
1101
1102 if (diff < 0)
1103 diff = 0;
1104
1105 if (diff < *uTimeout)
1106 *uTimeout = diff;
1107 }
1108
1109 pCurrent = pCurrent->next;
1110 }
1111}
1112
1113/**
1114 * Check if timeout has passed in given list of Slirp timers.
1115 *
1116 * @param opaque Pointer to NAT State context.
1117 *
1118 * @thread ?
1119 */
1120static void drvNAT_CheckTimeout(void *opaque)
1121{
1122 PDRVNAT pThis = (PDRVNAT)opaque;
1123 Assert(pThis);
1124
1125 int64_t currTime = drvNAT_ClockGetNsCb(pThis) / (1000 * 1000);
1126 SlirpTimer *pCurrent = pThis->pNATState->pTimerHead;
1127 while (pCurrent != NULL)
1128 {
1129 if (pCurrent->uTimeExpire != 0)
1130 {
1131 int64_t diff = pCurrent->uTimeExpire - currTime;
1132 if (diff <= 0)
1133 {
1134 pCurrent->uTimeExpire = 0;
1135 pCurrent->pHandler(pCurrent->opaque);
1136 }
1137 }
1138
1139 pCurrent = pCurrent->next;
1140 }
1141}
1142
1143/**
1144 * Converts slirp representation of poll events to host representation.
1145 *
1146 * @param iEvents Integer representing slirp type poll events.
1147 *
1148 * @returns Integer representing host type poll events.
1149 *
1150 * @thread ?
1151 */
1152static int drvNAT_PollEventSlirpToHost(int iEvents) {
1153 int iRet = 0;
1154#ifndef RT_OS_WINDOWS
1155 if (iEvents & SLIRP_POLL_IN) iRet |= POLLIN;
1156 if (iEvents & SLIRP_POLL_OUT) iRet |= POLLOUT;
1157 if (iEvents & SLIRP_POLL_PRI) iRet |= POLLPRI;
1158 if (iEvents & SLIRP_POLL_ERR) iRet |= POLLERR;
1159 if (iEvents & SLIRP_POLL_HUP) iRet |= POLLHUP;
1160#else
1161 if (iEvents & SLIRP_POLL_IN) iRet |= (POLLRDNORM | POLLRDBAND);
1162 if (iEvents & SLIRP_POLL_OUT) iRet |= POLLWRNORM;
1163 if (iEvents & SLIRP_POLL_PRI) iRet |= (POLLIN);
1164 if (iEvents & SLIRP_POLL_ERR) iRet |= 0;
1165 if (iEvents & SLIRP_POLL_HUP) iRet |= 0;
1166#endif
1167 return iRet;
1168}
1169
1170/**
1171 * Converts host representation of poll events to slirp representation.
1172 *
1173 * @param iEvents Integer representing host type poll events.
1174 *
1175 * @returns Integer representing slirp type poll events.
1176 *
1177 * @thread ?
1178 */
1179static int drvNAT_PollEventHostToSlirp(int iEvents) {
1180 int iRet = 0;
1181#ifndef RT_OS_WINDOWS
1182 if (iEvents & POLLIN) iRet |= SLIRP_POLL_IN;
1183 if (iEvents & POLLOUT) iRet |= SLIRP_POLL_OUT;
1184 if (iEvents & POLLPRI) iRet |= SLIRP_POLL_PRI;
1185 if (iEvents & POLLERR) iRet |= SLIRP_POLL_ERR;
1186 if (iEvents & POLLHUP) iRet |= SLIRP_POLL_HUP;
1187#else
1188 if (iEvents & (POLLRDNORM | POLLRDBAND)) iRet |= SLIRP_POLL_IN;
1189 if (iEvents & POLLWRNORM) iRet |= SLIRP_POLL_OUT;
1190 if (iEvents & (POLLPRI)) iRet |= SLIRP_POLL_PRI;
1191 if (iEvents & POLLERR) iRet |= SLIRP_POLL_ERR;
1192 if (iEvents & POLLHUP) iRet |= SLIRP_POLL_HUP;
1193#endif
1194 return iRet;
1195}
1196
1197
1198/*
1199 * Libslirp Callbacks
1200 */
1201/**
1202 * Callback called by libslirp to send packet into guest.
1203 *
1204 * @param pBuf Pointer to packet buffer.
1205 * @param cb Size of packet.
1206 * @param opaque Pointer to NAT State context.
1207 *
1208 * @returns Size of packet received or -1 on error.
1209 *
1210 * @thread ?
1211 */
1212static DECLCALLBACK(ssize_t) drvNAT_SendPacketCb(const void *pBuf, size_t cb, void *opaque /* PDRVNAT */)
1213{
1214 char *pNewBuf = (char *)RTMemAlloc(cb);
1215 if (pNewBuf == NULL)
1216 return -1;
1217
1218 memcpy(pNewBuf, pBuf, cb);
1219
1220 PDRVNAT pThis = (PDRVNAT)opaque;
1221 Assert(pThis);
1222
1223 LogFlow(("slirp_output BEGIN %p %d\n", pNewBuf, cb));
1224 Log6(("slirp_output: pNewBuf=%p cb=%#x (pThis=%p)\n"
1225 "%.*Rhxd\n", pNewBuf, cb, pThis, cb, pNewBuf));
1226
1227 /* don't queue new requests when the NAT thread is about to stop */
1228 if (pThis->pSlirpThread->enmState != PDMTHREADSTATE_RUNNING)
1229 return -1;
1230
1231 ASMAtomicIncU32(&pThis->cPkts);
1232 int rc = RTReqQueueCallEx(pThis->hRecvReqQueue, NULL /*ppReq*/, 0 /*cMillies*/, RTREQFLAGS_VOID | RTREQFLAGS_NO_WAIT,
1233 (PFNRT)drvNATRecvWorker, 3, pThis, pNewBuf, cb);
1234 AssertRC(rc);
1235 drvNATRecvWakeup(pThis->pDrvIns, pThis->pRecvThread);
1236 drvNATNotifyNATThread(pThis, "drvNAT_SendPacketCb");
1237 STAM_COUNTER_INC(&pThis->StatQueuePktSent);
1238 LogFlowFuncLeave();
1239 return cb;
1240}
1241
1242/**
1243 * Callback called by libslirp on an error from a guest.
1244 *
1245 * @param pMsg Error message string.
1246 * @param opaque Pointer to NAT State context.
1247 *
1248 * @thread ?
1249 */
1250static DECLCALLBACK(void) drvNAT_GuestErrorCb(const char *pMsg, void *opaque)
1251{
1252 PDRVNAT pThis = (PDRVNAT)opaque;
1253 Assert(pThis);
1254
1255 PDMDRV_SET_ERROR(pThis->pDrvIns, VERR_PDM_UNKNOWN_DRVREG_VERSION,
1256 N_("Unknown error: "));
1257 LogRel((pMsg));
1258}
1259
1260/**
1261 * Callback called by libslirp to get the current timestamp in nanoseconds.
1262 *
1263 * @param opaque Pointer to NAT State context.
1264 *
1265 * @returns 64-bit signed integer representing time in nanoseconds.
1266 */
1267static DECLCALLBACK(int64_t) drvNAT_ClockGetNsCb(void *opaque)
1268{
1269 PDRVNAT pThis = (PDRVNAT)opaque;
1270 Assert(pThis);
1271
1272 RT_NOREF(pThis);
1273
1274 return (int64_t)RTTimeNanoTS();
1275}
1276
1277/**
1278 * Callback called by slirp to create a new timer and insert it into the given list.
1279 *
1280 * @param slirpTimeCb Callback function supplied to the new timer upon timer expiry.
1281 * Called later by the timeout handler.
1282 * @param cb_opaque Opaque object supplied to slirpTimeCb when called. Should be
1283 * Identical to the opaque parameter.
1284 * @param opaque Pointer to NAT State context.
1285 *
1286 * @returns Pointer to new timer.
1287 */
1288static DECLCALLBACK(void *) drvNAT_TimerNewCb(SlirpTimerCb slirpTimeCb, void *cb_opaque, void *opaque)
1289{
1290 PDRVNAT pThis = (PDRVNAT)opaque;
1291 Assert(pThis);
1292
1293 SlirpTimer *pNewTimer = (SlirpTimer *)RTMemAlloc(sizeof(SlirpTimer));
1294 if (!pNewTimer)
1295 return NULL;
1296
1297 pNewTimer->next = pThis->pNATState->pTimerHead;
1298 pNewTimer->uTimeExpire = 0;
1299 pNewTimer->pHandler = slirpTimeCb;
1300 pNewTimer->opaque = cb_opaque;
1301 pThis->pNATState->pTimerHead = pNewTimer;
1302
1303 return pNewTimer;
1304}
1305
1306/**
1307 * Callback called by slirp to free a timer.
1308 *
1309 * @param pTimer Pointer to slirpTimer object to be freed.
1310 * @param opaque Pointer to NAT State context.
1311 */
1312static DECLCALLBACK(void) drvNAT_TimerFreeCb(void *pTimer, void *opaque)
1313{
1314 PDRVNAT pThis = (PDRVNAT)opaque;
1315 Assert(pThis);
1316 SlirpTimer *pCurrent = pThis->pNATState->pTimerHead;
1317
1318 while (pCurrent != NULL)
1319 {
1320 if (pCurrent == (SlirpTimer *)pTimer)
1321 {
1322 SlirpTimer *pTmp = pCurrent->next;
1323 RTMemFree(pCurrent);
1324 pCurrent = pTmp;
1325 }
1326 else
1327 pCurrent = pCurrent->next;
1328 }
1329}
1330
1331/**
1332 * Callback called by slirp to modify a timer.
1333 *
1334 * @param pTimer Pointer to slirpTimer object to be modified.
1335 * @param expireTime Signed 64-bit integer representing the new expiry time.
1336 * @param opaque Pointer to NAT State context.
1337 */
1338static DECLCALLBACK(void) drvNAT_TimerModCb(void *pTimer, int64_t expireTime, void *opaque)
1339{
1340 PDRVNAT pThis = (PDRVNAT)opaque;
1341 Assert(pThis);
1342
1343 RT_NOREF(pThis);
1344
1345 ((SlirpTimer *)pTimer)->uTimeExpire = expireTime;
1346}
1347
1348/**
1349 * Callback called by slirp when there is I/O that needs to happen.
1350 *
1351 * @param opaque Pointer to NAT State context.
1352 */
1353static DECLCALLBACK(void) drvNAT_NotifyCb(void *opaque)
1354{
1355 PDRVNAT pThis = (PDRVNAT)opaque;
1356
1357 drvNATAsyncIoWakeup(pThis->pDrvIns, NULL);
1358}
1359
1360/**
1361 * Registers poll. Unused function (other than logging).
1362 */
1363static DECLCALLBACK(void) drvNAT_RegisterPoll(int fd, void *opaque)
1364{
1365 RT_NOREF(fd, opaque);
1366 Log4(("Poll registered\n"));
1367}
1368
1369/**
1370 * Unregisters poll. Unused function (other than logging).
1371 */
1372static DECLCALLBACK(void) drvNAT_UnregisterPoll(int fd, void *opaque)
1373{
1374 RT_NOREF(fd, opaque);
1375 Log4(("Poll unregistered\n"));
1376}
1377
1378/**
1379 * Callback function to add entry to pollfd array.
1380 *
1381 * @param iFd Integer of system file descriptor of socket.
1382 * (on windows, this is a VBox internal, not system, value).
1383 * @param iEvents Integer of slirp type poll events.
1384 * @param opaque Pointer to NAT State context.
1385 *
1386 * @returns Index of latest pollfd entry.
1387 *
1388 * @thread ?
1389 */
1390static DECLCALLBACK(int) drvNAT_AddPollCb(int iFd, int iEvents, void *opaque)
1391{
1392 PDRVNAT pThis = (PDRVNAT)opaque;
1393
1394 if (pThis->pNATState->nsock + 1 >= pThis->pNATState->uPollCap)
1395 {
1396 int cbNew = pThis->pNATState->uPollCap * 2 * sizeof(struct pollfd);
1397 struct pollfd *pvNew = (struct pollfd *)RTMemRealloc(pThis->pNATState->polls, cbNew);
1398 if (pvNew)
1399 {
1400 pThis->pNATState->polls = pvNew;
1401 pThis->pNATState->uPollCap *= 2;
1402 }
1403 else
1404 return -1;
1405 }
1406
1407 int idx = pThis->pNATState->nsock;
1408#ifdef RT_OS_WINDOWS
1409 pThis->pNATState->polls[idx].fd = libslirp_wrap_RTHandleTableLookup(iFd);
1410#else
1411 pThis->pNATState->polls[idx].fd = iFd;
1412#endif
1413 pThis->pNATState->polls[idx].events = drvNAT_PollEventSlirpToHost(iEvents);
1414 pThis->pNATState->polls[idx].revents = 0;
1415 pThis->pNATState->nsock += 1;
1416 return idx;
1417}
1418
1419/**
1420 * Get translated revents from a poll at a given index.
1421 *
1422 * @param idx Integer index of poll.
1423 * @param opaque Pointer to NAT State context.
1424 *
1425 * @returns Integer representing transalted revents.
1426 *
1427 * @thread ?
1428 */
1429static DECLCALLBACK(int) drvNAT_GetREventsCb(int idx, void *opaque)
1430{
1431 PDRVNAT pThis = (PDRVNAT)opaque;
1432 struct pollfd* polls = pThis->pNATState->polls;
1433 return drvNAT_PollEventHostToSlirp(polls[idx].revents);
1434}
1435
1436/**
1437 * Contructor/Destructor
1438 */
1439/**
1440 * Destruct a driver instance.
1441 *
1442 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
1443 * resources can be freed correctly.
1444 *
1445 * @param pDrvIns The driver instance data.
1446 */
1447static DECLCALLBACK(void) drvNATDestruct(PPDMDRVINS pDrvIns)
1448{
1449 PDRVNAT pThis = PDMINS_2_DATA(pDrvIns, PDRVNAT);
1450 LogFlow(("drvNATDestruct:\n"));
1451 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
1452
1453 SlirpState * const pNATState = pThis->pNATState;
1454 if (pNATState)
1455 {
1456 slirp_cleanup(pNATState->pSlirp);
1457
1458#ifdef VBOX_WITH_STATISTICS
1459# define DRV_PROFILE_COUNTER(name, dsc) DEREGISTER_COUNTER(name, pThis)
1460# define DRV_COUNTING_COUNTER(name, dsc) DEREGISTER_COUNTER(name, pThis)
1461# include "slirp/counters.h"
1462#endif
1463 RTMemFree(pNATState->polls);
1464 pNATState->polls = NULL;
1465
1466 RTMemFree(pNATState);
1467 pThis->pNATState = NULL;
1468 }
1469
1470 RTReqQueueDestroy(pThis->hSlirpReqQueue);
1471 pThis->hSlirpReqQueue = NIL_RTREQQUEUE;
1472
1473 RTReqQueueDestroy(pThis->hRecvReqQueue);
1474 pThis->hRecvReqQueue = NIL_RTREQQUEUE;
1475
1476 RTSemEventDestroy(pThis->EventRecv);
1477 pThis->EventRecv = NIL_RTSEMEVENT;
1478
1479 if (RTCritSectIsInitialized(&pThis->DevAccessLock))
1480 RTCritSectDelete(&pThis->DevAccessLock);
1481
1482 if (RTCritSectIsInitialized(&pThis->XmitLock))
1483 RTCritSectDelete(&pThis->XmitLock);
1484
1485#ifndef RT_OS_WINDOWS
1486 RTPipeClose(pThis->hPipeRead);
1487 RTPipeClose(pThis->hPipeWrite);
1488#endif
1489}
1490
1491/**
1492 * Construct a NAT network transport driver instance.
1493 *
1494 * @copydoc FNPDMDRVCONSTRUCT
1495 */
1496static DECLCALLBACK(int) drvNATConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
1497{
1498 RT_NOREF(fFlags);
1499 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
1500 PDRVNAT pThis = PDMINS_2_DATA(pDrvIns, PDRVNAT);
1501
1502 /*
1503 * Init the static parts.
1504 */
1505 pThis->pDrvIns = pDrvIns;
1506
1507 SlirpState * const pNATState = (SlirpState *)RTMemAllocZ(sizeof(*pNATState));
1508 if (pNATState == NULL)
1509 return VERR_NO_MEMORY;
1510 pThis->pNATState = pNATState;
1511 pNATState->nsock = 0;
1512 pNATState->pTimerHead = NULL;
1513 pNATState->polls = (struct pollfd *)RTMemAllocZ(64 * sizeof(struct pollfd));
1514 AssertReturn(pNATState->polls, VERR_NO_MEMORY);
1515 pNATState->uPollCap = 64;
1516
1517 pThis->hSlirpReqQueue = NIL_RTREQQUEUE;
1518 pThis->EventRecv = NIL_RTSEMEVENT;
1519
1520 /* IBase */
1521 pDrvIns->IBase.pfnQueryInterface = drvNATQueryInterface;
1522
1523 /* INetwork */
1524 pThis->INetworkUp.pfnBeginXmit = drvNATNetworkUp_BeginXmit;
1525 pThis->INetworkUp.pfnAllocBuf = drvNATNetworkUp_AllocBuf;
1526 pThis->INetworkUp.pfnFreeBuf = drvNATNetworkUp_FreeBuf;
1527 pThis->INetworkUp.pfnSendBuf = drvNATNetworkUp_SendBuf;
1528 pThis->INetworkUp.pfnEndXmit = drvNATNetworkUp_EndXmit;
1529 pThis->INetworkUp.pfnSetPromiscuousMode = drvNATNetworkUp_SetPromiscuousMode;
1530 pThis->INetworkUp.pfnNotifyLinkChanged = drvNATNetworkUp_NotifyLinkChanged;
1531
1532 /* NAT engine configuration */
1533 pThis->INetworkNATCfg.pfnRedirectRuleCommand = drvNATNetworkNatConfigRedirect;
1534 pThis->INetworkNATCfg.pfnNotifyDnsChanged = drvNATNotifyDnsChanged;
1535
1536 /*
1537 * Validate the config.
1538 */
1539 PDMDRV_VALIDATE_CONFIG_RETURN(pDrvIns,
1540 "PassDomain"
1541 "|TFTPPrefix"
1542 "|BootFile"
1543 "|Network"
1544 "|NextServer"
1545 "|DNSProxy"
1546 "|BindIP"
1547 "|UseHostResolver"
1548 "|SlirpMTU"
1549 "|AliasMode"
1550 "|SockRcv"
1551 "|SockSnd"
1552 "|TcpRcv"
1553 "|TcpSnd"
1554 "|ICMPCacheLimit"
1555 "|SoMaxConnection"
1556 "|LocalhostReachable"
1557 "|HostResolverMappings"
1558 "|ForwardBroadcast"
1559 , "PortForwarding");
1560
1561 LogRel(("These CFGM parameters are currently not supported when using NAT:\n"
1562 "DNSProxy\n"
1563 "UseHostResolver\n"
1564 "AliasMode\n"
1565 "SockRcv\n"
1566 "SockSnd\n"
1567 "TcpRcv\n"
1568 "TcpSnd\n"
1569 "ICMPCacheLimit\n"
1570 "HostResolverMappings\n"
1571 ));
1572
1573 /*
1574 * Get the configuration settings.
1575 */
1576 int rc;
1577
1578 bool fPassDomain = true;
1579 GET_BOOL(rc, pDrvIns, pCfg, "PassDomain", fPassDomain);
1580 pNATState->fPassDomain = fPassDomain;
1581
1582 bool fForwardBroadcast = false;
1583 GET_BOOL(rc, pDrvIns, pCfg, "ForwardBroadcast", fForwardBroadcast);
1584
1585 GET_STRING_ALLOC(rc, pDrvIns, pCfg, "TFTPPrefix", pThis->pszTFTPPrefix);
1586 GET_STRING_ALLOC(rc, pDrvIns, pCfg, "BootFile", pThis->pszBootFile);
1587 GET_STRING_ALLOC(rc, pDrvIns, pCfg, "NextServer", pThis->pszNextServer);
1588
1589 int fDNSProxy = 0;
1590 GET_S32(rc, pDrvIns, pCfg, "DNSProxy", fDNSProxy);
1591 int MTU = 1500;
1592 GET_S32(rc, pDrvIns, pCfg, "SlirpMTU", MTU);
1593 int i32AliasMode = 0;
1594 int i32MainAliasMode = 0;
1595 GET_S32(rc, pDrvIns, pCfg, "AliasMode", i32MainAliasMode);
1596 int iIcmpCacheLimit = 100;
1597 GET_S32(rc, pDrvIns, pCfg, "ICMPCacheLimit", iIcmpCacheLimit);
1598 bool fLocalhostReachable = false;
1599 GET_BOOL(rc, pDrvIns, pCfg, "LocalhostReachable", fLocalhostReachable);
1600
1601 i32AliasMode |= (i32MainAliasMode & 0x1 ? 0x1 : 0);
1602 i32AliasMode |= (i32MainAliasMode & 0x2 ? 0x40 : 0);
1603 i32AliasMode |= (i32MainAliasMode & 0x4 ? 0x4 : 0);
1604 int i32SoMaxConn = 10;
1605 GET_S32(rc, pDrvIns, pCfg, "SoMaxConnection", i32SoMaxConn);
1606 /*
1607 * Query the network port interface.
1608 */
1609 pThis->pIAboveNet = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMINETWORKDOWN);
1610 if (!pThis->pIAboveNet)
1611 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_ABOVE,
1612 N_("Configuration error: the above device/driver didn't "
1613 "export the network port interface"));
1614 pThis->pIAboveConfig = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMINETWORKCONFIG);
1615 if (!pThis->pIAboveConfig)
1616 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_ABOVE,
1617 N_("Configuration error: the above device/driver didn't "
1618 "export the network config interface"));
1619
1620 /* Generate a network address for this network card. */
1621 char szNetwork[32]; /* xxx.xxx.xxx.xxx/yy */
1622 GET_STRING(rc, pDrvIns, pCfg, "Network", szNetwork[0], sizeof(szNetwork));
1623 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1624 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("NAT%d: Configuration error: missing network"),
1625 pDrvIns->iInstance);
1626
1627 RTNETADDRIPV4 Network, Netmask, Nettemp;
1628 rc = RTCidrStrToIPv4(szNetwork, &Network, &Netmask);
1629 if (RT_FAILURE(rc))
1630 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
1631 N_("NAT#%d: Configuration error: network '%s' describes not a valid IPv4 network"),
1632 pDrvIns->iInstance, szNetwork);
1633
1634 /* Construct Libslirp Config and Initialzie Slirp */
1635
1636 LogFlow(("Here is what is coming out of the vbox config (NAT#%d):\n"
1637 " Network: %RTnaipv4\n"
1638 " Netmask: %RTnaipv4\n",
1639 pDrvIns->iInstance, RT_H2BE_U32(Network.u), RT_H2BE_U32(Netmask.u)));
1640
1641 struct in_addr vnetwork = RTNetIPv4AddrHEToInAddr(&Network);
1642 struct in_addr vnetmask = RTNetIPv4AddrHEToInAddr(&Netmask);
1643 Nettemp = Network; Nettemp.u |= 2; /* Usually 10.0.2.2 */
1644 struct in_addr vhost = RTNetIPv4AddrHEToInAddr(&Nettemp);
1645 Nettemp = Network; Nettemp.u |= 15; /* Usually 10.0.2.15 */
1646 struct in_addr vdhcp_start = RTNetIPv4AddrHEToInAddr(&Nettemp);
1647 Nettemp = Network; Nettemp.u |= 3; /* Usually 10.0.2.3 */
1648 struct in_addr vnameserver = RTNetIPv4AddrHEToInAddr(&Nettemp);
1649
1650 SlirpConfig slirpCfg = { 0 };
1651 static SlirpCb slirpCallbacks = { 0 };
1652
1653 slirpCfg.version = 4;
1654 slirpCfg.restricted = false;
1655 slirpCfg.in_enabled = true;
1656 slirpCfg.vnetwork = vnetwork;
1657 slirpCfg.vnetmask = vnetmask;
1658 slirpCfg.vhost = vhost;
1659 slirpCfg.in6_enabled = true;
1660
1661 /*
1662 * Use the same prefix as the NAT Network default:
1663 * [fd17:625c:f037:XXXX::/64] - RFC 4193 (ULA) Locally Assigned
1664 * Global ID where XXXX, 16 bit Subnet ID, are two bytes from the
1665 * middle of the IPv4 address, e.g. :0002: for 10.0.2.1.
1666 */
1667
1668 inet_pton(AF_INET6, "fd17:625c:f037:0::", &slirpCfg.vprefix_addr6);
1669 inet_pton(AF_INET6, "fd17:625c:f037:0::2", &slirpCfg.vhost6);
1670 inet_pton(AF_INET6, "fd17:625c:f037:0::3", &slirpCfg.vnameserver6);
1671 slirpCfg.vprefix_len = 64;
1672
1673 /* Copy the middle of the IPv4 addresses to the IPv6 addresses. */
1674 slirpCfg.vprefix_addr6.s6_addr[6] = RT_BYTE2(vhost.s_addr);
1675 slirpCfg.vprefix_addr6.s6_addr[7] = RT_BYTE3(vhost.s_addr);
1676 slirpCfg.vhost6.s6_addr[6] = RT_BYTE2(vhost.s_addr);
1677 slirpCfg.vhost6.s6_addr[7] = RT_BYTE3(vhost.s_addr);
1678 slirpCfg.vnameserver6.s6_addr[6] = RT_BYTE2(vnameserver.s_addr);
1679 slirpCfg.vnameserver6.s6_addr[7] = RT_BYTE3(vnameserver.s_addr);
1680
1681 slirpCfg.vhostname = "vbox";
1682 slirpCfg.tftp_server_name = pThis->pszNextServer;
1683 slirpCfg.tftp_path = pThis->pszTFTPPrefix;
1684 slirpCfg.bootfile = pThis->pszBootFile;
1685 slirpCfg.vdhcp_start = vdhcp_start;
1686 slirpCfg.vnameserver = vnameserver;
1687 slirpCfg.if_mtu = MTU;
1688
1689 slirpCfg.vdnssearch = NULL;
1690 slirpCfg.vdomainname = NULL;
1691 slirpCfg.disable_host_loopback = fLocalhostReachable;
1692 slirpCfg.fForwardBroadcast = fForwardBroadcast;
1693 slirpCfg.iSoMaxConn = i32SoMaxConn;
1694
1695 slirpCallbacks.send_packet = &drvNAT_SendPacketCb;
1696 slirpCallbacks.guest_error = &drvNAT_GuestErrorCb;
1697 slirpCallbacks.clock_get_ns = &drvNAT_ClockGetNsCb;
1698 slirpCallbacks.timer_new = &drvNAT_TimerNewCb;
1699 slirpCallbacks.timer_free = &drvNAT_TimerFreeCb;
1700 slirpCallbacks.timer_mod = &drvNAT_TimerModCb;
1701 slirpCallbacks.register_poll_fd = &drvNAT_RegisterPoll;
1702 slirpCallbacks.unregister_poll_fd = &drvNAT_UnregisterPoll;
1703 slirpCallbacks.notify = &drvNAT_NotifyCb;
1704 slirpCallbacks.init_completed = NULL;
1705 slirpCallbacks.timer_new_opaque = NULL;
1706
1707 Slirp *pSlirp = slirp_new(/* cfg */ &slirpCfg, /* callbacks */ &slirpCallbacks, /* opaque */ pThis);
1708
1709 if (pSlirp == NULL)
1710 return VERR_INVALID_POINTER;
1711
1712 pThis->pNATState->pSlirp = pSlirp;
1713
1714 rc = drvNATConstructRedir(pDrvIns->iInstance, pThis, pCfg, &Network);
1715 AssertLogRelRCReturn(rc, rc);
1716
1717 rc = PDMDrvHlpSSMRegisterLoadDone(pDrvIns, NULL);
1718 AssertLogRelRCReturn(rc, rc);
1719
1720 rc = RTReqQueueCreate(&pThis->hSlirpReqQueue);
1721 AssertLogRelRCReturn(rc, rc);
1722
1723 rc = RTReqQueueCreate(&pThis->hRecvReqQueue);
1724 AssertLogRelRCReturn(rc, rc);
1725
1726 rc = PDMDrvHlpThreadCreate(pDrvIns, &pThis->pRecvThread, pThis, drvNATRecv,
1727 drvNATRecvWakeup, 256 * _1K, RTTHREADTYPE_IO, "NATRX");
1728 AssertRCReturn(rc, rc);
1729
1730 rc = RTSemEventCreate(&pThis->EventRecv);
1731 AssertRCReturn(rc, rc);
1732
1733 rc = RTCritSectInit(&pThis->DevAccessLock);
1734 AssertRCReturn(rc, rc);
1735
1736 rc = RTCritSectInit(&pThis->XmitLock);
1737 AssertRCReturn(rc, rc);
1738
1739 char szTmp[128];
1740 RTStrPrintf(szTmp, sizeof(szTmp), "nat%d", pDrvIns->iInstance);
1741 PDMDrvHlpDBGFInfoRegister(pDrvIns, szTmp, "NAT info.", drvNATInfo);
1742
1743#ifdef VBOX_WITH_STATISTICS
1744# define DRV_PROFILE_COUNTER(name, dsc) REGISTER_COUNTER(name, pThis, STAMTYPE_PROFILE, STAMUNIT_TICKS_PER_CALL, dsc)
1745# define DRV_COUNTING_COUNTER(name, dsc) REGISTER_COUNTER(name, pThis, STAMTYPE_COUNTER, STAMUNIT_COUNT, dsc)
1746# include "slirp/counters.h"
1747#endif
1748
1749#ifndef RT_OS_WINDOWS
1750 // Create the control pipe.
1751 rc = RTPipeCreate(&pThis->hPipeRead, &pThis->hPipeWrite, 0 /*fFlags*/);
1752 AssertRCReturn(rc, rc);
1753#else
1754 // Create the wakeup socket pair.
1755 pThis->pWakeupSockPair[0] = NULL;
1756 pThis->pWakeupSockPair[1] = NULL;
1757
1758 /* idx=0 is write, idx=1 is read */
1759 rc = RTWinSocketPair(AF_INET, SOCK_DGRAM, 0, pThis->pWakeupSockPair);
1760 AssertRCReturn(rc, rc);
1761#endif
1762 /* initalize the notifier counter */
1763 pThis->cbWakeupNotifs = 0;
1764
1765 rc = PDMDrvHlpThreadCreate(pDrvIns, &pThis->pSlirpThread, pThis, drvNATAsyncIoThread,
1766 drvNATAsyncIoWakeup, 256 * _1K, RTTHREADTYPE_IO, "NAT");
1767 AssertRCReturn(rc, rc);
1768
1769 pThis->enmLinkState = pThis->enmLinkStateWant = PDMNETWORKLINKSTATE_UP;
1770
1771 return rc;
1772}
1773
1774/**
1775 * NAT network transport driver registration record.
1776 */
1777const PDMDRVREG g_DrvNATlibslirp =
1778{
1779 /* u32Version */
1780 PDM_DRVREG_VERSION,
1781 /* szName */
1782 "NAT",
1783 /* szRCMod */
1784 "",
1785 /* szR0Mod */
1786 "",
1787 /* pszDescription */
1788 "NATlibslrip Network Transport Driver",
1789 /* fFlags */
1790 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
1791 /* fClass. */
1792 PDM_DRVREG_CLASS_NETWORK,
1793 /* cMaxInstances */
1794 ~0U,
1795 /* cbInstance */
1796 sizeof(DRVNAT),
1797 /* pfnConstruct */
1798 drvNATConstruct,
1799 /* pfnDestruct */
1800 drvNATDestruct,
1801 /* pfnRelocate */
1802 NULL,
1803 /* pfnIOCtl */
1804 NULL,
1805 /* pfnPowerOn */
1806 NULL,
1807 /* pfnReset */
1808 NULL,
1809 /* pfnSuspend */
1810 NULL,
1811 /* pfnResume */
1812 NULL,
1813 /* pfnAttach */
1814 NULL,
1815 /* pfnDetach */
1816 NULL,
1817 /* pfnPowerOff */
1818 NULL,
1819 /* pfnSoftReset */
1820 NULL,
1821 /* u32EndVersion */
1822 PDM_DRVREG_VERSION
1823};
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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