Commit 1d945d79 authored by Tomek Mrugalski's avatar Tomek Mrugalski 🛰
Browse files

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

parent bc216c2c
......@@ -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 */
......@@ -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();
......
......@@ -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.
......
......@@ -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));
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment