VirtualBox

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

Last change on this file since 79568 was 79568, checked in by vboxsync, 6 years ago

Dhcpd: Went over the DhcpMessage a little as well as revisiting the lease reading code in the database. Logging is LogRel() or similar, no cout, RTPrintf or similar. The debug & release loggers can both output to stderr/out/whatever as needed. bugref:9288

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