VirtualBox

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

Last change on this file since 107792 was 107732, checked in by vboxsync, 4 months ago

Devices/Network: Fix header from parfait fix.. bugref:3409

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

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