Browse Source

[3274] Subnets are now able to store client class information.

Tomek Mrugalski 11 years ago
parent
commit
1d945d79ff

+ 23 - 1
src/lib/dhcp/classify.h

@@ -14,6 +14,9 @@
 
 #include <config.h>
 
+#ifndef CLASSIFY_H
+#define CLASSIFY_H
+
 #include <set>
 #include <string>
 
@@ -38,8 +41,27 @@ namespace dhcp {
     typedef std::string ClientClass;
 
     /// Container for storing client classes
-    typedef std::set<ClientClass> ClientClasses;
+    ///
+    /// Depending on how you look at it, this is either a little more than just
+    /// a set of strings or a client classifier that performs access control.
+    /// For now, it is a simple access list that may contain zero or more
+    /// class names. It is expected to grow in complexity once support for
+    /// client classes becomes more feature rich.
+    class ClientClasses : public std::set<ClientClass> {
+    public:
+        /// @brief returns if class X belongs to the defined classes
+        ///
+        /// @param x client class to be checked
+        /// @return true if X belongs to the classes
+        bool
+        contains(const ClientClass& x) const {
+            const_iterator it = find(x);
+            return (it != end());
+        }
+    };
 
 };
 
 };
+
+#endif /* CLASSIFY_H */

+ 15 - 0
src/lib/dhcpsrv/subnet.cc

@@ -76,6 +76,21 @@ Subnet::setRelay(const isc::dhcp::Subnet::RelayInfo& relay) {
     relay_ = relay;
 }
 
