VirtualBox

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

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

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 26.6 KB
Line 
1/* $Id: VBoxNetDHCP.cpp 76553 2019-01-01 01:45:53Z vboxsync $ */
2/** @file
3 * VBoxNetDHCP - DHCP Service for connecting to IntNet.
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/** @page pg_net_dhcp VBoxNetDHCP
19 *
20 * Write a few words...
21 *
22 */
23
24
25/*********************************************************************************************************************************
26* Header Files *
27*********************************************************************************************************************************/
28#include <VBox/com/com.h>
29#include <VBox/com/listeners.h>
30#include <VBox/com/string.h>
31#include <VBox/com/Guid.h>
32#include <VBox/com/array.h>
33#include <VBox/com/ErrorInfo.h>
34#include <VBox/com/errorprint.h>
35#include <VBox/com/EventQueue.h>
36#include <VBox/com/VirtualBox.h>
37
38#include <iprt/alloca.h>
39#include <iprt/buildconfig.h>
40#include <iprt/err.h>
41#include <iprt/net.h> /* must come before getopt */
42#include <iprt/getopt.h>
43#include <iprt/initterm.h>
44#include <iprt/message.h>
45#include <iprt/param.h>
46#include <iprt/path.h>
47#include <iprt/stream.h>
48#include <iprt/time.h>
49#include <iprt/string.h>
50#ifdef RT_OS_WINDOWS
51# include <iprt/thread.h>
52#endif
53
54#include <VBox/sup.h>
55#include <VBox/intnet.h>
56#include <VBox/intnetinline.h>
57#include <VBox/vmm/vmm.h>
58#include <VBox/version.h>
59
60#include "../NetLib/VBoxNetLib.h"
61#include "../NetLib/shared_ptr.h"
62
63#include <vector>
64#include <list>
65#include <string>
66#include <map>
67
68#include "../NetLib/VBoxNetBaseService.h"
69#include "../NetLib/utils.h"
70
71#ifdef RT_OS_WINDOWS /* WinMain */
72# include <iprt/win/windows.h>
73# include <stdlib.h>
74# ifdef INET_ADDRSTRLEN
75/* On Windows INET_ADDRSTRLEN defined as 22 Ws2ipdef.h, because it include port number */
76# undef INET_ADDRSTRLEN
77# endif
78# define INET_ADDRSTRLEN 16
79#else
80# include <netinet/in.h>
81#endif
82
83
84#include "Config.h"
85
86
87/*********************************************************************************************************************************
88* Structures and Typedefs *
89*********************************************************************************************************************************/
90/**
91 * DHCP server instance.
92 */
93class VBoxNetDhcp : public VBoxNetBaseService, public NATNetworkEventAdapter
94{
95public:
96 VBoxNetDhcp();
97 virtual ~VBoxNetDhcp();
98
99 int init();
100 void done();
101 void usage(void) { /* XXX: document options */ };
102 int parseOpt(int rc, const RTGETOPTUNION& getOptVal);
103 int processFrame(void *, size_t) {return VERR_IGNORED; };
104 int processGSO(PCPDMNETWORKGSO, size_t) {return VERR_IGNORED; };
105 int processUDP(void *, size_t);
106
107protected:
108 bool handleDhcpMsg(uint8_t uMsgType, PCRTNETBOOTP pDhcpMsg, size_t cb);
109
110 void debugPrintV(int32_t iMinLevel, bool fMsg, const char *pszFmt, va_list va) const;
111 static const char *debugDhcpName(uint8_t uMsgType);
112
113private:
114 int initNoMain();
115 int initWithMain();
116 HRESULT HandleEvent(VBoxEventType_T aEventType, IEvent *pEvent);
117
118 static int hostDnsServers(const ComHostPtr& host,
119 const RTNETADDRIPV4& networkid,
120 const AddressToOffsetMapping& mapping,
121 AddressList& servers);
122 int fetchAndUpdateDnsInfo();
123
124protected:
125 /** @name The DHCP server specific configuration data members.
126 * @{ */
127 /*
128 * XXX: what was the plan? SQL3 or plain text file?
129 * How it will coexists with managment from VBoxManagement, who should manage db
130 * in that case (VBoxManage, VBoxSVC ???)
131 */
132 std::string m_LeaseDBName;
133
134 /** @} */
135
136 /* corresponding dhcp server description in Main */
137 ComPtr<IDHCPServer> m_DhcpServer;
138
139 ComPtr<INATNetwork> m_NATNetwork;
140
141 /** Listener for Host DNS changes */
142 ComNatListenerPtr m_VBoxListener;
143 ComNatListenerPtr m_VBoxClientListener;
144
145 NetworkManager *m_NetworkManager;
146
147 /*
148 * We will ignore cmd line parameters IFF there will be some DHCP specific arguments
149 * otherwise all paramters will come from Main.
150 */
151 bool m_fIgnoreCmdLineParameters;
152
153 /*
154 * -b -n 10.0.1.2 -m 255.255.255.0 -> to the list processing in
155 */
156 typedef struct
157 {
158 char Key;
159 std::string strValue;
160 } CMDLNPRM;
161 std::list<CMDLNPRM> CmdParameterll;
162 typedef std::list<CMDLNPRM>::iterator CmdParameterIterator;
163
164 /** @name Debug stuff
165 * @{ */
166 int32_t m_cVerbosity;
167 uint8_t m_uCurMsgType;
168 size_t m_cbCurMsg;
169 PCRTNETBOOTP m_pCurMsg;
170 VBOXNETUDPHDRS m_CurHdrs;
171 /** @} */
172};
173
174
175static inline int configGetBoundryAddress(const ComDhcpServerPtr& dhcp, bool fUpperBoundry, RTNETADDRIPV4& boundryAddress)
176{
177 boundryAddress.u = INADDR_ANY;
178
179 HRESULT hrc;
180 com::Bstr strAddress;
181 if (fUpperBoundry)
182 hrc = dhcp->COMGETTER(UpperIP)(strAddress.asOutParam());
183 else
184 hrc = dhcp->COMGETTER(LowerIP)(strAddress.asOutParam());
185 AssertComRCReturn(hrc, VERR_INTERNAL_ERROR);
186
187 return RTNetStrToIPv4Addr(com::Utf8Str(strAddress).c_str(), &boundryAddress);
188}
189
190
191/*********************************************************************************************************************************
192* Global Variables *
193*********************************************************************************************************************************/
194/** Pointer to the DHCP server. */
195static VBoxNetDhcp *g_pDhcp;
196
197/* DHCP server specific options */
198static RTGETOPTDEF g_aOptionDefs[] =
199{
200 { "--lease-db", 'D', RTGETOPT_REQ_STRING },
201 { "--begin-config", 'b', RTGETOPT_REQ_NOTHING },
202 { "--gateway", 'g', RTGETOPT_REQ_IPV4ADDR },
203 { "--lower-ip", 'l', RTGETOPT_REQ_IPV4ADDR },
204 { "--upper-ip", 'u', RTGETOPT_REQ_IPV4ADDR },
205};
206
207/**
208 * Construct a DHCP server with a default configuration.
209 */
210VBoxNetDhcp::VBoxNetDhcp()
211 : VBoxNetBaseService("VBoxNetDhcp", "VBoxNetDhcp"),
212 m_NetworkManager(NULL)
213{
214 /* m_enmTrunkType = kIntNetTrunkType_WhateverNone; */
215 RTMAC mac;
216 mac.au8[0] = 0x08;
217 mac.au8[1] = 0x00;
218 mac.au8[2] = 0x27;
219 mac.au8[3] = 0x40;
220 mac.au8[4] = 0x41;
221 mac.au8[5] = 0x42;
222 setMacAddress(mac);
223
224 RTNETADDRIPV4 address;
225 address.u = RT_H2N_U32_C(RT_BSWAP_U32_C(RT_MAKE_U32_FROM_U8( 10, 0, 2, 5)));
226 setIpv4Address(address);
227
228 setSendBufSize(8 * _1K);
229 setRecvBufSize(50 * _1K);
230
231 m_uCurMsgType = UINT8_MAX;
232 m_cbCurMsg = 0;
233 m_pCurMsg = NULL;
234 RT_ZERO(m_CurHdrs);
235
236 m_fIgnoreCmdLineParameters = true;
237
238 for(unsigned int i = 0; i < RT_ELEMENTS(g_aOptionDefs); ++i)
239 addCommandLineOption(&g_aOptionDefs[i]);
240}
241
242
243/**
244 * Destruct a DHCP server.
245 */
246VBoxNetDhcp::~VBoxNetDhcp()
247{
248}
249
250
251
252
253/**
254 * Parse the DHCP specific arguments.
255 *
256 * This callback caled for each paramenter so
257 * ....
258 * we nee post analisys of the parameters, at least
259 * for -b, -g, -l, -u, -m
260 */
261int VBoxNetDhcp::parseOpt(int rc, const RTGETOPTUNION& Val)
262{
263 CMDLNPRM prm;
264
265 /* Ok, we've entered here, thus we can't ignore cmd line parameters anymore */
266 m_fIgnoreCmdLineParameters = false;
267
268 prm.Key = rc;
269
270 switch (rc)
271 {
272 case 'l':
273 case 'u':
274 case 'g':
275 {
276 char buf[17];
277 RTStrPrintf(buf, 17, "%RTnaipv4", Val.IPv4Addr.u);
278 prm.strValue = buf;
279 CmdParameterll.push_back(prm);
280 }
281 break;
282
283 case 'b': // ignore
284 case 'D': // ignore
285 break;
286
287 default:
288 rc = RTGetOptPrintError(rc, &Val);
289 RTPrintf("Use --help for more information.\n");
290 return rc;
291 }
292
293 return VINF_SUCCESS;
294}
295
296int VBoxNetDhcp::init()
297{
298 int rc = this->VBoxNetBaseService::init();
299 AssertRCReturn(rc, rc);
300
301 if (isMainNeeded())
302 rc = initWithMain();
303 else
304 rc = initNoMain();
305 AssertRCReturn(rc, rc);
306
307 m_NetworkManager = NetworkManager::getNetworkManager(m_DhcpServer);
308 AssertPtrReturn(m_NetworkManager, VERR_INTERNAL_ERROR);
309
310 m_NetworkManager->setOurAddress(getIpv4Address());
311 m_NetworkManager->setOurNetmask(getIpv4Netmask());
312 m_NetworkManager->setOurMac(getMacAddress());
313 m_NetworkManager->setService(this);
314
315 return VINF_SUCCESS;
316}
317
318void VBoxNetDhcp::done()
319{
320 destroyNatListener(m_VBoxListener, virtualbox);
321 destroyClientListener(m_VBoxClientListener, virtualboxClient);
322}
323
324int VBoxNetDhcp::processUDP(void *pv, size_t cbPv)
325{
326 PCRTNETBOOTP pDhcpMsg = (PCRTNETBOOTP)pv;
327 m_pCurMsg = pDhcpMsg;
328 m_cbCurMsg = cbPv;
329
330 uint8_t uMsgType;
331 if (RTNetIPv4IsDHCPValid(NULL /* why is this here? */, pDhcpMsg, cbPv, &uMsgType))
332 {
333 m_uCurMsgType = uMsgType;
334 {
335 /* To avoid fight with event processing thread */
336 VBoxNetALock(this);
337 handleDhcpMsg(uMsgType, pDhcpMsg, cbPv);
338 }
339 m_uCurMsgType = UINT8_MAX;
340 }
341 else
342 debugPrint(1, true, "VBoxNetDHCP: Skipping invalid DHCP packet.\n"); /** @todo handle pure bootp clients too? */
343
344 m_pCurMsg = NULL;
345 m_cbCurMsg = 0;
346
347 return VINF_SUCCESS;
348}
349
350
351/**
352 * Handles a DHCP message.
353 *
354 * @returns true if handled, false if not. (IGNORED BY CALLER)
355 * @param uMsgType The message type.
356 * @param pDhcpMsg The DHCP message.
357 * @param cb The size of the DHCP message.
358 */
359bool VBoxNetDhcp::handleDhcpMsg(uint8_t uMsgType, PCRTNETBOOTP pDhcpMsg, size_t cb)
360{
361 if (pDhcpMsg->bp_op == RTNETBOOTP_OP_REQUEST)
362 {
363 AssertPtrReturn(m_NetworkManager, false);
364
365 switch (uMsgType)
366 {
367 case RTNET_DHCP_MT_DISCOVER:
368 return m_NetworkManager->handleDhcpReqDiscover(pDhcpMsg, cb);
369
370 case RTNET_DHCP_MT_REQUEST:
371 return m_NetworkManager->handleDhcpReqRequest(pDhcpMsg, cb);
372
373 case RTNET_DHCP_MT_DECLINE:
374 return m_NetworkManager->handleDhcpReqDecline(pDhcpMsg, cb);
375
376 case RTNET_DHCP_MT_RELEASE:
377 return m_NetworkManager->handleDhcpReqRelease(pDhcpMsg, cb);
378
379 case RTNET_DHCP_MT_INFORM:
380 debugPrint(0, true, "Should we handle this?");
381 break;
382
383 default:
384 debugPrint(0, true, "Unexpected.");
385 break;
386 }
387 }
388 return false;
389}
390
391/**
392 * Print debug message depending on the m_cVerbosity level.
393 *
394 * @param iMinLevel The minimum m_cVerbosity level for this message.
395 * @param fMsg Whether to dump parts for the current DHCP message.
396 * @param pszFmt The message format string.
397 * @param va Optional arguments.
398 */
399void VBoxNetDhcp::debugPrintV(int iMinLevel, bool fMsg, const char *pszFmt, va_list va) const
400{
401 if (iMinLevel <= m_cVerbosity)
402 {
403 va_list vaCopy; /* This dude is *very* special, thus the copy. */
404 va_copy(vaCopy, va);
405 RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: %s: %N\n", iMinLevel >= 2 ? "debug" : "info", pszFmt, &vaCopy);
406 va_end(vaCopy);
407
408 if ( fMsg
409 && m_cVerbosity >= 2
410 && m_pCurMsg)
411 {
412 /* XXX: export this to debugPrinfDhcpMsg or variant and other method export
413 * to base class
414 */
415 const char *pszMsg = m_uCurMsgType != UINT8_MAX ? debugDhcpName(m_uCurMsgType) : "";
416 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",
417 pszMsg,
418 &m_pCurMsg->bp_chaddr,
419 m_pCurMsg->bp_ciaddr.au8[0], m_pCurMsg->bp_ciaddr.au8[1], m_pCurMsg->bp_ciaddr.au8[2], m_pCurMsg->bp_ciaddr.au8[3],
420 m_pCurMsg->bp_yiaddr.au8[0], m_pCurMsg->bp_yiaddr.au8[1], m_pCurMsg->bp_yiaddr.au8[2], m_pCurMsg->bp_yiaddr.au8[3],
421 m_pCurMsg->bp_siaddr.au8[0], m_pCurMsg->bp_siaddr.au8[1], m_pCurMsg->bp_siaddr.au8[2], m_pCurMsg->bp_siaddr.au8[3],
422 m_pCurMsg->bp_xid);
423 }
424 }
425}
426
427
428/**
429 * Gets the name of given DHCP message type.
430 *
431 * @returns Readonly name.
432 * @param uMsgType The message number.
433 */
434/* static */ const char *VBoxNetDhcp::debugDhcpName(uint8_t uMsgType)
435{
436 switch (uMsgType)
437 {
438 case 0: return "MT_00";
439 case RTNET_DHCP_MT_DISCOVER: return "DISCOVER";
440 case RTNET_DHCP_MT_OFFER: return "OFFER";
441 case RTNET_DHCP_MT_REQUEST: return "REQUEST";
442 case RTNET_DHCP_MT_DECLINE: return "DECLINE";
443 case RTNET_DHCP_MT_ACK: return "ACK";
444 case RTNET_DHCP_MT_NAC: return "NAC";
445 case RTNET_DHCP_MT_RELEASE: return "RELEASE";
446 case RTNET_DHCP_MT_INFORM: return "INFORM";
447 case 9: return "MT_09";
448 case 10: return "MT_0a";
449 case 11: return "MT_0b";
450 case 12: return "MT_0c";
451 case 13: return "MT_0d";
452 case 14: return "MT_0e";
453 case 15: return "MT_0f";
454 case 16: return "MT_10";
455 case 17: return "MT_11";
456 case 18: return "MT_12";
457 case 19: return "MT_13";
458 case UINT8_MAX: return "MT_ff";
459 default: return "UNKNOWN";
460 }
461}
462
463
464int VBoxNetDhcp::initNoMain()
465{
466 CmdParameterIterator it;
467
468 RTNETADDRIPV4 address = getIpv4Address();
469 RTNETADDRIPV4 netmask = getIpv4Netmask();
470 RTNETADDRIPV4 networkId;
471 networkId.u = address.u & netmask.u;
472
473 RTNETADDRIPV4 UpperAddress;
474 RTNETADDRIPV4 LowerAddress = networkId;
475 UpperAddress.u = RT_H2N_U32(RT_N2H_U32(LowerAddress.u) | RT_N2H_U32(netmask.u));
476
477 for (it = CmdParameterll.begin(); it != CmdParameterll.end(); ++it)
478 {
479 switch(it->Key)
480 {
481 case 'l':
482 RTNetStrToIPv4Addr(it->strValue.c_str(), &LowerAddress);
483 break;
484
485 case 'u':
486 RTNetStrToIPv4Addr(it->strValue.c_str(), &UpperAddress);
487 break;
488 case 'b':
489 break;
490
491 }
492 }
493
494 ConfigurationManager *confManager = ConfigurationManager::getConfigurationManager();
495 AssertPtrReturn(confManager, VERR_INTERNAL_ERROR);
496 confManager->addNetwork(unconst(g_RootConfig),
497 networkId,
498 netmask,
499 LowerAddress,
500 UpperAddress);
501
502 return VINF_SUCCESS;
503}
504
505
506int VBoxNetDhcp::initWithMain()
507{
508 /* ok, here we should initiate instance of dhcp server
509 * and listener for Dhcp configuration events
510 */
511 AssertRCReturn(virtualbox.isNull(), VERR_INTERNAL_ERROR);
512 std::string networkName = getNetworkName();
513
514 int rc = findDhcpServer(virtualbox, networkName, m_DhcpServer);
515 AssertRCReturn(rc, rc);
516
517 rc = findNatNetwork(virtualbox, networkName, m_NATNetwork);
518 AssertRCReturn(rc, rc);
519
520 BOOL fNeedDhcpServer = isDhcpRequired(m_NATNetwork);
521 if (!fNeedDhcpServer)
522 return VERR_CANCELLED;
523
524 RTNETADDRIPV4 gateway;
525 com::Bstr strGateway;
526 HRESULT hrc = m_NATNetwork->COMGETTER(Gateway)(strGateway.asOutParam());
527 AssertComRCReturn(hrc, VERR_INTERNAL_ERROR);
528 RTNetStrToIPv4Addr(com::Utf8Str(strGateway).c_str(), &gateway);
529
530 ConfigurationManager *confManager = ConfigurationManager::getConfigurationManager();
531 AssertPtrReturn(confManager, VERR_INTERNAL_ERROR);
532 confManager->addToAddressList(RTNET_DHCP_OPT_ROUTERS, gateway);
533
534 rc = fetchAndUpdateDnsInfo();
535 AssertMsgRCReturn(rc, ("Wasn't able to fetch Dns info"), rc);
536
537 {
538 ComEventTypeArray eventTypes;
539 eventTypes.push_back(VBoxEventType_OnHostNameResolutionConfigurationChange);
540 eventTypes.push_back(VBoxEventType_OnNATNetworkStartStop);
541 rc = createNatListener(m_VBoxListener, virtualbox, this, eventTypes);
542 AssertRCReturn(rc, rc);
543 }
544
545 {
546 ComEventTypeArray eventTypes;
547 eventTypes.push_back(VBoxEventType_OnVBoxSVCAvailabilityChanged);
548 rc = createClientListener(m_VBoxClientListener, virtualboxClient, this, eventTypes);
549 AssertRCReturn(rc, rc);
550 }
551
552 RTNETADDRIPV4 LowerAddress;
553 rc = configGetBoundryAddress(m_DhcpServer, false, LowerAddress);
554 AssertMsgRCReturn(rc, ("can't get lower boundrary adderss'"),rc);
555
556 RTNETADDRIPV4 UpperAddress;
557 rc = configGetBoundryAddress(m_DhcpServer, true, UpperAddress);
558 AssertMsgRCReturn(rc, ("can't get upper boundrary adderss'"),rc);
559
560 RTNETADDRIPV4 address = getIpv4Address();
561 RTNETADDRIPV4 netmask = getIpv4Netmask();
562 RTNETADDRIPV4 networkId = networkid(address, netmask);
563 std::string name = std::string("default");
564
565 confManager->addNetwork(unconst(g_RootConfig),
566 networkId,
567 netmask,
568 LowerAddress,
569 UpperAddress);
570
571 com::Bstr bstr;
572 hrc = virtualbox->COMGETTER(HomeFolder)(bstr.asOutParam());
573 com::Utf8StrFmt strXmlLeaseFile("%ls%c%s.leases",
574 bstr.raw(), RTPATH_DELIMITER, networkName.c_str());
575 confManager->loadFromFile(strXmlLeaseFile);
576
577 return VINF_SUCCESS;
578}
579
580
581int VBoxNetDhcp::fetchAndUpdateDnsInfo()
582{
583 ComHostPtr host;
584 if (SUCCEEDED(virtualbox->COMGETTER(Host)(host.asOutParam())))
585 {
586 AddressToOffsetMapping mapIp4Addr2Off;
587 int rc = localMappings(m_NATNetwork, mapIp4Addr2Off);
588 /* XXX: here could be several cases: 1. COM error, 2. not found (empty) 3. ? */
589 AssertMsgRCReturn(rc, ("Can't fetch local mappings"), rc);
590
591 RTNETADDRIPV4 address = getIpv4Address();
592 RTNETADDRIPV4 netmask = getIpv4Netmask();
593
594 AddressList nameservers;
595 rc = hostDnsServers(host, networkid(address, netmask), mapIp4Addr2Off, nameservers);
596 AssertMsgRCReturn(rc, ("Debug me!!!"), rc);
597 /* XXX: Search strings */
598
599 std::string domain;
600 rc = hostDnsDomain(host, domain);
601 AssertMsgRCReturn(rc, ("Debug me!!"), rc);
602
603 {
604 VBoxNetALock(this);
605 ConfigurationManager *confManager = ConfigurationManager::getConfigurationManager();
606 confManager->flushAddressList(RTNET_DHCP_OPT_DNS);
607
608 for (AddressList::iterator it = nameservers.begin(); it != nameservers.end(); ++it)
609 confManager->addToAddressList(RTNET_DHCP_OPT_DNS, *it);
610
611 confManager->setString(RTNET_DHCP_OPT_DOMAIN_NAME, domain);
612 }
613 }
614
615 return VINF_SUCCESS;
616}
617
618
619int VBoxNetDhcp::hostDnsServers(const ComHostPtr& host,
620 const RTNETADDRIPV4& networkid,
621 const AddressToOffsetMapping& mapping,
622 AddressList& servers)
623{
624 ComBstrArray strs;
625
626 HRESULT hrc = host->COMGETTER(NameServers)(ComSafeArrayAsOutParam(strs));
627 if (FAILED(hrc))
628 return VERR_NOT_FOUND;
629
630 /*
631 * Recent fashion is to run dnsmasq on 127.0.1.1 which we
632 * currently can't map. If that's the only nameserver we've got,
633 * we need to use DNS proxy for VMs to reach it.
634 */
635 bool fUnmappedLoopback = false;
636
637 for (size_t i = 0; i < strs.size(); ++i)
638 {
639 RTNETADDRIPV4 addr;
640 int rc;
641
642 rc = RTNetStrToIPv4Addr(com::Utf8Str(strs[i]).c_str(), &addr);
643 if (RT_FAILURE(rc))
644 continue;
645
646 if (addr.u == INADDR_ANY)
647 {
648 /*
649 * This doesn't seem to be very well documented except for
650 * RTFS of res_init.c, but INADDR_ANY is a valid value for
651 * for "nameserver".
652 */
653 addr.u = RT_H2N_U32_C(INADDR_LOOPBACK);
654 }
655
656 if (addr.au8[0] == 127)
657 {
658 AddressToOffsetMapping::const_iterator remap(mapping.find(addr));
659
660 if (remap != mapping.end())
661 {
662 int offset = remap->second;
663 addr.u = RT_H2N_U32(RT_N2H_U32(networkid.u) + offset);
664 }
665 else
666 {
667 fUnmappedLoopback = true;
668 continue;
669 }
670 }
671
672 servers.push_back(addr);
673 }
674
675 if (servers.empty() && fUnmappedLoopback)
676 {
677 RTNETADDRIPV4 proxy;
678
679 proxy.u = networkid.u | RT_H2N_U32_C(1U);
680 servers.push_back(proxy);
681 }
682
683 return VINF_SUCCESS;
684}
685
686
687HRESULT VBoxNetDhcp::HandleEvent(VBoxEventType_T aEventType, IEvent *pEvent)
688{
689 switch (aEventType)
690 {
691 case VBoxEventType_OnHostNameResolutionConfigurationChange:
692 fetchAndUpdateDnsInfo();
693 break;
694
695 case VBoxEventType_OnNATNetworkStartStop:
696 {
697 ComPtr <INATNetworkStartStopEvent> pStartStopEvent = pEvent;
698
699 com::Bstr networkName;
700 HRESULT hrc = pStartStopEvent->COMGETTER(NetworkName)(networkName.asOutParam());
701 AssertComRCReturn(hrc, hrc);
702 if (networkName.compare(getNetworkName().c_str()))
703 break; /* change not for our network */
704
705 BOOL fStart = TRUE;
706 hrc = pStartStopEvent->COMGETTER(StartEvent)(&fStart);
707 AssertComRCReturn(hrc, hrc);
708 if (!fStart)
709 shutdown();
710 break;
711 }
712
713 case VBoxEventType_OnVBoxSVCAvailabilityChanged:
714 {
715 shutdown();
716 break;
717 }
718
719 default: break; /* Shut up MSC. */
720 }
721
722 return S_OK;
723}
724
725#ifdef RT_OS_WINDOWS
726
727/** The class name for the DIFx-killable window. */
728static WCHAR g_wszWndClassName[] = L"VBoxNetDHCPClass";
729/** Whether to exit the process on quit. */
730static bool g_fExitProcessOnQuit = true;
731
732/**
733 * Window procedure for making us DIFx-killable.
734 */
735static LRESULT CALLBACK DIFxKillableWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
736{
737 if (uMsg == WM_DESTROY)
738 {
739 PostQuitMessage(0);
740 return 0;
741 }
742 return DefWindowProc(hwnd, uMsg, wParam, lParam);
743}
744
745/** @callback_method_impl{FNRTTHREAD,
746 * Thread that creates service a window the DIFx can destroy, thereby
747 * triggering process termination. }
748 */
749static DECLCALLBACK(int) DIFxKillableProcessThreadProc(RTTHREAD hThreadSelf, void *pvUser)
750{
751 RT_NOREF(hThreadSelf, pvUser);
752 HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(NULL);
753
754 /* Register the Window Class. */
755 WNDCLASSW WndCls;
756 WndCls.style = 0;
757 WndCls.lpfnWndProc = DIFxKillableWindowProc;
758 WndCls.cbClsExtra = 0;
759 WndCls.cbWndExtra = sizeof(void *);
760 WndCls.hInstance = hInstance;
761 WndCls.hIcon = NULL;
762 WndCls.hCursor = NULL;
763 WndCls.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1);
764 WndCls.lpszMenuName = NULL;
765 WndCls.lpszClassName = g_wszWndClassName;
766
767 ATOM atomWindowClass = RegisterClassW(&WndCls);
768 if (atomWindowClass != 0)
769 {
770 /* Create the window. */
771 HWND hwnd = CreateWindowExW(WS_EX_TOOLWINDOW | WS_EX_TRANSPARENT | WS_EX_TOPMOST,
772 g_wszWndClassName, g_wszWndClassName,
773 WS_POPUPWINDOW,
774 -200, -200, 100, 100, NULL, NULL, hInstance, NULL);
775 if (hwnd)
776 {
777 SetWindowPos(hwnd, HWND_TOPMOST, -200, -200, 0, 0,
778 SWP_NOACTIVATE | SWP_HIDEWINDOW | SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_NOSIZE);
779
780 MSG msg;
781 while (GetMessage(&msg, NULL, 0, 0))
782 {
783 TranslateMessage(&msg);
784 DispatchMessage(&msg);
785 }
786
787 DestroyWindow(hwnd);
788 }
789
790 UnregisterClassW(g_wszWndClassName, hInstance);
791
792 if (hwnd && g_fExitProcessOnQuit)
793 exit(0);
794 }
795 return 0;
796}
797
798#endif /* RT_OS_WINDOWS */
799
800/**
801 * Entry point.
802 */
803extern "C" DECLEXPORT(int) TrustedMain(int argc, char **argv)
804{
805 /*
806 * Instantiate the DHCP server and hand it the options.
807 */
808 VBoxNetDhcp *pDhcp = new VBoxNetDhcp();
809 if (!pDhcp)
810 {
811 RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: new VBoxNetDhcp failed!\n");
812 return 1;
813 }
814
815 RTEXITCODE rcExit = (RTEXITCODE)pDhcp->parseArgs(argc - 1, argv + 1);
816 if (rcExit != RTEXITCODE_SUCCESS)
817 return rcExit;
818
819#ifdef RT_OS_WINDOWS
820 /* DIFx hack. */
821 RTTHREAD hMakeUseKillableThread = NIL_RTTHREAD;
822 int rc2 = RTThreadCreate(&hMakeUseKillableThread, DIFxKillableProcessThreadProc, NULL, 0,
823 RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "DIFxKill");
824 if (RT_FAILURE(rc2))
825 hMakeUseKillableThread = NIL_RTTHREAD;
826#endif
827
828 pDhcp->init();
829
830 /*
831 * Try connect the server to the network.
832 */
833 int rc = pDhcp->tryGoOnline();
834 if (RT_SUCCESS(rc))
835 {
836 /*
837 * Process requests.
838 */
839 g_pDhcp = pDhcp;
840 rc = pDhcp->run();
841 pDhcp->done();
842
843 g_pDhcp = NULL;
844 }
845 delete pDhcp;
846
847#ifdef RT_OS_WINDOWS
848 /* Kill DIFx hack. */
849 if (hMakeUseKillableThread != NIL_RTTHREAD)
850 {
851 g_fExitProcessOnQuit = false;
852 PostThreadMessage((DWORD)RTThreadGetNative(hMakeUseKillableThread), WM_QUIT, 0, 0);
853 RTThreadWait(hMakeUseKillableThread, RT_MS_1SEC * 5U, NULL);
854 }
855#endif
856
857 return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
858}
859
860
861#ifndef VBOX_WITH_HARDENING
862
863int main(int argc, char **argv)
864{
865 int rc = RTR3InitExe(argc, &argv, RTR3INIT_FLAGS_SUPLIB);
866 if (RT_FAILURE(rc))
867 return RTMsgInitFailure(rc);
868
869 return TrustedMain(argc, argv);
870}
871
872# ifdef RT_OS_WINDOWS
873
874
875
876/** (We don't want a console usually.) */
877int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
878{
879 NOREF(hInstance); NOREF(hPrevInstance); NOREF(lpCmdLine); NOREF(nCmdShow);
880 return main(__argc, __argv);
881}
882# endif /* RT_OS_WINDOWS */
883
884#endif /* !VBOX_WITH_HARDENING */
885
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