Browse Source

[3554] Configurable MAC sources implemented.

Tomek Mrugalski 10 years ago
parent
commit
f643dc9f47

+ 15 - 0
src/bin/dhcp6/dhcp6.spec

@@ -422,6 +422,21 @@
                 } ]
                 } ]
             }
             }
       },
       },
+
+      { "item_name": "mac-sources",
+        "item_type": "list",
+        "item_optional": true,
+        "item_default": [ "any" ],
+        "item_description": "Lists MAC/hardware address acquisition sources",
+        "list_item_spec":
+        {
+          "item_name": "source",
+          "item_type": "string",
+          "item_optional": true,
+          "item_default": "any"
+        }
+      } ,
+
       { "item_name": "dhcp-ddns",
       { "item_name": "dhcp-ddns",
         "item_type": "map",
         "item_type": "map",
         "item_optional": false,
         "item_optional": false,

+ 12 - 4
src/bin/dhcp6/dhcp6_srv.cc

@@ -1253,10 +1253,18 @@ Dhcpv6Srv::assignIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid,
         hostname = fqdn->getDomainName();
         hostname = fqdn->getDomainName();
     }
     }
 
 
-    // Attempt to get MAC address using any of available mechanisms.
-    // It's ok if there response is NULL. Hardware address is optional in Lease6
-    /// @todo: Make this configurable after trac 3554 is done.
-    HWAddrPtr hwaddr = query->getMAC(Pkt::HWADDR_SOURCE_ANY);
+    // Attempt to get MAC address using configured mechanisms.
+    // It's ok if there response is NULL. Hardware address is optional in Lease6.
+    std::vector<uint32_t> mac_sources = CfgMgr::instance().getCurrentCfg()->
+        getMACSources();
+    HWAddrPtr hwaddr;
+    for (std::vector<uint32_t>::const_iterator it = mac_sources.begin();
+         it != mac_sources.end(); ++it) {
+        hwaddr = query->getMAC(*it);
+        if (hwaddr) {
+            break;
+        }
+    }
 
 
     // Use allocation engine to pick a lease for this client. Allocation engine
     // Use allocation engine to pick a lease for this client. Allocation engine
     // will try to honour the hint, but it is just a hint - some other address
     // will try to honour the hint, but it is just a hint - some other address

+ 3 - 0
src/bin/dhcp6/json_config_parser.cc

