VirtualBox

source: vbox/trunk/src/VBox/NetworkServices/Dhcpd/VBoxNetDhcpd.cpp@ 95851

Last change on this file since 95851 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 20.1 KB
Line 
1/* $Id: VBoxNetDhcpd.cpp 93115 2022-01-01 11:31:46Z vboxsync $ */
2/** @file
3 * VBoxNetDhcpd - DHCP server for host-only and NAT networks.
4 */
5
6/*
7 * Copyright (C) 2009-2022 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/** @page pg_net_dhcp VBoxNetDHCP
20 *
21 * Write a few words...
22 *
23 */
24
25
26/*********************************************************************************************************************************
27* Header Files *
28*********************************************************************************************************************************/
29#include <iprt/cdefs.h>
30
31/*
32 * Need to get host/network order conversion stuff from Windows headers,
33 * so we do not define them in LWIP and then try to re-define them in
34 * Windows headers.
35 */
36#ifdef RT_OS_WINDOWS
37# include <iprt/win/winsock2.h>
38#endif
39
40#include "DhcpdInternal.h"
41#include <iprt/param.h>
42#include <iprt/errcore.h>
43
44#include <iprt/initterm.h>
45#include <iprt/message.h>
46
47#include <iprt/net.h>
48#include <iprt/path.h>
49#include <iprt/stream.h>
50
51#include <VBox/sup.h>
52#include <VBox/vmm/vmm.h>
53#include <VBox/vmm/pdmnetinline.h>
54#include <VBox/intnet.h>
55#include <VBox/intnetinline.h>
56
57#include "VBoxLwipCore.h"
58#include "Config.h"
59#include "DHCPD.h"
60#include "DhcpMessage.h"
61
62extern "C"
63{
64#include "lwip/sys.h"
65#include "lwip/pbuf.h"
66#include "lwip/netif.h"
67#include "lwip/tcpip.h"
68#include "lwip/udp.h"
69#include "netif/etharp.h"
70}
71
72#include <iprt/sanitized/string>
73#include <vector>
74#include <memory>
75
76#ifdef RT_OS_WINDOWS
77# include <iprt/win/windows.h>
78#endif
79
80struct delete_pbuf
81{
82 delete_pbuf() {}
83 void operator()(struct pbuf *p) const { pbuf_free(p); }
84};
85
86typedef std::unique_ptr<pbuf, delete_pbuf> unique_ptr_pbuf;
87
88
89#define CALL_VMMR0(op, req) \
90 (SUPR3CallVMMR0Ex(NIL_RTR0PTR, NIL_VMCPUID, (op), 0, &(req).Hdr))
91
92
93class VBoxNetDhcpd
94{
95 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(VBoxNetDhcpd);
96
97private:
98 PRTLOGGER m_pStderrReleaseLogger;
99
100 /* intnet plumbing */
101 PSUPDRVSESSION m_pSession;
102 INTNETIFHANDLE m_hIf;
103 PINTNETBUF m_pIfBuf;
104
105 /* lwip stack connected to the intnet */
106 struct netif m_LwipNetif;
107
108 Config *m_Config;
109
110 /* listening pcb */
111 struct udp_pcb *m_Dhcp4Pcb;
112
113 DHCPD m_server;
114
115public:
116 VBoxNetDhcpd();
117 ~VBoxNetDhcpd();
118
119 int main(int argc, char **argv);
120
121private:
122 int logInitStderr();
123
124 /*
125 * Boilerplate code.
126 */
127 int r3Init();
128 void r3Fini();
129
130 int vmmInit();
131
132 int ifInit(const RTCString &strNetwork,
133 const RTCString &strTrunk = RTCString(),
134 INTNETTRUNKTYPE enmTrunkType = kIntNetTrunkType_WhateverNone);
135 int ifOpen(const RTCString &strNetwork,
136 const RTCString &strTrunk,
137 INTNETTRUNKTYPE enmTrunkType);
138 int ifGetBuf();
139 int ifActivate();
140
141 int ifProcessInput();
142 int ifFlush();
143
144 int ifClose();
145
146 void ifPump();
147 int ifInput(void *pvSegFrame, uint32_t cbSegFrame);
148
149
150 /*
151 * lwIP callbacks
152 */
153 static DECLCALLBACK(void) lwipInitCB(void *pvArg);
154 void lwipInit();
155
156 static err_t netifInitCB(netif *pNetif) RT_NOTHROW_PROTO;
157 err_t netifInit(netif *pNetif);
158
159 static err_t netifLinkOutputCB(netif *pNetif, pbuf *pPBuf) RT_NOTHROW_PROTO;
160 err_t netifLinkOutput(pbuf *pPBuf);
161
162 static void dhcp4RecvCB(void *arg, struct udp_pcb *pcb, struct pbuf *p,
163 ip_addr_t *addr, u16_t port) RT_NOTHROW_PROTO;
164 void dhcp4Recv(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port);
165};
166
167
168VBoxNetDhcpd::VBoxNetDhcpd()
169 : m_pStderrReleaseLogger(NULL),
170 m_pSession(NIL_RTR0PTR),
171 m_hIf(INTNET_HANDLE_INVALID),
172 m_pIfBuf(NULL),
173 m_LwipNetif(),
174 m_Config(NULL),
175 m_Dhcp4Pcb(NULL)
176{
177 int rc;
178
179 logInitStderr();
180
181 rc = r3Init();
182 if (RT_FAILURE(rc))
183 return;
184
185 vmmInit();
186}
187
188
189VBoxNetDhcpd::~VBoxNetDhcpd()
190{
191 ifClose();
192 r3Fini();
193}
194
195
196/*
197 * We don't know the name of the release log file until we parse our
198 * configuration because we use network name as basename. To get
199 * early logging to work, start with stderr-only release logger.
200 *
201 * We disable "sup" for this logger to avoid spam from SUPR3Init().
202 */
203int VBoxNetDhcpd::logInitStderr()
204{
205 static const char * const s_apszGroups[] = VBOX_LOGGROUP_NAMES;
206
207 PRTLOGGER pLogger;
208 int rc;
209
210 uint32_t fFlags = 0;
211#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
212 fFlags |= RTLOGFLAGS_USECRLF;
213#endif
214
215 rc = RTLogCreate(&pLogger, fFlags,
216 "all -sup all.restrict -default.restrict",
217 NULL, /* environment base */
218 RT_ELEMENTS(s_apszGroups), s_apszGroups,
219 RTLOGDEST_STDERR, NULL);
220 if (RT_FAILURE(rc))
221 {
222 RTPrintf("Failed to init stderr logger: %Rrs\n", rc);
223 return rc;
224 }
225
226 m_pStderrReleaseLogger = pLogger;
227 RTLogRelSetDefaultInstance(m_pStderrReleaseLogger);
228
229 return VINF_SUCCESS;
230}
231
232
233int VBoxNetDhcpd::r3Init()
234{
235 AssertReturn(m_pSession == NIL_RTR0PTR, VERR_GENERAL_FAILURE);
236
237 int rc = SUPR3Init(&m_pSession);
238 return rc;
239}
240
241
242void VBoxNetDhcpd::r3Fini()
243{
244 if (m_pSession == NIL_RTR0PTR)
245 return;
246
247 SUPR3Term();
248 m_pSession = NIL_RTR0PTR;
249}
250
251
252int VBoxNetDhcpd::vmmInit()
253{
254 char szPathVMMR0[RTPATH_MAX];
255 int rc = RTPathExecDir(szPathVMMR0, sizeof(szPathVMMR0));
256 if (RT_SUCCESS(rc))
257 rc = RTPathAppend(szPathVMMR0, sizeof(szPathVMMR0), "VMMR0.r0");
258 if (RT_SUCCESS(rc))
259 rc = SUPR3LoadVMM(szPathVMMR0, NULL /*pErrInfo*/);
260 return rc;
261}
262
263
264int VBoxNetDhcpd::ifInit(const RTCString &strNetwork,
265 const RTCString &strTrunk,
266 INTNETTRUNKTYPE enmTrunkType)
267{
268 int rc;
269
270 rc = ifOpen(strNetwork, strTrunk, enmTrunkType);
271 if (RT_FAILURE(rc))
272 return rc;
273
274 rc = ifGetBuf();
275 if (RT_FAILURE(rc))
276 return rc;
277
278 rc = ifActivate();
279 if (RT_FAILURE(rc))
280 return rc;
281
282 return VINF_SUCCESS;
283}
284
285
286int VBoxNetDhcpd::ifOpen(const RTCString &strNetwork,
287 const RTCString &strTrunk,
288 INTNETTRUNKTYPE enmTrunkType)
289{
290 AssertReturn(m_pSession != NIL_RTR0PTR, VERR_GENERAL_FAILURE);
291 AssertReturn(m_hIf == INTNET_HANDLE_INVALID, VERR_GENERAL_FAILURE);
292
293 INTNETOPENREQ OpenReq;
294 RT_ZERO(OpenReq);
295
296 OpenReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
297 OpenReq.Hdr.cbReq = sizeof(OpenReq);
298 OpenReq.pSession = m_pSession;
299
300 int rc = RTStrCopy(OpenReq.szNetwork, sizeof(OpenReq.szNetwork), strNetwork.c_str());
301 AssertRCReturn(rc, rc);
302
303 rc = RTStrCopy(OpenReq.szTrunk, sizeof(OpenReq.szTrunk), strTrunk.c_str());
304 AssertRCReturn(rc, rc);
305
306 if (enmTrunkType != kIntNetTrunkType_Invalid)
307 OpenReq.enmTrunkType = enmTrunkType;
308 else
309 OpenReq.enmTrunkType = kIntNetTrunkType_WhateverNone;
310
311 OpenReq.fFlags = 0;
312 OpenReq.cbSend = _128K;
313 OpenReq.cbRecv = _256K;
314
315 OpenReq.hIf = INTNET_HANDLE_INVALID;
316
317 rc = CALL_VMMR0(VMMR0_DO_INTNET_OPEN, OpenReq);
318 if (RT_FAILURE(rc))
319 return rc;
320
321 m_hIf = OpenReq.hIf;
322 AssertReturn(m_hIf != INTNET_HANDLE_INVALID, VERR_GENERAL_FAILURE);
323
324 return VINF_SUCCESS;
325}
326
327
328int VBoxNetDhcpd::ifGetBuf()
329{
330 AssertReturn(m_pSession != NIL_RTR0PTR, VERR_GENERAL_FAILURE);
331 AssertReturn(m_hIf != INTNET_HANDLE_INVALID, VERR_GENERAL_FAILURE);
332 AssertReturn(m_pIfBuf == NULL, VERR_GENERAL_FAILURE);
333
334 INTNETIFGETBUFFERPTRSREQ GetBufferPtrsReq;
335 int rc;
336
337 GetBufferPtrsReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
338 GetBufferPtrsReq.Hdr.cbReq = sizeof(GetBufferPtrsReq);
339 GetBufferPtrsReq.pSession = m_pSession;
340 GetBufferPtrsReq.hIf = m_hIf;
341
342 GetBufferPtrsReq.pRing0Buf = NIL_RTR0PTR;
343 GetBufferPtrsReq.pRing3Buf = NULL;
344
345 rc = CALL_VMMR0(VMMR0_DO_INTNET_IF_GET_BUFFER_PTRS, GetBufferPtrsReq);
346 if (RT_FAILURE(rc))
347 return rc;
348
349 m_pIfBuf = GetBufferPtrsReq.pRing3Buf;
350 AssertReturn(m_pIfBuf != NULL, VERR_GENERAL_FAILURE);
351
352 return VINF_SUCCESS;
353}
354
355
356int VBoxNetDhcpd::ifActivate()
357{
358 AssertReturn(m_pSession != NIL_RTR0PTR, VERR_GENERAL_FAILURE);
359 AssertReturn(m_hIf != INTNET_HANDLE_INVALID, VERR_GENERAL_FAILURE);
360 AssertReturn(m_pIfBuf != NULL, VERR_GENERAL_FAILURE);
361
362 INTNETIFSETACTIVEREQ ActiveReq;
363 int rc;
364
365 ActiveReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
366 ActiveReq.Hdr.cbReq = sizeof(ActiveReq);
367 ActiveReq.pSession = m_pSession;
368 ActiveReq.hIf = m_hIf;
369
370 ActiveReq.fActive = 1;
371
372 rc = CALL_VMMR0(VMMR0_DO_INTNET_IF_SET_ACTIVE, ActiveReq);
373 return rc;
374}
375
376
377/**
378 * Process incoming packages forever.
379 *
380 * @note This function normally never returns, given that the process is
381 * typically just killed when shutting down a network.
382 */
383void VBoxNetDhcpd::ifPump()
384{
385 for (;;)
386 {
387 /*
388 * Wait for input:
389 */
390 INTNETIFWAITREQ WaitReq;
391 WaitReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
392 WaitReq.Hdr.cbReq = sizeof(WaitReq);
393 WaitReq.pSession = m_pSession;
394 WaitReq.hIf = m_hIf;
395 WaitReq.cMillies = RT_INDEFINITE_WAIT;
396 int rc = CALL_VMMR0(VMMR0_DO_INTNET_IF_WAIT, WaitReq);
397
398 /*
399 * Process any pending input before we wait again:
400 */
401 if ( RT_SUCCESS(rc)
402 || rc == VERR_INTERRUPTED
403 || rc == VERR_TIMEOUT /* paranoia */)
404 ifProcessInput();
405 else
406 {
407 DHCP_LOG_MSG_ERROR(("ifWait failed: %Rrc\n", rc));
408 return;
409 }
410 }
411}
412
413
414int VBoxNetDhcpd::ifProcessInput()
415{
416 AssertReturn(m_pSession != NIL_RTR0PTR, VERR_GENERAL_FAILURE);
417 AssertReturn(m_hIf != INTNET_HANDLE_INVALID, VERR_GENERAL_FAILURE);
418 AssertReturn(m_pIfBuf != NULL, VERR_GENERAL_FAILURE);
419
420 PCINTNETHDR pHdr = IntNetRingGetNextFrameToRead(&m_pIfBuf->Recv);
421 while (pHdr)
422 {
423 const uint8_t u8Type = pHdr->u8Type;
424 void *pvSegFrame;
425 uint32_t cbSegFrame;
426
427 if (u8Type == INTNETHDR_TYPE_FRAME)
428 {
429 pvSegFrame = IntNetHdrGetFramePtr(pHdr, m_pIfBuf);
430 cbSegFrame = pHdr->cbFrame;
431
432 ifInput(pvSegFrame, cbSegFrame);
433 }
434 else if (u8Type == INTNETHDR_TYPE_GSO)
435 {
436 size_t cbGso = pHdr->cbFrame;
437 size_t cbFrame = cbGso - sizeof(PDMNETWORKGSO);
438
439 PCPDMNETWORKGSO pGso = IntNetHdrGetGsoContext(pHdr, m_pIfBuf);
440 if (PDMNetGsoIsValid(pGso, cbGso, cbFrame))
441 {
442 const uint32_t cSegs = PDMNetGsoCalcSegmentCount(pGso, cbFrame);
443 for (uint32_t i = 0; i < cSegs; ++i)
444 {
445 uint8_t abHdrScratch[256];
446 pvSegFrame = PDMNetGsoCarveSegmentQD(pGso, (uint8_t *)(pGso + 1), cbFrame,
447 abHdrScratch,
448 i, cSegs,
449 &cbSegFrame);
450 ifInput(pvSegFrame, (uint32_t)cbFrame);
451 }
452 }
453 }
454
455 /* Advance: */
456 IntNetRingSkipFrame(&m_pIfBuf->Recv);
457 pHdr = IntNetRingGetNextFrameToRead(&m_pIfBuf->Recv);
458 }
459
460 return VINF_SUCCESS;
461}
462
463
464/**
465 * Got a frame from the internal network, feed it to the lwIP stack.
466 */
467int VBoxNetDhcpd::ifInput(void *pvFrame, uint32_t cbFrame)
468{
469 if (pvFrame == NULL)
470 return VERR_INVALID_PARAMETER;
471
472 if ( cbFrame <= sizeof(RTNETETHERHDR)
473 || cbFrame > UINT16_MAX - ETH_PAD_SIZE)
474 return VERR_INVALID_PARAMETER;
475
476 struct pbuf *p = pbuf_alloc(PBUF_RAW, (u16_t)cbFrame + ETH_PAD_SIZE, PBUF_POOL);
477 if (RT_UNLIKELY(p == NULL))
478 return VERR_NO_MEMORY;
479
480 /*
481 * The code below is inlined version of:
482 *
483 * pbuf_header(p, -ETH_PAD_SIZE); // hide padding
484 * pbuf_take(p, pvFrame, cbFrame);
485 * pbuf_header(p, ETH_PAD_SIZE); // reveal padding
486 */
487 struct pbuf *q = p;
488 uint8_t *pbChunk = (uint8_t *)pvFrame;
489 do
490 {
491 uint8_t *payload = (uint8_t *)q->payload;
492 size_t len = q->len;
493
494#if ETH_PAD_SIZE
495 if (RT_LIKELY(q == p)) /* single pbuf is large enough */
496 {
497 payload += ETH_PAD_SIZE;
498 len -= ETH_PAD_SIZE;
499 }
500#endif
501 memcpy(payload, pbChunk, len);
502 pbChunk += len;
503 q = q->next;
504 } while (RT_UNLIKELY(q != NULL));
505
506 m_LwipNetif.input(p, &m_LwipNetif);
507 return VINF_SUCCESS;
508}
509
510
511/**
512 * Got a frame from the lwIP stack, feed it to the internal network.
513 */
514err_t VBoxNetDhcpd::netifLinkOutput(pbuf *pPBuf)
515{
516 if (pPBuf->tot_len < sizeof(struct eth_hdr)) /* includes ETH_PAD_SIZE */
517 return ERR_ARG;
518
519 PINTNETHDR pHdr;
520 void *pvFrame;
521 u16_t cbFrame = pPBuf->tot_len - ETH_PAD_SIZE;
522 int rc = IntNetRingAllocateFrame(&m_pIfBuf->Send, cbFrame, &pHdr, &pvFrame);
523 if (RT_FAILURE(rc))
524 return ERR_MEM;
525
526 pbuf_copy_partial(pPBuf, pvFrame, cbFrame, ETH_PAD_SIZE);
527 IntNetRingCommitFrameEx(&m_pIfBuf->Send, pHdr, cbFrame);
528
529 ifFlush();
530 return ERR_OK;
531}
532
533
534int VBoxNetDhcpd::ifFlush()
535{
536 INTNETIFSENDREQ SendReq;
537
538 SendReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
539 SendReq.Hdr.cbReq = sizeof(SendReq);
540 SendReq.pSession = m_pSession;
541
542 SendReq.hIf = m_hIf;
543
544 return CALL_VMMR0(VMMR0_DO_INTNET_IF_SEND, SendReq);
545}
546
547
548int VBoxNetDhcpd::ifClose()
549{
550 if (m_hIf == INTNET_HANDLE_INVALID)
551 return VINF_SUCCESS;
552
553 INTNETIFCLOSEREQ CloseReq;
554
555 CloseReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
556 CloseReq.Hdr.cbReq = sizeof(CloseReq);
557 CloseReq.pSession = m_pSession;
558
559 CloseReq.hIf = m_hIf;
560
561 m_hIf = INTNET_HANDLE_INVALID;
562 m_pIfBuf = NULL;
563
564 CALL_VMMR0(VMMR0_DO_INTNET_IF_CLOSE, CloseReq);
565 return VINF_SUCCESS;
566}
567
568
569/* static */ DECLCALLBACK(void) VBoxNetDhcpd::lwipInitCB(void *pvArg)
570{
571 AssertPtrReturnVoid(pvArg);
572
573 VBoxNetDhcpd *self = static_cast<VBoxNetDhcpd *>(pvArg);
574 self->lwipInit();
575}
576
577
578/* static */ err_t VBoxNetDhcpd::netifInitCB(netif *pNetif) RT_NOTHROW_DEF
579{
580 AssertPtrReturn(pNetif, ERR_ARG);
581
582 VBoxNetDhcpd *self = static_cast<VBoxNetDhcpd *>(pNetif->state);
583 return self->netifInit(pNetif);
584}
585
586
587/* static */ err_t VBoxNetDhcpd::netifLinkOutputCB(netif *pNetif, pbuf *pPBuf) RT_NOTHROW_DEF
588{
589 AssertPtrReturn(pNetif, ERR_ARG);
590 AssertPtrReturn(pPBuf, ERR_ARG);
591
592 VBoxNetDhcpd *self = static_cast<VBoxNetDhcpd *>(pNetif->state);
593 AssertPtrReturn(self, ERR_IF);
594
595 return self->netifLinkOutput(pPBuf);
596}
597
598
599/* static */ void VBoxNetDhcpd::dhcp4RecvCB(void *arg, struct udp_pcb *pcb,
600 struct pbuf *p,
601 ip_addr_t *addr, u16_t port) RT_NOTHROW_DEF
602{
603 AssertPtrReturnVoid(arg);
604
605 VBoxNetDhcpd *self = static_cast<VBoxNetDhcpd *>(arg);
606 self->dhcp4Recv(pcb, p, addr, port);
607 pbuf_free(p);
608}
609
610
611
612
613
614int VBoxNetDhcpd::main(int argc, char **argv)
615{
616 /*
617 * Register string format types.
618 */
619 ClientId::registerFormat();
620 Binding::registerFormat();
621
622 /*
623 * Parse the command line into a configuration object.
624 */
625 m_Config = Config::create(argc, argv);
626 if (m_Config == NULL)
627 return VERR_GENERAL_FAILURE;
628
629 /*
630 * Initialize the server.
631 */
632 int rc = m_server.init(m_Config);
633 if (RT_SUCCESS(rc))
634 {
635 /* connect to the intnet */
636 rc = ifInit(m_Config->getNetwork(), m_Config->getTrunk(), m_Config->getTrunkType());
637 if (RT_SUCCESS(rc))
638 {
639 /* setup lwip */
640 rc = vboxLwipCoreInitialize(lwipInitCB, this);
641 if (RT_SUCCESS(rc))
642 {
643 /*
644 * Pump packets more or less for ever.
645 */
646 ifPump();
647 }
648 else
649 DHCP_LOG_MSG_ERROR(("Terminating - vboxLwipCoreInitialize failed: %Rrc\n", rc));
650 }
651 else
652 DHCP_LOG_MSG_ERROR(("Terminating - ifInit failed: %Rrc\n", rc));
653 }
654 else
655 DHCP_LOG_MSG_ERROR(("Terminating - Dhcpd::init failed: %Rrc\n", rc));
656 return rc;
657}
658
659
660void VBoxNetDhcpd::lwipInit()
661{
662 err_t error;
663
664 ip_addr_t addr, mask;
665 ip4_addr_set_u32(&addr, m_Config->getIPv4Address().u);
666 ip4_addr_set_u32(&mask, m_Config->getIPv4Netmask().u);
667
668 netif *pNetif = netif_add(&m_LwipNetif,
669 &addr, &mask,
670 IP_ADDR_ANY, /* gateway */
671 this, /* state */
672 VBoxNetDhcpd::netifInitCB, /* netif_init_fn */
673 tcpip_input); /* netif_input_fn */
674 if (pNetif == NULL)
675 return;
676
677 netif_set_up(pNetif);
678 netif_set_link_up(pNetif);
679
680 m_Dhcp4Pcb = udp_new();
681 if (RT_UNLIKELY(m_Dhcp4Pcb == NULL))
682 return; /* XXX? */
683
684 ip_set_option(m_Dhcp4Pcb, SOF_BROADCAST);
685 udp_recv(m_Dhcp4Pcb, dhcp4RecvCB, this);
686
687 error = udp_bind(m_Dhcp4Pcb, IP_ADDR_ANY, RTNETIPV4_PORT_BOOTPS);
688 if (error != ERR_OK)
689 {
690 udp_remove(m_Dhcp4Pcb);
691 m_Dhcp4Pcb = NULL;
692 return; /* XXX? */
693 }
694}
695
696
697err_t VBoxNetDhcpd::netifInit(netif *pNetif)
698{
699 pNetif->hwaddr_len = sizeof(RTMAC);
700 memcpy(pNetif->hwaddr, &m_Config->getMacAddress(), sizeof(RTMAC));
701
702 pNetif->mtu = 1500;
703
704 pNetif->flags = NETIF_FLAG_BROADCAST
705 | NETIF_FLAG_ETHARP
706 | NETIF_FLAG_ETHERNET;
707
708 pNetif->linkoutput = netifLinkOutputCB;
709 pNetif->output = etharp_output;
710
711 netif_set_default(pNetif);
712 return ERR_OK;
713}
714
715
716void VBoxNetDhcpd::dhcp4Recv(struct udp_pcb *pcb, struct pbuf *p,
717 ip_addr_t *addr, u16_t port)
718{
719 RT_NOREF(pcb, addr, port);
720
721 if (RT_UNLIKELY(p->next != NULL))
722 return; /* XXX: we want it in one chunk */
723
724 bool broadcasted = ip_addr_cmp(ip_current_dest_addr(), &ip_addr_broadcast)
725 || ip_addr_cmp(ip_current_dest_addr(), &ip_addr_any);
726
727 try
728 {
729 DhcpClientMessage *msgIn = DhcpClientMessage::parse(broadcasted, p->payload, p->len);
730 if (msgIn == NULL)
731 return;
732
733 std::unique_ptr<DhcpClientMessage> autoFreeMsgIn(msgIn);
734
735 DhcpServerMessage *msgOut = m_server.process(*msgIn);
736 if (msgOut == NULL)
737 return;
738
739 std::unique_ptr<DhcpServerMessage> autoFreeMsgOut(msgOut);
740
741 ip_addr_t dst = { msgOut->dst().u };
742 if (ip_addr_cmp(&dst, &ip_addr_any))
743 ip_addr_copy(dst, ip_addr_broadcast);
744
745 octets_t data;
746 int rc = msgOut->encode(data);
747 if (RT_FAILURE(rc))
748 return;
749
750 unique_ptr_pbuf q ( pbuf_alloc(PBUF_RAW, (u16_t)data.size(), PBUF_RAM) );
751 if (!q)
752 return;
753
754 err_t error = pbuf_take(q.get(), &data.front(), (u16_t)data.size());
755 if (error != ERR_OK)
756 return;
757
758 error = udp_sendto(pcb, q.get(), &dst, RTNETIPV4_PORT_BOOTPC);
759 if (error != ERR_OK)
760 return;
761 }
762 catch (std::bad_alloc &)
763 {
764 LogRel(("VBoxNetDhcpd::dhcp4Recv: Caught std::bad_alloc!\n"));
765 }
766}
767
768
769
770
771/*
772 * Entry point.
773 */
774extern "C" DECLEXPORT(int) TrustedMain(int argc, char **argv)
775{
776 VBoxNetDhcpd Dhcpd;
777 int rc = Dhcpd.main(argc, argv);
778 return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
779}
780
781
782#ifndef VBOX_WITH_HARDENING
783
784int main(int argc, char **argv)
785{
786 int rc = RTR3InitExe(argc, &argv, RTR3INIT_FLAGS_SUPLIB);
787 if (RT_SUCCESS(rc))
788 return TrustedMain(argc, argv);
789 return RTMsgInitFailure(rc);
790}
791
792
793# ifdef RT_OS_WINDOWS
794/** (We don't want a console usually.) */
795int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
796{
797 RT_NOREF(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
798
799 return main(__argc, __argv);
800}
801# endif /* RT_OS_WINDOWS */
802
803#endif /* !VBOX_WITH_HARDENING */
Note: See TracBrowser for help on using the repository browser.

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