VirtualBox

source: vbox/trunk/src/VBox/NetworkServices/DHCP/VBoxNetDHCP.cpp@ 49490

Last change on this file since 49490 was 49490, checked in by vboxsync, 11 years ago

VBoxNetDHCP. split ::init to ::initWithMain and ::initNoMain. The first step to avoid connection to Main when servicing Host-Only and Internal Network. ::initNoMain() drops connection at fist action. The further improvement will be hint from caller (cmdline parameter whether DHCP need consult Main and listen for changes on Host-side).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 31.4 KB
Line 
1/* $Id: VBoxNetDHCP.cpp 49490 2013-11-15 10:09:13Z vboxsync $ */
2/** @file
3 * VBoxNetDHCP - DHCP Service for connecting to IntNet.
4 */
5
6/*
7 * Copyright (C) 2009-2011 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/** @page pg_net_dhcp VBoxNetDHCP
19 *
20 * Write a few words...
21 *
22 */
23
24/*******************************************************************************
25* Header Files *
26*******************************************************************************/
27#include <VBox/com/com.h>
28#include <VBox/com/listeners.h>
29#include <VBox/com/string.h>
30#include <VBox/com/Guid.h>
31#include <VBox/com/array.h>
32#include <VBox/com/ErrorInfo.h>
33#include <VBox/com/errorprint.h>
34#include <VBox/com/EventQueue.h>
35#include <VBox/com/VirtualBox.h>
36
37#include <iprt/alloca.h>
38#include <iprt/buildconfig.h>
39#include <iprt/err.h>
40#include <iprt/net.h> /* must come before getopt */
41#include <iprt/getopt.h>
42#include <iprt/initterm.h>
43#include <iprt/message.h>
44#include <iprt/param.h>
45#include <iprt/path.h>
46#include <iprt/stream.h>
47#include <iprt/time.h>
48#include <iprt/string.h>
49
50#include <VBox/sup.h>
51#include <VBox/intnet.h>
52#include <VBox/intnetinline.h>
53#include <VBox/vmm/vmm.h>
54#include <VBox/version.h>
55
56
57#include "../NetLib/VBoxNetLib.h"
58#include "../NetLib/shared_ptr.h"
59
60#include <vector>
61#include <list>
62#include <string>
63#include <map>
64
65#include "../NetLib/VBoxNetBaseService.h"
66
67#ifdef RT_OS_WINDOWS /* WinMain */
68# include <Windows.h>
69# include <stdlib.h>
70# ifdef INET_ADDRSTRLEN
71/* On Windows INET_ADDRSTRLEN defined as 22 Ws2ipdef.h, because it include port number */
72# undef INET_ADDRSTRLEN
73# endif
74# define INET_ADDRSTRLEN 16
75#else
76# include <netinet/in.h>
77#endif
78
79
80#include "Config.h"
81/*******************************************************************************
82* Structures and Typedefs *
83*******************************************************************************/
84/**
85 * DHCP server instance.
86 */
87class VBoxNetDhcp: public VBoxNetBaseService
88{
89public:
90 VBoxNetDhcp();
91 virtual ~VBoxNetDhcp();
92
93 int init();
94 int run(void);
95 void usage(void) { /* XXX: document options */ };
96 int parseOpt(int rc, const RTGETOPTUNION& getOptVal);
97
98protected:
99 bool handleDhcpMsg(uint8_t uMsgType, PCRTNETBOOTP pDhcpMsg, size_t cb);
100 bool handleDhcpReqDiscover(PCRTNETBOOTP pDhcpMsg, size_t cb);
101 bool handleDhcpReqRequest(PCRTNETBOOTP pDhcpMsg, size_t cb);
102 bool handleDhcpReqDecline(PCRTNETBOOTP pDhcpMsg, size_t cb);
103 bool handleDhcpReqRelease(PCRTNETBOOTP pDhcpMsg, size_t cb);
104
105 void debugPrintV(int32_t iMinLevel, bool fMsg, const char *pszFmt, va_list va) const;
106 static const char *debugDhcpName(uint8_t uMsgType);
107
108private:
109 int initNoMain();
110 int initWithMain();
111
112protected:
113 /** @name The DHCP server specific configuration data members.
114 * @{ */
115 /*
116 * XXX: what was the plan? SQL3 or plain text file?
117 * How it will coexists with managment from VBoxManagement, who should manage db
118 * in that case (VBoxManage, VBoxSVC ???)
119 */
120 std::string m_LeaseDBName;
121
122 /** @} */
123
124 /* corresponding dhcp server description in Main */
125 ComPtr<IDHCPServer> m_DhcpServer;
126
127 ComPtr<INATNetwork> m_NATNetwork;
128
129 /*
130 * We will ignore cmd line parameters IFF there will be some DHCP specific arguments
131 * otherwise all paramters will come from Main.
132 */
133 bool m_fIgnoreCmdLineParameters;
134
135 /*
136 * -b -n 10.0.1.2 -m 255.255.255.0 -> to the list processing in
137 */
138 typedef struct
139 {
140 char Key;
141 std::string strValue;
142 } CMDLNPRM;
143 std::list<CMDLNPRM> CmdParameterll;
144 typedef std::list<CMDLNPRM>::iterator CmdParameterIterator;
145
146 /** @name Debug stuff
147 * @{ */
148 int32_t m_cVerbosity;
149 uint8_t m_uCurMsgType;
150 size_t m_cbCurMsg;
151 PCRTNETBOOTP m_pCurMsg;
152 VBOXNETUDPHDRS m_CurHdrs;
153 /** @} */
154};
155#if 0
156/* XXX: clean up it. */
157typedef std::vector<VBoxNetDhcpLease> DhcpLeaseContainer;
158typedef DhcpLeaseContainer::iterator DhcpLeaseIterator;
159typedef DhcpLeaseContainer::reverse_iterator DhcpLeaseRIterator;
160typedef DhcpLeaseContainer::const_iterator DhcpLeaseCIterator;
161#endif
162
163/*******************************************************************************
164* Global Variables *
165*******************************************************************************/
166/** Pointer to the DHCP server. */
167static VBoxNetDhcp *g_pDhcp;
168
169/* DHCP server specific options */
170static RTGETOPTDEF g_aOptionDefs[] =
171{
172 { "--lease-db", 'D', RTGETOPT_REQ_STRING },
173 { "--begin-config", 'b', RTGETOPT_REQ_NOTHING },
174 { "--gateway", 'g', RTGETOPT_REQ_IPV4ADDR },
175 { "--lower-ip", 'l', RTGETOPT_REQ_IPV4ADDR },
176 { "--upper-ip", 'u', RTGETOPT_REQ_IPV4ADDR },
177};
178
179#if 0
180/* XXX this will gone */
181/**
182 * Offer this lease to a client.
183 *
184 * @param xid The transaction ID.
185 */
186void VBoxNetDhcpLease::offer(uint32_t xid)
187{
188 m_enmState = kState_Offer;
189 m_xid = xid;
190 RTTimeNow(&m_ExpireTime);
191 RTTimeSpecAddSeconds(&m_ExpireTime, 60);
192}
193
194
195/**
196 * Activate this lease (i.e. a client is now using it).
197 */
198void VBoxNetDhcpLease::activate(void)
199{
200 m_enmState = kState_Active;
201 RTTimeNow(&m_ExpireTime);
202 RTTimeSpecAddSeconds(&m_ExpireTime, m_pCfg ? m_pCfg->m_cSecLease : 60); /* m_pCfg can be NULL right now... */
203}
204
205
206/**
207 * Activate this lease with a new transaction ID.
208 *
209 * @param xid The transaction ID.
210 * @todo check if this is really necessary.
211 */
212void VBoxNetDhcpLease::activate(uint32_t xid)
213{
214 activate();
215 m_xid = xid;
216}
217
218
219/**
220 * Release a lease either upon client request or because it didn't quite match a
221 * DHCP_REQUEST.
222 */
223void VBoxNetDhcpLease::release(void)
224{
225 m_enmState = kState_Free;
226 RTTimeNow(&m_ExpireTime);
227 RTTimeSpecAddSeconds(&m_ExpireTime, 5);
228}
229
230
231/**
232 * Checks if the lease has expired or not.
233 *
234 * This just checks the expiration time not the state. This is so that this
235 * method will work for reusing RELEASEd leases when the client comes back after
236 * a reboot or ipconfig /renew. Callers not interested in info on released
237 * leases should check the state first.
238 *
239 * @returns true if expired, false if not.
240 */
241bool VBoxNetDhcpLease::hasExpired() const
242{
243 RTTIMESPEC Now;
244 return RTTimeSpecGetSeconds(&m_ExpireTime) > RTTimeSpecGetSeconds(RTTimeNow(&Now));
245}
246#endif
247
248/**
249 * Construct a DHCP server with a default configuration.
250 */
251VBoxNetDhcp::VBoxNetDhcp()
252{
253 m_Name = "VBoxNetDhcp";
254 m_Network = "VBoxNetDhcp";
255 m_TrunkName = "";
256 m_enmTrunkType = kIntNetTrunkType_WhateverNone;
257 m_MacAddress.au8[0] = 0x08;
258 m_MacAddress.au8[1] = 0x00;
259 m_MacAddress.au8[2] = 0x27;
260 m_MacAddress.au8[3] = 0x40;
261 m_MacAddress.au8[4] = 0x41;
262 m_MacAddress.au8[5] = 0x42;
263 m_Ipv4Address.u = RT_H2N_U32_C(RT_BSWAP_U32_C(RT_MAKE_U32_FROM_U8( 10, 0, 2, 5)));
264
265 m_pSession = NIL_RTR0PTR;
266 m_cbSendBuf = 8192;
267 m_cbRecvBuf = 51200; /** @todo tune to 64 KB with help from SrvIntR0 */
268 m_hIf = INTNET_HANDLE_INVALID;
269 m_pIfBuf = NULL;
270
271 m_cVerbosity = 0;
272 m_uCurMsgType = UINT8_MAX;
273 m_cbCurMsg = 0;
274 m_pCurMsg = NULL;
275 memset(&m_CurHdrs, '\0', sizeof(m_CurHdrs));
276
277 m_fIgnoreCmdLineParameters = true;
278
279 for(unsigned int i = 0; i < RT_ELEMENTS(g_aOptionDefs); ++i)
280 m_vecOptionDefs.push_back(&g_aOptionDefs[i]);
281
282#if 0 /* enable to hack the code without a mile long argument list. */
283 VBoxNetDhcpCfg *pDefCfg = new VBoxNetDhcpCfg();
284 pDefCfg->m_LowerAddr.u = RT_H2N_U32_C(RT_BSWAP_U32_C(RT_MAKE_U32_FROM_U8( 10, 0, 2,100)));
285 pDefCfg->m_UpperAddr.u = RT_H2N_U32_C(RT_BSWAP_U32_C(RT_MAKE_U32_FROM_U8( 10, 0, 2,250)));
286 pDefCfg->m_SubnetMask.u = RT_H2N_U32_C(RT_BSWAP_U32_C(RT_MAKE_U32_FROM_U8(255,255,255, 0)));
287 RTNETADDRIPV4 Addr;
288 Addr.u = RT_H2N_U32_C(RT_BSWAP_U32_C(RT_MAKE_U32_FROM_U8( 10, 0, 2, 1)));
289 pDefCfg->m_Routers.push_back(Addr);
290 Addr.u = RT_H2N_U32_C(RT_BSWAP_U32_C(RT_MAKE_U32_FROM_U8( 10, 0, 2, 2)));
291 pDefCfg->m_DNSes.push_back(Addr);
292 pDefCfg->m_DomainName = "vboxnetdhcp.org";
293# if 0
294 pDefCfg->m_cSecLease = 60*60; /* 1 hour */
295# else
296 pDefCfg->m_cSecLease = 30; /* sec */
297# endif
298 pDefCfg->m_TftpServer = "10.0.2.3"; //??
299 this->addConfig(pDefCfg);
300#endif
301}
302
303
304/**
305 * Destruct a DHCP server.
306 */
307VBoxNetDhcp::~VBoxNetDhcp()
308{
309}
310
311
312
313
314/**
315 * Parse the DHCP specific arguments.
316 *
317 * This callback caled for each paramenter so
318 * ....
319 * we nee post analisys of the parameters, at least
320 * for -b, -g, -l, -u, -m
321 */
322int VBoxNetDhcp::parseOpt(int rc, const RTGETOPTUNION& Val)
323{
324 CMDLNPRM prm;
325
326 /* Ok, we've entered here, thus we can't ignore cmd line parameters anymore */
327 m_fIgnoreCmdLineParameters = false;
328
329 prm.Key = rc;
330
331 switch (rc)
332 {
333 case 'l':
334 case 'u':
335 case 'g':
336 {
337 char buf[17];
338 RTStrPrintf(buf, 17, "%RTnaipv4", Val.IPv4Addr.u);
339 prm.strValue = buf;
340 CmdParameterll.push_back(prm);
341 }
342 break;
343
344 case 'b': // ignore
345 case 'D': // ignore
346 break;
347
348 default:
349 rc = RTGetOptPrintError(rc, &Val);
350 RTPrintf("Use --help for more information.\n");
351 return rc;
352 }
353
354 return VINF_SUCCESS;
355}
356
357int VBoxNetDhcp::init()
358{
359 HRESULT hrc = S_OK;
360 /* ok, here we should initiate instance of dhcp server
361 * and listener for Dhcp configuration events
362 */
363 AssertRCReturn(virtualbox.isNull(), VERR_INTERNAL_ERROR);
364
365 hrc = virtualbox->FindDHCPServerByNetworkName(com::Bstr(m_Network.c_str()).raw(),
366 m_DhcpServer.asOutParam());
367 AssertComRCReturn(hrc, VERR_INTERNAL_ERROR);
368
369 hrc = virtualbox->FindNATNetworkByName(com::Bstr(m_Network.c_str()).raw(),
370 m_NATNetwork.asOutParam());
371
372
373 bool fNoMain = m_NATNetwork.isNull();
374 int rc;
375 NetworkManager *netManager = NetworkManager::getNetworkManager();
376
377 netManager->setOurAddress(m_Ipv4Address);
378 netManager->setOurNetmask(m_Ipv4Netmask);
379 netManager->setOurMac(m_MacAddress);
380
381 if (fNoMain)
382 rc = initNoMain();
383 else
384 rc = initWithMain();
385
386 AssertRCReturn(rc, rc);
387
388 return VINF_SUCCESS;
389}
390
391/**
392 * Runs the DHCP server.
393 *
394 * @returns exit code + error message to stderr on failure, won't return on
395 * success (you must kill this process).
396 */
397int VBoxNetDhcp::run(void)
398{
399
400 /* XXX: shortcut should be hidden from network manager */
401 NetworkManager *netManager = NetworkManager::getNetworkManager();
402 netManager->m_pSession = m_pSession;
403 netManager->m_hIf = m_hIf;
404 netManager->m_pIfBuf = m_pIfBuf;
405
406 /*
407 * The loop.
408 */
409 PINTNETRINGBUF pRingBuf = &m_pIfBuf->Recv;
410 for (;;)
411 {
412 /*
413 * Wait for a packet to become available.
414 */
415 INTNETIFWAITREQ WaitReq;
416 WaitReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
417 WaitReq.Hdr.cbReq = sizeof(WaitReq);
418 WaitReq.pSession = m_pSession;
419 WaitReq.hIf = m_hIf;
420 WaitReq.cMillies = 2000; /* 2 secs - the sleep is for some reason uninterruptible... */ /** @todo fix interruptability in SrvIntNet! */
421 int rc = SUPR3CallVMMR0Ex(NIL_RTR0PTR, NIL_VMCPUID, VMMR0_DO_INTNET_IF_WAIT, 0, &WaitReq.Hdr);
422 if (RT_FAILURE(rc))
423 {
424 if (rc == VERR_TIMEOUT || rc == VERR_INTERRUPTED)
425 continue;
426 RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: VMMR0_DO_INTNET_IF_WAIT returned %Rrc\n", rc);
427 return 1;
428 }
429
430 /*
431 * Process the receive buffer.
432 */
433 while (IntNetRingHasMoreToRead(pRingBuf))
434 {
435 size_t cb;
436 void *pv = VBoxNetUDPMatch(m_pIfBuf, RTNETIPV4_PORT_BOOTPS, &m_MacAddress,
437 VBOXNETUDP_MATCH_UNICAST | VBOXNETUDP_MATCH_BROADCAST | VBOXNETUDP_MATCH_CHECKSUM
438 | (m_cVerbosity > 2 ? VBOXNETUDP_MATCH_PRINT_STDERR : 0),
439 &m_CurHdrs, &cb);
440 if (pv && cb)
441 {
442 PCRTNETBOOTP pDhcpMsg = (PCRTNETBOOTP)pv;
443 m_pCurMsg = pDhcpMsg;
444 m_cbCurMsg = cb;
445
446 uint8_t uMsgType;
447 if (RTNetIPv4IsDHCPValid(NULL /* why is this here? */, pDhcpMsg, cb, &uMsgType))
448 {
449 m_uCurMsgType = uMsgType;
450 handleDhcpMsg(uMsgType, pDhcpMsg, cb);
451 m_uCurMsgType = UINT8_MAX;
452 }
453 else
454 debugPrint(1, true, "VBoxNetDHCP: Skipping invalid DHCP packet.\n"); /** @todo handle pure bootp clients too? */
455
456 m_pCurMsg = NULL;
457 m_cbCurMsg = 0;
458 }
459 else if (VBoxNetArpHandleIt(m_pSession, m_hIf, m_pIfBuf, &m_MacAddress, m_Ipv4Address))
460 {
461 /* nothing */
462 }
463
464 /* Advance to the next frame. */
465 IntNetRingSkipFrame(pRingBuf);
466 }
467 }
468
469 return 0;
470}
471
472
473/**
474 * Handles a DHCP message.
475 *
476 * @returns true if handled, false if not.
477 * @param uMsgType The message type.
478 * @param pDhcpMsg The DHCP message.
479 * @param cb The size of the DHCP message.
480 */
481bool VBoxNetDhcp::handleDhcpMsg(uint8_t uMsgType, PCRTNETBOOTP pDhcpMsg, size_t cb)
482{
483 if (pDhcpMsg->bp_op == RTNETBOOTP_OP_REQUEST)
484 {
485 switch (uMsgType)
486 {
487 case RTNET_DHCP_MT_DISCOVER:
488 return handleDhcpReqDiscover(pDhcpMsg, cb);
489
490 case RTNET_DHCP_MT_REQUEST:
491 return handleDhcpReqRequest(pDhcpMsg, cb);
492
493 case RTNET_DHCP_MT_DECLINE:
494 return handleDhcpReqDecline(pDhcpMsg, cb);
495
496 case RTNET_DHCP_MT_RELEASE:
497 return handleDhcpReqRelease(pDhcpMsg, cb);
498
499 case RTNET_DHCP_MT_INFORM:
500 debugPrint(0, true, "Should we handle this?");
501 break;
502
503 default:
504 debugPrint(0, true, "Unexpected.");
505 break;
506 }
507 }
508 return false;
509}
510
511
512/**
513 * The client is requesting an offer.
514 *
515 * @returns true.
516 *
517 * @param pDhcpMsg The message.
518 * @param cb The message size.
519 */
520bool VBoxNetDhcp::handleDhcpReqDiscover(PCRTNETBOOTP pDhcpMsg, size_t cb)
521{
522 RawOption opt;
523 memset(&opt, 0, sizeof(RawOption));
524 /* 1. Find client */
525 ConfigurationManager *confManager = ConfigurationManager::getConfigurationManager();
526 Client client = confManager->getClientByDhcpPacket(pDhcpMsg, cb);
527
528 /* 2. Find/Bind lease for client */
529 Lease lease = confManager->allocateLease4Client(client, pDhcpMsg, cb);
530 AssertReturn(lease != Lease::NullLease, VINF_SUCCESS);
531
532 int rc = ConfigurationManager::extractRequestList(pDhcpMsg, cb, opt);
533
534 /* 3. Send of offer */
535 NetworkManager *networkManager = NetworkManager::getNetworkManager();
536
537 lease.bindingPhase(true);
538 lease.phaseStart(RTTimeMilliTS());
539 lease.setExpiration(300); /* 3 min. */
540 networkManager->offer4Client(client, pDhcpMsg->bp_xid, opt.au8RawOpt, opt.cbRawOpt);
541
542 return VINF_SUCCESS;
543}
544
545
546/**
547 * The client is requesting an offer.
548 *
549 * @returns true.
550 *
551 * @param pDhcpMsg The message.
552 * @param cb The message size.
553 */
554bool VBoxNetDhcp::handleDhcpReqRequest(PCRTNETBOOTP pDhcpMsg, size_t cb)
555{
556 ConfigurationManager *confManager = ConfigurationManager::getConfigurationManager();
557 NetworkManager *networkManager = NetworkManager::getNetworkManager();
558
559 /* 1. find client */
560 Client client = confManager->getClientByDhcpPacket(pDhcpMsg, cb);
561
562 /* 2. find bound lease */
563 Lease l = client.lease();
564 if (l != Lease::NullLease)
565 {
566
567 if (l.isExpired())
568 {
569 /* send client to INIT state */
570 Client c(client);
571 networkManager->nak(client, pDhcpMsg->bp_xid);
572 confManager->expireLease4Client(c);
573 return true;
574 }
575 else {
576 /* XXX: Validate request */
577 RawOption opt;
578 RT_ZERO(opt);
579
580 Client c(client);
581 int rc = confManager->commitLease4Client(c);
582 AssertRCReturn(rc, false);
583
584 rc = ConfigurationManager::extractRequestList(pDhcpMsg, cb, opt);
585 AssertRCReturn(rc, false);
586
587 networkManager->ack(client, pDhcpMsg->bp_xid, opt.au8RawOpt, opt.cbRawOpt);
588 }
589 }
590 else
591 {
592 networkManager->nak(client, pDhcpMsg->bp_xid);
593 }
594 return true;
595}
596
597
598/**
599 * The client is declining an offer we've made.
600 *
601 * @returns true.
602 *
603 * @param pDhcpMsg The message.
604 * @param cb The message size.
605 */
606bool VBoxNetDhcp::handleDhcpReqDecline(PCRTNETBOOTP, size_t)
607{
608 /** @todo Probably need to match the server IP here to work correctly with
609 * other servers. */
610
611 /*
612 * The client is supposed to pass us option 50, requested address,
613 * from the offer. We also match the lease state. Apparently the
614 * MAC address is not supposed to be checked here.
615 */
616
617 /** @todo this is not required in the initial implementation, do it later. */
618 debugPrint(1, true, "DECLINE is not implemented");
619 return true;
620}
621
622
623/**
624 * The client is releasing its lease - good boy.
625 *
626 * @returns true.
627 *
628 * @param pDhcpMsg The message.
629 * @param cb The message size.
630 */
631bool VBoxNetDhcp::handleDhcpReqRelease(PCRTNETBOOTP, size_t)
632{
633 /** @todo Probably need to match the server IP here to work correctly with
634 * other servers. */
635
636 /*
637 * The client may pass us option 61, client identifier, which we should
638 * use to find the lease by.
639 *
640 * We're matching MAC address and lease state as well.
641 */
642
643 /*
644 * If no client identifier or if we couldn't find a lease by using it,
645 * we will try look it up by the client IP address.
646 */
647
648
649 /*
650 * If found, release it.
651 */
652
653
654 /** @todo this is not required in the initial implementation, do it later. */
655 debugPrint(1, true, "RELEASE is not implemented");
656 return true;
657}
658
659
660/**
661 * Print debug message depending on the m_cVerbosity level.
662 *
663 * @param iMinLevel The minimum m_cVerbosity level for this message.
664 * @param fMsg Whether to dump parts for the current DHCP message.
665 * @param pszFmt The message format string.
666 * @param va Optional arguments.
667 */
668void VBoxNetDhcp::debugPrintV(int iMinLevel, bool fMsg, const char *pszFmt, va_list va) const
669{
670 if (iMinLevel <= m_cVerbosity)
671 {
672 va_list vaCopy; /* This dude is *very* special, thus the copy. */
673 va_copy(vaCopy, va);
674 RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: %s: %N\n", iMinLevel >= 2 ? "debug" : "info", pszFmt, &vaCopy);
675 va_end(vaCopy);
676
677 if ( fMsg
678 && m_cVerbosity >= 2
679 && m_pCurMsg)
680 {
681 /* XXX: export this to debugPrinfDhcpMsg or variant and other method export
682 * to base class
683 */
684 const char *pszMsg = m_uCurMsgType != UINT8_MAX ? debugDhcpName(m_uCurMsgType) : "";
685 RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: debug: %8s chaddr=%.6Rhxs ciaddr=%d.%d.%d.%d yiaddr=%d.%d.%d.%d siaddr=%d.%d.%d.%d xid=%#x\n",
686 pszMsg,
687 &m_pCurMsg->bp_chaddr,
688 m_pCurMsg->bp_ciaddr.au8[0], m_pCurMsg->bp_ciaddr.au8[1], m_pCurMsg->bp_ciaddr.au8[2], m_pCurMsg->bp_ciaddr.au8[3],
689 m_pCurMsg->bp_yiaddr.au8[0], m_pCurMsg->bp_yiaddr.au8[1], m_pCurMsg->bp_yiaddr.au8[2], m_pCurMsg->bp_yiaddr.au8[3],
690 m_pCurMsg->bp_siaddr.au8[0], m_pCurMsg->bp_siaddr.au8[1], m_pCurMsg->bp_siaddr.au8[2], m_pCurMsg->bp_siaddr.au8[3],
691 m_pCurMsg->bp_xid);
692 }
693 }
694}
695
696
697/**
698 * Gets the name of given DHCP message type.
699 *
700 * @returns Readonly name.
701 * @param uMsgType The message number.
702 */
703/* static */ const char *VBoxNetDhcp::debugDhcpName(uint8_t uMsgType)
704{
705 switch (uMsgType)
706 {
707 case 0: return "MT_00";
708 case RTNET_DHCP_MT_DISCOVER: return "DISCOVER";
709 case RTNET_DHCP_MT_OFFER: return "OFFER";
710 case RTNET_DHCP_MT_REQUEST: return "REQUEST";
711 case RTNET_DHCP_MT_DECLINE: return "DECLINE";
712 case RTNET_DHCP_MT_ACK: return "ACK";
713 case RTNET_DHCP_MT_NAC: return "NAC";
714 case RTNET_DHCP_MT_RELEASE: return "RELEASE";
715 case RTNET_DHCP_MT_INFORM: return "INFORM";
716 case 9: return "MT_09";
717 case 10: return "MT_0a";
718 case 11: return "MT_0b";
719 case 12: return "MT_0c";
720 case 13: return "MT_0d";
721 case 14: return "MT_0e";
722 case 15: return "MT_0f";
723 case 16: return "MT_10";
724 case 17: return "MT_11";
725 case 18: return "MT_12";
726 case 19: return "MT_13";
727 case UINT8_MAX: return "MT_ff";
728 default: return "UNKNOWN";
729 }
730}
731
732
733int VBoxNetDhcp::initNoMain()
734{
735 /* In Host-Only mode we don't need Main. */
736 com::Shutdown();
737
738 CmdParameterIterator it;
739
740 RTNETADDRIPV4 networkId;
741 networkId.u = m_Ipv4Address.u & m_Ipv4Netmask.u;
742 RTNETADDRIPV4 netmask = m_Ipv4Netmask;
743
744 RTNETADDRIPV4 UpperAddress;
745 RTNETADDRIPV4 LowerAddress = networkId;
746 UpperAddress.u = RT_H2N_U32(RT_N2H_U32(LowerAddress.u) | RT_N2H_U32(netmask.u));
747
748 for (it = CmdParameterll.begin(); it != CmdParameterll.end(); ++it)
749 {
750 switch(it->Key)
751 {
752 case 'l':
753 RTNetStrToIPv4Addr(it->strValue.c_str(), &LowerAddress);
754 break;
755
756 case 'u':
757 RTNetStrToIPv4Addr(it->strValue.c_str(), &UpperAddress);
758 break;
759 case 'b':
760 break;
761
762 }
763 }
764
765 ConfigurationManager *confManager = ConfigurationManager::getConfigurationManager();
766 AssertPtrReturn(confManager, VERR_INTERNAL_ERROR);
767 confManager->addNetwork(unconst(g_RootConfig),
768 networkId,
769 m_Ipv4Netmask,
770 LowerAddress,
771 UpperAddress);
772
773 return VINF_SUCCESS;
774}
775
776
777int VBoxNetDhcp::initWithMain()
778{
779 BOOL fNeedDhcpServer = false;
780 if (FAILED(m_NATNetwork->COMGETTER(NeedDhcpServer)(&fNeedDhcpServer)))
781 return VERR_INTERNAL_ERROR;
782
783 if (!fNeedDhcpServer)
784 return VERR_CANCELLED;
785
786 RTNETADDRIPV4 gateway;
787 com::Bstr strGateway;
788
789 HRESULT hrc = m_NATNetwork->COMGETTER(Gateway)(strGateway.asOutParam());
790 AssertComRCReturn(hrc, VERR_INTERNAL_ERROR);
791 RTNetStrToIPv4Addr(com::Utf8Str(strGateway).c_str(), &gateway);
792
793 ConfigurationManager *confManager = ConfigurationManager::getConfigurationManager();
794 AssertPtrReturn(confManager, VERR_INTERNAL_ERROR);
795 confManager->addToAddressList(RTNET_DHCP_OPT_ROUTERS, gateway);
796
797 unsigned int i;
798 unsigned int count_strs;
799 com::SafeArray<BSTR> strs;
800 std::map<RTNETADDRIPV4, uint32_t> MapIp4Addr2Off;
801
802 hrc = m_NATNetwork->COMGETTER(LocalMappings)(ComSafeArrayAsOutParam(strs));
803 if ( SUCCEEDED(hrc)
804 && (count_strs = strs.size()))
805 {
806 for (i = 0; i < count_strs; ++i)
807 {
808 char szAddr[17];
809 RTNETADDRIPV4 ip4addr;
810 char *pszTerm;
811 uint32_t u32Off;
812 com::Utf8Str strLo2Off(strs[i]);
813 const char *pszLo2Off = strLo2Off.c_str();
814
815 RT_ZERO(szAddr);
816
817 pszTerm = RTStrStr(pszLo2Off, "=");
818
819 if ( pszTerm
820 && (pszTerm - pszLo2Off) <= INET_ADDRSTRLEN)
821 {
822 memcpy(szAddr, pszLo2Off, (pszTerm - pszLo2Off));
823 int rc = RTNetStrToIPv4Addr(szAddr, &ip4addr);
824 if (RT_SUCCESS(rc))
825 {
826 u32Off = RTStrToUInt32(pszTerm + 1);
827 if (u32Off != 0)
828 MapIp4Addr2Off.insert(
829 std::map<RTNETADDRIPV4,uint32_t>::value_type(ip4addr, u32Off));
830 }
831 }
832 }
833 }
834
835 strs.setNull();
836 ComPtr<IHost> host;
837 if (SUCCEEDED(virtualbox->COMGETTER(Host)(host.asOutParam())))
838 {
839 if (SUCCEEDED(host->COMGETTER(NameServers)(ComSafeArrayAsOutParam(strs))))
840 {
841 RTNETADDRIPV4 addr;
842
843 confManager->flushAddressList(RTNET_DHCP_OPT_DNS);
844 int rc;
845 for (i = 0; i < strs.size(); ++i)
846 {
847 rc = RTNetStrToIPv4Addr(com::Utf8Str(strs[i]).c_str(), &addr);
848 if (RT_SUCCESS(rc))
849 {
850 if (addr.au8[0] == 127)
851 {
852 if (MapIp4Addr2Off[addr] != 0)
853 {
854 addr.u = RT_H2N_U32(RT_N2H_U32(m_Ipv4Address.u & m_Ipv4Netmask.u)
855 + MapIp4Addr2Off[addr]);
856 }
857 else
858 continue;
859 }
860
861 confManager->addToAddressList(RTNET_DHCP_OPT_DNS, addr);
862 }
863 }
864 }
865
866 strs.setNull();
867#if 0
868 if (SUCCEEDED(host->COMGETTER(SearchStrings)(ComSafeArrayAsOutParam(strs))))
869 {
870 /* XXX: todo. */;
871 }
872 strs.setNull();
873#endif
874 com::Bstr domain;
875 if (SUCCEEDED(host->COMGETTER(DomainName)(domain.asOutParam())))
876 confManager->setString(RTNET_DHCP_OPT_DOMAIN_NAME, std::string(com::Utf8Str(domain).c_str()));
877 }
878
879 com::Bstr strUpperIp, strLowerIp;
880
881 RTNETADDRIPV4 LowerAddress;
882 RTNETADDRIPV4 UpperAddress;
883
884 hrc = m_DhcpServer->COMGETTER(UpperIP)(strUpperIp.asOutParam());
885 AssertComRCReturn(hrc, VERR_INTERNAL_ERROR);
886 RTNetStrToIPv4Addr(com::Utf8Str(strUpperIp).c_str(), &UpperAddress);
887
888
889 hrc = m_DhcpServer->COMGETTER(LowerIP)(strLowerIp.asOutParam());
890 AssertComRCReturn(hrc, VERR_INTERNAL_ERROR);
891 RTNetStrToIPv4Addr(com::Utf8Str(strLowerIp).c_str(), &LowerAddress);
892
893 RTNETADDRIPV4 networkId;
894 networkId.u = m_Ipv4Address.u & m_Ipv4Netmask.u;
895 std::string name = std::string("default");
896
897 confManager->addNetwork(unconst(g_RootConfig),
898 networkId,
899 m_Ipv4Netmask,
900 LowerAddress,
901 UpperAddress);
902
903 com::Bstr bstr;
904 hrc = virtualbox->COMGETTER(HomeFolder)(bstr.asOutParam());
905 std::string strXmlLeaseFile(com::Utf8StrFmt("%ls%c%s.leases",
906 bstr.raw(), RTPATH_DELIMITER, m_Network.c_str()).c_str());
907 confManager->loadFromFile(strXmlLeaseFile);
908
909 return VINF_SUCCESS;
910}
911
912/**
913 * Entry point.
914 */
915extern "C" DECLEXPORT(int) TrustedMain(int argc, char **argv)
916{
917 /*
918 * Instantiate the DHCP server and hand it the options.
919 */
920 HRESULT hrc = com::Initialize();
921 Assert(!FAILED(hrc));
922
923 VBoxNetDhcp *pDhcp = new VBoxNetDhcp();
924 if (!pDhcp)
925 {
926 RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: new VBoxNetDhcp failed!\n");
927 return 1;
928 }
929 int rc = pDhcp->parseArgs(argc - 1, argv + 1);
930 if (rc)
931 return rc;
932
933 pDhcp->init();
934
935 /*
936 * Try connect the server to the network.
937 */
938 rc = pDhcp->tryGoOnline();
939 if (RT_FAILURE(rc))
940 {
941 delete pDhcp;
942 return 1;
943 }
944
945 /*
946 * Process requests.
947 */
948 g_pDhcp = pDhcp;
949 rc = pDhcp->run();
950 g_pDhcp = NULL;
951 delete pDhcp;
952
953 return 0;
954}
955
956
957#ifndef VBOX_WITH_HARDENING
958
959int main(int argc, char **argv)
960{
961 int rc = RTR3InitExe(argc, &argv, RTR3INIT_FLAGS_SUPLIB);
962 if (RT_FAILURE(rc))
963 return RTMsgInitFailure(rc);
964
965 return TrustedMain(argc, argv);
966}
967
968# ifdef RT_OS_WINDOWS
969
970static LRESULT CALLBACK WindowProc(HWND hwnd,
971 UINT uMsg,
972 WPARAM wParam,
973 LPARAM lParam
974)
975{
976 if(uMsg == WM_DESTROY)
977 {
978 PostQuitMessage(0);
979 return 0;
980 }
981 return DefWindowProc (hwnd, uMsg, wParam, lParam);
982}
983
984static LPCWSTR g_WndClassName = L"VBoxNetDHCPClass";
985
986static DWORD WINAPI MsgThreadProc(__in LPVOID lpParameter)
987{
988 HWND hwnd = 0;
989 HINSTANCE hInstance = (HINSTANCE)GetModuleHandle (NULL);
990 bool bExit = false;
991
992 /* Register the Window Class. */
993 WNDCLASS wc;
994 wc.style = 0;
995 wc.lpfnWndProc = WindowProc;
996 wc.cbClsExtra = 0;
997 wc.cbWndExtra = sizeof(void *);
998 wc.hInstance = hInstance;
999 wc.hIcon = NULL;
1000 wc.hCursor = NULL;
1001 wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1);
1002 wc.lpszMenuName = NULL;
1003 wc.lpszClassName = g_WndClassName;
1004
1005 ATOM atomWindowClass = RegisterClass(&wc);
1006
1007 if (atomWindowClass != 0)
1008 {
1009 /* Create the window. */
1010 hwnd = CreateWindowEx (WS_EX_TOOLWINDOW | WS_EX_TRANSPARENT | WS_EX_TOPMOST,
1011 g_WndClassName, g_WndClassName,
1012 WS_POPUPWINDOW,
1013 -200, -200, 100, 100, NULL, NULL, hInstance, NULL);
1014
1015 if (hwnd)
1016 {
1017 SetWindowPos(hwnd, HWND_TOPMOST, -200, -200, 0, 0,
1018 SWP_NOACTIVATE | SWP_HIDEWINDOW | SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_NOSIZE);
1019
1020 MSG msg;
1021 while (GetMessage(&msg, NULL, 0, 0))
1022 {
1023 TranslateMessage(&msg);
1024 DispatchMessage(&msg);
1025 }
1026
1027 DestroyWindow (hwnd);
1028
1029 bExit = true;
1030 }
1031
1032 UnregisterClass (g_WndClassName, hInstance);
1033 }
1034
1035 if(bExit)
1036 {
1037 /* no need any accuracy here, in anyway the DHCP server usually gets terminated with TerminateProcess */
1038 exit(0);
1039 }
1040
1041 return 0;
1042}
1043
1044
1045/** (We don't want a console usually.) */
1046int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
1047{
1048 NOREF(hInstance); NOREF(hPrevInstance); NOREF(lpCmdLine); NOREF(nCmdShow);
1049
1050 HANDLE hThread = CreateThread(
1051 NULL, /*__in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes, */
1052 0, /*__in SIZE_T dwStackSize, */
1053 MsgThreadProc, /*__in LPTHREAD_START_ROUTINE lpStartAddress,*/
1054 NULL, /*__in_opt LPVOID lpParameter,*/
1055 0, /*__in DWORD dwCreationFlags,*/
1056 NULL /*__out_opt LPDWORD lpThreadId*/
1057 );
1058
1059 if(hThread != NULL)
1060 CloseHandle(hThread);
1061
1062 return main(__argc, __argv);
1063}
1064# endif /* RT_OS_WINDOWS */
1065
1066#endif /* !VBOX_WITH_HARDENING */
1067
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