Kea  1.9.9-git
pkt.cc
Go to the documentation of this file.
1 // Copyright (C) 2014-2019 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 <vector>
13 
14 namespace isc {
15 namespace dhcp {
16 
17 Pkt::Pkt(uint32_t transid, const isc::asiolink::IOAddress& local_addr,
18  const isc::asiolink::IOAddress& remote_addr, uint16_t local_port,
19  uint16_t remote_port)
20  :transid_(transid),
21  iface_(""),
22  ifindex_(-1),
23  local_addr_(local_addr),
24  remote_addr_(remote_addr),
25  local_port_(local_port),
26  remote_port_(remote_port),
27  buffer_out_(0),
28  copy_retrieved_options_(false)
29 {
30 }
31 
32 Pkt::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),
36  iface_(""),
37  ifindex_(-1),
38  local_addr_(local_addr),
39  remote_addr_(remote_addr),
40  local_port_(local_port),
41  remote_port_(remote_port),
42  buffer_out_(0),
43  copy_retrieved_options_(false)
44 {
45 
46  if (len != 0) {
47  if (buf == NULL) {
48  isc_throw(InvalidParameter, "data buffer passed to Pkt is NULL");
49  }
50  data_.resize(len);
51  memcpy(&data_[0], buf, len);
52  }
53 }
54 
55 void
57  options_.insert(std::pair<int, OptionPtr>(opt->getType(), opt));
58 }
59 
61 Pkt::getNonCopiedOption(const uint16_t type) const {
62  OptionCollection::const_iterator x = options_.find(type);
63  if (x != options_.end()) {
64  return (x->second);
65  }
66  return (OptionPtr());
67 }
68 
70 Pkt::getOption(const uint16_t type) {
71  OptionCollection::iterator x = options_.find(type);
72  if (x != options_.end()) {
74  OptionPtr option_copy = x->second->clone();
75  x->second = option_copy;
76  }
77  return (x->second);
78  }
79  return (OptionPtr()); // NULL
80 }
81 
82 bool
83 Pkt::delOption(uint16_t type) {
84 
85  isc::dhcp::OptionCollection::iterator x = options_.find(type);
86  if (x!=options_.end()) {
87  options_.erase(x);
88  return (true); // delete successful
89  } else {
90  return (false); // can't find option to be deleted
91  }
92 }
93 
94 bool
95 Pkt::inClass(const std::string& client_class) {
96  return (classes_.contains(client_class));
97 }
98 
99 void
100 Pkt::addClass(const std::string& client_class, bool required) {
101  // Always have ALL first.
102  if (classes_.empty()) {
103  classes_.insert("ALL");
104  }
105  ClientClasses& classes = !required ? classes_ : required_classes_;
106  if (!classes.contains(client_class)) {
107  classes.insert(client_class);
108  }
109 }
110 
111 void
113  timestamp_ = boost::posix_time::microsec_clock::universal_time();
114 }
115 
116 void Pkt::repack() {
117  if (!data_.empty()) {
118  buffer_out_.writeData(&data_[0], data_.size());
119  }
120 }
121 
122 void
123 Pkt::setRemoteHWAddr(const uint8_t htype, const uint8_t hlen,
124  const std::vector<uint8_t>& hw_addr) {
125  setHWAddrMember(htype, hlen, hw_addr, remote_hwaddr_);
126 }
127 
128 void
130  if (!hw_addr) {
131  isc_throw(BadValue, "Setting remote HW address to NULL is"
132  << " forbidden.");
133  }
134  remote_hwaddr_ = hw_addr;
135 }
136 
137 void
138 Pkt::setHWAddrMember(const uint8_t htype, const uint8_t,
139  const std::vector<uint8_t>& hw_addr,
140  HWAddrPtr& storage) {
141 
142  storage.reset(new HWAddr(hw_addr, htype));
143 }
144 
145 HWAddrPtr
146 Pkt::getMAC(uint32_t hw_addr_src) {
147  HWAddrPtr mac;
148 
150 
151  // Method 1: from raw sockets.
152  if (hw_addr_src & HWAddr::HWADDR_SOURCE_RAW) {
153  mac = getRemoteHWAddr();
154  if (mac) {
155  mac->source_ = HWAddr::HWADDR_SOURCE_RAW;
156  return (mac);
157  } else if (hw_addr_src == HWAddr::HWADDR_SOURCE_RAW) {
158  // If we're interested only in RAW sockets as source of that info,
159  // there's no point in trying other options.
160  return (HWAddrPtr());
161  }
162  }
163 
164  // Method 2: From client link-layer address option inserted by a relay
166  mac = getMACFromIPv6RelayOpt();
167  if (mac) {
168  return (mac);
169  } else if (hw_addr_src == HWAddr::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION) {
170  // If we're interested only in RFC6939 link layer address as source
171  // of that info, there's no point in trying other options.
172  return (HWAddrPtr());
173  }
174  }
175 
176  // Method 3: Extracted from DUID-LLT or DUID-LL
177  if(hw_addr_src & HWAddr::HWADDR_SOURCE_DUID) {
178  mac = getMACFromDUID();
179  if (mac) {
180  return (mac);
181  } else if (hw_addr_src == HWAddr::HWADDR_SOURCE_DUID) {
182  // If the only source allowed is DUID then we can skip the other
183  // methods.
184  return (HWAddrPtr());
185  }
186  }
187 
188  // Method 4: Extracted from source IPv6 link-local address
189  if (hw_addr_src & HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL) {
191  if (mac) {
192  return (mac);
193  } else if (hw_addr_src == HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL) {
194  // If we're interested only in link-local addr as source of that
195  // info, there's no point in trying other options.
196  return (HWAddrPtr());
197  }
198  }
199 
200  // Method 5: From remote-id option inserted by a relay
201  if(hw_addr_src & HWAddr::HWADDR_SOURCE_REMOTE_ID) {
203  if (mac) {
204  return (mac);
205  } else if (hw_addr_src == HWAddr::HWADDR_SOURCE_REMOTE_ID) {
206  // If the only source allowed is remote-id option then we can skip
207  // the other methods.
208  return (HWAddrPtr());
209  }
210  }
211 
212  // Method 6: From subscriber-id option inserted by a relay
213 
214  // Method 7: From docsis options
215  if (hw_addr_src & HWAddr::HWADDR_SOURCE_DOCSIS_CMTS) {
216  mac = getMACFromDocsisCMTS();
217  if (mac) {
218  return (mac);
219  } else if (hw_addr_src == HWAddr::HWADDR_SOURCE_DOCSIS_CMTS) {
220  // If we're interested only in CMTS options as a source of that
221  // info, there's no point in trying other options.
222  return (HWAddrPtr());
223  }
224  }
225 
226  // Method 8: From docsis options
227  if (hw_addr_src & HWAddr::HWADDR_SOURCE_DOCSIS_MODEM) {
228  mac = getMACFromDocsisModem();
229  if (mac) {
230  return (mac);
231  } else if (hw_addr_src == HWAddr::HWADDR_SOURCE_DOCSIS_MODEM) {
232  // If we're interested only in CMTS options as a source of that
233  // info, there's no point in trying other options.
234  return (HWAddrPtr());
235  }
236  }
237 
238  // Ok, none of the methods were suitable. Return NULL.
239  return (HWAddrPtr());
240 }
241 
242 HWAddrPtr
244  HWAddrPtr mac;
245 
246  if (addr.isV6LinkLocal()) {
247  std::vector<uint8_t> bin = addr.toBytes();
248 
249  // Double check that it's of appropriate size
250  if ((bin.size() == isc::asiolink::V6ADDRESS_LEN) &&
251  // Check that it's link-local (starts with fe80).
252  (bin[0] == 0xfe) && (bin[1] == 0x80) &&
253  // Check that u bit is set and g is clear.
254  // See Section 2.5.1 of RFC2373 for details.
255  ((bin[8] & 3) == 2) &&
256  // And that the IID is of EUI-64 type.
257  (bin[11] == 0xff) && (bin[12] == 0xfe)) {
258 
259  // Remove 8 most significant bytes
260  bin.erase(bin.begin(), bin.begin() + 8);
261 
262  // Ok, we're down to EUI-64 only now: XX:XX:XX:ff:fe:XX:XX:XX
263  bin.erase(bin.begin() + 3, bin.begin() + 5);
264 
265  // MAC-48 to EUI-64 involves inverting u bit (see explanation
266  // in Section 2.5.1 of RFC2373). We need to revert that.
267  bin[0] = bin[0] ^ 2;
268 
269  // Let's get the interface this packet was received on.
270  // We need it to get hardware type
272  uint16_t hwtype = 0; // not specified
273  if (iface) {
274  hwtype = iface->getHWType();
275  }
276 
277  mac.reset(new HWAddr(bin, hwtype));
279  }
280  }
281 
282  return (mac);
283 }
284 
285 };
286 };
virtual HWAddrPtr getMACFromRemoteIdRelayOption()=0
Attempts to obtain MAC address from remote-id relay option.
IfacePtr getIface(int ifindex)
Returns interface specified interface index.
Definition: iface_mgr.cc:875
HWAddrPtr getMACFromIPv6(const isc::asiolink::IOAddress &addr)
Attempts to convert IPv6 address into MAC.
Definition: pkt.cc:243
OptionBuffer data_
Unparsed data (in received packets).
Definition: pkt.h:312
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:17
std::string iface_
Name of the network interface the packet was received/to be sent over.
Definition: pkt.h:729
bool inClass(const isc::dhcp::ClientClass &client_class)
Checks whether a client belongs to a given class.
Definition: pkt.cc:95
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
A generic exception that is thrown if a parameter given to a method or function is considered invalid...
boost::shared_ptr< HWAddr > HWAddrPtr
Shared pointer to a hardware address structure.
Definition: hwaddr.h:154
boost::shared_ptr< Iface > IfacePtr
Type definition for the pointer to an Iface object.
Definition: iface_mgr.h:463
boost::shared_ptr< Option > OptionPtr
Definition: option.h:36
virtual HWAddrPtr getMACFromDocsisModem()=0
Attempts to extract MAC/Hardware address from DOCSIS options inserted by the modem itself...
virtual void addOption(const OptionPtr &opt)
Adds an option to this packet.
Definition: pkt.cc:56
OptionPtr getNonCopiedOption(const uint16_t type) const
Returns the first option of specified type without copying.
Definition: pkt.cc:61
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
void writeData(const void *data, size_t len)
Copy an arbitrary length of data into the buffer.
Definition: buffer.h:550
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
ClientClasses classes_
Classes this packet belongs to.
Definition: pkt.h:596
bool contains(const ClientClass &x) const
returns if class x belongs to the defined classes
Definition: classify.h:99
virtual HWAddrPtr getMACFromDocsisCMTS()=0
Attempts to extract MAC/Hardware address from DOCSIS options inserted by the CMTS (the relay agent) ...
bool delOption(uint16_t type)
Attempts to delete first suboption of requested type.
Definition: pkt.cc:83
HWAddrPtr getRemoteHWAddr() const
Returns the remote HW address obtained from raw sockets.
Definition: pkt.h:559
bool copy_retrieved_options_
Indicates if a copy of the retrieved option should be returned when Pkt::getOption is called...
Definition: pkt.h:770
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_CMTS
A CMTS (acting as DHCP relay agent) that supports DOCSIS standard can insert DOCSIS options that cont...
Definition: hwaddr.h:73
void setRemoteHWAddr(const HWAddrPtr &hw_addr)
Sets remote hardware address.
Definition: pkt.cc:129
Defines the logger used by the top-level component of kea-dhcp-ddns.
void updateTimestamp()
Update packet timestamp.
Definition: pkt.cc:112
HWAddrPtr remote_hwaddr_
Definition: pkt.h:776
virtual HWAddrPtr getMACFromIPv6RelayOpt()=0
Attempts to obtain MAC address from relay option client-linklayer-addr.
void addClass(const isc::dhcp::ClientClass &client_class, bool required=false)
Adds packet to a specified class.
Definition: pkt.cc:100
virtual HWAddrPtr getMACFromDUID()=0
Attempts to obtain MAC address from DUID-LL or DUID-LLT.
static const uint32_t HWADDR_SOURCE_RAW
Obtained first hand from raw socket (100% reliable).
Definition: hwaddr.h:44
OptionPtr getOption(const uint16_t type)
Returns the first option of specified type.
Definition: pkt.cc:70
void repack()
Copies content of input buffer to output buffer.
Definition: pkt.cc:116
static IfaceMgr & instance()
IfaceMgr is a singleton class.
Definition: iface_mgr.cc:53
Hardware type that represents information from DHCPv4 packet.
Definition: hwaddr.h:20
void insert(const ClientClass &class_name)
Insert an element.
Definition: classify.h:62
bool empty() const
Check if classes is empty.
Definition: classify.h:73
isc::util::OutputBuffer buffer_out_
Output buffer (used during message transmission)
Definition: pkt.h:764
virtual HWAddrPtr getMACFromSrcLinkLocalAddr()=0
Attempts to obtain MAC address from source link-local IPv6 address.
ClientClasses required_classes_
Classes which are required to be evaluated.
Definition: pkt.h:604
isc::dhcp::OptionCollection options_
Collection of options present in this message.
Definition: pkt.h:614
Container for storing client class names.
Definition: classify.h:43
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
boost::posix_time::ptime timestamp_
packet timestamp
Definition: pkt.h:773
HWAddrPtr getMAC(uint32_t hw_addr_src)
Returns MAC address.
Definition: pkt.cc:146