]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#4110] Checkpoint: began UTs
authorFrancis Dupont <fdupont@isc.org>
Fri, 6 Mar 2026 13:37:20 +0000 (14:37 +0100)
committerFrancis Dupont <fdupont@isc.org>
Mon, 8 Jun 2026 15:24:16 +0000 (17:24 +0200)
src/bin/dhcp4/tests/classify_unittest.cc
src/bin/dhcp6/dhcp6_messages.cc
src/bin/dhcp6/dhcp6_messages.h

index 17c213a3c0998d1dbcd26a4c05b347dbc4aefce1..1542ee25b6ba9c9efdd3f19782fd207bf342a6a8 100644 (file)
@@ -93,8 +93,6 @@ namespace {
 ///   - the following class defined: not member('KNOWN'), DROP
 ///     (the not member also verifies that the DROP class is set only
 ///      after the host reservation lookup)
-/// @note the reservation includes a hostname because raw reservations are
-/// not yet allowed.
 ///
 /// - Configuration 7:
 ///   - Used for the DROP class and reservation class.
@@ -125,6 +123,42 @@ namespace {
 ///   - 1 reservation for HW address 'aa:bb:cc:dd:ee:ff'
 ///     setting the DROP class
 ///
+/// - Configuration 10:
+///   - Used for the REJECT class
+///   - 1 subnet: 10.0.0.0/24
+///   - 1 pool: 10.0.0.10-10.0.0.100
+///   - the following class defined: option[93].hex == 0x0009, REJECT
+///
+/// - Configuration 11:
+///   - Used for the REJECT class and reservation existence.
+///   - 1 subnet: 10.0.0.0/24
+///   - 1 pool: 10.0.0.10-10.0.0.100
+///   - 1 reservation for HW address 'aa:bb:cc:dd:ee:ff'
+///   - the following class defined: not member('KNOWN'), REJECT
+///     (the not member also verifies that the REJECT class is set only
+///      after the host reservation lookup)
+///
+/// - Configuration 12:
+///   - Used for the REJECT class and reservation class.
+///   - 1 subnet: 10.0.0.0/24
+///   - 1 pool: 10.0.0.10-10.0.0.100
+///   - 1 reservation for HW address 'aa:bb:cc:dd:ee:ff'
+///     setting the allowed class
+///   - the following classes defined:
+///     - allowed
+///     - member('KNOWN') or member('UNKNOWN'), t
+///     - not member('allowed') and member('t'), REJECT
+///     The function of the always true 't' class is to move the REJECT
+///     evaluation to the classification point after the host reservation
+///     lookup, i.e. indirect KNOWN / UNKNOWN dependency.
+///
+/// - Configuration 13:
+///   - Used for the early global reservations lookup / drop.
+///   - 1 subnet: 10.0.0.0/24
+///   - 1 pool: 10.0.0.10-10.0.0.100
+///   - 1 reservation for HW address 'aa:bb:cc:dd:ee:ff'
+///     setting the REJECT class
+///
 const char* CONFIGS[] = {
     // Configuration 0
     "{ \"interfaces-config\": {"
@@ -357,8 +391,8 @@ const char* CONFIGS[] = {
         "    \"id\": 1,"
         "    \"pools\": [ { \"pool\": \"10.0.0.10-10.0.0.100\" } ],"
         "    \"reservations\": [ {"
-        "        \"hw-address\": \"aa:bb:cc:dd:ee:ff\","
-        "        \"hostname\": \"allowed\" } ]"
+        "        \"hw-address\": \"aa:bb:cc:dd:ee:ff\""
+        "    } ]"
         " } ]"
     "}",
 
@@ -435,6 +469,85 @@ const char* CONFIGS[] = {
         "    \"client-classes\": [ \"DROP\" ] } ]"
     "}",
 
+    // Configuration 10
+    "{ \"interfaces-config\": {"
+        "   \"interfaces\": [ \"*\" ]"
+        "},"
+        "\"valid-lifetime\": 600,"
+        "\"client-classes\": ["
+        "{"
+        "   \"name\": \"REJECT\","
+        "   \"test\": \"option[93].hex == 0x0009\""
+        "}],"
+        "\"subnet4\": [ { "
+        "    \"subnet\": \"10.0.0.0/24\", "
+        "    \"id\": 1,"
+        "    \"pools\": [ { \"pool\": \"10.0.0.10-10.0.0.100\" } ]"
+        " } ]"
+    "}",
+
+    // Configuration 11
+    "{ \"interfaces-config\": {"
+        "   \"interfaces\": [ \"*\" ]"
+        "},"
+        "\"valid-lifetime\": 600,"
+        "\"client-classes\": ["
+        "{"
+        "   \"name\": \"REJECT\","
+        "   \"test\": \"not member('KNOWN')\""
+        "}],"
+        "\"subnet4\": [ { "
+        "    \"subnet\": \"10.0.0.0/24\", "
+        "    \"id\": 1,"
+        "    \"pools\": [ { \"pool\": \"10.0.0.10-10.0.0.100\" } ],"
+        "    \"reservations\": [ {"
+        "        \"hw-address\": \"aa:bb:cc:dd:ee:ff\""
+        " } ]"
+    "}",
+
+    // Configuration 12
+    "{ \"interfaces-config\": {"
+        "   \"interfaces\": [ \"*\" ]"
+        "},"
+        "\"valid-lifetime\": 600,"
+        "\"client-classes\": ["
+        "{"
+        "   \"name\": \"allowed\""
+        "},"
+        "{"
+        "   \"name\": \"t\","
+        "   \"test\": \"member('KNOWN') or member('UNKNOWN')\""
+        "},"
+        "{"
+        "   \"name\": \"REJECT\","
+        "   \"test\": \"not member('allowed') and member('t')\""
+        "}],"
+        "\"subnet4\": [ { "
+        "    \"subnet\": \"10.0.0.0/24\", "
+        "    \"id\": 1,"
+        "    \"pools\": [ { \"pool\": \"10.0.0.10-10.0.0.100\" } ],"
+        "    \"reservations\": [ {"
+        "        \"hw-address\": \"aa:bb:cc:dd:ee:ff\","
+        "        \"client-classes\": [ \"allowed\" ] } ]"
+        " } ]"
+    "}",
+
+    // Configuration 13
+    "{ \"interfaces-config\": {"
+        "   \"interfaces\": [ \"*\" ]"
+        "},"
+        "\"valid-lifetime\": 600,"
+        "\"early-global-reservations-lookup\": true,"
+        "\"subnet4\": [ { "
+        "    \"subnet\": \"10.0.0.0/24\", "
+        "    \"id\": 1,"
+        "    \"interface\": \"eth0\","
+        "    \"pools\": [ { \"pool\": \"10.0.0.10-10.0.0.100\" } ] } ],"
+        "\"reservations\": [ {"
+        "    \"hw-address\": \"aa:bb:cc:dd:ee:ff\","
+        "    \"client-classes\": [ \"REJECT\" ] } ]"
+    "}",
+
 };
 
 /// @brief Test fixture class for testing classification.
@@ -2647,4 +2760,76 @@ TEST_F(ClassifyTest, templateDependOnKnown) {
     EXPECT_EQ(response->getYiaddr(), IOAddress("192.0.2.1"));
 }
 
+// This test checks the handling for the REJECT special class in a Solicit.
+TEST_F(ClassifyTest, rejectClassSolicit) {
+    Dhcp4Client client(srv_, Dhcp4Client::SELECTING);
+
+    // Configure DHCP server.
+    configure(CONFIGS[10], *client.getServer());
+
+    // Send the discover.
+    client.doDiscover();
+
+    // No option: OFFER.
+    ASSERT_TRUE(client.getContext().response_);
+    int type = client.getContext().response_->getType();
+    EXPECT_EQ(DHCPOFFER, type);
+    IOAddress addr = client.getContext().response_->getYiaddr();
+    EXPECT_EQ("10.0.0.10", addr.toText());
+
+    // Retry with an option matching the REJECT class.
+    Dhcp4Client client2(srv_, Dhcp4Client::SELECTING);
+
+    // Add the pxe option.
+    OptionPtr pxe(new OptionInt<uint16_t>(Option::V4, 93, 0x0009));
+    client2.addExtraOption(pxe);
+
+    // Send the discover.
+    client2.doDiscover();
+
+    // Option: no offer.
+    EXPECT_FALSE(client2.getContext().response_);
+}
+
+// This test checks the handling for the REJECT special class in a Request.
+TEST_F(ClassifyTest, rejectClassRequest) {
+    Dhcp4Client client(srv_, Dhcp4Client::SELECTING);
+
+    // Configure DHCP server.
+    configure(CONFIGS[10], *client.getServer());
+
+    // Send the discover.
+    client.doDiscover();
+
+    // send the request.
+    client.doRequest();
+
+    // No option: ACK.
+    ASSERT_TRUE(client.getContext().response_);
+    int type = client.getContext().response_->getType();
+    EXPECT_EQ(DHCPACK, type);
+    IOAddress addr = client.getContext().response_->getYiaddr();
+    EXPECT_EQ("10.0.0.10", addr.toText());
+
+    // Retry with an option matching the REJECT class.
+    Dhcp4Client client2(srv_, Dhcp4Client::SELECTING);
+
+    // Send the discover.
+    client2.doDiscover();
+
+    // Add the pxe option.
+    OptionPtr pxe(new OptionInt<uint16_t>(Option::V4, 93, 0x0009));
+    client2.addExtraOption(pxe);
+
+    // Send the request.
+    client2.doRequest();
+
+    // Option: no offer.
+    ASSERT_TRUE(client2.getContext().response_);
+    type = client2.getContext().response_->getType();
+    EXPECT_EQ(DHCPNAK, type);
+    addr = client2.getContext().response_->getYiaddr();
+    EXPECT_EQ("0.0.0.0", addr.toText());
+}
+
 } // end of anonymous namespace
index c140e4436dcaecb96768c056c579d260d0f0c8e6..a0645494ead9b65db45a5a1b27e3a42fbaaac773 100644 (file)
@@ -122,6 +122,7 @@ extern const isc::log::MessageID DHCP6_PACKET_PROCESS_STD_EXCEPTION_MAIN = "DHCP
 extern const isc::log::MessageID DHCP6_PACKET_QUEUE_FULL = "DHCP6_PACKET_QUEUE_FULL";
 extern const isc::log::MessageID DHCP6_PACKET_RECEIVED = "DHCP6_PACKET_RECEIVED";
 extern const isc::log::MessageID DHCP6_PACKET_RECEIVE_FAIL = "DHCP6_PACKET_RECEIVE_FAIL";
+extern const isc::log::MessageID DHCP6_PACKET_REJECT_CLASS = "DHCP6_PACKET_REJECT_CLASS";
 extern const isc::log::MessageID DHCP6_PACKET_SEND = "DHCP6_PACKET_SEND";
 extern const isc::log::MessageID DHCP6_PACKET_SEND_FAIL = "DHCP6_PACKET_SEND_FAIL";
 extern const isc::log::MessageID DHCP6_PACK_FAIL = "DHCP6_PACK_FAIL";
@@ -303,6 +304,7 @@ const char* values[] = {
     "DHCP6_PACKET_QUEUE_FULL", "multi-threading packet queue is full",
     "DHCP6_PACKET_RECEIVED", "%1: %2 (type %3) received from %4 to %5 on interface %6",
     "DHCP6_PACKET_RECEIVE_FAIL", "error on attempt to receive packet: %1",
+    "DHCP6_PACKET_REJECT_CLASS", "assignment rejected as member of the special class 'REJECT': %1 %2",
     "DHCP6_PACKET_SEND", "%1: trying to send packet %2 (type %3) from [%4]:%5 to [%6]:%7 on interface %8",
     "DHCP6_PACKET_SEND_FAIL", "%1: failed to send DHCPv6 packet: %2",
     "DHCP6_PACK_FAIL", "%1: failed to assemble response correctly: %2",
index 3420f1b72d0383dbf4d3d2cd5fc1fdc075890b61..d1ec5c8db8790f605c03619e72e28eda2828c217 100644 (file)
@@ -123,6 +123,7 @@ extern const isc::log::MessageID DHCP6_PACKET_PROCESS_STD_EXCEPTION_MAIN;
 extern const isc::log::MessageID DHCP6_PACKET_QUEUE_FULL;
 extern const isc::log::MessageID DHCP6_PACKET_RECEIVED;
 extern const isc::log::MessageID DHCP6_PACKET_RECEIVE_FAIL;
+extern const isc::log::MessageID DHCP6_PACKET_REJECT_CLASS;
 extern const isc::log::MessageID DHCP6_PACKET_SEND;
 extern const isc::log::MessageID DHCP6_PACKET_SEND_FAIL;
 extern const isc::log::MessageID DHCP6_PACK_FAIL;