]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[5374] Fixed options in DHCPv4 pool
authorFrancis Dupont <fdupont@isc.org>
Mon, 27 Nov 2017 14:03:17 +0000 (15:03 +0100)
committerFrancis Dupont <fdupont@isc.org>
Mon, 27 Nov 2017 14:03:17 +0000 (15:03 +0100)
src/bin/dhcp4/dhcp4_srv.cc
src/bin/dhcp4/tests/shared_network_unittest.cc

index e5f39d21bb91a0572e8453e133dc397deea70461..36e6cf6b1ac2dd13fb9780fdd3d9d5b7360afc65 100644 (file)
@@ -1185,12 +1185,25 @@ Dhcpv4Srv::buildCfgOptionList(Dhcpv4Exchange& ex) {
         co_list.push_back(host->getCfgOption4());
     }
 
-    // Secondly, subnet configured options.
+    // Secondly, pool specific options.
+    Pkt4Ptr resp = ex.getResponse();
+    IOAddress addr = IOAddress::IPV4_ZERO_ADDRESS();
+    if (resp) {
+        addr = resp->getYiaddr();
+    }
+    if (!addr.isV4Zero()) {
+        PoolPtr pool = subnet->getPool(Lease::TYPE_V4, addr, false);
+        if (pool && !pool->getCfgOption()->empty()) {
+            co_list.push_back(pool->getCfgOption());
+        }
+    }
+
+    // Thirdly, subnet configured options.
     if (!subnet->getCfgOption()->empty()) {
         co_list.push_back(subnet->getCfgOption());
     }
 
-    // Thirdly, shared network specific options.
+    // Forthly, shared network specific options.
     SharedNetwork4Ptr network;
     subnet->getSharedNetwork(network);
     if (network && !network->getCfgOption()->empty()) {
index 9e564d551e919e76e58e076b3841b06055e7b608..fc7d00452ab3ed6bc6468d811946b4e8d79b5073 100644 (file)
@@ -2050,4 +2050,545 @@ TEST_F(Dhcpv4SharedNetworkTest, poolInSubnetSelectedByClass) {
         doRequest(client2, "192.0.2.100");
     });
 }
