VirtualBox

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

Last change on this file since 47208 was 47111, checked in by vboxsync, 12 years ago

VBoxNetDHCP: fix

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