@@ -613,6 +613,9 @@ namespace dhcp {
         parser = new HooksLibrariesParser(config_id);
         parser = new HooksLibrariesParser(config_id);
     } else if (config_id.compare("dhcp-ddns") == 0) {
     } else if (config_id.compare("dhcp-ddns") == 0) {
         parser = new D2ClientConfigParser(config_id);
         parser = new D2ClientConfigParser(config_id);
+    } else if (config_id.compare("mac-sources") == 0) {
+        parser = new MACSourcesListConfigParser(config_id,
+                                                globalContext());
     } else {
     } else {
         isc_throw(DhcpConfigError,
         isc_throw(DhcpConfigError,
                 "unsupported global configuration parameter: "
                 "unsupported global configuration parameter: "

+ 0 - 3
src/bin/dhcp6/json_config_parser.h

@@ -15,9 +15,6 @@
 #ifndef DHCP6_CONFIG_PARSER_H
 #ifndef DHCP6_CONFIG_PARSER_H
 #define DHCP6_CONFIG_PARSER_H
 #define DHCP6_CONFIG_PARSER_H
 
 
-/// @todo: This header file and its .cc counterpart are very similar between
-/// DHCPv4 and DHCPv6. They should be merged. See ticket #2355.
-
 #include <cc/data.h>
 #include <cc/data.h>
 #include <dhcpsrv/parsers/dhcp_parsers.h>
 #include <dhcpsrv/parsers/dhcp_parsers.h>
 #include <exceptions/exceptions.h>
 #include <exceptions/exceptions.h>

+ 38 - 0
src/lib/dhcp/pkt.cc

@@ -20,6 +20,16 @@
 namespace isc {
 namespace isc {
 namespace dhcp {
 namespace dhcp {
 
 
+const uint32_t Pkt::HWADDR_SOURCE_ANY = 0xffffffff;
+const uint32_t Pkt::HWADDR_SOURCE_UNKNOWN = 0x00000000;
+const uint32_t Pkt::HWADDR_SOURCE_RAW = 0x00000001;
+const uint32_t Pkt::HWADDR_SOURCE_DUID = 0x00000002;
+const uint32_t Pkt::HWADDR_SOURCE_IPV6_LINK_LOCAL = 0x00000004;
+const uint32_t Pkt::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION = 0x00000008;
+const uint32_t Pkt::HWADDR_SOURCE_REMOTE_ID = 0x00000010;
+const uint32_t Pkt::HWADDR_SOURCE_SUBSCRIBER_ID = 0x00000020;
+const uint32_t Pkt::HWADDR_SOURCE_DOCSIS = 0x00000040;
+
 Pkt::Pkt(uint32_t transid, const isc::asiolink::IOAddress& local_addr,
 Pkt::Pkt(uint32_t transid, const isc::asiolink::IOAddress& local_addr,
          const isc::asiolink::IOAddress& remote_addr, uint16_t local_port,
          const isc::asiolink::IOAddress& remote_addr, uint16_t local_port,
          uint16_t remote_port)
          uint16_t remote_port)
@@ -223,6 +233,34 @@ Pkt::getMACFromIPv6(const isc::asiolink::IOAddress& addr) {
     return (HWAddrPtr(new HWAddr(bin, hwtype)));
     return (HWAddrPtr(new HWAddr(bin, hwtype)));
 }
 }
 
 
+uint16_t Pkt::MACSourceFromText(const std::string& name) {
+
+    struct {
+        const char * name;
+        uint32_t type;
+    } sources[] = {
+        { "any", Pkt::HWADDR_SOURCE_ANY },
+        { "raw", Pkt::HWADDR_SOURCE_RAW },
+        { "duid", Pkt::HWADDR_SOURCE_DUID },
+        { "ipv6-link-local", Pkt::HWADDR_SOURCE_IPV6_LINK_LOCAL },
+        { "client-link-addr-option", Pkt::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION },
+        { "rfc6939", Pkt::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION },
+        { "remote-id", Pkt::HWADDR_SOURCE_REMOTE_ID },
+        { "rfc4649", Pkt::HWADDR_SOURCE_REMOTE_ID },
+        { "subscriber-id", Pkt::HWADDR_SOURCE_SUBSCRIBER_ID },
+        { "rfc4580", Pkt::HWADDR_SOURCE_SUBSCRIBER_ID },
+        { "docsis", Pkt::HWADDR_SOURCE_DOCSIS }
+    };
+
+    for (int i=0; i < sizeof(sources)/sizeof(sources[0]); ++i) {
+        if (name.compare(sources[i].name)) {
+            return (sources[i].type);
+        }
+    }
+
+    isc_throw(BadValue, "Can't convert '" << name << "' to any known MAC source.");
+}
+
 
 
 };
 };
 };
 };

+ 24 - 12
src/lib/dhcp/pkt.h

@@ -44,51 +44,63 @@ public:
     ///
     ///
     /// @brief The list covers all possible MAC/hw address sources.
     /// @brief The list covers all possible MAC/hw address sources.
     ///
     ///
-    /// @note The uncommented ones are currently supported. When you implement
-    /// a new method, please uncomment appropriate line here.
-    ///
     /// @{
     /// @{
 
 
     /// Not really a type, only used in getMAC() calls.
     /// Not really a type, only used in getMAC() calls.
-    static const uint32_t HWADDR_SOURCE_ANY = 0xffff;
+    static const uint32_t HWADDR_SOURCE_ANY;
 
 
     /// Used when actual origin is not known, e.g. when reading from a
     /// Used when actual origin is not known, e.g. when reading from a
     /// lease database that didn't store that information.
     /// lease database that didn't store that information.
-    static const uint32_t HWADDR_SOURCE_UNKNOWN = 0x0000;
+    static const uint32_t HWADDR_SOURCE_UNKNOWN;
 
 
     /// Obtained first hand from raw socket (100% reliable).
     /// Obtained first hand from raw socket (100% reliable).
-    static const uint32_t HWADDR_SOURCE_RAW = 0x0001;
+    static const uint32_t HWADDR_SOURCE_RAW;
 
 
     /// Extracted from DUID-LL or DUID-LLT (not 100% reliable as the client
     /// Extracted from DUID-LL or DUID-LLT (not 100% reliable as the client
     /// can send fake DUID).
     /// can send fake DUID).
-    //static const uint32_t HWADDR_SOURCE_DUID = 0x0002;
+    static const uint32_t HWADDR_SOURCE_DUID;
 
 
     /// Extracted from IPv6 link-local address. Not 100% reliable, as the
     /// Extracted from IPv6 link-local address. Not 100% reliable, as the
     /// client can use different IID other than EUI-64, e.g. Windows supports
     /// client can use different IID other than EUI-64, e.g. Windows supports
     /// RFC4941 and uses random values instead of EUI-64.
     /// RFC4941 and uses random values instead of EUI-64.
-    static const uint32_t HWADDR_SOURCE_IPV6_LINK_LOCAL = 0x0004;
+    static const uint32_t HWADDR_SOURCE_IPV6_LINK_LOCAL;
 
 
     /// Get it from RFC6939 option. (A relay agent can insert client link layer
     /// Get it from RFC6939 option. (A relay agent can insert client link layer
     /// address option). Note that a skilled attacker can fake that by sending
     /// 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
     /// his request relayed, so the legitimate relay will think it's a second
     /// relay.
     /// relay.
-    static const uint32_t HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION = 0x0008;
+    static const uint32_t HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION;
 
 
     /// A relay can insert remote-id. In some deployments it contains a MAC
     /// A relay can insert remote-id. In some deployments it contains a MAC
     /// address (RFC4649).
     /// address (RFC4649).
-    //static const uint32_t HWADDR_SOURCE_REMOTE_ID = 0x0010;
+    static const uint32_t HWADDR_SOURCE_REMOTE_ID;
 
 
     /// A relay can insert a subscriber-id option. In some deployments it
     /// A relay can insert a subscriber-id option. In some deployments it
     /// contains a MAC address (RFC4580).
     /// contains a MAC address (RFC4580).
-    //static const uint32_t HWADDR_SOURCE_SUBSCRIBER_ID = 0x0020;
+    static const uint32_t HWADDR_SOURCE_SUBSCRIBER_ID;
 
 
     /// A CMTS (acting as DHCP relay agent) that supports DOCSIS standard
     /// A CMTS (acting as DHCP relay agent) that supports DOCSIS standard
     /// can insert DOCSIS options that contain client's MAC address.
     /// can insert DOCSIS options that contain client's MAC address.
     /// Client in this context would be a cable modem.
     /// Client in this context would be a cable modem.
-    //static const uint32_t HWADDR_SOURCE_DOCSIS_OPTIONS = 0x0040;
+    static const uint32_t HWADDR_SOURCE_DOCSIS;
 
 
     /// @}
     /// @}
 
 
+    /// @brief Attempts to convert known hardware address sources to uint32_t
+    ///
+    /// Supported strings are: any => 0xffffffff
+    ///                        raw => 0x00000001
+    ///                        duid => 0x00000002
+    ///                        ipv6-link-local 0x00000004
+    ///                        client-link-addr-option, rfc6939 => 0x00000008
+    ///                        remote-id, rfc4649 => 0x00000010
+    ///                        subscriber-id, rfc4580 => 0x00000020
+    ///                        docsis => 0x00000040
+    ///
+    /// @throw BadValue if specified string is unknown
+    /// @return bitmask version of a given method
+    static uint16_t MACSourceFromText(const std::string& name);
+
 protected:
 protected:
 
 
     /// @brief Constructor.
     /// @brief Constructor.

+ 40 - 0
src/lib/dhcpsrv/parsers/dhcp_parsers.cc

@@ -187,6 +187,7 @@ InterfaceListConfigParser(const std::string& param_name,
 void
 void
 InterfaceListConfigParser::build(ConstElementPtr value) {
 InterfaceListConfigParser::build(ConstElementPtr value) {
     CfgIface cfg_iface;
     CfgIface cfg_iface;
+
     BOOST_FOREACH(ConstElementPtr iface, value->listValue()) {
     BOOST_FOREACH(ConstElementPtr iface, value->listValue()) {
         std::string iface_name = iface->stringValue();
         std::string iface_name = iface->stringValue();
         try {
         try {
@@ -206,6 +207,45 @@ InterfaceListConfigParser::commit() {
     // Nothing to do.
     // Nothing to do.
 }
 }
 
 
+// ******************** MACSourcesListConfigParser *************************
+
+MACSourcesListConfigParser::
+MACSourcesListConfigParser(const std::string& param_name,
+                           ParserContextPtr global_context)
+    : param_name_(param_name), global_context_(global_context) {
+    if (param_name_ != "mac-sources") {
+        isc_throw(BadValue, "Internal error. MAC sources configuration "
+            "parser called for the wrong parameter: " << param_name);
+    }
+}
+
+void
+MACSourcesListConfigParser::build(ConstElementPtr value) {
+    CfgIface cfg_iface;
+    uint32_t source = 0;
+
+    // By default, there's only one source defined: ANY.
+    // If user specified anything, we need to get rid of that default.
+    CfgMgr::instance().getStagingCfg()->clearMACSources();
+
+    BOOST_FOREACH(ConstElementPtr source_elem, value->listValue()) {
+        std::string source_str = source_elem->stringValue();
+        try {
+            source = Pkt::MACSourceFromText(source_str);
+            CfgMgr::instance().getStagingCfg()->addMACSource(source);
+        } catch (const std::exception& ex) {
+            isc_throw(DhcpConfigError, "Failed to convert '"
+                      << source_str << "' to any recognized MAC source:"
+                      << ex.what() << " (" << value->getPosition() << ")");
+        }
+    }
+}
+
+void
+MACSourcesListConfigParser::commit() {
+    // Nothing to do.
+}
+
 // ******************** HooksLibrariesParser *************************
 // ******************** HooksLibrariesParser *************************
 
 
 HooksLibrariesParser::HooksLibrariesParser(const std::string& param_name)
 HooksLibrariesParser::HooksLibrariesParser(const std::string& param_name)

+ 43 - 4
src/lib/dhcpsrv/parsers/dhcp_parsers.h

@@ -382,12 +382,10 @@ private:
 
 
 /// @brief parser for interface list definition
 /// @brief parser for interface list definition
 ///
 ///
-/// This parser handles Dhcp4/interface entry.
+/// This parser handles Dhcp4/interfaces and Dhcp6/interfaces entries.
 /// It contains a list of network interfaces that the server listens on.
 /// It contains a list of network interfaces that the server listens on.
 /// In particular, it can contain an entry called "all" or "any" that
 /// In particular, it can contain an entry called "all" or "any" that
 /// designates all interfaces.
 /// designates all interfaces.
-///
-/// It is useful for parsing Dhcp4/interface parameter.
 class InterfaceListConfigParser : public DhcpConfigParser {
 class InterfaceListConfigParser : public DhcpConfigParser {
 public:
 public:
 
 
@@ -422,6 +420,48 @@ private:
     ParserContextPtr global_context_;
     ParserContextPtr global_context_;
 };
 };
 
 
+
+/// @brief parser for MAC/hardware aquisition sources
+///
+/// This parser handles Dhcp6/mac-sources entry.
+/// It contains a list of MAC/hardware aquisition source, i.e. methods how
+/// MAC address can possibly by obtained in DHCPv6. For a currently supported
+/// methods, see @ref isc::dhcp::Pkt::getMAC.
+class MACSourcesListConfigParser : public DhcpConfigParser {
+public:
+
+    /// @brief constructor
+    ///
+    /// As this is a dedicated parser, it must be used to parse
+    /// "mac-sources" parameter only. All other types will throw exception.
+    ///
+    /// @param param_name name of the configuration parameter being parsed
+    /// @param global_context Global parser context.
+    /// @throw BadValue if supplied parameter name is not "mac-sources"
+    MACSourcesListConfigParser(const std::string& param_name,
+                               ParserContextPtr global_context);
+
+    /// @brief parses parameters value
+    ///
+    /// Parses configuration entry (list of sources) and adds each element
+    /// to the sources list.
+    ///
+    /// @param value pointer to the content of parsed values
+    virtual void build(isc::data::ConstElementPtr value);
+
+    /// @brief Does nothing.
+    virtual void commit();
+
+private:
+
+    // Parsed parameter name
+    std::string param_name_;
+
+    /// Global parser context.
+    ParserContextPtr global_context_;
+};
+
+
 /// @brief Parser for hooks library list
 /// @brief Parser for hooks library list
 ///
 ///
 /// This parser handles the list of hooks libraries.  This is an optional list,
 /// This parser handles the list of hooks libraries.  This is an optional list,
@@ -1172,4 +1212,3 @@ typedef boost::shared_ptr<Uint32Parser> Uint32ParserPtr;
 }; // end of isc namespace
 }; // end of isc namespace
 
 
 #endif // DHCP_PARSERS_H
 #endif // DHCP_PARSERS_H
-

+ 7 - 0
src/lib/dhcpsrv/srv_config.cc

@@ -16,6 +16,7 @@
 #include <dhcpsrv/srv_config.h>
 #include <dhcpsrv/srv_config.h>
 #include <log/logger_manager.h>
 #include <log/logger_manager.h>
 #include <log/logger_specification.h>
 #include <log/logger_specification.h>
+#include <dhcp/pkt.h> // Needed for HWADDR_SOURCE_*
 #include <list>
 #include <list>
 #include <sstream>
 #include <sstream>
 
 
@@ -28,12 +29,18 @@ SrvConfig::SrvConfig()
     : sequence_(0), cfg_option_def_(new CfgOptionDef()),
     : sequence_(0), cfg_option_def_(new CfgOptionDef()),
       cfg_option_(new CfgOption()), cfg_subnets4_(new CfgSubnets4()),
       cfg_option_(new CfgOption()), cfg_subnets4_(new CfgSubnets4()),
       cfg_subnets6_(new CfgSubnets6()), cfg_hosts_(new CfgHosts()) {
       cfg_subnets6_(new CfgSubnets6()), cfg_hosts_(new CfgHosts()) {
+
+    // By default, use any hardware source that is available.
+    mac_sources_.push_back(Pkt::HWADDR_SOURCE_ANY);
 }
 }
 
 
 SrvConfig::SrvConfig(const uint32_t sequence)
 SrvConfig::SrvConfig(const uint32_t sequence)
     : sequence_(sequence), cfg_option_def_(new CfgOptionDef()),
     : sequence_(sequence), cfg_option_def_(new CfgOptionDef()),
       cfg_option_(new CfgOption()), cfg_subnets4_(new CfgSubnets4()),
       cfg_option_(new CfgOption()), cfg_subnets4_(new CfgSubnets4()),
       cfg_subnets6_(new CfgSubnets6()), cfg_hosts_(new CfgHosts()) {
       cfg_subnets6_(new CfgSubnets6()), cfg_hosts_(new CfgHosts()) {
+
+    // By default, use any hardware source that is available.
+    mac_sources_.push_back(Pkt::HWADDR_SOURCE_ANY);
 }
 }
 
 
 std::string
 std::string

+ 25 - 0
src/lib/dhcpsrv/srv_config.h

@@ -235,6 +235,28 @@ public:
         return (cfg_hosts_);
         return (cfg_hosts_);
     }
     }
 
 
+    /// @brief Adds additional MAC/hardware address aquisition.
+    ///
+    /// @param source MAC source (see constants in Pkt::HWADDR_SOURCE_*)
+    ///
+    /// Specified source is being added to the mac_sources_ array.
+    void addMACSource(uint32_t source) {
+        mac_sources_.push_back(source);
+    }
+
+    /// @brief Provides access to the configure MAC/Hardware address sources.
+    ///
+    /// @note The const reference returned is only valid as long as the
+    /// object that returned it.
+    const std::vector<uint32_t>& getMACSources() const {
+        return mac_sources_;
+    }
+
+    /// @brief Removes any configured MAC/Hardware address sources.
+    void clearMACSources() {
+        mac_sources_.clear();
+    }
+
     //@}
     //@}
 
 
     /// @brief Copies the currnet configuration to a new configuration.
     /// @brief Copies the currnet configuration to a new configuration.
@@ -310,6 +332,7 @@ public:
 
 
     //@}
     //@}
 
 
+
 private:
 private:
 
 
     /// @brief Sequence number identifying the configuration.
     /// @brief Sequence number identifying the configuration.
@@ -348,6 +371,8 @@ private:
     /// reservations for different IPv4 and IPv6 subnets.
     /// reservations for different IPv4 and IPv6 subnets.
     CfgHostsPtr cfg_hosts_;
     CfgHostsPtr cfg_hosts_;
 
 
+    /// @brief A list of configured MAC sources.
+    std::vector<uint32_t> mac_sources_;
 };
 };
 
 
 /// @name Pointers to the @c SrvConfig object.
 /// @name Pointers to the @c SrvConfig object.

+ 2 - 1
src/lib/dhcpsrv/tests/Makefile.am

@@ -120,7 +120,8 @@ if USE_CLANGPP
 libdhcpsrv_unittests_CXXFLAGS += -Wno-unused-variable -Wno-unused-parameter
 libdhcpsrv_unittests_CXXFLAGS += -Wno-unused-variable -Wno-unused-parameter
 endif
 endif
 
 
-libdhcpsrv_unittests_LDADD  = $(top_builddir)/src/lib/dhcpsrv/libkea-dhcpsrv.la
+libdhcpsrv_unittests_LDADD  = $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la
+libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/dhcpsrv/libkea-dhcpsrv.la
 libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/dhcpsrv/testutils/libdhcpsrvtest.la
 libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/dhcpsrv/testutils/libdhcpsrvtest.la
 libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/dhcp/tests/libdhcptest.la
 libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/dhcp/tests/libdhcptest.la
 libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la
 libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la