VirtualBox

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

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

DHCP: G/c lines.

  • 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 49566 2013-11-20 08:49: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
700/**
701 * Network manager creates DHCPOFFER datagramm
702 */
703int NetworkManager::offer4Client(const Client& client, uint32_t u32Xid,
704 uint8_t *pu8ReqList, int cReqList)
705{
706 Lease l(client); /* XXX: oh, it looks badly, but now we have lease */
707 prepareReplyPacket4Client(client, u32Xid);
708
709 RTNETADDRIPV4 address = l.getAddress();
710 m->BootPReplyMsg.BootPHeader.bp_yiaddr = address;
711
712 /* Ubuntu ???*/
713 m->BootPReplyMsg.BootPHeader.bp_ciaddr = address;
714
715 /* options:
716 * - IP lease time
717 * - message type
718 * - server identifier
719 */
720 RawOption opt;
721 RT_ZERO(opt);
722
723 std::vector<RawOption> extra(2);
724 opt.u8OptId = RTNET_DHCP_OPT_MSG_TYPE;
725 opt.au8RawOpt[0] = RTNET_DHCP_MT_OFFER;
726 opt.cbRawOpt = 1;
727 extra.push_back(opt);
728
729 opt.u8OptId = RTNET_DHCP_OPT_LEASE_TIME;
730
731 const NetworkConfigEntity *pCfg = l.getConfig();
732 AssertPtr(pCfg);
733
734 *(uint32_t *)opt.au8RawOpt = RT_H2N_U32(pCfg->expirationPeriod());
735 opt.cbRawOpt = sizeof(RTNETADDRIPV4);
736
737 extra.push_back(opt);
738
739 processParameterReqList(client, pu8ReqList, cReqList);
740
741 return doReply(client, extra);
742}
743
744/**
745 * Network manager creates DHCPACK
746 */
747int NetworkManager::ack(const Client& client, uint32_t u32Xid,
748 uint8_t *pu8ReqList, int cReqList)
749{
750 RTNETADDRIPV4 address;
751
752 prepareReplyPacket4Client(client, u32Xid);
753
754 Lease l = client.lease();
755 address = l.getAddress();
756 m->BootPReplyMsg.BootPHeader.bp_ciaddr = address;
757
758
759 /* rfc2131 4.3.1 is about DHCPDISCOVER and this value is equal to ciaddr from
760 * DHCPREQUEST or 0 ...
761 * XXX: Using addressHint is not correct way to initialize [cy]iaddress...
762 */
763 m->BootPReplyMsg.BootPHeader.bp_ciaddr = address;
764 m->BootPReplyMsg.BootPHeader.bp_yiaddr = address;
765
766 Assert(m->BootPReplyMsg.BootPHeader.bp_yiaddr.u);
767
768 /* options:
769 * - IP address lease time (if DHCPREQUEST)
770 * - message type
771 * - server identifier
772 */
773 RawOption opt;
774 RT_ZERO(opt);
775
776 std::vector<RawOption> extra(2);
777 opt.u8OptId = RTNET_DHCP_OPT_MSG_TYPE;
778 opt.au8RawOpt[0] = RTNET_DHCP_MT_ACK;
779 opt.cbRawOpt = 1;
780 extra.push_back(opt);
781
782 /*
783 * XXX: lease time should be conditional. If on dhcprequest then tim should be provided,
784 * else on dhcpinform it mustn't.
785 */
786 opt.u8OptId = RTNET_DHCP_OPT_LEASE_TIME;
787 *(uint32_t *)opt.au8RawOpt = RT_H2N_U32(l.getExpiration());
788 opt.cbRawOpt = sizeof(RTNETADDRIPV4);
789 extra.push_back(opt);
790
791 processParameterReqList(client, pu8ReqList, cReqList);
792
793 return doReply(client, extra);
794}
795
796/**
797 * Network manager creates DHCPNAK
798 */
799int NetworkManager::nak(const Client& client, uint32_t u32Xid)
800{
801
802 Lease l = client.lease();
803 if (l == Lease::NullLease)
804 return VERR_INTERNAL_ERROR;
805
806 prepareReplyPacket4Client(client, u32Xid);
807
808 /* this field filed in prepareReplyPacket4Session, and
809 * RFC 2131 require to have it zero fo NAK.
810 */
811 m->BootPReplyMsg.BootPHeader.bp_yiaddr.u = 0;
812
813 /* options:
814 * - message type (if DHCPREQUEST)
815 * - server identifier
816 */
817 RawOption opt;
818 std::vector<RawOption> extra;
819
820 opt.u8OptId = RTNET_DHCP_OPT_MSG_TYPE;
821 opt.au8RawOpt[0] = RTNET_DHCP_MT_NAC;
822 opt.cbRawOpt = 1;
823 extra.push_back(opt);
824
825 return doReply(client, extra);
826}
827
828
829const RTNETADDRIPV4& NetworkManager::getOurAddress() const
830{
831 return m->m_OurAddress;
832}
833
834
835const RTNETADDRIPV4& NetworkManager::getOurNetmask() const
836{
837 return m->m_OurNetmask;
838}
839
840
841const RTMAC& NetworkManager::getOurMac() const
842{
843 return m->m_OurMac;
844}
845
846
847void NetworkManager::setOurAddress(const RTNETADDRIPV4& aAddress)
848{
849 m->m_OurAddress = aAddress;
850}
851
852
853void NetworkManager::setOurNetmask(const RTNETADDRIPV4& aNetmask)
854{
855 m->m_OurNetmask = aNetmask;
856}
857
858
859void NetworkManager::setOurMac(const RTMAC& aMac)
860{
861 m->m_OurMac = aMac;
862}
863
864
865void NetworkManager::setSession(PSUPDRVSESSION aSession)
866{
867 m->m_pSession = aSession;
868}
869
870
871void NetworkManager::setInterface(INTNETIFHANDLE aIf)
872{
873 m->m_hIf = aIf;
874}
875
876
877void NetworkManager::setRingBuffer(PINTNETBUF aBuf)
878{
879 m->m_pIfBuf = aBuf;
880}
881
882/**
883 *
884 */
885int NetworkManager::prepareReplyPacket4Client(const Client& client, uint32_t u32Xid)
886{
887 RT_ZERO(m->BootPReplyMsg);
888
889 m->BootPReplyMsg.BootPHeader.bp_op = RTNETBOOTP_OP_REPLY;
890 m->BootPReplyMsg.BootPHeader.bp_htype = RTNET_ARP_ETHER;
891 m->BootPReplyMsg.BootPHeader.bp_hlen = sizeof(RTMAC);
892 m->BootPReplyMsg.BootPHeader.bp_hops = 0;
893 m->BootPReplyMsg.BootPHeader.bp_xid = u32Xid;
894 m->BootPReplyMsg.BootPHeader.bp_secs = 0;
895 /* XXX: bp_flags should be processed specially */
896 m->BootPReplyMsg.BootPHeader.bp_flags = 0;
897 m->BootPReplyMsg.BootPHeader.bp_ciaddr.u = 0;
898 m->BootPReplyMsg.BootPHeader.bp_giaddr.u = 0;
899
900 m->BootPReplyMsg.BootPHeader.bp_chaddr.Mac = client.getMacAddress();
901
902 const Lease l = client.lease();
903 m->BootPReplyMsg.BootPHeader.bp_yiaddr = l.getAddress();
904 m->BootPReplyMsg.BootPHeader.bp_siaddr.u = 0;
905
906
907 m->BootPReplyMsg.BootPHeader.bp_vend.Dhcp.dhcp_cookie = RT_H2N_U32_C(RTNET_DHCP_COOKIE);
908
909 memset(&m->BootPReplyMsg.BootPHeader.bp_vend.Dhcp.dhcp_opts[0],
910 '\0',
911 RTNET_DHCP_OPT_SIZE);
912
913 return VINF_SUCCESS;
914}
915
916
917int NetworkManager::doReply(const Client& client, const std::vector<RawOption>& extra)
918{
919 int rc;
920
921 /*
922 Options....
923 */
924 VBoxNetDhcpWriteCursor Cursor(&m->BootPReplyMsg.BootPHeader, RTNET_DHCP_NORMAL_SIZE);
925
926 /* The basics */
927
928 Cursor.optIPv4Addr(RTNET_DHCP_OPT_SERVER_ID, m->m_OurAddress);
929
930 const Lease l = client.lease();
931 const std::map<uint8_t, RawOption>& options = l.options();
932
933 for(std::vector<RawOption>::const_iterator it = extra.begin();
934 it != extra.end(); ++it)
935 {
936 if (!Cursor.begin(it->u8OptId, it->cbRawOpt))
937 break;
938 Cursor.put(it->au8RawOpt, it->cbRawOpt);
939
940 }
941
942 for(std::map<uint8_t, RawOption>::const_iterator it = options.begin();
943 it != options.end(); ++it)
944 {
945 if (!Cursor.begin(it->second.u8OptId, it->second.cbRawOpt))
946 break;
947 Cursor.put(it->second.au8RawOpt, it->second.cbRawOpt);
948
949 }
950
951 Cursor.optEnd();
952
953 /*
954 */
955#if 0
956 /** @todo need to see someone set this flag to check that it's correct. */
957 if (!(pDhcpMsg->bp_flags & RTNET_DHCP_FLAGS_NO_BROADCAST))
958 {
959 rc = VBoxNetUDPUnicast(m_pSession,
960 m_hIf,
961 m_pIfBuf,
962 m_OurAddress,
963 &m_OurMac,
964 RTNETIPV4_PORT_BOOTPS, /* sender */
965 IPv4AddrBrdCast,
966 &BootPReplyMsg.BootPHeader->bp_chaddr.Mac,
967 RTNETIPV4_PORT_BOOTPC, /* receiver */
968 &BootPReplyMsg, cbBooPReplyMsg);
969 }
970 else
971#endif
972 rc = VBoxNetUDPBroadcast(m->m_pSession,
973 m->m_hIf,
974 m->m_pIfBuf,
975 m->m_OurAddress,
976 &m->m_OurMac,
977 RTNETIPV4_PORT_BOOTPS, /* sender */
978 RTNETIPV4_PORT_BOOTPC,
979 &m->BootPReplyMsg, RTNET_DHCP_NORMAL_SIZE);
980
981 AssertRCReturn(rc,rc);
982
983 return VINF_SUCCESS;
984}
985
986
987int NetworkManager::processParameterReqList(const Client& client, uint8_t *pu8ReqList, int cReqList)
988{
989 /* request parameter list */
990 RawOption opt;
991 int idxParam = 0;
992
993 uint8_t *pReqList = pu8ReqList;
994
995 const Lease const_l = client.lease();
996 Lease l = Lease(const_l);
997
998 const NetworkConfigEntity *pNetCfg = l.getConfig();
999
1000 for (idxParam = 0; idxParam < cReqList; ++idxParam)
1001 {
1002
1003 bool fIgnore = false;
1004 RT_ZERO(opt);
1005 opt.u8OptId = pReqList[idxParam];
1006
1007 switch(pReqList[idxParam])
1008 {
1009 case RTNET_DHCP_OPT_SUBNET_MASK:
1010 ((PRTNETADDRIPV4)opt.au8RawOpt)->u = pNetCfg->netmask().u;
1011 opt.cbRawOpt = sizeof(RTNETADDRIPV4);
1012
1013 break;
1014
1015 case RTNET_DHCP_OPT_ROUTERS:
1016 case RTNET_DHCP_OPT_DNS:
1017 {
1018 const Ipv4AddressContainer lst =
1019 g_ConfigurationManager->getAddressList(pReqList[idxParam]);
1020 PRTNETADDRIPV4 pAddresses = (PRTNETADDRIPV4)&opt.au8RawOpt[0];
1021
1022 for (Ipv4AddressConstIterator it = lst.begin();
1023 it != lst.end();
1024 ++it)
1025 {
1026 *pAddresses = (*it);
1027 pAddresses++;
1028 opt.cbRawOpt += sizeof(RTNETADDRIPV4);
1029 }
1030
1031 if (lst.empty())
1032 fIgnore = true;
1033 }
1034 break;
1035 case RTNET_DHCP_OPT_DOMAIN_NAME:
1036 {
1037 std::string domainName = g_ConfigurationManager->getString(pReqList[idxParam]);
1038 if (domainName == g_ConfigurationManager->m_noString)
1039 {
1040 fIgnore = true;
1041 break;
1042 }
1043
1044 char *pszDomainName = (char *)&opt.au8RawOpt[0];
1045
1046 strcpy(pszDomainName, domainName.c_str());
1047 opt.cbRawOpt = domainName.length();
1048 }
1049 break;
1050 default:
1051 Log(("opt: %d is ignored\n", pReqList[idxParam]));
1052 fIgnore = true;
1053 break;
1054 }
1055
1056 if (!fIgnore)
1057 l.options().insert(std::map<uint8_t, RawOption>::value_type(opt.u8OptId, opt));
1058
1059 }
1060
1061 return VINF_SUCCESS;
1062}
1063
1064/* Utility */
1065bool operator== (const RTMAC& lhs, const RTMAC& rhs)
1066{
1067 return ( lhs.au16[0] == rhs.au16[0]
1068 && lhs.au16[1] == rhs.au16[1]
1069 && lhs.au16[2] == rhs.au16[2]);
1070}
1071
1072
1073/* Client */
1074Client::Client()
1075{
1076 m = SharedPtr<ClientData>();
1077}
1078
1079
1080void Client::initWithMac(const RTMAC& mac)
1081{
1082 m = SharedPtr<ClientData>(new ClientData());
1083 m->m_mac = mac;
1084}
1085
1086
1087bool Client::operator== (const RTMAC& mac) const
1088{
1089 return (m.get() && m->m_mac == mac);
1090}
1091
1092
1093const RTMAC& Client::getMacAddress() const
1094{
1095 return m->m_mac;
1096}
1097
1098
1099Lease Client::lease()
1100{
1101 if (!m.get()) return Lease::NullLease;
1102
1103 if (m->fHasLease)
1104 return Lease(*this);
1105 else
1106 return Lease::NullLease;
1107}
1108
1109
1110const Lease Client::lease() const
1111{
1112 return const_cast<Client *>(this)->lease();
1113}
1114
1115
1116Client::Client(ClientData *data):m(SharedPtr<ClientData>(data)){}
1117
1118/* Lease */
1119Lease::Lease()
1120{
1121 m = SharedPtr<ClientData>();
1122}
1123
1124
1125Lease::Lease (const Client& c)
1126{
1127 m = SharedPtr<ClientData>(c.m);
1128 if ( !m->fHasLease
1129 || ( isExpired()
1130 && !isInBindingPhase()))
1131 {
1132 m->fHasLease = true;
1133 m->fBinding = true;
1134 phaseStart(RTTimeMilliTS());
1135 }
1136}
1137
1138
1139bool Lease::isExpired() const
1140{
1141 AssertPtrReturn(m.get(), false);
1142
1143 if (!m->fBinding)
1144 return (ASMDivU64ByU32RetU32(RTTimeMilliTS() - m->u64TimestampLeasingStarted, 1000)
1145 > m->u32LeaseExpirationPeriod);
1146 else
1147 return (ASMDivU64ByU32RetU32(RTTimeMilliTS() - m->u64TimestampBindingStarted, 1000)
1148 > m->u32BindExpirationPeriod);
1149}
1150
1151
1152void Lease::expire()
1153{
1154 /* XXX: TODO */
1155}
1156
1157
1158void Lease::phaseStart(uint64_t u64Start)
1159{
1160 if (m->fBinding)
1161 m->u64TimestampBindingStarted = u64Start;
1162 else
1163 m->u64TimestampLeasingStarted = u64Start;
1164}
1165
1166
1167void Lease::bindingPhase(bool fOnOff)
1168{
1169 m->fBinding = fOnOff;
1170}
1171
1172
1173bool Lease::isInBindingPhase() const
1174{
1175 return m->fBinding;
1176}
1177
1178
1179uint64_t Lease::issued() const
1180{
1181 return m->u64TimestampLeasingStarted;
1182}
1183
1184
1185void Lease::setExpiration(uint32_t exp)
1186{
1187 if (m->fBinding)
1188 m->u32BindExpirationPeriod = exp;
1189 else
1190 m->u32LeaseExpirationPeriod = exp;
1191}
1192
1193
1194uint32_t Lease::getExpiration() const
1195{
1196 if (m->fBinding)
1197 return m->u32BindExpirationPeriod;
1198 else
1199 return m->u32LeaseExpirationPeriod;
1200}
1201
1202
1203RTNETADDRIPV4 Lease::getAddress() const
1204{
1205 return m->m_address;
1206}
1207
1208
1209void Lease::setAddress(RTNETADDRIPV4 address)
1210{
1211 m->m_address = address;
1212}
1213
1214
1215const NetworkConfigEntity *Lease::getConfig() const
1216{
1217 return m->pCfg;
1218}
1219
1220
1221void Lease::setConfig(NetworkConfigEntity *pCfg)
1222{
1223 m->pCfg = pCfg;
1224}
1225
1226
1227const MapOptionId2RawOption& Lease::options() const
1228{
1229 return m->options;
1230}
1231
1232
1233MapOptionId2RawOption& Lease::options()
1234{
1235 return m->options;
1236}
1237
1238
1239Lease::Lease(ClientData *pd):m(SharedPtr<ClientData>(pd)){}
1240
1241
1242bool Lease::toXML(xml::ElementNode *node) const
1243{
1244 bool valueAddition = node->setAttribute(tagXMLLeaseAttributeMac.c_str(), com::Utf8StrFmt("%RTmac", &m->m_mac));
1245 if (!valueAddition) return false;
1246
1247 valueAddition = node->setAttribute(tagXMLLeaseAttributeNetwork.c_str(), com::Utf8StrFmt("%RTnaipv4", m->m_network));
1248 if (!valueAddition) return false;
1249
1250 xml::ElementNode *address = node->createChild(tagXMLLeaseAddress.c_str());
1251 if (!address) return false;
1252
1253 valueAddition = address->setAttribute(tagXMLAddressAttributeValue.c_str(), com::Utf8StrFmt("%RTnaipv4", m->m_address));
1254 if (!valueAddition) return false;
1255
1256 xml::ElementNode *time = node->createChild(tagXMLLeaseTime.c_str());
1257 if (!time) return false;
1258
1259 valueAddition = time->setAttribute(tagXMLTimeAttributeIssued.c_str(),
1260 m->u64TimestampLeasingStarted);
1261 if (!valueAddition) return false;
1262
1263 valueAddition = time->setAttribute(tagXMLTimeAttributeExpiration.c_str(),
1264 m->u32LeaseExpirationPeriod);
1265 if (!valueAddition) return false;
1266
1267 return true;
1268}
1269
1270
1271bool Lease::fromXML(const xml::ElementNode *node)
1272{
1273 com::Utf8Str mac;
1274 bool valueExists = node->getAttributeValue(tagXMLLeaseAttributeMac.c_str(), mac);
1275 if (!valueExists) return false;
1276 int rc = RTNetStrToMacAddr(mac.c_str(), &m->m_mac);
1277 if (RT_FAILURE(rc)) return false;
1278
1279 com::Utf8Str network;
1280 valueExists = node->getAttributeValue(tagXMLLeaseAttributeNetwork.c_str(), network);
1281 if (!valueExists) return false;
1282 rc = RTNetStrToIPv4Addr(network.c_str(), &m->m_network);
1283 if (RT_FAILURE(rc)) return false;
1284
1285 /* Address */
1286 const xml::ElementNode *address = node->findChildElement(tagXMLLeaseAddress.c_str());
1287 if (!address) return false;
1288 com::Utf8Str addressValue;
1289 valueExists = address->getAttributeValue(tagXMLAddressAttributeValue.c_str(), addressValue);
1290 if (!valueExists) return false;
1291 rc = RTNetStrToIPv4Addr(addressValue.c_str(), &m->m_address);
1292
1293 /* Time */
1294 const xml::ElementNode *time = node->findChildElement(tagXMLLeaseTime.c_str());
1295 if (!time) return false;
1296
1297 valueExists = time->getAttributeValue(tagXMLTimeAttributeIssued.c_str(),
1298 &m->u64TimestampLeasingStarted);
1299 if (!valueExists) return false;
1300 m->fBinding = false;
1301
1302 valueExists = time->getAttributeValue(tagXMLTimeAttributeExpiration.c_str(),
1303 &m->u32LeaseExpirationPeriod);
1304 if (!valueExists) return false;
1305
1306 m->fHasLease = true;
1307 return true;
1308}
1309
1310
1311const Lease Lease::NullLease;
1312
1313
1314const 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