/// This class is purely virtual. Please instantiate Pkt4, Pkt6 or any
/// other derived classes.
class Pkt {
+public:
+
+ /// @brief specified where did we get this MAC address from?
+ ///
+ /// The list covers all possible MAC sources. The uncommented ones
+ /// are currently supported. When you implement a new method, please
+ /// uncomment appropriate line here.
+ enum MACSource {
+
+ /// Not really a type, only used in getMAC() calls
+ MAC_SOURCE_ANY,
+
+ /// obtained first hand from raw socket (100% reliable)
+ MAC_SOURCE_RAW,
+
+ /// extracted from DUID-LL or DUID-LLT (not reliable as the client
+ /// can send fake DUID)
+ // MAC_SOURCE_DUID,
+
+ /// extracted from IPv6 link-local address. Client can use different
+ /// IID other than EUI-64, e.g. Windows supports RFC4941 and uses
+ /// random values instead of EUI-64.
+ // MAC_SOURCE_IPV6_LINK_LOCAL,
+
+ /// RFC6939 (a relay agent can insert client link layer address option)
+ /// Note that a skilled attacker can fake that by sending his request
+ /// relayed, so the legitimate relay will think it's a second relay.
+ // MAC_SOURCE_CLIENT_ADDR_RELAY_OPTION,
+
+ /// A relay can insert remote-id. In some deployments it contains a MAC
+ /// address.
+ // MAC_SOURCE_REMOTE_ID,
+
+ /// A relay can insert a subscriber-id option. In some deployments it
+ /// contains a MAC address.
+ // MAC_SOURCE_SUBSCRIBER_ID,
+
+ /// A CMTS (acting as DHCP relay agent) that supports DOCSIS standard
+ /// can insert DOCSIS options that contain client's MAC address.
+ /// Client in this context would be a cable modem.
+ // MAC_SOURCE_DOCSIS_OPTIONS
+ };
+
protected:
Pkt(uint32_t transid, const isc::asiolink::IOAddress& local_addr,
const isc::asiolink::IOAddress& remote_addr, uint16_t local_port,
void setRemoteHWAddr(const uint8_t htype, const uint8_t hlen,
const std::vector<uint8_t>& mac_addr);
- /// @brief Returns the remote HW address.
+ /// @brief Returns the remote HW address obtained from raw sockets.
///
/// @return remote HW address.
HWAddrPtr getRemoteHWAddr() const {
return (remote_hwaddr_);
}
+ /// @brief Returns MAC address.
+ ///
+ /// The difference between this method and getRemoteHWAddr() is that
+ /// getRemoteHWAddr() returns only what was obtained from raw sockets.
+ /// This method is more generic and can attempt to obtain MAC from
+ /// varied sources: raw sockets, client-id, link-local IPv6 address,
+ /// and various relay options.
+ HWAddrPtr getMAC(MACSource from);
+
/// @brief virtual desctructor
///
/// There is nothing to clean up here, but since there are virtual methods,
EXPECT_TRUE(pkt.inClass("foo"));
}
+// Tests whether MAC can be obtained and that MAC sources are not
+// confused.
+TEST_F(Pkt4Test, getMAC) {
+ Pkt4 pkt(DHCPOFFER, 1234);
+
+ // DHCPv6 packet by default doens't have MAC address specified.
+ EXPECT_FALSE(pkt.getMAC(Pkt::MAC_SOURCE_ANY));
+ EXPECT_FALSE(pkt.getMAC(Pkt::MAC_SOURCE_RAW));
+
+ // Let's invent a MAC
+ const uint8_t hw[] = { 2, 4, 6, 8, 10, 12 }; // MAC
+ const uint8_t hw_type = 123; // hardware type
+ HWAddrPtr dummy_hwaddr(new HWAddr(hw, sizeof(hw), hw_type));
+
+ // Now let's pretend that we obtained it from raw sockets
+ pkt.setRemoteHWAddr(dummy_hwaddr);
+
+ // Now we should be able to get something
+ ASSERT_TRUE(pkt.getMAC(Pkt::MAC_SOURCE_ANY));
+ ASSERT_TRUE(pkt.getMAC(Pkt::MAC_SOURCE_RAW));
+
+ // Check that the returned MAC is indeed the expected one
+ ASSERT_TRUE(*dummy_hwaddr == *pkt.getMAC(Pkt::MAC_SOURCE_ANY));
+ ASSERT_TRUE(*dummy_hwaddr == *pkt.getMAC(Pkt::MAC_SOURCE_RAW));
+}
+
} // end of anonymous namespace
#include <dhcp/option_int.h>
#include <dhcp/option_int_array.h>
#include <dhcp/pkt6.h>
+#include <dhcp/hwaddr.h>
#include <dhcp/docsis3_option_defs.h>
#include <util/range_utilities.h>
EXPECT_TRUE(pkt.inClass("foo"));
}
+// Tests whether MAC can be obtained and that MAC sources are not
+// confused.
+TEST_F(Pkt6Test, getMAC) {
+ Pkt6 pkt(DHCPV6_ADVERTISE, 1234);
+
+ // DHCPv6 packet by default doens't have MAC address specified.
+ EXPECT_FALSE(pkt.getMAC(Pkt::MAC_SOURCE_ANY));
+ EXPECT_FALSE(pkt.getMAC(Pkt::MAC_SOURCE_RAW));
+
+ // Let's invent a MAC
+ const uint8_t hw[] = { 2, 4, 6, 8, 10, 12 }; // MAC
+ const uint8_t hw_type = 123; // hardware type
+ HWAddrPtr dummy_hwaddr(new HWAddr(hw, sizeof(hw), hw_type));
+
+ // Now let's pretend that we obtained it from raw sockets
+ pkt.setRemoteHWAddr(dummy_hwaddr);
+
+ // Now we should be able to get something
+ ASSERT_TRUE(pkt.getMAC(Pkt::MAC_SOURCE_ANY));
+ ASSERT_TRUE(pkt.getMAC(Pkt::MAC_SOURCE_RAW));
+
+ // Check that the returned MAC is indeed the expected one
+ ASSERT_TRUE(*dummy_hwaddr == *pkt.getMAC(Pkt::MAC_SOURCE_ANY));
+ ASSERT_TRUE(*dummy_hwaddr == *pkt.getMAC(Pkt::MAC_SOURCE_RAW));
+}
+
}