#include <config.h>
+#ifndef CLASSIFY_H
+#define CLASSIFY_H
+
#include <set>
#include <string>
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 */
#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>
/// 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)
///
/// @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.
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));
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));