Kea 2.2.0
bootp_callouts.cc
Go to the documentation of this file.
1// Copyright (C) 2019-2020 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 <stats/stats_mgr.h>
13
14#include <vector>
15
16using namespace isc;
17using namespace isc::bootp;
18using namespace isc::dhcp;
19using namespace isc::hooks;
20using namespace isc::log;
21using namespace isc::stats;
22
23namespace {
24
25// DHCP Specific options listed in RFC 1533 section 9 and with a code name
26// beginning by DHO_DHCP_.
27const std::vector<uint16_t> DHCP_SPECIFIC_OPTIONS = {
39};
40
41// Size of the BOOTP space for vendor extensions.
42const size_t BOOT_VENDOR_SPACE_SIZE = 64;
43
44// Minimum size of a BOOTP message.
45const size_t BOOT_MIN_SIZE = Pkt4::DHCPV4_PKT_HDR_LEN + BOOT_VENDOR_SPACE_SIZE;
46
47// Check as compile time it is really 300!
48static_assert(BOOT_MIN_SIZE == 300, "BOOT_MIN_SIZE is not 300");
49
50} // end of anonymous namespace.
51
52// Functions accessed by the hooks framework use C linkage to avoid the name
53// mangling that accompanies use of the C++ compiler as well as to avoid
54// issues related to namespaces.
55extern "C" {
56
68 if (status == CalloutHandle::NEXT_STEP_DROP) {
69 return (0);
70 }
71
72 // Get the received unpacked message.
73 Pkt4Ptr query;
74 handle.getArgument("query4", query);
75
76 try {
77 if (handle.getStatus() != CalloutHandle::NEXT_STEP_SKIP) {
78 query->unpack();
79 }
80
81 // Not DHCP query nor BOOTP response?
82 if ((query->getType() == DHCP_NOTYPE) &&
83 (query->getOp() == BOOTREQUEST)) {
84
85 query->addClass("BOOTP");
86 query->setType(DHCPREQUEST);
87
89 .arg(query->getLabel());
90 }
91 } catch (const SkipRemainingOptionsError& ex) {
92 // An option failed to unpack but we are to attempt to process it
93 // anyway. Log it and let's hope for the best.
96 .arg(ex.what());
97 } catch (const std::exception& ex) {
98 // Failed to parse the packet.
101 .arg(query->getRemoteAddr().toText())
102 .arg(query->getLocalAddr().toText())
103 .arg(query->getIface())
104 .arg(ex.what());
105
106 // Increase the statistics of parse failures and dropped packets.
107 StatsMgr::instance().addValue("pkt4-parse-failed",
108 static_cast<int64_t>(1));
109 StatsMgr::instance().addValue("pkt4-receive-drop",
110 static_cast<int64_t>(1));
111
112 handle.setStatus(CalloutHandle::NEXT_STEP_DROP);
113
114 return (0);
115 }
116
117 // Avoid to unpack it a second time!
118 handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
119
120 return (0);
121}
122
132 if (status == CalloutHandle::NEXT_STEP_DROP) {
133 return (0);
134 }
135
136 // Get the query message.
137 Pkt4Ptr query;
138 handle.getArgument("query4", query);
139
140 // Check if it is a BOOTP query.
141 if (!query->inClass("BOOTP")) {
142 return (0);
143 }
144
145 // Get the response message.
146 Pkt4Ptr response;
147 handle.getArgument("response4", response);
148
149 if (status == CalloutHandle::NEXT_STEP_SKIP) {
150 isc_throw(InvalidOperation, "packet pack already handled");
151 }
152
153 for (uint16_t code : DHCP_SPECIFIC_OPTIONS) {
154 while (response->delOption(code))
155 ;
156 }
157
158 // Pack the response.
159 try {
161 .arg(response->getLabel());
162 response->pack();
163
164 // The pack method adds a DHO_END option at the end.
165 isc::util::OutputBuffer& buffer = response->getBuffer();
166 size_t size = buffer.getLength();
167 if (size < BOOT_MIN_SIZE) {
168 size_t delta = BOOT_MIN_SIZE - size;
169 std::vector<uint8_t> zeros(delta, 0);
170 buffer.writeData(&zeros[0], delta);
171 }
172 } catch (const std::exception& ex) {
174 .arg(response->getLabel())
175 .arg(ex.what());
176 }
177
178 // Avoid to pack it a second time!
179 handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
180
181 return (0);
182}
183
187int load(LibraryHandle& /* handle */) {
189 return (0);
190}
191
195int unload() {
197 return (0);
198}
199
204 return (1);
205}
206
207} // 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.
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.
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.
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
Definition: buffer.h:294
void writeData(const void *data, size_t len)
Copy an arbitrary length of data into the buffer.
Definition: buffer.h:550
size_t getLength() const
Return the length of data written in the buffer.
Definition: buffer.h:403
#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
#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:544
@ BOOTREQUEST
Definition: dhcp4.h:46
@ DHCPREQUEST
Definition: dhcp4.h:236
@ DHCP_NOTYPE
Message Type option missing.
Definition: dhcp4.h:233
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.