Kea 3.3.1
pkt.cc
Go to the documentation of this file.
1// Copyright (C) 2014-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#include <utility>
9#include <dhcp/pkt.h>
10#include <dhcp/iface_mgr.h>
11#include <dhcp/hwaddr.h>
12#include <boost/foreach.hpp>
13#include <vector>
14
15using namespace boost::posix_time;
16
17namespace isc {
18namespace dhcp {
19
20const std::string PktEvent::SOCKET_RECEIVED("socket_received");
21const std::string PktEvent::BUFFER_READ("buffer_read");
22const std::string PktEvent::RESPONSE_SENT("response_sent");
23
24Pkt::Pkt(uint32_t transid, const isc::asiolink::IOAddress& local_addr,
25 const isc::asiolink::IOAddress& remote_addr, uint16_t local_port,
26 uint16_t remote_port)
27 : transid_(transid), iface_(""), ifindex_(UNSET_IFINDEX), local_addr_(local_addr),
28 remote_addr_(remote_addr), local_port_(local_port),
29 remote_port_(remote_port), buffer_out_(0), copy_retrieved_options_(false) {
30}
31
32Pkt::Pkt(const uint8_t* buf, uint32_t len, const isc::asiolink::IOAddress& local_addr,
33 const isc::asiolink::IOAddress& remote_addr, uint16_t local_port,
34 uint16_t remote_port)
35 : transid_(0), iface_(""), ifindex_(UNSET_IFINDEX), local_addr_(local_addr),
36 remote_addr_(remote_addr), local_port_(local_port),
37 remote_port_(remote_port), buffer_out_(0), copy_retrieved_options_(false) {
38 if (len != 0) {
39 if (buf == NULL) {
40 isc_throw(InvalidParameter, "data buffer passed to Pkt is NULL");
41 }
42 data_.resize(len);
43 memcpy(&data_[0], buf, len);
44 }
45}
46
49 OptionCollection options;
50 for (auto const& option : options_) {
51 options.emplace(std::make_pair(option.second->getType(), option.second->clone()));
52 }
53 return (options);
54}
55
56void
58 options_.insert(std::pair<int, OptionPtr>(opt->getType(), opt));
59}
60
62Pkt::getNonCopiedOption(const uint16_t type) const {
63 auto const& x = options_.find(type);
64 if (x != options_.end()) {
65 return (x->second);
66 }
67 return (OptionPtr());
68}
69
71Pkt::getOption(const uint16_t type) {
72 auto const& x = options_.find(type);
73 if (x != options_.end()) {
75 OptionPtr option_copy = x->second->clone();
76 x->second = option_copy;
77 }
78 return (x->second);
79 }
80 return (OptionPtr()); // NULL
81}
82
84Pkt::getNonCopiedOptions(const uint16_t opt_type) const {
85 std::pair<OptionCollection::const_iterator,
86 OptionCollection::const_iterator> range = options_.equal_range(opt_type);
87 return (OptionCollection(range.first, range.second));
88}
89
91Pkt::getOptions(const uint16_t opt_type) {
92 OptionCollection options_copy;
93
94 std::pair<OptionCollection::iterator,
95 OptionCollection::iterator> range = options_.equal_range(opt_type);
96 // If options should be copied on retrieval, we should now iterate over
97 // matching options, copy them and replace the original ones with new
98 // instances.
100 BOOST_FOREACH(auto& opt_it, range) {
101 OptionPtr option_copy = opt_it.second->clone();
102 opt_it.second = option_copy;
103 }
104 }
105 // Finally, return updated options. This can also be empty in some cases.
106 return (OptionCollection(range.first, range.second));
107}
108
109bool
110Pkt::delOption(uint16_t type) {
111 auto const& x = options_.find(type);
112 if (x != options_.end()) {
113 options_.erase(x);
114 return (true); // delete successful
115 } else {
116 return (false); // can't find option to be deleted
117 }
118}
119
120bool
121Pkt::inClass(const ClientClass& client_class) {
122 return (classes_.contains(client_class));
123}
124
125void
126Pkt::addClass(const ClientClass& client_class) {
127 if (!classes_.contains(client_class)) {
128 classes_.insert(client_class);
129 static_cast<void>(subclasses_.push_back(SubClassRelation(client_class, client_class)));
130 }
131}
132
133void
135 if (!additional_classes_.contains(client_class)) {
136 additional_classes_.insert(client_class);
137 // Since this list is pre-evaluation, we do not add subclass relationship.
138 }
139}
140
141void
142Pkt::addSubClass(const ClientClass& class_def, const ClientClass& subclass) {
143 if (!classes_.contains(subclass)) {
144 classes_.insert(subclass);
145 static_cast<void>(subclasses_.push_back(SubClassRelation(subclass, subclass)));
146 }
147 if (!classes_.contains(class_def)) {
148 classes_.insert(class_def);
149 static_cast<void>(subclasses_.push_back(SubClassRelation(class_def, subclass)));
150 }
151}
152
153void
154Pkt::copyClasses(const Pkt& other) {
155 for (auto const& cclass : other.classes_) {
156 if (!classes_.contains(cclass)) {
157 classes_.insert(cclass);
158 }
159 }
160}
161
162void
164 timestamp_ = boost::posix_time::microsec_clock::universal_time();
165}
166
168 if (!data_.empty()) {
169 buffer_out_.writeData(&data_[0], data_.size());
170 }
171}
172
173void
174Pkt::setRemoteHWAddr(const uint8_t htype, const uint8_t hlen,
175 const std::vector<uint8_t>& hw_addr) {
176 setHWAddrMember(htype, hlen, hw_addr, remote_hwaddr_);
177}
178
179void
181 if (!hw_addr) {
182 isc_throw(BadValue, "Setting remote HW address to NULL is"
183 << " forbidden.");
184 }
185 remote_hwaddr_ = hw_addr;
186}
187
188void
189Pkt::setHWAddrMember(const uint8_t htype, const uint8_t,
190 const std::vector<uint8_t>& hw_addr,
191 HWAddrPtr& storage) {
192 storage.reset(new HWAddr(hw_addr, htype));
193}
194
196Pkt::getMAC(uint32_t hw_addr_src) {
197 HWAddrPtr mac;
198
200
201 // Method 1: from raw sockets.
202 if (hw_addr_src & HWAddr::HWADDR_SOURCE_RAW) {
203 mac = getRemoteHWAddr();
204 if (mac) {
205 mac->source_ = HWAddr::HWADDR_SOURCE_RAW;
206 return (mac);
207 } else if (hw_addr_src == HWAddr::HWADDR_SOURCE_RAW) {
208 // If we're interested only in RAW sockets as source of that info,
209 // there's no point in trying other options.
210 return (HWAddrPtr());
211 }
212 }
213
214 // Method 2: From client link-layer address option inserted by a relay
217 if (mac) {
218 return (mac);
219 } else if (hw_addr_src == HWAddr::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION) {
220 // If we're interested only in RFC6939 link layer address as source
221 // of that info, there's no point in trying other options.
222 return (HWAddrPtr());
223 }
224 }
225
226 // Method 3: Extracted from DUID-LLT or DUID-LL
227 if(hw_addr_src & HWAddr::HWADDR_SOURCE_DUID) {
228 mac = getMACFromDUID();
229 if (mac) {
230 return (mac);
231 } else if (hw_addr_src == HWAddr::HWADDR_SOURCE_DUID) {
232 // If the only source allowed is DUID then we can skip the other
233 // methods.
234 return (HWAddrPtr());
235 }
236 }
237
238 // Method 4: Extracted from source IPv6 link-local address
239 if (hw_addr_src & HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL) {
241 if (mac) {
242 return (mac);
243 } else if (hw_addr_src == HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL) {
244 // If we're interested only in link-local addr as source of that
245 // info, there's no point in trying other options.
246 return (HWAddrPtr());
247 }
248 }
249
250 // Method 5: From remote-id option inserted by a relay
251 if(hw_addr_src & HWAddr::HWADDR_SOURCE_REMOTE_ID) {
253 if (mac) {
254 return (mac);
255 } else if (hw_addr_src == HWAddr::HWADDR_SOURCE_REMOTE_ID) {
256 // If the only source allowed is remote-id option then we can skip
257 // the other methods.
258 return (HWAddrPtr());
259 }
260 }
261
262 // Method 6: From subscriber-id option inserted by a relay
263
264 // Method 7: From docsis options
265 if (hw_addr_src & HWAddr::HWADDR_SOURCE_DOCSIS_CMTS) {
266 mac = getMACFromDocsisCMTS();
267 if (mac) {
268 return (mac);
269 } else if (hw_addr_src == HWAddr::HWADDR_SOURCE_DOCSIS_CMTS) {
270 // If we're interested only in CMTS options as a source of that
271 // info, there's no point in trying other options.
272 return (HWAddrPtr());
273 }
274 }
275
276 // Method 8: From docsis options
277 if (hw_addr_src & HWAddr::HWADDR_SOURCE_DOCSIS_MODEM) {
278 mac = getMACFromDocsisModem();
279 if (mac) {
280 return (mac);
281 } else if (hw_addr_src == HWAddr::HWADDR_SOURCE_DOCSIS_MODEM) {
282 // If we're interested only in CMTS options as a source of that
283 // info, there's no point in trying other options.
284 return (HWAddrPtr());
285 }
286 }
287
288 // Ok, none of the methods were suitable. Return NULL.
289 return (HWAddrPtr());
290}
291
294 HWAddrPtr mac;
295
296 if (addr.isV6LinkLocal()) {
297 std::vector<uint8_t> bin = addr.toBytes();
298
299 // Double check that it's of appropriate size
300 if ((bin.size() == isc::asiolink::V6ADDRESS_LEN) &&
301 // Check that it's link-local (starts with fe80).
302 (bin[0] == 0xfe) && (bin[1] == 0x80) &&
303 // Check that u bit is set and g is clear.
304 // See Section 2.5.1 of RFC2373 for details.
305 ((bin[8] & 3) == 2) &&
306 // And that the IID is of EUI-64 type.
307 (bin[11] == 0xff) && (bin[12] == 0xfe)) {
308
309 // Remove 8 most significant bytes
310 bin.erase(bin.begin(), bin.begin() + 8);
311
312 // Ok, we're down to EUI-64 only now: XX:XX:XX:ff:fe:XX:XX:XX
313 bin.erase(bin.begin() + 3, bin.begin() + 5);
314
315 // MAC-48 to EUI-64 involves inverting u bit (see explanation
316 // in Section 2.5.1 of RFC2373). We need to revert that.
317 bin[0] = bin[0] ^ 2;
318
319 // Let's get the interface this packet was received on.
320 // We need it to get hardware type
322 uint16_t hwtype = 0; // not specified
323 if (iface) {
324 hwtype = iface->getHWType();
325 }
326
327 mac.reset(new HWAddr(bin, hwtype));
329 }
330 }
331
332 return (mac);
333}
334
335
336void
337Pkt::addPktEvent(const std::string& label, const boost::posix_time::ptime& timestamp) {
338 events_.push_back(PktEvent(label, timestamp));
339}
340
341void
342Pkt::setPktEvent(const std::string& label, const ptime& timestamp) {
343 for (auto& event : events_) {
344 if (event.label_ == label) {
345 event.timestamp_ = timestamp;
346 return;
347 }
348 }
349
350 events_.push_back(PktEvent(label, timestamp));
351}
352
353void
354Pkt::addPktEvent(const std::string& label, const struct timeval& tv) {
355 time_t time_t_secs = tv.tv_sec;
356 ptime timestamp = from_time_t(time_t_secs);
357 time_duration usecs(0, 0, 0, tv.tv_usec);
358 timestamp += usecs;
359 addPktEvent(label, timestamp);
360}
361
362ptime
363Pkt::getPktEventTime(const std::string& label) const {
364 for (auto const& event : events_) {
365 if (event.label_ == label) {
366 return (event.timestamp_);
367 }
368 }
369
370 return (PktEvent::EMPTY_TIME());
371}
372
373void
375 events_.clear();
376}
377
378std::string
379Pkt::dumpPktEvents(bool verbose /* = false */) const {
380 std::stringstream oss;
381 if (verbose) {
382 oss << "Event log: " << std::endl;
383 }
384
385 bool first_pass = true;
386 boost::posix_time::ptime beg_time;
387 boost::posix_time::ptime prev_time;
388 for (auto const& event : events_) {
389 if (!verbose) {
390 oss << (first_pass ? "" : ", ") << event.timestamp_ << " : " << event.label_;
391 } else {
392 oss << event.timestamp_ << " : " << event.label_;
393 if (first_pass) {
394 oss << std::endl;
395 beg_time = event.timestamp_;
396 } else {
397 oss << " elapsed: " << event.timestamp_ - prev_time << std::endl;
398 }
399
400 prev_time = event.timestamp_;
401 }
402
403 first_pass = false;
404 }
405
406 if (verbose) {
407 oss << "total elapsed: " << prev_time - beg_time;
408 }
409
410 return (oss.str());
411}
412
413} // end of namespace isc::dhcp
414} // end of namespace isc
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 if a parameter given to a method or function is considered invalid...
IfacePtr getIface(const unsigned int ifindex)
Returns interface specified interface index.
Definition iface_mgr.cc:937
static IfaceMgr & instance()
IfaceMgr is a singleton class.
Definition iface_mgr.cc:52
Describes an event during the life cycle of a packet.
Definition pkt.h:89
static const std::string BUFFER_READ
Event that marks when a packet is read from the socket buffer by application.
Definition pkt.h:97
static const std::string SOCKET_RECEIVED
Event that marks when a packet is placed in the socket buffer by the kernel.
Definition pkt.h:93
static const std::string RESPONSE_SENT
Event that marks when a packet is been written to the socket by application.
Definition pkt.h:101
static boost::posix_time::ptime & EMPTY_TIME()
Fetch an empty timestamp, used for logic comparisons.
Definition pkt.h:124
bool delOption(uint16_t type)
Attempts to delete first suboption of requested type.
Definition pkt.cc:110
virtual HWAddrPtr getMACFromDocsisModem()=0
Attempts to extract MAC/Hardware address from DOCSIS options inserted by the modem itself.
isc::dhcp::OptionCollection getOptions(const uint16_t type)
Returns all instances of specified type.
Definition pkt.cc:91
isc::asiolink::IOAddress remote_addr_
Remote IP address.
Definition pkt.h:953
virtual HWAddrPtr getMACFromDocsisCMTS()=0
Attempts to extract MAC/Hardware address from DOCSIS options inserted by the CMTS (the relay agent).
void addClass(const isc::dhcp::ClientClass &client_class)
Adds a specified class to the packet.
Definition pkt.cc:126
uint16_t local_port_
local TDP or UDP port
Definition pkt.h:956
uint32_t transid_
Transaction-id (32 bits for v4, 24 bits for v6).
Definition pkt.h:931
void addAdditionalClass(const isc::dhcp::ClientClass &client_class)
Adds a specified class to the packet's additional class list.
Definition pkt.cc:134
void repack()
Copies content of input buffer to output buffer.
Definition pkt.cc:167
isc::asiolink::IOAddress local_addr_
Local IP (v4 or v6) address.
Definition pkt.h:947
virtual HWAddrPtr getMACFromRemoteIdRelayOption()=0
Attempts to obtain MAC address from remote-id relay option.
OptionBuffer data_
Unparsed data (in received packets).
Definition pkt.h:421
HWAddrPtr getRemoteHWAddr() const
Returns the remote HW address obtained from raw sockets.
Definition pkt.h:750
virtual HWAddrPtr getMACFromSrcLinkLocalAddr()=0
Attempts to obtain MAC address from source link-local IPv6 address.
ClientClasses classes_
Classes this packet belongs to.
Definition pkt.h:787
void setPktEvent(const std::string &label, const boost::posix_time::ptime &timestamp=PktEvent::now())
Updates (or adds) an event in the event stack.
Definition pkt.cc:342
virtual size_t len()=0
Returns packet size in binary format.
uint16_t remote_port_
remote TCP or UDP port
Definition pkt.h:959
HWAddrPtr remote_hwaddr_
Definition pkt.h:981
isc::dhcp::OptionCollection options_
Collection of options present in this message.
Definition pkt.h:819
isc::util::OutputBuffer buffer_out_
Output buffer (used during message transmission).
Definition pkt.h:969
virtual HWAddrPtr getMACFromDUID()=0
Attempts to obtain MAC address from DUID-LL or DUID-LLT.
SubClassRelationContainer subclasses_
SubClasses this packet belongs to.
Definition pkt.h:809
void addPktEvent(const std::string &label, const boost::posix_time::ptime &timestamp=PktEvent::now())
Adds an event to the end of the event stack.
Definition pkt.cc:337
void clearPktEvents()
Discards contents of the packet event stack.
Definition pkt.cc:374
void copyClasses(const Pkt &other)
Simple copy of classes from another packet.
Definition pkt.cc:154
OptionCollection getNonCopiedOptions(const uint16_t opt_type) const
Returns all option instances of specified type without copying.
Definition pkt.cc:84
Pkt(uint32_t transid, const isc::asiolink::IOAddress &local_addr, const isc::asiolink::IOAddress &remote_addr, uint16_t local_port, uint16_t remote_port)
Constructor.
Definition pkt.cc:24
boost::posix_time::ptime getPktEventTime(const std::string &label) const
Fetches the timestamp for a given event in the stack.
Definition pkt.cc:363
OptionCollection cloneOptions()
Clones all options so that they can be safely modified.
Definition pkt.cc:48
OptionPtr getOption(const uint16_t type)
Returns the first option of specified type.
Definition pkt.cc:71
void setRemoteHWAddr(const HWAddrPtr &hw_addr)
Sets remote hardware address.
Definition pkt.cc:180
void addSubClass(const isc::dhcp::ClientClass &class_def, const isc::dhcp::ClientClass &subclass)
Adds a specified subclass to the packet.
Definition pkt.cc:142
bool inClass(const isc::dhcp::ClientClass &client_class)
Checks whether a client belongs to a given class.
Definition pkt.cc:121
virtual HWAddrPtr getMACFromIPv6RelayOpt()=0
Attempts to obtain MAC address from relay option client-linklayer-addr.
unsigned int ifindex_
Interface index.
Definition pkt.h:941
boost::posix_time::ptime timestamp_
packet timestamp
Definition pkt.h:978
HWAddrPtr getMAC(uint32_t hw_addr_src)
Returns MAC address.
Definition pkt.cc:196
ClientClasses additional_classes_
Classes to be evaluated during additional class evaluation.
Definition pkt.h:801
void updateTimestamp()
Update packet timestamp.
Definition pkt.cc:163
bool copy_retrieved_options_
Indicates if a copy of the retrieved option should be returned when Pkt::getOption is called.
Definition pkt.h:975
std::string iface_
Name of the network interface the packet was received/to be sent over.
Definition pkt.h:934
std::string dumpPktEvents(bool verbose=false) const
Creates a dump of the stack contents to a string for logging.
Definition pkt.cc:379
OptionPtr getNonCopiedOption(const uint16_t type) const
Returns the first option of specified type without copying.
Definition pkt.cc:62
HWAddrPtr getMACFromIPv6(const isc::asiolink::IOAddress &addr)
Attempts to convert IPv6 address into MAC.
Definition pkt.cc:293
virtual void addOption(const OptionPtr &opt)
Adds an option to this packet.
Definition pkt.cc:57
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
static const uint32_t HWADDR_SOURCE_RAW
Obtained first hand from raw socket (100% reliable).
Definition hwaddr.h:44
static const uint32_t HWADDR_SOURCE_REMOTE_ID
A relay can insert remote-id.
Definition hwaddr.h:63
static const uint32_t HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION
Get it from RFC6939 option.
Definition hwaddr.h:59
static const uint32_t HWADDR_SOURCE_IPV6_LINK_LOCAL
Extracted from IPv6 link-local address.
Definition hwaddr.h:53
static const uint32_t HWADDR_SOURCE_DOCSIS_MODEM
A cable modem (acting as DHCP client) that supports DOCSIS standard can insert DOCSIS options that co...
Definition hwaddr.h:79
static const uint32_t HWADDR_SOURCE_DUID
Extracted from DUID-LL or DUID-LLT (not 100% reliable as the client can send fake DUID).
Definition hwaddr.h:48
static const uint32_t HWADDR_SOURCE_DOCSIS_CMTS
A CMTS (acting as DHCP relay agent) that supports DOCSIS standard can insert DOCSIS options that cont...
Definition hwaddr.h:73
std::string ClientClass
Defines a single class name.
Definition classify.h:45
boost::shared_ptr< Iface > IfacePtr
Type definition for the pointer to an Iface object.
Definition iface_mgr.h:555
std::multimap< unsigned int, OptionPtr > OptionCollection
A collection of DHCP (v4 or v6) options.
Definition option.h:40
boost::shared_ptr< HWAddr > HWAddrPtr
Shared pointer to a hardware address structure.
Definition hwaddr.h:154
constexpr unsigned int UNSET_IFINDEX
A value used to signal that the interface index was not set.
Definition pkt.h:30
boost::shared_ptr< Option > OptionPtr
Definition option.h:37
Defines the logger used by the top-level component of kea-lfc.
Hardware type that represents information from DHCPv4 packet.
Definition hwaddr.h:20
Defines a subclass to template class relation.
Definition classify.h:70