diff options
author | Francis Dupont <fdupont@isc.org> | 2024-10-08 16:10:13 +0200 |
---|---|---|
committer | Francis Dupont <fdupont@isc.org> | 2024-10-11 10:18:01 +0200 |
commit | dc8af16a6eaf6cdcf54c63f4e050f4b052261b47 (patch) | |
tree | abd0c72599ca0b4dae4c478ccacc3ef12c652243 | |
parent | [#3585] Completed changelog (diff) | |
download | kea-dc8af16a6eaf6cdcf54c63f4e050f4b052261b47.tar.xz kea-dc8af16a6eaf6cdcf54c63f4e050f4b052261b47.zip |
[#3588] Modified no test required classes
-rw-r--r-- | changelog_unreleased/3588-required-no-test | 6 | ||||
-rw-r--r-- | changelog_unreleased/3590-required-precedence (renamed from changelog_unreleased/3590-required-precence) | 0 | ||||
-rw-r--r-- | doc/sphinx/arm/dhcp4-srv.rst | 4 | ||||
-rw-r--r-- | doc/sphinx/arm/dhcp6-srv.rst | 4 | ||||
-rw-r--r-- | src/bin/dhcp4/dhcp4_messages.cc | 8 | ||||
-rw-r--r-- | src/bin/dhcp4/dhcp4_messages.h | 4 | ||||
-rw-r--r-- | src/bin/dhcp4/dhcp4_messages.mes | 21 | ||||
-rw-r--r-- | src/bin/dhcp4/dhcp4_srv.cc | 10 | ||||
-rw-r--r-- | src/bin/dhcp4/tests/classify_unittest.cc | 94 | ||||
-rw-r--r-- | src/bin/dhcp6/dhcp6_messages.cc | 8 | ||||
-rw-r--r-- | src/bin/dhcp6/dhcp6_messages.h | 4 | ||||
-rw-r--r-- | src/bin/dhcp6/dhcp6_messages.mes | 21 | ||||
-rw-r--r-- | src/bin/dhcp6/dhcp6_srv.cc | 10 | ||||
-rw-r--r-- | src/bin/dhcp6/tests/classify_unittest.cc | 100 |
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. |