2
0
mirror of https://gitlab.isc.org/isc-projects/kea synced 2025-08-29 04:57:52 +00:00

[#3588] Modified no test required classes

This commit is contained in:
Francis Dupont 2024-10-08 16:10:13 +02:00
parent 8263915af3
commit dc8af16a6e
14 changed files with 256 additions and 38 deletions

View File

@ -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)

View File

@ -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 and shared network, i.e. in the same order from the way in which
``option-data`` is processed. ``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:: .. note::
Vendor-Identifying Vendor Options are a special case: for all other Vendor-Identifying Vendor Options are a special case: for all other

View File

@ -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 (pd-)pool, subnet, and shared network, i.e. in the same order from the
way in which ``option-data`` is processed. 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: .. _dhcp6-ddns-config:
DDNS for DHCPv6 DDNS for DHCPv6

View File

@ -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_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_ASSIGNED = "DHCP4_CLASS_ASSIGNED";
extern const isc::log::MessageID DHCP4_CLASS_UNCONFIGURED = "DHCP4_CLASS_UNCONFIGURED"; 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_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_DATA = "DHCP4_CLIENT_FQDN_DATA";
extern const isc::log::MessageID DHCP4_CLIENT_FQDN_PROCESS = "DHCP4_CLIENT_FQDN_PROCESS"; 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_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_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_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_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_RESERVED_HOSTNAME_ASSIGNED = "DHCP4_RESERVED_HOSTNAME_ASSIGNED";
extern const isc::log::MessageID DHCP4_RESPONSE_DATA = "DHCP4_RESPONSE_DATA"; 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_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_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_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_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_DATA", "%1: Client sent FQDN option: %2",
"DHCP4_CLIENT_FQDN_PROCESS", "%1: processing Client FQDN option", "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_REQUEST", "%1: server is processing DHCPREQUEST with hint=%2",
"DHCP4_REQUIRED_CLASS_EVAL_ERROR", "%1: Expression '%2' evaluated to %3", "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_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_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_RESERVED_HOSTNAME_ASSIGNED", "%1: server assigned reserved hostname %2",
"DHCP4_RESPONSE_DATA", "%1: responding with packet %2 (type %3), packet details: %4", "DHCP4_RESPONSE_DATA", "%1: responding with packet %2 (type %3), packet details: %4",

View File

@ -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_CLASSES_ASSIGNED_AFTER_SUBNET_SELECTION;
extern const isc::log::MessageID DHCP4_CLASS_ASSIGNED; extern const isc::log::MessageID DHCP4_CLASS_ASSIGNED;
extern const isc::log::MessageID DHCP4_CLASS_UNCONFIGURED; 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_CLIENTID_IGNORED_FOR_LEASES;
extern const isc::log::MessageID DHCP4_CLIENT_FQDN_DATA; extern const isc::log::MessageID DHCP4_CLIENT_FQDN_DATA;
extern const isc::log::MessageID DHCP4_CLIENT_FQDN_PROCESS; 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_REQUEST;
extern const isc::log::MessageID DHCP4_REQUIRED_CLASS_EVAL_ERROR; 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_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_RESERVATIONS_LOOKUP_FIRST_ENABLED;
extern const isc::log::MessageID DHCP4_RESERVED_HOSTNAME_ASSIGNED; extern const isc::log::MessageID DHCP4_RESERVED_HOSTNAME_ASSIGNED;
extern const isc::log::MessageID DHCP4_RESPONSE_DATA; extern const isc::log::MessageID DHCP4_RESPONSE_DATA;

View File

@ -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 before the classification was added to Kea is used, or class naming is
inconsistent. 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 % DHCP4_CLIENTID_IGNORED_FOR_LEASES %1: not using client identifier for lease allocation for subnet %2
Logged at debug log level 50. Logged at debug log level 50.
This debug message is issued when the server is processing the DHCPv4 message 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 been successfully evaluated. The client class name and the result value of the
evaluation are printed. 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. % 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 This is a message informing that host reservations lookup is performed before
lease lookup when multi-threading is enabled overwriting configured value. lease lookup when multi-threading is enabled overwriting configured value.

View File

@ -4866,15 +4866,19 @@ void Dhcpv4Srv::requiredClassify(Dhcpv4Exchange& ex) {
for (auto const& cclass : classes) { for (auto const& cclass : classes) {
const ClientClassDefPtr class_def = dict->findClass(cclass); const ClientClassDefPtr class_def = dict->findClass(cclass);
if (!class_def) { 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); .arg(cclass);
// Ignore it as it can't have an attached action
continue; continue;
} }
const ExpressionPtr& expr_ptr = class_def->getMatchExpr(); 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) { 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); .arg(cclass);
query->addClass(cclass);
continue; continue;
} }
// Evaluate the expression which can return false (no match), // Evaluate the expression which can return false (no match),

View File

