Kea 3.2.0-git
lease_query_impl6.cc
Go to the documentation of this file.
1// Copyright (C) 2020-2026 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
93LeaseQueryImpl6::processQuery(PktPtr base_query, bool& invalid) const {
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 invalid = true;
104 StatsMgr::instance().addValue("pkt6-rfc-violation",
105 static_cast<int64_t>(1));
106 isc_throw(BadValue, "DHCPV6_LEASEQUERY must supply a D6O_CLIENTID");
107 }
108
109 // If client sent a server-id, validate it.
110 try {
111 testServerId(query);
112 } catch (const BadValue&) {
113 invalid = true;
114 // Drop statistic updated by testServerId.
115 throw;
116 }
117
118 // Validates query content using the source address.
119 IOAddress requester_ip = query->getRemoteAddr();
120 if (requester_ip.isV6Zero()) {
122 invalid = true;
123 StatsMgr::instance().addValue("pkt6-rfc-violation",
124 static_cast<int64_t>(1));
125 isc_throw(BadValue, "DHCPV6_LEASEQUERY source address cannot be ::");
126 }
127
128 if (!isRequester(requester_ip)) {
129 // RFC 5007 says we may discard or return STATUS_NotAllowed
130 invalid = true;
131 StatsMgr::instance().addValue("pkt6-admin-filtered",
132 static_cast<int64_t>(1));
134 "rejecting DHCPV6_LEASEQUERY from unauthorized requester: "
135 << requester_ip.toText());
136 }
137
138 // Get the lease query option.
139 OptionCustomPtr lq_option = boost::dynamic_pointer_cast<OptionCustom>
140 (query->getOption(D6O_LQ_QUERY));
141 if (!lq_option) {
142 invalid = true;
143 StatsMgr::instance().addValue("pkt6-rfc-violation",
144 static_cast<int64_t>(1));
145 isc_throw(BadValue, "DHCPV6_LEASEQUERY must supply a D6O_LQ_QUERY option");
146 }
147
148 // Extract the type and link fields.
149 uint8_t query_type;
150 IOAddress query_link_addr(IOAddress::IPV6_ZERO_ADDRESS());
151 try {
152 query_type = lq_option->readInteger<uint8_t>(0);
153 query_link_addr = lq_option->readAddress(1);
154 } catch (const std::exception& ex) {
155 // unpack() should catch this?
156 invalid = true;
157 StatsMgr::instance().addValue("pkt6-rfc-violation",
158 static_cast<int64_t>(1));
159 isc_throw(BadValue, "error reading query field(s):" << ex.what());
160 }
161
162 // Based on the query type, extract the requisite options and
163 // perform the query.
164 Lease6Collection leases;
165 Option6StatusCodePtr status_opt;
166 switch (query_type) {
167 case LQ6QT_BY_ADDRESS: {
168 Option6IAAddrPtr query_iaaddr = boost::dynamic_pointer_cast<Option6IAAddr>
169 (lq_option->getOption(D6O_IAADDR));
170 if (!query_iaaddr) {
171 status_opt = makeStatusOption(STATUS_MalformedQuery, "missing D6O_IAADDR");
172 } else {
173 status_opt = queryByIpAddress(query_iaaddr->getAddress(), leases, prefix_lens_);
174 }
175
176 break;
177 }
178
179 case LQ6QT_BY_CLIENTID: {
180 OptionPtr opt = lq_option->getOption(D6O_CLIENTID);
181 if (!opt) {
182 status_opt = makeStatusOption(STATUS_MalformedQuery, "missing D6O_CLIENTID");
183 break;
184 }
185
186 DuidPtr query_client_id;
187 try {
188 query_client_id.reset(new DUID(opt->getData()));
189 } catch (const std::exception& ex) {
190 status_opt = makeStatusOption(STATUS_MalformedQuery, "malformed D6O_CLIENTID");
191 break;
192 }
193
194 status_opt = queryByClientId(query_client_id, query_link_addr, leases);
195 break;
196 }
197
198 default:
199 status_opt = makeStatusOption(STATUS_UnknownQueryType, "unknown query-type");
200 break;
201 }
202
203 // Construct the reply.
204 Pkt6Ptr reply = buildReply(status_opt, query, leases);
205 if (reply) {
206 sendResponse(reply);
207 }
208}
209
211LeaseQueryImpl6::getPrefixFromAddress(const IOAddress& address, uint8_t prefix_length) {
212 if (address.getFamily() != AF_INET6) {
213 isc_throw(BadValue, "getPrefixFromAddress() - not a v6 address: " << address);
214 }
215
216 if (prefix_length == 0 || prefix_length > 128) {
217 isc_throw(BadValue, "getPrefixFromAddress() - invalid prefix length:" << prefix_length);
218 }
219
220 // Get the address as bytes.
221 auto address_bytes = address.toBytes();
222
223 // Copy the whole bytes into the prefix first.
224 auto keep_bytes = prefix_length / 8;
225 std::vector<uint8_t> prefix_bytes(address_bytes.begin(), address_bytes.begin() + keep_bytes);
226
227 // Mask on any remaining bits.
228 auto keep_bits = prefix_length % 8;
229
230 static uint8_t masks[] = { 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe };
231 if (keep_bits) {
232 prefix_bytes.push_back(address_bytes[keep_bytes] & masks[keep_bits - 1]);
233 }
234
235 // IOAddress::fromBytes() requires 16 bytes of data so pad it out with zeros.
236 prefix_bytes.insert(prefix_bytes.end(), 16 - prefix_bytes.size(), 0);
237
238 return (IOAddress::fromBytes(AF_INET6, prefix_bytes.data()));
239}
240
243 const PrefixLengthList& prefix_lengths) {
244 // Database possible call: check if the hook was terminated.
246 // Look for a lease for the given address.
248 if (!lease && prefix_lengths.size()) {
249 // Iterate over list of prefix-lengths in descending order.
250 for (auto const& it : boost::adaptors::reverse(prefix_lengths)) {
251 IOAddress prefix = getPrefixFromAddress(iaaddr, it);
253 if (lease) {
254 break;
255 }
256 }
257 }
258
259 if (lease) {
260 if ((lease->state_ == Lease::STATE_DEFAULT) && (!lease->expired())) {
261 // Found an active lease.
262 leases.push_back(lease);
263 return (makeStatusOption(STATUS_Success, "active lease found"));
264 }
265
266 // There's a lease but it isn't active.
267 // Not real clear what should get returned in this case.
268 return (makeStatusOption(STATUS_Success, "inactive lease exists"));
269 }
270
271 // We didn't find a lease, so we need to determine if it is a lease
272 // we should know about. We iterate over all subnets, in case the
273 // address is inRange() of more than one subnet.
274 const Subnet6Collection* subnets;
275 subnets = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getAll();
276 for (auto const& subnet : *subnets) {
277
278 // Belongs to a pool in this subnet, but not leased.
279 if ((subnet->inPool(Lease::TYPE_NA, iaaddr)) ||
280 (subnet->inPool(Lease::TYPE_PD, iaaddr))) {
281 return (makeStatusOption(STATUS_Success, "no active lease"));
282 }
283 }
284
285 return (makeStatusOption(STATUS_NotConfigured, "address not in a configured pool"));
286}
287
289LeaseQueryImpl6::queryByClientId(const DuidPtr& client_id, const IOAddress& link_addr,
290 Lease6Collection& leases) {
291 // If the client specified a link to filter on, look up matching subnets.
292 // We'll fetch the leases by client DUID and link filter them afterwards.
293 SubnetIDSet links;
294 if (!link_addr.isV6Zero()) {
295 auto subnets = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6();
296 links = subnets->getLinks(link_addr);
297 if (links.empty()) {
298 return (makeStatusOption(STATUS_NotConfigured, "not a configured link"));
299 }
300 }
301
302 // Database possible call: check if the hook was terminated.
304
305 // Fetch all leases by client DUID.
306 Lease6Collection found_leases = LeaseMgrFactory::instance().getLeases6(*client_id);
307
308 // We want only the active leases.
309 if (!found_leases.empty()) {
310 for (auto const& lease : found_leases) {
311 if (lease->state_ == Lease::STATE_DEFAULT && !lease->expired()) {
312 // Filter by query links (if any).
313 if (!links.empty() && !links.count(lease->subnet_id_)) {
314 continue;
315 }
316
317 // It's a match, keep it.
318 leases.push_back(lease);
319 }
320 }
321 }
322
323 if (!leases.empty()) {
324 // Sort the leases by descending value of CLTT (i.e. newest first)
325 std::sort(leases.begin(), leases.end(), cltt_descending);
326 return (makeStatusOption(STATUS_Success, "active lease(s) found"));
327 }
328
329 return (makeStatusOption(STATUS_Success, "no active leases"));
330}
331
334 IOAddress& start_addr,
335 const size_t page_size,
336 const IOAddress& link_addr,
337 SubnetIDSet& links,
338 Lease6Collection& leases) {
339 // If the client specified a link to filter on, look up matching subnets.
340 links.clear();
341 if (!link_addr.isV6Zero()) {
342 auto subnets = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6();
343 links = subnets->getLinks(link_addr);
344 if (links.empty()) {
345 return (makeStatusOption(STATUS_NotConfigured, "not a configured link"));
346 }
347 }
348
349 // Fetch an initial page of leases by relay DUID.
350 start_addr = IOAddress::IPV6_ZERO_ADDRESS();
351 Lease6Collection found_leases;
352 for (;;) {
353 // Database possible call: check if the hook was terminated.
355
356 found_leases =
358 start_addr,
359 LeasePageSize(page_size));
360 if (found_leases.empty()) {
361 return (makeStatusOption(STATUS_Success, "no active leases"));
362 }
363 // Record the last address to restart from this point.
364 start_addr = found_leases.back()->addr_;
365 for (auto const& lease : found_leases) {
366 if (lease->state_ == Lease::STATE_DEFAULT && !lease->expired()) {
367 // Filter by query links (if any).
368 if (!links.empty() && !links.count(lease->subnet_id_)) {
369 continue;
370 }
371
372 // It's a match, keep it.
373 leases.push_back(lease);
374 }
375 }
376
377 if (!leases.empty()) {
378 return (makeStatusOption(STATUS_Success, "active lease(s) found"));
379 }
380 }
381}
382
383void
385 IOAddress& start_addr,
386 const size_t page_size,
387 const SubnetIDSet& links,
388 Lease6Collection& leases) {
389 // Database possible call: check if the hook was terminated.
391
392 Lease6Collection found_leases =
394 start_addr,
395 LeasePageSize(page_size));
396 if (found_leases.empty()) {
397 return;
398 }
399 const IOAddress seen = start_addr;
400 // Record the last address to restart from this point.
401 start_addr = found_leases.back()->addr_;
402 if (start_addr == seen) {
403 return;
404 }
405 for (auto const& lease : found_leases) {
406 if (lease->addr_ == seen) {
407 continue;
408 }
409 if (lease->state_ == Lease::STATE_DEFAULT && !lease->expired()) {
410 // Filter by query links (if any).
411 if (!links.empty() && !links.count(lease->subnet_id_)) {
412 continue;
413 }
414 }
415
416 // It's a match, keep it.
417 leases.push_back(lease);
418 }
419}
420
423 IOAddress& start_addr,
424 const size_t page_size,
425 const IOAddress& link_addr,
426 SubnetIDSet& links,
427 Lease6Collection& leases) {
428 // If the client specified a link to filter on, look up matching subnets.
429 links.clear();
430 if (!link_addr.isV6Zero()) {
431 auto subnets = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6();
432 links = subnets->getLinks(link_addr);
433 if (links.empty()) {
434 return (makeStatusOption(STATUS_NotConfigured, "not a configured link"));
435 }
436 }
437
438 // Fetch an initial page of leases by remote id.
439 start_addr = IOAddress::IPV6_ZERO_ADDRESS();
440 Lease6Collection found_leases;
441 for (;;) {
442 // Database possible call: check if the hook was terminated.
444
445 found_leases =
447 start_addr,
448 LeasePageSize(page_size));
449 if (found_leases.empty()) {
450 return (makeStatusOption(STATUS_Success, "no active leases"));
451 }
452 // Record the last address to restart from this point.
453 start_addr = found_leases.back()->addr_;
454 for (auto const& lease : found_leases) {
455 if (lease->state_ == Lease::STATE_DEFAULT && !lease->expired()) {
456 // Filter by query links (if any).
457 if (!links.empty() && !links.count(lease->subnet_id_)) {
458 continue;
459 }
460
461 // It's a match, keep it.
462 leases.push_back(lease);
463 }
464 }
465
466 if (!leases.empty()) {
467 return (makeStatusOption(STATUS_Success, "active lease(s) found"));
468 }
469 }
470}
471
472void
474 IOAddress& start_addr,
475 const size_t page_size,
476 const SubnetIDSet& links,
477 Lease6Collection& leases) {
478 // Database possible call: check if the hook was terminated.
480
481 Lease6Collection found_leases =
483 start_addr,
484 LeasePageSize(page_size));
485 if (found_leases.empty()) {
486 return;
487 }
488 const IOAddress seen = start_addr;
489 // Record the last address to restart from this point.
490 start_addr = found_leases.back()->addr_;
491 if (start_addr == seen) {
492 return;
493 }
494 for (auto const& lease : found_leases) {
495 if (lease->addr_ == seen) {
496 continue;
497 }
498 if (lease->state_ == Lease::STATE_DEFAULT && !lease->expired()) {
499 // Filter by query links (if any).
500 if (!links.empty() && !links.count(lease->subnet_id_)) {
501 continue;
502 }
503 }
504
505 // It's a match, keep it.
506 leases.push_back(lease);
507 }
508}
509
512 const size_t page_size,
513 const IOAddress& link_addr,
514 SubnetIDSet& links,
515 Lease6Collection& leases) {
516 // The link is required.
517 if (link_addr.isV6Zero()) {
518 return (makeStatusOption(STATUS_MalformedQuery, "link address is ::"));
519 }
520 links.clear();
521 auto subnets = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6();
522 links = subnets->getLinks(link_addr);
523 if (links.empty()) {
524 return (makeStatusOption(STATUS_NotConfigured, "not a configured link"));
525 }
526
527 Lease6Collection found_leases;
528 // Iterate over subnets.
529 for (;;) {
530 // Try first subnet.
531 auto it = links.begin();
532 if (it == links.end()) {
533 // No subnet: done.
534 return (makeStatusOption(STATUS_Success, "no active leases"));
535 }
536 // Fetch an initial page of leases on the subnet.
537 start_addr = IOAddress::IPV6_ZERO_ADDRESS();
538 for (;;) {
539 // Database possible call: check if the hook was terminated.
541
542 found_leases =
543 LeaseMgrFactory::instance().getLeases6(*it, start_addr,
544 LeasePageSize(page_size));
545 if (found_leases.empty()) {
546 // Remove the current subnet and try the next one.
547 links.erase(it);
548 start_addr = IOAddress::IPV6_ZERO_ADDRESS();
549 break;
550 }
551
552 // Record the last address to restart from this point.
553 start_addr = found_leases.back()->addr_;
554 for (auto const& lease : found_leases) {
555 if (lease->state_ == Lease::STATE_DEFAULT &&
556 !lease->expired()) {
557 // It's a match, keep it.
558 leases.push_back(lease);
559 }
560 }
561 if (!leases.empty()) {
562 return (makeStatusOption(STATUS_Success, "active lease(s) found"));
563 }
564 }
565 }
566}
567
568void
570 const size_t page_size,
571 SubnetIDSet& links,
572 Lease6Collection& leases) {
573
574 Lease6Collection found_leases;
575 // Iterate over subnets.
576 for (;;) {
577 // Try first subnet.
578 auto it = links.begin();
579 if (it == links.end()) {
580 // No subnet: done.
581 return;
582 }
583 // Fetch next page of leases on the subnet.
584 for (;;) {
585 // Database possible call: check if the hook was terminated.
587
588 found_leases =
589 LeaseMgrFactory::instance().getLeases6(*it, start_addr,
590 LeasePageSize(page_size));
591 if (found_leases.empty()) {
592 // Remove the current subnet and try the next one.
593 links.erase(it);
594 start_addr = IOAddress::IPV6_ZERO_ADDRESS();
595 break;
596 }
597
598 const IOAddress seen = start_addr;
599 // Record the last address to restart from this point.
600 start_addr = found_leases.back()->addr_;
601 if (start_addr == seen) {
602 return;
603 }
604 for (auto const& lease : found_leases) {
605 if (lease->addr_ == seen) {
606 continue;
607 }
608 if (lease->state_ == Lease::STATE_DEFAULT &&
609 !lease->expired()) {
610 // It's a match, keep it.
611 leases.push_back(lease);
612 }
613 }
614 if (!leases.empty()) {
615 return;
616 }
617 }
618 }
619}
620
623 const Pkt6Ptr& query,
624 Lease6Collection& leases) {
625 if (!status) {
626 // Shouldn't happen.
627 isc_throw(Unexpected, "status option cannot be empty");
628 }
629
630 Pkt6Ptr reply;
631 switch (status->getStatusCode()) {
632 case STATUS_Success: {
633 // Create the reply.
634 reply = initReply(query);
635
636 // If we found leases add the client and/or relay-data options.
637 if (!leases.empty()) {
638 // Add the client option.
639 OptionPtr client_opt = makeClientOption(leases);
640 reply->addOption(client_opt);
641
642 // If we are returning leases (not links), make the
643 // relay option from the extended-store (if any) of
644 // the newest lease.
645 if (client_opt->getType() != D6O_LQ_CLIENT_LINK) {
646 OptionPtr opt = makeRelayOption(*(*leases.begin()));
647 if (opt) {
648 reply->addOption(opt);
649 }
650 }
651 }
652
655
656 // RFC 5007 says you may return a status of success.
657 // ISC DHCP does not.
658 reply->addOption(status);
659 break;
660 }
661
665 case STATUS_NotAllowed: {
666 // Query could not be performed or was for an address
667 // we do not know about. We send back only the status.
668 reply = initReply(query);
669 reply->addOption(status);
670 break;
671 }
672
673 default:
674 // No meaningful reply can be sent.
675 break;
676 }
677
678 return (reply);
679}
680
683 Pkt6Ptr reply;
684
685 reply.reset(new Pkt6(DHCPV6_LEASEQUERY_REPLY, query->getTransid()));
686 reply->setRemoteAddr(query->getRemoteAddr());
687 reply->setRemotePort(query->getRemotePort());
688 reply->setLocalAddr(query->getLocalAddr());
689 reply->setLocalPort(query->getLocalPort());
690 reply->setIface(query->getIface());
691 reply->setIndex(query->getIndex());
692
693 DuidPtr duid = query->getClientId();
694 if (!duid) {
695 isc_throw(Unexpected, "query has no D6O_CLIENTID");
696 }
697
698 OptionPtr opt(new Option(Option::V6, D6O_CLIENTID, duid->getDuid()));
699 reply->addOption(opt);
700
702 ->getCfgDUID()->getCurrentDuid();
703 if (!server_id) {
704 isc_throw(Unexpected, "server_id does not exist");
705 }
706
707 opt.reset(new Option(Option::V6, D6O_SERVERID, server_id->getDuid()));
708 reply->addOption(opt);
709 return (reply);
710}
711
714 Pkt6Ptr response;
715
716 response.reset(new Pkt6(DHCPV6_LEASEQUERY_DATA, query->getTransid()));
717 response->setRemoteAddr(query->getRemoteAddr());
718 response->setRemotePort(query->getRemotePort());
719 return (response);
720}
721
724 Pkt6Ptr done;
725
726 done.reset(new Pkt6(DHCPV6_LEASEQUERY_DONE, query->getTransid()));
727 done->setRemoteAddr(query->getRemoteAddr());
728 done->setRemotePort(query->getRemotePort());
729 return (done);
730}
731
734 if (leases.empty()) {
735 isc_throw(Unexpected, "makeClientOption: leases list is empty");
736 }
737
738 // Querying by client-id may find leases on multiple links.
739 // We need to detect that case so we can return a D6O_LQ_CLIENT_LINK
740 // option.
741 // Iterate over leases and build a list of unique subnet ids.
742 SubnetIDSet links;
743 for (auto const& lease : leases) {
744 if (lease->subnet_id_) {
745 // The use of a set will remove duplicates.
746 static_cast<void>(links.insert(lease->subnet_id_));
747 }
748 }
749
750 if (links.size() > 1) {
751 CfgSubnets6Ptr subnets = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6();
753 for (auto const& link : links) {
754 ConstSubnet6Ptr subnet = subnets->getBySubnetId(link);
755 if (!subnet) {
756 continue;
757 }
758 std::pair<isc::asiolink::IOAddress, uint8_t> pair = subnet->get();
759 addrs.push_back(pair.first);
760 }
761
763 return (opt);
764 }
765
767 OptionCustomPtr cd_option(new OptionCustom(def, Option::V6));
768
769 // Get the client id and CLTT from the first lease.
770 const Lease6& first_lease = *(*leases.begin());
771 OptionPtr opt(new Option(Option::V6, D6O_CLIENTID, first_lease.duid_->getDuid()));
772 cd_option->addOption(opt);
773
774 // How much time has elapsed since last client transmission?
775 time_t now = time(0);
776 time_t elapsed;
777 if (first_lease.cltt_ < now) {
778 elapsed = now - first_lease.cltt_;
779 } else {
780 // Something insane here so send back times unadjusted.
781 elapsed = 0;
782 }
783
784 // Add CLTT option based on the newest lease.
785 opt.reset(new OptionUint32(Option::V6, D6O_CLT_TIME, elapsed));
786 cd_option->addOption(opt);
787
788 // Iterate over the leases adding the appropriate option
789 // for each one.
790 for (auto const& lease : leases) {
791 if (lease->cltt_ < now) {
792 elapsed = now - lease->cltt_;
793 } else {
794 // Something insane here so send back times unadjusted.
795 elapsed = 0;
796 }
797
798 // Calculate the remaining lifetimes.
799 uint32_t preferred = lease->preferred_lft_;
800 if (elapsed < preferred) {
801 preferred -= elapsed;
802 }
803
804 uint32_t valid = lease->valid_lft_;
805 if (elapsed < valid) {
806 valid -= elapsed;
807 }
808
809 // Create the option.
810 OptionPtr lease_opt;
811 if (lease->type_ == Lease::TYPE_NA) {
812 lease_opt.reset(new Option6IAAddr(D6O_IAADDR, lease->addr_,
813 preferred, valid));
814 } else {
815 lease_opt.reset(new Option6IAPrefix(D6O_IAPREFIX,
816 lease->addr_, lease->prefixlen_,
817 preferred, valid));
818 }
819
820 cd_option->addOption(lease_opt);
821 }
822
823 return (cd_option);
824}
825
829 OptionCustomPtr cd_option(new OptionCustom(def, Option::V6));
830
831 // Get the client id and CLTT.
832 OptionPtr opt(new Option(Option::V6, D6O_CLIENTID, lease->duid_->getDuid()));
833 cd_option->addOption(opt);
834
835 // How much time has elapsed since last client transmission?
836 time_t now = time(0);
837 time_t elapsed;
838 if (lease->cltt_ < now) {
839 elapsed = now - lease->cltt_;
840 } else {
841 // Something insane here so send back times unadjusted.
842 elapsed = 0;
843 }
844
845 // Add CLTT option.
846 opt.reset(new OptionUint32(Option::V6, D6O_CLT_TIME, elapsed));
847 cd_option->addOption(opt);
848
849 // Calculate the remaining lifetimes.
850 uint32_t preferred = lease->preferred_lft_;
851 if (elapsed < preferred) {
852 preferred -= elapsed;
853 }
854
855 uint32_t valid = lease->valid_lft_;
856 if (elapsed < valid) {
857 valid -= elapsed;
858 }
859
860 // Create the resource option.
861 OptionPtr lease_opt;
862 if (lease->type_ == Lease::TYPE_NA) {
863 lease_opt.reset(new Option6IAAddr(D6O_IAADDR, lease->addr_,
864 preferred, valid));
865 } else {
866 lease_opt.reset(new Option6IAPrefix(D6O_IAPREFIX,
867 lease->addr_, lease->prefixlen_,
868 preferred, valid));
869 }
870 cd_option->addOption(lease_opt);
871
872 // Add relay info.
873 OptionPtr relay_opt = makeRelayOption(*lease);
874 if (relay_opt) {
875 cd_option->addOption(relay_opt);
876 }
877
878 return (cd_option);
879}
880
883 ConstElementPtr user_context;
884 std::vector<RelayInfoPtr> relay_infos;
885
886 try {
887 if (lease.getContext()) {
888 user_context = UserContext::toElement(lease.getContext());
889 }
890
891 if (!user_context) {
892 return (OptionPtr());
893 }
894
895 ConstElementPtr extended_info = user_context->get("ISC");
896 if (!extended_info) {
897 return (OptionPtr());
898 }
899
900 // New layout puts the extended info in the relay-info entry.
901 ConstElementPtr relay_info = extended_info->get("relay-info");
902 if (!relay_info) {
903 // Old layout uses the relays entry.
904 relay_info = extended_info->get("relays");
905 }
906 if (!relay_info) {
907 return (OptionPtr());
908 }
909
910 // Parse the relay element list into Pkt6::RelayInfo instances.
911 parseRelayInfoList(relay_info, relay_infos);
912 if (relay_infos.empty()) {
913 // If we have an empty list, that's actually wrong, it should not
914 // have been stored in the first place.
915 isc_throw(Unexpected, "relay info list should not be empty");
916 }
917 } catch (const std::exception& ex) {
919 .arg(lease.toText())
920 .arg(ex.what());
921 return (OptionPtr());
922 }
923
924 // Create the relay data option.
926 OptionCustomPtr rd_option(new OptionCustom(def, Option::V6));
927
928 // The peer field should come from the outer-most relay
929 rd_option->writeAddress(relay_infos.front()->peeraddr_, 0);
930
931 // For convenience, set the index of the last one.
932 size_t innermost = relay_infos.size() - 1;
933
934 // Iterate backward through the RelayInfo list and calculate the
935 // packed size of each one in succession.
936 uint16_t len = 0;
937 for (size_t i = relay_infos.size(); i > 0; --i) {
938 relay_infos[i - 1]->relay_msg_len_ = len;
939 len += getRelayOverhead(*(relay_infos[i - 1]), (i == innermost));
940 }
941
942 // Now iterate forward over them, writing them to an OutputBuffer.
944 + relay_infos[0]->relay_msg_len_);
945
946 for (size_t i = 0; i < relay_infos.size(); ++i) {
947 RelayInfoPtr relay = relay_infos[i];
948
949 // build relay-forw/relay-repl header (see RFC 9915, section 9)
950 buffer_out.writeUint8(DHCPV6_RELAY_FORW);
951 buffer_out.writeUint8(relay->hop_count_);
952 buffer_out.writeData(&(relay->linkaddr_.toBytes()[0]),
953 isc::asiolink::V6ADDRESS_LEN);
954 buffer_out.writeData(&relay->peeraddr_.toBytes()[0],
955 isc::asiolink::V6ADDRESS_LEN);
956
957 // Store every option in this relay's scope.
958 for (auto const& opt : relay->options_) {
959 (opt.second)->pack(buffer_out);
960 }
961
962 // Include the header for the relay-msg option which will
963 // contain the next relay forward. It's payload will be generated
964 // in the next iteration.
965 if (i < innermost) {
966 buffer_out.writeUint16(D6O_RELAY_MSG);
967 buffer_out.writeUint16(relay->relay_msg_len_);
968 }
969 }
970
971 // Now convert them to an option buffer and add them to
972 // relay data option.
973 const OptionBuffer& relay_buffer = buffer_out.getVector();
974 rd_option->writeBinary(relay_buffer, 1);
975
976 // Dizzy yet? Don't worry, we're done.
977 return (rd_option);
978}
979
980uint16_t
982 uint16_t len = Pkt6::DHCPV6_RELAY_HDR_LEN; // fixed header
983
984 if (innermost) {
985 len += Option::OPTION6_HDR_LEN; // header of the relay-msg option
986 }
987
988 for (auto const& opt : relay.options_) {
989 len += (opt.second)->len();
990 }
991
992 return (len);
993}
994
995void
997 std::vector<RelayInfoPtr>& relay_infos) {
998 if (!relay_info || relay_info->getType() != Element::list) {
999 isc_throw(BadValue, "parseRelayInfoList: relay-info element empty or not a list");
1000 }
1001
1002 for (auto const& relay : relay_info->listValue()) {
1004 relay_infos.push_back(info);
1005 }
1006}
1007
1010 if (!relay_elem || (relay_elem->getType() != Element::map)) {
1011 isc_throw(BadValue, "parseRelayInfo: relay element empty or not a map");
1012 }
1013
1014 RelayInfoPtr relay_info(new Pkt6::RelayInfo());
1015 auto elem = relay_elem->get("hop");
1016 if (!elem) {
1017 isc_throw(BadValue, "parseRelayInfo: 'hop' is missing");
1018 }
1019
1020 try {
1021 relay_info->hop_count_ = static_cast<uint8_t>(elem->intValue());
1022 } catch (const std::exception& ex) {
1023 isc_throw(BadValue, "parseRelayInfo: 'hop' is invalid: " << ex.what());
1024 }
1025
1026 elem = relay_elem->get("peer");
1027 if (!elem) {
1028 isc_throw(BadValue, "parseRelayInfo: 'peer' is missing");
1029 }
1030
1031 try {
1032 relay_info->peeraddr_ = IOAddress(elem->stringValue());
1033 if (!relay_info->peeraddr_.isV6()) {
1034 isc_throw(BadValue, "not a V6 address: " << relay_info->peeraddr_);
1035 }
1036 } catch (const std::exception& ex) {
1037 isc_throw(BadValue, "parseRelayInfo: 'peer' is invalid: " << ex.what());
1038 }
1039
1040 elem = relay_elem->get("link");
1041 if (!elem) {
1042 isc_throw(BadValue, "parseRelayInfo: 'link' is missing");
1043 }
1044
1045 try {
1046 relay_info->linkaddr_ = IOAddress(elem->stringValue());
1047 if (!relay_info->linkaddr_.isV6()) {
1048 isc_throw(BadValue, "not a V6 address: " << relay_info->linkaddr_);
1049 }
1050 } catch (const std::exception& ex) {
1051 isc_throw(BadValue, "parseRelayInfo: 'link' is invalid: " << ex.what());
1052 }
1053
1054 // The options element is optional.
1055 elem = relay_elem->get("options");
1056 if (elem) {
1057 try {
1058 std::string hex_str = elem->stringValue();
1059
1060 OptionBuffer binary;
1061 util::str::decodeFormattedHexString(hex_str, binary);
1062 static_cast<void>(LibDHCP::unpackOptions6(binary, DHCP6_OPTION_SPACE,
1063 relay_info->options_));
1064 } catch (const std::exception& ex) {
1065 isc_throw(BadValue, "parseRelayInfo: 'options' is invalid: " << ex.what());
1066 }
1067 }
1068
1069 return (relay_info);
1070}
1071
1072void
1074 OptionPtr client_server_id = query->getOption(D6O_SERVERID);
1075 if (client_server_id) {
1076 DuidPtr client_duid;
1077 try {
1078 client_duid.reset(new DUID(client_server_id->getData()));
1079 } catch (const std::exception& ex) {
1080 StatsMgr::instance().addValue("pkt6-rfc-violation",
1081 static_cast<int64_t>(1));
1082 isc_throw(BadValue, "DHCPV6_LEASEQUERY D6O_SERVERID malformed: "
1083 << ex.what());
1084 }
1085
1086 DuidPtr server_id = CfgMgr::instance().getCurrentCfg()->getCfgDUID()->getCurrentDuid();
1087 if (!server_id) {
1088 StatsMgr::instance().addValue("pkt6-rfc-violation",
1089 static_cast<int64_t>(1));
1090 isc_throw(Unexpected, "Server has no current server id?");
1091 } else if (*client_duid != *server_id) {
1092 StatsMgr::instance().addValue("pkt6-not-for-us",
1093 static_cast<int64_t>(1));
1094 isc_throw(BadValue, "rejecting DHCPV6_LEASEQUERY from: "
1095 << query->getRemoteAddr() << ", unknown server-id: "
1096 << (client_server_id ? client_server_id->toText() : "malformed"));
1097 }
1098 }
1099
1100 // We have a winner!
1101}
1102
1103void
1105 // Pack the response.
1106 try {
1107 response->pack();
1108 } catch (const std::exception& ex) {
1110 .arg(leaseQueryLabel(response))
1111 .arg(ex.what());
1112 return;
1113 }
1114
1115 try {
1116 send(response);
1118 .arg(leaseQueryLabel(response))
1119 .arg(response->getRemoteAddr())
1120 .arg(response->getRemotePort());
1121
1122 StatsMgr::instance().addValue("pkt6-sent", static_cast<int64_t>(1));
1123 StatsMgr::instance().addValue("pkt6-lease-query-reply-sent",
1124 static_cast<int64_t>(1));
1125 } catch (const std::exception& ex) {
1127 .arg(leaseQueryLabel(response))
1128 .arg(response->getIface())
1129 .arg(response->getRemoteAddr())
1130 .arg(response->getRemotePort())
1131 .arg(ex.what());
1132 }
1133}
1134
1135void LeaseQueryImpl6::send(const dhcp::Pkt6Ptr& response) const {
1136 IfaceMgr::instance().send(response);
1137}
1138
1141 const std::string message) {
1142 Option6StatusCodePtr opt(new Option6StatusCode(status_code, message));
1143 return (opt);
1144}
1145
1146std::string
1148 std::stringstream label;
1149
1150 try {
1151 DuidPtr client_id = packet->getClientId();
1152 label << "type: " << packet->getName()
1153 << ", client id: " << (client_id ? client_id->toText() : "<none>")
1154 << ", requester: " << packet->getRemoteAddr()
1155 << ", transid: " << packet->getTransid();
1156
1157 } catch (const std::exception& ex) {
1158 // Shouldn't happen. This just ensures we're exception safe.
1159 label << "label error" << ex.what();
1160 }
1161
1162 return (label.str());
1163}
1164
1165int
1167 ConstElementPtr response;
1168 size_t upgraded = 0;
1170 try {
1172 auto& lease_mgr = LeaseMgrFactory::instance();
1173 // check getExtendedInfoTablesEnabled() here?
1174 upgraded = lease_mgr.upgradeExtendedInfo6(page_size);
1175 } catch (const std::exception& ex) {
1176 // log here.
1177 response = createAnswer(CONTROL_RESULT_ERROR, ex.what());
1178 handle.setArgument("response", response);
1179 return (1);
1180 }
1181
1182 // log here.
1183 std::ostringstream msg;
1184 msg << "Upgraded " << upgraded << " lease";
1185 if (upgraded != 1) {
1186 msg << "s";
1187 }
1188 response = createAnswer(CONTROL_RESULT_SUCCESS, msg.str());
1189 handle.setArgument("response", response);
1190 return (0);
1191}
1192
1193void
1195 if (build_prefix_lens_) {
1196 // Empty the current entries.
1198
1199 // traverse subnet pd pools and build list
1200 const Subnet6Collection* subnets = cfg->getCfgSubnets6()->getAll();
1201 for (auto const& subnet : *subnets) {
1202 const PoolCollection& pools = subnet->getPools(Lease::TYPE_PD);
1203 for (auto const& pool : pools) {
1204 Pool6Ptr p6 = boost::dynamic_pointer_cast<Pool6>(pool);
1205 addPrefixLength(p6->getLength());
1206 }
1207 }
1208 }
1209
1212}
1213
1214std::string
1216 std::ostringstream oss;
1217 oss << "[";
1218
1219 auto first_one = true;
1220 for (auto const& it : boost::adaptors::reverse(prefix_lengths)) {
1221 if (!first_one) {
1222 oss << ",";
1223 } else {
1224 first_one = false;
1225 }
1226
1227 oss << " " << static_cast<int>(it);
1228 }
1229
1230 oss << " ]";
1231 return (oss.str());
1232}
@ map
Definition data.h:160
@ integer
Definition data.h:153
@ list
Definition data.h:159
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:52
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 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, size_t rec_level=0)
Parses provided buffer as DHCPv6 options and creates Option objects.
Definition libdhcp++.cc:320
static const OptionDefinition & D6O_CLIENT_DATA_DEF()
Get definition of D6O_CLIENT_DATA option.
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 9915.
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.
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.
virtual void processQuery(isc::dhcp::PktPtr base_query, bool &invalid) const
Processes a single DHCPv6 client Lease Query.
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:30
@ info
Definition db_log.h:126
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:620
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:934
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:553
DuidPtr duid_
Client identifier.
Definition lease.h:556
static constexpr 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