VirtualBox

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

Last change on this file since 96407 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

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