VirtualBox

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

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

VBoxNetDHCP: removes session handling. binding and lease expiration control was added.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 30.1 KB
Line 
1/* $Id: VBoxNetDHCP.cpp 47501 2013-08-01 06:24:41Z 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#if 0
621 HRESULT hrc;
622 com::SafeArray<BSTR> sf;
623 hrc = m_DhcpServer->GetMacOptions(com::BstrFmt("%02X%02X%02X%02X%02X%02X",
624 pDhcpMsg->bp_chaddr.Mac.au8[0],
625 pDhcpMsg->bp_chaddr.Mac.au8[1],
626 pDhcpMsg->bp_chaddr.Mac.au8[2],
627 pDhcpMsg->bp_chaddr.Mac.au8[3],
628 pDhcpMsg->bp_chaddr.Mac.au8[4],
629 pDhcpMsg->bp_chaddr.Mac.au8[5]).raw(),
630 ComSafeArrayAsOutParam(sf));
631 if (SUCCEEDED(hrc))
632 {
633 /* XXX: per-host configuration */
634 }
635#endif
636 RawOption opt;
637 memset(&opt, 0, sizeof(RawOption));
638 /* 1. Find client */
639 ConfigurationManager *confManager = ConfigurationManager::getConfigurationManager();
640 Client *client = confManager->getClientByDhcpPacket(pDhcpMsg, cb);
641
642 /* 2. Find/Bind lease for client */
643 Lease *lease = confManager->allocateLease4Client(client, pDhcpMsg, cb);
644 AssertPtrReturn(lease, VINF_SUCCESS);
645
646 int rc = ConfigurationManager::extractRequestList(pDhcpMsg, cb, opt);
647
648 /* 3. Send of offer */
649 NetworkManager *networkManager = NetworkManager::getNetworkManager();
650
651 lease->fBinding = true;
652 lease->u64TimestampBindingStarted = RTTimeMilliTS();
653 lease->u32BindExpirationPeriod = 300; /* 3 min. */
654 networkManager->offer4Client(client, pDhcpMsg->bp_xid, opt.au8RawOpt, opt.cbRawOpt);
655 } /* end of if(!m_DhcpServer.isNull()) */
656
657 return VINF_SUCCESS;
658}
659
660
661/**
662 * The client is requesting an offer.
663 *
664 * @returns true.
665 *
666 * @param pDhcpMsg The message.
667 * @param cb The message size.
668 */
669bool VBoxNetDhcp::handleDhcpReqRequest(PCRTNETBOOTP pDhcpMsg, size_t cb)
670{
671 ConfigurationManager *confManager = ConfigurationManager::getConfigurationManager();
672 NetworkManager *networkManager = NetworkManager::getNetworkManager();
673
674 /* 1. find client */
675 Client *client = confManager->getClientByDhcpPacket(pDhcpMsg, cb);
676
677 /* 2. find bound lease */
678 if (client->m_lease)
679 {
680
681 if (client->m_lease->isExpired())
682 {
683 /* send client to INIT state */
684 networkManager->nak(client, pDhcpMsg->bp_xid);
685 confManager->expireLease4Client(client);
686 return true;
687 }
688 /* XXX: Validate request */
689 RawOption opt;
690 memset((void *)&opt, 0, sizeof(RawOption));
691
692 int rc = confManager->commitLease4Client(client);
693 AssertRCReturn(rc, false);
694
695 rc = ConfigurationManager::extractRequestList(pDhcpMsg, cb, opt);
696 AssertRCReturn(rc, false);
697
698 networkManager->ack(client, pDhcpMsg->bp_xid, opt.au8RawOpt, opt.cbRawOpt);
699 }
700 else
701 {
702 networkManager->nak(client, pDhcpMsg->bp_xid);
703 }
704 return true;
705}
706
707
708/**
709 * The client is declining an offer we've made.
710 *
711 * @returns true.
712 *
713 * @param pDhcpMsg The message.
714 * @param cb The message size.
715 */
716bool VBoxNetDhcp::handleDhcpReqDecline(PCRTNETBOOTP pDhcpMsg, size_t cb)
717{
718 /** @todo Probably need to match the server IP here to work correctly with
719 * other servers. */
720
721 /*
722 * The client is supposed to pass us option 50, requested address,
723 * from the offer. We also match the lease state. Apparently the
724 * MAC address is not supposed to be checked here.
725 */
726
727 /** @todo this is not required in the initial implementation, do it later. */
728 debugPrint(1, true, "DECLINE is not implemented");
729 return true;
730}
731
732
733/**
734 * The client is releasing its lease - good boy.
735 *
736 * @returns true.
737 *
738 * @param pDhcpMsg The message.
739 * @param cb The message size.
740 */
741bool VBoxNetDhcp::handleDhcpReqRelease(PCRTNETBOOTP pDhcpMsg, size_t cb)
742{
743 /** @todo Probably need to match the server IP here to work correctly with
744 * other servers. */
745
746 /*
747 * The client may pass us option 61, client identifier, which we should
748 * use to find the lease by.
749 *
750 * We're matching MAC address and lease state as well.
751 */
752
753 /*
754 * If no client identifier or if we couldn't find a lease by using it,
755 * we will try look it up by the client IP address.
756 */
757
758
759 /*
760 * If found, release it.
761 */
762
763
764 /** @todo this is not required in the initial implementation, do it later. */
765 debugPrint(1, true, "RELEASE is not implemented");
766 return true;
767}
768
769
770/**
771 * Print debug message depending on the m_cVerbosity level.
772 *
773 * @param iMinLevel The minimum m_cVerbosity level for this message.
774 * @param fMsg Whether to dump parts for the current DHCP message.
775 * @param pszFmt The message format string.
776 * @param va Optional arguments.
777 */
778void VBoxNetDhcp::debugPrintV(int iMinLevel, bool fMsg, const char *pszFmt, va_list va) const
779{
780 if (iMinLevel <= m_cVerbosity)
781 {
782 va_list vaCopy; /* This dude is *very* special, thus the copy. */
783 va_copy(vaCopy, va);
784 RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: %s: %N\n", iMinLevel >= 2 ? "debug" : "info", pszFmt, &vaCopy);
785 va_end(vaCopy);
786
787 if ( fMsg
788 && m_cVerbosity >= 2
789 && m_pCurMsg)
790 {
791 /* XXX: export this to debugPrinfDhcpMsg or variant and other method export
792 * to base class
793 */
794 const char *pszMsg = m_uCurMsgType != UINT8_MAX ? debugDhcpName(m_uCurMsgType) : "";
795 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",
796 pszMsg,
797 &m_pCurMsg->bp_chaddr,
798 m_pCurMsg->bp_ciaddr.au8[0], m_pCurMsg->bp_ciaddr.au8[1], m_pCurMsg->bp_ciaddr.au8[2], m_pCurMsg->bp_ciaddr.au8[3],
799 m_pCurMsg->bp_yiaddr.au8[0], m_pCurMsg->bp_yiaddr.au8[1], m_pCurMsg->bp_yiaddr.au8[2], m_pCurMsg->bp_yiaddr.au8[3],
800 m_pCurMsg->bp_siaddr.au8[0], m_pCurMsg->bp_siaddr.au8[1], m_pCurMsg->bp_siaddr.au8[2], m_pCurMsg->bp_siaddr.au8[3],
801 m_pCurMsg->bp_xid);
802 }
803 }
804}
805
806
807/**
808 * Gets the name of given DHCP message type.
809 *
810 * @returns Readonly name.
811 * @param uMsgType The message number.
812 */
813/* static */ const char *VBoxNetDhcp::debugDhcpName(uint8_t uMsgType)
814{
815 switch (uMsgType)
816 {
817 case 0: return "MT_00";
818 case RTNET_DHCP_MT_DISCOVER: return "DISCOVER";
819 case RTNET_DHCP_MT_OFFER: return "OFFER";
820 case RTNET_DHCP_MT_REQUEST: return "REQUEST";
821 case RTNET_DHCP_MT_DECLINE: return "DECLINE";
822 case RTNET_DHCP_MT_ACK: return "ACK";
823 case RTNET_DHCP_MT_NAC: return "NAC";
824 case RTNET_DHCP_MT_RELEASE: return "RELEASE";
825 case RTNET_DHCP_MT_INFORM: return "INFORM";
826 case 9: return "MT_09";
827 case 10: return "MT_0a";
828 case 11: return "MT_0b";
829 case 12: return "MT_0c";
830 case 13: return "MT_0d";
831 case 14: return "MT_0e";
832 case 15: return "MT_0f";
833 case 16: return "MT_10";
834 case 17: return "MT_11";
835 case 18: return "MT_12";
836 case 19: return "MT_13";
837 case UINT8_MAX: return "MT_ff";
838 default: return "UNKNOWN";
839 }
840}
841
842
843
844/**
845 * Entry point.
846 */
847extern "C" DECLEXPORT(int) TrustedMain(int argc, char **argv, char **envp)
848{
849 /*
850 * Instantiate the DHCP server and hand it the options.
851 */
852 HRESULT hrc = com::Initialize();
853 Assert(!FAILED(hrc));
854
855 VBoxNetDhcp *pDhcp = new VBoxNetDhcp();
856 if (!pDhcp)
857 {
858 RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: new VBoxNetDhcp failed!\n");
859 return 1;
860 }
861 int rc = pDhcp->parseArgs(argc - 1, argv + 1);
862 if (rc)
863 return rc;
864
865 pDhcp->init();
866
867 /*
868 * Try connect the server to the network.
869 */
870 rc = pDhcp->tryGoOnline();
871 if (rc)
872 {
873 delete pDhcp;
874 return rc;
875 }
876
877 /*
878 * Process requests.
879 */
880 g_pDhcp = pDhcp;
881 rc = pDhcp->run();
882 g_pDhcp = NULL;
883 delete pDhcp;
884
885 return rc;
886}
887
888
889#ifndef VBOX_WITH_HARDENING
890
891int main(int argc, char **argv, char **envp)
892{
893 int rc = RTR3InitExe(argc, &argv, RTR3INIT_FLAGS_SUPLIB);
894 if (RT_FAILURE(rc))
895 return RTMsgInitFailure(rc);
896
897 return TrustedMain(argc, argv, envp);
898}
899
900# ifdef RT_OS_WINDOWS
901
902static LRESULT CALLBACK WindowProc(HWND hwnd,
903 UINT uMsg,
904 WPARAM wParam,
905 LPARAM lParam
906)
907{
908 if(uMsg == WM_DESTROY)
909 {
910 PostQuitMessage(0);
911 return 0;
912 }
913 return DefWindowProc (hwnd, uMsg, wParam, lParam);
914}
915
916static LPCWSTR g_WndClassName = L"VBoxNetDHCPClass";
917
918static DWORD WINAPI MsgThreadProc(__in LPVOID lpParameter)
919{
920 HWND hwnd = 0;
921 HINSTANCE hInstance = (HINSTANCE)GetModuleHandle (NULL);
922 bool bExit = false;
923
924 /* Register the Window Class. */
925 WNDCLASS wc;
926 wc.style = 0;
927 wc.lpfnWndProc = WindowProc;
928 wc.cbClsExtra = 0;
929 wc.cbWndExtra = sizeof(void *);
930 wc.hInstance = hInstance;
931 wc.hIcon = NULL;
932 wc.hCursor = NULL;
933 wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1);
934 wc.lpszMenuName = NULL;
935 wc.lpszClassName = g_WndClassName;
936
937 ATOM atomWindowClass = RegisterClass(&wc);
938
939 if (atomWindowClass != 0)
940 {
941 /* Create the window. */
942 hwnd = CreateWindowEx (WS_EX_TOOLWINDOW | WS_EX_TRANSPARENT | WS_EX_TOPMOST,
943 g_WndClassName, g_WndClassName,
944 WS_POPUPWINDOW,
945 -200, -200, 100, 100, NULL, NULL, hInstance, NULL);
946
947 if (hwnd)
948 {
949 SetWindowPos(hwnd, HWND_TOPMOST, -200, -200, 0, 0,
950 SWP_NOACTIVATE | SWP_HIDEWINDOW | SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_NOSIZE);
951
952 MSG msg;
953 while (GetMessage(&msg, NULL, 0, 0))
954 {
955 TranslateMessage(&msg);
956 DispatchMessage(&msg);
957 }
958
959 DestroyWindow (hwnd);
960
961 bExit = true;
962 }
963
964 UnregisterClass (g_WndClassName, hInstance);
965 }
966
967 if(bExit)
968 {
969 /* no need any accuracy here, in anyway the DHCP server usually gets terminated with TerminateProcess */
970 exit(0);
971 }
972
973 return 0;
974}
975
976
977/** (We don't want a console usually.) */
978int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
979{
980 NOREF(hInstance); NOREF(hPrevInstance); NOREF(lpCmdLine); NOREF(nCmdShow);
981
982 HANDLE hThread = CreateThread(
983 NULL, /*__in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes, */
984 0, /*__in SIZE_T dwStackSize, */
985 MsgThreadProc, /*__in LPTHREAD_START_ROUTINE lpStartAddress,*/
986 NULL, /*__in_opt LPVOID lpParameter,*/
987 0, /*__in DWORD dwCreationFlags,*/
988 NULL /*__out_opt LPDWORD lpThreadId*/
989 );
990
991 if(hThread != NULL)
992 CloseHandle(hThread);
993
994 return main(__argc, __argv, environ);
995}
996# endif /* RT_OS_WINDOWS */
997
998#endif /* !VBOX_WITH_HARDENING */
999
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