@ -1238,6 +1238,100 @@ TEST_F(ClassifyTest, precedenceNetwork) {
EXPECT_EQ("10.0.0.3", addrs[0].toText()); 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. // This test checks the handling for the DROP special class.
TEST_F(ClassifyTest, dropClass) { TEST_F(ClassifyTest, dropClass) {
Dhcp4Client client(Dhcp4Client::SELECTING); Dhcp4Client client(Dhcp4Client::SELECTING);

View File

@ -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_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_ASSIGNED = "DHCP6_CLASS_ASSIGNED";
extern const isc::log::MessageID DHCP6_CLASS_UNCONFIGURED = "DHCP6_CLASS_UNCONFIGURED"; 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_COMPLETE = "DHCP6_CONFIG_COMPLETE";
extern const isc::log::MessageID DHCP6_CONFIG_LOAD_FAIL = "DHCP6_CONFIG_LOAD_FAIL"; 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"; 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_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_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_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_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_RESERVATIONS_LOOKUP_FIRST_ENABLED = "DHCP6_RESERVATIONS_LOOKUP_FIRST_ENABLED";
extern const isc::log::MessageID DHCP6_RESPONSE_DATA = "DHCP6_RESPONSE_DATA"; 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_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_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_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_COMPLETE", "DHCPv6 server has completed configuration: %1",
"DHCP6_CONFIG_LOAD_FAIL", "configuration error using file: %1, reason: %2", "DHCP6_CONFIG_LOAD_FAIL", "configuration error using file: %1, reason: %2",
"DHCP6_CONFIG_PACKET_QUEUE", "DHCPv6 packet queue info after configuration: %1", "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_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_ERROR", "%1: Expression '%2' evaluated to %3",
"DHCP6_REQUIRED_CLASS_EVAL_RESULT", "%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_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_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", "DHCP6_RESPONSE_DATA", "%1: responding with packet %2 (type %3), packet details: %4",

View File

@ -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_CLASSES_ASSIGNED_AFTER_SUBNET_SELECTION;
extern const isc::log::MessageID DHCP6_CLASS_ASSIGNED; extern const isc::log::MessageID DHCP6_CLASS_ASSIGNED;
extern const isc::log::MessageID DHCP6_CLASS_UNCONFIGURED; 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_COMPLETE;
extern const isc::log::MessageID DHCP6_CONFIG_LOAD_FAIL; extern const isc::log::MessageID DHCP6_CONFIG_LOAD_FAIL;
extern const isc::log::MessageID DHCP6_CONFIG_PACKET_QUEUE; 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_RELEASE_PD_FAIL_WRONG_IAID;
extern const isc::log::MessageID DHCP6_REQUIRED_CLASS_EVAL_ERROR; 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_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_REQUIRED_OPTIONS_CHECK_FAIL;
extern const isc::log::MessageID DHCP6_RESERVATIONS_LOOKUP_FIRST_ENABLED; extern const isc::log::MessageID DHCP6_RESERVATIONS_LOOKUP_FIRST_ENABLED;
extern const isc::log::MessageID DHCP6_RESPONSE_DATA; extern const isc::log::MessageID DHCP6_RESPONSE_DATA;

View File

@ -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 before the classification was added to Kea is used, or class naming is
inconsistent. 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 % DHCP6_CONFIG_COMPLETE DHCPv6 server has completed configuration: %1
This is an informational message announcing the successful processing of a This is an informational message announcing the successful processing of a
new configuration. it is output during server startup, and when an updated 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 been successfully evaluated. The client class name and the result value of the
evaluation are printed. 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 % DHCP6_REQUIRED_OPTIONS_CHECK_FAIL %1: %2 message received from %3 failed the following check: %4
Logged at debug log level 40. Logged at debug log level 40.
This message indicates that received DHCPv6 packet is invalid. This may be due This message indicates that received DHCPv6 packet is invalid. This may be due

View File

@ -4495,15 +4495,19 @@ Dhcpv6Srv::requiredClassify(const Pkt6Ptr& pkt, AllocEngine::ClientContext6& ctx
for (auto const& cclass : classes) { for (auto const& cclass : classes) {
const ClientClassDefPtr class_def = dict->findClass(cclass); const ClientClassDefPtr class_def = dict->findClass(cclass);
if (!class_def) { 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); .arg(cclass);
// Ignore it as it can't have an attached action
continue; continue;
} }
const ExpressionPtr& expr_ptr = class_def->getMatchExpr(); 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) { 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); .arg(cclass);
pkt->addClass(cclass);
continue; continue;
} }
// Evaluate the expression which can return false (no match), // Evaluate the expression which can return false (no match),

View File

@ -2268,6 +2268,106 @@ TEST_F(ClassifyTest, precedenceNetwork) {
EXPECT_EQ("2001:db8:1::3", addrs[0].toText()); 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. // This test checks the complex membership from HA with server1 telephone.
TEST_F(ClassifyTest, server1Telephone) { TEST_F(ClassifyTest, server1Telephone) {
// Create a client. // Create a client.