VirtualBox

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

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

VBoxNetDhcp::init: temporary com::Utf8Str object is destructed at the
end of the statement, leaving pszLo2Off dangling - give it proper
lifetime.

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