Kea 3.1.5
lease_query_impl6.cc
Go to the documentation of this file.
1// Copyright (C) 2020-2025 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
8
10#include <dhcp/dhcp6.h>
11#include <dhcp/libdhcp++.h>
12#include <dhcp/pkt6.h>
13#include <dhcp/option_custom.h>
14#include <dhcp/option_int.h>
16#include <dhcp/option6_iaaddr.h>
18#include <dhcpsrv/cfgmgr.h>
20#include <lease_query_impl6.h>
21#include <lease_query_log.h>
22#include <blq_service.h>
23#include <stats/stats_mgr.h>
24#include <util/encode/encode.h>
25#include <util/io.h>
26#include <util/str.h>
27
28#include <boost/range/adaptor/reversed.hpp>
29#include <boost/shared_ptr.hpp>
30#include <boost/pointer_cast.hpp>
31
32#include <set>
33
34using namespace isc;
35using namespace isc::asiolink;
36using namespace isc::config;
37using namespace isc::data;
38using namespace isc::dhcp;
39using namespace isc::hooks;
40using namespace isc::lease_query;
41using namespace isc::log;
42using namespace isc::stats;
43
44namespace {
45
47bool cltt_descending(const Lease6Ptr& first, const Lease6Ptr& second) {
48 return (first->cltt_ > second->cltt_);
49}
50
51}
52
55 auto blq_service = BulkLeaseQueryService::instance();
56 if (blq_service) {
57 CfgMgr::instance().getStagingCfg()->getCfgDbAccess()->
58 setExtendedInfoTablesEnabled(blq_service->getExtendedInfoTablesEnabled());
59 }
60
61 ConstElementPtr prefix_lengths = config->get("prefix-lengths");
62 if (!prefix_lengths) {
63 return;
64 }
65
66 if (prefix_lengths->getType() != Element::list) {
67 isc_throw(BadValue, "'prefix-lengths' is not a list");
68 }
69
70 // If it's specified, empty or otherwise, we don't build it dynamically.
71 // An empty list "[]" means we don't do PD pool searching by IP address.
72 build_prefix_lens_ = false;
73 for (auto const& entry : prefix_lengths->listValue()) {
74 try {
75 if (entry->getType() != Element::integer) {
76 isc_throw(BadValue, "must be an integer");
77 }
78
79 auto plen = entry->intValue();
80 if (plen <= 0 || plen > 128) {
81 isc_throw(BadValue, "must be greater than 0 and less than or equal to 128");
82 }
83
84 addPrefixLength(plen);
85 } catch (const std::exception& ex) {
86 isc_throw(BadValue, "'prefix-lengths' entry '" << entry->str()
87 << "' is invalid: " << ex.what());
88 }
89 }
90}
91
92void
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 std::pair<isc::asiolink::IOAddress, uint8_t> pair = subnet->get();
756 addrs.push_back(pair.first);
757 }
758
760 return (opt);
761 }
762
764 OptionCustomPtr cd_option(new OptionCustom(def, Option::V6));
765
766 // Get the client id and CLTT from the first lease.
767 const Lease6& first_lease = *(*leases.begin());
768 OptionPtr opt(new Option(Option::V6, D6O_CLIENTID, first_lease.duid_->getDuid()));
769 cd_option->addOption(opt);
770
771 // How much time has elapsed since last client transmission?
772 time_t now = time(0);
773 time_t elapsed;
774 if (first_lease.cltt_ < now) {
775 elapsed = now - first_lease.cltt_;
776 } else {
777 // Something insane here so send back times unadjusted.
778 elapsed = 0;
779 }
780
781 // Add CLTT option based on the newest lease.
782 opt.reset(new OptionUint32(Option::V6, D6O_CLT_TIME, elapsed));
783 cd_option->addOption(opt);
784
785 // Iterate over the leases adding the appropriate option
786 // for each one.
787 for (auto const& lease : leases) {
788 if (lease->cltt_ < now) {
789 elapsed = now - lease->cltt_;
790 } else {
791 // Something insane here so send back times unadjusted.
792 elapsed = 0;
793 }
794
795 // Calculate the remaining lifetimes.
796 uint32_t preferred = lease->preferred_lft_;
797 if (elapsed < preferred) {
798 preferred -= elapsed;
799 }
800
801 uint32_t valid = lease->valid_lft_;
802 if (elapsed < valid) {
803 valid -= elapsed;
804 }
805
806 // Create the option.
807 OptionPtr lease_opt;
808 if (lease->type_ == Lease::TYPE_NA) {
809 lease_opt.reset(new Option6IAAddr(D6O_IAADDR, lease->addr_,
810 preferred, valid));
811 } else {
812 lease_opt.reset(new Option6IAPrefix(D6O_IAPREFIX,
813 lease->addr_, lease->prefixlen_,
814 preferred, valid));
815 }
816
817 cd_option->addOption(lease_opt);
818 }
819
820 return (cd_option);
821}
822
826 OptionCustomPtr cd_option(new OptionCustom(def, Option::V6));
827
828 // Get the client id and CLTT.
829 OptionPtr opt(new Option(Option::V6, D6O_CLIENTID, lease->duid_->getDuid()));
830 cd_option->addOption(opt);
831
832 // How much time has elapsed since last client transmission?
833 time_t now = time(0);
834 time_t elapsed;
835 if (lease->cltt_ < now) {
836 elapsed = now - lease->cltt_;
837 } else {
838 // Something insane here so send back times unadjusted.
839 elapsed = 0;
840 }
841
842 // Add CLTT option.
843 opt.reset(new OptionUint32(Option::V6, D6O_CLT_TIME, elapsed));
844 cd_option->addOption(opt);
845
846 // Calculate the remaining lifetimes.
847 uint32_t preferred = lease->preferred_lft_;
848 if (elapsed < preferred) {
849 preferred -= elapsed;
850 }
851
852 uint32_t valid = lease->valid_lft_;
853 if (elapsed < valid) {
854 valid -= elapsed;
855 }
856
857 // Create the resource option.
858 OptionPtr lease_opt;
859 if (lease->type_ == Lease::TYPE_NA) {
860 lease_opt.reset(new Option6IAAddr(D6O_IAADDR, lease->addr_,
861 preferred, valid));
862 } else {
863 lease_opt.reset(new Option6IAPrefix(D6O_IAPREFIX,
864 lease->addr_, lease->prefixlen_,
865 preferred, valid));
866 }
867 cd_option->addOption(lease_opt);
868
869 // Add relay info.
870 OptionPtr relay_opt = makeRelayOption(*lease);
871 if (relay_opt) {
872 cd_option->addOption(relay_opt);
873 }
874
875 return (cd_option);
876}
877
880 ConstElementPtr user_context;
881 std::vector<RelayInfoPtr> relay_infos;
882
883 try {
884 if (lease.getContext()) {
885 user_context = UserContext::toElement(lease.getContext());
886 }
887
888 if (!user_context) {
889 return (OptionPtr());
890 }
891
892 ConstElementPtr extended_info = user_context->get("ISC");
893 if (!extended_info) {
894 return (OptionPtr());
895 }
896
897 // New layout puts the extended info in the relay-info entry.
898 ConstElementPtr relay_info = extended_info->get("relay-info");
899 if (!relay_info) {
900 // Old layout uses the relays entry.
901 relay_info = extended_info->get("relays");
902 }
903 if (!relay_info) {
904 return (OptionPtr());
905 }
906
907 // Parse the relay element list into Pkt6::RelayInfo instances.
908 parseRelayInfoList(relay_info, relay_infos);
909 if (relay_infos.empty()) {
910 // If we have an empty list, that's actually wrong, it should not
911 // have been stored in the first place.
912 isc_throw(Unexpected, "relay info list should not be empty");
913 }
914 } catch (const std::exception& ex) {
916 .arg(lease.toText())
917 .arg(ex.what());
918 return (OptionPtr());
919 }
920
921 // Create the relay data option.
923 OptionCustomPtr rd_option(new OptionCustom(def, Option::V6));
924
925 // The peer field should come from the outer-most relay
926 rd_option->writeAddress(relay_infos.front()->peeraddr_, 0);
927
928 // For convenience, set the index of the last one.
929 size_t innermost = relay_infos.size() - 1;
930
931 // Iterate backward through the RelayInfo list and calculate the
932 // packed size of each one in succession.
933 uint16_t len = 0;
934 for (size_t i = relay_infos.size(); i > 0; --i) {
935 relay_infos[i - 1]->relay_msg_len_ = len;
936 len += getRelayOverhead(*(relay_infos[i - 1]), (i == innermost));
937 }
938
939 // Now iterate forward over them, writing them to an OutputBuffer.
941 + relay_infos[0]->relay_msg_len_);
942
943 for (size_t i = 0; i < relay_infos.size(); ++i) {
944 RelayInfoPtr relay = relay_infos[i];
945
946 // build relay-forw/relay-repl header (see RFC 8415, section 9)
947 buffer_out.writeUint8(DHCPV6_RELAY_FORW);
948 buffer_out.writeUint8(relay->hop_count_);
949 buffer_out.writeData(&(relay->linkaddr_.toBytes()[0]),
950 isc::asiolink::V6ADDRESS_LEN);
951 buffer_out.writeData(&relay->peeraddr_.toBytes()[0],
952 isc::asiolink::V6ADDRESS_LEN);
953
954 // Store every option in this relay's scope.
955 for (auto const& opt : relay->options_) {
956 (opt.second)->pack(buffer_out);
957 }
958
959 // Include the header for the relay-msg option which will
960 // contain the next relay forward. It's payload will be generated
961 // in the next iteration.
962 if (i < innermost) {
963 buffer_out.writeUint16(D6O_RELAY_MSG);
964 buffer_out.writeUint16(relay->relay_msg_len_);
965 }
966 }
967
968 // Now convert them to an option buffer and add them to
969 // relay data option.
970 const OptionBuffer& relay_buffer = buffer_out.getVector();
971 rd_option->writeBinary(relay_buffer, 1);
972
973 // Dizzy yet? Don't worry, we're done.
974 return (rd_option);
975}
976
977uint16_t
979 uint16_t len = Pkt6::DHCPV6_RELAY_HDR_LEN; // fixed header
980
981 if (innermost) {
982 len += Option::OPTION6_HDR_LEN; // header of the relay-msg option
983 }
984
985 for (auto const& opt : relay.options_) {
986 len += (opt.second)->len();
987 }
988
989 return (len);
990}
991
992void
994 std::vector<RelayInfoPtr>& relay_infos) {
995 if (!relay_info || relay_info->getType() != Element::list) {
996 isc_throw(BadValue, "parseRelayInfoList: relay-info element empty or not a list");
997 }
998
999 for (auto const& relay : relay_info->listValue()) {
1001 relay_infos.push_back(info);
1002 }
1003}
1004
1007 if (!relay_elem || (relay_elem->getType() != Element::map)) {
1008 isc_throw(BadValue, "parseRelayInfo: relay element empty or not a map");
1009 }
1010
1011 RelayInfoPtr relay_info(new Pkt6::RelayInfo());
1012 auto elem = relay_elem->get("hop");
1013 if (!elem) {
1014 isc_throw(BadValue, "parseRelayInfo: 'hop' is missing");
1015 }
1016
1017 try {
1018 relay_info->hop_count_ = static_cast<uint8_t>(elem->intValue());
1019 } catch (const std::exception& ex) {
1020 isc_throw(BadValue, "parseRelayInfo: 'hop' is invalid: " << ex.what());
1021 }
1022
1023 elem = relay_elem->get("peer");
1024 if (!elem) {
1025 isc_throw(BadValue, "parseRelayInfo: 'peer' is missing");
1026 }
1027
1028 try {
1029 relay_info->peeraddr_ = IOAddress(elem->stringValue());
1030 if (!relay_info->peeraddr_.isV6()) {
1031 isc_throw(BadValue, "not a V6 address: " << relay_info->peeraddr_);
1032 }
1033 } catch (const std::exception& ex) {
1034 isc_throw(BadValue, "parseRelayInfo: 'peer' is invalid: " << ex.what());
1035 }
1036
1037 elem = relay_elem->get("link");
1038 if (!elem) {
1039 isc_throw(BadValue, "parseRelayInfo: 'link' is missing");
1040 }
1041
1042 try {
1043 relay_info->linkaddr_ = IOAddress(elem->stringValue());
1044 if (!relay_info->linkaddr_.isV6()) {
1045 isc_throw(BadValue, "not a V6 address: " << relay_info->linkaddr_);
1046 }
1047 } catch (const std::exception& ex) {
1048 isc_throw(BadValue, "parseRelayInfo: 'link' is invalid: " << ex.what());
1049 }
1050
1051 // The options element is optional.
1052 elem = relay_elem->get("options");
1053 if (elem) {
1054 try {
1055 std::string hex_str = elem->stringValue();
1056
1057 OptionBuffer binary;
1058 util::str::decodeFormattedHexString(hex_str, binary);
1059 static_cast<void>(LibDHCP::unpackOptions6(binary, DHCP6_OPTION_SPACE,
1060 relay_info->options_));
1061 } catch (const std::exception& ex) {
1062 isc_throw(BadValue, "parseRelayInfo: 'options' is invalid: " << ex.what());
1063 }
1064 }
1065
1066 return (relay_info);
1067}
1068
1069void
1071 OptionPtr client_server_id = query->getOption(D6O_SERVERID);
1072 if (client_server_id) {
1073 DuidPtr client_duid;
1074 try {
1075 client_duid.reset(new DUID(client_server_id->getData()));
1076 } catch (const std::exception& ex) {
1077 StatsMgr::instance().addValue("pkt6-rfc-violation",
1078 static_cast<int64_t>(1));
1079 isc_throw(BadValue, "DHCPV6_LEASEQUERY D6O_SERVERID malformed: "
1080 << ex.what());
1081 }
1082
1083 DuidPtr server_id = CfgMgr::instance().getCurrentCfg()->getCfgDUID()->getCurrentDuid();
1084 if (!server_id) {
1085 StatsMgr::instance().addValue("pkt6-rfc-violation",
1086 static_cast<int64_t>(1));
1087 isc_throw(Unexpected, "Server has no current server id?");
1088 } else if (*client_duid != *server_id) {
1089 StatsMgr::instance().addValue("pkt6-not-for-us",
1090 static_cast<int64_t>(1));
1091 isc_throw(BadValue, "rejecting DHCPV6_LEASEQUERY from: "
1092 << query->getRemoteAddr() << ", unknown server-id: "
1093 << (client_server_id ? client_server_id->toText() : "malformed"));
1094 }
1095 }
1096
1097 // We have a winner!
1098}
1099
1100void
1102 // Pack the response.
1103 try {
1104 response->pack();
1105 } catch (const std::exception& ex) {
1107 .arg(leaseQueryLabel(response))
1108 .arg(ex.what());
1109 return;
1110 }
1111
1112 try {
1113 send(response);
1115 .arg(leaseQueryLabel(response))
1116 .arg(response->getRemoteAddr())
1117 .arg(response->getRemotePort());
1118
1119 StatsMgr::instance().addValue("pkt6-sent", static_cast<int64_t>(1));
1120 StatsMgr::instance().addValue("pkt6-lease-query-reply-sent",
1121 static_cast<int64_t>(1));
1122 } catch (const std::exception& ex) {
1124 .arg(leaseQueryLabel(response))
1125 .arg(response->getIface())
1126 .arg(response->getRemoteAddr())
1127 .arg(response->getRemotePort())
1128 .arg(ex.what());
1129 }
1130}
1131
1132void LeaseQueryImpl6::send(const dhcp::Pkt6Ptr& response) const {
1133 IfaceMgr::instance().send(response);
1134}
1135
1138 const std::string message) {
1139 Option6StatusCodePtr opt(new Option6StatusCode(status_code, message));
1140 return (opt);
1141}
1142
1143std::string
1145 std::stringstream label;
1146
1147 try {
1148 DuidPtr client_id = packet->getClientId();
1149 label << "type: " << packet->getName()
1150 << ", client id: " << (client_id ? client_id->toText() : "<none>")
1151 << ", requester: " << packet->getRemoteAddr()
1152 << ", transid: " << packet->getTransid();
1153
1154 } catch (const std::exception& ex) {
1155 // Shouldn't happen. This just ensures we're exception safe.
1156 label << "label error" << ex.what();
1157 }
1158
1159 return (label.str());
1160}
1161
1162int
1164 ConstElementPtr response;
1165 size_t upgraded = 0;
1167 try {
1169 auto& lease_mgr = LeaseMgrFactory::instance();
1170 // check getExtendedInfoTablesEnabled() here?
1171 upgraded = lease_mgr.upgradeExtendedInfo6(page_size);
1172 } catch (const std::exception& ex) {
1173 // log here.
1174 response = createAnswer(CONTROL_RESULT_ERROR, ex.what());
1175 handle.setArgument("response", response);
1176 return (1);
1177 }
1178
1179 // log here.
1180 std::ostringstream msg;
1181 msg << "Upgraded " << upgraded << " lease";
1182 if (upgraded != 1) {
1183 msg << "s";
1184 }
1185 response = createAnswer(CONTROL_RESULT_SUCCESS, msg.str());
1186 handle.setArgument("response", response);
1187 return (0);
1188}
1189
1190void
1192 if (build_prefix_lens_) {
1193 // Empty the current entries.
1195
1196 // traverse subnet pd pools and build list
1197 const Subnet6Collection* subnets = cfg->getCfgSubnets6()->getAll();
1198 for (auto const& subnet : *subnets) {
1199 const PoolCollection& pools = subnet->getPools(Lease::TYPE_PD);
1200 for (auto const& pool : pools) {
1201 Pool6Ptr p6 = boost::dynamic_pointer_cast<Pool6>(pool);
1202 addPrefixLength(p6->getLength());
1203 }
1204 }
1205 }
1206
1209}
1210
1211std::string
1213 std::ostringstream oss;
1214 oss << "[";
1215
1216 auto first_one = true;
1217 for (auto const& it : boost::adaptors::reverse(prefix_lengths)) {
1218 if (!first_one) {
1219 oss << ",";
1220 } else {
1221 first_one = false;
1222 }
1223
1224 oss << " " << static_cast<int>(it);
1225 }
1226
1227 oss << " ]";
1228 return (oss.str());
1229}
@ map
Definition data.h:147
@ integer
Definition data.h:140
@ list
Definition data.h:146
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
A generic exception that is thrown when an unexpected error condition occurs.
static CfgMgr & instance()
returns a single instance of Configuration Manager
Definition cfgmgr.cc:29
SrvConfigPtr getStagingCfg()
Returns a pointer to the staging configuration.
Definition cfgmgr.cc:121
SrvConfigPtr getCurrentCfg()
Returns a pointer to the current configuration.
Definition cfgmgr.cc:116
Holds DUID (DHCPv6 Unique Identifier)
Definition duid.h:142
static IfaceMgr & instance()
IfaceMgr is a singleton class.
Definition iface_mgr.cc:49
bool send(const Pkt6Ptr &pkt)
Sends an IPv6 packet.
static TrackingLeaseMgr & instance()
Return current lease manager.
virtual Lease6Collection getLeases6(Lease::Type type, const DUID &duid, uint32_t iaid) const =0
Returns existing IPv6 leases for a given DUID+IA combination.
virtual Lease6Collection getLeases6ByRelayId(const DUID &relay_id, const asiolink::IOAddress &lower_bound_address, const LeasePageSize &page_size)=0
Returns existing IPv6 leases with a given relay-id.
virtual Lease6Collection getLeases6ByRemoteId(const OptionBuffer &remote_id, const asiolink::IOAddress &lower_bound_address, const LeasePageSize &page_size)=0
Returns existing IPv6 leases with a given remote-id.
virtual Lease6Ptr getLease6(Lease::Type type, const isc::asiolink::IOAddress &addr) const =0
Returns existing IPv6 lease for a given IPv6 address.
Wraps value holding size of the page with leases.
Definition lease_mgr.h:46
static const OptionDefinition & D6O_LQ_RELAY_DATA_DEF()
Get definition of D6O_LQ_RELAY_DATA option.
static const OptionDefinition & D6O_CLIENT_DATA_DEF()
Get definition of D6O_CLIENT_DATA option.
static size_t unpackOptions6(const OptionBuffer &buf, const std::string &option_space, isc::dhcp::OptionCollection &options, size_t *relay_msg_offset=0, size_t *relay_msg_len=0)
Parses provided buffer as DHCPv6 options and creates Option objects.
Definition libdhcp++.cc:317
DHCPv6 Option class for handling list of IPv6 addresses.
std::vector< isc::asiolink::IOAddress > AddressContainer
a container for (IPv6) addresses
Class that represents IAPREFIX option in DHCPv6.
This class represents Status Code option (13) from RFC 8415.
Option with defined data fields represented as buffers that can be accessed using data field index.
Base class representing a DHCP option definition.
static const size_t OPTION6_HDR_LEN
length of any DHCPv6 option header
Definition option.h:87
Represents a DHCPv6 packet.
Definition pkt6.h:44
static const size_t DHCPV6_RELAY_HDR_LEN
specifies relay DHCPv6 packet header length (over UDP)
Definition pkt6.h:50
Per-packet callout handle.
void setArgument(const std::string &name, T value)
Set argument.
static BulkLeaseQueryServicePtr instance()
Returns a pointer to the sole instance of the BulkLeaseQueryService, can return null.
static void testServerId(const dhcp::Pkt6Ptr &query)
Validates the server-id of a received DHCPV6_LEASEQUERY.
static RelayInfoPtr parseRelayInfo(data::ConstElementPtr relay)
Converts an Element::map into an Pkt6::RelayInfo instance.
static void queryByRelayIdNext(const dhcp::DuidPtr &relay_id, asiolink::IOAddress &start_addr, const size_t page_size, const dhcp::SubnetIDSet &links, dhcp::Lease6Collection &leases)
Subsequent query for active leases matching a relay id (i.e.
static uint16_t getRelayOverhead(const dhcp::Pkt6::RelayInfo &relay, bool innermost)
Calculates the packed size (in octets) of a given RelayInfo.
static asiolink::IOAddress getPrefixFromAddress(const asiolink::IOAddress &address, const uint8_t prefix_length)
Creates a prefix of a given length from an address.
void addPrefixLength(uint8_t prefix_len)
Add a prefix to the list of prefix lengths.
static dhcp::Pkt6Ptr initDone(const dhcp::Pkt6Ptr &query)
Creates the final query done response.
static std::string dumpPrefixLengthList(const PrefixLengthList &prefix_lengths)
Dump the given list of prefix lengths to a string.
static dhcp::Option6StatusCodePtr queryByRemoteIdStart(const dhcp::OptionBuffer &remote_id, asiolink::IOAddress &start_addr, const size_t page_size, const asiolink::IOAddress &link_addr, dhcp::SubnetIDSet &links, dhcp::Lease6Collection &leases)
Initial query for active leases matching a remote id.
LeaseQueryImpl6(const data::ConstElementPtr config)
Constructor.
void sendResponse(const dhcp::Pkt6Ptr &response) const
Sends a response to the requester.
static dhcp::Option6StatusCodePtr queryByRelayIdStart(const dhcp::DuidPtr &relay_id, asiolink::IOAddress &start_addr, const size_t page_size, const asiolink::IOAddress &link_addr, dhcp::SubnetIDSet &links, dhcp::Lease6Collection &leases)
Initial query for active leases matching a relay id (i.e.
PrefixLengthList prefix_lens_
List of PD prefix lengths to use when searching for leases by address.
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:29
@ info
Definition db_log.h:120
boost::shared_ptr< isc::dhcp::Pkt > PktPtr
A pointer to either Pkt4 or Pkt6 packet.
Definition pkt.h:999
std::set< dhcp::SubnetID > SubnetIDSet
Ordered list aka set of subnetIDs.
Definition subnet_id.h:43
boost::shared_ptr< const Subnet6 > ConstSubnet6Ptr
A const pointer to a Subnet6 object.
Definition subnet.h:623
boost::shared_ptr< OptionCustom > OptionCustomPtr
A pointer to the OptionCustom object.
boost::shared_ptr< DUID > DuidPtr
Definition duid.h:136
boost::shared_ptr< Lease6 > Lease6Ptr
Pointer to a Lease6 structure.
Definition lease.h:528
std::vector< Lease6Ptr > Lease6Collection
A collection of IPv6 leases.
Definition lease.h:693
boost::multi_index_container< Subnet6Ptr, boost::multi_index::indexed_by< boost::multi_index::ordered_unique< boost::multi_index::tag< SubnetSubnetIdIndexTag >, boost::multi_index::const_mem_fun< Subnet, SubnetID, &Subnet::getID > >, boost::multi_index::ordered_unique< boost::multi_index::tag< SubnetPrefixIndexTag >, boost::multi_index::const_mem_fun< Subnet, std::string, &Subnet::toText > >, boost::multi_index::ordered_non_unique< boost::multi_index::tag< SubnetModificationTimeIndexTag >, boost::multi_index::const_mem_fun< data::BaseStampedElement, boost::posix_time::ptime, &data::BaseStampedElement::getModificationTime > > > > Subnet6Collection
A collection of Subnet6 objects.
Definition subnet.h:937
boost::shared_ptr< SrvConfig > SrvConfigPtr
Non-const pointer to the SrvConfig.
std::vector< PoolPtr > PoolCollection
a container for either IPv4 or IPv6 Pools
Definition pool.h:729
boost::shared_ptr< Option6AddrLst > Option6AddrLstPtr
Pointer to the Option6AddrLst object.
boost::shared_ptr< CfgSubnets6 > CfgSubnets6Ptr
Non-const pointer.
boost::shared_ptr< Option6StatusCode > Option6StatusCodePtr
Pointer to the isc::dhcp::Option6StatusCode.
boost::shared_ptr< Option6IAAddr > Option6IAAddrPtr
A pointer to the isc::dhcp::Option6IAAddr object.
boost::shared_ptr< Pkt6 > Pkt6Ptr
A pointer to Pkt6 packet.
Definition pkt6.h:31
std::vector< uint8_t > OptionBuffer
buffer types used in DHCP code.
Definition option.h:24
boost::shared_ptr< Option > OptionPtr
Definition option.h:37
boost::shared_ptr< Pool6 > Pool6Ptr
a pointer an IPv6 Pool
Definition pool.h:536
const isc::log::MessageID DHCP6_LEASE_QUERY_REPLY_SENT
std::set< uint8_t > PrefixLengthList
Defines an ordered list of prefix lengths.
boost::shared_ptr< dhcp::Pkt6::RelayInfo > RelayInfoPtr
Defines a shared pointer to a Pkt6::RelayInfo.
const isc::log::MessageID DHCP6_LEASE_QUERY_PACKET_PACK_FAILED
const isc::log::MessageID DHCP6_LEASE_QUERY_REPLY_SEND_FAILED
const isc::log::MessageID DHCP6_LEASE_QUERY_PREFIX_LENGTH_LIST
isc::log::Logger lease_query_logger("lease-query-hooks")
const isc::log::MessageID DHCP6_LEASE_QUERY_ERROR_GETTING_RELAY_INFO
const int DBGLVL_TRACE_BASIC
Trace basic operations.
void decodeFormattedHexString(const string &hex_string, vector< uint8_t > &binary)
Converts a formatted string of hexadecimal digits into a vector.
Definition str.cc:212
Defines the logger used by the top-level component of kea-lfc.
#define DHCP6_OPTION_SPACE
data::ConstElementPtr getContext() const
Returns const pointer to the user context.
static data::ElementPtr toElement(data::ConstElementPtr map)
Copy an Element map.
Structure that holds a lease for IPv6 address and/or prefix.
Definition lease.h:536
virtual std::string toText() const
Convert Lease to Printable Form.
Definition lease.cc:544
DuidPtr duid_
Client identifier.
Definition lease.h:556
static const uint32_t STATE_DEFAULT
A lease in the default state.
Definition lease.h:69
@ TYPE_PD
the lease contains IPv6 prefix (for prefix delegation)
Definition lease.h:49
@ TYPE_NA
the lease contains non-temporary IPv6 address
Definition lease.h:47
time_t cltt_
Client last transmission time.
Definition lease.h:149
structure that describes a single relay information
Definition pkt6.h:85
isc::dhcp::OptionCollection options_
options received from a specified relay, except relay-msg option
Definition pkt6.h:104