summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFrancis Dupont <fdupont@isc.org>2024-10-08 16:10:13 +0200
committerFrancis Dupont <fdupont@isc.org>2024-10-11 10:18:01 +0200
commitdc8af16a6eaf6cdcf54c63f4e050f4b052261b47 (patch)
treeabd0c72599ca0b4dae4c478ccacc3ef12c652243
parent[#3585] Completed changelog (diff)
downloadkea-dc8af16a6eaf6cdcf54c63f4e050f4b052261b47.tar.xz
kea-dc8af16a6eaf6cdcf54c63f4e050f4b052261b47.zip
[#3588] Modified no test required classes
-rw-r--r--changelog_unreleased/3588-required-no-test6
-rw-r--r--changelog_unreleased/3590-required-precedence (renamed from changelog_unreleased/3590-required-precence)0
-rw-r--r--doc/sphinx/arm/dhcp4-srv.rst4
-rw-r--r--doc/sphinx/arm/dhcp6-srv.rst4
-rw-r--r--src/bin/dhcp4/dhcp4_messages.cc8
-rw-r--r--src/bin/dhcp4/dhcp4_messages.h4
-rw-r--r--src/bin/dhcp4/dhcp4_messages.mes21
-rw-r--r--src/bin/dhcp4/dhcp4_srv.cc10
-rw-r--r--src/bin/dhcp4/tests/classify_unittest.cc94
-rw-r--r--src/bin/dhcp6/dhcp6_messages.cc8
-rw-r--r--src/bin/dhcp6/dhcp6_messages.h4
-rw-r--r--src/bin/dhcp6/dhcp6_messages.mes21
-rw-r--r--src/bin/dhcp6/dhcp6_srv.cc10
-rw-r--r--src/bin/dhcp6/tests/classify_unittest.cc100
14 files changed, 256 insertions, 38 deletions
diff --git a/changelog_unreleased/3588-required-no-test b/changelog_unreleased/3588-required-no-test
new file mode 100644
index 0000000000..0f2b9e0f19
--- /dev/null
+++ b/changelog_unreleased/3588-required-no-test
@@ -0,0 +1,6 @@
+[func]* fdupont
+ Modified the behavior of required client classes
+ configured without a test expression: they are now
+ unconditionally added as they always evaluate to
+ true (vs false previously).
+ (Gitlab #3388)
diff --git a/changelog_unreleased/3590-required-precence b/changelog_unreleased/3590-required-precedence
index c9c09dbb3d..c9c09dbb3d 100644
--- a/changelog_unreleased/3590-required-precence
+++ b/changelog_unreleased/3590-required-precedence
diff --git a/doc/sphinx/arm/dhcp4-srv.rst b/doc/sphinx/arm/dhcp4-srv.rst
index 3eb08147cd..b0a30cceca 100644
--- a/doc/sphinx/arm/dhcp4-srv.rst
+++ b/doc/sphinx/arm/dhcp4-srv.rst
@@ -3423,6 +3423,10 @@ The order in which required classes are considered is: pool, subnet,
and shared network, i.e. in the same order from the way in which
``option-data`` is processed.
+Since Kea version 2.7.4 required client classes configured without
+a test expression are unconditionally added, i.e. they are considered
+to always be evaluated to ``true``.
+
.. note::
Vendor-Identifying Vendor Options are a special case: for all other
diff --git a/doc/sphinx/arm/dhcp6-srv.rst b/doc/sphinx/arm/dhcp6-srv.rst
index 29bc86481f..1f03f70a16 100644
--- a/doc/sphinx/arm/dhcp6-srv.rst
+++ b/doc/sphinx/arm/dhcp6-srv.rst
@@ -3201,6 +3201,10 @@ levels. The order in which required classes are considered is:
(pd-)pool, subnet, and shared network, i.e. in the same order from the
way in which ``option-data`` is processed.
+Since Kea version 2.7.4 required client classes configured without
+a test expression are unconditionally added, i.e. they are considered
+to always be evaluated to ``true``.
+
.. _dhcp6-ddns-config:
DDNS for DHCPv6
diff --git a/src/bin/dhcp4/dhcp4_messages.cc b/src/bin/dhcp4/dhcp4_messages.cc
index 9d4cedc5e4..81d191c925 100644
--- a/src/bin/dhcp4/dhcp4_messages.cc
+++ b/src/bin/dhcp4/dhcp4_messages.cc
@@ -19,8 +19,6 @@ extern const isc::log::MessageID DHCP4_CLASSES_ASSIGNED = "DHCP4_CLASSES_ASSIGNE
extern const isc::log::MessageID DHCP4_CLASSES_ASSIGNED_AFTER_SUBNET_SELECTION = "DHCP4_CLASSES_ASSIGNED_AFTER_SUBNET_SELECTION";
extern const isc::log::MessageID DHCP4_CLASS_ASSIGNED = "DHCP4_CLASS_ASSIGNED";
extern const isc::log::MessageID DHCP4_CLASS_UNCONFIGURED = "DHCP4_CLASS_UNCONFIGURED";
-extern const isc::log::MessageID DHCP4_CLASS_UNDEFINED = "DHCP4_CLASS_UNDEFINED";
-extern const isc::log::MessageID DHCP4_CLASS_UNTESTABLE = "DHCP4_CLASS_UNTESTABLE";
extern const isc::log::MessageID DHCP4_CLIENTID_IGNORED_FOR_LEASES = "DHCP4_CLIENTID_IGNORED_FOR_LEASES";
extern const isc::log::MessageID DHCP4_CLIENT_FQDN_DATA = "DHCP4_CLIENT_FQDN_DATA";
extern const isc::log::MessageID DHCP4_CLIENT_FQDN_PROCESS = "DHCP4_CLIENT_FQDN_PROCESS";
@@ -150,6 +148,8 @@ extern const isc::log::MessageID DHCP4_RELEASE_FAIL_WRONG_CLIENT = "DHCP4_RELEAS
extern const isc::log::MessageID DHCP4_REQUEST = "DHCP4_REQUEST";
extern const isc::log::MessageID DHCP4_REQUIRED_CLASS_EVAL_ERROR = "DHCP4_REQUIRED_CLASS_EVAL_ERROR";
extern const isc::log::MessageID DHCP4_REQUIRED_CLASS_EVAL_RESULT = "DHCP4_REQUIRED_CLASS_EVAL_RESULT";
+extern const isc::log::MessageID DHCP4_REQUIRED_CLASS_UNDEFINED = "DHCP4_REQUIRED_CLASS_UNDEFINED";
+extern const isc::log::MessageID DHCP4_REQUIRED_CLASS_UNTESTABLE = "DHCP4_REQUIRED_CLASS_UNTESTABLE";
extern const isc::log::MessageID DHCP4_RESERVATIONS_LOOKUP_FIRST_ENABLED = "DHCP4_RESERVATIONS_LOOKUP_FIRST_ENABLED";
extern const isc::log::MessageID DHCP4_RESERVED_HOSTNAME_ASSIGNED = "DHCP4_RESERVED_HOSTNAME_ASSIGNED";
extern const isc::log::MessageID DHCP4_RESPONSE_DATA = "DHCP4_RESPONSE_DATA";
@@ -197,8 +197,6 @@ const char* values[] = {
"DHCP4_CLASSES_ASSIGNED_AFTER_SUBNET_SELECTION", "%1: client packet has been assigned to the following classes: %2",
"DHCP4_CLASS_ASSIGNED", "%1: client packet has been assigned to the following class: %2",
"DHCP4_CLASS_UNCONFIGURED", "%1: client packet belongs to an unconfigured class: %2",
- "DHCP4_CLASS_UNDEFINED", "required class %1 has no definition",
- "DHCP4_CLASS_UNTESTABLE", "required class %1 has no test expression",
"DHCP4_CLIENTID_IGNORED_FOR_LEASES", "%1: not using client identifier for lease allocation for subnet %2",
"DHCP4_CLIENT_FQDN_DATA", "%1: Client sent FQDN option: %2",
"DHCP4_CLIENT_FQDN_PROCESS", "%1: processing Client FQDN option",
@@ -328,6 +326,8 @@ const char* values[] = {
"DHCP4_REQUEST", "%1: server is processing DHCPREQUEST with hint=%2",
"DHCP4_REQUIRED_CLASS_EVAL_ERROR", "%1: Expression '%2' evaluated to %3",
"DHCP4_REQUIRED_CLASS_EVAL_RESULT", "%1: Expression '%2' evaluated to %3",
+ "DHCP4_REQUIRED_CLASS_UNDEFINED", "required class %1 has no definition",
+ "DHCP4_REQUIRED_CLASS_UNTESTABLE", "required class %1 has no test expression",
"DHCP4_RESERVATIONS_LOOKUP_FIRST_ENABLED", "Multi-threading is enabled and host reservations lookup is always performed first.",
"DHCP4_RESERVED_HOSTNAME_ASSIGNED", "%1: server assigned reserved hostname %2",
"DHCP4_RESPONSE_DATA", "%1: responding with packet %2 (type %3), packet details: %4",
diff --git a/src/bin/dhcp4/dhcp4_messages.h b/src/bin/dhcp4/dhcp4_messages.h
index 2005b255f4..00e60df071 100644
--- a/src/bin/dhcp4/dhcp4_messages.h
+++ b/src/bin/dhcp4/dhcp4_messages.h
@@ -20,8 +20,6 @@ extern const isc::log::MessageID DHCP4_CLASSES_ASSIGNED;
extern const isc::log::MessageID DHCP4_CLASSES_ASSIGNED_AFTER_SUBNET_SELECTION;
extern const isc::log::MessageID DHCP4_CLASS_ASSIGNED;
extern const isc::log::MessageID DHCP4_CLASS_UNCONFIGURED;
-extern const isc::log::MessageID DHCP4_CLASS_UNDEFINED;
-extern const isc::log::MessageID DHCP4_CLASS_UNTESTABLE;
extern const isc::log::MessageID DHCP4_CLIENTID_IGNORED_FOR_LEASES;
extern const isc::log::MessageID DHCP4_CLIENT_FQDN_DATA;
extern const isc::log::MessageID DHCP4_CLIENT_FQDN_PROCESS;
@@ -151,6 +149,8 @@ extern const isc::log::MessageID DHCP4_RELEASE_FAIL_WRONG_CLIENT;
extern const isc::log::MessageID DHCP4_REQUEST;
extern const isc::log::MessageID DHCP4_REQUIRED_CLASS_EVAL_ERROR;
extern const isc::log::MessageID DHCP4_REQUIRED_CLASS_EVAL_RESULT;
+extern const isc::log::MessageID DHCP4_REQUIRED_CLASS_UNDEFINED;
+extern const isc::log::MessageID DHCP4_REQUIRED_CLASS_UNTESTABLE;
extern const isc::log::MessageID DHCP4_RESERVATIONS_LOOKUP_FIRST_ENABLED;
extern const isc::log::MessageID DHCP4_RESERVED_HOSTNAME_ASSIGNED;
extern const isc::log::MessageID DHCP4_RESPONSE_DATA;
diff --git a/src/bin/dhcp4/dhcp4_messages.mes b/src/bin/dhcp4/dhcp4_messages.mes
index 98a4609bb3..41cb5652a4 100644
--- a/src/bin/dhcp4/dhcp4_messages.mes
+++ b/src/bin/dhcp4/dhcp4_messages.mes
@@ -94,16 +94,6 @@ which cannot be found in the configuration. Either a hook written
before the classification was added to Kea is used, or class naming is
inconsistent.
-% DHCP4_CLASS_UNDEFINED required class %1 has no definition
-Logged at debug log level 40.
-This debug message informs that a class is listed for required evaluation but
-has no definition.
-
-% DHCP4_CLASS_UNTESTABLE required class %1 has no test expression
-Logged at debug log level 40.
-This debug message informs that a class was listed for required evaluation but
-its definition does not include a test expression to evaluate.
-
% DHCP4_CLIENTID_IGNORED_FOR_LEASES %1: not using client identifier for lease allocation for subnet %2
Logged at debug log level 50.
This debug message is issued when the server is processing the DHCPv4 message
@@ -989,6 +979,17 @@ This debug message indicates that the expression of a required client class has
been successfully evaluated. The client class name and the result value of the
evaluation are printed.
+% DHCP4_REQUIRED_CLASS_UNDEFINED required class %1 has no definition
+Logged at debug log level 40.
+This debug message informs that a class is listed for required evaluation but
+has no definition. The class is ignored.
+
+% DHCP4_REQUIRED_CLASS_UNTESTABLE required class %1 has no test expression
+Logged at debug log level 40.
+This debug message informs that a class was listed for required evaluation but
+its definition does not include a test expression to evaluate. The class is
+unconditionally added to the query.
+
% DHCP4_RESERVATIONS_LOOKUP_FIRST_ENABLED Multi-threading is enabled and host reservations lookup is always performed first.
This is a message informing that host reservations lookup is performed before
lease lookup when multi-threading is enabled overwriting configured value.
diff --git a/src/bin/dhcp4/dhcp4_srv.cc b/src/bin/dhcp4/dhcp4_srv.cc
index 107874f12b..7dc53314ab 100644
--- a/src/bin/dhcp4/dhcp4_srv.cc
+++ b/src/bin/dhcp4/dhcp4_srv.cc
@@ -4866,15 +4866,19 @@ void Dhcpv4Srv::requiredClassify(Dhcpv4Exchange& ex) {
for (auto const& cclass : classes) {
const ClientClassDefPtr class_def = dict->findClass(cclass);
if (!class_def) {
- LOG_DEBUG(dhcp4_logger, DBG_DHCP4_BASIC, DHCP4_CLASS_UNDEFINED)
+ LOG_DEBUG(dhcp4_logger, DBG_DHCP4_BASIC,
+ DHCP4_REQUIRED_CLASS_UNDEFINED)
.arg(cclass);
+ // Ignore it as it can't have an attached action
continue;
}
const ExpressionPtr& expr_ptr = class_def->getMatchExpr();
- // Nothing to do without an expression to evaluate
+ // Add a class without an expression to evaluate
if (!expr_ptr) {
- LOG_DEBUG(dhcp4_logger, DBG_DHCP4_BASIC, DHCP4_CLASS_UNTESTABLE)
+ LOG_DEBUG(dhcp4_logger, DBG_DHCP4_BASIC,
+ DHCP4_REQUIRED_CLASS_UNTESTABLE)
.arg(cclass);
+ query->addClass(cclass);
continue;
}
// Evaluate the expression which can return false (no match),
diff --git a/src/bin/dhcp4/tests/classify_unittest.cc b/src/bin/dhcp4/tests/classify_unittest.cc
index b8bf032497..a0fe8bff1d 100644
--- a/src/bin/dhcp4/tests/classify_unittest.cc
+++ b/src/bin/dhcp4/tests/classify_unittest.cc
@@ -1238,6 +1238,100 @@ TEST_F(ClassifyTest, precedenceNetwork) {
EXPECT_EQ("10.0.0.3", addrs[0].toText());
}
+// This test checks a required class without a test entry can be
+// unconditionally added.
+TEST_F(ClassifyTest, requiredNoTest) {
+ std::string config =
+ "{"
+ "\"interfaces-config\": {"
+ " \"interfaces\": [ \"*\" ]"
+ "},"
+ "\"valid-lifetime\": 600,"
+ "\"client-classes\": ["
+ " {"
+ " \"name\": \"for-network\","
+ " \"option-data\": [ {"
+ " \"name\": \"domain-name-servers\","
+ " \"data\": \"10.0.0.3\""
+ " } ]"
+ " }"
+ "],"
+ "\"shared-networks\": [ {"
+ " \"name\": \"frog\","
+ " \"require-client-classes\": [ \"for-network\" ],"
+ " \"subnet4\": [ { "
+ " \"subnet\": \"10.0.0.0/24\","
+ " \"id\": 1,"
+ " \"pools\": [ { "
+ " \"pool\": \"10.0.0.10-10.0.0.100\""
+ " } ]"
+ " } ]"
+ "} ]"
+ "}";
+
+ // Create a client requesting domain-name-servers option
+ Dhcp4Client client(Dhcp4Client::SELECTING);
+ client.requestOptions(DHO_DOMAIN_NAME_SERVERS);
+
+ // Load the config and perform a DORA
+ configure(config, *client.getServer());
+ ASSERT_NO_THROW(client.doDORA());
+
+ // Check response
+ Pkt4Ptr resp = client.getContext().response_;
+ ASSERT_TRUE(resp);
+ EXPECT_EQ("10.0.0.10", resp->getYiaddr().toText());
+
+ // Check domain-name-servers option
+ OptionPtr opt = resp->getOption(DHO_DOMAIN_NAME_SERVERS);
+ ASSERT_TRUE(opt);
+ Option4AddrLstPtr servers =
+ boost::dynamic_pointer_cast<Option4AddrLst>(opt);
+ ASSERT_TRUE(servers);
+ auto addrs = servers->getAddresses();
+ ASSERT_EQ(1, addrs.size());
+ EXPECT_EQ("10.0.0.3", addrs[0].toText());
+}
+
+// This test checks a required class which is not defined is ignored.
+TEST_F(ClassifyTest, requiredNoDefined) {
+ std::string config =
+ "{"
+ "\"interfaces-config\": {"
+ " \"interfaces\": [ \"*\" ]"
+ "},"
+ "\"valid-lifetime\": 600,"
+ "\"shared-networks\": [ {"
+ " \"name\": \"frog\","
+ " \"require-client-classes\": [ \"for-network\" ],"
+ " \"subnet4\": [ { "
+ " \"subnet\": \"10.0.0.0/24\","
+ " \"id\": 1,"
+ " \"pools\": [ { "
+ " \"pool\": \"10.0.0.10-10.0.0.100\""
+ " } ]"
+ " } ]"
+ "} ]"
+ "}";
+
+ // Create a client requesting domain-name-servers option
+ Dhcp4Client client(Dhcp4Client::SELECTING);
+ client.requestOptions(DHO_DOMAIN_NAME_SERVERS);
+
+ // Load the config and perform a DORA
+ configure(config, *client.getServer());
+ ASSERT_NO_THROW(client.doDORA());
+
+ // Check response
+ Pkt4Ptr resp = client.getContext().response_;
+ ASSERT_TRUE(resp);
+ EXPECT_EQ("10.0.0.10", resp->getYiaddr().toText());
+
+ // Check domain-name-servers option
+ OptionPtr opt = resp->getOption(DHO_DOMAIN_NAME_SERVERS);
+ EXPECT_FALSE(opt);
+}
+
// This test checks the handling for the DROP special class.
TEST_F(ClassifyTest, dropClass) {
Dhcp4Client client(Dhcp4Client::SELECTING);
diff --git a/src/bin/dhcp6/dhcp6_messages.cc b/src/bin/dhcp6/dhcp6_messages.cc
index 3b436d8876..af7d80707d 100644
--- a/src/bin/dhcp6/dhcp6_messages.cc
+++ b/src/bin/dhcp6/dhcp6_messages.cc
@@ -21,8 +21,6 @@ extern const isc::log::MessageID DHCP6_CLASSES_ASSIGNED = "DHCP6_CLASSES_ASSIGNE
extern const isc::log::MessageID DHCP6_CLASSES_ASSIGNED_AFTER_SUBNET_SELECTION = "DHCP6_CLASSES_ASSIGNED_AFTER_SUBNET_SELECTION";
extern const isc::log::MessageID DHCP6_CLASS_ASSIGNED = "DHCP6_CLASS_ASSIGNED";
extern const isc::log::MessageID DHCP6_CLASS_UNCONFIGURED = "DHCP6_CLASS_UNCONFIGURED";
-extern const isc::log::MessageID DHCP6_CLASS_UNDEFINED = "DHCP6_CLASS_UNDEFINED";
-extern const isc::log::MessageID DHCP6_CLASS_UNTESTABLE = "DHCP6_CLASS_UNTESTABLE";
extern const isc::log::MessageID DHCP6_CONFIG_COMPLETE = "DHCP6_CONFIG_COMPLETE";
extern const isc::log::MessageID DHCP6_CONFIG_LOAD_FAIL = "DHCP6_CONFIG_LOAD_FAIL";
extern const isc::log::MessageID DHCP6_CONFIG_PACKET_QUEUE = "DHCP6_CONFIG_PACKET_QUEUE";
@@ -149,6 +147,8 @@ extern const isc::log::MessageID DHCP6_RELEASE_PD_FAIL_WRONG_DUID = "DHCP6_RELEA
extern const isc::log::MessageID DHCP6_RELEASE_PD_FAIL_WRONG_IAID = "DHCP6_RELEASE_PD_FAIL_WRONG_IAID";
extern const isc::log::MessageID DHCP6_REQUIRED_CLASS_EVAL_ERROR = "DHCP6_REQUIRED_CLASS_EVAL_ERROR";
extern const isc::log::MessageID DHCP6_REQUIRED_CLASS_EVAL_RESULT = "DHCP6_REQUIRED_CLASS_EVAL_RESULT";
+extern const isc::log::MessageID DHCP6_REQUIRED_CLASS_UNDEFINED = "DHCP6_REQUIRED_CLASS_UNDEFINED";
+extern const isc::log::MessageID DHCP6_REQUIRED_CLASS_UNTESTABLE = "DHCP6_REQUIRED_CLASS_UNTESTABLE";
extern const isc::log::MessageID DHCP6_REQUIRED_OPTIONS_CHECK_FAIL = "DHCP6_REQUIRED_OPTIONS_CHECK_FAIL";
extern const isc::log::MessageID DHCP6_RESERVATIONS_LOOKUP_FIRST_ENABLED = "DHCP6_RESERVATIONS_LOOKUP_FIRST_ENABLED";
extern const isc::log::MessageID DHCP6_RESPONSE_DATA = "DHCP6_RESPONSE_DATA";
@@ -188,8 +188,6 @@ const char* values[] = {
"DHCP6_CLASSES_ASSIGNED_AFTER_SUBNET_SELECTION", "%1: client packet has been assigned to the following classes: %2",
"DHCP6_CLASS_ASSIGNED", "%1: client packet has been assigned to the following class: %2",
"DHCP6_CLASS_UNCONFIGURED", "%1: client packet belongs to an unconfigured class: %2",
- "DHCP6_CLASS_UNDEFINED", "required class %1 has no definition",
- "DHCP6_CLASS_UNTESTABLE", "required class %1 has no test expression",
"DHCP6_CONFIG_COMPLETE", "DHCPv6 server has completed configuration: %1",
"DHCP6_CONFIG_LOAD_FAIL", "configuration error using file: %1, reason: %2",
"DHCP6_CONFIG_PACKET_QUEUE", "DHCPv6 packet queue info after configuration: %1",
@@ -316,6 +314,8 @@ const char* values[] = {
"DHCP6_RELEASE_PD_FAIL_WRONG_IAID", "%1: client tried to release prefix %2/%3, but it used wrong IAID (expected %4, but got %5)",
"DHCP6_REQUIRED_CLASS_EVAL_ERROR", "%1: Expression '%2' evaluated to %3",
"DHCP6_REQUIRED_CLASS_EVAL_RESULT", "%1: Expression '%2' evaluated to %3",
+ "DHCP6_REQUIRED_CLASS_UNDEFINED", "required class %1 has no definition",
+ "DHCP6_REQUIRED_CLASS_UNTESTABLE", "required class %1 has no test expression",
"DHCP6_REQUIRED_OPTIONS_CHECK_FAIL", "%1: %2 message received from %3 failed the following check: %4",
"DHCP6_RESERVATIONS_LOOKUP_FIRST_ENABLED", "Multi-threading is enabled and host reservations lookup is always performed first.",
"DHCP6_RESPONSE_DATA", "%1: responding with packet %2 (type %3), packet details: %4",
diff --git a/src/bin/dhcp6/dhcp6_messages.h b/src/bin/dhcp6/dhcp6_messages.h
index dcd9a5af47..2faa9cee77 100644
--- a/src/bin/dhcp6/dhcp6_messages.h
+++ b/src/bin/dhcp6/dhcp6_messages.h
@@ -22,8 +22,6 @@ extern const isc::log::MessageID DHCP6_CLASSES_ASSIGNED;
extern const isc::log::MessageID DHCP6_CLASSES_ASSIGNED_AFTER_SUBNET_SELECTION;
extern const isc::log::MessageID DHCP6_CLASS_ASSIGNED;
extern const isc::log::MessageID DHCP6_CLASS_UNCONFIGURED;
-extern const isc::log::MessageID DHCP6_CLASS_UNDEFINED;
-extern const isc::log::MessageID DHCP6_CLASS_UNTESTABLE;
extern const isc::log::MessageID DHCP6_CONFIG_COMPLETE;
extern const isc::log::MessageID DHCP6_CONFIG_LOAD_FAIL;
extern const isc::log::MessageID DHCP6_CONFIG_PACKET_QUEUE;
@@ -150,6 +148,8 @@ extern const isc::log::MessageID DHCP6_RELEASE_PD_FAIL_WRONG_DUID;
extern const isc::log::MessageID DHCP6_RELEASE_PD_FAIL_WRONG_IAID;
extern const isc::log::MessageID DHCP6_REQUIRED_CLASS_EVAL_ERROR;
extern const isc::log::MessageID DHCP6_REQUIRED_CLASS_EVAL_RESULT;
+extern const isc::log::MessageID DHCP6_REQUIRED_CLASS_UNDEFINED;
+extern const isc::log::MessageID DHCP6_REQUIRED_CLASS_UNTESTABLE;
extern const isc::log::MessageID DHCP6_REQUIRED_OPTIONS_CHECK_FAIL;
extern const isc::log::MessageID DHCP6_RESERVATIONS_LOOKUP_FIRST_ENABLED;
extern const isc::log::MessageID DHCP6_RESPONSE_DATA;
diff --git a/src/bin/dhcp6/dhcp6_messages.mes b/src/bin/dhcp6/dhcp6_messages.mes
index 3e3a08836e..6fb9072a7d 100644
--- a/src/bin/dhcp6/dhcp6_messages.mes
+++ b/src/bin/dhcp6/dhcp6_messages.mes
@@ -112,16 +112,6 @@ which cannot be found in the configuration. Either a hook written
before the classification was added to Kea is used, or class naming is
inconsistent.
-% DHCP6_CLASS_UNDEFINED required class %1 has no definition
-Logged at debug log level 40.
-This debug message informs that a class is listed for required evaluation but
-has no definition.
-
-% DHCP6_CLASS_UNTESTABLE required class %1 has no test expression
-Logged at debug log level 40.
-This debug message informs that a class was listed for required evaluation but
-its definition does not include a test expression to evaluate.
-
% DHCP6_CONFIG_COMPLETE DHCPv6 server has completed configuration: %1
This is an informational message announcing the successful processing of a
new configuration. it is output during server startup, and when an updated
@@ -994,6 +984,17 @@ This debug message indicates that the expression of a required client class has
been successfully evaluated. The client class name and the result value of the
evaluation are printed.
+% DHCP6_REQUIRED_CLASS_UNDEFINED required class %1 has no definition
+Logged at debug log level 40.
+This debug message informs that a class is listed for required evaluation but
+has no definition. The class is ignored.
+
+% DHCP6_REQUIRED_CLASS_UNTESTABLE required class %1 has no test expression
+Logged at debug log level 40.
+This debug message informs that a class was listed for required evaluation but
+its definition does not include a test expression to evaluate. The class is
+unconditionally added to the query.
+
% DHCP6_REQUIRED_OPTIONS_CHECK_FAIL %1: %2 message received from %3 failed the following check: %4
Logged at debug log level 40.
This message indicates that received DHCPv6 packet is invalid. This may be due
diff --git a/src/bin/dhcp6/dhcp6_srv.cc b/src/bin/dhcp6/dhcp6_srv.cc
index 6df6460603..ee4841e16e 100644
--- a/src/bin/dhcp6/dhcp6_srv.cc
+++ b/src/bin/dhcp6/dhcp6_srv.cc
@@ -4495,15 +4495,19 @@ Dhcpv6Srv::requiredClassify(const Pkt6Ptr& pkt, AllocEngine::ClientContext6& ctx
for (auto const& cclass : classes) {
const ClientClassDefPtr class_def = dict->findClass(cclass);
if (!class_def) {
- LOG_DEBUG(dhcp6_logger, DBG_DHCP6_BASIC, DHCP6_CLASS_UNDEFINED)
+ LOG_DEBUG(dhcp6_logger, DBG_DHCP6_BASIC,
+ DHCP6_REQUIRED_CLASS_UNDEFINED)
.arg(cclass);
+ // Ignore it as it can't have an attached action
continue;
}
const ExpressionPtr& expr_ptr = class_def->getMatchExpr();
- // Nothing to do without an expression to evaluate
+ // Add a class without an expression to evaluate
if (!expr_ptr) {
- LOG_DEBUG(dhcp6_logger, DBG_DHCP6_BASIC, DHCP6_CLASS_UNTESTABLE)
+ LOG_DEBUG(dhcp6_logger, DBG_DHCP6_BASIC,
+ DHCP6_REQUIRED_CLASS_UNTESTABLE)
.arg(cclass);
+ pkt->addClass(cclass);
continue;
}
// Evaluate the expression which can return false (no match),
diff --git a/src/bin/dhcp6/tests/classify_unittest.cc b/src/bin/dhcp6/tests/classify_unittest.cc
index 2892076aba..a090f84406 100644
--- a/src/bin/dhcp6/tests/classify_unittest.cc
+++ b/src/bin/dhcp6/tests/classify_unittest.cc
@@ -2268,6 +2268,106 @@ TEST_F(ClassifyTest, precedenceNetwork) {
EXPECT_EQ("2001:db8:1::3", addrs[0].toText());
}
+// This test checks a required class without a test entry can be
+// unconditionally added.
+TEST_F(ClassifyTest, requiredNoTest) {
+ std::string config =
+ "{"
+ "\"interfaces-config\": {"
+ " \"interfaces\": [ \"*\" ]"
+ "},"
+ "\"client-classes\": ["
+ " {"
+ " \"name\": \"for-network\","
+ " \"option-data\": [ {"
+ " \"name\": \"dns-servers\","
+ " \"data\": \"2001:db8:1::3\""
+ " } ]"
+ " }"
+ "],"
+ "\"shared-networks\": [ {"
+ " \"name\": \"frog\","
+ " \"interface\": \"eth1\","
+ " \"require-client-classes\": [ \"for-network\" ],"
+ " \"subnet6\": [ { "
+ " \"subnet\": \"2001:db8:1::/64\","
+ " \"id\": 1,"
+ " \"pools\": [ { "
+ " \"pool\": \"2001:db8:1::1 - 2001:db8:1::64\""
+ " } ]"
+ " } ]"
+ "} ],"
+ "\"valid-lifetime\": 600"
+ "}";
+
+ // Create a client requesting dns-servers option
+ Dhcp6Client client;
+ client.setInterface("eth1");
+ client.requestAddress(0xabca, IOAddress("2001:db8:1::28"));
+ client.requestOption(D6O_NAME_SERVERS);
+
+ // Load the config and perform a SARR
+ configure(config, *client.getServer());
+ ASSERT_NO_THROW(client.doSARR());
+
+ // Check response
+ EXPECT_EQ(1, client.getLeaseNum());
+ Pkt6Ptr resp = client.getContext().response_;
+ ASSERT_TRUE(resp);
+
+ // Check dns-servers option
+ OptionPtr opt = resp->getOption(D6O_NAME_SERVERS);
+ ASSERT_TRUE(opt);
+ Option6AddrLstPtr servers =
+ boost::dynamic_pointer_cast<Option6AddrLst>(opt);
+ ASSERT_TRUE(servers);
+ auto addrs = servers->getAddresses();
+ ASSERT_EQ(1, addrs.size());
+ EXPECT_EQ("2001:db8:1::3", addrs[0].toText());
+}
+
+// This test checks a required class which is not defined is ignored.
+TEST_F(ClassifyTest, requiredNoDefined) {
+ std::string config =
+ "{"
+ "\"interfaces-config\": {"
+ " \"interfaces\": [ \"*\" ]"
+ "},"
+ "\"shared-networks\": [ {"
+ " \"name\": \"frog\","
+ " \"interface\": \"eth1\","
+ " \"require-client-classes\": [ \"for-network\" ],"
+ " \"subnet6\": [ { "
+ " \"subnet\": \"2001:db8:1::/64\","
+ " \"id\": 1,"
+ " \"pools\": [ { "
+ " \"pool\": \"2001:db8:1::1 - 2001:db8:1::64\""
+ " } ]"
+ " } ]"
+ "} ],"
+ "\"valid-lifetime\": 600"
+ "}";
+
+ // Create a client requesting dns-servers option
+ Dhcp6Client client;
+ client.setInterface("eth1");
+ client.requestAddress(0xabca, IOAddress("2001:db8:1::28"));
+ client.requestOption(D6O_NAME_SERVERS);
+
+ // Load the config and perform a SARR
+ configure(config, *client.getServer());
+ ASSERT_NO_THROW(client.doSARR());
+
+ // Check response
+ EXPECT_EQ(1, client.getLeaseNum());
+ Pkt6Ptr resp = client.getContext().response_;
+ ASSERT_TRUE(resp);
+
+ // Check dns-servers option
+ OptionPtr opt = resp->getOption(D6O_NAME_SERVERS);
+ EXPECT_FALSE(opt);
+}
+
// This test checks the complex membership from HA with server1 telephone.
TEST_F(ClassifyTest, server1Telephone) {
// Create a client.