VirtualBox

source: vbox/trunk/src/VBox/NetworkServices/DHCP/Config.cpp@ 49569

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

VBoxNetDHCP/Config.cpp: lines.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 32.7 KB
Line 
1/* $Id: Config.cpp 49569 2013-11-20 08:59:17Z vboxsync $ */
2
3/**
4 * XXX: license.
5 */
6
7#include <iprt/asm.h>
8#include <iprt/net.h>
9#include <iprt/time.h>
10
11#include <VBox/sup.h>
12#include <VBox/intnet.h>
13#include <VBox/intnetinline.h>
14#include <VBox/vmm/vmm.h>
15#include <VBox/version.h>
16
17#include <VBox/com/string.h>
18
19#include <iprt/cpp/xml.h>
20
21#include "../NetLib/VBoxNetLib.h"
22#include "../NetLib/shared_ptr.h"
23
24#include <list>
25#include <vector>
26#include <map>
27#include <string>
28
29#include "Config.h"
30#include "ClientDataInt.h"
31
32bool operator== (const Lease& lhs, const Lease& rhs)
33{
34 return (lhs.m.get() == rhs.m.get());
35}
36
37
38bool operator!= (const Lease& lhs, const Lease& rhs)
39{
40 return !(lhs == rhs);
41}
42
43
44bool operator< (const Lease& lhs, const Lease& rhs)
45{
46 return ( (lhs.getAddress() < rhs.getAddress())
47 || (lhs.issued() < rhs.issued()));
48}
49/* consts */
50
51const NullConfigEntity *g_NullConfig = new NullConfigEntity();
52RootConfigEntity *g_RootConfig = new RootConfigEntity(std::string("ROOT"), 1200 /* 20 min. */);
53const ClientMatchCriteria *g_AnyClient = new AnyClientMatchCriteria();
54
55static ConfigurationManager *g_ConfigurationManager = ConfigurationManager::getConfigurationManager();
56
57static NetworkManager *g_NetworkManager = NetworkManager::getNetworkManager();
58
59bool MACClientMatchCriteria::check(const Client& client) const
60{
61 return (client == m_mac);
62}
63
64
65int BaseConfigEntity::match(Client& client, BaseConfigEntity **cfg)
66{
67 int iMatch = (m_criteria && m_criteria->check(client)? m_MatchLevel: 0);
68 if (m_children.empty())
69 {
70 if (iMatch > 0)
71 {
72 *cfg = this;
73 return iMatch;
74 }
75 }
76 else
77 {
78 *cfg = this;
79 /* XXX: hack */
80 BaseConfigEntity *matching = this;
81 int matchingLevel = m_MatchLevel;
82
83 for (std::vector<BaseConfigEntity *>::iterator it = m_children.begin();
84 it != m_children.end();
85 ++it)
86 {
87 iMatch = (*it)->match(client, &matching);
88 if (iMatch > matchingLevel)
89 {
90 *cfg = matching;
91 matchingLevel = iMatch;
92 }
93 }
94 return matchingLevel;
95 }
96 return iMatch;
97}
98
99/* Client */
100/* Configs
101 NetworkConfigEntity(std::string name,
102 ConfigEntity* pCfg,
103 ClientMatchCriteria* criteria,
104 RTNETADDRIPV4& networkID,
105 RTNETADDRIPV4& networkMask)
106*/
107static const RTNETADDRIPV4 g_AnyIpv4 = {0};
108static const RTNETADDRIPV4 g_AllIpv4 = {0xffffffff};
109RootConfigEntity::RootConfigEntity(std::string name, uint32_t expPeriod):
110 NetworkConfigEntity(name, g_NullConfig, g_AnyClient, g_AnyIpv4, g_AllIpv4)
111{
112 m_MatchLevel = 2;
113 m_u32ExpirationPeriod = expPeriod;
114}
115
116/* Configuration Manager */
117struct ConfigurationManager::Data
118{
119 Data():fFileExists(false){}
120
121 MapLease2Ip4Address m_allocations;
122 Ipv4AddressContainer m_nameservers;
123 Ipv4AddressContainer m_routers;
124
125 std::string m_domainName;
126 VecClient m_clients;
127 std::string m_leaseStorageFilename;
128 bool fFileExists;
129};
130
131ConfigurationManager *ConfigurationManager::getConfigurationManager()
132{
133 if (!g_ConfigurationManager)
134
135
136 {
137 g_ConfigurationManager = new ConfigurationManager();
138 g_ConfigurationManager->init();
139 }
140
141 return g_ConfigurationManager;
142}
143
144
145const std::string tagXMLLeases = "Leases";
146const std::string tagXMLLeasesAttributeVersion = "version";
147const std::string tagXMLLeasesVersion_1_0 = "1.0";
148const std::string tagXMLLease = "Lease";
149const std::string tagXMLLeaseAttributeMac = "mac";
150const std::string tagXMLLeaseAttributeNetwork = "network";
151const std::string tagXMLLeaseAddress = "Address";
152const std::string tagXMLAddressAttributeValue = "value";
153const std::string tagXMLLeaseTime = "Time";
154const std::string tagXMLTimeAttributeIssued = "issued";
155const std::string tagXMLTimeAttributeExpiration = "expiration";
156const std::string tagXMLLeaseOptions = "Options";
157
158/**
159 * <Leases version="1.0">
160 * <Lease mac="" network=""/>
161 * <Address value=""/>
162 * <Time issued="" expiration=""/>
163 * <options>
164 * <option name="" type=""/>
165 * </option>
166 * </options>
167 * </Lease>
168 * </Leases>
169 */
170int ConfigurationManager::loadFromFile(const std::string& leaseStorageFileName)
171{
172 m->m_leaseStorageFilename = leaseStorageFileName;
173
174 xml::XmlFileParser parser;
175 xml::Document doc;
176
177 try {
178 parser.read(m->m_leaseStorageFilename.c_str(), doc);
179 }
180 catch (...)
181 {
182 return VINF_SUCCESS;
183 }
184
185 /* XML parsing */
186 xml::ElementNode *root = doc.getRootElement();
187
188 if (!root || !root->nameEquals(tagXMLLeases.c_str()))
189 {
190 m->fFileExists = false;
191 return VERR_NOT_FOUND;
192 }
193
194 com::Utf8Str version;
195 if (root)
196 root->getAttributeValue(tagXMLLeasesAttributeVersion.c_str(), version);
197
198 /* XXX: version check */
199 xml::NodesLoop leases(*root);
200
201 bool valueExists;
202 const xml::ElementNode *lease;
203 while ((lease = leases.forAllNodes()))
204 {
205 if (!lease->nameEquals(tagXMLLease.c_str()))
206 continue;
207
208 ClientData *data = new ClientData();
209 Lease l(data);
210 if (l.fromXML(lease))
211 {
212
213 m->m_allocations.insert(MapLease2Ip4AddressPair(l, l.getAddress()));
214
215
216 NetworkConfigEntity *pNetCfg = NULL;
217 Client c(data);
218 int rc = g_RootConfig->match(c, (BaseConfigEntity **)&pNetCfg);
219 Assert(rc >= 0 && pNetCfg);
220
221 l.setConfig(pNetCfg);
222
223 m->m_clients.push_back(c);
224 }
225 }
226
227 return VINF_SUCCESS;
228}
229
230
231int ConfigurationManager::saveToFile()
232{
233 if (m->m_leaseStorageFilename.empty())
234 return VINF_SUCCESS;
235
236 xml::Document doc;
237
238 xml::ElementNode *root = doc.createRootElement(tagXMLLeases.c_str());
239 if (!root)
240 return VERR_INTERNAL_ERROR;
241
242 root->setAttribute(tagXMLLeasesAttributeVersion.c_str(), tagXMLLeasesVersion_1_0.c_str());
243
244 for(MapLease2Ip4AddressConstIterator it = m->m_allocations.begin();
245 it != m->m_allocations.end(); ++it)
246 {
247 xml::ElementNode *lease = root->createChild(tagXMLLease.c_str());
248 if (!it->first.toXML(lease))
249 {
250 /* XXX: todo logging + error handling */
251 }
252 }
253
254 try {
255 xml::XmlFileWriter writer(doc);
256 writer.write(m->m_leaseStorageFilename.c_str(), true);
257 } catch(...){}
258
259 return VINF_SUCCESS;
260}
261
262
263int ConfigurationManager::extractRequestList(PCRTNETBOOTP pDhcpMsg, size_t cbDhcpMsg, RawOption& rawOpt)
264{
265 return ConfigurationManager::findOption(RTNET_DHCP_OPT_PARAM_REQ_LIST, pDhcpMsg, cbDhcpMsg, rawOpt);
266}
267
268
269Client ConfigurationManager::getClientByDhcpPacket(const RTNETBOOTP *pDhcpMsg, size_t cbDhcpMsg)
270{
271
272 VecClientIterator it;
273 bool fDhcpValid = false;
274 uint8_t uMsgType = 0;
275
276 fDhcpValid = RTNetIPv4IsDHCPValid(NULL, pDhcpMsg, cbDhcpMsg, &uMsgType);
277 AssertReturn(fDhcpValid, Client::NullClient);
278
279 LogFlowFunc(("dhcp:mac:%RTmac\n", &pDhcpMsg->bp_chaddr.Mac));
280 /* 1st. client IDs */
281 for ( it = m->m_clients.begin();
282 it != m->m_clients.end();
283 ++it)
284 {
285 if ((*it) == pDhcpMsg->bp_chaddr.Mac)
286 {
287 LogFlowFunc(("client:mac:%RTmac\n", it->getMacAddress()));
288 /* check timestamp that request wasn't expired. */
289 return (*it);
290 }
291 }
292
293 if (it == m->m_clients.end())
294 {
295 /* We hasn't got any session for this client */
296 Client c;
297 c.initWithMac(pDhcpMsg->bp_chaddr.Mac);
298 m->m_clients.push_back(c);
299 return m->m_clients.back();
300 }
301
302 return Client::NullClient;
303}
304
305/**
306 * Finds an option.
307 *
308 * @returns On success, a pointer to the first byte in the option data (no none
309 * then it'll be the byte following the 0 size field) and *pcbOpt set
310 * to the option length.
311 * On failure, NULL is returned and *pcbOpt unchanged.
312 *
313 * @param uOption The option to search for.
314 * @param pDhcpMsg The DHCP message.
315 * that this is adjusted if the option length is larger
316 * than the message buffer.
317 */
318int
319ConfigurationManager::findOption(uint8_t uOption, PCRTNETBOOTP pDhcpMsg, size_t cbDhcpMsg, RawOption& opt)
320{
321 Assert(uOption != RTNET_DHCP_OPT_PAD);
322
323 /*
324 * Validate the DHCP bits and figure the max size of the options in the vendor field.
325 */
326 if (cbDhcpMsg <= RT_UOFFSETOF(RTNETBOOTP, bp_vend.Dhcp.dhcp_opts))
327 return VERR_INVALID_PARAMETER;
328
329 if (pDhcpMsg->bp_vend.Dhcp.dhcp_cookie != RT_H2N_U32_C(RTNET_DHCP_COOKIE))
330 return VERR_INVALID_PARAMETER;
331
332 size_t cbLeft = cbDhcpMsg - RT_UOFFSETOF(RTNETBOOTP, bp_vend.Dhcp.dhcp_opts);
333 if (cbLeft > RTNET_DHCP_OPT_SIZE)
334 cbLeft = RTNET_DHCP_OPT_SIZE;
335
336 /*
337 * Search the vendor field.
338 */
339 bool fExtended = false;
340 uint8_t const *pb = &pDhcpMsg->bp_vend.Dhcp.dhcp_opts[0];
341 while (pb && cbLeft > 0)
342 {
343 uint8_t uCur = *pb;
344 if (uCur == RTNET_DHCP_OPT_PAD)
345 {
346 cbLeft--;
347 pb++;
348 }
349 else if (cbLeft <= 1)
350 break;
351 else
352 {
353 size_t cbCur = pb[1];
354 if (cbCur > cbLeft - 2)
355 cbCur = cbLeft - 2;
356 if (uCur == uOption)
357 {
358 opt.u8OptId = uCur;
359 memcpy(opt.au8RawOpt, pb+2, cbCur);
360 opt.cbRawOpt = cbCur;
361 return VINF_SUCCESS;
362 }
363 pb += cbCur + 2;
364 cbLeft -= cbCur - 2;
365 }
366 }
367
368 /** @todo search extended dhcp option field(s) when present */
369
370 return VERR_NOT_FOUND;
371}
372
373
374/**
375 * We bind lease for client till it continue with it on DHCPREQUEST.
376 */
377Lease ConfigurationManager::allocateLease4Client(const Client& client, PCRTNETBOOTP pDhcpMsg, size_t cbDhcpMsg)
378{
379 {
380 /**
381 * This mean that client has already bound or commited lease.
382 * If we've it happens it means that we received DHCPDISCOVER twice.
383 */
384 const Lease l = client.lease();
385 if (l != Lease::NullLease)
386 {
387 /* Here we should take lease from the m_allocation which was feed with leases
388 * on start
389 */
390 if (l.isExpired())
391 {
392 expireLease4Client(const_cast<Client&>(client));
393 if (!l.isExpired())
394 return l;
395 }
396 else
397 {
398 AssertReturn(l.getAddress().u != 0, Lease::NullLease);
399 return l;
400 }
401 }
402 }
403
404 RTNETADDRIPV4 hintAddress;
405 RawOption opt;
406 NetworkConfigEntity *pNetCfg;
407
408 Client cl(client);
409 AssertReturn(g_RootConfig->match(cl, (BaseConfigEntity **)&pNetCfg) > 0, Lease::NullLease);
410
411 /* DHCPDISCOVER MAY contain request address */
412 hintAddress.u = 0;
413 int rc = findOption(RTNET_DHCP_OPT_REQ_ADDR, pDhcpMsg, cbDhcpMsg, opt);
414 if (RT_SUCCESS(rc))
415 {
416 hintAddress.u = *(uint32_t *)opt.au8RawOpt;
417 if ( RT_H2N_U32(hintAddress.u) < RT_H2N_U32(pNetCfg->lowerIp().u)
418 || RT_H2N_U32(hintAddress.u) > RT_H2N_U32(pNetCfg->upperIp().u))
419 hintAddress.u = 0; /* clear hint */
420 }
421
422 if ( hintAddress.u
423 && !isAddressTaken(hintAddress))
424 {
425 Lease l(cl);
426 l.setConfig(pNetCfg);
427 l.setAddress(hintAddress);
428 m->m_allocations.insert(MapLease2Ip4AddressPair(l, hintAddress));
429 return l;
430 }
431
432 uint32_t u32 = 0;
433 for(u32 = RT_H2N_U32(pNetCfg->lowerIp().u);
434 u32 <= RT_H2N_U32(pNetCfg->upperIp().u);
435 ++u32)
436 {
437 RTNETADDRIPV4 address;
438 address.u = RT_H2N_U32(u32);
439 if (!isAddressTaken(address))
440 {
441 Lease l(cl);
442 l.setConfig(pNetCfg);
443 l.setAddress(address);
444 m->m_allocations.insert(MapLease2Ip4AddressPair(l, address));
445 return l;
446 }
447 }
448
449 return Lease::NullLease;
450}
451
452
453int ConfigurationManager::commitLease4Client(Client& client)
454{
455 Lease l = client.lease();
456 AssertReturn(l != Lease::NullLease, VERR_INTERNAL_ERROR);
457
458 l.bindingPhase(false);
459 const NetworkConfigEntity *pCfg = l.getConfig();
460
461 AssertPtr(pCfg);
462 l.setExpiration(pCfg->expirationPeriod());
463 l.phaseStart(RTTimeMilliTS());
464
465 saveToFile();
466
467 return VINF_SUCCESS;
468}
469
470
471int ConfigurationManager::expireLease4Client(Client& client)
472{
473 Lease l = client.lease();
474 AssertReturn(l != Lease::NullLease, VERR_INTERNAL_ERROR);
475
476 if (l.isInBindingPhase())
477 {
478
479 MapLease2Ip4AddressIterator it = m->m_allocations.find(l);
480 AssertReturn(it != m->m_allocations.end(), VERR_NOT_FOUND);
481
482 /*
483 * XXX: perhaps it better to keep this allocation ????
484 */
485 m->m_allocations.erase(it);
486
487 l.expire();
488 return VINF_SUCCESS;
489 }
490
491 l = Lease(client); /* re-new */
492 return VINF_SUCCESS;
493}
494
495
496bool ConfigurationManager::isAddressTaken(const RTNETADDRIPV4& addr, Lease& lease)
497{
498 MapLease2Ip4AddressIterator it;
499
500 for (it = m->m_allocations.begin();
501 it != m->m_allocations.end();
502 ++it)
503 {
504 if (it->second.u == addr.u)
505 {
506 if (lease != Lease::NullLease)
507 lease = it->first;
508
509 return true;
510 }
511 }
512 lease = Lease::NullLease;
513 return false;
514}
515
516
517bool ConfigurationManager::isAddressTaken(const RTNETADDRIPV4& addr)
518{
519 Lease ignore;
520 return isAddressTaken(addr, ignore);
521}
522
523
524NetworkConfigEntity *ConfigurationManager::addNetwork(NetworkConfigEntity *,
525 const RTNETADDRIPV4& networkId,
526 const RTNETADDRIPV4& netmask,
527 RTNETADDRIPV4& LowerAddress,
528 RTNETADDRIPV4& UpperAddress)
529{
530 static int id;
531 char name[64];
532
533 RTStrPrintf(name, RT_ELEMENTS(name), "network-%d", id);
534 std::string strname(name);
535 id++;
536
537
538 if (!LowerAddress.u)
539 LowerAddress = networkId;
540
541 if (!UpperAddress.u)
542 UpperAddress.u = networkId.u | (~netmask.u);
543
544 return new NetworkConfigEntity(strname,
545 g_RootConfig,
546 g_AnyClient,
547 5,
548 networkId,
549 netmask,
550 LowerAddress,
551 UpperAddress);
552}
553
554HostConfigEntity *ConfigurationManager::addHost(NetworkConfigEntity* pCfg,
555 const RTNETADDRIPV4& address,
556 ClientMatchCriteria *criteria)
557{
558 static int id;
559 char name[64];
560
561 RTStrPrintf(name, RT_ELEMENTS(name), "host-%d", id);
562 std::string strname(name);
563 id++;
564
565 return new HostConfigEntity(address, strname, pCfg, criteria);
566}
567
568int ConfigurationManager::addToAddressList(uint8_t u8OptId, RTNETADDRIPV4& address)
569{
570 switch(u8OptId)
571 {
572 case RTNET_DHCP_OPT_DNS:
573 m->m_nameservers.push_back(address);
574 break;
575 case RTNET_DHCP_OPT_ROUTERS:
576 m->m_routers.push_back(address);
577 break;
578 default:
579 Log(("dhcp-opt: list (%d) unsupported\n", u8OptId));
580 }
581 return VINF_SUCCESS;
582}
583
584
585int ConfigurationManager::flushAddressList(uint8_t u8OptId)
586{
587 switch(u8OptId)
588 {
589 case RTNET_DHCP_OPT_DNS:
590 m->m_nameservers.clear();
591 break;
592 case RTNET_DHCP_OPT_ROUTERS:
593 m->m_routers.clear();
594 break;
595 default:
596 Log(("dhcp-opt: list (%d) unsupported\n", u8OptId));
597 }
598 return VINF_SUCCESS;
599}
600
601
602const Ipv4AddressContainer& ConfigurationManager::getAddressList(uint8_t u8OptId)
603{
604 switch(u8OptId)
605 {
606 case RTNET_DHCP_OPT_DNS:
607 return m->m_nameservers;
608
609 case RTNET_DHCP_OPT_ROUTERS:
610 return m->m_routers;
611
612 }
613 /* XXX: Grrr !!! */
614 return m_empty;
615}
616
617
618int ConfigurationManager::setString(uint8_t u8OptId, const std::string& str)
619{
620 switch (u8OptId)
621 {
622 case RTNET_DHCP_OPT_DOMAIN_NAME:
623 m->m_domainName = str;
624 break;
625 default:
626 break;
627 }
628
629 return VINF_SUCCESS;
630}
631
632
633const std::string& ConfigurationManager::getString(uint8_t u8OptId)
634{
635 switch (u8OptId)
636 {
637 case RTNET_DHCP_OPT_DOMAIN_NAME:
638 if (m->m_domainName.length())
639 return m->m_domainName;
640 else
641 return m_noString;
642 default:
643 break;
644 }
645
646 return m_noString;
647}
648
649
650void ConfigurationManager::init()
651{
652 m = new ConfigurationManager::Data();
653}
654
655
656ConfigurationManager::~ConfigurationManager() { if (m) delete m; }
657
658/**
659 * Network manager
660 */
661struct NetworkManager::Data
662{
663 Data()
664 {
665 RT_ZERO(BootPReplyMsg);
666 cbBooPReplyMsg = 0;
667
668 m_pSession = NIL_RTR0PTR;
669 m_pIfBuf = NULL;
670 m_OurAddress.u = 0;
671 m_OurNetmask.u = 0;
672 RT_ZERO(m_OurMac);
673 }
674
675 union {
676 RTNETBOOTP BootPHeader;
677 uint8_t au8Storage[1024];
678 } BootPReplyMsg;
679 int cbBooPReplyMsg;
680
681 /* XXX: artifacts should be hidden or removed from here. */
682 PSUPDRVSESSION m_pSession;
683 INTNETIFHANDLE m_hIf;
684 PINTNETBUF m_pIfBuf;
685
686 RTNETADDRIPV4 m_OurAddress;
687 RTNETADDRIPV4 m_OurNetmask;
688 RTMAC m_OurMac;
689};
690
691
692NetworkManager::NetworkManager():m(NULL)
693{
694 m = new NetworkManager::Data();
695}
696
697
698NetworkManager::~NetworkManager()
699{
700 delete m;
701 m = NULL;
702}
703
704
705NetworkManager *NetworkManager::getNetworkManager()
706{
707 if (!g_NetworkManager)
708 g_NetworkManager = new NetworkManager();
709
710 return g_NetworkManager;
711}
712
713
714const RTNETADDRIPV4& NetworkManager::getOurAddress() const
715{
716 return m->m_OurAddress;
717}
718
719
720const RTNETADDRIPV4& NetworkManager::getOurNetmask() const
721{
722 return m->m_OurNetmask;
723}
724
725
726const RTMAC& NetworkManager::getOurMac() const
727{
728 return m->m_OurMac;
729}
730
731
732void NetworkManager::setOurAddress(const RTNETADDRIPV4& aAddress)
733{
734 m->m_OurAddress = aAddress;
735}
736
737
738void NetworkManager::setOurNetmask(const RTNETADDRIPV4& aNetmask)
739{
740 m->m_OurNetmask = aNetmask;
741}
742
743
744void NetworkManager::setOurMac(const RTMAC& aMac)
745{
746 m->m_OurMac = aMac;
747}
748
749
750void NetworkManager::setSession(PSUPDRVSESSION aSession)
751{
752 m->m_pSession = aSession;
753}
754
755
756void NetworkManager::setInterface(INTNETIFHANDLE aIf)
757{
758 m->m_hIf = aIf;
759}
760
761
762void NetworkManager::setRingBuffer(PINTNETBUF aBuf)
763{
764 m->m_pIfBuf = aBuf;
765}
766/**
767 * Network manager creates DHCPOFFER datagramm
768 */
769int NetworkManager::offer4Client(const Client& client, uint32_t u32Xid,
770 uint8_t *pu8ReqList, int cReqList)
771{
772 Lease l(client); /* XXX: oh, it looks badly, but now we have lease */
773 prepareReplyPacket4Client(client, u32Xid);
774
775 RTNETADDRIPV4 address = l.getAddress();
776 m->BootPReplyMsg.BootPHeader.bp_yiaddr = address;
777
778 /* Ubuntu ???*/
779 m->BootPReplyMsg.BootPHeader.bp_ciaddr = address;
780
781 /* options:
782 * - IP lease time
783 * - message type
784 * - server identifier
785 */
786 RawOption opt;
787 RT_ZERO(opt);
788
789 std::vector<RawOption> extra(2);
790 opt.u8OptId = RTNET_DHCP_OPT_MSG_TYPE;
791 opt.au8RawOpt[0] = RTNET_DHCP_MT_OFFER;
792 opt.cbRawOpt = 1;
793 extra.push_back(opt);
794
795 opt.u8OptId = RTNET_DHCP_OPT_LEASE_TIME;
796
797 const NetworkConfigEntity *pCfg = l.getConfig();
798 AssertPtr(pCfg);
799
800 *(uint32_t *)opt.au8RawOpt = RT_H2N_U32(pCfg->expirationPeriod());
801 opt.cbRawOpt = sizeof(RTNETADDRIPV4);
802
803 extra.push_back(opt);
804
805 processParameterReqList(client, pu8ReqList, cReqList);
806
807 return doReply(client, extra);
808}
809
810/**
811 * Network manager creates DHCPACK
812 */
813int NetworkManager::ack(const Client& client, uint32_t u32Xid,
814 uint8_t *pu8ReqList, int cReqList)
815{
816 RTNETADDRIPV4 address;
817
818 prepareReplyPacket4Client(client, u32Xid);
819
820 Lease l = client.lease();
821 address = l.getAddress();
822 m->BootPReplyMsg.BootPHeader.bp_ciaddr = address;
823
824
825 /* rfc2131 4.3.1 is about DHCPDISCOVER and this value is equal to ciaddr from
826 * DHCPREQUEST or 0 ...
827 * XXX: Using addressHint is not correct way to initialize [cy]iaddress...
828 */
829 m->BootPReplyMsg.BootPHeader.bp_ciaddr = address;
830 m->BootPReplyMsg.BootPHeader.bp_yiaddr = address;
831
832 Assert(m->BootPReplyMsg.BootPHeader.bp_yiaddr.u);
833
834 /* options:
835 * - IP address lease time (if DHCPREQUEST)
836 * - message type
837 * - server identifier
838 */
839 RawOption opt;
840 RT_ZERO(opt);
841
842 std::vector<RawOption> extra(2);
843 opt.u8OptId = RTNET_DHCP_OPT_MSG_TYPE;
844 opt.au8RawOpt[0] = RTNET_DHCP_MT_ACK;
845 opt.cbRawOpt = 1;
846 extra.push_back(opt);
847
848 /*
849 * XXX: lease time should be conditional. If on dhcprequest then tim should be provided,
850 * else on dhcpinform it mustn't.
851 */
852 opt.u8OptId = RTNET_DHCP_OPT_LEASE_TIME;
853 *(uint32_t *)opt.au8RawOpt = RT_H2N_U32(l.getExpiration());
854 opt.cbRawOpt = sizeof(RTNETADDRIPV4);
855 extra.push_back(opt);
856
857 processParameterReqList(client, pu8ReqList, cReqList);
858
859 return doReply(client, extra);
860}
861
862/**
863 * Network manager creates DHCPNAK
864 */
865int NetworkManager::nak(const Client& client, uint32_t u32Xid)
866{
867
868 Lease l = client.lease();
869 if (l == Lease::NullLease)
870 return VERR_INTERNAL_ERROR;
871
872 prepareReplyPacket4Client(client, u32Xid);
873
874 /* this field filed in prepareReplyPacket4Session, and
875 * RFC 2131 require to have it zero fo NAK.
876 */
877 m->BootPReplyMsg.BootPHeader.bp_yiaddr.u = 0;
878
879 /* options:
880 * - message type (if DHCPREQUEST)
881 * - server identifier
882 */
883 RawOption opt;
884 std::vector<RawOption> extra;
885
886 opt.u8OptId = RTNET_DHCP_OPT_MSG_TYPE;
887 opt.au8RawOpt[0] = RTNET_DHCP_MT_NAC;
888 opt.cbRawOpt = 1;
889 extra.push_back(opt);
890
891 return doReply(client, extra);
892}
893
894/**
895 *
896 */
897int NetworkManager::prepareReplyPacket4Client(const Client& client, uint32_t u32Xid)
898{
899 RT_ZERO(m->BootPReplyMsg);
900
901 m->BootPReplyMsg.BootPHeader.bp_op = RTNETBOOTP_OP_REPLY;
902 m->BootPReplyMsg.BootPHeader.bp_htype = RTNET_ARP_ETHER;
903 m->BootPReplyMsg.BootPHeader.bp_hlen = sizeof(RTMAC);
904 m->BootPReplyMsg.BootPHeader.bp_hops = 0;
905 m->BootPReplyMsg.BootPHeader.bp_xid = u32Xid;
906 m->BootPReplyMsg.BootPHeader.bp_secs = 0;
907 /* XXX: bp_flags should be processed specially */
908 m->BootPReplyMsg.BootPHeader.bp_flags = 0;
909 m->BootPReplyMsg.BootPHeader.bp_ciaddr.u = 0;
910 m->BootPReplyMsg.BootPHeader.bp_giaddr.u = 0;
911
912 m->BootPReplyMsg.BootPHeader.bp_chaddr.Mac = client.getMacAddress();
913
914 const Lease l = client.lease();
915 m->BootPReplyMsg.BootPHeader.bp_yiaddr = l.getAddress();
916 m->BootPReplyMsg.BootPHeader.bp_siaddr.u = 0;
917
918
919 m->BootPReplyMsg.BootPHeader.bp_vend.Dhcp.dhcp_cookie = RT_H2N_U32_C(RTNET_DHCP_COOKIE);
920
921 memset(&m->BootPReplyMsg.BootPHeader.bp_vend.Dhcp.dhcp_opts[0],
922 '\0',
923 RTNET_DHCP_OPT_SIZE);
924
925 return VINF_SUCCESS;
926}
927
928
929int NetworkManager::doReply(const Client& client, const std::vector<RawOption>& extra)
930{
931 int rc;
932
933 /*
934 Options....
935 */
936 VBoxNetDhcpWriteCursor Cursor(&m->BootPReplyMsg.BootPHeader, RTNET_DHCP_NORMAL_SIZE);
937
938 /* The basics */
939
940 Cursor.optIPv4Addr(RTNET_DHCP_OPT_SERVER_ID, m->m_OurAddress);
941
942 const Lease l = client.lease();
943 const std::map<uint8_t, RawOption>& options = l.options();
944
945 for(std::vector<RawOption>::const_iterator it = extra.begin();
946 it != extra.end(); ++it)
947 {
948 if (!Cursor.begin(it->u8OptId, it->cbRawOpt))
949 break;
950 Cursor.put(it->au8RawOpt, it->cbRawOpt);
951
952 }
953
954 for(std::map<uint8_t, RawOption>::const_iterator it = options.begin();
955 it != options.end(); ++it)
956 {
957 if (!Cursor.begin(it->second.u8OptId, it->second.cbRawOpt))
958 break;
959 Cursor.put(it->second.au8RawOpt, it->second.cbRawOpt);
960
961 }
962
963 Cursor.optEnd();
964
965 /*
966 */
967#if 0
968 /** @todo need to see someone set this flag to check that it's correct. */
969 if (!(pDhcpMsg->bp_flags & RTNET_DHCP_FLAGS_NO_BROADCAST))
970 {
971 rc = VBoxNetUDPUnicast(m_pSession,
972 m_hIf,
973 m_pIfBuf,
974 m_OurAddress,
975 &m_OurMac,
976 RTNETIPV4_PORT_BOOTPS, /* sender */
977 IPv4AddrBrdCast,
978 &BootPReplyMsg.BootPHeader->bp_chaddr.Mac,
979 RTNETIPV4_PORT_BOOTPC, /* receiver */
980 &BootPReplyMsg, cbBooPReplyMsg);
981 }
982 else
983#endif
984 rc = VBoxNetUDPBroadcast(m->m_pSession,
985 m->m_hIf,
986 m->m_pIfBuf,
987 m->m_OurAddress,
988 &m->m_OurMac,
989 RTNETIPV4_PORT_BOOTPS, /* sender */
990 RTNETIPV4_PORT_BOOTPC,
991 &m->BootPReplyMsg, RTNET_DHCP_NORMAL_SIZE);
992
993 AssertRCReturn(rc,rc);
994
995 return VINF_SUCCESS;
996}
997
998
999int NetworkManager::processParameterReqList(const Client& client, uint8_t *pu8ReqList, int cReqList)
1000{
1001 /* request parameter list */
1002 RawOption opt;
1003 int idxParam = 0;
1004
1005 uint8_t *pReqList = pu8ReqList;
1006
1007 const Lease const_l = client.lease();
1008 Lease l = Lease(const_l);
1009
1010 const NetworkConfigEntity *pNetCfg = l.getConfig();
1011
1012 for (idxParam = 0; idxParam < cReqList; ++idxParam)
1013 {
1014
1015 bool fIgnore = false;
1016 RT_ZERO(opt);
1017 opt.u8OptId = pReqList[idxParam];
1018
1019 switch(pReqList[idxParam])
1020 {
1021 case RTNET_DHCP_OPT_SUBNET_MASK:
1022 ((PRTNETADDRIPV4)opt.au8RawOpt)->u = pNetCfg->netmask().u;
1023 opt.cbRawOpt = sizeof(RTNETADDRIPV4);
1024
1025 break;
1026
1027 case RTNET_DHCP_OPT_ROUTERS:
1028 case RTNET_DHCP_OPT_DNS:
1029 {
1030 const Ipv4AddressContainer lst =
1031 g_ConfigurationManager->getAddressList(pReqList[idxParam]);
1032 PRTNETADDRIPV4 pAddresses = (PRTNETADDRIPV4)&opt.au8RawOpt[0];
1033
1034 for (Ipv4AddressConstIterator it = lst.begin();
1035 it != lst.end();
1036 ++it)
1037 {
1038 *pAddresses = (*it);
1039 pAddresses++;
1040 opt.cbRawOpt += sizeof(RTNETADDRIPV4);
1041 }
1042
1043 if (lst.empty())
1044 fIgnore = true;
1045 }
1046 break;
1047 case RTNET_DHCP_OPT_DOMAIN_NAME:
1048 {
1049 std::string domainName = g_ConfigurationManager->getString(pReqList[idxParam]);
1050 if (domainName == g_ConfigurationManager->m_noString)
1051 {
1052 fIgnore = true;
1053 break;
1054 }
1055
1056 char *pszDomainName = (char *)&opt.au8RawOpt[0];
1057
1058 strcpy(pszDomainName, domainName.c_str());
1059 opt.cbRawOpt = domainName.length();
1060 }
1061 break;
1062 default:
1063 Log(("opt: %d is ignored\n", pReqList[idxParam]));
1064 fIgnore = true;
1065 break;
1066 }
1067
1068 if (!fIgnore)
1069 l.options().insert(std::map<uint8_t, RawOption>::value_type(opt.u8OptId, opt));
1070
1071 }
1072
1073 return VINF_SUCCESS;
1074}
1075
1076/* Utility */
1077bool operator== (const RTMAC& lhs, const RTMAC& rhs)
1078{
1079 return ( lhs.au16[0] == rhs.au16[0]
1080 && lhs.au16[1] == rhs.au16[1]
1081 && lhs.au16[2] == rhs.au16[2]);
1082}
1083
1084
1085/* Client */
1086Client::Client()
1087{
1088 m = SharedPtr<ClientData>();
1089}
1090
1091
1092void Client::initWithMac(const RTMAC& mac)
1093{
1094 m = SharedPtr<ClientData>(new ClientData());
1095 m->m_mac = mac;
1096}
1097
1098
1099bool Client::operator== (const RTMAC& mac) const
1100{
1101 return (m.get() && m->m_mac == mac);
1102}
1103
1104
1105const RTMAC& Client::getMacAddress() const
1106{
1107 return m->m_mac;
1108}
1109
1110
1111Lease Client::lease()
1112{
1113 if (!m.get()) return Lease::NullLease;
1114
1115 if (m->fHasLease)
1116 return Lease(*this);
1117 else
1118 return Lease::NullLease;
1119}
1120
1121
1122const Lease Client::lease() const
1123{
1124 return const_cast<Client *>(this)->lease();
1125}
1126
1127
1128Client::Client(ClientData *data):m(SharedPtr<ClientData>(data)){}
1129
1130/* Lease */
1131Lease::Lease()
1132{
1133 m = SharedPtr<ClientData>();
1134}
1135
1136
1137Lease::Lease (const Client& c)
1138{
1139 m = SharedPtr<ClientData>(c.m);
1140 if ( !m->fHasLease
1141 || ( isExpired()
1142 && !isInBindingPhase()))
1143 {
1144 m->fHasLease = true;
1145 m->fBinding = true;
1146 phaseStart(RTTimeMilliTS());
1147 }
1148}
1149
1150
1151bool Lease::isExpired() const
1152{
1153 AssertPtrReturn(m.get(), false);
1154
1155 if (!m->fBinding)
1156 return (ASMDivU64ByU32RetU32(RTTimeMilliTS() - m->u64TimestampLeasingStarted, 1000)
1157 > m->u32LeaseExpirationPeriod);
1158 else
1159 return (ASMDivU64ByU32RetU32(RTTimeMilliTS() - m->u64TimestampBindingStarted, 1000)
1160 > m->u32BindExpirationPeriod);
1161}
1162
1163
1164void Lease::expire()
1165{
1166 /* XXX: TODO */
1167}
1168
1169
1170void Lease::phaseStart(uint64_t u64Start)
1171{
1172 if (m->fBinding)
1173 m->u64TimestampBindingStarted = u64Start;
1174 else
1175 m->u64TimestampLeasingStarted = u64Start;
1176}
1177
1178
1179void Lease::bindingPhase(bool fOnOff)
1180{
1181 m->fBinding = fOnOff;
1182}
1183
1184
1185bool Lease::isInBindingPhase() const
1186{
1187 return m->fBinding;
1188}
1189
1190
1191uint64_t Lease::issued() const
1192{
1193 return m->u64TimestampLeasingStarted;
1194}
1195
1196
1197void Lease::setExpiration(uint32_t exp)
1198{
1199 if (m->fBinding)
1200 m->u32BindExpirationPeriod = exp;
1201 else
1202 m->u32LeaseExpirationPeriod = exp;
1203}
1204
1205
1206uint32_t Lease::getExpiration() const
1207{
1208 if (m->fBinding)
1209 return m->u32BindExpirationPeriod;
1210 else
1211 return m->u32LeaseExpirationPeriod;
1212}
1213
1214
1215RTNETADDRIPV4 Lease::getAddress() const
1216{
1217 return m->m_address;
1218}
1219
1220
1221void Lease::setAddress(RTNETADDRIPV4 address)
1222{
1223 m->m_address = address;
1224}
1225
1226
1227const NetworkConfigEntity *Lease::getConfig() const
1228{
1229 return m->pCfg;
1230}
1231
1232
1233void Lease::setConfig(NetworkConfigEntity *pCfg)
1234{
1235 m->pCfg = pCfg;
1236}
1237
1238
1239const MapOptionId2RawOption& Lease::options() const
1240{
1241 return m->options;
1242}
1243
1244
1245MapOptionId2RawOption& Lease::options()
1246{
1247 return m->options;
1248}
1249
1250
1251Lease::Lease(ClientData *pd):m(SharedPtr<ClientData>(pd)){}
1252
1253
1254bool Lease::toXML(xml::ElementNode *node) const
1255{
1256 bool valueAddition = node->setAttribute(tagXMLLeaseAttributeMac.c_str(), com::Utf8StrFmt("%RTmac", &m->m_mac));
1257 if (!valueAddition) return false;
1258
1259 valueAddition = node->setAttribute(tagXMLLeaseAttributeNetwork.c_str(), com::Utf8StrFmt("%RTnaipv4", m->m_network));
1260 if (!valueAddition) return false;
1261
1262 xml::ElementNode *address = node->createChild(tagXMLLeaseAddress.c_str());
1263 if (!address) return false;
1264
1265 valueAddition = address->setAttribute(tagXMLAddressAttributeValue.c_str(), com::Utf8StrFmt("%RTnaipv4", m->m_address));
1266 if (!valueAddition) return false;
1267
1268 xml::ElementNode *time = node->createChild(tagXMLLeaseTime.c_str());
1269 if (!time) return false;
1270
1271 valueAddition = time->setAttribute(tagXMLTimeAttributeIssued.c_str(),
1272 m->u64TimestampLeasingStarted);
1273 if (!valueAddition) return false;
1274
1275 valueAddition = time->setAttribute(tagXMLTimeAttributeExpiration.c_str(),
1276 m->u32LeaseExpirationPeriod);
1277 if (!valueAddition) return false;
1278
1279 return true;
1280}
1281
1282
1283bool Lease::fromXML(const xml::ElementNode *node)
1284{
1285 com::Utf8Str mac;
1286 bool valueExists = node->getAttributeValue(tagXMLLeaseAttributeMac.c_str(), mac);
1287 if (!valueExists) return false;
1288 int rc = RTNetStrToMacAddr(mac.c_str(), &m->m_mac);
1289 if (RT_FAILURE(rc)) return false;
1290
1291 com::Utf8Str network;
1292 valueExists = node->getAttributeValue(tagXMLLeaseAttributeNetwork.c_str(), network);
1293 if (!valueExists) return false;
1294 rc = RTNetStrToIPv4Addr(network.c_str(), &m->m_network);
1295 if (RT_FAILURE(rc)) return false;
1296
1297 /* Address */
1298 const xml::ElementNode *address = node->findChildElement(tagXMLLeaseAddress.c_str());
1299 if (!address) return false;
1300 com::Utf8Str addressValue;
1301 valueExists = address->getAttributeValue(tagXMLAddressAttributeValue.c_str(), addressValue);
1302 if (!valueExists) return false;
1303 rc = RTNetStrToIPv4Addr(addressValue.c_str(), &m->m_address);
1304
1305 /* Time */
1306 const xml::ElementNode *time = node->findChildElement(tagXMLLeaseTime.c_str());
1307 if (!time) return false;
1308
1309 valueExists = time->getAttributeValue(tagXMLTimeAttributeIssued.c_str(),
1310 &m->u64TimestampLeasingStarted);
1311 if (!valueExists) return false;
1312 m->fBinding = false;
1313
1314 valueExists = time->getAttributeValue(tagXMLTimeAttributeExpiration.c_str(),
1315 &m->u32LeaseExpirationPeriod);
1316 if (!valueExists) return false;
1317
1318 m->fHasLease = true;
1319 return true;
1320}
1321
1322
1323const Lease Lease::NullLease;
1324
1325
1326const Client Client::NullClient;
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