Kea 3.1.1
ping_check_callouts.cc
Go to the documentation of this file.
1// Copyright (C) 2023-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
11#include <dhcpsrv/cfgmgr.h>
12#include <ping_check_log.h>
13#include <ping_check_mgr.h>
14#include <hooks/hooks.h>
15#include <process/daemon.h>
16#include <string>
17
18namespace isc {
19namespace ping_check {
20
23
24} // end of namespace ping_check
25} // end of namespace isc
26
27using namespace isc;
28using namespace isc::asiolink;
29using namespace isc::log;
30using namespace isc::data;
31using namespace isc::db;
32using namespace isc::dhcp;
33using namespace isc::ping_check;
34using namespace isc::hooks;
35using namespace isc::process;
36using namespace std;
37
38// Functions accessed by the hooks framework use C linkage to avoid the name
39// mangling that accompanies use of the C++ compiler as well as to avoid
40// issues related to namespaces.
41extern "C" {
42
47 try {
48 SrvConfigPtr server_config;
49 handle.getArgument("server_config", server_config);
50 mgr->updateSubnetConfig(server_config);
51
52 NetworkStatePtr network_state;
53 handle.getArgument("network_state", network_state);
54
55 // Schedule a start of the services. This ensures we begin after
56 // the dust has settled and Kea MT mode has been firmly established.
57 mgr->startService(network_state);
59 } catch (const std::exception& ex) {
61 .arg(ex.what());
62
64 ostringstream os;
65 os << "Error: " << ex.what();
66 string error(os.str());
67 handle.setArgument("error", error);
68 return (1);
69 }
70
71 return (0);
72}
73
85 AuditEntryCollectionPtr audit_entries;
86 handle.getArgument("audit_entries", audit_entries);
87
88 auto const& object_type_idx = audit_entries->get<AuditEntryObjectTypeTag>();
89 auto range = object_type_idx.equal_range("dhcp4_subnet");
90 if (std::distance(range.first, range.second)) {
91 try {
92 // Server config has been committed, so use the current configuration.
93 mgr->updateSubnetConfig(CfgMgr::instance().getCurrentCfg());
94 } catch (const std::exception& ex) {
96 .arg(ex.what());
97 return (1);
98 }
99 }
100
101 return (0);
102}
103
109 if (status == CalloutHandle::NEXT_STEP_DROP ||
111 return (0);
112 }
113
114 Pkt4Ptr query4;
115 Lease4Ptr lease4;
116 ParkingLotHandlePtr parking_lot;
117 try {
118 // Get all arguments available for the leases4_committed hook point.
119 // If any of these arguments is not available this is a programmatic
120 // error. An exception will be thrown which will be caught by the
121 // caller and logged.
122 handle.getArgument("query4", query4);
123
124 Lease4CollectionPtr leases4;
125 handle.getArgument("leases4", leases4);
126
127 uint32_t offer_lifetime;
128 handle.getArgument("offer_lifetime", offer_lifetime);
129
130 Lease4Ptr old_lease;
131 handle.getArgument("old_lease", old_lease);
132
133 ConstHostPtr host;
134 handle.getArgument("host", host);
135
136 if (query4->getType() != DHCPDISCOVER) {
137 isc_throw(InvalidOperation, "query4 is not a DHCPDISCOVER");
138 }
139
140 if (!leases4) {
141 isc_throw(InvalidOperation, "leases4 is null");
142 }
143
144 if (!leases4->empty()) {
145 lease4 = (*leases4)[0];
146 }
147
148 if (!lease4) {
149 isc_throw(InvalidOperation, "leases4 is empty, no lease to check");
150 }
151
152 // Fetch the parking lot. If it's empty the server is not employing
153 // parking, which is fine.
154 // Create a reference to the parked packet. This signals that we have a
155 // stake in unparking it.
156 parking_lot = handle.getParkingLotHandlePtr();
157 if (parking_lot) {
158 parking_lot->reference(query4);
159 }
160
161 // Get configuration based on the lease's subnet.
162 auto const& config = mgr->getScopedConfig(lease4);
163
164 // Call shouldPing() to determine if we should ping check or not.
165 // - status == PARK - ping check it
166 // - status == CONTINUE - check not needed, release DHCPOFFER to client
167 // - status == DROP - duplicate check, drop the duplicate DHCPOFFER
168 status = mgr->shouldPing(lease4, query4, old_lease, host, config);
169 handle.setStatus(status);
170 if (status == CalloutHandle::NEXT_STEP_PARK) {
171 mgr->startPing(lease4, query4, parking_lot, config);
172 } else {
173 // Dereference the parked packet. This releases our stake in it.
174 if (parking_lot) {
175 parking_lot->dereference(query4);
176 }
177 }
178
179 } catch (const std::exception& ex) {
181 .arg(query4 ? query4->getLabel() : "<no query>")
182 .arg(lease4 ? lease4->addr_.toText() : "<no lease>")
183 .arg(ex.what());
184 // Make sure we dereference.
185 if (parking_lot) {
186 parking_lot->dereference(query4);
187 }
188
189 return (1);
190 }
191
192 return (0);
193}
194
199int load(LibraryHandle& handle) {
200 try {
201 // Make the hook library only loadable by kea-dhcp4.
202 const string& proc_name = Daemon::getProcName();
203 if (proc_name != "kea-dhcp4") {
204 isc_throw(isc::Unexpected, "Bad process name: " << proc_name
205 << ", expected kea-dhcp4");
206 }
207
208 // Instantiate the manager singleton.
209 mgr.reset(new PingCheckMgr());
210
211 // Configure the manager using the hook library's parameters.
212 ConstElementPtr json = handle.getParameters();
213 mgr->configure(json);
214 } catch (const exception& ex) {
216 .arg(ex.what());
217 return (1);
218 }
219
221 return (0);
222}
223
227int unload() {
228 if (mgr) {
230 mgr.reset();
231 }
233 return (0);
234}
235
240 return (1);
241}
242
243} // end extern "C"
CalloutNextStep
Specifies allowed next steps.
@ NEXT_STEP_PARK
park the packet
@ NEXT_STEP_DROP
drop the packet
@ NEXT_STEP_SKIP
skip the next processing step
A generic exception that is thrown if a function is called in a prohibited way.
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
Per-packet callout handle.
@ NEXT_STEP_DROP
drop the packet
ParkingLotHandlePtr getParkingLotHandlePtr() const
Returns pointer to the parking lot handle for this hook point.
CalloutNextStep getStatus() const
Returns the next processing step.
void setStatus(const CalloutNextStep next)
Sets the next processing step.
void getArgument(const std::string &name, T &value) const
Get argument.
void setArgument(const std::string &name, T value)
Set argument.
isc::data::ConstElementPtr getParameters()
Get configuration parameter common code.
static std::string getProcName()
returns the process name This value is used as when forming the default PID file name
Definition daemon.cc:151
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
Definition macros.h:32
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
Definition macros.h:20
boost::shared_ptr< const Element > ConstElementPtr
Definition data.h:29
@ error
Definition db_log.h:118
boost::shared_ptr< AuditEntryCollection > AuditEntryCollectionPtr
boost::shared_ptr< Lease4Collection > Lease4CollectionPtr
A shared pointer to the collection of IPv4 leases.
Definition lease.h:523
boost::shared_ptr< Pkt4 > Pkt4Ptr
A pointer to Pkt4 object.
Definition pkt4.h:556
boost::shared_ptr< SrvConfig > SrvConfigPtr
Non-const pointer to the SrvConfig.
boost::shared_ptr< NetworkState > NetworkStatePtr
Pointer to the NetworkState object.
@ DHCPDISCOVER
Definition dhcp4.h:235
boost::shared_ptr< const Host > ConstHostPtr
Const pointer to the Host object.
Definition host.h:840
boost::shared_ptr< Lease4 > Lease4Ptr
Pointer to a Lease4 structure.
Definition lease.h:315
boost::shared_ptr< ParkingLotHandle > ParkingLotHandlePtr
Pointer to the parking lot handle.
PingCheckMgrPtr mgr
PingCheckMgr singleton.
isc::log::Logger ping_check_logger("ping-check-hooks")
boost::shared_ptr< PingCheckMgr > PingCheckMgrPtr
Defines a shared pointer to a PingCheckMgr.
Defines the logger used by the top-level component of kea-lfc.
int dhcp4_srv_configured(CalloutHandle &handle)
dhcp4_srv_configured implementation.
int multi_threading_compatible()
This function is called to retrieve the multi-threading compatibility.
int lease4_offer(CalloutHandle &handle)
lease4_offer callout implementation.
int unload()
This function is called when the library is unloaded.
int cb4_updated(CalloutHandle &handle)
cb4_updated callout implementation.
int load(LibraryHandle &handle)
This function is called when the library is loaded.
const isc::log::MessageID PING_CHECK_LOAD_ERROR
const isc::log::MessageID PING_CHECK_LEASE4_OFFER_FAILED
const isc::log::MessageID PING_CHECK_DHCP4_SRV_CONFIGURED_FAILED
const isc::log::MessageID PING_CHECK_CB4_UPDATE_FAILED
const isc::log::MessageID PING_CHECK_UNLOAD
const isc::log::MessageID PING_CHECK_LOAD_OK
Tag used to access index by object type.