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