From: Francis Dupont Date: Mon, 27 Nov 2017 14:03:17 +0000 (+0100) Subject: [5374] Fixed options in DHCPv4 pool X-Git-Tag: trac5458a_base~14^2~20 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1db3a9656fd382550895dba637c9c2f63f05c4c2;p=thirdparty%2Fkea.git [5374] Fixed options in DHCPv4 pool --- diff --git a/src/bin/dhcp4/dhcp4_srv.cc b/src/bin/dhcp4/dhcp4_srv.cc index e5f39d21bb..36e6cf6b1a 100644 --- a/src/bin/dhcp4/dhcp4_srv.cc +++ b/src/bin/dhcp4/dhcp4_srv.cc @@ -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()) { diff --git a/src/bin/dhcp4/tests/shared_network_unittest.cc b/src/bin/dhcp4/tests/shared_network_unittest.cc index 9e564d551e..fc7d00452a 100644 --- a/src/bin/dhcp4/tests/shared_network_unittest.cc +++ b/src/bin/dhcp4/tests/shared_network_unittest.cc @@ -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(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(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(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(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(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(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