Kea 2.5.8
bootp_callouts.cc
Go to the documentation of this file.
1// Copyright (C) 2019-2022 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
8
9#include <bootp_log.h>
10#include <hooks/hooks.h>
11#include <dhcp/pkt4.h>
12#include <process/daemon.h>
13#include <stats/stats_mgr.h>
14
15#include <vector>
16
17using namespace isc;
18using namespace isc::bootp;
19using namespace isc::dhcp;
20using namespace isc::hooks;
21using namespace isc::log;
22using namespace isc::process;
23using namespace isc::stats;
24
25namespace {
26
27// DHCP Specific options listed in RFC 1533 section 9 and with a code name
28// beginning by DHO_DHCP_.
29const std::vector<uint16_t> DHCP_SPECIFIC_OPTIONS = {
41};
42
43// Size of the BOOTP space for vendor extensions.
44const size_t BOOT_VENDOR_SPACE_SIZE = 64;
45
46// Minimum size of a BOOTP message.
47const size_t BOOT_MIN_SIZE = Pkt4::DHCPV4_PKT_HDR_LEN + BOOT_VENDOR_SPACE_SIZE;
48
49// Check as compile time it is really 300!
50static_assert(BOOT_MIN_SIZE == 300, "BOOT_MIN_SIZE is not 300");
51
52} // end of anonymous namespace.
53
54// Functions accessed by the hooks framework use C linkage to avoid the name
55// mangling that accompanies use of the C++ compiler as well as to avoid
56// issues related to namespaces.
57extern "C" {
58
70 if (status == CalloutHandle::NEXT_STEP_DROP) {
71 return (0);
72 }
73
74 // Get the received unpacked message.
75 Pkt4Ptr query;
76 handle.getArgument("query4", query);
77
78 try {
80 query->unpack();
81 }
82
83 // Not DHCP query nor BOOTP response?
84 if ((query->getType() == DHCP_NOTYPE) &&
85 (query->getOp() == BOOTREQUEST)) {
86
87 query->addClass("BOOTP");
88 query->setType(DHCPREQUEST);
89
91 .arg(query->getLabel());
92 }
93 } catch (const SkipRemainingOptionsError& ex) {
94 // An option failed to unpack but we are to attempt to process it
95 // anyway. Log it and let's hope for the best.
98 .arg(ex.what());
99 } catch (const std::exception& ex) {
100 // Failed to parse the packet.
103 .arg(query->getRemoteAddr().toText())
104 .arg(query->getLocalAddr().toText())
105 .arg(query->getIface())
106 .arg(ex.what());
107
108 // Increase the statistics of parse failures and dropped packets.
109 StatsMgr::instance().addValue("pkt4-parse-failed",
110 static_cast<int64_t>(1));
111 StatsMgr::instance().addValue("pkt4-receive-drop",
112 static_cast<int64_t>(1));
113
115
116 return (0);
117 }
118
119 // Avoid to unpack it a second time!
121
122 return (0);
123}
124
134 if (status == CalloutHandle::NEXT_STEP_DROP) {
135 return (0);
136 }
137
138 // Get the query message.
139 Pkt4Ptr query;
140 handle.getArgument("query4", query);
141
142 // Check if it is a BOOTP query.
143 if (!query->inClass("BOOTP")) {
144 return (0);
145 }
146
147 // Get the response message.
148 Pkt4Ptr response;
149 handle.getArgument("response4", response);
150
151 if (status == CalloutHandle::NEXT_STEP_SKIP) {
152 isc_throw(InvalidOperation, "packet pack already handled");
153 }
154
155 for (uint16_t code : DHCP_SPECIFIC_OPTIONS) {
156 while (response->delOption(code))
157 ;
158 }
159
160 // Pack the response.
161 try {
163 .arg(response->getLabel());
164 response->pack();
165
166 // The pack method adds a DHO_END option at the end.
167 isc::util::OutputBuffer& buffer = response->getBuffer();
168 size_t size = buffer.getLength();
169 if (size < BOOT_MIN_SIZE) {
170 size_t delta = BOOT_MIN_SIZE - size;
171 std::vector<uint8_t> zeros(delta, 0);
172 buffer.writeData(&zeros[0], delta);
173 }
174 } catch (const std::exception& ex) {
176 .arg(response->getLabel())
177 .arg(ex.what());
178 }
179
180 // Avoid to pack it a second time!
182
183 return (0);
184}
185
189int load(LibraryHandle& /* handle */) {
190 const std::string& proc_name = Daemon::getProcName();
191 if (proc_name != "kea-dhcp4") {
192 isc_throw(isc::Unexpected, "Bad process name: " << proc_name
193 << ", expected kea-dhcp4");
194 }
196 return (0);
197}
198
202int unload() {
204 return (0);
205}
206
211 return (1);
212}
213
214} // end extern "C"
int load(LibraryHandle &)
This function is called when the library is loaded.
int multi_threading_compatible()
This function is called to retrieve the multi-threading compatibility.
int pkt4_send(CalloutHandle &handle)
This callout is called at the "pkt4_send" hook.
int unload()
This function is called when the library is unloaded.
int buffer4_receive(CalloutHandle &handle)
This callout is called at the "buffer4_receive" hook.
const isc::log::MessageID BOOTP_LOAD
const isc::log::MessageID BOOTP_PACKET_UNPACK_FAILED
const isc::log::MessageID BOOTP_PACKET_PACK
const isc::log::MessageID BOOTP_UNLOAD
const isc::log::MessageID BOOTP_PACKET_OPTIONS_SKIPPED
const isc::log::MessageID BOOTP_BOOTP_QUERY
const isc::log::MessageID BOOTP_PACKET_PACK_FAIL
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
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 const size_t DHCPV4_PKT_HDR_LEN
specifies DHCPv4 packet header length (fixed part)
Definition: pkt4.h:50
Exception thrown during option unpacking This exception is thrown when an error has occurred,...
Definition: option.h:52
Per-packet callout handle.
CalloutNextStep
Specifies allowed next steps.
@ NEXT_STEP_DROP
drop the packet
@ NEXT_STEP_SKIP
skip the next processing step
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.
static std::string getProcName()
returns the process name This value is used as when forming the default PID file name
Definition: daemon.cc:129
static StatsMgr & instance()
Statistics Manager accessor method.
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
Definition: buffer.h:347
void writeData(const void *data, size_t len)
Copy an arbitrary length of data into the buffer.
Definition: buffer.h:556
size_t getLength() const
Return the length of data written in the buffer.
Definition: buffer.h:412
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
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_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
Definition: macros.h:20
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition: macros.h:14
isc::log::Logger bootp_logger("bootp-hooks")
Definition: bootp_log.h:18
@ DHO_DHCP_MAX_MESSAGE_SIZE
Definition: dhcp4.h:126
@ DHO_DHCP_MESSAGE
Definition: dhcp4.h:125
@ DHO_DHCP_REBINDING_TIME
Definition: dhcp4.h:128
@ DHO_DHCP_MESSAGE_TYPE
Definition: dhcp4.h:122
@ DHO_DHCP_SERVER_IDENTIFIER
Definition: dhcp4.h:123
@ DHO_DHCP_CLIENT_IDENTIFIER
Definition: dhcp4.h:130
@ DHO_DHCP_REQUESTED_ADDRESS
Definition: dhcp4.h:119
@ DHO_DHCP_OPTION_OVERLOAD
Definition: dhcp4.h:121
@ DHO_DHCP_PARAMETER_REQUEST_LIST
Definition: dhcp4.h:124
@ DHO_DHCP_RENEWAL_TIME
Definition: dhcp4.h:127
@ DHO_DHCP_LEASE_TIME
Definition: dhcp4.h:120
boost::shared_ptr< Pkt4 > Pkt4Ptr
A pointer to Pkt4 object.
Definition: pkt4.h:555
@ BOOTREQUEST
Definition: dhcp4.h:46
@ DHCPREQUEST
Definition: dhcp4.h:238
@ DHCP_NOTYPE
Message Type option missing.
Definition: dhcp4.h:235
const int DBGLVL_TRACE_BASIC
Trace basic operations.
Definition: log_dbglevels.h:69
Defines the logger used by the top-level component of kea-lfc.