VirtualBox

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

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

Main/DHCPServer,Dhcpd,VBoxManage: Added --log option to the DHCP server so we can start logging early. Added log rotation and limits. Put the config file next to the log and leases file. Validate DHCP options by reusing the parser code from the server, adding a bunch more DHCP options to the parser. Removed legacy and hardcoded configuration options from the dhcp server, it's all config file now. Fixed a bug in the option parsing of the VBoxManage dhcpserver add/modify commands. bugref:9288

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 19.4 KB
Line 
1/* $Id: VBoxNetDhcpd.cpp 79761 2019-07-14 03:18:41Z 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 DHCP_LOG_MSG_ERROR(("ifWait failed: %Rrc\n", rc));
383 return;
384 }
385 }
386}
387
388
389int VBoxNetDhcpd::ifWait(uint32_t cMillies)
390{
391 AssertReturn(m_pSession != NIL_RTR0PTR, VERR_GENERAL_FAILURE);
392 AssertReturn(m_hIf != INTNET_HANDLE_INVALID, VERR_GENERAL_FAILURE);
393
394 INTNETIFWAITREQ WaitReq;
395 int rc;
396
397 WaitReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
398 WaitReq.Hdr.cbReq = sizeof(WaitReq);
399 WaitReq.pSession = m_pSession;
400 WaitReq.hIf = m_hIf;
401
402 WaitReq.cMillies = cMillies;
403
404 rc = CALL_VMMR0(VMMR0_DO_INTNET_IF_WAIT, WaitReq);
405 return rc;
406}
407
408
409int VBoxNetDhcpd::ifProcessInput()
410{
411 AssertReturn(m_pSession != NIL_RTR0PTR, VERR_GENERAL_FAILURE);
412 AssertReturn(m_hIf != INTNET_HANDLE_INVALID, VERR_GENERAL_FAILURE);
413 AssertReturn(m_pIfBuf != NULL, VERR_GENERAL_FAILURE);
414
415 for (PCINTNETHDR pHdr;
416 (pHdr = IntNetRingGetNextFrameToRead(&m_pIfBuf->Recv)) != NULL;
417 IntNetRingSkipFrame(&m_pIfBuf->Recv))
418 {
419 const uint8_t u8Type = pHdr->u8Type;
420 void *pvSegFrame;
421 uint32_t cbSegFrame;
422
423 if (u8Type == INTNETHDR_TYPE_FRAME)
424 {
425 pvSegFrame = IntNetHdrGetFramePtr(pHdr, m_pIfBuf);
426 cbSegFrame = pHdr->cbFrame;
427
428 ifInput(pvSegFrame, cbSegFrame);
429 }
430 else if (u8Type == INTNETHDR_TYPE_GSO)
431 {
432 PCPDMNETWORKGSO pGso;
433 size_t cbGso = pHdr->cbFrame;
434 size_t cbFrame = cbGso - sizeof(PDMNETWORKGSO);
435
436 pGso = IntNetHdrGetGsoContext(pHdr, m_pIfBuf);
437 if (!PDMNetGsoIsValid(pGso, cbGso, cbFrame))
438 continue;
439
440 const uint32_t cSegs = PDMNetGsoCalcSegmentCount(pGso, cbFrame);
441 for (uint32_t i = 0; i < cSegs; ++i)
442 {
443 uint8_t abHdrScratch[256];
444 pvSegFrame = PDMNetGsoCarveSegmentQD(pGso, (uint8_t *)(pGso + 1), cbFrame,
445 abHdrScratch,
446 i, cSegs,
447 &cbSegFrame);
448 ifInput(pvSegFrame, (uint32_t)cbFrame);
449 }
450 }
451 }
452
453 return VINF_SUCCESS;
454}
455
456
457/**
458 * Got a frame from the internal network, feed it to the lwIP stack.
459 */
460int VBoxNetDhcpd::ifInput(void *pvFrame, uint32_t cbFrame)
461{
462 if (pvFrame == NULL)
463 return VERR_INVALID_PARAMETER;
464
465 if ( cbFrame <= sizeof(RTNETETHERHDR)
466 || cbFrame > UINT16_MAX - ETH_PAD_SIZE)
467 return VERR_INVALID_PARAMETER;
468
469 struct pbuf *p = pbuf_alloc(PBUF_RAW, (u16_t)cbFrame + ETH_PAD_SIZE, PBUF_POOL);
470 if (RT_UNLIKELY(p == NULL))
471 return VERR_NO_MEMORY;
472
473 /*
474 * The code below is inlined version of:
475 *
476 * pbuf_header(p, -ETH_PAD_SIZE); // hide padding
477 * pbuf_take(p, pvFrame, cbFrame);
478 * pbuf_header(p, ETH_PAD_SIZE); // reveal padding
479 */
480 struct pbuf *q = p;
481 uint8_t *pbChunk = (uint8_t *)pvFrame;
482 do {
483 uint8_t *payload = (uint8_t *)q->payload;
484 size_t len = q->len;
485
486#if ETH_PAD_SIZE
487 if (RT_LIKELY(q == p)) /* single pbuf is large enough */
488 {
489 payload += ETH_PAD_SIZE;
490 len -= ETH_PAD_SIZE;
491 }
492#endif
493 memcpy(payload, pbChunk, len);
494 pbChunk += len;
495 q = q->next;
496 } while (RT_UNLIKELY(q != NULL));
497
498 m_LwipNetif.input(p, &m_LwipNetif);
499 return VINF_SUCCESS;
500}
501
502
503/**
504 * Got a frame from the lwIP stack, feed it to the internal network.
505 */
506err_t VBoxNetDhcpd::netifLinkOutput(pbuf *pPBuf)
507{
508 PINTNETHDR pHdr;
509 void *pvFrame;
510 u16_t cbFrame;
511 int rc;
512
513 if (pPBuf->tot_len < sizeof(struct eth_hdr)) /* includes ETH_PAD_SIZE */
514 return ERR_ARG;
515
516 cbFrame = pPBuf->tot_len - ETH_PAD_SIZE;
517 rc = IntNetRingAllocateFrame(&m_pIfBuf->Send, cbFrame, &pHdr, &pvFrame);
518 if (RT_FAILURE(rc))
519 return ERR_MEM;
520
521 pbuf_copy_partial(pPBuf, pvFrame, cbFrame, ETH_PAD_SIZE);
522 IntNetRingCommitFrameEx(&m_pIfBuf->Send, pHdr, cbFrame);
523
524 ifFlush();
525 return ERR_OK;
526}
527
528
529int VBoxNetDhcpd::ifFlush()
530{
531 INTNETIFSENDREQ SendReq;
532 int rc;
533
534 SendReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
535 SendReq.Hdr.cbReq = sizeof(SendReq);
536 SendReq.pSession = m_pSession;
537
538 SendReq.hIf = m_hIf;
539
540 rc = CALL_VMMR0(VMMR0_DO_INTNET_IF_SEND, SendReq);
541 return rc;
542}
543
544
545int VBoxNetDhcpd::ifClose()
546{
547 if (m_hIf == INTNET_HANDLE_INVALID)
548 return VINF_SUCCESS;
549
550 INTNETIFCLOSEREQ CloseReq;
551
552 CloseReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
553 CloseReq.Hdr.cbReq = sizeof(CloseReq);
554 CloseReq.pSession = m_pSession;
555
556 CloseReq.hIf = m_hIf;
557
558 m_hIf = INTNET_HANDLE_INVALID;
559 m_pIfBuf = NULL;
560
561 CALL_VMMR0(VMMR0_DO_INTNET_IF_CLOSE, CloseReq);
562 return VINF_SUCCESS;
563}
564
565
566/* static */ DECLCALLBACK(void) VBoxNetDhcpd::lwipInitCB(void *pvArg)
567{
568 AssertPtrReturnVoid(pvArg);
569
570 VBoxNetDhcpd *self = static_cast<VBoxNetDhcpd *>(pvArg);
571 self->lwipInit();
572}
573
574
575/* static */ err_t VBoxNetDhcpd::netifInitCB(netif *pNetif)
576{
577 AssertPtrReturn(pNetif, ERR_ARG);
578
579 VBoxNetDhcpd *self = static_cast<VBoxNetDhcpd *>(pNetif->state);
580 return self->netifInit(pNetif);
581}
582
583
584/* static */ err_t VBoxNetDhcpd::netifLinkOutputCB(netif *pNetif, pbuf *pPBuf)
585{
586 AssertPtrReturn(pNetif, ERR_ARG);
587 AssertPtrReturn(pPBuf, ERR_ARG);
588
589 VBoxNetDhcpd *self = static_cast<VBoxNetDhcpd *>(pNetif->state);
590 AssertPtrReturn(self, ERR_IF);
591
592 return self->netifLinkOutput(pPBuf);
593}
594
595
596/* static */ void VBoxNetDhcpd::dhcp4RecvCB(void *arg, struct udp_pcb *pcb,
597 struct pbuf *p,
598 ip_addr_t *addr, u16_t port)
599{
600 AssertPtrReturnVoid(arg);
601
602 VBoxNetDhcpd *self = static_cast<VBoxNetDhcpd *>(arg);
603 self->dhcp4Recv(pcb, p, addr, port);
604 pbuf_free(p);
605}
606
607
608
609
610
611int VBoxNetDhcpd::main(int argc, char **argv)
612{
613 /*
614 * Register string format types.
615 */
616 ClientId::registerFormat();
617 Binding::registerFormat();
618
619 /*
620 * Parse the command line into a configuration object.
621 */
622 m_Config = Config::create(argc, argv);
623 if (m_Config == NULL)
624 return VERR_GENERAL_FAILURE;
625
626 /*
627 * Initialize the server.
628 */
629 int rc = m_server.init(m_Config);
630 if (RT_SUCCESS(rc))
631 {
632 /* connect to the intnet */
633 rc = ifInit(m_Config->getNetwork(), m_Config->getTrunk(), m_Config->getTrunkType());
634 if (RT_SUCCESS(rc))
635 {
636 /* setup lwip */
637 rc = vboxLwipCoreInitialize(lwipInitCB, this);
638 if (RT_SUCCESS(rc))
639 {
640 /*
641 * Pump packets more or less for ever.
642 */
643 ifPump();
644 }
645 else
646 DHCP_LOG_MSG_ERROR(("Terminating - vboxLwipCoreInitialize failed: %Rrc\n", rc));
647 }
648 else
649 DHCP_LOG_MSG_ERROR(("Terminating - ifInit failed: %Rrc\n", rc));
650 }
651 else
652 DHCP_LOG_MSG_ERROR(("Terminating - Dhcpd::init failed: %Rrc\n", rc));
653 return rc;
654}
655
656
657void VBoxNetDhcpd::lwipInit()
658{
659 err_t error;
660
661 ip_addr_t addr, mask;
662 ip4_addr_set_u32(&addr, m_Config->getIPv4Address().u);
663 ip4_addr_set_u32(&mask, m_Config->getIPv4Netmask().u);
664
665 netif *pNetif = netif_add(&m_LwipNetif,
666 &addr, &mask,
667 IP_ADDR_ANY, /* gateway */
668 this, /* state */
669 VBoxNetDhcpd::netifInitCB, /* netif_init_fn */
670 tcpip_input); /* netif_input_fn */
671 if (pNetif == NULL)
672 return;
673
674 netif_set_up(pNetif);
675 netif_set_link_up(pNetif);
676
677 m_Dhcp4Pcb = udp_new();
678 if (RT_UNLIKELY(m_Dhcp4Pcb == NULL))
679 return; /* XXX? */
680
681 ip_set_option(m_Dhcp4Pcb, SOF_BROADCAST);
682 udp_recv(m_Dhcp4Pcb, dhcp4RecvCB, this);
683
684 error = udp_bind(m_Dhcp4Pcb, IP_ADDR_ANY, RTNETIPV4_PORT_BOOTPS);
685 if (error != ERR_OK)
686 {
687 udp_remove(m_Dhcp4Pcb);
688 m_Dhcp4Pcb = NULL;
689 return; /* XXX? */
690 }
691}
692
693
694err_t VBoxNetDhcpd::netifInit(netif *pNetif)
695{
696 pNetif->hwaddr_len = sizeof(RTMAC);
697 memcpy(pNetif->hwaddr, &m_Config->getMacAddress(), sizeof(RTMAC));
698
699 pNetif->mtu = 1500;
700
701 pNetif->flags = NETIF_FLAG_BROADCAST
702 | NETIF_FLAG_ETHARP
703 | NETIF_FLAG_ETHERNET;
704
705 pNetif->linkoutput = netifLinkOutputCB;
706 pNetif->output = etharp_output;
707
708 netif_set_default(pNetif);
709 return ERR_OK;
710}
711
712
713void VBoxNetDhcpd::dhcp4Recv(struct udp_pcb *pcb, struct pbuf *p,
714 ip_addr_t *addr, u16_t port)
715{
716 RT_NOREF(pcb, addr, port);
717
718 if (RT_UNLIKELY(p->next != NULL))
719 return; /* XXX: we want it in one chunk */
720
721 bool broadcasted = ip_addr_cmp(ip_current_dest_addr(), &ip_addr_broadcast)
722 || ip_addr_cmp(ip_current_dest_addr(), &ip_addr_any);
723
724 try
725 {
726 DhcpClientMessage *msgIn = DhcpClientMessage::parse(broadcasted, p->payload, p->len);
727 if (msgIn == NULL)
728 return;
729
730 std::unique_ptr<DhcpClientMessage> autoFreeMsgIn(msgIn);
731
732 DhcpServerMessage *msgOut = m_server.process(*msgIn);
733 if (msgOut == NULL)
734 return;
735
736 std::unique_ptr<DhcpServerMessage> autoFreeMsgOut(msgOut);
737
738 ip_addr_t dst = { msgOut->dst().u };
739 if (ip_addr_cmp(&dst, &ip_addr_any))
740 ip_addr_copy(dst, ip_addr_broadcast);
741
742 octets_t data;
743 int rc = msgOut->encode(data);
744 if (RT_FAILURE(rc))
745 return;
746
747 unique_ptr_pbuf q ( pbuf_alloc(PBUF_RAW, (u16_t)data.size(), PBUF_RAM) );
748 if (!q)
749 return;
750
751 err_t error = pbuf_take(q.get(), &data.front(), (u16_t)data.size());
752 if (error != ERR_OK)
753 return;
754
755 error = udp_sendto(pcb, q.get(), &dst, RTNETIPV4_PORT_BOOTPC);
756 if (error != ERR_OK)
757 return;
758 }
759 catch (std::bad_alloc &)
760 {
761 LogRel(("VBoxNetDhcpd::dhcp4Recv: Caught std::bad_alloc!\n"));
762 }
763}
764
765
766
767
768/*
769 * Entry point.
770 */
771extern "C" DECLEXPORT(int) TrustedMain(int argc, char **argv)
772{
773 VBoxNetDhcpd Dhcpd;
774 int rc = Dhcpd.main(argc, argv);
775
776 return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
777}
778
779
780#ifndef VBOX_WITH_HARDENING
781
782int main(int argc, char **argv)
783{
784 int rc = RTR3InitExe(argc, &argv, RTR3INIT_FLAGS_SUPLIB);
785 if (RT_FAILURE(rc))
786 return RTMsgInitFailure(rc);
787
788 return TrustedMain(argc, argv);
789}
790
791
792# ifdef RT_OS_WINDOWS
793/** (We don't want a console usually.) */
794int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
795{
796 RT_NOREF(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
797
798 return main(__argc, __argv);
799}
800# endif /* RT_OS_WINDOWS */
801
802#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