+
+// Verify option processing precedence
+// Order is global < class < shared-network < subnet < pool < host reservation
+TEST_F(Dhcpv4SharedNetworkTest, precedenceGlobal) {
+    const std::string config =
+        "{"
+        "    \"interfaces-config\": {"
+        "        \"interfaces\": [ \"*\" ]"
+        "    },"
+        "    \"valid-lifetime\": 600,"
+        "    \"option-data\": ["
+        "        {"
+        "           \"name\": \"domain-name-servers\","
+        "           \"data\": \"192.0.2.1\""
+        "        }"
+        "    ],"
+        "    \"shared-networks\": ["
+        "        {"
+        "            \"name\": \"frog\","
+        "            \"interface\": \"eth1\","
+        "            \"subnet4\": ["
+        "                {"
+        "                    \"subnet\": \"192.0.2.0/26\","
+        "                    \"id\": 10,"
+        "                    \"pools\": ["
+        "                        {"
+        "                            \"pool\": \"192.0.2.1 - 192.0.2.63\""
+        "                        }"
+        "                    ],"
+        "                    \"reservations\": ["
+        "                        {"
+        "                            \"hw-address\": \"aa:bb:cc:dd:ee:ff\","
+        "                            \"ip-address\": \"192.0.2.28\""
+        "                        }"
+        "                    ]"
+        "                }"
+        "            ]"
+        "        }"
+        "    ]"
+        "}";
+
+    // Create client and set MAC address to the one that has a reservation.
+    Dhcp4Client client(Dhcp4Client::SELECTING);
+    client.setIfaceName("eth1");
+    client.setHWAddress("aa:bb:cc:dd:ee:ff");
+    // Request domain-name-servers
+    client.requestOptions(DHO_DOMAIN_NAME_SERVERS);
+
+    // Create server configuration
+    configure(config, *client.getServer());
+
+    // Perform a DORA
+    doDORA(client, "192.0.2.28", "192.0.2.28");
+
+    // Check response
+    Pkt4Ptr resp = client.getContext().response_;
+    ASSERT_TRUE(resp);
+    EXPECT_EQ(DHCPACK, resp->getType());
+    EXPECT_EQ("192.0.2.28", 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("192.0.2.1", addrs[0].toText());
+}
+
+// Verify option processing precedence
+// Order is global < class < shared-network < subnet < pool < host reservation
+TEST_F(Dhcpv4SharedNetworkTest, precedenceClass) {
+    const std::string config =
+        "{"
+        "    \"interfaces-config\": {"
+        "        \"interfaces\": [ \"*\" ]"
+        "    },"
+        "    \"valid-lifetime\": 600,"
+        "    \"option-data\": ["
+        "        {"
+        "           \"name\": \"domain-name-servers\","
+        "           \"data\": \"192.0.2.1\""
+        "        }"
+        "    ],"
+        "    \"client-classes\": ["
+        "        {"
+        "            \"name\": \"alpha\","
+        "            \"test\": \"'' == ''\","
+        "            \"option-data\": ["
+        "                {"
+        "                   \"name\": \"domain-name-servers\","
+        "                   \"data\": \"192.0.2.2\""
+        "                }"
+        "            ]"
+        "        }"
+        "    ],"
+        "    \"shared-networks\": ["
+        "        {"
+        "            \"name\": \"frog\","
+        "            \"interface\": \"eth1\","
+        "            \"subnet4\": ["
+        "                {"
+        "                    \"subnet\": \"192.0.2.0/26\","
+        "                    \"id\": 10,"
+        "                    \"pools\": ["
+        "                        {"
+        "                            \"pool\": \"192.0.2.1 - 192.0.2.63\""
+        "                        }"
+        "                    ],"
+        "                    \"reservations\": ["
+        "                        {"
+        "                            \"hw-address\": \"aa:bb:cc:dd:ee:ff\","
+        "                            \"ip-address\": \"192.0.2.28\""
+        "                        }"
+        "                    ]"
+        "                }"
+        "            ]"
+        "        }"
+        "    ]"
+        "}";
+
+    // Create client and set MAC address to the one that has a reservation.
+    Dhcp4Client client(Dhcp4Client::SELECTING);
+    client.setIfaceName("eth1");
+    client.setHWAddress("aa:bb:cc:dd:ee:ff");
+    // Request domain-name-servers
+    client.requestOptions(DHO_DOMAIN_NAME_SERVERS);
+
+    // Create server configuration
+    configure(config, *client.getServer());
+
+    // Perform a DORA
+    doDORA(client, "192.0.2.28", "192.0.2.28");
+
+    // Check response
+    Pkt4Ptr resp = client.getContext().response_;
+    ASSERT_TRUE(resp);
+    EXPECT_EQ(DHCPACK, resp->getType());
+    EXPECT_EQ("192.0.2.28", 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("192.0.2.2", addrs[0].toText());
+}
+
+// Verify option processing precedence
+// Order is global < class < shared-network < subnet < pool < host reservation
+TEST_F(Dhcpv4SharedNetworkTest, precedenceNetwork) {
+    const std::string config =
+        "{"
+        "    \"interfaces-config\": {"
+        "        \"interfaces\": [ \"*\" ]"
+        "    },"
+        "    \"valid-lifetime\": 600,"
+        "    \"option-data\": ["
+        "        {"
+        "           \"name\": \"domain-name-servers\","
+        "           \"data\": \"192.0.2.1\""
+        "        }"
+        "    ],"
+        "    \"client-classes\": ["
+        "        {"
+        "            \"name\": \"alpha\","
+        "            \"test\": \"'' == ''\","
+        "            \"option-data\": ["
+        "                {"
+        "                   \"name\": \"domain-name-servers\","
+        "                   \"data\": \"192.0.2.2\""
+        "                }"
+        "            ]"
+        "        }"
+        "    ],"
+        "    \"shared-networks\": ["
+        "        {"
+        "            \"name\": \"frog\","
+        "            \"interface\": \"eth1\","
+        "            \"option-data\": ["
+        "                {"
+        "                   \"name\": \"domain-name-servers\","
+        "                   \"data\": \"192.0.2.3\""
+        "                }"
+        "            ],"
+        "            \"subnet4\": ["
+        "                {"
+        "                    \"subnet\": \"192.0.2.0/26\","
+        "                    \"id\": 10,"
+        "                    \"pools\": ["
+        "                        {"
+        "                            \"pool\": \"192.0.2.1 - 192.0.2.63\""
+        "                        }"
+        "                    ],"
+        "                    \"reservations\": ["
+        "                        {"
+        "                            \"hw-address\": \"aa:bb:cc:dd:ee:ff\","
+        "                            \"ip-address\": \"192.0.2.28\""
+        "                        }"
+        "                    ]"
+        "                }"
+        "            ]"
+        "        }"
+        "    ]"
+        "}";
+
+    // Create client and set MAC address to the one that has a reservation.
+    Dhcp4Client client(Dhcp4Client::SELECTING);
+    client.setIfaceName("eth1");
+    client.setHWAddress("aa:bb:cc:dd:ee:ff");
+    // Request domain-name-servers
+    client.requestOptions(DHO_DOMAIN_NAME_SERVERS);
+
+    // Create server configuration
+    configure(config, *client.getServer());
+
+    // Perform a DORA
+    doDORA(client, "192.0.2.28", "192.0.2.28");
+
+    // Check response
+    Pkt4Ptr resp = client.getContext().response_;
+    ASSERT_TRUE(resp);
+    EXPECT_EQ(DHCPACK, resp->getType());
+    EXPECT_EQ("192.0.2.28", 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("192.0.2.3", addrs[0].toText());
+}
+
+// Verify option processing precedence
+// Order is global < class < shared-network < subnet < pool < host reservation
+TEST_F(Dhcpv4SharedNetworkTest, precedenceSubnet) {
+    const std::string config =
+        "{"
+        "    \"interfaces-config\": {"
+        "        \"interfaces\": [ \"*\" ]"
+        "    },"
+        "    \"valid-lifetime\": 600,"
+        "    \"option-data\": ["
+        "        {"
+        "           \"name\": \"domain-name-servers\","
+        "           \"data\": \"192.0.2.1\""
+        "        }"
+        "    ],"
+        "    \"client-classes\": ["
+        "        {"
+        "            \"name\": \"alpha\","
+        "            \"test\": \"'' == ''\","
+        "            \"option-data\": ["
+        "                {"
+        "                   \"name\": \"domain-name-servers\","
+        "                   \"data\": \"192.0.2.2\""
+        "                }"
+        "            ]"
+        "        }"
+        "    ],"
+        "    \"shared-networks\": ["
+        "        {"
+        "            \"name\": \"frog\","
+        "            \"interface\": \"eth1\","
+        "            \"option-data\": ["
+        "                {"
+        "                   \"name\": \"domain-name-servers\","
+        "                   \"data\": \"192.0.2.3\""
+        "                }"
+        "            ],"
+        "            \"subnet4\": ["
+        "                {"
+        "                    \"subnet\": \"192.0.2.0/26\","
+        "                    \"id\": 10,"
+        "                    \"option-data\": ["
+        "                        {"
+        "                           \"name\": \"domain-name-servers\","
+        "                           \"data\": \"192.0.2.4\""
+        "                        }"
+        "                    ],"
+        "                    \"pools\": ["
+        "                        {"
+        "                            \"pool\": \"192.0.2.1 - 192.0.2.63\""
+        "                        }"
+        "                    ],"
+        "                    \"reservations\": ["
+        "                        {"
+        "                            \"hw-address\": \"aa:bb:cc:dd:ee:ff\","
+        "                            \"ip-address\": \"192.0.2.28\""
+        "                        }"
+        "                    ]"
+        "                }"
+        "            ]"
+        "        }"
+        "    ]"
+        "}";
+
+    // Create client and set MAC address to the one that has a reservation.
+    Dhcp4Client client(Dhcp4Client::SELECTING);
+    client.setIfaceName("eth1");
+    client.setHWAddress("aa:bb:cc:dd:ee:ff");
+    // Request domain-name-servers
+    client.requestOptions(DHO_DOMAIN_NAME_SERVERS);
+
+    // Create server configuration
+    configure(config, *client.getServer());
+
+    // Perform a DORA
+    doDORA(client, "192.0.2.28", "192.0.2.28");
+
+    // Check response
+    Pkt4Ptr resp = client.getContext().response_;
+    ASSERT_TRUE(resp);
+    EXPECT_EQ(DHCPACK, resp->getType());
+    EXPECT_EQ("192.0.2.28", 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("192.0.2.4", addrs[0].toText());
+}
+
+// Verify option processing precedence
+// Order is global < class < shared-network < subnet < pool < host reservation
+TEST_F(Dhcpv4SharedNetworkTest, precedencePool) {
+    const std::string config =
+        "{"
+        "    \"interfaces-config\": {"
+        "        \"interfaces\": [ \"*\" ]"
+        "    },"
+        "    \"valid-lifetime\": 600,"
+        "    \"option-data\": ["
+        "        {"
+        "           \"name\": \"domain-name-servers\","
+        "           \"data\": \"192.0.2.1\""
+        "        }"
+        "    ],"
+        "    \"client-classes\": ["
+        "        {"
+        "            \"name\": \"alpha\","
+        "            \"test\": \"'' == ''\","
+        "            \"option-data\": ["
+        "                {"
+        "                   \"name\": \"domain-name-servers\","
+        "                   \"data\": \"192.0.2.2\""
+        "                }"
+        "            ]"
+        "        }"
+        "    ],"
+        "    \"shared-networks\": ["
+        "        {"
+        "            \"name\": \"frog\","
+        "            \"interface\": \"eth1\","
+        "            \"option-data\": ["
+        "                {"
+        "                   \"name\": \"domain-name-servers\","
+        "                   \"data\": \"192.0.2.3\""
+        "                }"
+        "            ],"
+        "            \"subnet4\": ["
+        "                {"
+        "                    \"subnet\": \"192.0.2.0/26\","
+        "                    \"id\": 10,"
+        "                    \"option-data\": ["
+        "                        {"
+        "                           \"name\": \"domain-name-servers\","
+        "                           \"data\": \"192.0.2.4\""
+        "                        }"
+        "                    ],"
+        "                    \"pools\": ["
+        "                        {"
+        "                            \"pool\": \"192.0.2.1 - 192.0.2.63\","
+        "                            \"option-data\": ["
+        "                                {"
+        "                                   \"name\": \"domain-name-servers\","
+        "                                   \"data\": \"192.0.2.5\""
+        "                                }"
+        "                            ]"
+        "                        }"
+        "                    ],"
+        "                    \"reservations\": ["
+        "                        {"
+        "                            \"hw-address\": \"aa:bb:cc:dd:ee:ff\","
+        "                            \"ip-address\": \"192.0.2.28\""
+        "                        }"
+        "                    ]"
+        "                }"
+        "            ]"
+        "        }"
+        "    ]"
+        "}";
+
+    // Create client and set MAC address to the one that has a reservation.
+    Dhcp4Client client(Dhcp4Client::SELECTING);
+    client.setIfaceName("eth1");
+    client.setHWAddress("aa:bb:cc:dd:ee:ff");
+    // Request domain-name-servers
+    client.requestOptions(DHO_DOMAIN_NAME_SERVERS);
+
+    // Create server configuration
+    configure(config, *client.getServer());
+
+    // Perform a DORA
+    doDORA(client, "192.0.2.28", "192.0.2.28");
+
+    // Check response
+    Pkt4Ptr resp = client.getContext().response_;
+    ASSERT_TRUE(resp);
+    EXPECT_EQ(DHCPACK, resp->getType());
+    EXPECT_EQ("192.0.2.28", 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("192.0.2.5", addrs[0].toText());
+}
+
+// Verify option processing precedence
+// Order is global < class < shared-network < subnet < pool < host reservation
+TEST_F(Dhcpv4SharedNetworkTest, precedenceReservation) {
+    const std::string config =
+        "{"
+        "    \"interfaces-config\": {"
+        "        \"interfaces\": [ \"*\" ]"
+        "    },"
+        "    \"valid-lifetime\": 600,"
+        "    \"option-data\": ["
+        "        {"
+        "           \"name\": \"domain-name-servers\","
+        "           \"data\": \"192.0.2.1\""
+        "        }"
+        "    ],"
+        "    \"client-classes\": ["
+        "        {"
+        "            \"name\": \"alpha\","
+        "            \"test\": \"'' == ''\","
+        "            \"option-data\": ["
+        "                {"
+        "                   \"name\": \"domain-name-servers\","
+        "                   \"data\": \"192.0.2.2\""
+        "                }"
+        "            ]"
+        "        }"
+        "    ],"
+        "    \"shared-networks\": ["
+        "        {"
+        "            \"name\": \"frog\","
+        "            \"interface\": \"eth1\","
+        "            \"option-data\": ["
+        "                {"
+        "                   \"name\": \"domain-name-servers\","
+        "                   \"data\": \"192.0.2.3\""
+        "                }"
+        "            ],"
+        "            \"subnet4\": ["
+        "                {"
+        "                    \"subnet\": \"192.0.2.0/26\","
+        "                    \"id\": 10,"
+        "                    \"option-data\": ["
+        "                        {"
+        "                           \"name\": \"domain-name-servers\","
+        "                           \"data\": \"192.0.2.4\""
+        "                        }"
+        "                    ],"
+        "                    \"pools\": ["
+        "                        {"
+        "                            \"pool\": \"192.0.2.1 - 192.0.2.63\","
+        "                            \"option-data\": ["
+        "                                {"
+        "                                   \"name\": \"domain-name-servers\","
+        "                                   \"data\": \"192.0.2.5\""
+        "                                }"
+        "                            ]"
+        "                        }"
+        "                    ],"
+        "                    \"reservations\": ["
+        "                        {"
+        "                            \"hw-address\": \"aa:bb:cc:dd:ee:ff\","
+        "                            \"ip-address\": \"192.0.2.28\","
+        "                            \"option-data\": ["
+        "                                {"
+        "                                   \"name\": \"domain-name-servers\","
+        "                                   \"data\": \"192.0.2.6\""
+        "                                }"
+        "                            ]"
+        "                        }"
+        "                    ]"
+        "                }"
+        "            ]"
+        "        }"
+        "    ]"
+        "}";
+
+    // Create client and set MAC address to the one that has a reservation.
+    Dhcp4Client client(Dhcp4Client::SELECTING);
+    client.setIfaceName("eth1");
+    client.setHWAddress("aa:bb:cc:dd:ee:ff");
+    // Request domain-name-servers
+    client.requestOptions(DHO_DOMAIN_NAME_SERVERS);
+
+    // Create server configuration
+    configure(config, *client.getServer());
+
+    // Perform a DORA
+    doDORA(client, "192.0.2.28", "192.0.2.28");
+
+    // Check response
+    Pkt4Ptr resp = client.getContext().response_;
+    ASSERT_TRUE(resp);
+    EXPECT_EQ(DHCPACK, resp->getType());
+    EXPECT_EQ("192.0.2.28", 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("192.0.2.6", addrs[0].toText());
+}
+
 } // end of anonymous namespace