Kea 3.1.1
lease_query_impl6.cc
Go to the documentation of this file.
1// Copyright (C) 2020-2025 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
8
10#include <dhcp/dhcp6.h>
11#include <dhcp/libdhcp++.h>
12#include <dhcp/pkt6.h>
13#include <dhcp/option_custom.h>
14#include <dhcp/option_int.h>
16#include <dhcp/option6_iaaddr.h>
18#include <dhcpsrv/cfgmgr.h>
20#include <lease_query_impl6.h>
21#include <lease_query_log.h>
22#include <blq_service.h>
23#include <stats/stats_mgr.h>
24#include <util/encode/encode.h>
25#include <util/io.h>
26#include <util/str.h>
27
28#include <boost/range/adaptor/reversed.hpp>
29#include <boost/shared_ptr.hpp>
30#include <boost/pointer_cast.hpp>
31
32#include <set>
33
34using namespace isc;
35using namespace isc::asiolink;
36using namespace isc::config;
37using namespace isc::data;
38using namespace isc::dhcp;
39using namespace isc::hooks;
40using namespace isc::lease_query;
41using namespace isc::log;
42using namespace isc::stats;
43
44namespace {
45
47bool cltt_descending(const Lease6Ptr& first, const Lease6Ptr& second) {
48 return (first->cltt_ > second->cltt_);
49}
50
51}
52
55 auto blq_service = BulkLeaseQueryService::instance();
56 if (blq_service) {
57 CfgMgr::instance().getStagingCfg()->getCfgDbAccess()->
58 setExtendedInfoTablesEnabled(blq_service->getExtendedInfoTablesEnabled());
59 }
60
61 ConstElementPtr prefix_lengths = config->get("prefix-lengths");
62 if (!prefix_lengths) {
63 return;
64 }
65
66 if (prefix_lengths->getType() != Element::list) {
67 isc_throw(BadValue, "'prefix-lengths' is not a list");
68 }
69
70 // If it's specified, empty or otherwise, we don't build it dynamically.
71 // An empty list "[]" means we don't do PD pool searching by IP address.
72 build_prefix_lens_ = false;
73 for (auto const& entry : prefix_lengths->listValue()) {
74 try {
75 if (entry->getType() != Element::integer) {
76 isc_throw(BadValue, "must be an integer");
77 }
78
79 auto plen = entry->intValue();
80 if (plen <= 0 || plen > 128) {
81 isc_throw(BadValue, "must be greater than 0 and less than or equal to 128");
82 }
83
84 addPrefixLength(plen);
85 } catch (const std::exception& ex) {
86 isc_throw(BadValue, "'prefix-lengths' entry '" << entry->str()
87 << "' is invalid: " << ex.what());
88 }
89 }
90}
91
92void
94 Pkt6Ptr query = boost::dynamic_pointer_cast<Pkt6>(base_query);
95 if (!query) {
96 // Shouldn't happen.
97 isc_throw(BadValue, "LeaseQueryImpl6 query is not DHCPv6 packet");
98 }
99
100 // Ensure there is a client id
101 DuidPtr req_clientid = query->getClientId();
102 if (!req_clientid) {
103 isc_throw(BadValue, "DHCPV6_LEASEQUERY must supply a D6O_CLIENTID");
104 }
105
106 // If client sent a server-id, validate it.
107 testServerId(query);
108
109 // Validates query content using the source address.
110 IOAddress requester_ip = query->getRemoteAddr();
111 if (requester_ip.isV6Zero()) {
113 isc_throw(BadValue, "DHCPV6_LEASEQUERY source address cannot be ::");
114 }
115
116 if (!isRequester(requester_ip)) {
117 // RFC 5007 says we may discard or return STATUS_NotAllowed
119 "rejecting DHCPV6_LEASEQUERY from unauthorized requester: "
120 << requester_ip.toText());
121 }
122
123 // Get the lease query option.
124 OptionCustomPtr lq_option = boost::dynamic_pointer_cast<OptionCustom>
125 (query->getOption(D6O_LQ_QUERY));
126 if (!lq_option) {
127 isc_throw(BadValue, "DHCPV6_LEASEQUERY must supply a D6O_LQ_QUERY option");
128 }
129
130 // Extract the type and link fields.
131 uint8_t query_type;
132 IOAddress query_link_addr(IOAddress::IPV6_ZERO_ADDRESS());
133 try {
134 query_type = lq_option->readInteger<uint8_t>(0);
135 query_link_addr = lq_option->readAddress(1);
136 } catch (const std::exception& ex) {
137 // unpack() should catch this?
138 isc_throw(BadValue, "error reading query field(s):" << ex.what());
139 }
140
141 // Based on the query type, extract the requisite options and
142 // perform the query.
143 Lease6Collection leases;
144 Option6StatusCodePtr status_opt;
145 switch (query_type) {
146 case LQ6QT_BY_ADDRESS: {
147 Option6IAAddrPtr query_iaaddr = boost::dynamic_pointer_cast<Option6IAAddr>
148 (lq_option->getOption(D6O_IAADDR));
149 if (!query_iaaddr) {
150 status_opt = makeStatusOption(STATUS_MalformedQuery, "missing D6O_IAADDR");
151 } else {
152 status_opt = queryByIpAddress(query_iaaddr->getAddress(), leases, prefix_lens_);
153 }
154
155 break;
156 }
157
158 case LQ6QT_BY_CLIENTID: {
159 OptionPtr opt = lq_option->getOption(D6O_CLIENTID);
160 if (!opt) {
161 status_opt = makeStatusOption(STATUS_MalformedQuery, "missing D6O_CLIENTID");
162 break;
163 }
164
165 DuidPtr query_client_id;
166 try {
167 query_client_id.reset(new DUID(opt->getData()));
168 } catch (const std::exception& ex) {
169 status_opt = makeStatusOption(STATUS_MalformedQuery, "malformed D6O_CLIENTID");
170 break;
171 }
172
173 status_opt = queryByClientId(query_client_id, query_link_addr, leases);
174 break;
175 }
176
177 default:
178 status_opt = makeStatusOption(STATUS_UnknownQueryType, "unknown query-type");
179 break;
180 }
181
182 // Construct the reply.
183 Pkt6Ptr reply = buildReply(status_opt, query, leases);
184 if (reply) {
185 sendResponse(reply);
186 }
187}
188
190LeaseQueryImpl6::getPrefixFromAddress(const IOAddress& address, uint8_t prefix_length) {
191 if (address.getFamily() != AF_INET6) {
192 isc_throw(BadValue, "getPrefixFromAddress() - not a v6 address: " << address);
193 }
194
195 if (prefix_length == 0 || prefix_length > 128) {
196 isc_throw(BadValue, "getPrefixFromAddress() - invalid prefix length:" << prefix_length);
197 }
198
199 // Get the address as bytes.
200 auto address_bytes = address.toBytes();
201
202 // Copy the whole bytes into the prefix first.
203 auto keep_bytes = prefix_length / 8;
204 std::vector<uint8_t> prefix_bytes(address_bytes.begin(), address_bytes.begin() + keep_bytes);
205
206 // Mask on any remaining bits.
207 auto keep_bits = prefix_length % 8;
208
209 static uint8_t masks[] = { 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe };
210 if (keep_bits) {
211 prefix_bytes.push_back(address_bytes[keep_bytes] & masks[keep_bits - 1]);
212 }
213
214 // IOAddress::fromBytes() requires 16 bytes of data so pad it out with zeros.
215 prefix_bytes.insert(prefix_bytes.end(), 16 - prefix_bytes.size(), 0);
216
217 return (IOAddress::fromBytes(AF_INET6, prefix_bytes.data()));
218}
219
222 const PrefixLengthList& prefix_lengths) {
223 // Database possible call: check if the hook was terminated.
225 // Look for a lease for the given address.
227 if (!lease && prefix_lengths.size()) {
228 // Iterate over list of prefix-lengths in descending order.
229 for (auto const& it : boost::adaptors::reverse(prefix_lengths)) {
230 IOAddress prefix = getPrefixFromAddress(iaaddr, it);
232 if (lease) {
233 break;
234 }
235 }
236 }
237
238 if (lease) {
239 if ((lease->state_ == Lease::STATE_DEFAULT) && (!lease->expired())) {
240 // Found an active lease.
241 leases.push_back(lease);
242 return (makeStatusOption(STATUS_Success, "active lease found"));
243 }
244
245 // There's a lease but it isn't active.
246 // Not real clear what should get returned in this case.
247 return (makeStatusOption(STATUS_Success, "inactive lease exists"));
248 }
249
250 // We didn't find a lease, so we need to determine if it is a lease
251 // we should know about. We iterate over all subnets, in case the
252 // address is inRange() of more than one subnet.
253 const Subnet6Collection* subnets;
254 subnets = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getAll();
255 for (auto const& subnet : *subnets) {
256
257 // Belongs to a pool in this subnet, but not leased.
258 if ((subnet->inPool(Lease::TYPE_NA, iaaddr)) ||
259 (subnet->inPool(Lease::TYPE_PD, iaaddr))) {
260 return (makeStatusOption(STATUS_Success, "no active lease"));
261 }
262 }
263
264 return (makeStatusOption(STATUS_NotConfigured, "address not in a configured pool"));
265}
266
268LeaseQueryImpl6::queryByClientId(const DuidPtr& client_id, const IOAddress& link_addr,
269 Lease6Collection& leases) {
270 // If the client specified a link to filter on, look up matching subnets.
271 // We'll fetch the leases by client DUID and link filter them afterwards.
272 SubnetIDSet links;
273 if (!link_addr.isV6Zero()) {
274 auto subnets = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6();
275 links = subnets->getLinks(link_addr);
276 if (links.empty()) {
277 return (makeStatusOption(STATUS_NotConfigured, "not a configured link"));
278 }
279 }
280
281 // Database possible call: check if the hook was terminated.
283
284 // Fetch all leases by client DUID.
285 Lease6Collection found_leases = LeaseMgrFactory::instance().getLeases6(*client_id);
286
287 // We want only the active leases.
288 if (!found_leases.empty()) {
289 for (auto const& lease : found_leases) {
290 if (lease->state_ == Lease::STATE_DEFAULT && !lease->expired()) {
291 // Filter by query links (if any).
292 if (!links.empty() && !links.count(lease->subnet_id_)) {
293 continue;
294 }
295
296 // It's a match, keep it.
297 leases.push_back(lease);
298 }
299 }
300 }
301
302 if (!leases.empty()) {
303 // Sort the leases by descending value of CLTT (i.e. newest first)
304 std::sort(leases.begin(), leases.end(), cltt_descending);
305 return (makeStatusOption(STATUS_Success, "active lease(s) found"));
306 }
307
308 return (makeStatusOption(STATUS_Success, "no active leases"));
309}
310
313 IOAddress& start_addr,
314 const size_t page_size,
315 const IOAddress& link_addr,
316 SubnetIDSet& links,
317 Lease6Collection& leases) {
318 // If the client specified a link to filter on, look up matching subnets.
319 links.clear();
320 if (!link_addr.isV6Zero()) {
321 auto subnets = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6();
322 links = subnets->getLinks(link_addr);
323 if (links.empty()) {
324 return (makeStatusOption(STATUS_NotConfigured, "not a configured link"));
325 }
326 }
327
328 // Fetch an initial page of leases by relay DUID.
329 start_addr = IOAddress::IPV6_ZERO_ADDRESS();
330 Lease6Collection found_leases;
331 for (;;) {
332 // Database possible call: check if the hook was terminated.
334
335 found_leases =
337 start_addr,
338 LeasePageSize(page_size));
339 if (found_leases.empty()) {
340 return (makeStatusOption(STATUS_Success, "no active leases"));
341 }
342 // Record the last address to restart from this point.
343 start_addr = found_leases.back()->addr_;
344 for (auto const& lease : found_leases) {
345 if (lease->state_ == Lease::STATE_DEFAULT && !lease->expired()) {
346 // Filter by query links (if any).
347 if (!links.empty() && !links.count(lease->subnet_id_)) {
348 continue;
349 }
350
351 // It's a match, keep it.
352 leases.push_back(lease);
353 }
354 }
355
356 if (!leases.empty()) {
357 return (makeStatusOption(STATUS_Success, "active lease(s) found"));
358 }
359 }
360}
361
362void
364 IOAddress& start_addr,
365 const size_t page_size,
366 const SubnetIDSet& links,
367 Lease6Collection& leases) {
368 // Database possible call: check if the hook was terminated.
370
371 Lease6Collection found_leases =
373 start_addr,
374 LeasePageSize(page_size));
375 if (found_leases.empty()) {
376 return;
377 }
378 const IOAddress seen = start_addr;
379 // Record the last address to restart from this point.
380 start_addr = found_leases.back()->addr_;
381 if (start_addr == seen) {
382 return;
383 }
384 for (auto const& lease : found_leases) {
385 if (lease->addr_ == seen) {
386 continue;
387 }
388 if (lease->state_ == Lease::STATE_DEFAULT && !lease->expired()) {
389 // Filter by query links (if any).
390 if (!links.empty() && !links.count(lease->subnet_id_)) {
391 continue;
392 }
393 }
394
395 // It's a match, keep it.
396 leases.push_back(lease);
397 }
398}
399
402 IOAddress& start_addr,
403 const size_t page_size,
404 const IOAddress& link_addr,
405 SubnetIDSet& links,
406 Lease6Collection& leases) {
407 // If the client specified a link to filter on, look up matching subnets.
408 links.clear();
409 if (!link_addr.isV6Zero()) {
410 auto subnets = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6();
411 links = subnets->getLinks(link_addr);
412 if (links.empty()) {
413 return (makeStatusOption(STATUS_NotConfigured, "not a configured link"));
414 }
415 }
416
417 // Fetch an initial page of leases by remote id.
418 start_addr = IOAddress::IPV6_ZERO_ADDRESS();
419 Lease6Collection found_leases;
420 for (;;) {
421 // Database possible call: check if the hook was terminated.
423
424 found_leases =
426 start_addr,
427 LeasePageSize(page_size));
428 if (found_leases.empty()) {
429 return (makeStatusOption(STATUS_Success, "no active leases"));
430 }
431 // Record the last address to restart from this point.
432 start_addr = found_leases.back()->addr_;
433 for (auto const& lease : found_leases) {
434 if (lease->state_ == Lease::STATE_DEFAULT && !lease->expired()) {
435 // Filter by query links (if any).
436 if (!links.empty() && !links.count(lease->subnet_id_)) {
437 continue;
438 }
439
440 // It's a match, keep it.
441 leases.push_back(lease);
442 }
443 }
444
445 if (!leases.empty()) {
446 return (makeStatusOption(STATUS_Success, "active lease(s) found"));
447 }
448 }
449}
450
451void
453 IOAddress& start_addr,
454 const size_t page_size,
455 const SubnetIDSet& links,
456 Lease6Collection& leases) {
457 // Database possible call: check if the hook was terminated.
459
460 Lease6Collection found_leases =
462 start_addr,
463 LeasePageSize(page_size));
464 if (found_leases.empty()) {
465 return;
466 }
467 const IOAddress seen = start_addr;
468 // Record the last address to restart from this point.
469 start_addr = found_leases.back()->addr_;
470 if (start_addr == seen) {
471 return;
472 }
473 for (auto const& lease : found_leases) {
474 if (lease->addr_ == seen) {
475 continue;
476 }
477 if (lease->state_ == Lease::STATE_DEFAULT && !lease->expired()) {
478 // Filter by query links (if any).
479 if (!links.empty() && !links.count(lease->subnet_id_)) {
480 continue;
481 }
482 }
483
484 // It's a match, keep it.
485 leases.push_back(lease);
486 }
487}
488
491 const size_t page_size,
492 const IOAddress& link_addr,
493 SubnetIDSet& links,
494 Lease6Collection& leases) {
495 // The link is required.
496 if (link_addr.isV6Zero()) {
497 return (makeStatusOption(STATUS_MalformedQuery, "link address is ::"));
498 }
499 links.clear();
500 auto subnets = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6();
501 links = subnets->getLinks(link_addr);
502 if (links.empty()) {
503 return (makeStatusOption(STATUS_NotConfigured, "not a configured link"));
504 }
505
506 Lease6Collection found_leases;
507 // Iterate over subnets.
508 for (;;) {
509 // Try first subnet.
510 auto it = links.begin();
511 if (it == links.end()) {
512 // No subnet: done.
513 return (makeStatusOption(STATUS_Success, "no active leases"));
514 }
515 // Fetch an initial page of leases on the subnet.
516 start_addr = IOAddress::IPV6_ZERO_ADDRESS();
517 for (;;) {
518 // Database possible call: check if the hook was terminated.
520
521 found_leases =
522 LeaseMgrFactory::instance().getLeases6(*it, start_addr,
523 LeasePageSize(page_size));
524 if (found_leases.empty()) {
525 // Remove the current subnet and try the next one.
526 links.erase(it);
527 start_addr = IOAddress::IPV6_ZERO_ADDRESS();
528 break;
529 }
530
531 // Record the last address to restart from this point.
532 start_addr = found_leases.back()->addr_;
533 for (auto const& lease : found_leases) {
534 if (lease->state_ == Lease::STATE_DEFAULT &&
535 !lease->expired()) {
536 // It's a match, keep it.
537 leases.push_back(lease);
538 }
539 }
540 if (!leases.empty()) {
541 return (makeStatusOption(STATUS_Success, "active lease(s) found"));
542 }
543 }
544 }
545}
546
547void
549 const size_t page_size,
550 SubnetIDSet& links,
551 Lease6Collection& leases) {
552
553 Lease6Collection found_leases;
554 // Iterate over subnets.
555 for (;;) {
556 // Try first subnet.
557 auto it = links.begin();
558 if (it == links.end()) {
559 // No subnet: done.
560 return;
561 }
562 // Fetch next page of leases on the subnet.
563 for (;;) {
564 // Database possible call: check if the hook was terminated.
566
567 found_leases =
568 LeaseMgrFactory::instance().getLeases6(*it, start_addr,
569 LeasePageSize(page_size));
570 if (found_leases.empty()) {
571 // Remove the current subnet and try the next one.
572 links.erase(it);
573 start_addr = IOAddress::IPV6_ZERO_ADDRESS();
574 break;
575 }
576
577 const IOAddress seen = start_addr;
578 // Record the last address to restart from this point.
579 start_addr = found_leases.back()->addr_;
580 if (start_addr == seen) {
581 return;
582 }
583 for (auto const& lease : found_leases) {
584 if (lease->addr_ == seen) {
585 continue;
586 }
587 if (lease->state_ == Lease::STATE_DEFAULT &&
588 !lease->expired()) {
589 // It's a match, keep it.
590 leases.push_back(lease);
591 }
592 }
593 if (!leases.empty()) {
594 return;
595 }
596 }
597 }
598}
599
602 const Pkt6Ptr& query,
603 Lease6Collection& leases) {
604 if (!status) {
605 // Shouldn't happen.
606 isc_throw(Unexpected, "status option cannot be empty");
607 }
608
609 Pkt6Ptr reply;
610 switch (status->getStatusCode()) {
611 case STATUS_Success: {
612 // Create the reply.
613 reply = initReply(query);
614
615 // If we found leases add the client and/or relay-data options.
616 if (!leases.empty()) {
617 // Add the client option.
618 OptionPtr client_opt = makeClientOption(leases);
619 reply->addOption(client_opt);
620
621 // If we are returning leases (not links), make the
622 // relay option from the extended-store (if any) of
623 // the newest lease.
624 if (client_opt->getType() != D6O_LQ_CLIENT_LINK) {
625 OptionPtr opt = makeRelayOption(*(*leases.begin()));
626 if (opt) {
627 reply->addOption(opt);
628 }
629 }
630 }
631
634
635 // RFC 5007 says you may return a status of success.
636 // ISC DHCP does not.
637 reply->addOption(status);
638 break;
639 }
640
644 case STATUS_NotAllowed: {
645 // Query could not be performed or was for an address
646 // we do not know about. We send back only the status.
647 reply = initReply(query);
648 reply->addOption(status);
649 break;
650 }
651
652 default:
653 // No meaningful reply can be sent.
654 break;
655 }
656
657 return (reply);
658}
659
662 Pkt6Ptr reply;
663
664 reply.reset(new Pkt6(DHCPV6_LEASEQUERY_REPLY, query->getTransid()));
665 reply->setRemoteAddr(query->getRemoteAddr());
666 reply->setRemotePort(query->getRemotePort());
667 reply->setLocalAddr(query->getLocalAddr());
668 reply->setLocalPort(query->getLocalPort());
669 reply->setIface(query->getIface());
670 reply->setIndex(query->getIndex());
671
672 DuidPtr duid = query->getClientId();
673 if (!duid) {
674 isc_throw(Unexpected, "query has no D6O_CLIENTID");
675 }
676
677 OptionPtr opt(new Option(Option::V6, D6O_CLIENTID, duid->getDuid()));
678 reply->addOption(opt);
679
681 ->getCfgDUID()->getCurrentDuid();
682 if (!server_id) {
683 isc_throw(Unexpected, "server_id does not exist");
684 }
685
686 opt.reset(new Option(Option::V6, D6O_SERVERID, server_id->getDuid()));
687 reply->addOption(opt);
688 return (reply);
689}
690
693 Pkt6Ptr response;
694
695 response.reset(new Pkt6(DHCPV6_LEASEQUERY_DATA, query->getTransid()));
696 response->setRemoteAddr(query->getRemoteAddr());
697 response->setRemotePort(query->getRemotePort());
698 return (response);
699}
700
703 Pkt6Ptr done;
704
705 done.reset(new Pkt6(DHCPV6_LEASEQUERY_DONE, query->getTransid()));
706 done->setRemoteAddr(query->getRemoteAddr());
707 done->setRemotePort(query->getRemotePort());
708 return (done);
709}
710
713 if (leases.empty()) {
714 isc_throw(Unexpected, "makeClientOption: leases list is empty");
715 }
716
717 // Querying by client-id may find leases on multiple links.
718 // We need to detect that case so we can return a D6O_LQ_CLIENT_LINK
719 // option.
720 // Iterate over leases and build a list of unique subnet ids.
721 SubnetIDSet links;
722 for (auto const& lease : leases) {
723 if (lease->subnet_id_) {
724 // The use of a set will remove duplicates.
725 static_cast<void>(links.insert(lease->subnet_id_));
726 }
727 }
728
729 if (links.size() > 1) {
730 CfgSubnets6Ptr subnets = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6();
732 for (auto const& link : links) {
733 ConstSubnet6Ptr subnet = subnets->getBySubnetId(link);
734 std::pair<isc::asiolink::IOAddress, uint8_t> pair = subnet->get();
735 addrs.push_back(pair.first);
736 }
737
739 return (opt);
740 }
741
743 OptionCustomPtr cd_option(new OptionCustom(def, Option::V6));
744
745 // Get the client id and CLTT from the first lease.
746 const Lease6& first_lease = *(*leases.begin());
747 OptionPtr opt(new Option(Option::V6, D6O_CLIENTID, first_lease.duid_->getDuid()));
748 cd_option->addOption(opt);
749
750 // How much time has elapsed since last client transmission?
751 time_t now = time(0);
752 time_t elapsed;
753 if (first_lease.cltt_ < now) {
754 elapsed = now - first_lease.cltt_;
755 } else {
756 // Something insane here so send back times unadjusted.
757 elapsed = 0;
758 }
759
760 // Add CLTT option based on the newest lease.
761 opt.reset(new OptionUint32(Option::V6, D6O_CLT_TIME, elapsed));
762 cd_option->addOption(opt);
763
764 // Iterate over the leases adding the appropriate option
765 // for each one.
766 for (auto const& lease : leases) {
767 if (lease->cltt_ < now) {
768 elapsed = now - lease->cltt_;
769 } else {
770 // Something insane here so send back times unadjusted.
771 elapsed = 0;
772 }
773
774 // Calculate the remaining lifetimes.
775 uint32_t preferred = lease->preferred_lft_;
776 if (elapsed < preferred) {
777 preferred -= elapsed;
778 }
779
780 uint32_t valid = lease->valid_lft_;
781 if (elapsed < valid) {
782 valid -= elapsed;
783 }
784
785 // Create the option.
786 OptionPtr lease_opt;
787 if (lease->type_ == Lease::TYPE_NA) {
788 lease_opt.reset(new Option6IAAddr(D6O_IAADDR, lease->addr_,
789 preferred, valid));
790 } else {
791 lease_opt.reset(new Option6IAPrefix(D6O_IAPREFIX,
792 lease->addr_, lease->prefixlen_,
793 preferred, valid));
794 }
795
796 cd_option->addOption(lease_opt);
797 }
798
799 return (cd_option);
800}
801
805 OptionCustomPtr cd_option(new OptionCustom(def, Option::V6));
806
807 // Get the client id and CLTT.
808 OptionPtr opt(new Option(Option::V6, D6O_CLIENTID, lease->duid_->getDuid()));
809 cd_option->addOption(opt);
810
811 // How much time has elapsed since last client transmission?
812 time_t now = time(0);
813 time_t elapsed;
814 if (lease->cltt_ < now) {
815 elapsed = now - lease->cltt_;
816 } else {
817 // Something insane here so send back times unadjusted.
818 elapsed = 0;
819 }
820
821 // Add CLTT option.
822 opt.reset(new OptionUint32(Option::V6, D6O_CLT_TIME, elapsed));
823 cd_option->addOption(opt);
824
825 // Calculate the remaining lifetimes.
826 uint32_t preferred = lease->preferred_lft_;
827 if (elapsed < preferred) {
828 preferred -= elapsed;
829 }
830
831 uint32_t valid = lease->valid_lft_;
832 if (elapsed < valid) {
833 valid -= elapsed;
834 }
835
836 // Create the resource option.
837 OptionPtr lease_opt;
838 if (lease->type_ == Lease::TYPE_NA) {
839 lease_opt.reset(new Option6IAAddr(D6O_IAADDR, lease->addr_,
840 preferred, valid));
841 } else {
842 lease_opt.reset(new Option6IAPrefix(D6O_IAPREFIX,
843 lease->addr_, lease->prefixlen_,
844 preferred, valid));
845 }
846 cd_option->addOption(lease_opt);
847
848 // Add relay info.
849 OptionPtr relay_opt = makeRelayOption(*lease);
850 if (relay_opt) {
851 cd_option->addOption(relay_opt);
852 }
853
854 return (cd_option);
855}
856
859 ConstElementPtr user_context;
860 std::vector<RelayInfoPtr> relay_infos;
861
862 try {
863 if (lease.getContext()) {
864 user_context = UserContext::toElement(lease.getContext());
865 }
866
867 if (!user_context) {
868 return (OptionPtr());
869 }
870
871 ConstElementPtr extended_info = user_context->get("ISC");
872 if (!extended_info) {
873 return (OptionPtr());
874 }
875
876 // New layout puts the extended info in the relay-info entry.
877 ConstElementPtr relay_info = extended_info->get("relay-info");
878 if (!relay_info) {
879 // Old layout uses the relays entry.
880 relay_info = extended_info->get("relays");
881 }
882 if (!relay_info) {
883 return (OptionPtr());
884 }
885
886 // Parse the relay element list into Pkt6::RelayInfo instances.
887 parseRelayInfoList(relay_info, relay_infos);
888 if (relay_infos.empty()) {
889 // If we have an empty list, that's actually wrong, it should not
890 // have been stored in the first place.
891 isc_throw(Unexpected, "relay info list should not be empty");
892 }
893 } catch (const std::exception& ex) {
895 .arg(lease.toText())
896 .arg(ex.what());
897 return (OptionPtr());
898 }
899
900 // Create the relay data option.
902 OptionCustomPtr rd_option(new OptionCustom(def, Option::V6));
903
904 // The peer field should come from the outer-most relay
905 rd_option->writeAddress(relay_infos.front()->peeraddr_, 0);
906
907 // For convenience, set the index of the last one.
908 size_t innermost = relay_infos.size() - 1;
909
910 // Iterate backward through the RelayInfo list and calculate the
911 // packed size of each one in succession.
912 uint16_t len = 0;
913 for (size_t i = relay_infos.size(); i > 0; --i) {
914 relay_infos[i - 1]->relay_msg_len_ = len;
915 len += getRelayOverhead(*(relay_infos[i - 1]), (i == innermost));
916 }
917
918 // Now iterate forward over them, writing them to an OutputBuffer.
920 + relay_infos[0]->relay_msg_len_);
921
922 for (size_t i = 0; i < relay_infos.size(); ++i) {
923 RelayInfoPtr relay = relay_infos[i];
924
925 // build relay-forw/relay-repl header (see RFC 8415, section 9)
926 buffer_out.writeUint8(DHCPV6_RELAY_FORW);
927 buffer_out.writeUint8(relay->hop_count_);
928 buffer_out.writeData(&(relay->linkaddr_.toBytes()[0]),
929 isc::asiolink::V6ADDRESS_LEN);
930 buffer_out.writeData(&relay->peeraddr_.toBytes()[0],
931 isc::asiolink::V6ADDRESS_LEN);
932
933 // Store every option in this relay's scope.
934 for (auto const& opt : relay->options_) {
935 (opt.second)->pack(buffer_out);
936 }
937
938 // Include the header for the relay-msg option which will
939 // contain the next relay forward. It's payload will be generated
940 // in the next iteration.
941 if (i < innermost) {
942 buffer_out.writeUint16(D6O_RELAY_MSG);
943 buffer_out.writeUint16(relay->relay_msg_len_);
944 }
945 }
946
947 // Now convert them to an option buffer and add them to
948 // relay data option.
949 const OptionBuffer& relay_buffer = buffer_out.getVector();
950 rd_option->writeBinary(relay_buffer, 1);
951
952 // Dizzy yet? Don't worry, we're done.
953 return (rd_option);
954}
955
956uint16_t
958 uint16_t len = Pkt6::DHCPV6_RELAY_HDR_LEN; // fixed header
959
960 if (innermost) {
961 len += Option::OPTION6_HDR_LEN; // header of the relay-msg option
962 }
963
964 for (auto const& opt : relay.options_) {
965 len += (opt.second)->len();
966 }
967
968 return (len);
969}
970
971void
973 std::vector<RelayInfoPtr>& relay_infos) {
974 if (!relay_info || relay_info->getType() != Element::list) {
975 isc_throw(BadValue, "parseRelayInfoList: relay-info element empty or not a list");
976 }
977
978 for (auto const& relay : relay_info->listValue()) {
980 relay_infos.push_back(info);
981 }
982}
983
986 if (!relay_elem || (relay_elem->getType() != Element::map)) {
987 isc_throw(BadValue, "parseRelayInfo: relay element empty or not a map");
988 }
989
990 RelayInfoPtr relay_info(new Pkt6::RelayInfo());
991 auto elem = relay_elem->get("hop");
992 if (!elem) {
993 isc_throw(BadValue, "parseRelayInfo: 'hop' is missing");
994 }
995
996 try {
997 relay_info->hop_count_ = static_cast<uint8_t>(elem->intValue());
998 } catch (const std::exception& ex) {
999 isc_throw(BadValue, "parseRelayInfo: 'hop' is invalid: " << ex.what());
1000 }
1001
1002 elem = relay_elem->get("peer");
1003 if (!elem) {
1004 isc_throw(BadValue, "parseRelayInfo: 'peer' is missing");
1005 }
1006
1007 try {
1008 relay_info->peeraddr_ = IOAddress(elem->stringValue());
1009 if (!relay_info->peeraddr_.isV6()) {
1010 isc_throw(BadValue, "not a V6 address: " << relay_info->peeraddr_);
1011 }
1012 } catch (const std::exception& ex) {
1013 isc_throw(BadValue, "parseRelayInfo: 'peer' is invalid: " << ex.what());
1014 }
1015
1016 elem = relay_elem->get("link");
1017 if (!elem) {
1018 isc_throw(BadValue, "parseRelayInfo: 'link' is missing");
1019 }
1020
1021 try {
1022 relay_info->linkaddr_ = IOAddress(elem->stringValue());
1023 if (!relay_info->linkaddr_.isV6()) {
1024 isc_throw(BadValue, "not a V6 address: " << relay_info->linkaddr_);
1025 }
1026 } catch (const std::exception& ex) {
1027 isc_throw(BadValue, "parseRelayInfo: 'link' is invalid: " << ex.what());
1028 }
1029
1030 // The options element is optional.
1031 elem = relay_elem->get("options");
1032 if (elem) {
1033 try {
1034 std::string hex_str = elem->stringValue();
1035
1036 OptionBuffer binary;
1037 util::str::decodeFormattedHexString(hex_str, binary);
1038 static_cast<void>(LibDHCP::unpackOptions6(binary, DHCP6_OPTION_SPACE,
1039 relay_info->options_));
1040 } catch (const std::exception& ex) {
1041 isc_throw(BadValue, "parseRelayInfo: 'options' is invalid: " << ex.what());
1042 }
1043 }
1044
1045 return (relay_info);
1046}
1047
1048void
1050 OptionPtr client_server_id = query->getOption(D6O_SERVERID);
1051 if (client_server_id) {
1052 DuidPtr client_duid;
1053 try {
1054 client_duid.reset(new DUID(client_server_id->getData()));
1055 } catch (const std::exception& ex) {
1056 isc_throw(BadValue, "DHCPV6_LEASEQUERY D6O_SERVERID malformed: "
1057 << ex.what());
1058 }
1059
1060 DuidPtr server_id = CfgMgr::instance().getCurrentCfg()->getCfgDUID()->getCurrentDuid();
1061 if (!server_id) {
1062 isc_throw(Unexpected, "Server has no current server id?");
1063 } else if (*client_duid != *server_id) {
1064 isc_throw(BadValue, "rejecting DHCPV6_LEASEQUERY from: "
1065 << query->getRemoteAddr() << ", unknown server-id: "
1066 << (client_server_id ? client_server_id->toText() : "malformed"));
1067 }
1068 }
1069
1070 // We have a winner!
1071}
1072
1073void
1075 // Pack the response.
1076 try {
1077 response->pack();
1078 } catch (const std::exception& ex) {
1080 .arg(leaseQueryLabel(response))
1081 .arg(ex.what());
1082 return;
1083 }
1084
1085 try {
1086 send(response);
1088 .arg(leaseQueryLabel(response))
1089 .arg(response->getRemoteAddr())
1090 .arg(response->getRemotePort());
1091
1092 StatsMgr::instance().addValue("pkt6-sent", static_cast<int64_t>(1));
1093 StatsMgr::instance().addValue("pkt6-lease-query-reply-sent",
1094 static_cast<int64_t>(1));
1095 } catch (const std::exception& ex) {
1097 .arg(leaseQueryLabel(response))
1098 .arg(response->getIface())
1099 .arg(response->getRemoteAddr())
1100 .arg(response->getRemotePort())
1101 .arg(ex.what());
1102 }
1103}
1104
1105void LeaseQueryImpl6::send(const dhcp::Pkt6Ptr& response) const {
1106 IfaceMgr::instance().send(response);
1107}
1108
1111 const std::string message) {
1112 Option6StatusCodePtr opt(new Option6StatusCode(status_code, message));
1113 return (opt);
1114}
1115
1116std::string
1118 std::stringstream label;
1119
1120 try {
1121 DuidPtr client_id = packet->getClientId();
1122 label << "type: " << packet->getName()
1123 << ", client id: " << (client_id ? client_id->toText() : "<none>")
1124 << ", requester: " << packet->getRemoteAddr()
1125 << ", transid: " << packet->getTransid();
1126
1127 } catch (const std::exception& ex) {
1128 // Shouldn't happen. This just ensures we're exception safe.
1129 label << "label error" << ex.what();
1130 }
1131
1132 return (label.str());
1133}
1134
1135int
1137 ConstElementPtr response;
1138 size_t upgraded = 0;
1140 try {
1142 auto& lease_mgr = LeaseMgrFactory::instance();
1143 // check getExtendedInfoTablesEnabled() here?
1144 upgraded = lease_mgr.upgradeExtendedInfo6(page_size);
1145 } catch (const std::exception& ex) {
1146 // log here.
1147 response = createAnswer(CONTROL_RESULT_ERROR, ex.what());
1148 handle.setArgument("response", response);
1149 return (1);
1150 }
1151
1152 // log here.
1153 std::ostringstream msg;
1154 msg << "Upgraded " << upgraded << " lease";
1155 if (upgraded != 1) {
1156 msg << "s";
1157 }
1158 response = createAnswer(CONTROL_RESULT_SUCCESS, msg.str());
1159 handle.setArgument("response", response);
1160 return (0);
1161}
1162
1163void
1165 if (build_prefix_lens_) {
1166 // Empty the current entries.
1168
1169 // traverse subnet pd pools and build list
1170 const Subnet6Collection* subnets = cfg->getCfgSubnets6()->getAll();
1171 for (auto const& subnet : *subnets) {
1172 const PoolCollection& pools = subnet->getPools(Lease::TYPE_PD);
1173 for (auto const& pool : pools) {
1174 Pool6Ptr p6 = boost::dynamic_pointer_cast<Pool6>(pool);
1175 addPrefixLength(p6->getLength());
1176 }
1177 }
1178 }
1179
1182}
1183
1184std::string
1186 std::ostringstream oss;
1187 oss << "[";
1188
1189 auto first_one = true;
1190 for (auto const& it : boost::adaptors::reverse(prefix_lengths)) {
1191 if (!first_one) {
1192 oss << ",";
1193 } else {
1194 first_one = false;
1195 }
1196
1197 oss << " " << static_cast<int>(it);
1198 }
1199
1200 oss << " ]";
1201 return (oss.str());
1202}
@ map
Definition data.h:147
@ integer
Definition data.h:140
@ list
Definition data.h:146
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
A generic exception that is thrown when an unexpected error condition occurs.
static CfgMgr & instance()
returns a single instance of Configuration Manager
Definition cfgmgr.cc:29
SrvConfigPtr getStagingCfg()
Returns a pointer to the staging configuration.
Definition cfgmgr.cc:121
SrvConfigPtr getCurrentCfg()
Returns a pointer to the current configuration.
Definition cfgmgr.cc:116
Holds DUID (DHCPv6 Unique Identifier)
Definition duid.h:142
static IfaceMgr & instance()
IfaceMgr is a singleton class.
Definition iface_mgr.cc:54
bool send(const Pkt6Ptr &pkt)
Sends an IPv6 packet.
static TrackingLeaseMgr & instance()
Return current lease manager.
virtual Lease6Collection getLeases6(Lease::Type type, const DUID &duid, uint32_t iaid) const =0
Returns existing IPv6 leases for a given DUID+IA combination.
virtual Lease6Collection getLeases6ByRelayId(const DUID &relay_id, const asiolink::IOAddress &lower_bound_address, const LeasePageSize &page_size)=0
Returns existing IPv6 leases with a given relay-id.
virtual Lease6Collection getLeases6ByRemoteId(const OptionBuffer &remote_id, const asiolink::IOAddress &lower_bound_address, const LeasePageSize &page_size)=0
Returns existing IPv6 leases with a given remote-id.
virtual Lease6Ptr getLease6(Lease::Type type, const isc::asiolink::IOAddress &addr) const =0
Returns existing IPv6 lease for a given IPv6 address.
Wraps value holding size of the page with leases.
Definition lease_mgr.h:46
static const OptionDefinition & D6O_LQ_RELAY_DATA_DEF()
Get definition of D6O_LQ_RELAY_DATA option.
static const OptionDefinition & D6O_CLIENT_DATA_DEF()
Get definition of D6O_CLIENT_DATA option.
static size_t unpackOptions6(const OptionBuffer &buf, const std::string &option_space, isc::dhcp::OptionCollection &options, size_t *relay_msg_offset=0, size_t *relay_msg_len=0)
Parses provided buffer as DHCPv6 options and creates Option objects.
Definition libdhcp++.cc:317
DHCPv6 Option class for handling list of IPv6 addresses.
std::vector< isc::asiolink::IOAddress > AddressContainer
a container for (IPv6) addresses
Class that represents IAPREFIX option in DHCPv6.
This class represents Status Code option (13) from RFC 8415.
Option with defined data fields represented as buffers that can be accessed using data field index.
Base class representing a DHCP option definition.
static const size_t OPTION6_HDR_LEN
length of any DHCPv6 option header
Definition option.h:87
Represents a DHCPv6 packet.
Definition pkt6.h:44
static const size_t DHCPV6_RELAY_HDR_LEN
specifies relay DHCPv6 packet header length (over UDP)
Definition pkt6.h:50
Per-packet callout handle.
void setArgument(const std::string &name, T value)
Set argument.
static BulkLeaseQueryServicePtr instance()
Returns a pointer to the sole instance of the BulkLeaseQueryService, can return null.
static void testServerId(const dhcp::Pkt6Ptr &query)
Validates the server-id of a received DHCPV6_LEASEQUERY.
static RelayInfoPtr parseRelayInfo(data::ConstElementPtr relay)
Converts an Element::map into an Pkt6::RelayInfo instance.
static void queryByRelayIdNext(const dhcp::DuidPtr &relay_id, asiolink::IOAddress &start_addr, const size_t page_size, const dhcp::SubnetIDSet &links, dhcp::Lease6Collection &leases)
Subsequent query for active leases matching a relay id (i.e.
static uint16_t getRelayOverhead(const dhcp::Pkt6::RelayInfo &relay, bool innermost)
Calculates the packed size (in octets) of a given RelayInfo.
static asiolink::IOAddress getPrefixFromAddress(const asiolink::IOAddress &address, const uint8_t prefix_length)
Creates a prefix of a given length from an address.
void addPrefixLength(uint8_t prefix_len)
Add a prefix to the list of prefix lengths.
static dhcp::Pkt6Ptr initDone(const dhcp::Pkt6Ptr &query)
Creates the final query done response.
static std::string dumpPrefixLengthList(const PrefixLengthList &prefix_lengths)
Dump the given list of prefix lengths to a string.
static dhcp::Option6StatusCodePtr queryByRemoteIdStart(const dhcp::OptionBuffer &remote_id, asiolink::IOAddress &start_addr, const size_t page_size, const asiolink::IOAddress &link_addr, dhcp::SubnetIDSet &links, dhcp::Lease6Collection &leases)
Initial query for active leases matching a remote id.
LeaseQueryImpl6(const data::ConstElementPtr config)
Constructor.
void sendResponse(const dhcp::Pkt6Ptr &response) const
Sends a response to the requester.
static dhcp::Option6StatusCodePtr queryByRelayIdStart(const dhcp::DuidPtr &relay_id, asiolink::IOAddress &start_addr, const size_t page_size, const asiolink::IOAddress &link_addr, dhcp::SubnetIDSet &links, dhcp::Lease6Collection &leases)
Initial query for active leases matching a relay id (i.e.
PrefixLengthList prefix_lens_
List of PD prefix lengths to use when searching for leases by address.
virtual void processQuery(dhcp::PktPtr base_query) const
Processes a single DHCPv6 client Lease Query.
static dhcp::Option6StatusCodePtr makeStatusOption(const DHCPv6StatusCode &status_code, const std::string message="")
Constructs a D6O_STATUS_CODE option.
static dhcp::Option6StatusCodePtr queryByLinkStart(asiolink::IOAddress &start_addr, const size_t page_size, const asiolink::IOAddress &link_addr, dhcp::SubnetIDSet &links, dhcp::Lease6Collection &leases)
Initial query for active leases of a given link.
static dhcp::OptionPtr makeClientOption(dhcp::Lease6Collection &leases)
Constructs a client option based on a collection of leases.
void clearPrefixLengthList()
Empty the prefix length list.
static dhcp::OptionPtr makeRelayOption(const dhcp::Lease6 &lease)
Constructs a D6O_LQ_RELAY_DATA option from a lease user-context.
static std::string leaseQueryLabel(const dhcp::Pkt6Ptr &packet)
Convenience method for generating per packet logging info.
static dhcp::Option6StatusCodePtr queryByIpAddress(const asiolink::IOAddress &iaaddr, dhcp::Lease6Collection &leases, const PrefixLengthList &prefix_lengths=PrefixLengthList())
Queries for an active lease matching an ip address.
virtual void send(const dhcp::Pkt6Ptr &response) const
Wrapper around the call to IfaceMgr::send().
static dhcp::Pkt6Ptr buildReply(const dhcp::Option6StatusCodePtr &status, const dhcp::Pkt6Ptr &query, dhcp::Lease6Collection &leases)
Creates a lease query reply packet.
static void queryByLinkNext(asiolink::IOAddress &start_addr, const size_t page_size, dhcp::SubnetIDSet &links, dhcp::Lease6Collection &leases)
Subsequent query for active leases of a given link.
static dhcp::Pkt6Ptr initReply(const dhcp::Pkt6Ptr &query)
Creates the initial query reply.
void populatePrefixLengthList(dhcp::SrvConfigPtr cfg)
Populates the prefix length list from the given configuration.
static dhcp::Option6StatusCodePtr queryByClientId(const dhcp::DuidPtr &client_id, const asiolink::IOAddress &link_addr, dhcp::Lease6Collection &leases)
Queries for active leases matching a client id (i.e.
static void parseRelayInfoList(data::ConstElementPtr relays, std::vector< RelayInfoPtr > &relay_infos)
Converts an Element::list into a list of Pkt6::RelayInfo instances.
static void queryByRemoteIdNext(const dhcp::OptionBuffer &remote_id, asiolink::IOAddress &start_addr, const size_t page_size, const dhcp::SubnetIDSet &links, dhcp::Lease6Collection &leases)
Subsequent query for active leases matching a remote id.
bool build_prefix_lens_
True if the prefix length should be gleaned from configured pools.
static int upgradeHandler(hooks::CalloutHandle &handle)
Upgrade extended information.
static dhcp::Pkt6Ptr initData(const dhcp::Pkt6Ptr &query)
Creates the query data response.
LeaseQueryImpl(uint16_t family, const isc::data::ConstElementPtr config)
Constructor.
bool isRequester(const isc::asiolink::IOAddress &address) const
Checks if the given address belongs to a valid requester.
static size_t PageSize
Page size to commands.
static StatsMgr & instance()
Statistics Manager accessor method.
RAII class creating a critical section.
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
Definition buffer.h:346
void writeUint8(uint8_t data)
Write an unsigned 8-bit integer into the buffer.
Definition buffer.h:476
void writeUint16(uint16_t data)
Write an unsigned 16-bit integer in host byte order into the buffer in network byte order.
Definition buffer.h:501
void writeData(const void *data, size_t len)
Copy an arbitrary length of data into the buffer.
Definition buffer.h:559
const std::vector< uint8_t > & getVector() const
Return the buffer.
Definition buffer.h:436
This file contains several functions and constants that are used for handling commands and responses ...
DHCPv6StatusCode
Definition dhcp6.h:175
@ STATUS_NotAllowed
Definition dhcp6.h:186
@ STATUS_MalformedQuery
Definition dhcp6.h:184
@ STATUS_Success
Definition dhcp6.h:176
@ STATUS_UnknownQueryType
Definition dhcp6.h:183
@ STATUS_NotConfigured
Definition dhcp6.h:185
@ D6O_SERVERID
Definition dhcp6.h:22
@ D6O_CLIENTID
Definition dhcp6.h:21
@ D6O_RELAY_MSG
Definition dhcp6.h:29
@ D6O_CLT_TIME
Definition dhcp6.h:66
@ D6O_LQ_QUERY
Definition dhcp6.h:64
@ D6O_IAADDR
Definition dhcp6.h:25
@ D6O_LQ_CLIENT_LINK
Definition dhcp6.h:68
@ D6O_IAPREFIX
Definition dhcp6.h:46
#define LQ6QT_BY_ADDRESS
Definition dhcp6.h:338
@ DHCPV6_LEASEQUERY_DATA
Definition dhcp6.h:226
@ DHCPV6_LEASEQUERY_DONE
Definition dhcp6.h:225
@ DHCPV6_LEASEQUERY_REPLY
Definition dhcp6.h:223
@ DHCPV6_RELAY_FORW
Definition dhcp6.h:219
#define LQ6QT_BY_CLIENTID
Definition dhcp6.h:339
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
OptionInt< uint32_t > OptionUint32
Definition option_int.h:34
void addValue(const std::string &name, const int64_t value)
Records incremental integer observation.
#define CHECK_TERMINATED
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
Definition macros.h:32
#define LOG_WARN(LOGGER, MESSAGE)
Macro to conveniently test warn output and log it.
Definition macros.h:26
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition macros.h:14
const int CONTROL_RESULT_ERROR
Status code indicating a general failure.
ConstElementPtr createAnswer()
Creates a standard config/command level success answer message (i.e.
const int CONTROL_RESULT_SUCCESS
Status code indicating a successful operation.
boost::shared_ptr< const Element > ConstElementPtr
Definition data.h:29
@ info
Definition db_log.h:120
boost::shared_ptr< isc::dhcp::Pkt > PktPtr
A pointer to either Pkt4 or Pkt6 packet.
Definition pkt.h:999
std::set< dhcp::SubnetID > SubnetIDSet
Ordered list aka set of subnetIDs.
Definition subnet_id.h:43
boost::shared_ptr< const Subnet6 > ConstSubnet6Ptr
A const pointer to a Subnet6 object.
Definition subnet.h:623
boost::shared_ptr< OptionCustom > OptionCustomPtr
A pointer to the OptionCustom object.
boost::shared_ptr< DUID > DuidPtr
Definition duid.h:136
boost::shared_ptr< Lease6 > Lease6Ptr
Pointer to a Lease6 structure.
Definition lease.h:528
std::vector< Lease6Ptr > Lease6Collection
A collection of IPv6 leases.
Definition lease.h:693
boost::multi_index_container< Subnet6Ptr, boost::multi_index::indexed_by< boost::multi_index::ordered_unique< boost::multi_index::tag< SubnetSubnetIdIndexTag >, boost::multi_index::const_mem_fun< Subnet, SubnetID, &Subnet::getID > >, boost::multi_index::ordered_unique< boost::multi_index::tag< SubnetPrefixIndexTag >, boost::multi_index::const_mem_fun< Subnet, std::string, &Subnet::toText > >, boost::multi_index::ordered_non_unique< boost::multi_index::tag< SubnetModificationTimeIndexTag >, boost::multi_index::const_mem_fun< data::BaseStampedElement, boost::posix_time::ptime, &data::BaseStampedElement::getModificationTime > > > > Subnet6Collection
A collection of Subnet6 objects.
Definition subnet.h:937
boost::shared_ptr< SrvConfig > SrvConfigPtr
Non-const pointer to the SrvConfig.
std::vector< PoolPtr > PoolCollection
a container for either IPv4 or IPv6 Pools
Definition pool.h:729
boost::shared_ptr< Option6AddrLst > Option6AddrLstPtr
Pointer to the Option6AddrLst object.
boost::shared_ptr< CfgSubnets6 > CfgSubnets6Ptr
Non-const pointer.
boost::shared_ptr< Option6StatusCode > Option6StatusCodePtr
Pointer to the isc::dhcp::Option6StatusCode.
boost::shared_ptr< Option6IAAddr > Option6IAAddrPtr
A pointer to the isc::dhcp::Option6IAAddr object.
boost::shared_ptr< Pkt6 > Pkt6Ptr
A pointer to Pkt6 packet.
Definition pkt6.h:31
std::vector< uint8_t > OptionBuffer
buffer types used in DHCP code.
Definition option.h:24
boost::shared_ptr< Option > OptionPtr
Definition option.h:37
boost::shared_ptr< Pool6 > Pool6Ptr
a pointer an IPv6 Pool
Definition pool.h:536
const isc::log::MessageID DHCP6_LEASE_QUERY_REPLY_SENT
std::set< uint8_t > PrefixLengthList
Defines an ordered list of prefix lengths.
boost::shared_ptr< dhcp::Pkt6::RelayInfo > RelayInfoPtr
Defines a shared pointer to a Pkt6::RelayInfo.
const isc::log::MessageID DHCP6_LEASE_QUERY_PACKET_PACK_FAILED
const isc::log::MessageID DHCP6_LEASE_QUERY_REPLY_SEND_FAILED
const isc::log::MessageID DHCP6_LEASE_QUERY_PREFIX_LENGTH_LIST
isc::log::Logger lease_query_logger("lease-query-hooks")
const isc::log::MessageID DHCP6_LEASE_QUERY_ERROR_GETTING_RELAY_INFO
const int DBGLVL_TRACE_BASIC
Trace basic operations.
void decodeFormattedHexString(const string &hex_string, vector< uint8_t > &binary)
Converts a formatted string of hexadecimal digits into a vector.
Definition str.cc:212
Defines the logger used by the top-level component of kea-lfc.
#define DHCP6_OPTION_SPACE
data::ConstElementPtr getContext() const
Returns const pointer to the user context.
static data::ElementPtr toElement(data::ConstElementPtr map)
Copy an Element map.
Structure that holds a lease for IPv6 address and/or prefix.
Definition lease.h:536
virtual std::string toText() const
Convert Lease to Printable Form.
Definition lease.cc:544
DuidPtr duid_
Client identifier.
Definition lease.h:556
static const uint32_t STATE_DEFAULT
A lease in the default state.
Definition lease.h:69
@ TYPE_PD
the lease contains IPv6 prefix (for prefix delegation)
Definition lease.h:49
@ TYPE_NA
the lease contains non-temporary IPv6 address
Definition lease.h:47
time_t cltt_
Client last transmission time.
Definition lease.h:149
structure that describes a single relay information
Definition pkt6.h:85
isc::dhcp::OptionCollection options_
options received from a specified relay, except relay-msg option
Definition pkt6.h:104