Kea 3.1.1
lease_query_impl4.cc
Go to the documentation of this file.
1// Copyright (C) 2020-2025 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
8
10#include <dhcpsrv/cfgmgr.h>
11#include <dhcp/iface_mgr.h>
12#include <dhcp/option_int.h>
13#include <dhcp/option_custom.h>
16#include <lease_query_log.h>
17#include <lease_query_impl4.h>
18#include <stats/stats_mgr.h>
19#include <util/str.h>
20
21#include <boost/pointer_cast.hpp>
22
23#include <sstream>
24#include <vector>
25
26using namespace isc;
27using namespace isc::asiolink;
28using namespace isc::config;
29using namespace isc::data;
30using namespace isc::dhcp;
31using namespace isc::hooks;
32using namespace isc::lease_query;
33using namespace isc::log;
34using namespace isc::stats;
35
36namespace {
37
39bool cltt_descending(const Lease4Ptr& first, const Lease4Ptr& second) {
40 return (first->cltt_ > second->cltt_);
41}
42
43} // end of anonymous namespace
44
48
49void
51 Pkt4Ptr query = boost::dynamic_pointer_cast<Pkt4>(base_query);
52 if (!query) {
53 // Shouldn't happen.
54 isc_throw(BadValue, "LeaseQueryImpl4 query is not DHCPv4 packet");
55 }
56
58 IOAddress requester_ip = query->getGiaddr();
59 if (requester_ip.isV4Zero()) {
60 isc_throw(BadValue, "giaddr cannot be 0.0.0.0");
61 }
62
63 if (!isRequester(requester_ip)) {
64 isc_throw(BadValue, "rejecting query from unauthorized requester: "
65 << requester_ip.toText());
66 }
67
68 OptionPtr client_server_id;
69 if (!acceptServerId(query, client_server_id)) {
70 isc_throw(BadValue, "rejecting query from: "
71 << requester_ip.toText() << ", unknown server-id: "
72 << (client_server_id ? client_server_id->toText() : "malformed"));
73 }
74
75 // Let's figure out which query type we have base on which attributes
76 // the client sent. The attributes are mutually exclusive so we'll
77 // make a bit mask of which ones the query contains and go from there.
78 IOAddress ciaddr = query->getCiaddr();
79 uint8_t query_mask = (!ciaddr.isV4Zero() ? 1 : 0);
80
81 HWAddrPtr hwaddr = query->getHWAddr();
82 query_mask |= ((hwaddr->htype_ || hwaddr->hwaddr_.size()) ? 2 : 0);
83
84 ClientIdPtr client_id;
85 OptionPtr opt = query->getOption(DHO_DHCP_CLIENT_IDENTIFIER);
86 if (opt) {
87 client_id.reset(new ClientId(opt->getData()));
88 query_mask += 4;
89 }
90
91 Lease4Collection leases;
92 DHCPMessageType response_type;
93
94 // Do the query based on which query attribute we have,
95 // or error out.
96 switch (query_mask) {
97 case 1:
98 // Query by ip address.
99 response_type = queryByIpAddress(ciaddr, leases);
100 break;
101 case 2:
102 // Query by HW address.
103 response_type = queryByHWAddr(hwaddr, leases);
104 break;
105 case 4:
106 // Query by client id.
107 response_type = queryByClientId(client_id, leases);
108 break;
109 default:
110 // We have some combination of the three which is invalid.
111 isc_throw(BadValue, "malformed lease query: "
112 << "ciaddr: [" << ciaddr
113 << "] HWAddr: [" << hwaddr->toText()
114 << "] Client id: [" << (client_id ? client_id->toText() : "")
115 << "]");
116 }
117
118 Pkt4Ptr response = buildResponse(response_type, query, leases);
120 if (response) {
121 sendResponse(response);
122 }
123}
124
127 Lease4Collection& leases) {
129 if (lease) {
130 if (lease->state_ == Lease::STATE_DEFAULT && !lease->expired()) {
131 // Found an active lease.
132 leases.push_back(lease);
133 return (DHCPLEASEACTIVE);
134 }
135
136 // We have a lease but it's not active.
137 return (DHCPLEASEUNASSIGNED);
138 }
139
140 // We didn't find a lease, so we need to determine if it is a lease
141 // we should know about. We iterate over all subnets, in case the
142 // address is inRange() of more than one subnet.
143 const Subnet4Collection* subnets;
144 subnets = CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->getAll();
145 for (auto const& subnet : *subnets) {
146
147 if (subnet->inPool(Lease::TYPE_V4, ciaddr)) {
148 // Belongs to a pool in this subnet, but not leased.
149 return (DHCPLEASEUNASSIGNED);
150 }
151 }
152
153 // Not an address we know about.
154 return (DHCPLEASEUNKNOWN);
155}
156
159 Lease4Collection& leases) {
160 leases = winnowLeases(LeaseMgrFactory::instance().getLease4(*client_id));
161 return (!leases.empty() ? DHCPLEASEACTIVE : DHCPLEASEUNKNOWN);
162}
163
166 Lease4Collection& leases) {
167 leases = winnowLeases(LeaseMgrFactory::instance().getLease4(*hwaddr));
168 return (!leases.empty() ? DHCPLEASEACTIVE : DHCPLEASEUNKNOWN);
169}
170
173 // We want only the active leases and we want them ordered
174 // newest to oldest by CLTT.
175 Lease4Collection active_leases;
176 if (!found_leases.empty()) {
177 for (auto const& lease : found_leases) {
178 if (lease->state_ == Lease::STATE_DEFAULT && !lease->expired()) {
179 active_leases.push_back(lease);
180 }
181 }
182
183 std::sort(active_leases.begin(), active_leases.end(), cltt_descending);
184 }
185
186 return (active_leases);
187}
188
191 const Pkt4Ptr& query,
192 const Lease4Collection& leases) {
193 // Create the basic response packet.
194 Pkt4Ptr response = initResponse(response_type, query);
195
196 switch(response_type) {
197 case DHCPLEASEUNKNOWN:
198 case DHCPLEASEUNASSIGNED: {
199 // RFC 4388 is ambiguous on this issue, so for
200 // negative queries we will always return the
201 // query parameter. Only one which will have
202 // a non-empty value. This alleviates the requester
203 // from having to try to match queries to
204 // responses.
205 response->setCiaddr(query->getCiaddr());
206 response->setHWAddr(query->getHWAddr());
207 OptionPtr opt = query->getOption(DHO_DHCP_CLIENT_IDENTIFIER);
208 if (opt) {
209 response->addOption(opt);
210 }
211
212 // Add the server-id.
213 CfgOptionList co_list;
214 buildCfgOptionList(co_list, query);
215 appendServerId(response, co_list);
216 break;
217 }
218
219 case DHCPLEASEACTIVE: {
220 if (leases.size() == 0) {
221 isc_throw(Unexpected, "buildResponse - lease list is empty!");
222 }
223
224 // Get the newest active lease.
225 const Lease4Ptr& newest = leases[0];
226
227 // Set ciaddr and HW address from lease values.
228 response->setCiaddr(newest->addr_);
229 if (newest->hwaddr_) {
230 response->setHWAddr(newest->hwaddr_);
231 }
232
233 // Add the active lease options.
234 addOptions(query, response, newest);
235
236 // Add the associated leases (if any).
237 addAssociatedLeases(response, leases);
238 break;
239 }
240
241 default:
242 // Shouldn't happen.
243 isc_throw(Unexpected, "invalid response type: " << response_type);
244 break;
245 }
246
247 return (response);
248}
249
252 Pkt4Ptr response(new Pkt4(response_type, query->getTransid()));
253 response->setGiaddr(query->getGiaddr());
254
255 // Zero out the hwaddr type. Pkt4 constructor defaults it to HTYPE_ETHER.
256 response->setHWAddr(HWAddrPtr(new HWAddr(std::vector<uint8_t>{}, 0)));
257
258 // Set the destination to giaddr at the standard server port.
259 response->setRemoteAddr(query->getGiaddr());
260 response->setRemotePort(DHCP4_SERVER_PORT);
261
262 HWAddrPtr dst_hw_addr = query->getRemoteHWAddr();
263 if (dst_hw_addr) {
264 response->setRemoteHWAddr(dst_hw_addr);
265 }
266
267 // Set the source accordingly.
268 IOAddress local_addr = query->getLocalAddr();
269 if (local_addr.isV4Bcast()) {
270 local_addr = IfaceMgr::instance().getSocket(query).addr_;
271 }
272
273 response->setLocalAddr(local_addr);
274 response->setLocalPort(query->getLocalPort());
275 response->setIface(query->getIface());
276 response->setIndex(query->getIndex());
277
278 HWAddrPtr src_hw_addr = query->getLocalHWAddr();
279 if (src_hw_addr) {
280 response->setLocalHWAddr(src_hw_addr);
281 }
282
283 // If we got server id from the client add it.
284 OptionPtr client_server_id = query->getOption(DHO_DHCP_SERVER_IDENTIFIER);
285 if (client_server_id) {
286 response->addOption(client_server_id);
287 }
288
289 return (response);
290}
291
292void
295 int cnt = 0;
296 for (auto const& lease : leases) {
297 if (lease->addr_ != response->getCiaddr()) {
298 associates->addAddress(lease->addr_);
299 ++cnt;
300 }
301 }
302
303 if (cnt) {
304 response->addOption(associates);
305 }
306}
307
308void
309LeaseQueryImpl4::addOptions(const Pkt4Ptr& query, Pkt4Ptr response, const Lease4Ptr& lease) {
310 // Per RFC 4388 all of the following options should be sent if the
311 // client asks for them in the query's PRL option. ISC DHCP always sends
312 // them, so for now we will too.
313
314 // Get the subnet for finding various options.
316 ->getCfgSubnets4()->getSubnet(lease->subnet_id_);
317 if (!subnet) {
318 isc_throw(Unexpected, "subnet_id: " << lease->subnet_id_ << " does not exist!");
319 }
320
321 // Add the client-id.
322 if (lease->client_id_) {
324 lease->client_id_->getClientId()));
325 response->addOption(cid_opt);
326 }
327
328 // Add lease life time, T1 and T2.
329 addLeaseTimes(response, lease, subnet);
330
331 // Add relay-agent-info (82) from the extended info in the lease's
332 // user-context and add it to the response.
333 addRelayAgentInfo(response, lease);
334
335 // Add the server-id.
336 CfgOptionList co_list;
337 buildCfgOptionList(co_list, query);
338 appendServerId(response, co_list);
339}
340
341void
343 const Subnet4Ptr& subnet) {
344 time_t now = time(0);
345 time_t elapsed;
346
347 // How much time has elapsed since last client transmission?
348 if (now > lease->cltt_) {
349 elapsed = now - lease->cltt_;
350 } else {
351 // Something insane here so send back times unadjusted.
352 elapsed = 0;
353 }
354
355 // Add the time elapsed CLTT (see RFC 4388 6.1)
357 response->addOption(opt);
358
359 // If the lifetime is infinite use as is, and skip sending T1/T2.
360 if (lease->valid_lft_ == Lease::INFINITY_LFT) {
363 response->addOption(opt);
364 return;
365 }
366
367 // Calculate the remaining life time.
368 time_t adjusted_lft = lease->valid_lft_ - elapsed;
369
370 // Add the adjusted lease time to the packet.
371 opt.reset(new OptionUint32(Option::V4, DHO_DHCP_LEASE_TIME, adjusted_lft));
372 response->addOption(opt);
373
374 // Now figure out T1 and T2. This logic is largely lifted from
375 // Dhcpv4Srv::setTeeTimes(), it would be handy if there were
376 // a way to share it.
377 time_t t2_time = 0;
378 // If T2 is explicitly configured we'll use try value.
379 if (!subnet->getT2().unspecified()) {
380 t2_time = subnet->getT2();
381 } else if (subnet->getCalculateTeeTimes()) {
382 // Calculating tee times is enabled, so calculated it.
383 t2_time = static_cast<time_t>(round(subnet->getT2Percent()
384 * (lease->valid_lft_)));
385 }
386
387 // Calculate remaining T2.
388 t2_time -= elapsed;
389
390 // Send the T2 candidate value only if it's sane: to be sane it must be less than
391 // the valid life time.
392 time_t timer_ceiling = adjusted_lft;
393 if (t2_time > 0 && t2_time < timer_ceiling) {
395 response->addOption(t2);
396 // When we send T2, timer ceiling for T1 becomes T2.
397 timer_ceiling = t2_time;
398 }
399
400 time_t t1_time = 0;
401 // If T1 is explicitly configured we'll use try value.
402 if (!subnet->getT1().unspecified()) {
403 t1_time = subnet->getT1();
404 } else if (subnet->getCalculateTeeTimes()) {
405 // Calculating tee times is enabled, so calculate it.
406 t1_time = static_cast<time_t>(round(subnet->getT1Percent()
407 * (lease->valid_lft_)));
408 }
409
410 // Calculate remaining T1.
411 t1_time -= elapsed;
412
413 // Send T1 if it's sane: If we sent T2, T1 must be less than that. If not it must be
414 // less than the valid life time.
415 if (t1_time > 0 && t1_time < timer_ceiling) {
417 response->addOption(t1);
418 }
419}
420
421void
423 ConstElementPtr user_context;
424 if (lease->getContext()) {
425 user_context = UserContext::toElement(lease->getContext());
426 }
427
428 if (!user_context) {
429 return;
430 }
431
432 ConstElementPtr extended_info = user_context->get("ISC");
433 if (!extended_info) {
434 return;
435 }
436
437 ConstElementPtr relay_agent_info = extended_info->get("relay-agent-info");
438 if (!relay_agent_info) {
439 return;
440 }
441
442 // In the new layout the relay-agent-info is a map and the RAI content
443 // is in the sub-options entry of the map, in the old layout the
444 // relay-agent-info is a string holding the RAI content.
445 if (relay_agent_info->getType() == Element::map) {
446 relay_agent_info = relay_agent_info->get("sub-options");
447 if (!relay_agent_info) {
448 return;
449 }
450 }
451
452 try {
453 std::vector<uint8_t> opt_data;
454 util::str::decodeFormattedHexString(relay_agent_info->stringValue(), opt_data);
455
456 OptionPtr rai;
457 rai.reset(new Option(Option::V4, DHO_DHCP_AGENT_OPTIONS, opt_data));
458 response->addOption(rai);
459 } catch (const std::exception& ex) {
460 isc_throw(Unexpected, "Error creating relay-agent-info option: " << ex.what());
461 }
462}
463
464std::string
466 std::stringstream label;
467
468 try {
469 label << "type: " << packet->getName()
470 << ", giaddr: " << packet->getGiaddr().toText()
471 << ", transid: " << packet->getTransid()
472 << ", ciaddr: " << packet->getCiaddr().toText();
473
474 HWAddrPtr hwaddr = packet->getHWAddr();
475 label << ", hwaddr: " << (hwaddr ? hwaddr->toText() : "none");
476
477 OptionPtr client_opt = packet->getOption(DHO_DHCP_CLIENT_IDENTIFIER);
478 if (!client_opt) {
479 label << ", cid: none";
480 } else {
481 try {
482 ClientId client_id(client_opt->getData());
483 label << ", cid: " << client_id.toText();
484 } catch (...) {
485 label << ", cid: (malformed)";
486 }
487 }
488 } catch (const std::exception& ex) {
489 // Shouldn't happen. This just ensures we're exception safe.
490 label << "label error" << ex.what();
491 }
492
493 return (label.str());
494}
495
496void
498 // Pack the response.
499 try {
500 response->pack();
501 } catch (const std::exception& ex) {
503 .arg(leaseQueryLabel(response))
504 .arg(ex.what());
505 }
506
507 try {
508 IfaceMgr::instance().send(response);
510 .arg(leaseQueryLabel(response))
511 .arg(response->getRemoteAddr())
512 .arg(response->getRemotePort());
513
514 StatsMgr::instance().addValue("pkt4-sent", static_cast<int64_t>(1));
515 switch (response->getType()) {
516 case DHCPLEASEUNKNOWN:
517 StatsMgr::instance().addValue("pkt4-lease-query-response-unknown-sent",
518 static_cast<int64_t>(1));
519 break;
521 StatsMgr::instance().addValue("pkt4-lease-query-response-unassigned-sent",
522 static_cast<int64_t>(1));
523 break;
524 case DHCPLEASEACTIVE:
525 StatsMgr::instance().addValue("pkt4-lease-query-response-active-sent",
526 static_cast<int64_t>(1));
527 break;
528 default:
529 // Shouldn't happen
530 break;
531 }
532
533 } catch (const std::exception& ex) {
535 .arg(leaseQueryLabel(response))
536 .arg(response->getIface())
537 .arg(response->getRemoteAddr())
538 .arg(response->getRemotePort())
539 .arg(ex.what());
540 }
541}
542
543bool
544LeaseQueryImpl4::acceptServerId(const Pkt4Ptr& query, OptionPtr& server_id_opt) {
545 // Regardless of the outcome we send back the client server-id. It's only
546 // meaningful to the caller when we return true.
547 server_id_opt = query->getOption(DHO_DHCP_SERVER_IDENTIFIER);
548 if (!server_id_opt) {
549 // Client did not specify a server id, accept the query.
550 return (true);
551 }
552
553 // Server identifier is present. Let's convert it to 4-byte address
554 // and try to match with server identifiers used by the server.
555 OptionCustomPtr option_custom =
556 boost::dynamic_pointer_cast<OptionCustom>(server_id_opt);
557 // Unable to convert the option to the option type which encapsulates it.
558 // We treat this as non-matching server id.
559 if (!option_custom) {
560 return (false);
561 }
562 // The server identifier option should carry exactly one IPv4 address.
563 if (option_custom->getDataFieldsNum() != 1) {
564 return (false);
565 }
566
567 // The server identifier MUST be an IPv4 address and not 0.0.0.0.
568 IOAddress client_server_id = option_custom->readAddress();
569 if (!client_server_id.isV4() ||
570 (client_server_id == IOAddress::IPV4_ZERO_ADDRESS())) {
571 return (false);
572 }
573
574 // If we're listening on the client's server_id
575 // accept the query.
576 if (IfaceMgr::instance().hasOpenSocket(client_server_id)) {
577 return (true);
578 }
579
580 // Check if there are any subnets configured with
581 // this server identifier.
583 ConstCfgSubnets4Ptr cfg_subnets = cfg->getCfgSubnets4();
584 if (cfg_subnets->hasSubnetWithServerId(client_server_id)) {
585 return (true);
586 }
587
588 // This server identifier is not configured for any of the subnets, so
589 // check on the shared network level.
590 CfgSharedNetworks4Ptr cfg_networks = cfg->getCfgSharedNetworks4();
591 if (cfg_networks->hasNetworkWithServerId(client_server_id)) {
592 return (true);
593 }
594
595 // Check if the server identifier is configured at client class level.
596 const ClientClasses& classes = query->getClasses();
597 for (auto const& cclass : classes) {
598 // Find the client class definition for this class
600 getClientClassDictionary()->findClass(cclass);
601 if (!ccdef) {
602 continue;
603 }
604
605 if (ccdef->getCfgOption()->empty()) {
606 // Skip classes which don't configure options
607 continue;
608 }
609
610 OptionCustomPtr context_opt_server_id = boost::dynamic_pointer_cast<OptionCustom>
611 (ccdef->getCfgOption()->get(DHCP4_OPTION_SPACE, DHO_DHCP_SERVER_IDENTIFIER).option_);
612 if (context_opt_server_id && (context_opt_server_id->readAddress() == client_server_id)) {
613 return (true);
614 }
615 }
616
617 // Finally, it is possible that the server identifier is specified
618 // on the global level.
619 OptionCustomPtr cfg_server_id = boost::dynamic_pointer_cast<OptionCustom>
620 (cfg->getCfgOption()->get(DHCP4_OPTION_SPACE, DHO_DHCP_SERVER_IDENTIFIER).option_);
621
622 return (cfg_server_id && (cfg_server_id->readAddress() == client_server_id));
623}
624
625void
627 if (response->getOption(DHO_DHCP_SERVER_IDENTIFIER)) {
628 // Already has it.
629 return;
630 }
631
632 // If there's one in the configured options use it.
633 for (auto const& cfg_options : co_list) {
634 OptionDescriptor server_id_desc = cfg_options->get(DHCP4_OPTION_SPACE,
636 if (server_id_desc.option_) {
637 response->addOption(server_id_desc.option_);
638 return;
639 }
640 }
641
642 // Failing all of the above, let's infer one from the local address.
644 OptionCustomPtr server_id(new OptionCustom(option_def, Option::V4));
645 server_id->writeAddress(response->getLocalAddr());
646 response->addOption(server_id);
647}
648
649void
651 const Lease4Ptr& lease, const Subnet4Ptr& subnet) {
652 // When lease is provided we're getting options for an active lease response.
653 if (lease) {
654 if (!subnet) {
655 isc_throw (Unexpected, "buildCfgOptionList: subnet must be provided with lease");
656 }
657
665
666 // Add pool options.
667 PoolPtr pool = subnet->getPool(Lease::TYPE_V4, lease->addr_, false);
668 if (pool && !pool->getCfgOption()->empty()) {
669 co_list.push_back(pool->getCfgOption());
670 }
671
672 // Add subnet options.
673 if (!subnet->getCfgOption()->empty()) {
674 co_list.push_back(subnet->getCfgOption());
675 }
676
677 // Next shared network options.
678 SharedNetwork4Ptr network;
679 subnet->getSharedNetwork(network);
680 if (network && !network->getCfgOption()->empty()) {
681 co_list.push_back(network->getCfgOption());
682 }
683
684 // Each class in the incoming packet
685 const ClientClasses& classes = query->getClasses();
686 for (auto const& cclass : classes) {
687 // Find the client class definition for this class
689 getClientClassDictionary()->findClass(cclass);
690 if (!ccdef) {
691 // Skip it
692 continue;
693 }
694
695 if (ccdef->getCfgOption()->empty()) {
696 // Skip classes which don't configure options
697 continue;
698 }
699
700 co_list.push_back(ccdef->getCfgOption());
701 }
702 }
703
704 // Add global options
705 if (!CfgMgr::instance().getCurrentCfg()->getCfgOption()->empty()) {
706 co_list.push_back(CfgMgr::instance().getCurrentCfg()->getCfgOption());
707 }
708}
709
710int
712 ConstElementPtr response;
713 size_t upgraded = 0;
715 try {
717 auto& lease_mgr = LeaseMgrFactory::instance();
718 upgraded = lease_mgr.upgradeExtendedInfo4(page_size);
719 } catch (const std::exception& ex) {
720 // log here.
721 response = createAnswer(CONTROL_RESULT_ERROR, ex.what());
722 handle.setArgument("response", response);
723 return (1);
724 }
725
726 // log here.
727 std::ostringstream msg;
728 msg << "Upgraded " << upgraded << " lease";
729 if (upgraded != 1) {
730 msg << "s";
731 }
732 response = createAnswer(CONTROL_RESULT_SUCCESS, msg.str());
733 handle.setArgument("response", response);
734 return (0);
735}
@ map
Definition data.h:147
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
A generic exception that is thrown when an unexpected error condition occurs.
static CfgMgr & instance()
returns a single instance of Configuration Manager
Definition cfgmgr.cc:29
SrvConfigPtr getCurrentCfg()
Returns a pointer to the current configuration.
Definition cfgmgr.cc:116
Container for storing client class names.
Definition classify.h:110
Holds Client identifier or client IPv4 address.
Definition duid.h:222
std::string toText() const
Returns textual representation of the identifier (e.g.
Definition duid.h:88
static IfaceMgr & instance()
IfaceMgr is a singleton class.
Definition iface_mgr.cc:54
bool send(const Pkt6Ptr &pkt)
Sends an IPv6 packet.
uint16_t getSocket(const isc::dhcp::Pkt6Ptr &pkt)
Return most suitable socket for transmitting specified IPv6 packet.
static TrackingLeaseMgr & instance()
Return current lease manager.
virtual Lease4Ptr getLease4(const isc::asiolink::IOAddress &addr) const =0
Returns an IPv4 lease for specified IPv4 address.
Wraps value holding size of the page with leases.
Definition lease_mgr.h:46
static const OptionDefinition & DHO_DHCP_SERVER_IDENTIFIER_DEF()
Get definition of DHO_DHCP_SERVER_IDENTIFIER option.
DHCPv4 Option class for handling list of IPv4 addresses.
Option with defined data fields represented as buffers that can be accessed using data field index.
Base class representing a DHCP option definition.
Option descriptor.
Definition cfg_option.h:49
OptionPtr option_
Option instance.
Definition cfg_option.h:52
Represents DHCPv4 packet.
Definition pkt4.h:37
Per-packet callout handle.
void setArgument(const std::string &name, T value)
Set argument.
static dhcp::DHCPMessageType queryByIpAddress(const asiolink::IOAddress &ciaddr, dhcp::Lease4Collection &leases)
Queries for an active lease matching an ip address.
static void addOptions(const dhcp::Pkt4Ptr &query, dhcp::Pkt4Ptr response, const dhcp::Lease4Ptr &lease)
Adds options to a query response.
static int upgradeHandler(hooks::CalloutHandle &handle)
Upgrade extended information.
static void sendResponse(const dhcp::Pkt4Ptr &response)
Packs and sends a query response.
static void addLeaseTimes(dhcp::Pkt4Ptr response, const dhcp::Lease4Ptr &lease, const dhcp::Subnet4Ptr &subnet)
Adds life time, T1, and T2 options to a query response.
LeaseQueryImpl4(const data::ConstElementPtr config)
Constructor.
virtual void processQuery(dhcp::PktPtr base_query) const
Processes a single DHCPv4 client Lease Query.
static void addAssociatedLeases(dhcp::Pkt4Ptr response, const dhcp::Lease4Collection &leases)
Adds associated leases to a query response.
static std::string leaseQueryLabel(const dhcp::Pkt4Ptr &packet)
Convenience method for generating per packet logging info.
static dhcp::Lease4Collection winnowLeases(const dhcp::Lease4Collection &leases)
Creates a list of active leases from a list of leases.
static bool acceptServerId(const dhcp::Pkt4Ptr &query, dhcp::OptionPtr &server_id_opt)
Validates dhcp-server-identifier option in the inbound query (if one)
static dhcp::DHCPMessageType queryByHWAddr(const dhcp::HWAddrPtr &hwaddr, dhcp::Lease4Collection &leases)
Queries LeaseMgr for active leases matching a HW address.
static void buildCfgOptionList(dhcp::CfgOptionList &co_list, const dhcp::Pkt4Ptr &query, const dhcp::Lease4Ptr &lease=dhcp::Lease4Ptr(), const dhcp::Subnet4Ptr &subnet=dhcp::Subnet4Ptr())
Constructs a list of configured option sets for a given lease and it's subnet.
static dhcp::DHCPMessageType queryByClientId(const dhcp::ClientIdPtr &client_id, dhcp::Lease4Collection &leases)
Queries LeaseMgr for active leases matching a client.
static void appendServerId(dhcp::Pkt4Ptr &response, dhcp::CfgOptionList &co_list)
Adds dhcp-server-identifier option (54) to the response.
static void addRelayAgentInfo(dhcp::Pkt4Ptr response, const dhcp::Lease4Ptr &lease)
Adds relay-agent-info option to a query response.
static dhcp::Pkt4Ptr initResponse(dhcp::DHCPMessageType response_type, const dhcp::Pkt4Ptr &query)
Creates the initial query response.
static dhcp::Pkt4Ptr buildResponse(dhcp::DHCPMessageType response_type, const dhcp::Pkt4Ptr &query, const dhcp::Lease4Collection &leases)
Creates a lease query response packet.
LeaseQueryImpl(uint16_t family, const isc::data::ConstElementPtr config)
Constructor.
bool isRequester(const isc::asiolink::IOAddress &address) const
Checks if the given address belongs to a valid requester.
static size_t PageSize
Page size to commands.
static StatsMgr & instance()
Statistics Manager accessor method.
RAII class creating a critical section.
This file contains several functions and constants that are used for handling commands and responses ...
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
OptionInt< uint32_t > OptionUint32
Definition option_int.h:34
boost::shared_ptr< OptionUint32 > OptionUint32Ptr
Definition option_int.h:35
void addValue(const std::string &name, const int64_t value)
Records incremental integer observation.
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
Definition macros.h:32
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition macros.h:14
const int CONTROL_RESULT_ERROR
Status code indicating a general failure.
ConstElementPtr createAnswer()
Creates a standard config/command level success answer message (i.e.
const int CONTROL_RESULT_SUCCESS
Status code indicating a successful operation.
boost::shared_ptr< const Element > ConstElementPtr
Definition data.h:29
boost::shared_ptr< isc::dhcp::Pkt > PktPtr
A pointer to either Pkt4 or Pkt6 packet.
Definition pkt.h:999
boost::shared_ptr< Subnet4 > Subnet4Ptr
A pointer to a Subnet4 object.
Definition subnet.h:461
@ DHO_DHCP_REBINDING_TIME
Definition dhcp4.h:128
@ DHO_DHCP_SERVER_IDENTIFIER
Definition dhcp4.h:123
@ DHO_DHCP_CLIENT_IDENTIFIER
Definition dhcp4.h:130
@ DHO_DHCP_AGENT_OPTIONS
Definition dhcp4.h:151
@ DHO_ASSOCIATED_IP
Definition dhcp4.h:161
@ DHO_CLIENT_LAST_TRANSACTION_TIME
Definition dhcp4.h:160
@ DHO_DHCP_RENEWAL_TIME
Definition dhcp4.h:127
@ DHO_DHCP_LEASE_TIME
Definition dhcp4.h:120
boost::shared_ptr< OptionCustom > OptionCustomPtr
A pointer to the OptionCustom object.
boost::shared_ptr< Pkt4 > Pkt4Ptr
A pointer to Pkt4 object.
Definition pkt4.h:556
boost::shared_ptr< ClientClassDef > ClientClassDefPtr
a pointer to an ClientClassDef
boost::shared_ptr< SrvConfig > SrvConfigPtr
Non-const pointer to the SrvConfig.
boost::shared_ptr< HWAddr > HWAddrPtr
Shared pointer to a hardware address structure.
Definition hwaddr.h:154
boost::shared_ptr< Pool > PoolPtr
a pointer to either IPv4 or IPv6 Pool
Definition pool.h:726
boost::multi_index_container< Subnet4Ptr, 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< SubnetServerIdIndexTag >, boost::multi_index::const_mem_fun< Network4, asiolink::IOAddress, &Network4::getServerId > >, 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 > > > > Subnet4Collection
A collection of Subnet4 objects.
Definition subnet.h:866
boost::shared_ptr< ClientId > ClientIdPtr
Shared pointer to a Client ID.
Definition duid.h:216
DHCPMessageType
Definition dhcp4.h:233
@ DHCPLEASEUNKNOWN
Definition dhcp4.h:246
@ DHCPLEASEACTIVE
Definition dhcp4.h:247
@ DHCPLEASEUNASSIGNED
Definition dhcp4.h:245
boost::shared_ptr< const CfgSubnets4 > ConstCfgSubnets4Ptr
Const pointer.
boost::shared_ptr< CfgSharedNetworks4 > CfgSharedNetworks4Ptr
Pointer to the configuration of IPv4 shared networks.
boost::shared_ptr< SharedNetwork4 > SharedNetwork4Ptr
Pointer to SharedNetwork4 object.
std::vector< Lease4Ptr > Lease4Collection
A collection of IPv4 leases.
Definition lease.h:520
boost::shared_ptr< Lease4 > Lease4Ptr
Pointer to a Lease4 structure.
Definition lease.h:315
boost::shared_ptr< Option4AddrLst > Option4AddrLstPtr
A pointer to the Option4AddrLst object.
boost::shared_ptr< Option > OptionPtr
Definition option.h:37
std::list< ConstCfgOptionPtr > CfgOptionList
Const pointer list.
Definition cfg_option.h:979
const isc::log::MessageID DHCP4_LEASE_QUERY_PACKET_PACK_FAILED
const isc::log::MessageID DHCP4_LEASE_QUERY_SEND_FAILED
const isc::log::MessageID DHCP4_LEASE_QUERY_RESPONSE_SENT
isc::log::Logger lease_query_logger("lease-query-hooks")
const int DBGLVL_TRACE_BASIC
Trace basic operations.
void decodeFormattedHexString(const string &hex_string, vector< uint8_t > &binary)
Converts a formatted string of hexadecimal digits into a vector.
Definition str.cc:212
Defines the logger used by the top-level component of kea-lfc.
#define DHCP4_OPTION_SPACE
global std option spaces
static data::ElementPtr toElement(data::ConstElementPtr map)
Copy an Element map.
Hardware type that represents information from DHCPv4 packet.
Definition hwaddr.h:20
static const uint32_t INFINITY_LFT
Infinity (means static, i.e. never expire)
Definition lease.h:34
static const uint32_t STATE_DEFAULT
A lease in the default state.
Definition lease.h:69
@ TYPE_V4
IPv4 lease.
Definition lease.h:50