VirtualBox

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

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

VBoxNetServices: moves bool operator== (const RTMAC&, const RTMAC&) to utils header.

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