VirtualBox

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

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

NetworkServices/DHCP: use Utf8Str

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