Kea 3.2.1-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}
DUID(const std::vector< uint8_t > &data)
Constructor from vector.
Definition duid.cc:27
@ map
Definition data.h:160
@ integer
Definition data.h:153
@ list
Definition data.h:159
Option6IAAddr(uint16_t type, const isc::asiolink::IOAddress &addr, uint32_t preferred, uint32_t valid)
Constructor, used for options constructed (during transmission).
Option6IAPrefix(uint16_t type, const isc::asiolink::IOAddress &addr, uint8_t prefix_length, uint32_t preferred, uint32_t valid)
Constructor, used for options constructed (during transmission).
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
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
LeasePageSize(const size_t page_size)
Constructor.
Definition lease_mgr.cc:47
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.
Option6AddrLst(uint16_t type, const AddressContainer &addrs)
Constructor used during option generation.
std::vector< isc::asiolink::IOAddress > AddressContainer
a container for (IPv6) addresses
Option6StatusCode(const uint16_t status_code, const std::string &status_message)
Constructor, used for options constructed (during transmission).
OptionCustom(const OptionDefinition &def, Universe u)
Constructor, used for options to be sent.
Base class representing a DHCP option definition.
static const size_t OPTION6_HDR_LEN
length of any DHCPv6 option header
Definition option.h:87
Option(Universe u, uint16_t type)
ctor, used for options constructed, usually during transmission
Definition option.cc:39
Pkt6(uint8_t msg_type, uint32_t transid, DHCPv6Proto proto=UDP)
Constructor, used in replying to a message.
Definition pkt6.cc:58
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(const int status_code, const std::string &text, const ConstElementPtr &arg)
Creates a standard config/command level answer message.
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