VirtualBox

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

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

DHCP/NetworkManager: visibility (ack,nak, offer4Client) from public to private.

  • 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 49567 2013-11-20 08:52:10Z 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
59int BaseConfigEntity::match(Client& client, BaseConfigEntity **cfg)
60{
61 int iMatch = (m_criteria && m_criteria->check(client)? m_MatchLevel: 0);
62 if (m_children.empty())
63 {
64 if (iMatch > 0)
65 {
66 *cfg = this;
67 return iMatch;
68 }
69 }
70 else
71 {
72 *cfg = this;
73 /* XXX: hack */
74 BaseConfigEntity *matching = this;
75 int matchingLevel = m_MatchLevel;
76
77 for (std::vector<BaseConfigEntity *>::iterator it = m_children.begin();
78 it != m_children.end();
79 ++it)
80 {
81 iMatch = (*it)->match(client, &matching);
82 if (iMatch > matchingLevel)
83 {
84 *cfg = matching;
85 matchingLevel = iMatch;
86 }
87 }
88 return matchingLevel;
89 }
90 return iMatch;
91}
92
93/* Client */
94/* Configs
95 NetworkConfigEntity(std::string name,
96 ConfigEntity* pCfg,
97 ClientMatchCriteria* criteria,
98 RTNETADDRIPV4& networkID,
99 RTNETADDRIPV4& networkMask)
100*/
101static const RTNETADDRIPV4 g_AnyIpv4 = {0};
102static const RTNETADDRIPV4 g_AllIpv4 = {0xffffffff};
103RootConfigEntity::RootConfigEntity(std::string name, uint32_t expPeriod):
104 NetworkConfigEntity(name, g_NullConfig, g_AnyClient, g_AnyIpv4, g_AllIpv4)
105{
106 m_MatchLevel = 2;
107 m_u32ExpirationPeriod = expPeriod;
108}
109
110/* Configuration Manager */
111struct ConfigurationManager::Data
112{
113 Data():fFileExists(false){}
114
115 MapLease2Ip4Address m_allocations;
116 Ipv4AddressContainer m_nameservers;
117 Ipv4AddressContainer m_routers;
118
119 std::string m_domainName;
120 VecClient m_clients;
121 std::string m_leaseStorageFilename;
122 bool fFileExists;
123};
124
125ConfigurationManager *ConfigurationManager::getConfigurationManager()
126{
127 if (!g_ConfigurationManager)
128
129
130 {
131 g_ConfigurationManager = new ConfigurationManager();
132 g_ConfigurationManager->init();
133 }
134
135 return g_ConfigurationManager;
136}
137
138
139const std::string tagXMLLeases = "Leases";
140const std::string tagXMLLeasesAttributeVersion = "version";
141const std::string tagXMLLeasesVersion_1_0 = "1.0";
142const std::string tagXMLLease = "Lease";
143const std::string tagXMLLeaseAttributeMac = "mac";
144const std::string tagXMLLeaseAttributeNetwork = "network";
145const std::string tagXMLLeaseAddress = "Address";
146const std::string tagXMLAddressAttributeValue = "value";
147const std::string tagXMLLeaseTime = "Time";
148const std::string tagXMLTimeAttributeIssued = "issued";
149const std::string tagXMLTimeAttributeExpiration = "expiration";
150const std::string tagXMLLeaseOptions = "Options";
151
152/**
153 * <Leases version="1.0">
154 * <Lease mac="" network=""/>
155 * <Address value=""/>
156 * <Time issued="" expiration=""/>
157 * <options>
158 * <option name="" type=""/>
159 * </option>
160 * </options>
161 * </Lease>
162 * </Leases>
163 */
164int ConfigurationManager::loadFromFile(const std::string& leaseStorageFileName)
165{
166 m->m_leaseStorageFilename = leaseStorageFileName;
167
168 xml::XmlFileParser parser;
169 xml::Document doc;
170
171 try {
172 parser.read(m->m_leaseStorageFilename.c_str(), doc);
173 }
174 catch (...)
175 {
176 return VINF_SUCCESS;
177 }
178
179 /* XML parsing */
180 xml::ElementNode *root = doc.getRootElement();
181
182 if (!root || !root->nameEquals(tagXMLLeases.c_str()))
183 {
184 m->fFileExists = false;
185 return VERR_NOT_FOUND;
186 }
187
188 com::Utf8Str version;
189 if (root)
190 root->getAttributeValue(tagXMLLeasesAttributeVersion.c_str(), version);
191
192 /* XXX: version check */
193 xml::NodesLoop leases(*root);
194
195 bool valueExists;
196 const xml::ElementNode *lease;
197 while ((lease = leases.forAllNodes()))
198 {
199 if (!lease->nameEquals(tagXMLLease.c_str()))
200 continue;
201
202 ClientData *data = new ClientData();
203 Lease l(data);
204 if (l.fromXML(lease))
205 {
206
207 m->m_allocations.insert(MapLease2Ip4AddressPair(l, l.getAddress()));
208
209
210 NetworkConfigEntity *pNetCfg = NULL;
211 Client c(data);
212 int rc = g_RootConfig->match(c, (BaseConfigEntity **)&pNetCfg);
213 Assert(rc >= 0 && pNetCfg);
214
215 l.setConfig(pNetCfg);
216
217 m->m_clients.push_back(c);
218 }
219 }
220
221 return VINF_SUCCESS;
222}
223
224
225int ConfigurationManager::saveToFile()
226{
227 if (m->m_leaseStorageFilename.empty())
228 return VINF_SUCCESS;
229
230 xml::Document doc;
231
232 xml::ElementNode *root = doc.createRootElement(tagXMLLeases.c_str());
233 if (!root)
234 return VERR_INTERNAL_ERROR;
235
236 root->setAttribute(tagXMLLeasesAttributeVersion.c_str(), tagXMLLeasesVersion_1_0.c_str());
237
238 for(MapLease2Ip4AddressConstIterator it = m->m_allocations.begin();
239 it != m->m_allocations.end(); ++it)
240 {
241 xml::ElementNode *lease = root->createChild(tagXMLLease.c_str());
242 if (!it->first.toXML(lease))
243 {
244 /* XXX: todo logging + error handling */
245 }
246 }
247
248 try {
249 xml::XmlFileWriter writer(doc);
250 writer.write(m->m_leaseStorageFilename.c_str(), true);
251 } catch(...){}
252
253 return VINF_SUCCESS;
254}
255
256
257int ConfigurationManager::extractRequestList(PCRTNETBOOTP pDhcpMsg, size_t cbDhcpMsg, RawOption& rawOpt)
258{
259 return ConfigurationManager::findOption(RTNET_DHCP_OPT_PARAM_REQ_LIST, pDhcpMsg, cbDhcpMsg, rawOpt);
260}
261
262
263Client ConfigurationManager::getClientByDhcpPacket(const RTNETBOOTP *pDhcpMsg, size_t cbDhcpMsg)
264{
265
266 VecClientIterator it;
267 bool fDhcpValid = false;
268 uint8_t uMsgType = 0;
269
270 fDhcpValid = RTNetIPv4IsDHCPValid(NULL, pDhcpMsg, cbDhcpMsg, &uMsgType);
271 AssertReturn(fDhcpValid, Client::NullClient);
272
273 LogFlowFunc(("dhcp:mac:%RTmac\n", &pDhcpMsg->bp_chaddr.Mac));
274 /* 1st. client IDs */
275 for ( it = m->m_clients.begin();
276 it != m->m_clients.end();
277 ++it)
278 {
279 if ((*it) == pDhcpMsg->bp_chaddr.Mac)
280 {
281 LogFlowFunc(("client:mac:%RTmac\n", it->getMacAddress()));
282 /* check timestamp that request wasn't expired. */
283 return (*it);
284 }
285 }
286
287 if (it == m->m_clients.end())
288 {
289 /* We hasn't got any session for this client */
290 Client c;
291 c.initWithMac(pDhcpMsg->bp_chaddr.Mac);
292 m->m_clients.push_back(c);
293 return m->m_clients.back();
294 }
295
296 return Client::NullClient;
297}
298
299/**
300 * Finds an option.
301 *
302 * @returns On success, a pointer to the first byte in the option data (no none
303 * then it'll be the byte following the 0 size field) and *pcbOpt set
304 * to the option length.
305 * On failure, NULL is returned and *pcbOpt unchanged.
306 *
307 * @param uOption The option to search for.
308 * @param pDhcpMsg The DHCP message.
309 * that this is adjusted if the option length is larger
310 * than the message buffer.
311 */
312int
313ConfigurationManager::findOption(uint8_t uOption, PCRTNETBOOTP pDhcpMsg, size_t cbDhcpMsg, RawOption& opt)
314{
315 Assert(uOption != RTNET_DHCP_OPT_PAD);
316
317 /*
318 * Validate the DHCP bits and figure the max size of the options in the vendor field.
319 */
320 if (cbDhcpMsg <= RT_UOFFSETOF(RTNETBOOTP, bp_vend.Dhcp.dhcp_opts))
321 return VERR_INVALID_PARAMETER;
322
323 if (pDhcpMsg->bp_vend.Dhcp.dhcp_cookie != RT_H2N_U32_C(RTNET_DHCP_COOKIE))
324 return VERR_INVALID_PARAMETER;
325
326 size_t cbLeft = cbDhcpMsg - RT_UOFFSETOF(RTNETBOOTP, bp_vend.Dhcp.dhcp_opts);
327 if (cbLeft > RTNET_DHCP_OPT_SIZE)
328 cbLeft = RTNET_DHCP_OPT_SIZE;
329
330 /*
331 * Search the vendor field.
332 */
333 bool fExtended = false;
334 uint8_t const *pb = &pDhcpMsg->bp_vend.Dhcp.dhcp_opts[0];
335 while (pb && cbLeft > 0)
336 {
337 uint8_t uCur = *pb;
338 if (uCur == RTNET_DHCP_OPT_PAD)
339 {
340 cbLeft--;
341 pb++;
342 }
343 else if (cbLeft <= 1)
344 break;
345 else
346 {
347 size_t cbCur = pb[1];
348 if (cbCur > cbLeft - 2)
349 cbCur = cbLeft - 2;
350 if (uCur == uOption)
351 {
352 opt.u8OptId = uCur;
353 memcpy(opt.au8RawOpt, pb+2, cbCur);
354 opt.cbRawOpt = cbCur;
355 return VINF_SUCCESS;
356 }
357 pb += cbCur + 2;
358 cbLeft -= cbCur - 2;
359 }
360 }
361
362 /** @todo search extended dhcp option field(s) when present */
363
364 return VERR_NOT_FOUND;
365}
366
367
368/**
369 * We bind lease for client till it continue with it on DHCPREQUEST.
370 */
371Lease ConfigurationManager::allocateLease4Client(const Client& client, PCRTNETBOOTP pDhcpMsg, size_t cbDhcpMsg)
372{
373 {
374 /**
375 * This mean that client has already bound or commited lease.
376 * If we've it happens it means that we received DHCPDISCOVER twice.
377 */
378 const Lease l = client.lease();
379 if (l != Lease::NullLease)
380 {
381 /* Here we should take lease from the m_allocation which was feed with leases
382 * on start
383 */
384 if (l.isExpired())
385 {
386 expireLease4Client(const_cast<Client&>(client));
387 if (!l.isExpired())
388 return l;
389 }
390 else
391 {
392 AssertReturn(l.getAddress().u != 0, Lease::NullLease);
393 return l;
394 }
395 }
396 }
397
398 RTNETADDRIPV4 hintAddress;
399 RawOption opt;
400 NetworkConfigEntity *pNetCfg;
401
402 Client cl(client);
403 AssertReturn(g_RootConfig->match(cl, (BaseConfigEntity **)&pNetCfg) > 0, Lease::NullLease);
404
405 /* DHCPDISCOVER MAY contain request address */
406 hintAddress.u = 0;
407 int rc = findOption(RTNET_DHCP_OPT_REQ_ADDR, pDhcpMsg, cbDhcpMsg, opt);
408 if (RT_SUCCESS(rc))
409 {
410 hintAddress.u = *(uint32_t *)opt.au8RawOpt;
411 if ( RT_H2N_U32(hintAddress.u) < RT_H2N_U32(pNetCfg->lowerIp().u)
412 || RT_H2N_U32(hintAddress.u) > RT_H2N_U32(pNetCfg->upperIp().u))
413 hintAddress.u = 0; /* clear hint */
414 }
415
416 if ( hintAddress.u
417 && !isAddressTaken(hintAddress))
418 {
419 Lease l(cl);
420 l.setConfig(pNetCfg);
421 l.setAddress(hintAddress);
422 m->m_allocations.insert(MapLease2Ip4AddressPair(l, hintAddress));
423 return l;
424 }
425
426 uint32_t u32 = 0;
427 for(u32 = RT_H2N_U32(pNetCfg->lowerIp().u);
428 u32 <= RT_H2N_U32(pNetCfg->upperIp().u);
429 ++u32)
430 {
431 RTNETADDRIPV4 address;
432 address.u = RT_H2N_U32(u32);
433 if (!isAddressTaken(address))
434 {
435 Lease l(cl);
436 l.setConfig(pNetCfg);
437 l.setAddress(address);
438 m->m_allocations.insert(MapLease2Ip4AddressPair(l, address));
439 return l;
440 }
441 }
442
443 return Lease::NullLease;
444}
445
446
447int ConfigurationManager::commitLease4Client(Client& client)
448{
449 Lease l = client.lease();
450 AssertReturn(l != Lease::NullLease, VERR_INTERNAL_ERROR);
451
452 l.bindingPhase(false);
453 const NetworkConfigEntity *pCfg = l.getConfig();
454
455 AssertPtr(pCfg);
456 l.setExpiration(pCfg->expirationPeriod());
457 l.phaseStart(RTTimeMilliTS());
458
459 saveToFile();
460
461 return VINF_SUCCESS;
462}
463
464
465int ConfigurationManager::expireLease4Client(Client& client)
466{
467 Lease l = client.lease();
468 AssertReturn(l != Lease::NullLease, VERR_INTERNAL_ERROR);
469
470 if (l.isInBindingPhase())
471 {
472
473 MapLease2Ip4AddressIterator it = m->m_allocations.find(l);
474 AssertReturn(it != m->m_allocations.end(), VERR_NOT_FOUND);
475
476 /*
477 * XXX: perhaps it better to keep this allocation ????
478 */
479 m->m_allocations.erase(it);
480
481 l.expire();
482 return VINF_SUCCESS;
483 }
484
485 l = Lease(client); /* re-new */
486 return VINF_SUCCESS;
487}
488
489bool ConfigurationManager::isAddressTaken(const RTNETADDRIPV4& addr, Lease& lease)
490{
491 MapLease2Ip4AddressIterator it;
492
493 for (it = m->m_allocations.begin();
494 it != m->m_allocations.end();
495 ++it)
496 {
497 if (it->second.u == addr.u)
498 {
499 if (lease != Lease::NullLease)
500 lease = it->first;
501
502 return true;
503 }
504 }
505 lease = Lease::NullLease;
506 return false;
507}
508
509
510NetworkConfigEntity *ConfigurationManager::addNetwork(NetworkConfigEntity *,
511 const RTNETADDRIPV4& networkId,
512 const RTNETADDRIPV4& netmask,
513 RTNETADDRIPV4& LowerAddress,
514 RTNETADDRIPV4& UpperAddress)
515{
516 static int id;
517 char name[64];
518
519 RTStrPrintf(name, RT_ELEMENTS(name), "network-%d", id);
520 std::string strname(name);
521 id++;
522
523
524 if (!LowerAddress.u)
525 LowerAddress = networkId;
526
527 if (!UpperAddress.u)
528 UpperAddress.u = networkId.u | (~netmask.u);
529
530 return new NetworkConfigEntity(strname,
531 g_RootConfig,
532 g_AnyClient,
533 5,
534 networkId,
535 netmask,
536 LowerAddress,
537 UpperAddress);
538}
539
540HostConfigEntity *ConfigurationManager::addHost(NetworkConfigEntity* pCfg,
541 const RTNETADDRIPV4& address,
542 ClientMatchCriteria *criteria)
543{
544 static int id;
545 char name[64];
546
547 RTStrPrintf(name, RT_ELEMENTS(name), "host-%d", id);
548 std::string strname(name);
549 id++;
550
551 return new HostConfigEntity(address, strname, pCfg, criteria);
552}
553
554int ConfigurationManager::addToAddressList(uint8_t u8OptId, RTNETADDRIPV4& address)
555{
556 switch(u8OptId)
557 {
558 case RTNET_DHCP_OPT_DNS:
559 m->m_nameservers.push_back(address);
560 break;
561 case RTNET_DHCP_OPT_ROUTERS:
562 m->m_routers.push_back(address);
563 break;
564 default:
565 Log(("dhcp-opt: list (%d) unsupported\n", u8OptId));
566 }
567 return VINF_SUCCESS;
568}
569
570
571int ConfigurationManager::flushAddressList(uint8_t u8OptId)
572{
573 switch(u8OptId)
574 {
575 case RTNET_DHCP_OPT_DNS:
576 m->m_nameservers.clear();
577 break;
578 case RTNET_DHCP_OPT_ROUTERS:
579 m->m_routers.clear();
580 break;
581 default:
582 Log(("dhcp-opt: list (%d) unsupported\n", u8OptId));
583 }
584 return VINF_SUCCESS;
585}
586
587
588const Ipv4AddressContainer& ConfigurationManager::getAddressList(uint8_t u8OptId)
589{
590 switch(u8OptId)
591 {
592 case RTNET_DHCP_OPT_DNS:
593 return m->m_nameservers;
594
595 case RTNET_DHCP_OPT_ROUTERS:
596 return m->m_routers;
597
598 }
599 /* XXX: Grrr !!! */
600 return m_empty;
601}
602
603
604int ConfigurationManager::setString(uint8_t u8OptId, const std::string& str)
605{
606 switch (u8OptId)
607 {
608 case RTNET_DHCP_OPT_DOMAIN_NAME:
609 m->m_domainName = str;
610 break;
611 default:
612 break;
613 }
614
615 return VINF_SUCCESS;
616}
617
618
619const std::string& ConfigurationManager::getString(uint8_t u8OptId)
620{
621 switch (u8OptId)
622 {
623 case RTNET_DHCP_OPT_DOMAIN_NAME:
624 if (m->m_domainName.length())
625 return m->m_domainName;
626 else
627 return m_noString;
628 default:
629 break;
630 }
631
632 return m_noString;
633}
634
635
636void ConfigurationManager::init()
637{
638 m = new ConfigurationManager::Data();
639}
640
641
642ConfigurationManager::~ConfigurationManager() { if (m) delete m; }
643
644/**
645 * Network manager
646 */
647struct NetworkManager::Data
648{
649 Data()
650 {
651 RT_ZERO(BootPReplyMsg);
652 cbBooPReplyMsg = 0;
653
654 m_pSession = NIL_RTR0PTR;
655 m_pIfBuf = NULL;
656 m_OurAddress.u = 0;
657 m_OurNetmask.u = 0;
658 RT_ZERO(m_OurMac);
659 }
660
661 union {
662 RTNETBOOTP BootPHeader;
663 uint8_t au8Storage[1024];
664 } BootPReplyMsg;
665 int cbBooPReplyMsg;
666
667 /* XXX: artifacts should be hidden or removed from here. */
668 PSUPDRVSESSION m_pSession;
669 INTNETIFHANDLE m_hIf;
670 PINTNETBUF m_pIfBuf;
671
672 RTNETADDRIPV4 m_OurAddress;
673 RTNETADDRIPV4 m_OurNetmask;
674 RTMAC m_OurMac;
675};
676
677
678NetworkManager::NetworkManager():m(NULL)
679{
680 m = new NetworkManager::Data();
681}
682
683
684NetworkManager::~NetworkManager()
685{
686 delete m;
687 m = NULL;
688}
689
690
691NetworkManager *NetworkManager::getNetworkManager()
692{
693 if (!g_NetworkManager)
694 g_NetworkManager = new NetworkManager();
695
696 return g_NetworkManager;
697}
698
699
700const RTNETADDRIPV4& NetworkManager::getOurAddress() const
701{
702 return m->m_OurAddress;
703}
704
705
706const RTNETADDRIPV4& NetworkManager::getOurNetmask() const
707{
708 return m->m_OurNetmask;
709}
710
711
712const RTMAC& NetworkManager::getOurMac() const
713{
714 return m->m_OurMac;
715}
716
717
718void NetworkManager::setOurAddress(const RTNETADDRIPV4& aAddress)
719{
720 m->m_OurAddress = aAddress;
721}
722
723
724void NetworkManager::setOurNetmask(const RTNETADDRIPV4& aNetmask)
725{
726 m->m_OurNetmask = aNetmask;
727}
728
729
730void NetworkManager::setOurMac(const RTMAC& aMac)
731{
732 m->m_OurMac = aMac;
733}
734
735
736void NetworkManager::setSession(PSUPDRVSESSION aSession)
737{
738 m->m_pSession = aSession;
739}
740
741
742void NetworkManager::setInterface(INTNETIFHANDLE aIf)
743{
744 m->m_hIf = aIf;
745}
746
747
748void NetworkManager::setRingBuffer(PINTNETBUF aBuf)
749{
750 m->m_pIfBuf = aBuf;
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(2);
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);
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(2);
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);
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 = VBoxNetUDPBroadcast(m->m_pSession,
971 m->m_hIf,
972 m->m_pIfBuf,
973 m->m_OurAddress,
974 &m->m_OurMac,
975 RTNETIPV4_PORT_BOOTPS, /* sender */
976 RTNETIPV4_PORT_BOOTPC,
977 &m->BootPReplyMsg, RTNET_DHCP_NORMAL_SIZE);
978
979 AssertRCReturn(rc,rc);
980
981 return VINF_SUCCESS;
982}
983
984
985int NetworkManager::processParameterReqList(const Client& client, uint8_t *pu8ReqList, int cReqList)
986{
987 /* request parameter list */
988 RawOption opt;
989 int idxParam = 0;
990
991 uint8_t *pReqList = pu8ReqList;
992
993 const Lease const_l = client.lease();
994 Lease l = Lease(const_l);
995
996 const NetworkConfigEntity *pNetCfg = l.getConfig();
997
998 for (idxParam = 0; idxParam < cReqList; ++idxParam)
999 {
1000
1001 bool fIgnore = false;
1002 RT_ZERO(opt);
1003 opt.u8OptId = pReqList[idxParam];
1004
1005 switch(pReqList[idxParam])
1006 {
1007 case RTNET_DHCP_OPT_SUBNET_MASK:
1008 ((PRTNETADDRIPV4)opt.au8RawOpt)->u = pNetCfg->netmask().u;
1009 opt.cbRawOpt = sizeof(RTNETADDRIPV4);
1010
1011 break;
1012
1013 case RTNET_DHCP_OPT_ROUTERS:
1014 case RTNET_DHCP_OPT_DNS:
1015 {
1016 const Ipv4AddressContainer lst =
1017 g_ConfigurationManager->getAddressList(pReqList[idxParam]);
1018 PRTNETADDRIPV4 pAddresses = (PRTNETADDRIPV4)&opt.au8RawOpt[0];
1019
1020 for (Ipv4AddressConstIterator it = lst.begin();
1021 it != lst.end();
1022 ++it)
1023 {
1024 *pAddresses = (*it);
1025 pAddresses++;
1026 opt.cbRawOpt += sizeof(RTNETADDRIPV4);
1027 }
1028
1029 if (lst.empty())
1030 fIgnore = true;
1031 }
1032 break;
1033 case RTNET_DHCP_OPT_DOMAIN_NAME:
1034 {
1035 std::string domainName = g_ConfigurationManager->getString(pReqList[idxParam]);
1036 if (domainName == g_ConfigurationManager->m_noString)
1037 {
1038 fIgnore = true;
1039 break;
1040 }
1041
1042 char *pszDomainName = (char *)&opt.au8RawOpt[0];
1043
1044 strcpy(pszDomainName, domainName.c_str());
1045 opt.cbRawOpt = domainName.length();
1046 }
1047 break;
1048 default:
1049 Log(("opt: %d is ignored\n", pReqList[idxParam]));
1050 fIgnore = true;
1051 break;
1052 }
1053
1054 if (!fIgnore)
1055 l.options().insert(std::map<uint8_t, RawOption>::value_type(opt.u8OptId, opt));
1056
1057 }
1058
1059 return VINF_SUCCESS;
1060}
1061
1062/* Utility */
1063bool operator== (const RTMAC& lhs, const RTMAC& rhs)
1064{
1065 return ( lhs.au16[0] == rhs.au16[0]
1066 && lhs.au16[1] == rhs.au16[1]
1067 && lhs.au16[2] == rhs.au16[2]);
1068}
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
1231MapOptionId2RawOption& Lease::options()
1232{
1233 return m->options;
1234}
1235
1236
1237Lease::Lease(ClientData *pd):m(SharedPtr<ClientData>(pd)){}
1238
1239
1240bool Lease::toXML(xml::ElementNode *node) const
1241{
1242 bool valueAddition = node->setAttribute(tagXMLLeaseAttributeMac.c_str(), com::Utf8StrFmt("%RTmac", &m->m_mac));
1243 if (!valueAddition) return false;
1244
1245 valueAddition = node->setAttribute(tagXMLLeaseAttributeNetwork.c_str(), com::Utf8StrFmt("%RTnaipv4", m->m_network));
1246 if (!valueAddition) return false;
1247
1248 xml::ElementNode *address = node->createChild(tagXMLLeaseAddress.c_str());
1249 if (!address) return false;
1250
1251 valueAddition = address->setAttribute(tagXMLAddressAttributeValue.c_str(), com::Utf8StrFmt("%RTnaipv4", m->m_address));
1252 if (!valueAddition) return false;
1253
1254 xml::ElementNode *time = node->createChild(tagXMLLeaseTime.c_str());
1255 if (!time) return false;
1256
1257 valueAddition = time->setAttribute(tagXMLTimeAttributeIssued.c_str(),
1258 m->u64TimestampLeasingStarted);
1259 if (!valueAddition) return false;
1260
1261 valueAddition = time->setAttribute(tagXMLTimeAttributeExpiration.c_str(),
1262 m->u32LeaseExpirationPeriod);
1263 if (!valueAddition) return false;
1264
1265 return true;
1266}
1267
1268
1269bool Lease::fromXML(const xml::ElementNode *node)
1270{
1271 com::Utf8Str mac;
1272 bool valueExists = node->getAttributeValue(tagXMLLeaseAttributeMac.c_str(), mac);
1273 if (!valueExists) return false;
1274 int rc = RTNetStrToMacAddr(mac.c_str(), &m->m_mac);
1275 if (RT_FAILURE(rc)) return false;
1276
1277 com::Utf8Str network;
1278 valueExists = node->getAttributeValue(tagXMLLeaseAttributeNetwork.c_str(), network);
1279 if (!valueExists) return false;
1280 rc = RTNetStrToIPv4Addr(network.c_str(), &m->m_network);
1281 if (RT_FAILURE(rc)) return false;
1282
1283 /* Address */
1284 const xml::ElementNode *address = node->findChildElement(tagXMLLeaseAddress.c_str());
1285 if (!address) return false;
1286 com::Utf8Str addressValue;
1287 valueExists = address->getAttributeValue(tagXMLAddressAttributeValue.c_str(), addressValue);
1288 if (!valueExists) return false;
1289 rc = RTNetStrToIPv4Addr(addressValue.c_str(), &m->m_address);
1290
1291 /* Time */
1292 const xml::ElementNode *time = node->findChildElement(tagXMLLeaseTime.c_str());
1293 if (!time) return false;
1294
1295 valueExists = time->getAttributeValue(tagXMLTimeAttributeIssued.c_str(),
1296 &m->u64TimestampLeasingStarted);
1297 if (!valueExists) return false;
1298 m->fBinding = false;
1299
1300 valueExists = time->getAttributeValue(tagXMLTimeAttributeExpiration.c_str(),
1301 &m->u32LeaseExpirationPeriod);
1302 if (!valueExists) return false;
1303
1304 m->fHasLease = true;
1305 return true;
1306}
1307
1308
1309const Lease Lease::NullLease;
1310
1311
1312const 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