Kea 3.3.1
lease_query_impl4.cc
Go to the documentation of this file.
1// Copyright (C) 2020-2026 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
8
10#include <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
50LeaseQueryImpl4::processQuery(PktPtr base_query, bool& invalid) const {
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 invalid = true;
61 StatsMgr::instance().addValue("pkt4-rfc-violation",
62 static_cast<int64_t>(1));
63 isc_throw(BadValue, "giaddr cannot be 0.0.0.0");
64 }
65
66 if (!isRequester(requester_ip)) {
67 invalid = true;
68 StatsMgr::instance().addValue("pkt4-admin-filtered",
69 static_cast<int64_t>(1));
70 isc_throw(BadValue, "rejecting query from unauthorized requester: "
71 << requester_ip.toText());
72 }
73
74 OptionPtr client_server_id;
75 if (!acceptServerId(query, client_server_id)) {
76 invalid = true;
77 // Drop statistic updated by acceptServerId.
78 isc_throw(BadValue, "rejecting query from: "
79 << requester_ip.toText() << ", unknown server-id: "
80 << (client_server_id ? client_server_id->toText() : "malformed"));
81 }
82
83 // Let's figure out which query type we have base on which attributes
84 // the client sent. The attributes are mutually exclusive so we'll
85 // make a bit mask of which ones the query contains and go from there.
86 IOAddress ciaddr = query->getCiaddr();
87 uint8_t query_mask = (!ciaddr.isV4Zero() ? 1 : 0);
88
89 HWAddrPtr hwaddr = query->getHWAddr();
90 // Ignore the htype.
91 query_mask |= (hwaddr->hwaddr_.size() ? 2 : 0);
92
93 ClientIdPtr client_id;
94 OptionPtr opt = query->getOption(DHO_DHCP_CLIENT_IDENTIFIER);
95 if (opt) {
96 client_id.reset(new ClientId(opt->getData()));
97 query_mask += 4;
98 }
99
100 Lease4Collection leases;
101 DHCPMessageType response_type;
102
103 // Do the query based on which query attribute we have,
104 // or error out.
105 switch (query_mask) {
106 case 1:
107 // Query by ip address.
108 response_type = queryByIpAddress(ciaddr, leases);
109 break;
110 case 2:
111 // Query by HW address.
112 response_type = queryByHWAddr(hwaddr, leases);
113 break;
114 case 4:
115 // Query by client id.
116 response_type = queryByClientId(client_id, leases);
117 break;
118 default:
119 // We have some combination of the three which is invalid.
120 invalid = true;
121 StatsMgr::instance().addValue("pkt4-rfc-violation",
122 static_cast<int64_t>(1));
123 isc_throw(BadValue, "malformed lease query: "
124 << "ciaddr: [" << ciaddr
125 << "] HWAddr: [" << hwaddr->toText()
126 << "] Client id: [" << (client_id ? client_id->toText() : "")
127 << "]");
128 }
129
130 Pkt4Ptr response = buildResponse(response_type, query, leases);
132 if (response) {
133 sendResponse(response);
134 }
135}
136
139 Lease4Collection& leases) {
141 if (lease) {
142 if (lease->state_ == Lease::STATE_DEFAULT && !lease->expired()) {
143 // Found an active lease.
144 leases.push_back(lease);
145 return (DHCPLEASEACTIVE);
146 }
147
148 // We have a lease but it's not active.
149 return (DHCPLEASEUNASSIGNED);
150 }
151
152 // We didn't find a lease, so we need to determine if it is a lease
153 // we should know about. We iterate over all subnets, in case the
154 // address is inRange() of more than one subnet.
155 const Subnet4Collection* subnets;
156 subnets = CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->getAll();
157 for (auto const& subnet : *subnets) {
158
159 if (subnet->inPool(Lease::TYPE_V4, ciaddr)) {
160 // Belongs to a pool in this subnet, but not leased.
161 return (DHCPLEASEUNASSIGNED);
162 }
163 }
164
165 // Not an address we know about.
166 return (DHCPLEASEUNKNOWN);
167}
168
171 Lease4Collection& leases) {
172 leases = winnowLeases(LeaseMgrFactory::instance().getLease4(*client_id));
173 return (!leases.empty() ? DHCPLEASEACTIVE : DHCPLEASEUNKNOWN);
174}
175
178 Lease4Collection& leases) {
179 leases = winnowLeases(LeaseMgrFactory::instance().getLease4(*hwaddr));
180 return (!leases.empty() ? DHCPLEASEACTIVE : DHCPLEASEUNKNOWN);
181}
182
185 // We want only the active leases and we want them ordered
186 // newest to oldest by CLTT.
187 Lease4Collection active_leases;
188 if (!found_leases.empty()) {
189 for (auto const& lease : found_leases) {
190 if (lease->state_ == Lease::STATE_DEFAULT && !lease->expired()) {
191 active_leases.push_back(lease);
192 }
193 }
194
195 std::sort(active_leases.begin(), active_leases.end(), cltt_descending);
196 }
197
198 return (active_leases);
199}
200
203 const Pkt4Ptr& query,
204 const Lease4Collection& leases) {
205 // Create the basic response packet.
206 Pkt4Ptr response = initResponse(response_type, query);
207
208 switch(response_type) {
209 case DHCPLEASEUNKNOWN:
210 case DHCPLEASEUNASSIGNED: {
211 // RFC 4388 is ambiguous on this issue, so for
212 // negative queries we will always return the
213 // query parameter. Only one which will have
214 // a non-empty value. This alleviates the requester
215 // from having to try to match queries to
216 // responses.
217 response->setCiaddr(query->getCiaddr());
218 response->setHWAddr(query->getHWAddr());
219 OptionPtr opt = query->getOption(DHO_DHCP_CLIENT_IDENTIFIER);
220 if (opt) {
221 response->addOption(opt);
222 }
223
224 // Add the server-id.
225 CfgOptionList co_list;
226 buildCfgOptionList(co_list, query);
227 appendServerId(response, co_list);
228 break;
229 }
230
231 case DHCPLEASEACTIVE: {
232 if (leases.size() == 0) {
233 isc_throw(Unexpected, "buildResponse - lease list is empty!");
234 }
235
236 // Get the newest active lease.
237 const Lease4Ptr& newest = leases[0];
238
239 // Set ciaddr and HW address from lease values.
240 response->setCiaddr(newest->addr_);
241 if (newest->hwaddr_) {
242 response->setHWAddr(newest->hwaddr_);
243 }
244
245 // Add the active lease options.
246 addOptions(query, response, newest);
247
248 // Add the associated leases (if any).
249 addAssociatedLeases(response, leases);
250 break;
251 }
252
253 default:
254 // Shouldn't happen.
255 isc_throw(Unexpected, "invalid response type: " << response_type);
256 break;
257 }
258
259 return (response);
260}
261
264 Pkt4Ptr response(new Pkt4(response_type, query->getTransid()));
265 response->setGiaddr(query->getGiaddr());
266
267 // Zero out the hwaddr type. Pkt4 constructor defaults it to HTYPE_ETHER.
268 response->setHWAddr(HWAddrPtr(new HWAddr(std::vector<uint8_t>{}, 0)));
269
270 // Set the destination to giaddr at the standard server port.
271 response->setRemoteAddr(query->getGiaddr());
272 response->setRemotePort(DHCP4_SERVER_PORT);
273
274 HWAddrPtr dst_hw_addr = query->getRemoteHWAddr();
275 if (dst_hw_addr) {
276 response->setRemoteHWAddr(dst_hw_addr);
277 }
278
279 // Set the source accordingly.
280 IOAddress local_addr = query->getLocalAddr();
281 if (local_addr.isV4Bcast()) {
282 local_addr = IfaceMgr::instance().getSocket(query).addr_;
283 }
284
285 response->setLocalAddr(local_addr);
286 response->setLocalPort(query->getLocalPort());
287 response->setIface(query->getIface());
288 response->setIndex(query->getIndex());
289
290 HWAddrPtr src_hw_addr = query->getLocalHWAddr();
291 if (src_hw_addr) {
292 response->setLocalHWAddr(src_hw_addr);
293 }
294
295 // If we got server id from the client add it.
296 OptionPtr client_server_id = query->getOption(DHO_DHCP_SERVER_IDENTIFIER);
297 if (client_server_id) {
298 response->addOption(client_server_id);
299 }
300
301 return (response);
302}
303
304void
307 int cnt = 0;
308 for (auto const& lease : leases) {
309 if (lease->addr_ != response->getCiaddr()) {
310 associates->addAddress(lease->addr_);
311 ++cnt;
312 }
313 }
314
315 if (cnt) {
316 response->addOption(associates);
317 }
318}
319
320void
321LeaseQueryImpl4::addOptions(const Pkt4Ptr& query, Pkt4Ptr response, const Lease4Ptr& lease) {
322 // Per RFC 4388 all of the following options should be sent if the
323 // client asks for them in the query's PRL option. ISC DHCP always sends
324 // them, so for now we will too.
325
326 // Get the subnet for finding various options.
328 ->getCfgSubnets4()->getSubnet(lease->subnet_id_);
329 if (!subnet) {
330 isc_throw(Unexpected, "subnet_id: " << lease->subnet_id_ << " does not exist!");
331 }
332
333 // Add the client-id.
334 if (lease->client_id_) {
336 lease->client_id_->getClientId()));
337 response->addOption(cid_opt);
338 }
339
340 // Add lease life time, T1 and T2.
341 addLeaseTimes(response, lease, subnet);
342
343 // Add relay-agent-info (82) from the extended info in the lease's
344 // user-context and add it to the response.
345 addRelayAgentInfo(response, lease);
346
347 // Add the server-id.
348 CfgOptionList co_list;
349 buildCfgOptionList(co_list, query);
350 appendServerId(response, co_list);
351}
352
353void
355 const Subnet4Ptr& subnet) {
356 time_t now = time(0);
357 time_t elapsed;
358
359 // How much time has elapsed since last client transmission?
360 if (now > lease->cltt_) {
361 elapsed = now - lease->cltt_;
362 } else {
363 // Something insane here so send back times unadjusted.
364 elapsed = 0;
365 }
366
367 // Add the time elapsed CLTT (see RFC 4388 6.1)
369 response->addOption(opt);
370
371 // If the lifetime is infinite use as is, and skip sending T1/T2.
372 if (lease->valid_lft_ == Lease::INFINITY_LFT) {
375 response->addOption(opt);
376 return;
377 }
378
379 // Calculate the remaining life time.
380 time_t adjusted_lft = lease->valid_lft_ - elapsed;
381
382 // Add the adjusted lease time to the packet.
383 opt.reset(new OptionUint32(Option::V4, DHO_DHCP_LEASE_TIME, adjusted_lft));
384 response->addOption(opt);
385
386 // Now figure out T1 and T2. This logic is largely lifted from
387 // Dhcpv4Srv::setTeeTimes(), it would be handy if there were
388 // a way to share it.
389 time_t t2_time = 0;
390 // If T2 is explicitly configured we'll use try value.
391 if (!subnet->getT2().unspecified()) {
392 t2_time = subnet->getT2();
393 } else if (subnet->getCalculateTeeTimes()) {
394 // Calculating tee times is enabled, so calculated it.
395 t2_time = static_cast<time_t>(round(subnet->getT2Percent()
396 * (lease->valid_lft_)));
397 }
398
399 // Calculate remaining T2.
400 t2_time -= elapsed;
401
402 // Send the T2 candidate value only if it's sane: to be sane it must be less than
403 // the valid life time.
404 time_t timer_ceiling = adjusted_lft;
405 if (t2_time > 0 && t2_time < timer_ceiling) {
407 response->addOption(t2);
408 // When we send T2, timer ceiling for T1 becomes T2.
409 timer_ceiling = t2_time;
410 }
411
412 time_t t1_time = 0;
413 // If T1 is explicitly configured we'll use try value.
414 if (!subnet->getT1().unspecified()) {
415 t1_time = subnet->getT1();
416 } else if (subnet->getCalculateTeeTimes()) {
417 // Calculating tee times is enabled, so calculate it.
418 t1_time = static_cast<time_t>(round(subnet->getT1Percent()
419 * (lease->valid_lft_)));
420 }
421
422 // Calculate remaining T1.
423 t1_time -= elapsed;
424
425 // Send T1 if it's sane: If we sent T2, T1 must be less than that. If not it must be
426 // less than the valid life time.
427 if (t1_time > 0 && t1_time < timer_ceiling) {
429 response->addOption(t1);
430 }
431}
432
433void
435 ConstElementPtr user_context;
436 if (lease->getContext()) {
437 user_context = UserContext::toElement(lease->getContext());
438 }
439
440 if (!user_context) {
441 return;
442 }
443
444 ConstElementPtr extended_info = user_context->get("ISC");
445 if (!extended_info) {
446 return;
447 }
448
449 ConstElementPtr relay_agent_info = extended_info->get("relay-agent-info");
450 if (!relay_agent_info) {
451 return;
452 }
453
454 // In the new layout the relay-agent-info is a map and the RAI content
455 // is in the sub-options entry of the map, in the old layout the
456 // relay-agent-info is a string holding the RAI content.
457 if (relay_agent_info->getType() == Element::map) {
458 relay_agent_info = relay_agent_info->get("sub-options");
459 if (!relay_agent_info) {
460 return;
461 }
462 }
463
464 try {
465 std::vector<uint8_t> opt_data;
466 util::str::decodeFormattedHexString(relay_agent_info->stringValue(), opt_data);
467
468 OptionPtr rai;
469 rai.reset(new Option(Option::V4, DHO_DHCP_AGENT_OPTIONS, opt_data));
470 response->addOption(rai);
471 } catch (const std::exception& ex) {
472 isc_throw(Unexpected, "Error creating relay-agent-info option: " << ex.what());
473 }
474}
475
476std::string
478 std::stringstream label;
479
480 try {
481 label << "type: " << packet->getName()
482 << ", giaddr: " << packet->getGiaddr().toText()
483 << ", transid: " << packet->getTransid()
484 << ", ciaddr: " << packet->getCiaddr().toText();
485
486 HWAddrPtr hwaddr = packet->getHWAddr();
487 label << ", hwaddr: " << (hwaddr ? hwaddr->toText() : "none");
488
489 OptionPtr client_opt = packet->getOption(DHO_DHCP_CLIENT_IDENTIFIER);
490 if (!client_opt) {
491 label << ", cid: none";
492 } else {
493 try {
494 ClientId client_id(client_opt->getData());
495 label << ", cid: " << client_id.toText();
496 } catch (...) {
497 label << ", cid: (malformed)";
498 }
499 }
500 } catch (const std::exception& ex) {
501 // Shouldn't happen. This just ensures we're exception safe.
502 label << "label error" << ex.what();
503 }
504
505 return (label.str());
506}
507
508void
510 // Pack the response.
511 try {
512 response->pack();
513 } catch (const std::exception& ex) {
515 .arg(leaseQueryLabel(response))
516 .arg(ex.what());
517 }
518
519 try {
520 IfaceMgr::instance().send(response);
522 .arg(leaseQueryLabel(response))
523 .arg(response->getRemoteAddr())
524 .arg(response->getRemotePort());
525
526 StatsMgr::instance().addValue("pkt4-sent", static_cast<int64_t>(1));
527 switch (response->getType()) {
528 case DHCPLEASEUNKNOWN:
529 StatsMgr::instance().addValue("pkt4-lease-query-response-unknown-sent",
530 static_cast<int64_t>(1));
531 break;
533 StatsMgr::instance().addValue("pkt4-lease-query-response-unassigned-sent",
534 static_cast<int64_t>(1));
535 break;
536 case DHCPLEASEACTIVE:
537 StatsMgr::instance().addValue("pkt4-lease-query-response-active-sent",
538 static_cast<int64_t>(1));
539 break;
540 default:
541 // Shouldn't happen
542 break;
543 }
544
545 } catch (const std::exception& ex) {
547 .arg(leaseQueryLabel(response))
548 .arg(response->getIface())
549 .arg(response->getRemoteAddr())
550 .arg(response->getRemotePort())
551 .arg(ex.what());
552 }
553}
554
555bool
556LeaseQueryImpl4::acceptServerId(const Pkt4Ptr& query, OptionPtr& server_id_opt) {
557 // Regardless of the outcome we send back the client server-id. It's only
558 // meaningful to the caller when we return true.
559 server_id_opt = query->getOption(DHO_DHCP_SERVER_IDENTIFIER);
560 if (!server_id_opt) {
561 // Client did not specify a server id, accept the query.
562 return (true);
563 }
564
565 // Server identifier is present. Let's convert it to 4-byte address
566 // and try to match with server identifiers used by the server.
567 OptionCustomPtr option_custom =
568 boost::dynamic_pointer_cast<OptionCustom>(server_id_opt);
569 // Unable to convert the option to the option type which encapsulates it.
570 // We treat this as non-matching server id.
571 if (!option_custom) {
572 StatsMgr::instance().addValue("pkt4-rfc-violation",
573 static_cast<int64_t>(1));
574 return (false);
575 }
576 // The server identifier option should carry exactly one IPv4 address.
577 if (option_custom->getDataFieldsNum() != 1) {
578 StatsMgr::instance().addValue("pkt4-rfc-violation",
579 static_cast<int64_t>(1));
580 return (false);
581 }
582
583 // The server identifier MUST be an IPv4 address and not 0.0.0.0.
584 IOAddress client_server_id = option_custom->readAddress();
585 if (!client_server_id.isV4() ||
586 (client_server_id == IOAddress::IPV4_ZERO_ADDRESS())) {
587 StatsMgr::instance().addValue("pkt4-rfc-violation",
588 static_cast<int64_t>(1));
589 return (false);
590 }
591
592 // If we're listening on the client's server_id
593 // accept the query.
594 if (IfaceMgr::instance().hasOpenSocket(client_server_id)) {
595 return (true);
596 }
597
598 // Check if there are any subnets configured with
599 // this server identifier.
601 ConstCfgSubnets4Ptr cfg_subnets = cfg->getCfgSubnets4();
602 if (cfg_subnets->hasSubnetWithServerId(client_server_id)) {
603 return (true);
604 }
605
606 // This server identifier is not configured for any of the subnets, so
607 // check on the shared network level.
608 CfgSharedNetworks4Ptr cfg_networks = cfg->getCfgSharedNetworks4();
609 if (cfg_networks->hasNetworkWithServerId(client_server_id)) {
610 return (true);
611 }
612
613 // Check if the server identifier is configured at client class level.
614 const ClientClasses& classes = query->getClasses();
615 for (auto const& cclass : classes) {
616 // Find the client class definition for this class
618 getClientClassDictionary()->findClass(cclass);
619 if (!ccdef) {
620 continue;
621 }
622
623 if (ccdef->getCfgOption()->empty()) {
624 // Skip classes which don't configure options
625 continue;
626 }
627
628 OptionCustomPtr context_opt_server_id = boost::dynamic_pointer_cast<OptionCustom>
629 (ccdef->getCfgOption()->get(DHCP4_OPTION_SPACE, DHO_DHCP_SERVER_IDENTIFIER).option_);
630 if (context_opt_server_id && (context_opt_server_id->readAddress() == client_server_id)) {
631 return (true);
632 }
633 }
634
635 // Finally, it is possible that the server identifier is specified
636 // on the global level.
637 OptionCustomPtr cfg_server_id = boost::dynamic_pointer_cast<OptionCustom>
638 (cfg->getCfgOption()->get(DHCP4_OPTION_SPACE, DHO_DHCP_SERVER_IDENTIFIER).option_);
639
640 if (cfg_server_id && (cfg_server_id->readAddress() == client_server_id)) {
641 return (true);
642 }
643
644 // Everything failed so the query is not for us.
645 StatsMgr::instance().addValue("pkt4-not-for-us",
646 static_cast<int64_t>(1));
647 return (false);
648}
649
650void
652 if (response->getOption(DHO_DHCP_SERVER_IDENTIFIER)) {
653 // Already has it.
654 return;
655 }
656
657 // If there's one in the configured options use it.
658 for (auto const& cfg_options : co_list) {
659 OptionDescriptor server_id_desc = cfg_options->get(DHCP4_OPTION_SPACE,
661 if (server_id_desc.option_) {
662 response->addOption(server_id_desc.option_);
663 return;
664 }
665 }
666
667 // Failing all of the above, let's infer one from the local address.
669 OptionCustomPtr server_id(new OptionCustom(option_def, Option::V4));
670 server_id->writeAddress(response->getLocalAddr());
671 response->addOption(server_id);
672}
673
674void
676 const Lease4Ptr& lease, const Subnet4Ptr& subnet) {
677 // When lease is provided we're getting options for an active lease response.
678 if (lease) {
679 if (!subnet) {
680 isc_throw (Unexpected, "buildCfgOptionList: subnet must be provided with lease");
681 }
682
690
691 // Add pool options.
692 PoolPtr pool = subnet->getPool(Lease::TYPE_V4, lease->addr_, false);
693 if (pool && !pool->getCfgOption()->empty()) {
694 co_list.push_back(pool->getCfgOption());
695 }
696
697 // Add subnet options.
698 if (!subnet->getCfgOption()->empty()) {
699 co_list.push_back(subnet->getCfgOption());
700 }
701
702 // Next shared network options.
703 SharedNetwork4Ptr network;
704 subnet->getSharedNetwork(network);
705 if (network && !network->getCfgOption()->empty()) {
706 co_list.push_back(network->getCfgOption());
707 }
708
709 // Each class in the incoming packet
710 const ClientClasses& classes = query->getClasses();
711 for (auto const& cclass : classes) {
712 // Find the client class definition for this class
714 getClientClassDictionary()->findClass(cclass);
715 if (!ccdef) {
716 // Skip it
717 continue;
718 }
719
720 if (ccdef->getCfgOption()->empty()) {
721 // Skip classes which don't configure options
722 continue;
723 }
724
725 co_list.push_back(ccdef->getCfgOption());
726 }
727 }
728
729 // Add global options
730 if (!CfgMgr::instance().getCurrentCfg()->getCfgOption()->empty()) {
731 co_list.push_back(CfgMgr::instance().getCurrentCfg()->getCfgOption());
732 }
733}
734
735int
737 ConstElementPtr response;
738 size_t upgraded = 0;
740 try {
742 auto& lease_mgr = LeaseMgrFactory::instance();
743 upgraded = lease_mgr.upgradeExtendedInfo4(page_size);
744 } catch (const std::exception& ex) {
745 // log here.
746 response = createAnswer(CONTROL_RESULT_ERROR, ex.what());
747 handle.setArgument("response", response);
748 return (1);
749 }
750
751 // log here.
752 std::ostringstream msg;
753 msg << "Upgraded " << upgraded << " lease";
754 if (upgraded != 1) {
755 msg << "s";
756 }
757 response = createAnswer(CONTROL_RESULT_SUCCESS, msg.str());
758 handle.setArgument("response", response);
759 return (0);
760}
@ map
Definition data.h:160
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:111
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:52
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:50
OptionPtr option_
Option instance.
Definition cfg_option.h:53
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(isc::dhcp::PktPtr base_query, bool &invalid) 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:30
boost::shared_ptr< isc::dhcp::Pkt > PktPtr
A pointer to either Pkt4 or Pkt6 packet.
Definition pkt.h:1005
boost::shared_ptr< Subnet4 > Subnet4Ptr
A pointer to a Subnet4 object.
Definition subnet.h:458
@ 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:863
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:989
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 constexpr uint32_t STATE_DEFAULT
A lease in the default state.
Definition lease.h:69
@ TYPE_V4
IPv4 lease.
Definition lease.h:50