Parcourir la source

Add stub code for radius support

Olivier Le Brouster il y a 7 ans
Parent
commit
5b6f0d45e8

+ 9 - 0
src/lib/dhcpsrv/Makefile.am

@@ -19,6 +19,9 @@ endif
 if HAVE_CQL
 AM_CPPFLAGS += $(CQL_CPPFLAGS)
 endif
+if HAVE_RADCLI
+AM_CPPFLAGS += $(RADCLI_CFLAGS)
+endif
 
 AM_CXXFLAGS = $(KEA_CXXFLAGS)
 
@@ -144,6 +147,9 @@ if HAVE_CQL
 libkea_dhcpsrv_la_SOURCES += cql_lease_mgr.cc cql_lease_mgr.h
 libkea_dhcpsrv_la_SOURCES += cql_connection.cc cql_connection.h
 endif
+if HAVE_RADCLI
+libkea_dhcpsrv_la_SOURCES += radius_host_data_source.cc radius_host_data_source.h
+endif
 libkea_dhcpsrv_la_SOURCES += pool.cc pool.h
 libkea_dhcpsrv_la_SOURCES += srv_config.cc srv_config.h
 libkea_dhcpsrv_la_SOURCES += subnet.cc subnet.h
@@ -206,6 +212,9 @@ endif
 if HAVE_CQL
 libkea_dhcpsrv_la_LDFLAGS += $(CQL_LIBS)
 endif
+if HAVE_RADCLI
+libkea_dhcpsrv_la_LDFLAGS += $(RADCLI_LIBS)
+endif
 
 # The message file should be in the distribution
 EXTRA_DIST += alloc_engine_messages.mes

+ 12 - 0
src/lib/dhcpsrv/host_data_source_factory.cc

@@ -18,6 +18,11 @@
 #include <dhcpsrv/pgsql_host_data_source.h>
 #endif
 
+#ifdef HAVE_RADCLI
+#include <dhcpsrv/radius_host_data_source.h>
+#endif
+
+
 #include <boost/algorithm/string.hpp>
 #include <boost/foreach.hpp>
 #include <boost/scoped_ptr.hpp>
@@ -81,6 +86,13 @@ HostDataSourceFactory::create(const std::string& dbaccess) {
     }
 #endif
 
+#ifdef HAVE_RADCLI
+    if (db_type == "radius") {
+        getHostDataSourcePtr().reset(new RadiusHostDataSource(parameters));
+        return;
+    }
+#endif
+
     // Get here on no match.
     isc_throw(InvalidType, "Hosts database access parameter 'type': " <<
                            db_type << " is invalid");

+ 228 - 0
src/lib/dhcpsrv/radius_host_data_source.cc

