Kea: lease_query_impl6.cc Source File

| Kea 3.2.0-git

lease_query_impl6.cc
Go to the documentation of this file.
1// Copyright (C) 2020-2026 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
8
9#include <cc/command_interpreter.h>
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>
15#include <dhcp/option6_addrlst.h>
16#include <dhcp/option6_iaaddr.h>
17#include <dhcp/option6_iaprefix.h>
18#include <dhcpsrv/cfgmgr.h>
19#include <dhcpsrv/lease_mgr_factory.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
53LeaseQueryImpl6::LeaseQueryImpl6(const ConstElementPtr config)
54 : LeaseQueryImpl(AF_INET6, config), prefix_lens_(), build_prefix_lens_(true) {
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));
133 isc_throw(BadValue,
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
210 IOAddress
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
241 Option6StatusCodePtr
242LeaseQueryImpl6::queryByIpAddress(const IOAddress& iaaddr, Lease6Collection& leases,
243 const PrefixLengthList& prefix_lengths) {
244 // Database possible call: check if the hook was terminated.
245 CHECK_TERMINATED;
246 // Look for a lease for the given address.
247 Lease6Ptr lease = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA, iaaddr);
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);
252 lease = LeaseMgrFactory::instance().getLease6(Lease::TYPE_PD, prefix);
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
288 Option6StatusCodePtr
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.
303 CHECK_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
332 Option6StatusCodePtr
333LeaseQueryImpl6::queryByRelayIdStart(const DuidPtr& relay_id,
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.
354 CHECK_TERMINATED;
355
356 found_leases =
357 LeaseMgrFactory::instance().getLeases6ByRelayId(*relay_id,
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
384LeaseQueryImpl6::queryByRelayIdNext(const DuidPtr& relay_id,
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.
390 CHECK_TERMINATED;
391
392 Lease6Collection found_leases =
393 LeaseMgrFactory::instance().getLeases6ByRelayId(*relay_id,
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
421 Option6StatusCodePtr
422LeaseQueryImpl6::queryByRemoteIdStart(const OptionBuffer& remote_id,
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.
443 CHECK_TERMINATED;
444
445 found_leases =
446 LeaseMgrFactory::instance().getLeases6ByRemoteId(remote_id,
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
473LeaseQueryImpl6::queryByRemoteIdNext(const OptionBuffer& remote_id,
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.
479 CHECK_TERMINATED;
480
481 Lease6Collection found_leases =
482 LeaseMgrFactory::instance().getLeases6ByRemoteId(remote_id,
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
510 Option6StatusCodePtr
511LeaseQueryImpl6::queryByLinkStart(IOAddress& start_addr,
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.
540 CHECK_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
569LeaseQueryImpl6::queryByLinkNext(IOAddress& start_addr,
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.
586 CHECK_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
621 Pkt6Ptr
622LeaseQueryImpl6::buildReply(const Option6StatusCodePtr& status,
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
662 case STATUS_UnknownQueryType:
663 case STATUS_MalformedQuery:
664 case STATUS_NotConfigured:
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
681 Pkt6Ptr
682LeaseQueryImpl6::initReply(const Pkt6Ptr& query) {
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
701 DuidPtr server_id = CfgMgr::instance().getCurrentCfg()
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
712 Pkt6Ptr
713LeaseQueryImpl6::initData(const Pkt6Ptr& query) {
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
722 Pkt6Ptr
723LeaseQueryImpl6::initDone(const Pkt6Ptr& query) {
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
732 OptionPtr
733LeaseQueryImpl6::makeClientOption(Lease6Collection& leases) {
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();
752 Option6AddrLst::AddressContainer addrs;
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
762 Option6AddrLstPtr opt(new Option6AddrLst(D6O_LQ_CLIENT_LINK, addrs));
763 return (opt);
764 }
765
766 const OptionDefinition& def = LibDHCP::D6O_CLIENT_DATA_DEF();
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
826 OptionPtr
827 LeaseQueryImpl6::makeClientOption(Lease6Ptr lease) {
828 const OptionDefinition& def = LibDHCP::D6O_CLIENT_DATA_DEF();
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
881 OptionPtr
882LeaseQueryImpl6::makeRelayOption(const Lease6& lease) {
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) {
918 LOG_WARN(lease_query_logger, DHCP6_LEASE_QUERY_ERROR_GETTING_RELAY_INFO)
919 .arg(lease.toText())
920 .arg(ex.what());
921 return (OptionPtr());
922 }
923
924 // Create the relay data option.
925 const OptionDefinition& def = LibDHCP::D6O_LQ_RELAY_DATA_DEF();
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.
943 isc::util::OutputBuffer buffer_out(Pkt6::DHCPV6_RELAY_HDR_LEN
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
981LeaseQueryImpl6::getRelayOverhead(const Pkt6::RelayInfo& relay, bool innermost) {
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
996LeaseQueryImpl6::parseRelayInfoList(ConstElementPtr relay_info,
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()) {
1003 RelayInfoPtr info = parseRelayInfo(relay);
1004 relay_infos.push_back(info);
1005 }
1006}
1007
1008 RelayInfoPtr
1009LeaseQueryImpl6::parseRelayInfo(ConstElementPtr relay_elem) {
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
1073LeaseQueryImpl6::testServerId(const Pkt6Ptr& query) {
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
1104LeaseQueryImpl6::sendResponse(const dhcp::Pkt6Ptr& response) const {
1105 // Pack the response.
1106 try {
1107 response->pack();
1108 } catch (const std::exception& ex) {
1109 LOG_ERROR(lease_query_logger, DHCP6_LEASE_QUERY_PACKET_PACK_FAILED)
1110 .arg(leaseQueryLabel(response))
1111 .arg(ex.what());
1112 return;
1113 }
1114
1115 try {
1116 send(response);
1117 LOG_DEBUG(lease_query_logger, DBGLVL_TRACE_BASIC, DHCP6_LEASE_QUERY_REPLY_SENT)
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) {
1126 LOG_ERROR(lease_query_logger, DHCP6_LEASE_QUERY_REPLY_SEND_FAILED)
1127 .arg(leaseQueryLabel(response))
1128 .arg(response->getIface())
1129 .arg(response->getRemoteAddr())
1130 .arg(response->getRemotePort())
1131 .arg(ex.what());
1132 }
1133}
1134
1135 void LeaseQueryImpl6::send(const dhcp::Pkt6Ptr& response) const {
1136 IfaceMgr::instance().send(response);
1137}
1138
1139 Option6StatusCodePtr
1140LeaseQueryImpl6::makeStatusOption(const DHCPv6StatusCode& status_code,
1141 const std::string message) {
1142 Option6StatusCodePtr opt(new Option6StatusCode(status_code, message));
1143 return (opt);
1144}
1145
1146std::string
1147LeaseQueryImpl6::leaseQueryLabel(const Pkt6Ptr& packet) {
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
1166LeaseQueryImpl6::upgradeHandler(CalloutHandle& handle) {
1167 ConstElementPtr response;
1168 size_t upgraded = 0;
1169 LeasePageSize page_size(LeaseQueryImpl::PageSize);
1170 try {
1171 util::MultiThreadingCriticalSection cc;
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
1194LeaseQueryImpl6::populatePrefixLengthList(SrvConfigPtr cfg) {
1195 if (build_prefix_lens_) {
1196 // Empty the current entries.
1197 clearPrefixLengthList();
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
1210 LOG_DEBUG(lease_query_logger, DBGLVL_TRACE_BASIC, DHCP6_LEASE_QUERY_PREFIX_LENGTH_LIST)
1211 .arg(dumpPrefixLengthList(prefix_lens_));
1212}
1213
1214std::string
1215LeaseQueryImpl6::dumpPrefixLengthList(const PrefixLengthList& prefix_lengths) {
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}
blq_service.h
cfgmgr.h
Element::map
@ map
Definition data.h:160
Element::integer
@ integer
Definition data.h:153
Element::list
@ list
Definition data.h:159
isc::BadValue
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
Definition exceptions/exceptions.h:132
isc::Unexpected
A generic exception that is thrown when an unexpected error condition occurs.
Definition exceptions/exceptions.h:153
isc::asiolink::IOAddress
The IOAddress class represents an IP addresses (version agnostic).
Definition io_address.h:53
isc::asiolink::IOAddress::toText
std::string toText() const
Convert the address to a string.
Definition io_address.cc:60
isc::asiolink::IOAddress::toBytes
std::vector< uint8_t > toBytes() const
Return address as set of bytes.
Definition io_address.cc:81
isc::asiolink::IOAddress::isV6Zero
bool isV6Zero() const
Convenience function to check if it is an IPv4 zero address.
Definition io_address.h:151
isc::asiolink::IOAddress::getFamily
short getFamily() const
Returns the address family.
Definition io_address.cc:96
isc::asiolink::IOAddress::IPV6_ZERO_ADDRESS
static const IOAddress & IPV6_ZERO_ADDRESS()
Returns an IPv6 zero address.
Definition io_address.h:297
isc::asiolink::IOAddress::fromBytes
static IOAddress fromBytes(short family, const uint8_t *data)
Creates an address from over wire data.
Definition io_address.cc:65
isc::dhcp::CfgMgr::instance
static CfgMgr & instance()
returns a single instance of Configuration Manager
Definition cfgmgr.cc:29
isc::dhcp::CfgMgr::getStagingCfg
SrvConfigPtr getStagingCfg()
Returns a pointer to the staging configuration.
Definition cfgmgr.cc:121
isc::dhcp::CfgMgr::getCurrentCfg
SrvConfigPtr getCurrentCfg()
Returns a pointer to the current configuration.
Definition cfgmgr.cc:116
isc::dhcp::DUID
Holds DUID (DHCPv6 Unique Identifier).
Definition duid.h:142
isc::dhcp::IfaceMgr::instance
static IfaceMgr & instance()
IfaceMgr is a singleton class.
Definition iface_mgr.cc:52
isc::dhcp::IfaceMgr::send
bool send(const Pkt6Ptr &pkt)
Sends an IPv6 packet.
Definition iface_mgr.cc:1208
isc::dhcp::LeaseMgrFactory::instance
static TrackingLeaseMgr & instance()
Return current lease manager.
Definition lease_mgr_factory.cc:148
isc::dhcp::LeaseMgr::getLeases6
virtual Lease6Collection getLeases6(Lease::Type type, const DUID &duid, uint32_t iaid) const =0
Returns existing IPv6 leases for a given DUID+IA combination.
isc::dhcp::LeaseMgr::getLeases6ByRelayId
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.
isc::dhcp::LeaseMgr::getLeases6ByRemoteId
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.
isc::dhcp::LeaseMgr::getLease6
virtual Lease6Ptr getLease6(Lease::Type type, const isc::asiolink::IOAddress &addr) const =0
Returns existing IPv6 lease for a given IPv6 address.
isc::dhcp::LeasePageSize
Wraps value holding size of the page with leases.
Definition lease_mgr.h:46
isc::dhcp::LibDHCP::D6O_LQ_RELAY_DATA_DEF
static const OptionDefinition & D6O_LQ_RELAY_DATA_DEF()
Get definition of D6O_LQ_RELAY_DATA option.
Definition libdhcp++.cc:1606
isc::dhcp::LibDHCP::unpackOptions6
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
isc::dhcp::LibDHCP::D6O_CLIENT_DATA_DEF
static const OptionDefinition & D6O_CLIENT_DATA_DEF()
Get definition of D6O_CLIENT_DATA option.
Definition libdhcp++.cc:1588
isc::dhcp::Option6AddrLst
DHCPv6 Option class for handling list of IPv6 addresses.
Definition option6_addrlst.h:22
isc::dhcp::Option6AddrLst::AddressContainer
std::vector< isc::asiolink::IOAddress > AddressContainer
a container for (IPv6) addresses
Definition option6_addrlst.h:26
isc::dhcp::Option6IAAddr
Definition option6_iaaddr.h:22
isc::dhcp::Option6IAPrefix
Class that represents IAPREFIX option in DHCPv6.
Definition option6_iaprefix.h:51
isc::dhcp::Option6StatusCode
This class represents Status Code option (13) from RFC 9915.
Definition option6_status_code.h:24
isc::dhcp::OptionCustom
Option with defined data fields represented as buffers that can be accessed using data field index.
Definition option_custom.h:31
isc::dhcp::OptionDefinition
Base class representing a DHCP option definition.
Definition option_definition.h:138
isc::dhcp::Option
Definition option.h:81
isc::dhcp::Option::V6
@ V6
Definition option.h:90
isc::dhcp::Option::OPTION6_HDR_LEN
static const size_t OPTION6_HDR_LEN
length of any DHCPv6 option header
Definition option.h:87
isc::dhcp::Pkt6
Represents a DHCPv6 packet.
Definition pkt6.h:44
isc::dhcp::Pkt6::DHCPV6_RELAY_HDR_LEN
static const size_t DHCPV6_RELAY_HDR_LEN
specifies relay DHCPv6 packet header length (over UDP)
Definition pkt6.h:50
isc::hooks::CalloutHandle
Per-packet callout handle.
Definition callout_handle.h:78
isc::hooks::CalloutHandle::setArgument
void setArgument(const std::string &name, T value)
Set argument.
Definition callout_handle.h:147
isc::lease_query::BulkLeaseQueryService::instance
static BulkLeaseQueryServicePtr instance()
Returns a pointer to the sole instance of the BulkLeaseQueryService, can return null.
Definition blq_service.cc:225
isc::lease_query::LeaseQueryImpl6::testServerId
static void testServerId(const dhcp::Pkt6Ptr &query)
Validates the server-id of a received DHCPV6_LEASEQUERY.
Definition lease_query_impl6.cc:1073
isc::lease_query::LeaseQueryImpl6::parseRelayInfo
static RelayInfoPtr parseRelayInfo(data::ConstElementPtr relay)
Converts an Element::map into an Pkt6::RelayInfo instance.
Definition lease_query_impl6.cc:1009
isc::lease_query::LeaseQueryImpl6::queryByRelayIdNext
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.
Definition lease_query_impl6.cc:384
isc::lease_query::LeaseQueryImpl6::getRelayOverhead
static uint16_t getRelayOverhead(const dhcp::Pkt6::RelayInfo &relay, bool innermost)
Calculates the packed size (in octets) of a given RelayInfo.
Definition lease_query_impl6.cc:981
isc::lease_query::LeaseQueryImpl6::getPrefixFromAddress
static asiolink::IOAddress getPrefixFromAddress(const asiolink::IOAddress &address, const uint8_t prefix_length)
Creates a prefix of a given length from an address.
Definition lease_query_impl6.cc:211
isc::lease_query::LeaseQueryImpl6::addPrefixLength
void addPrefixLength(uint8_t prefix_len)
Add a prefix to the list of prefix lengths.
Definition lease_query_impl6.h:454
isc::lease_query::LeaseQueryImpl6::initDone
static dhcp::Pkt6Ptr initDone(const dhcp::Pkt6Ptr &query)
Creates the final query done response.
Definition lease_query_impl6.cc:723
isc::lease_query::LeaseQueryImpl6::dumpPrefixLengthList
static std::string dumpPrefixLengthList(const PrefixLengthList &prefix_lengths)
Dump the given list of prefix lengths to a string.
Definition lease_query_impl6.cc:1215
isc::lease_query::LeaseQueryImpl6::queryByRemoteIdStart
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.
Definition lease_query_impl6.cc:422
isc::lease_query::LeaseQueryImpl6::LeaseQueryImpl6
LeaseQueryImpl6(const data::ConstElementPtr config)
Constructor.
Definition lease_query_impl6.cc:53
isc::lease_query::LeaseQueryImpl6::sendResponse
void sendResponse(const dhcp::Pkt6Ptr &response) const
Sends a response to the requester.
Definition lease_query_impl6.cc:1104
isc::lease_query::LeaseQueryImpl6::queryByRelayIdStart
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.
Definition lease_query_impl6.cc:333
isc::lease_query::LeaseQueryImpl6::prefix_lens_
PrefixLengthList prefix_lens_
List of PD prefix lengths to use when searching for leases by address.
Definition lease_query_impl6.h:493
isc::lease_query::LeaseQueryImpl6::makeStatusOption
static dhcp::Option6StatusCodePtr makeStatusOption(const DHCPv6StatusCode &status_code, const std::string message="")
Constructs a D6O_STATUS_CODE option.
Definition lease_query_impl6.cc:1140
isc::lease_query::LeaseQueryImpl6::queryByLinkStart
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.
Definition lease_query_impl6.cc:511
isc::lease_query::LeaseQueryImpl6::makeClientOption
static dhcp::OptionPtr makeClientOption(dhcp::Lease6Collection &leases)
Constructs a client option based on a collection of leases.
Definition lease_query_impl6.cc:733
isc::lease_query::LeaseQueryImpl6::clearPrefixLengthList
void clearPrefixLengthList()
Empty the prefix length list.
Definition lease_query_impl6.h:461
isc::lease_query::LeaseQueryImpl6::makeRelayOption
static dhcp::OptionPtr makeRelayOption(const dhcp::Lease6 &lease)
Constructs a D6O_LQ_RELAY_DATA option from a lease user-context.
Definition lease_query_impl6.cc:882
isc::lease_query::LeaseQueryImpl6::leaseQueryLabel
static std::string leaseQueryLabel(const dhcp::Pkt6Ptr &packet)
Convenience method for generating per packet logging info.
Definition lease_query_impl6.cc:1147
isc::lease_query::LeaseQueryImpl6::queryByIpAddress
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.
Definition lease_query_impl6.cc:242
isc::lease_query::LeaseQueryImpl6::send
virtual void send(const dhcp::Pkt6Ptr &response) const
Wrapper around the call to IfaceMgr::send().
Definition lease_query_impl6.cc:1135
isc::lease_query::LeaseQueryImpl6::buildReply
static dhcp::Pkt6Ptr buildReply(const dhcp::Option6StatusCodePtr &status, const dhcp::Pkt6Ptr &query, dhcp::Lease6Collection &leases)
Creates a lease query reply packet.
Definition lease_query_impl6.cc:622
isc::lease_query::LeaseQueryImpl6::queryByLinkNext
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.
Definition lease_query_impl6.cc:569
isc::lease_query::LeaseQueryImpl6::processQuery
virtual void processQuery(isc::dhcp::PktPtr base_query, bool &invalid) const
Processes a single DHCPv6 client Lease Query.
Definition lease_query_impl6.cc:93
isc::lease_query::LeaseQueryImpl6::initReply
static dhcp::Pkt6Ptr initReply(const dhcp::Pkt6Ptr &query)
Creates the initial query reply.
Definition lease_query_impl6.cc:682
isc::lease_query::LeaseQueryImpl6::populatePrefixLengthList
void populatePrefixLengthList(dhcp::SrvConfigPtr cfg)
Populates the prefix length list from the given configuration.
Definition lease_query_impl6.cc:1194
isc::lease_query::LeaseQueryImpl6::queryByClientId
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.
Definition lease_query_impl6.cc:289
isc::lease_query::LeaseQueryImpl6::parseRelayInfoList
static void parseRelayInfoList(data::ConstElementPtr relays, std::vector< RelayInfoPtr > &relay_infos)
Converts an Element::list into a list of Pkt6::RelayInfo instances.
Definition lease_query_impl6.cc:996
isc::lease_query::LeaseQueryImpl6::queryByRemoteIdNext
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.
Definition lease_query_impl6.cc:473
isc::lease_query::LeaseQueryImpl6::build_prefix_lens_
bool build_prefix_lens_
True if the prefix length should be gleaned from configured pools.
Definition lease_query_impl6.h:498
isc::lease_query::LeaseQueryImpl6::upgradeHandler
static int upgradeHandler(hooks::CalloutHandle &handle)
Upgrade extended information.
Definition lease_query_impl6.cc:1166
isc::lease_query::LeaseQueryImpl6::initData
static dhcp::Pkt6Ptr initData(const dhcp::Pkt6Ptr &query)
Creates the query data response.
Definition lease_query_impl6.cc:713
isc::lease_query::LeaseQueryImpl::LeaseQueryImpl
LeaseQueryImpl(uint16_t family, const isc::data::ConstElementPtr config)
Constructor.
Definition lease_query_impl.cc:81
isc::lease_query::LeaseQueryImpl::isRequester
bool isRequester(const isc::asiolink::IOAddress &address) const
Checks if the given address belongs to a valid requester.
Definition lease_query_impl.cc:150
isc::lease_query::LeaseQueryImpl::PageSize
static size_t PageSize
Page size to commands.
Definition lease_query_impl.h:228
isc::stats::StatsMgr::instance
static StatsMgr & instance()
Statistics Manager accessor method.
Definition lib/stats/stats_mgr.cc:30
isc::util::MultiThreadingCriticalSection
RAII class creating a critical section.
Definition multi_threading_mgr.h:374
isc::util::OutputBuffer
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
Definition buffer.h:346
isc::util::OutputBuffer::writeUint8
void writeUint8(uint8_t data)
Write an unsigned 8-bit integer into the buffer.
Definition buffer.h:476
isc::util::OutputBuffer::writeUint16
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
isc::util::OutputBuffer::writeData
void writeData(const void *data, size_t len)
Copy an arbitrary length of data into the buffer.
Definition buffer.h:559
isc::util::OutputBuffer::getVector
const std::vector< uint8_t > & getVector() const
Return the buffer.
Definition buffer.h:436
command_interpreter.h
This file contains several functions and constants that are used for handling commands and responses ...
dhcp6.h
DHCPv6StatusCode
DHCPv6StatusCode
Definition dhcp6.h:175
STATUS_NotAllowed
@ STATUS_NotAllowed
Definition dhcp6.h:186
STATUS_MalformedQuery
@ STATUS_MalformedQuery
Definition dhcp6.h:184
STATUS_Success
@ STATUS_Success
Definition dhcp6.h:176
STATUS_UnknownQueryType
@ STATUS_UnknownQueryType
Definition dhcp6.h:183
STATUS_NotConfigured
@ STATUS_NotConfigured
Definition dhcp6.h:185
D6O_SERVERID
@ D6O_SERVERID
Definition dhcp6.h:22
D6O_CLIENTID
@ D6O_CLIENTID
Definition dhcp6.h:21
D6O_RELAY_MSG
@ D6O_RELAY_MSG
Definition dhcp6.h:29
D6O_CLT_TIME
@ D6O_CLT_TIME
Definition dhcp6.h:66
D6O_LQ_QUERY
@ D6O_LQ_QUERY
Definition dhcp6.h:64
D6O_IAADDR
@ D6O_IAADDR
Definition dhcp6.h:25
D6O_LQ_CLIENT_LINK
@ D6O_LQ_CLIENT_LINK
Definition dhcp6.h:68
D6O_IAPREFIX
@ D6O_IAPREFIX
Definition dhcp6.h:46
LQ6QT_BY_ADDRESS
#define LQ6QT_BY_ADDRESS
Definition dhcp6.h:338
DHCPV6_LEASEQUERY_DATA
@ DHCPV6_LEASEQUERY_DATA
Definition dhcp6.h:226
DHCPV6_LEASEQUERY_DONE
@ DHCPV6_LEASEQUERY_DONE
Definition dhcp6.h:225
DHCPV6_LEASEQUERY_REPLY
@ DHCPV6_LEASEQUERY_REPLY
Definition dhcp6.h:223
DHCPV6_RELAY_FORW
@ DHCPV6_RELAY_FORW
Definition dhcp6.h:219
LQ6QT_BY_CLIENTID
#define LQ6QT_BY_CLIENTID
Definition dhcp6.h:339
encode.h
isc_throw
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Definition exceptions/exceptions.h:210
isc::dhcp::OptionUint32
OptionInt< uint32_t > OptionUint32
Definition option_int.h:34
isc::stats::StatsMgr::addValue
void addValue(const std::string &name, const int64_t value)
Records incremental integer observation.
Definition lib/stats/stats_mgr.cc:70
io.h
lease_mgr_factory.h
lease_query_impl6.h
CHECK_TERMINATED
#define CHECK_TERMINATED
Definition lease_query_impl.h:32
lease_query_log.h
stats_mgr.h
libdhcp++.h
LOG_ERROR
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
Definition macros.h:32
LOG_WARN
#define LOG_WARN(LOGGER, MESSAGE)
Macro to conveniently test warn output and log it.
Definition macros.h:26
LOG_DEBUG
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition macros.h:14
isc::asiolink
Definition addr_utilities.cc:170
isc::config
Definition command_interpreter.cc:23
isc::config::CONTROL_RESULT_ERROR
const int CONTROL_RESULT_ERROR
Status code indicating a general failure.
Definition command_interpreter.h:45
isc::config::createAnswer
ConstElementPtr createAnswer()
Creates a standard config/command level success answer message (i.e.
Definition command_interpreter.cc:54
isc::config::CONTROL_RESULT_SUCCESS
const int CONTROL_RESULT_SUCCESS
Status code indicating a successful operation.
Definition command_interpreter.h:42
isc::data
Definition base_stamped_element.cc:12
isc::data::ConstElementPtr
boost::shared_ptr< const Element > ConstElementPtr
Definition data.h:30
isc::db::info
@ info
Definition db_log.h:126
isc::dhcp
Definition dhcp4/client_handler.cc:20
isc::dhcp::PktPtr
boost::shared_ptr< isc::dhcp::Pkt > PktPtr
A pointer to either Pkt4 or Pkt6 packet.
Definition pkt.h:999
isc::dhcp::SubnetIDSet
std::set< dhcp::SubnetID > SubnetIDSet
Ordered list aka set of subnetIDs.
Definition subnet_id.h:43
isc::dhcp::ConstSubnet6Ptr
boost::shared_ptr< const Subnet6 > ConstSubnet6Ptr
A const pointer to a Subnet6 object.
Definition subnet.h:620
isc::dhcp::OptionCustomPtr
boost::shared_ptr< OptionCustom > OptionCustomPtr
A pointer to the OptionCustom object.
Definition option_custom.h:468
isc::dhcp::DuidPtr
boost::shared_ptr< DUID > DuidPtr
Definition duid.h:136
isc::dhcp::Lease6Ptr
boost::shared_ptr< Lease6 > Lease6Ptr
Pointer to a Lease6 structure.
Definition lease.h:528
isc::dhcp::Lease6Collection
std::vector< Lease6Ptr > Lease6Collection
A collection of IPv6 leases.
Definition lease.h:693
isc::dhcp::Subnet6Collection
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
isc::dhcp::SrvConfigPtr
boost::shared_ptr< SrvConfig > SrvConfigPtr
Non-const pointer to the SrvConfig.
Definition srv_config.h:1148
isc::dhcp::PoolCollection
std::vector< PoolPtr > PoolCollection
a container for either IPv4 or IPv6 Pools
Definition pool.h:729
isc::dhcp::Option6AddrLstPtr
boost::shared_ptr< Option6AddrLst > Option6AddrLstPtr
Pointer to the Option6AddrLst object.
Definition option6_addrlst.h:93
isc::dhcp::CfgSubnets6Ptr
boost::shared_ptr< CfgSubnets6 > CfgSubnets6Ptr
Non-const pointer.
Definition cfg_subnets6.h:348
isc::dhcp::Option6StatusCodePtr
boost::shared_ptr< Option6StatusCode > Option6StatusCodePtr
Pointer to the isc::dhcp::Option6StatusCode.
Definition option6_status_code.h:21
isc::dhcp::Option6IAAddrPtr
boost::shared_ptr< Option6IAAddr > Option6IAAddrPtr
A pointer to the isc::dhcp::Option6IAAddr object.
Definition option6_iaaddr.h:20
isc::dhcp::Pkt6Ptr
boost::shared_ptr< Pkt6 > Pkt6Ptr
A pointer to Pkt6 packet.
Definition pkt6.h:31
isc::dhcp::OptionBuffer
std::vector< uint8_t > OptionBuffer
buffer types used in DHCP code.
Definition option.h:24
isc::dhcp::OptionPtr
boost::shared_ptr< Option > OptionPtr
Definition option.h:37
isc::dhcp::Pool6Ptr
boost::shared_ptr< Pool6 > Pool6Ptr
a pointer an IPv6 Pool
Definition pool.h:536
isc::hooks
Definition callout_handle.cc:21
isc::lease_query
Definition blq_msg.h:15
isc::lease_query::DHCP6_LEASE_QUERY_REPLY_SENT
const isc::log::MessageID DHCP6_LEASE_QUERY_REPLY_SENT
Definition lease_query_messages.h:43
isc::lease_query::PrefixLengthList
std::set< uint8_t > PrefixLengthList
Defines an ordered list of prefix lengths.
Definition lease_query_impl6.h:30
isc::lease_query::RelayInfoPtr
boost::shared_ptr< dhcp::Pkt6::RelayInfo > RelayInfoPtr
Defines a shared pointer to a Pkt6::RelayInfo.
Definition lease_query_impl6.h:26
isc::lease_query::DHCP6_LEASE_QUERY_PACKET_PACK_FAILED
const isc::log::MessageID DHCP6_LEASE_QUERY_PACKET_PACK_FAILED
Definition lease_query_messages.h:37
isc::lease_query::DHCP6_LEASE_QUERY_REPLY_SEND_FAILED
const isc::log::MessageID DHCP6_LEASE_QUERY_REPLY_SEND_FAILED
Definition lease_query_messages.h:42
isc::lease_query::DHCP6_LEASE_QUERY_PREFIX_LENGTH_LIST
const isc::log::MessageID DHCP6_LEASE_QUERY_PREFIX_LENGTH_LIST
Definition lease_query_messages.h:39
isc::lease_query::lease_query_logger
isc::log::Logger lease_query_logger("lease-query-hooks")
Definition lease_query_log.h:17
isc::lease_query::DHCP6_LEASE_QUERY_ERROR_GETTING_RELAY_INFO
const isc::log::MessageID DHCP6_LEASE_QUERY_ERROR_GETTING_RELAY_INFO
Definition lease_query_messages.h:35
isc::log
Definition buffer_appender_impl.cc:17
isc::log::DBGLVL_TRACE_BASIC
const int DBGLVL_TRACE_BASIC
Trace basic operations.
Definition log_dbglevels.h:69
isc::stats
Definition context.cc:18
isc::util::str::decodeFormattedHexString
void decodeFormattedHexString(const string &hex_string, vector< uint8_t > &binary)
Converts a formatted string of hexadecimal digits into a vector.
Definition str.cc:212
isc
Defines the logger used by the top-level component of kea-lfc.
Definition check_exists_add.cc:18
option6_addrlst.h
option6_iaaddr.h
option6_iaprefix.h
option_custom.h
option_int.h
pkt6.h
DHCP6_OPTION_SPACE
#define DHCP6_OPTION_SPACE
Definition std_option_defs.h:17
str.h
isc::data::UserContext::getContext
data::ConstElementPtr getContext() const
Returns const pointer to the user context.
Definition user_context.h:24
isc::data::UserContext::toElement
static data::ElementPtr toElement(data::ConstElementPtr map)
Copy an Element map.
Definition user_context.cc:24
isc::dhcp::Lease6
Structure that holds a lease for IPv6 address and/or prefix.
Definition lease.h:536
isc::dhcp::Lease6::toText
virtual std::string toText() const
Convert Lease to Printable Form.
Definition lease.cc:553
isc::dhcp::Lease6::duid_
DuidPtr duid_
Client identifier.
Definition lease.h:556
isc::dhcp::Lease::STATE_DEFAULT
static constexpr uint32_t STATE_DEFAULT
A lease in the default state.
Definition lease.h:69
isc::dhcp::Lease::TYPE_PD
@ TYPE_PD
the lease contains IPv6 prefix (for prefix delegation)
Definition lease.h:49
isc::dhcp::Lease::TYPE_NA
@ TYPE_NA
the lease contains non-temporary IPv6 address
Definition lease.h:47
isc::dhcp::Lease::cltt_
time_t cltt_
Client last transmission time.
Definition lease.h:149
isc::dhcp::Pkt6::RelayInfo
structure that describes a single relay information
Definition pkt6.h:85
isc::dhcp::Pkt6::RelayInfo::options_
isc::dhcp::OptionCollection options_
options received from a specified relay, except relay-msg option
Definition pkt6.h:104