summaryrefslogtreecommitdiffstats
path: root/src/lib/dhcp/pkt.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/dhcp/pkt.cc')
-rw-r--r--src/lib/dhcp/pkt.cc269
1 files changed, 269 insertions, 0 deletions
diff --git a/src/lib/dhcp/pkt.cc b/src/lib/dhcp/pkt.cc
new file mode 100644
index 0000000..4d214c7
--- /dev/null
+++ b/src/lib/dhcp/pkt.cc
@@ -0,0 +1,269 @@
+// Copyright (C) 2014-2022 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+#include <utility>
+#include <dhcp/pkt.h>
+#include <dhcp/iface_mgr.h>
+#include <dhcp/hwaddr.h>
+#include <vector>
+
+namespace isc {
+namespace dhcp {
+
+Pkt::Pkt(uint32_t transid, const isc::asiolink::IOAddress& local_addr,
+ const isc::asiolink::IOAddress& remote_addr, uint16_t local_port,
+ uint16_t remote_port)
+ : transid_(transid), iface_(""), ifindex_(-1), local_addr_(local_addr),
+ remote_addr_(remote_addr), local_port_(local_port),
+ remote_port_(remote_port), buffer_out_(0), copy_retrieved_options_(false) {
+}
+
+Pkt::Pkt(const uint8_t* buf, uint32_t len, const isc::asiolink::IOAddress& local_addr,
+ const isc::asiolink::IOAddress& remote_addr, uint16_t local_port,
+ uint16_t remote_port)
+ : transid_(0), iface_(""), ifindex_(-1), local_addr_(local_addr),
+ remote_addr_(remote_addr), local_port_(local_port),
+ remote_port_(remote_port), buffer_out_(0), copy_retrieved_options_(false) {
+ if (len != 0) {
+ if (buf == NULL) {
+ isc_throw(InvalidParameter, "data buffer passed to Pkt is NULL");
+ }
+ data_.resize(len);
+ memcpy(&data_[0], buf, len);
+ }
+}
+
+void
+Pkt::addOption(const OptionPtr& opt) {
+ options_.insert(std::pair<int, OptionPtr>(opt->getType(), opt));
+}
+
+OptionPtr
+Pkt::getNonCopiedOption(const uint16_t type) const {
+ const auto& x = options_.find(type);
+ if (x != options_.end()) {
+ return (x->second);
+ }
+ return (OptionPtr());
+}
+
+OptionPtr
+Pkt::getOption(const uint16_t type) {
+ const auto& x = options_.find(type);
+ if (x != options_.end()) {
+ if (copy_retrieved_options_) {
+ OptionPtr option_copy = x->second->clone();
+ x->second = option_copy;
+ }
+ return (x->second);
+ }
+ return (OptionPtr()); // NULL
+}
+
+bool
+Pkt::delOption(uint16_t type) {
+ const auto& x = options_.find(type);
+ if (x != options_.end()) {
+ options_.erase(x);
+ return (true); // delete successful
+ } else {
+ return (false); // can't find option to be deleted
+ }
+}
+
+bool
+Pkt::inClass(const std::string& client_class) {
+ return (classes_.contains(client_class));
+}
+
+void
+Pkt::addClass(const std::string& client_class, bool required) {
+ // Always have ALL first.
+ if (classes_.empty()) {
+ classes_.insert("ALL");
+ }
+ ClientClasses& classes = !required ? classes_ : required_classes_;
+ if (!classes.contains(client_class)) {
+ classes.insert(client_class);
+ }
+}
+
+void
+Pkt::updateTimestamp() {
+ timestamp_ = boost::posix_time::microsec_clock::universal_time();
+}
+
+void Pkt::repack() {
+ if (!data_.empty()) {
+ buffer_out_.writeData(&data_[0], data_.size());
+ }
+}
+
+void
+Pkt::setRemoteHWAddr(const uint8_t htype, const uint8_t hlen,
+ const std::vector<uint8_t>& hw_addr) {
+ setHWAddrMember(htype, hlen, hw_addr, remote_hwaddr_);
+}
+
+void
+Pkt::setRemoteHWAddr(const HWAddrPtr& hw_addr) {
+ if (!hw_addr) {
+ isc_throw(BadValue, "Setting remote HW address to NULL is"
+ << " forbidden.");
+ }
+ remote_hwaddr_ = hw_addr;
+}
+
+void
+Pkt::setHWAddrMember(const uint8_t htype, const uint8_t,
+ const std::vector<uint8_t>& hw_addr,
+ HWAddrPtr& storage) {
+ storage.reset(new HWAddr(hw_addr, htype));
+}
+
+HWAddrPtr
+Pkt::getMAC(uint32_t hw_addr_src) {
+ HWAddrPtr mac;
+
+ /// @todo: Implement an array of method pointers instead of set of ifs
+
+ // Method 1: from raw sockets.
+ if (hw_addr_src & HWAddr::HWADDR_SOURCE_RAW) {
+ mac = getRemoteHWAddr();
+ if (mac) {
+ mac->source_ = HWAddr::HWADDR_SOURCE_RAW;
+ return (mac);
+ } else if (hw_addr_src == HWAddr::HWADDR_SOURCE_RAW) {
+ // If we're interested only in RAW sockets as source of that info,
+ // there's no point in trying other options.
+ return (HWAddrPtr());
+ }
+ }
+
+ // Method 2: From client link-layer address option inserted by a relay
+ if (hw_addr_src & HWAddr::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION) {
+ mac = getMACFromIPv6RelayOpt();
+ if (mac) {
+ return (mac);
+ } else if (hw_addr_src == HWAddr::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION) {
+ // If we're interested only in RFC6939 link layer address as source
+ // of that info, there's no point in trying other options.
+ return (HWAddrPtr());
+ }
+ }
+
+ // Method 3: Extracted from DUID-LLT or DUID-LL
+ if(hw_addr_src & HWAddr::HWADDR_SOURCE_DUID) {
+ mac = getMACFromDUID();
+ if (mac) {
+ return (mac);
+ } else if (hw_addr_src == HWAddr::HWADDR_SOURCE_DUID) {
+ // If the only source allowed is DUID then we can skip the other
+ // methods.
+ return (HWAddrPtr());
+ }
+ }
+
+ // Method 4: Extracted from source IPv6 link-local address
+ if (hw_addr_src & HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL) {
+ mac = getMACFromSrcLinkLocalAddr();
+ if (mac) {
+ return (mac);
+ } else if (hw_addr_src == HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL) {
+ // If we're interested only in link-local addr as source of that
+ // info, there's no point in trying other options.
+ return (HWAddrPtr());
+ }
+ }
+
+ // Method 5: From remote-id option inserted by a relay
+ if(hw_addr_src & HWAddr::HWADDR_SOURCE_REMOTE_ID) {
+ mac = getMACFromRemoteIdRelayOption();
+ if (mac) {
+ return (mac);
+ } else if (hw_addr_src == HWAddr::HWADDR_SOURCE_REMOTE_ID) {
+ // If the only source allowed is remote-id option then we can skip
+ // the other methods.
+ return (HWAddrPtr());
+ }
+ }
+
+ // Method 6: From subscriber-id option inserted by a relay
+
+ // Method 7: From docsis options
+ if (hw_addr_src & HWAddr::HWADDR_SOURCE_DOCSIS_CMTS) {
+ mac = getMACFromDocsisCMTS();
+ if (mac) {
+ return (mac);
+ } else if (hw_addr_src == HWAddr::HWADDR_SOURCE_DOCSIS_CMTS) {
+ // If we're interested only in CMTS options as a source of that
+ // info, there's no point in trying other options.
+ return (HWAddrPtr());
+ }
+ }
+
+ // Method 8: From docsis options
+ if (hw_addr_src & HWAddr::HWADDR_SOURCE_DOCSIS_MODEM) {
+ mac = getMACFromDocsisModem();
+ if (mac) {
+ return (mac);
+ } else if (hw_addr_src == HWAddr::HWADDR_SOURCE_DOCSIS_MODEM) {
+ // If we're interested only in CMTS options as a source of that
+ // info, there's no point in trying other options.
+ return (HWAddrPtr());
+ }
+ }
+
+ // Ok, none of the methods were suitable. Return NULL.
+ return (HWAddrPtr());
+}
+
+HWAddrPtr
+Pkt::getMACFromIPv6(const isc::asiolink::IOAddress& addr) {
+ HWAddrPtr mac;
+
+ if (addr.isV6LinkLocal()) {
+ std::vector<uint8_t> bin = addr.toBytes();
+
+ // Double check that it's of appropriate size
+ if ((bin.size() == isc::asiolink::V6ADDRESS_LEN) &&
+ // Check that it's link-local (starts with fe80).
+ (bin[0] == 0xfe) && (bin[1] == 0x80) &&
+ // Check that u bit is set and g is clear.
+ // See Section 2.5.1 of RFC2373 for details.
+ ((bin[8] & 3) == 2) &&
+ // And that the IID is of EUI-64 type.
+ (bin[11] == 0xff) && (bin[12] == 0xfe)) {
+
+ // Remove 8 most significant bytes
+ bin.erase(bin.begin(), bin.begin() + 8);
+
+ // Ok, we're down to EUI-64 only now: XX:XX:XX:ff:fe:XX:XX:XX
+ bin.erase(bin.begin() + 3, bin.begin() + 5);
+
+ // MAC-48 to EUI-64 involves inverting u bit (see explanation
+ // in Section 2.5.1 of RFC2373). We need to revert that.
+ bin[0] = bin[0] ^ 2;
+
+ // Let's get the interface this packet was received on.
+ // We need it to get hardware type
+ IfacePtr iface = IfaceMgr::instance().getIface(iface_);
+ uint16_t hwtype = 0; // not specified
+ if (iface) {
+ hwtype = iface->getHWType();
+ }
+
+ mac.reset(new HWAddr(bin, hwtype));
+ mac->source_ = HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL;
+ }
+ }
+
+ return (mac);
+}
+
+} // end of namespace isc::dhcp
+} // end of namespace isc