VirtualBox

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

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

lwip-nat: dhcp missed loop.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 33.0 KB
Line 
1/* $Id: VBoxNetDHCP.cpp 48377 2013-09-09 07:19:32Z 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 unsigned int i;
387 int count_strs;
388 com::SafeArray<BSTR> strs;
389 std::map<RTNETADDRIPV4, uint32_t> MapIp4Addr2Off;
390
391 hrc = m_NATNetwork->COMGETTER(LocalMappings)(ComSafeArrayAsOutParam(strs));
392 if ( SUCCEEDED(hrc)
393 && (count_strs = strs.size()))
394 {
395 for (i = 0; i < count_strs; ++i)
396 {
397 char aszAddr[17];
398 RTNETADDRIPV4 ip4addr;
399 char *pszTerm;
400 uint32_t u32Off;
401 const char *pszLo2Off = com::Utf8Str(strs[i]).c_str();
402
403 RT_ZERO(aszAddr);
404
405 pszTerm = RTStrStr(pszLo2Off, ";");
406
407 if ( pszTerm
408 && (pszTerm - pszLo2Off) >= 17)
409 {
410
411 memcpy(aszAddr, pszLo2Off, (pszTerm - pszLo2Off));
412 int rc = RTNetStrToIPv4Addr(aszAddr, &ip4addr);
413 if (RT_SUCCESS(rc))
414 {
415
416 u32Off = RTStrToUInt32(pszTerm + 1);
417 if (u32Off != 0)
418 MapIp4Addr2Off.insert(
419 std::map<RTNETADDRIPV4,uint32_t>::value_type(ip4addr, u32Off));
420 }
421 }
422 }
423 }
424
425 strs.setNull();
426 ComPtr<IHost> host;
427 if (SUCCEEDED(virtualbox->COMGETTER(Host)(host.asOutParam())))
428 {
429 if (SUCCEEDED(host->COMGETTER(NameServers)(ComSafeArrayAsOutParam(strs))))
430 {
431 RTNETADDRIPV4 addr;
432 confManager->flushAddressList(RTNET_DHCP_OPT_DNS);
433 int rc;
434 for (i = 0; i < strs.size(); ++i)
435 {
436 rc = RTNetStrToIPv4Addr(com::Utf8Str(strs[i]).c_str(), &addr);
437 if (RT_SUCCESS(rc))
438 {
439 if (addr.au8[0] == 127)
440 {
441 if (MapIp4Addr2Off[addr] != 0)
442 {
443 addr.u = RT_H2N_U32(RT_N2H_U32(m_Ipv4Address.u & m_Ipv4Netmask.u)
444 + MapIp4Addr2Off[addr]);
445 }
446 else
447 continue;
448 }
449
450 confManager->addToAddressList(RTNET_DHCP_OPT_DNS, addr);
451 }
452 }
453 }
454
455 strs.setNull();
456#if 0
457 if (SUCCEEDED(host->COMGETTER(SearchStrings)(ComSafeArrayAsOutParam(strs))))
458 {
459 /* XXX: todo. */;
460 }
461 strs.setNull();
462
463 Bstr domain;
464 if (SUCCEEDED(host->COMGETTER(DomainName)(domain.asOutPutParam())))
465 {
466 /* XXX: todo. */
467 }
468#endif
469 }
470 }
471
472 NetworkManager *netManager = NetworkManager::getNetworkManager();
473
474 netManager->setOurAddress(m_Ipv4Address);
475 netManager->setOurNetmask(m_Ipv4Netmask);
476 netManager->setOurMac(m_MacAddress);
477
478 /* Configuration fetching */
479 if (m_fIgnoreCmdLineParameters)
480 {
481 /* just fetch option array and add options to config */
482 /* per VM-settings ???
483 *
484 * - we have vms with attached adapters with known mac-addresses
485 * - mac-addresses might be changed as well as names, how keep our config cleaned ????
486 */
487 com::SafeArray<BSTR> sf;
488 hrc = m_DhcpServer->COMGETTER(GlobalOptions)(ComSafeArrayAsOutParam(sf));
489 AssertComRCReturn(hrc, VERR_INTERNAL_ERROR);
490
491#if 0
492 for (int i = 0; i < sf.size(); ++i)
493 {
494 RTPrintf("%d: %s\n", i, com::Utf8Str(sf[i]).c_str());
495 }
496
497#endif
498 com::Bstr strUpperIp, strLowerIp;
499
500 RTNETADDRIPV4 LowerAddress;
501 RTNETADDRIPV4 UpperAddress;
502
503 hrc = m_DhcpServer->COMGETTER(UpperIP)(strUpperIp.asOutParam());
504 AssertComRCReturn(hrc, VERR_INTERNAL_ERROR);
505 RTNetStrToIPv4Addr(com::Utf8Str(strUpperIp).c_str(), &UpperAddress);
506
507
508 hrc = m_DhcpServer->COMGETTER(LowerIP)(strLowerIp.asOutParam());
509 AssertComRCReturn(hrc, VERR_INTERNAL_ERROR);
510 RTNetStrToIPv4Addr(com::Utf8Str(strLowerIp).c_str(), &LowerAddress);
511
512 RTNETADDRIPV4 networkId;
513 networkId.u = m_Ipv4Address.u & m_Ipv4Netmask.u;
514 std::string name = std::string("default");
515
516 NetworkConfigEntity *pCfg = confManager->addNetwork(unconst(g_RootConfig),
517 networkId,
518 m_Ipv4Netmask,
519 LowerAddress,
520 UpperAddress);
521
522 } /* if(m_fIgnoreCmdLineParameters) */
523 else
524 {
525 CmdParameterIterator it;
526
527 RTNETADDRIPV4 networkId;
528 networkId.u = m_Ipv4Address.u & m_Ipv4Netmask.u;
529 RTNETADDRIPV4 netmask = m_Ipv4Netmask;
530 RTNETADDRIPV4 LowerAddress;
531 RTNETADDRIPV4 UpperAddress;
532
533 LowerAddress = networkId;
534 UpperAddress.u = RT_H2N_U32(RT_N2H_U32(LowerAddress.u) | RT_N2H_U32(netmask.u));
535
536 int idx = 0;
537 char name[64];
538
539
540 for (it = CmdParameterll.begin(); it != CmdParameterll.end(); ++it)
541 {
542 idx++;
543 RTStrPrintf(name, RT_ELEMENTS(name), "network-%d", idx);
544 std::string strname(name);
545
546 switch(it->Key)
547 {
548 case 'b':
549 /* config */
550 NetworkConfigEntity(strname,
551 g_RootConfig,
552 g_AnyClient,
553 5,
554 networkId,
555 netmask,
556 LowerAddress,
557 UpperAddress);
558 case 'l':
559 case 'u':
560 case 'm':
561 case 'g':
562 /* XXX: TBD */
563 break;
564 }
565 }
566 }
567 return VINF_SUCCESS;
568}
569
570/**
571 * Runs the DHCP server.
572 *
573 * @returns exit code + error message to stderr on failure, won't return on
574 * success (you must kill this process).
575 */
576int VBoxNetDhcp::run(void)
577{
578
579 /* XXX: shortcut should be hidden from network manager */
580 NetworkManager *netManager = NetworkManager::getNetworkManager();
581 netManager->m_pSession = m_pSession;
582 netManager->m_hIf = m_hIf;
583 netManager->m_pIfBuf = m_pIfBuf;
584
585 /*
586 * The loop.
587 */
588 PINTNETRINGBUF pRingBuf = &m_pIfBuf->Recv;
589 for (;;)
590 {
591 /*
592 * Wait for a packet to become available.
593 */
594 INTNETIFWAITREQ WaitReq;
595 WaitReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
596 WaitReq.Hdr.cbReq = sizeof(WaitReq);
597 WaitReq.pSession = m_pSession;
598 WaitReq.hIf = m_hIf;
599 WaitReq.cMillies = 2000; /* 2 secs - the sleep is for some reason uninterruptible... */ /** @todo fix interruptability in SrvIntNet! */
600 int rc = SUPR3CallVMMR0Ex(NIL_RTR0PTR, NIL_VMCPUID, VMMR0_DO_INTNET_IF_WAIT, 0, &WaitReq.Hdr);
601 if (RT_FAILURE(rc))
602 {
603 if (rc == VERR_TIMEOUT || rc == VERR_INTERRUPTED)
604 continue;
605 RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: VMMR0_DO_INTNET_IF_WAIT returned %Rrc\n", rc);
606 return 1;
607 }
608
609 /*
610 * Process the receive buffer.
611 */
612 while (IntNetRingHasMoreToRead(pRingBuf))
613 {
614 size_t cb;
615 void *pv = VBoxNetUDPMatch(m_pIfBuf, RTNETIPV4_PORT_BOOTPS, &m_MacAddress,
616 VBOXNETUDP_MATCH_UNICAST | VBOXNETUDP_MATCH_BROADCAST | VBOXNETUDP_MATCH_CHECKSUM
617 | (m_cVerbosity > 2 ? VBOXNETUDP_MATCH_PRINT_STDERR : 0),
618 &m_CurHdrs, &cb);
619 if (pv && cb)
620 {
621 PCRTNETBOOTP pDhcpMsg = (PCRTNETBOOTP)pv;
622 m_pCurMsg = pDhcpMsg;
623 m_cbCurMsg = cb;
624
625 uint8_t uMsgType;
626 if (RTNetIPv4IsDHCPValid(NULL /* why is this here? */, pDhcpMsg, cb, &uMsgType))
627 {
628 m_uCurMsgType = uMsgType;
629 handleDhcpMsg(uMsgType, pDhcpMsg, cb);
630 m_uCurMsgType = UINT8_MAX;
631 }
632 else
633 debugPrint(1, true, "VBoxNetDHCP: Skipping invalid DHCP packet.\n"); /** @todo handle pure bootp clients too? */
634
635 m_pCurMsg = NULL;
636 m_cbCurMsg = 0;
637 }
638 else if (VBoxNetArpHandleIt(m_pSession, m_hIf, m_pIfBuf, &m_MacAddress, m_Ipv4Address))
639 {
640 /* nothing */
641 }
642
643 /* Advance to the next frame. */
644 IntNetRingSkipFrame(pRingBuf);
645 }
646 }
647
648 return 0;
649}
650
651
652/**
653 * Handles a DHCP message.
654 *
655 * @returns true if handled, false if not.
656 * @param uMsgType The message type.
657 * @param pDhcpMsg The DHCP message.
658 * @param cb The size of the DHCP message.
659 */
660bool VBoxNetDhcp::handleDhcpMsg(uint8_t uMsgType, PCRTNETBOOTP pDhcpMsg, size_t cb)
661{
662 if (pDhcpMsg->bp_op == RTNETBOOTP_OP_REQUEST)
663 {
664 switch (uMsgType)
665 {
666 case RTNET_DHCP_MT_DISCOVER:
667 return handleDhcpReqDiscover(pDhcpMsg, cb);
668
669 case RTNET_DHCP_MT_REQUEST:
670 return handleDhcpReqRequest(pDhcpMsg, cb);
671
672 case RTNET_DHCP_MT_DECLINE:
673 return handleDhcpReqDecline(pDhcpMsg, cb);
674
675 case RTNET_DHCP_MT_RELEASE:
676 return handleDhcpReqRelease(pDhcpMsg, cb);
677
678 case RTNET_DHCP_MT_INFORM:
679 debugPrint(0, true, "Should we handle this?");
680 break;
681
682 default:
683 debugPrint(0, true, "Unexpected.");
684 break;
685 }
686 }
687 return false;
688}
689
690
691/**
692 * The client is requesting an offer.
693 *
694 * @returns true.
695 *
696 * @param pDhcpMsg The message.
697 * @param cb The message size.
698 */
699bool VBoxNetDhcp::handleDhcpReqDiscover(PCRTNETBOOTP pDhcpMsg, size_t cb)
700{
701
702 /* let's main first */
703 if (!m_DhcpServer.isNull())
704 {
705#if 0
706 HRESULT hrc;
707 com::SafeArray<BSTR> sf;
708 hrc = m_DhcpServer->GetMacOptions(com::BstrFmt("%02X%02X%02X%02X%02X%02X",
709 pDhcpMsg->bp_chaddr.Mac.au8[0],
710 pDhcpMsg->bp_chaddr.Mac.au8[1],
711 pDhcpMsg->bp_chaddr.Mac.au8[2],
712 pDhcpMsg->bp_chaddr.Mac.au8[3],
713 pDhcpMsg->bp_chaddr.Mac.au8[4],
714 pDhcpMsg->bp_chaddr.Mac.au8[5]).raw(),
715 ComSafeArrayAsOutParam(sf));
716 if (SUCCEEDED(hrc))
717 {
718 /* XXX: per-host configuration */
719 }
720#endif
721 RawOption opt;
722 memset(&opt, 0, sizeof(RawOption));
723 /* 1. Find client */
724 ConfigurationManager *confManager = ConfigurationManager::getConfigurationManager();
725 Client *client = confManager->getClientByDhcpPacket(pDhcpMsg, cb);
726
727 /* 2. Find/Bind lease for client */
728 Lease *lease = confManager->allocateLease4Client(client, pDhcpMsg, cb);
729 AssertPtrReturn(lease, VINF_SUCCESS);
730
731 int rc = ConfigurationManager::extractRequestList(pDhcpMsg, cb, opt);
732
733 /* 3. Send of offer */
734 NetworkManager *networkManager = NetworkManager::getNetworkManager();
735
736 lease->fBinding = true;
737 lease->u64TimestampBindingStarted = RTTimeMilliTS();
738 lease->u32BindExpirationPeriod = 300; /* 3 min. */
739 networkManager->offer4Client(client, pDhcpMsg->bp_xid, opt.au8RawOpt, opt.cbRawOpt);
740 } /* end of if(!m_DhcpServer.isNull()) */
741
742 return VINF_SUCCESS;
743}
744
745
746/**
747 * The client is requesting an offer.
748 *
749 * @returns true.
750 *
751 * @param pDhcpMsg The message.
752 * @param cb The message size.
753 */
754bool VBoxNetDhcp::handleDhcpReqRequest(PCRTNETBOOTP pDhcpMsg, size_t cb)
755{
756 ConfigurationManager *confManager = ConfigurationManager::getConfigurationManager();
757 NetworkManager *networkManager = NetworkManager::getNetworkManager();
758
759 /* 1. find client */
760 Client *client = confManager->getClientByDhcpPacket(pDhcpMsg, cb);
761
762 /* 2. find bound lease */
763 if (client->m_lease)
764 {
765
766 if (client->m_lease->isExpired())
767 {
768 /* send client to INIT state */
769 networkManager->nak(client, pDhcpMsg->bp_xid);
770 confManager->expireLease4Client(client);
771 return true;
772 }
773 /* XXX: Validate request */
774 RawOption opt;
775 memset((void *)&opt, 0, sizeof(RawOption));
776
777 int rc = confManager->commitLease4Client(client);
778 AssertRCReturn(rc, false);
779
780 rc = ConfigurationManager::extractRequestList(pDhcpMsg, cb, opt);
781 AssertRCReturn(rc, false);
782
783 networkManager->ack(client, pDhcpMsg->bp_xid, opt.au8RawOpt, opt.cbRawOpt);
784 }
785 else
786 {
787 networkManager->nak(client, pDhcpMsg->bp_xid);
788 }
789 return true;
790}
791
792
793/**
794 * The client is declining an offer we've made.
795 *
796 * @returns true.
797 *
798 * @param pDhcpMsg The message.
799 * @param cb The message size.
800 */
801bool VBoxNetDhcp::handleDhcpReqDecline(PCRTNETBOOTP pDhcpMsg, size_t cb)
802{
803 /** @todo Probably need to match the server IP here to work correctly with
804 * other servers. */
805
806 /*
807 * The client is supposed to pass us option 50, requested address,
808 * from the offer. We also match the lease state. Apparently the
809 * MAC address is not supposed to be checked here.
810 */
811
812 /** @todo this is not required in the initial implementation, do it later. */
813 debugPrint(1, true, "DECLINE is not implemented");
814 return true;
815}
816
817
818/**
819 * The client is releasing its lease - good boy.
820 *
821 * @returns true.
822 *
823 * @param pDhcpMsg The message.
824 * @param cb The message size.
825 */
826bool VBoxNetDhcp::handleDhcpReqRelease(PCRTNETBOOTP pDhcpMsg, size_t cb)
827{
828 /** @todo Probably need to match the server IP here to work correctly with
829 * other servers. */
830
831 /*
832 * The client may pass us option 61, client identifier, which we should
833 * use to find the lease by.
834 *
835 * We're matching MAC address and lease state as well.
836 */
837
838 /*
839 * If no client identifier or if we couldn't find a lease by using it,
840 * we will try look it up by the client IP address.
841 */
842
843
844 /*
845 * If found, release it.
846 */
847
848
849 /** @todo this is not required in the initial implementation, do it later. */
850 debugPrint(1, true, "RELEASE is not implemented");
851 return true;
852}
853
854
855/**
856 * Print debug message depending on the m_cVerbosity level.
857 *
858 * @param iMinLevel The minimum m_cVerbosity level for this message.
859 * @param fMsg Whether to dump parts for the current DHCP message.
860 * @param pszFmt The message format string.
861 * @param va Optional arguments.
862 */
863void VBoxNetDhcp::debugPrintV(int iMinLevel, bool fMsg, const char *pszFmt, va_list va) const
864{
865 if (iMinLevel <= m_cVerbosity)
866 {
867 va_list vaCopy; /* This dude is *very* special, thus the copy. */
868 va_copy(vaCopy, va);
869 RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: %s: %N\n", iMinLevel >= 2 ? "debug" : "info", pszFmt, &vaCopy);
870 va_end(vaCopy);
871
872 if ( fMsg
873 && m_cVerbosity >= 2
874 && m_pCurMsg)
875 {
876 /* XXX: export this to debugPrinfDhcpMsg or variant and other method export
877 * to base class
878 */
879 const char *pszMsg = m_uCurMsgType != UINT8_MAX ? debugDhcpName(m_uCurMsgType) : "";
880 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",
881 pszMsg,
882 &m_pCurMsg->bp_chaddr,
883 m_pCurMsg->bp_ciaddr.au8[0], m_pCurMsg->bp_ciaddr.au8[1], m_pCurMsg->bp_ciaddr.au8[2], m_pCurMsg->bp_ciaddr.au8[3],
884 m_pCurMsg->bp_yiaddr.au8[0], m_pCurMsg->bp_yiaddr.au8[1], m_pCurMsg->bp_yiaddr.au8[2], m_pCurMsg->bp_yiaddr.au8[3],
885 m_pCurMsg->bp_siaddr.au8[0], m_pCurMsg->bp_siaddr.au8[1], m_pCurMsg->bp_siaddr.au8[2], m_pCurMsg->bp_siaddr.au8[3],
886 m_pCurMsg->bp_xid);
887 }
888 }
889}
890
891
892/**
893 * Gets the name of given DHCP message type.
894 *
895 * @returns Readonly name.
896 * @param uMsgType The message number.
897 */
898/* static */ const char *VBoxNetDhcp::debugDhcpName(uint8_t uMsgType)
899{
900 switch (uMsgType)
901 {
902 case 0: return "MT_00";
903 case RTNET_DHCP_MT_DISCOVER: return "DISCOVER";
904 case RTNET_DHCP_MT_OFFER: return "OFFER";
905 case RTNET_DHCP_MT_REQUEST: return "REQUEST";
906 case RTNET_DHCP_MT_DECLINE: return "DECLINE";
907 case RTNET_DHCP_MT_ACK: return "ACK";
908 case RTNET_DHCP_MT_NAC: return "NAC";
909 case RTNET_DHCP_MT_RELEASE: return "RELEASE";
910 case RTNET_DHCP_MT_INFORM: return "INFORM";
911 case 9: return "MT_09";
912 case 10: return "MT_0a";
913 case 11: return "MT_0b";
914 case 12: return "MT_0c";
915 case 13: return "MT_0d";
916 case 14: return "MT_0e";
917 case 15: return "MT_0f";
918 case 16: return "MT_10";
919 case 17: return "MT_11";
920 case 18: return "MT_12";
921 case 19: return "MT_13";
922 case UINT8_MAX: return "MT_ff";
923 default: return "UNKNOWN";
924 }
925}
926
927
928
929/**
930 * Entry point.
931 */
932extern "C" DECLEXPORT(int) TrustedMain(int argc, char **argv, char **envp)
933{
934 /*
935 * Instantiate the DHCP server and hand it the options.
936 */
937 HRESULT hrc = com::Initialize();
938 Assert(!FAILED(hrc));
939
940 VBoxNetDhcp *pDhcp = new VBoxNetDhcp();
941 if (!pDhcp)
942 {
943 RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: new VBoxNetDhcp failed!\n");
944 return 1;
945 }
946 int rc = pDhcp->parseArgs(argc - 1, argv + 1);
947 if (rc)
948 return rc;
949
950 pDhcp->init();
951
952 /*
953 * Try connect the server to the network.
954 */
955 rc = pDhcp->tryGoOnline();
956 if (rc)
957 {
958 delete pDhcp;
959 return rc;
960 }
961
962 /*
963 * Process requests.
964 */
965 g_pDhcp = pDhcp;
966 rc = pDhcp->run();
967 g_pDhcp = NULL;
968 delete pDhcp;
969
970 return rc;
971}
972
973
974#ifndef VBOX_WITH_HARDENING
975
976int main(int argc, char **argv, char **envp)
977{
978 int rc = RTR3InitExe(argc, &argv, RTR3INIT_FLAGS_SUPLIB);
979 if (RT_FAILURE(rc))
980 return RTMsgInitFailure(rc);
981
982 return TrustedMain(argc, argv, envp);
983}
984
985# ifdef RT_OS_WINDOWS
986
987static LRESULT CALLBACK WindowProc(HWND hwnd,
988 UINT uMsg,
989 WPARAM wParam,
990 LPARAM lParam
991)
992{
993 if(uMsg == WM_DESTROY)
994 {
995 PostQuitMessage(0);
996 return 0;
997 }
998 return DefWindowProc (hwnd, uMsg, wParam, lParam);
999}
1000
1001static LPCWSTR g_WndClassName = L"VBoxNetDHCPClass";
1002
1003static DWORD WINAPI MsgThreadProc(__in LPVOID lpParameter)
1004{
1005 HWND hwnd = 0;
1006 HINSTANCE hInstance = (HINSTANCE)GetModuleHandle (NULL);
1007 bool bExit = false;
1008
1009 /* Register the Window Class. */
1010 WNDCLASS wc;
1011 wc.style = 0;
1012 wc.lpfnWndProc = WindowProc;
1013 wc.cbClsExtra = 0;
1014 wc.cbWndExtra = sizeof(void *);
1015 wc.hInstance = hInstance;
1016 wc.hIcon = NULL;
1017 wc.hCursor = NULL;
1018 wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1);
1019 wc.lpszMenuName = NULL;
1020 wc.lpszClassName = g_WndClassName;
1021
1022 ATOM atomWindowClass = RegisterClass(&wc);
1023
1024 if (atomWindowClass != 0)
1025 {
1026 /* Create the window. */
1027 hwnd = CreateWindowEx (WS_EX_TOOLWINDOW | WS_EX_TRANSPARENT | WS_EX_TOPMOST,
1028 g_WndClassName, g_WndClassName,
1029 WS_POPUPWINDOW,
1030 -200, -200, 100, 100, NULL, NULL, hInstance, NULL);
1031
1032 if (hwnd)
1033 {
1034 SetWindowPos(hwnd, HWND_TOPMOST, -200, -200, 0, 0,
1035 SWP_NOACTIVATE | SWP_HIDEWINDOW | SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_NOSIZE);
1036
1037 MSG msg;
1038 while (GetMessage(&msg, NULL, 0, 0))
1039 {
1040 TranslateMessage(&msg);
1041 DispatchMessage(&msg);
1042 }
1043
1044 DestroyWindow (hwnd);
1045
1046 bExit = true;
1047 }
1048
1049 UnregisterClass (g_WndClassName, hInstance);
1050 }
1051
1052 if(bExit)
1053 {
1054 /* no need any accuracy here, in anyway the DHCP server usually gets terminated with TerminateProcess */
1055 exit(0);
1056 }
1057
1058 return 0;
1059}
1060
1061
1062/** (We don't want a console usually.) */
1063int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
1064{
1065 NOREF(hInstance); NOREF(hPrevInstance); NOREF(lpCmdLine); NOREF(nCmdShow);
1066
1067 HANDLE hThread = CreateThread(
1068 NULL, /*__in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes, */
1069 0, /*__in SIZE_T dwStackSize, */
1070 MsgThreadProc, /*__in LPTHREAD_START_ROUTINE lpStartAddress,*/
1071 NULL, /*__in_opt LPVOID lpParameter,*/
1072 0, /*__in DWORD dwCreationFlags,*/
1073 NULL /*__out_opt LPDWORD lpThreadId*/
1074 );
1075
1076 if(hThread != NULL)
1077 CloseHandle(hThread);
1078
1079 return main(__argc, __argv, environ);
1080}
1081# endif /* RT_OS_WINDOWS */
1082
1083#endif /* !VBOX_WITH_HARDENING */
1084
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