VirtualBox

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

Last change on this file since 67954 was 64218, checked in by vboxsync, 8 years ago

VBoxNetDhcp: Instead of complaining in the comments that operator[] is
not const, just use find().

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 26.3 KB
Line 
1/* $Id: VBoxNetDHCP.cpp 64218 2016-10-12 10:28:37Z vboxsync $ */
2/** @file
3 * VBoxNetDHCP - DHCP Service for connecting to IntNet.
4 */
5
6/*
7 * Copyright (C) 2009-2016 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.au8[0] == 127)
647 {
648 AddressToOffsetMapping::const_iterator remap(mapping.find(addr));
649
650 if (remap != mapping.end())
651 {
652 int offset = remap->second;
653 addr.u = RT_H2N_U32(RT_N2H_U32(networkid.u) + offset);
654 }
655 else
656 {
657 fUnmappedLoopback = true;
658 continue;
659 }
660 }
661
662 servers.push_back(addr);
663 }
664
665 if (servers.empty() && fUnmappedLoopback)
666 {
667 RTNETADDRIPV4 proxy;
668
669 proxy.u = networkid.u | RT_H2N_U32_C(1U);
670 servers.push_back(proxy);
671 }
672
673 return VINF_SUCCESS;
674}
675
676
677HRESULT VBoxNetDhcp::HandleEvent(VBoxEventType_T aEventType, IEvent *pEvent)
678{
679 switch (aEventType)
680 {
681 case VBoxEventType_OnHostNameResolutionConfigurationChange:
682 fetchAndUpdateDnsInfo();
683 break;
684
685 case VBoxEventType_OnNATNetworkStartStop:
686 {
687 ComPtr <INATNetworkStartStopEvent> pStartStopEvent = pEvent;
688
689 com::Bstr networkName;
690 HRESULT hrc = pStartStopEvent->COMGETTER(NetworkName)(networkName.asOutParam());
691 AssertComRCReturn(hrc, hrc);
692 if (networkName.compare(getNetworkName().c_str()))
693 break; /* change not for our network */
694
695 BOOL fStart = TRUE;
696 hrc = pStartStopEvent->COMGETTER(StartEvent)(&fStart);
697 AssertComRCReturn(hrc, hrc);
698 if (!fStart)
699 shutdown();
700 break;
701 }
702
703 case VBoxEventType_OnVBoxSVCAvailabilityChanged:
704 {
705 shutdown();
706 break;
707 }
708
709 default: break; /* Shut up MSC. */
710 }
711
712 return S_OK;
713}
714
715#ifdef RT_OS_WINDOWS
716
717/** The class name for the DIFx-killable window. */
718static WCHAR g_wszWndClassName[] = L"VBoxNetDHCPClass";
719/** Whether to exit the process on quit. */
720static bool g_fExitProcessOnQuit = true;
721
722/**
723 * Window procedure for making us DIFx-killable.
724 */
725static LRESULT CALLBACK DIFxKillableWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
726{
727 if (uMsg == WM_DESTROY)
728 {
729 PostQuitMessage(0);
730 return 0;
731 }
732 return DefWindowProc(hwnd, uMsg, wParam, lParam);
733}
734
735/** @callback_method_impl{FNRTTHREAD,
736 * Thread that creates service a window the DIFx can destroy, thereby
737 * triggering process termination. }
738 */
739static DECLCALLBACK(int) DIFxKillableProcessThreadProc(RTTHREAD hThreadSelf, void *pvUser)
740{
741 RT_NOREF(hThreadSelf, pvUser);
742 HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(NULL);
743
744 /* Register the Window Class. */
745 WNDCLASSW WndCls;
746 WndCls.style = 0;
747 WndCls.lpfnWndProc = DIFxKillableWindowProc;
748 WndCls.cbClsExtra = 0;
749 WndCls.cbWndExtra = sizeof(void *);
750 WndCls.hInstance = hInstance;
751 WndCls.hIcon = NULL;
752 WndCls.hCursor = NULL;
753 WndCls.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1);
754 WndCls.lpszMenuName = NULL;
755 WndCls.lpszClassName = g_wszWndClassName;
756
757 ATOM atomWindowClass = RegisterClassW(&WndCls);
758 if (atomWindowClass != 0)
759 {
760 /* Create the window. */
761 HWND hwnd = CreateWindowExW(WS_EX_TOOLWINDOW | WS_EX_TRANSPARENT | WS_EX_TOPMOST,
762 g_wszWndClassName, g_wszWndClassName,
763 WS_POPUPWINDOW,
764 -200, -200, 100, 100, NULL, NULL, hInstance, NULL);
765 if (hwnd)
766 {
767 SetWindowPos(hwnd, HWND_TOPMOST, -200, -200, 0, 0,
768 SWP_NOACTIVATE | SWP_HIDEWINDOW | SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_NOSIZE);
769
770 MSG msg;
771 while (GetMessage(&msg, NULL, 0, 0))
772 {
773 TranslateMessage(&msg);
774 DispatchMessage(&msg);
775 }
776
777 DestroyWindow(hwnd);
778 }
779
780 UnregisterClassW(g_wszWndClassName, hInstance);
781
782 if (hwnd && g_fExitProcessOnQuit)
783 exit(0);
784 }
785 return 0;
786}
787
788#endif /* RT_OS_WINDOWS */
789
790/**
791 * Entry point.
792 */
793extern "C" DECLEXPORT(int) TrustedMain(int argc, char **argv)
794{
795 /*
796 * Instantiate the DHCP server and hand it the options.
797 */
798 VBoxNetDhcp *pDhcp = new VBoxNetDhcp();
799 if (!pDhcp)
800 {
801 RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: new VBoxNetDhcp failed!\n");
802 return 1;
803 }
804
805 RTEXITCODE rcExit = (RTEXITCODE)pDhcp->parseArgs(argc - 1, argv + 1);
806 if (rcExit != RTEXITCODE_SUCCESS)
807 return rcExit;
808
809#ifdef RT_OS_WINDOWS
810 /* DIFx hack. */
811 RTTHREAD hMakeUseKillableThread = NIL_RTTHREAD;
812 int rc2 = RTThreadCreate(&hMakeUseKillableThread, DIFxKillableProcessThreadProc, NULL, 0,
813 RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "DIFxKill");
814 if (RT_FAILURE(rc2))
815 hMakeUseKillableThread = NIL_RTTHREAD;
816#endif
817
818 pDhcp->init();
819
820 /*
821 * Try connect the server to the network.
822 */
823 int rc = pDhcp->tryGoOnline();
824 if (RT_SUCCESS(rc))
825 {
826 /*
827 * Process requests.
828 */
829 g_pDhcp = pDhcp;
830 rc = pDhcp->run();
831 pDhcp->done();
832
833 g_pDhcp = NULL;
834 }
835 delete pDhcp;
836
837#ifdef RT_OS_WINDOWS
838 /* Kill DIFx hack. */
839 if (hMakeUseKillableThread != NIL_RTTHREAD)
840 {
841 g_fExitProcessOnQuit = false;
842 PostThreadMessage((DWORD)RTThreadGetNative(hMakeUseKillableThread), WM_QUIT, 0, 0);
843 RTThreadWait(hMakeUseKillableThread, RT_MS_1SEC * 5U, NULL);
844 }
845#endif
846
847 return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
848}
849
850
851#ifndef VBOX_WITH_HARDENING
852
853int main(int argc, char **argv)
854{
855 int rc = RTR3InitExe(argc, &argv, RTR3INIT_FLAGS_SUPLIB);
856 if (RT_FAILURE(rc))
857 return RTMsgInitFailure(rc);
858
859 return TrustedMain(argc, argv);
860}
861
862# ifdef RT_OS_WINDOWS
863
864
865
866/** (We don't want a console usually.) */
867int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
868{
869 NOREF(hInstance); NOREF(hPrevInstance); NOREF(lpCmdLine); NOREF(nCmdShow);
870 return main(__argc, __argv);
871}
872# endif /* RT_OS_WINDOWS */
873
874#endif /* !VBOX_WITH_HARDENING */
875
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