Kea: lease_query_impl6.cc Source File

| Kea 3.0.0

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