+bool
+Subnet::clientSupported(const isc::dhcp::ClientClasses& classes) const {
+    if (white_list_.empty()) {
+        return (true); // There is no class defined for this subnet, so we do
+                       // support everyone.
+    }
+
+    return (classes.contains(white_list_));
+}
+
+void
+Subnet::allowClientClass(const isc::dhcp::ClientClass& class_name) {
+    white_list_ = class_name;
+}
+
 void
 Subnet::delOptions() {
     option_spaces_.clearItems();

+ 28 - 0
src/lib/dhcpsrv/subnet.h

@@ -24,6 +24,7 @@
 
 #include <asiolink/io_address.h>
 #include <dhcp/option.h>
+#include <dhcp/classify.h>
 #include <dhcpsrv/key_from_key.h>
 #include <dhcpsrv/option_space_container.h>
 #include <dhcpsrv/pool.h>
@@ -422,6 +423,26 @@ public:
     /// subnet object disappears.
     RelayInfo relay_;
 
+    /// @brief checks whether this subnet supports client that belongs to
+    ///        specified classes.
+    ///
+    /// This method checks whether a client that belongs to given classes can
+    /// use this subnet. For example, if this class is reserved for client
+    /// class "foo" and the client belongs to classes "foo", "bar" and "baz",
+    /// it is supported. On the other hand, client belonging to classes
+    /// "foobar" and "zyxxy" is not supported.
+    ///
+    /// @param client_classes list of all classes the client belongs to
+    /// @return true if client can be supported, false otherwise
+    bool
+    clientSupported(const isc::dhcp::ClientClasses& client_classes) const;
+
+    /// @brief adds class class_name to the list of supported classes
+    ///
+    /// @param class_name client class to be supported by this subnet
+    void
+    allowClientClass(const isc::dhcp::ClientClass& class_name);
+
 protected:
     /// @brief Returns all pools (non-const variant)
     ///
@@ -548,6 +569,13 @@ protected:
     /// @brief Name of the network interface (if connected directly)
     std::string iface_;
 
+    /// @brief optional definition of a client class
+    ///
+    /// If defined, only clients belonging to that class will be allowed to use
+    /// this particular subnet. The default value for this is "", which means
+    /// that any client is allowed, regardless of its class.
+    ClientClass white_list_;
+
 private:
 
     /// A collection of option spaces grouping option descriptors.

+ 76 - 0
src/lib/dhcpsrv/tests/subnet_unittest.cc

@@ -139,6 +139,44 @@ TEST(Subnet4Test, Subnet4_Pool4_checks) {
     EXPECT_THROW(subnet->addPool(pool3), BadValue);
 }
 
+// Tests whether Subnet4 object is able to store and process properly
+// information about allowed client classes.
+TEST(Subnet4Test, clientClasses) {
+    // Create the V4 subnet.
+    Subnet4Ptr subnet(new Subnet4(IOAddress("192.0.2.0"), 8, 1, 2, 3));
+
+    // This client does not belong to any class.
+    isc::dhcp::ClientClasses no_class;
+
+    // This client belongs to foo only.
+    isc::dhcp::ClientClasses foo_class;
+    foo_class.insert("foo");
+
+    // This client belongs to bar only. I like that client.
+    isc::dhcp::ClientClasses bar_class;
+    bar_class.insert("bar");
+
+    // This client belongs to foo, bar and baz classes.
+    isc::dhcp::ClientClasses three_classes;
+    three_classes.insert("foo");
+    three_classes.insert("bar");
+    three_classes.insert("baz");
+
+    // No class restrictions defined, any client should be supported
+    EXPECT_TRUE(subnet->clientSupported(no_class));
+    EXPECT_TRUE(subnet->clientSupported(foo_class));
+    EXPECT_TRUE(subnet->clientSupported(bar_class));
+    EXPECT_TRUE(subnet->clientSupported(three_classes));
+
+    // Let's allow only clients belongning to "bar" class.
+    subnet->allowClientClass("bar");
+
+    EXPECT_FALSE(subnet->clientSupported(no_class));
+    EXPECT_FALSE(subnet->clientSupported(foo_class));
+    EXPECT_TRUE(subnet->clientSupported(bar_class));
+    EXPECT_TRUE(subnet->clientSupported(three_classes));
+}
+
 TEST(Subnet4Test, addInvalidOption) {
     // Create the V4 subnet.
     Subnet4Ptr subnet(new Subnet4(IOAddress("192.0.2.0"), 8, 1, 2, 3));
@@ -416,6 +454,44 @@ TEST(Subnet6Test, PoolTypes) {
     EXPECT_THROW(subnet->addPool(pool5), BadValue);
 }
 
+// Tests whether Subnet6 object is able to store and process properly
+// information about allowed client classes.
+TEST(Subnet6Test, clientClasses) {
+    // Create the V6 subnet.
+    Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));
+
+    // This client does not belong to any class.
+    isc::dhcp::ClientClasses no_class;
+
+    // This client belongs to foo only.
+    isc::dhcp::ClientClasses foo_class;
+    foo_class.insert("foo");
+
+    // This client belongs to bar only. I like that client.
+    isc::dhcp::ClientClasses bar_class;
+    bar_class.insert("bar");
+
+    // This client belongs to foo, bar and baz classes.
+    isc::dhcp::ClientClasses three_classes;
+    three_classes.insert("foo");
+    three_classes.insert("bar");
+    three_classes.insert("baz");
+
+    // No class restrictions defined, any client should be supported
+    EXPECT_TRUE(subnet->clientSupported(no_class));
+    EXPECT_TRUE(subnet->clientSupported(foo_class));
+    EXPECT_TRUE(subnet->clientSupported(bar_class));
+    EXPECT_TRUE(subnet->clientSupported(three_classes));
+
+    // Let's allow only clients belongning to "bar" class.
+    subnet->allowClientClass("bar");
+
+    EXPECT_FALSE(subnet->clientSupported(no_class));
+    EXPECT_FALSE(subnet->clientSupported(foo_class));
+    EXPECT_TRUE(subnet->clientSupported(bar_class));
+    EXPECT_TRUE(subnet->clientSupported(three_classes));
+}
+
 TEST(Subnet6Test, Subnet6_Pool6_checks) {
 
     Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));