@@ -0,0 +1,228 @@
+// Copyright (C) 2015-2017 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 <dhcp/libdhcp++.h>
+#include <dhcp/option.h>
+#include <dhcp/option_definition.h>
+#include <dhcp/option_space.h>
+#include <dhcpsrv/cfg_option.h>
+#include <dhcpsrv/db_exceptions.h>
+#include <dhcpsrv/dhcpsrv_log.h>
+#include <dhcpsrv/radius_host_data_source.h>
+#include <dhcpsrv/db_exceptions.h>
+#include <util/buffer.h>
+#include <util/optional_value.h>
+
+#include <boost/algorithm/string/split.hpp>
+#include <boost/algorithm/string/classification.hpp>
+#include <boost/array.hpp>
+#include <boost/pointer_cast.hpp>
+#include <boost/static_assert.hpp>
+
+#include <stdint.h>
+#include <string>
+
+using namespace isc;
+using namespace isc::asiolink;
+using namespace isc::dhcp;
+using namespace isc::util;
+using namespace std;
+
+namespace {
+
+/// @brief Maximum size of an IPv6 address represented as a text string.
+///
+/// This is 32 hexadecimal characters written in 8 groups of four, plus seven
+/// colon separators.
+const size_t ADDRESS6_TEXT_MAX_LEN = 39;
+
+/// @brief Maximum length of classes stored in a dhcp4/6_client_classes
+/// columns.
+const size_t CLIENT_CLASSES_MAX_LEN = 255;
+
+/// @brief Maximum length of the hostname stored in DNS.
+///
+/// This length is restricted by the length of the domain-name carried
+/// in the Client FQDN %Option (see RFC4702 and RFC4704).
+const size_t HOSTNAME_MAX_LEN = 255;
+
+/// @brief Maximum length of option value.
+const size_t OPTION_VALUE_MAX_LEN = 4096;
+
+/// @brief Maximum length of option value specified in textual format.
+const size_t OPTION_FORMATTED_VALUE_MAX_LEN = 8192;
+
+/// @brief Maximum length of option space name.
+const size_t OPTION_SPACE_MAX_LEN = 128;
+
+/// @brief Maximum length of the server hostname.
+const size_t SERVER_HOSTNAME_MAX_LEN = 64;
+
+/// @brief Maximum length of the boot file name.
+const size_t BOOT_FILE_NAME_MAX_LEN = 128;
+
+/// @brief Numeric value representing last supported identifier.
+///
+/// This value is used to validate whether the identifier type stored in
+/// a database is within bounds. of supported identifiers.
+const uint8_t MAX_IDENTIFIER_TYPE = static_cast<uint8_t>(Host::LAST_IDENTIFIER_TYPE);
+
+namespace isc {
+namespace dhcp {
+
+RadiusHostDataSource::
+RadiusHostDataSource(const DatabaseConnection::ParameterMap& parameters) {
+    // TODO: radius session inilialisation
+}
+
+RadiusHostDataSource::~RadiusHostDataSource() {
+}
+
+void
+RadiusHostDataSource::add(const HostPtr& host) {
+    // cannot add a host with radius
+    isc_throw(NotImplemented, "RadiusHostDataSource::add not implemented");
+}
+
+bool
+RadiusHostDataSource::del(const SubnetID& subnet_id, const asiolink::IOAddress& addr) {
+    // cannot delete hosts with radius
+    isc_throw(NotImplemented, "RadiusHostDataSource::del not implemented");
+    return false;
+}
+
+bool
+RadiusHostDataSource::del4(const SubnetID& subnet_id,
+                          const Host::IdentifierType& identifier_type,
+                          const uint8_t* identifier_begin, const size_t identifier_len) {
+    // cannot delete hosts with radius
+    isc_throw(NotImplemented, "RadiusHostDataSource::del4 not implemented");
+    return false;
+}
+
+bool
+RadiusHostDataSource::del6(const SubnetID& subnet_id,
+                          const Host::IdentifierType& identifier_type,
+                          const uint8_t* identifier_begin, const size_t identifier_len) {
+    // cannot delete hosts with radius
+    isc_throw(NotImplemented, "RadiusHostDataSource::del6 not implemented");
+    return false;
+}
+
+ConstHostCollection
+RadiusHostDataSource::getAll(const HWAddrPtr& hwaddr,
+                            const DuidPtr& duid) const {
+    // TODO: libradcli call
+    return (ConstHostCollection());
+}
+
+ConstHostCollection
+RadiusHostDataSource::getAll(const Host::IdentifierType& identifier_type,
+                            const uint8_t* identifier_begin,
+                            const size_t identifier_len) const {
+    // TODO: libradcli call
+    return (ConstHostCollection());
+}
+
+ConstHostCollection
+RadiusHostDataSource::getAll4(const asiolink::IOAddress& address) const {
+    return (ConstHostCollection());
+}
+
+ConstHostPtr
+RadiusHostDataSource::get4(const SubnetID& subnet_id, const HWAddrPtr& hwaddr,
+                          const DuidPtr& duid) const {
+    // TODO: libradcli call
+    ConstHostPtr result = NULL;
+    return (result);
+}
+
+ConstHostPtr
+RadiusHostDataSource::get4(const SubnetID& subnet_id,
+                          const Host::IdentifierType& identifier_type,
+                          const uint8_t* identifier_begin,
+                          const size_t identifier_len) const {
+    // TODO: libradcli call
+    ConstHostPtr result = NULL;
+    return (result);
+}
+
+ConstHostPtr
+RadiusHostDataSource::get4(const SubnetID& subnet_id,
+                          const asiolink::IOAddress& address) const {
+    // TODO: libradcli call
+    ConstHostPtr result = NULL;
+    return (result);
+}
+
+ConstHostPtr
+RadiusHostDataSource::get6(const SubnetID& subnet_id, const DuidPtr& duid,
+                          const HWAddrPtr& hwaddr) const {
+    // TODO: libradcli call
+    ConstHostPtr result = NULL;
+    return (result);
+}
+
+ConstHostPtr
+RadiusHostDataSource::get6(const SubnetID& subnet_id,
+                          const Host::IdentifierType& identifier_type,
+                          const uint8_t* identifier_begin,
+                          const size_t identifier_len) const {
+    // TODO: libradcli call
+    ConstHostPtr result = NULL;
+    return (result);
+}
+
+ConstHostPtr
+RadiusHostDataSource::get6(const asiolink::IOAddress& prefix,
+                          const uint8_t prefix_len) const {
+    // TODO: libradcli call
+    ConstHostPtr result = NULL;
+    return (result);
+}
+
+ConstHostPtr
+RadiusHostDataSource::get6(const SubnetID& subnet_id,
+                          const asiolink::IOAddress& address) const {
+    // TODO: libradcli call
+    ConstHostPtr result = NULL;
+    return (result);
+}
+
+
+// Miscellaneous database methods.
+
+std::string RadiusHostDataSource::getName() const {
+    std::string name = "";
+    return (name);
+}
+
+std::string RadiusHostDataSource::getDescription() const {
+    return (std::string("Host data source that retrieves host information"
+                        "in radius server"));
+}
+
+std::pair<uint32_t, uint32_t> RadiusHostDataSource::getVersion() const {
+    // TODO: Not relevant for libradcli ?
+    return std::make_pair(0,0);
+}
+
+void
+RadiusHostDataSource::commit() {
+    // Not relevant for radius.
+}
+
+
+void
+RadiusHostDataSource::rollback() {
+    // Not relevant for radius.
+}
+
+
+}; // end of isc::dhcp namespace
+}; // end of isc namespace

+ 306 - 0
src/lib/dhcpsrv/radius_host_data_source.h

@@ -0,0 +1,306 @@
+// Copyright (C) 2015-2017 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/.
+
+#ifndef RADIUS_HOST_DATA_SOURCE_H
+#define RADIUS_HOST_DATA_SOURCE_H
+
+#include <dhcpsrv/base_host_data_source.h>
+#include <dhcpsrv/db_exceptions.h>
+
+namespace isc {
+namespace dhcp {
+
+/// @brief MySQL Host Data Source
+///
+/// This class implements the @ref isc::dhcp::BaseHostDataSource interface to
+/// a radius protocol.
+class RadiusHostDataSource: public BaseHostDataSource {
+public:
+
+    /// @brief Constructor
+    ///
+    /// Uses the following keywords in the parameters passed to it to
+    /// connect to the database:
+    /// - password - Password for radius
+    /// - host - Host to which to connect (optional, defaults to "localhost")
+    /// - port - Port to witch to connect (optional, defaults to 1812)
+    ///
+    /// @param parameters A data structure relating keywords and values
+    ///        concerned with the database.
+    ///
+    /// @throw isc::dhcp::NoPassword Mandatory password not given
+    /// @throw isc::dhcp::DbOpenError Error opening the database
+    /// @throw isc::dhcp::DbOperationError An operation on the open database has
+    ///        failed.
+    RadiusHostDataSource(const DatabaseConnection::ParameterMap& parameters);
+
+    /// @brief Virtual destructor.
+    ///
+    virtual ~RadiusHostDataSource();
+
+    /// @brief Return all hosts for the specified HW address or DUID.
+    ///
+    /// This method returns all @c Host objects which represent reservations
+    /// for the specified HW address or DUID. Note, that this method may
+    /// return multiple reservations because a particular client may have
+    /// reservations in multiple subnets and the same client may be identified
+    /// by HW address or DUID. The server is unable to verify that the specific
+    /// DUID and HW address belong to the same client, until the client sends
+    /// a DHCP message.
+    ///
+    /// Specifying both hardware address and DUID is allowed for this method
+    /// and results in returning all objects that are associated with hardware
+    /// address OR duid. For example: if one host is associated with the
+    /// specified hardware address and another host is associated with the
+    /// specified DUID, two hosts will be returned.
+    ///
+    /// @param hwaddr HW address of the client or NULL if no HW address
+    /// available.
+    /// @param duid client id or NULL if not available, e.g. DHCPv4 client case.
+    ///
+    /// @return Collection of const @c Host objects.
+    virtual ConstHostCollection
+    getAll(const HWAddrPtr& hwaddr, const DuidPtr& duid = DuidPtr()) const;
+
+    /// @brief Return all hosts connected to any subnet for which reservations
+    /// have been made using a specified identifier.
+    ///
+    /// This method returns all @c Host objects which represent reservations
+    /// for a specified identifier. This method may return multiple hosts
+    /// because a particular client may have reservations in multiple subnets.
+    ///
+    /// @param identifier_type Identifier type.
+    /// @param identifier_begin Pointer to a beginning of a buffer containing
+    /// an identifier.
+    /// @param identifier_len Identifier length.
+    ///
+    /// @return Collection of const @c Host objects.
+    virtual ConstHostCollection
+    getAll(const Host::IdentifierType& identifier_type,
+           const uint8_t* identifier_begin, const size_t identifier_len) const;
+
+    /// @brief Returns a collection of hosts using the specified IPv4 address.
+    ///
+    /// This method may return multiple @c Host objects if they are connected
+    /// to different subnets.
+    ///
+    /// @param address IPv4 address for which the @c Host object is searched.
+    ///
+    /// @return Collection of const @c Host objects.
+    virtual ConstHostCollection
+    getAll4(const asiolink::IOAddress& address) const;
+
+    /// @brief Returns a host connected to the IPv4 subnet.
+    ///
+    /// Implementations of this method should guard against the case when
+    /// multiple instances of the @c Host are present, e.g. when two
+    /// @c Host objects are found, one for the DUID, another one for the
+    /// HW address. In such case, an implementation of this method
+    /// should throw an MultipleRecords exception.
+    ///
+    /// @param subnet_id Subnet identifier.
+    /// @param hwaddr HW address of the client or NULL if no HW address
+    /// available.
+    /// @param duid client id or NULL if not available.
+    ///
+    /// @return Const @c Host object using a specified HW address or DUID.
+    virtual ConstHostPtr
+    get4(const SubnetID& subnet_id, const HWAddrPtr& hwaddr,
+         const DuidPtr& duid = DuidPtr()) const;
+
+    /// @brief Returns a host connected to the IPv4 subnet.
+    ///
+    /// @param subnet_id Subnet identifier.
+    /// @param identifier_type Identifier type.
+    /// @param identifier_begin Pointer to a beginning of a buffer containing
+    /// an identifier.
+    /// @param identifier_len Identifier length.
+    ///
+    /// @return Const @c Host object for which reservation has been made using
+    /// the specified identifier.
+    virtual ConstHostPtr
+    get4(const SubnetID& subnet_id, const Host::IdentifierType& identifier_type,
+         const uint8_t* identifier_begin, const size_t identifier_len) const;
+
+    /// @brief Returns a host connected to the IPv4 subnet and having
+    /// a reservation for a specified IPv4 address.
+    ///
+    /// One of the use cases for this method is to detect collisions between
+    /// dynamically allocated addresses and reserved addresses. When the new
+    /// address is assigned to a client, the allocation mechanism should check
+    /// if this address is not reserved for some other host and do not allocate
+    /// this address if reservation is present.
+    ///
+    /// Implementations of this method should guard against invalid addresses,
+    /// such as IPv6 address.
+    ///
+    /// @param subnet_id Subnet identifier.
+    /// @param address reserved IPv4 address.
+    ///
+    /// @return Const @c Host object using a specified IPv4 address.
+    virtual ConstHostPtr
+    get4(const SubnetID& subnet_id, const asiolink::IOAddress& address) const;
+
+    /// @brief Returns a host connected to the IPv6 subnet.
+    ///
+    /// Implementations of this method should guard against the case when
+    /// multiple instances of the @c Host are present, e.g. when two
+    /// @c Host objects are found, one for the DUID, another one for the
+    /// HW address. In such case, an implementation of this method
+    /// should throw an MultipleRecords exception.
+    ///
+    /// @param subnet_id Subnet identifier.
+    /// @param hwaddr HW address of the client or NULL if no HW address
+    /// available.
+    /// @param duid DUID or NULL if not available.
+    ///
+    /// @return Const @c Host object using a specified HW address or DUID.
+    virtual ConstHostPtr
+    get6(const SubnetID& subnet_id, const DuidPtr& duid,
+            const HWAddrPtr& hwaddr = HWAddrPtr()) const;
+
+    /// @brief Returns a host connected to the IPv6 subnet.
+    ///
+    /// @param subnet_id Subnet identifier.
+    /// @param identifier_type Identifier type.
+    /// @param identifier_begin Pointer to a beginning of a buffer containing
+    /// an identifier.
+    /// @param identifier_len Identifier length.
+    ///
+    /// @return Const @c Host object for which reservation has been made using
+    /// the specified identifier.
+    virtual ConstHostPtr
+    get6(const SubnetID& subnet_id, const Host::IdentifierType& identifier_type,
+         const uint8_t* identifier_begin, const size_t identifier_len) const;
+
+    /// @brief Returns a host using the specified IPv6 prefix.
+    ///
+    /// @param prefix IPv6 prefix for which the @c Host object is searched.
+    /// @param prefix_len IPv6 prefix length.
+    ///
+    /// @return Const @c Host object using a specified HW address or DUID.
+    virtual ConstHostPtr
+    get6(const asiolink::IOAddress& prefix, const uint8_t prefix_len) const;
+
+    /// @brief Returns a host connected to the IPv6 subnet and having
+    /// a reservation for a specified IPv6 address or prefix.
+    ///
+    /// @param subnet_id Subnet identifier.
+    /// @param address reserved IPv6 address/prefix.
+    ///
+    /// @return Const @c Host object using a specified IPv6 address/prefix.
+    virtual ConstHostPtr
+    get6(const SubnetID& subnet_id, const asiolink::IOAddress& address) const;
+
+    /// @brief Adds a new host to the collection.
+    ///
+    /// It is not possible to add a new host in radius backend.
+    //
+    /// The implementations of this method should guard against duplicate
+    /// reservations for the same host, where possible. For example, when the
+    /// reservation for the same HW address and subnet id is added twice, the
+    /// addHost method should throw an DuplicateEntry exception. Note, that
+    /// usually it is impossible to guard against adding duplicated host, where
+    /// one instance is identified by HW address, another one by DUID.
+    ///
+    /// @param host Pointer to the new @c Host object being added.
+    virtual void add(const HostPtr& host);
+
+    /// @brief Attempts to delete a host by (subnet-id, address)
+    ///
+    /// It is not possible to delete a host in radius backend.
+    ///
+    /// This method supports both v4 and v6.
+    ///
+    /// @param subnet_id subnet identifier.
+    /// @param addr specified address.
+    /// @return true if deletion was successful, false if the host was not there.
+    /// @throw various exceptions in case of errors
+    virtual bool del(const SubnetID& subnet_id, const asiolink::IOAddress& addr);
+
+    /// @brief Attempts to delete a host by (subnet4-id, identifier type, identifier)
+    ///
+    /// It is not possible to delete a host in radius backend.
+    ///
+    /// This method supports v4 hosts only.
+    ///
+    /// @param subnet_id subnet identifier.
+    /// @param addr specified address.
+    /// @return true if deletion was successful, false if the host was not there.
+    /// @throw various exceptions in case of errors
+    virtual bool del4(const SubnetID& subnet_id,
+                      const Host::IdentifierType& identifier_type,
+                      const uint8_t* identifier_begin, const size_t identifier_len);
+
+    /// @brief Attempts to delete a host by (subnet6-id, identifier type, identifier)
+    ///
+    /// It is not possible to delete a host in radius backend.
+    ///
+    /// This method supports v6 hosts only.
+    ///
+    /// @param subnet_id subnet identifier.
+    /// @param addr specified address.
+    /// @return true if deletion was successful, false if the host was not there.
+    /// @throw various exceptions in case of errors
+    virtual bool del6(const SubnetID& subnet_id,
+                      const Host::IdentifierType& identifier_type,
+                      const uint8_t* identifier_begin, const size_t identifier_len);
+
+    /// @brief Return backend type
+    ///
+    /// Returns the type of the backend (e.g. "radius", "memfile" etc.)
+    ///
+    /// @return Type of the backend.
+    virtual std::string getType() const {
+        return (std::string("radius"));
+    }
+
+    /// @brief Returns backend name.
+    ///
+    /// Each backend have specific name.
+    ///
+    /// @return "radius".
+    virtual std::string getName() const;
+
+    /// @brief Returns description of the backend.
+    ///
+    /// This description may be multiline text that describes the backend.
+    ///
+    /// @return Description of the backend.
+    virtual std::string getDescription() const;
+
+    /// @brief Returns backend version.
+    ///
+    /// @return Version number stored in the database, as a pair of unsigned
+    ///         integers. "first" is the major version number, "second" the
+    ///         minor number.
+    ///
+    /// @throw isc::dhcp::DbOperationError An operation on the open database
+    ///        has failed.
+    virtual std::pair<uint32_t, uint32_t> getVersion() const;
+
+    /// @brief Commit Transactions
+    ///
+    /// Not relevant for radius backend.
+    ///
+    /// Commits all pending database operations.
+    virtual void commit();
+
+    /// @brief Rollback Transactions
+    ///
+    /// Not relevant for radius backend.
+    ///
+    /// Rolls back all pending database operations.
+    virtual void rollback();
+
+private:
+
+};
+
+}
+}
+
+#endif // RADIUS_HOST_DATA_SOURCE_H