mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-31 05:55:28 +00:00
[#1894] negative test for cable labs vendor ID
This commit is contained in:
@@ -48,7 +48,110 @@ using namespace isc::dhcp::test;
|
||||
/// groups all vendor related tests under a single name. There were too many
|
||||
/// tests in Dhcpv4SrvTest class anyway.
|
||||
class VendorOptsTest : public Dhcpv4SrvTest {
|
||||
public:
|
||||
void testVendorOptionsORO(int vendor_id) {
|
||||
IfaceMgrTestConfig test_config(true);
|
||||
IfaceMgr::instance().openSockets4();
|
||||
|
||||
NakedDhcpv4Srv srv(0);
|
||||
|
||||
string config = R"(
|
||||
{
|
||||
"interfaces-config": {
|
||||
"interfaces": [ "*" ]
|
||||
},
|
||||
"option-data": [
|
||||
{
|
||||
"code": 2,
|
||||
"csv-format": true,
|
||||
"data": "192.0.2.1, 192.0.2.2",
|
||||
"name": "tftp-servers",
|
||||
"space": "vendor-4491"
|
||||
}
|
||||
],
|
||||
"subnet4": [
|
||||
{
|
||||
"interface": "eth0",
|
||||
"pools": [
|
||||
{
|
||||
"pool": "192.0.2.0/25"
|
||||
}
|
||||
],
|
||||
"subnet": "192.0.2.0/24"
|
||||
}
|
||||
]
|
||||
}
|
||||
)";
|
||||
|
||||
ConstElementPtr json;
|
||||
ASSERT_NO_THROW(json = parseDHCP4(config));
|
||||
|
||||
ConstElementPtr x;
|
||||
EXPECT_NO_THROW(x = configureDhcp4Server(srv, json));
|
||||
ASSERT_TRUE(x);
|
||||
comment_ = parseAnswer(rcode_, x);
|
||||
ASSERT_EQ(0, rcode_);
|
||||
|
||||
CfgMgr::instance().commit();
|
||||
|
||||
boost::shared_ptr<Pkt4> dis(new Pkt4(DHCPDISCOVER, 1234));
|
||||
// Set the giaddr and hops to non-zero address as if it was relayed.
|
||||
dis->setGiaddr(IOAddress("192.0.2.1"));
|
||||
dis->setHops(1);
|
||||
|
||||
OptionPtr clientid = generateClientId();
|
||||
dis->addOption(clientid);
|
||||
// Set interface. It is required by the server to generate server id.
|
||||
dis->setIface("eth0");
|
||||
dis->setIndex(ETH0_INDEX);
|
||||
|
||||
// Pass it to the server and get an advertise
|
||||
Pkt4Ptr offer = srv.processDiscover(dis);
|
||||
|
||||
// check if we get response at all
|
||||
ASSERT_TRUE(offer);
|
||||
|
||||
// We did not include any vendor opts in DISCOVER, so there should be none
|
||||
// in OFFER.
|
||||
ASSERT_FALSE(offer->getOption(DHO_VIVSO_SUBOPTIONS));
|
||||
|
||||
// Let's add a vendor-option (vendor-id=4491) with a single sub-option.
|
||||
// That suboption has code 1 and is a docsis ORO option.
|
||||
boost::shared_ptr<OptionUint8Array> vendor_oro(new OptionUint8Array(Option::V4,
|
||||
DOCSIS3_V4_ORO));
|
||||
vendor_oro->addValue(DOCSIS3_V4_TFTP_SERVERS); // Request option 33
|
||||
OptionPtr vendor(new OptionVendor(Option::V4, vendor_id));
|
||||
vendor->addOption(vendor_oro);
|
||||
dis->addOption(vendor);
|
||||
|
||||
// Need to process SOLICIT again after requesting new option.
|
||||
offer = srv.processDiscover(dis);
|
||||
ASSERT_TRUE(offer);
|
||||
|
||||
// Check if there is (or not) a vendor option in the response.
|
||||
OptionPtr tmp = offer->getOption(DHO_VIVSO_SUBOPTIONS);
|
||||
if (vendor_id != VENDOR_ID_CABLE_LABS) {
|
||||
EXPECT_FALSE(tmp);
|
||||
return;
|
||||
}
|
||||
ASSERT_TRUE(tmp);
|
||||
|
||||
// The response should be OptionVendor object
|
||||
boost::shared_ptr<OptionVendor> vendor_resp =
|
||||
boost::dynamic_pointer_cast<OptionVendor>(tmp);
|
||||
ASSERT_TRUE(vendor_resp);
|
||||
|
||||
OptionPtr docsis2 = vendor_resp->getOption(DOCSIS3_V4_TFTP_SERVERS);
|
||||
ASSERT_TRUE(docsis2);
|
||||
|
||||
Option4AddrLstPtr tftp_srvs = boost::dynamic_pointer_cast<Option4AddrLst>(docsis2);
|
||||
ASSERT_TRUE(tftp_srvs);
|
||||
|
||||
Option4AddrLst::AddressContainer addrs = tftp_srvs->getAddresses();
|
||||
ASSERT_EQ(2, addrs.size());
|
||||
EXPECT_EQ("192.0.2.1", addrs[0].toText());
|
||||
EXPECT_EQ("192.0.2.2", addrs[1].toText());
|
||||
}
|
||||
};
|
||||
|
||||
/// @todo Add more extensive vendor options tests, including multiple
|
||||
@@ -184,92 +287,13 @@ TEST_F(VendorOptsTest, docsisVendorORO) {
|
||||
// This test checks if Option Request Option (ORO) in docsis (vendor-id=4491)
|
||||
// vendor options is parsed correctly and the requested options are actually assigned.
|
||||
TEST_F(VendorOptsTest, vendorOptionsORO) {
|
||||
IfaceMgrTestConfig test_config(true);
|
||||
IfaceMgr::instance().openSockets4();
|
||||
testVendorOptionsORO(VENDOR_ID_CABLE_LABS);
|
||||
}
|
||||
|
||||
NakedDhcpv4Srv srv(0);
|
||||
|
||||
ConstElementPtr x;
|
||||
string config = "{ \"interfaces-config\": {"
|
||||
" \"interfaces\": [ \"*\" ]"
|
||||
"},"
|
||||
" \"option-data\": [ {"
|
||||
" \"name\": \"tftp-servers\","
|
||||
" \"space\": \"vendor-4491\","
|
||||
" \"code\": 2,"
|
||||
" \"data\": \"192.0.2.1, 192.0.2.2\","
|
||||
" \"csv-format\": true"
|
||||
" }],"
|
||||
"\"subnet4\": [ { "
|
||||
" \"pools\": [ { \"pool\": \"192.0.2.0/25\" } ],"
|
||||
" \"subnet\": \"192.0.2.0/24\", "
|
||||
" \"interface\": \"eth0\" "
|
||||
" } ]"
|
||||
"}";
|
||||
|
||||
ConstElementPtr json;
|
||||
ASSERT_NO_THROW(json = parseDHCP4(config));
|
||||
|
||||
EXPECT_NO_THROW(x = configureDhcp4Server(srv, json));
|
||||
ASSERT_TRUE(x);
|
||||
comment_ = parseAnswer(rcode_, x);
|
||||
ASSERT_EQ(0, rcode_);
|
||||
|
||||
CfgMgr::instance().commit();
|
||||
|
||||
boost::shared_ptr<Pkt4> dis(new Pkt4(DHCPDISCOVER, 1234));
|
||||
// Set the giaddr and hops to non-zero address as if it was relayed.
|
||||
dis->setGiaddr(IOAddress("192.0.2.1"));
|
||||
dis->setHops(1);
|
||||
|
||||
OptionPtr clientid = generateClientId();
|
||||
dis->addOption(clientid);
|
||||
// Set interface. It is required by the server to generate server id.
|
||||
dis->setIface("eth0");
|
||||
dis->setIndex(ETH0_INDEX);
|
||||
|
||||
// Pass it to the server and get an advertise
|
||||
Pkt4Ptr offer = srv.processDiscover(dis);
|
||||
|
||||
// check if we get response at all
|
||||
ASSERT_TRUE(offer);
|
||||
|
||||
// We did not include any vendor opts in DISCOVER, so there should be none
|
||||
// in OFFER.
|
||||
ASSERT_FALSE(offer->getOption(DHO_VIVSO_SUBOPTIONS));
|
||||
|
||||
// Let's add a vendor-option (vendor-id=4491) with a single sub-option.
|
||||
// That suboption has code 1 and is a docsis ORO option.
|
||||
boost::shared_ptr<OptionUint8Array> vendor_oro(new OptionUint8Array(Option::V4,
|
||||
DOCSIS3_V4_ORO));
|
||||
vendor_oro->addValue(DOCSIS3_V4_TFTP_SERVERS); // Request option 33
|
||||
OptionPtr vendor(new OptionVendor(Option::V4, 4491));
|
||||
vendor->addOption(vendor_oro);
|
||||
dis->addOption(vendor);
|
||||
|
||||
// Need to process SOLICIT again after requesting new option.
|
||||
offer = srv.processDiscover(dis);
|
||||
ASSERT_TRUE(offer);
|
||||
|
||||
// Check if there is a vendor option response
|
||||
OptionPtr tmp = offer->getOption(DHO_VIVSO_SUBOPTIONS);
|
||||
ASSERT_TRUE(tmp);
|
||||
|
||||
// The response should be OptionVendor object
|
||||
boost::shared_ptr<OptionVendor> vendor_resp =
|
||||
boost::dynamic_pointer_cast<OptionVendor>(tmp);
|
||||
ASSERT_TRUE(vendor_resp);
|
||||
|
||||
OptionPtr docsis2 = vendor_resp->getOption(DOCSIS3_V4_TFTP_SERVERS);
|
||||
ASSERT_TRUE(docsis2);
|
||||
|
||||
Option4AddrLstPtr tftp_srvs = boost::dynamic_pointer_cast<Option4AddrLst>(docsis2);
|
||||
ASSERT_TRUE(tftp_srvs);
|
||||
|
||||
Option4AddrLst::AddressContainer addrs = tftp_srvs->getAddresses();
|
||||
ASSERT_EQ(2, addrs.size());
|
||||
EXPECT_EQ("192.0.2.1", addrs[0].toText());
|
||||
EXPECT_EQ("192.0.2.2", addrs[1].toText());
|
||||
// Same as vendorOptionsORO except a different vendor ID than Cable Labs is
|
||||
// provided and vendor options are expected to not be present in the response.
|
||||
TEST_F(VendorOptsTest, vendorOptionsORODifferentVendorID) {
|
||||
testVendorOptionsORO(32768);
|
||||
}
|
||||
|
||||
// This test checks if Option Request Option (ORO) in docsis (vendor-id=4491)
|
||||
|
@@ -43,6 +43,113 @@ using namespace isc::asiolink;
|
||||
/// @brief Class dedicated to testing vendor options in DHCPv6
|
||||
class VendorOptsTest : public Dhcpv6SrvTest {
|
||||
public:
|
||||
void testVendorOptionsORO(int vendor_id) {
|
||||
IfaceMgrTestConfig test_config(true);
|
||||
|
||||
string config = R"(
|
||||
{
|
||||
"interfaces-config": {
|
||||
"interfaces": [ "*" ]
|
||||
},
|
||||
"option-data": [
|
||||
{
|
||||
"data": "normal_erouter_v6.cm",
|
||||
"name": "config-file",
|
||||
"space": "vendor-4491"
|
||||
}
|
||||
],
|
||||
"option-def": [
|
||||
{
|
||||
"code": 33,
|
||||
"name": "config-file",
|
||||
"space": "vendor-4491",
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"preferred-lifetime": 3000,
|
||||
"rebind-timer": 2000,
|
||||
"renew-timer": 1000,
|
||||
"subnet6": [
|
||||
{
|
||||
"interface": "eth0",
|
||||
"interface-id": "",
|
||||
"pools": [
|
||||
{
|
||||
"pool": "2001:db8:1::/64"
|
||||
}
|
||||
],
|
||||
"preferred-lifetime": 3000,
|
||||
"rebind-timer": 1000,
|
||||
"renew-timer": 1000,
|
||||
"subnet": "2001:db8:1::/48",
|
||||
"valid-lifetime": 4000
|
||||
}
|
||||
],
|
||||
"valid-lifetime": 4000
|
||||
}
|
||||
)";
|
||||
|
||||
ASSERT_NO_THROW(configure(config));
|
||||
|
||||
Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
|
||||
sol->setRemoteAddr(IOAddress("fe80::abcd"));
|
||||
sol->setIface("eth0");
|
||||
sol->setIndex(ETH0_INDEX);
|
||||
sol->addOption(generateIA(D6O_IA_NA, 234, 1500, 3000));
|
||||
OptionPtr clientid = generateClientId();
|
||||
sol->addOption(clientid);
|
||||
|
||||
// Pass it to the server and get an advertise
|
||||
AllocEngine::ClientContext6 ctx;
|
||||
bool drop = false;
|
||||
srv_.initContext(sol, ctx, drop);
|
||||
ASSERT_FALSE(drop);
|
||||
Pkt6Ptr adv = srv_.processSolicit(ctx);
|
||||
|
||||
// check if we get response at all
|
||||
ASSERT_TRUE(adv);
|
||||
|
||||
// We did not include any vendor opts in SOLICIT, so there should be none
|
||||
// in ADVERTISE.
|
||||
ASSERT_FALSE(adv->getOption(D6O_VENDOR_OPTS));
|
||||
|
||||
// Let's add a vendor-option (vendor-id=4491) with a single sub-option.
|
||||
// That suboption has code 1 and is a docsis ORO option.
|
||||
boost::shared_ptr<OptionUint16Array> vendor_oro(new OptionUint16Array(Option::V6,
|
||||
DOCSIS3_V6_ORO));
|
||||
vendor_oro->addValue(DOCSIS3_V6_CONFIG_FILE); // Request option 33
|
||||
OptionPtr vendor(new OptionVendor(Option::V6, vendor_id));
|
||||
vendor->addOption(vendor_oro);
|
||||
sol->addOption(vendor);
|
||||
|
||||
// Need to process SOLICIT again after requesting new option.
|
||||
AllocEngine::ClientContext6 ctx2;
|
||||
srv_.initContext(sol, ctx2, drop);
|
||||
ASSERT_FALSE(drop);
|
||||
adv = srv_.processSolicit(ctx2);
|
||||
ASSERT_TRUE(adv);
|
||||
|
||||
// Check if there is (or not) a vendor option in the response.
|
||||
OptionPtr tmp = adv->getOption(D6O_VENDOR_OPTS);
|
||||
if (vendor_id != VENDOR_ID_CABLE_LABS) {
|
||||
EXPECT_FALSE(tmp);
|
||||
return;
|
||||
}
|
||||
ASSERT_TRUE(tmp);
|
||||
|
||||
// The response should be OptionVendor object
|
||||
boost::shared_ptr<OptionVendor> vendor_resp =
|
||||
boost::dynamic_pointer_cast<OptionVendor>(tmp);
|
||||
ASSERT_TRUE(vendor_resp);
|
||||
|
||||
OptionPtr docsis33 = vendor_resp->getOption(33);
|
||||
ASSERT_TRUE(docsis33);
|
||||
|
||||
OptionStringPtr config_file = boost::dynamic_pointer_cast<OptionString>(docsis33);
|
||||
ASSERT_TRUE(config_file);
|
||||
EXPECT_EQ("normal_erouter_v6.cm", config_file->getValue());
|
||||
}
|
||||
|
||||
/// @brief Test what options a client can use to request vendor options.
|
||||
void testRequestingOfVendorOptions(vector<int8_t> const& client_options) {
|
||||
IfaceMgrTestConfig test_config(true);
|
||||
@@ -76,12 +183,12 @@ public:
|
||||
client.addExtraOption(vendor_option);
|
||||
}
|
||||
|
||||
// Let's check whether the server is not able to process this packet
|
||||
// and include vivso with appropriate sub-options
|
||||
// Let's check whether the server is able to process this packet
|
||||
// and include the appropriate options.
|
||||
EXPECT_NO_THROW(client.doSolicit());
|
||||
ASSERT_TRUE(client.getContext().response_);
|
||||
|
||||
// Check there's a response if an option was properly requested.
|
||||
// Check that there is a response if an option was properly requested.
|
||||
// Otherwise check that a response has not been provided and stop here.
|
||||
OptionPtr response(
|
||||
client.getContext().response_->getOption(D6O_VENDOR_OPTS));
|
||||
@@ -98,9 +205,9 @@ public:
|
||||
ASSERT_TRUE(response_vendor_options);
|
||||
EXPECT_EQ(vendor_id_, response_vendor_options->getVendorId());
|
||||
|
||||
// Now check that it contains requested option with the appropriate
|
||||
// content.
|
||||
OptionPtr suboption(response_vendor_options->getOption(option_));
|
||||
// Check that it contains requested option with the appropriate content.
|
||||
OptionPtr suboption(
|
||||
response_vendor_options->getOption(option_));
|
||||
ASSERT_TRUE(suboption);
|
||||
vector<uint8_t> binary_suboption = suboption->toBinary(false);
|
||||
string text(binary_suboption.begin(), binary_suboption.end());
|
||||
@@ -235,93 +342,13 @@ TEST_F(VendorOptsTest, docsisVendorORO) {
|
||||
// This test checks if Option Request Option (ORO) in docsis (vendor-id=4491)
|
||||
// vendor options is parsed correctly and the requested options are actually assigned.
|
||||
TEST_F(VendorOptsTest, vendorOptionsORO) {
|
||||
testVendorOptionsORO(VENDOR_ID_CABLE_LABS);
|
||||
}
|
||||
|
||||
IfaceMgrTestConfig test_config(true);
|
||||
|
||||
string config = "{ \"interfaces-config\": {"
|
||||
" \"interfaces\": [ \"*\" ]"
|
||||
"},"
|
||||
"\"preferred-lifetime\": 3000,"
|
||||
"\"rebind-timer\": 2000, "
|
||||
"\"renew-timer\": 1000, "
|
||||
" \"option-def\": [ {"
|
||||
" \"name\": \"config-file\","
|
||||
" \"code\": 33,"
|
||||
" \"type\": \"string\","
|
||||
" \"space\": \"vendor-4491\""
|
||||
" } ],"
|
||||
" \"option-data\": [ {"
|
||||
" \"name\": \"config-file\","
|
||||
" \"space\": \"vendor-4491\","
|
||||
" \"data\": \"normal_erouter_v6.cm\""
|
||||
" }],"
|
||||
"\"subnet6\": [ { "
|
||||
" \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ],"
|
||||
" \"subnet\": \"2001:db8:1::/48\", "
|
||||
" \"renew-timer\": 1000, "
|
||||
" \"rebind-timer\": 1000, "
|
||||
" \"preferred-lifetime\": 3000,"
|
||||
" \"valid-lifetime\": 4000,"
|
||||
" \"interface-id\": \"\","
|
||||
" \"interface\": \"eth0\""
|
||||
" } ],"
|
||||
"\"valid-lifetime\": 4000 }";
|
||||
|
||||
ASSERT_NO_THROW(configure(config));
|
||||
|
||||
Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
|
||||
sol->setRemoteAddr(IOAddress("fe80::abcd"));
|
||||
sol->setIface("eth0");
|
||||
sol->setIndex(ETH0_INDEX);
|
||||
sol->addOption(generateIA(D6O_IA_NA, 234, 1500, 3000));
|
||||
OptionPtr clientid = generateClientId();
|
||||
sol->addOption(clientid);
|
||||
|
||||
// Pass it to the server and get an advertise
|
||||
AllocEngine::ClientContext6 ctx;
|
||||
bool drop = false;
|
||||
srv_.initContext(sol, ctx, drop);
|
||||
ASSERT_FALSE(drop);
|
||||
Pkt6Ptr adv = srv_.processSolicit(ctx);
|
||||
|
||||
// check if we get response at all
|
||||
ASSERT_TRUE(adv);
|
||||
|
||||
// We did not include any vendor opts in SOLICIT, so there should be none
|
||||
// in ADVERTISE.
|
||||
ASSERT_FALSE(adv->getOption(D6O_VENDOR_OPTS));
|
||||
|
||||
// Let's add a vendor-option (vendor-id=4491) with a single sub-option.
|
||||
// That suboption has code 1 and is a docsis ORO option.
|
||||
boost::shared_ptr<OptionUint16Array> vendor_oro(new OptionUint16Array(Option::V6,
|
||||
DOCSIS3_V6_ORO));
|
||||
vendor_oro->addValue(DOCSIS3_V6_CONFIG_FILE); // Request option 33
|
||||
OptionPtr vendor(new OptionVendor(Option::V6, 4491));
|
||||
vendor->addOption(vendor_oro);
|
||||
sol->addOption(vendor);
|
||||
|
||||
// Need to process SOLICIT again after requesting new option.
|
||||
AllocEngine::ClientContext6 ctx2;
|
||||
srv_.initContext(sol, ctx2, drop);
|
||||
ASSERT_FALSE(drop);
|
||||
adv = srv_.processSolicit(ctx2);
|
||||
ASSERT_TRUE(adv);
|
||||
|
||||
// Check if there is vendor option response
|
||||
OptionPtr tmp = adv->getOption(D6O_VENDOR_OPTS);
|
||||
ASSERT_TRUE(tmp);
|
||||
|
||||
// The response should be OptionVendor object
|
||||
boost::shared_ptr<OptionVendor> vendor_resp =
|
||||
boost::dynamic_pointer_cast<OptionVendor>(tmp);
|
||||
ASSERT_TRUE(vendor_resp);
|
||||
|
||||
OptionPtr docsis33 = vendor_resp->getOption(33);
|
||||
ASSERT_TRUE(docsis33);
|
||||
|
||||
OptionStringPtr config_file = boost::dynamic_pointer_cast<OptionString>(docsis33);
|
||||
ASSERT_TRUE(config_file);
|
||||
EXPECT_EQ("normal_erouter_v6.cm", config_file->getValue());
|
||||
// Same as vendorOptionsORO except a different vendor ID than Cable Labs is
|
||||
// provided and vendor options are expected to not be present in the response.
|
||||
TEST_F(VendorOptsTest, vendorOptionsORODifferentVendorID) {
|
||||
testVendorOptionsORO(32768);
|
||||
}
|
||||
|
||||
// This test checks if Option Request Option (ORO) in docsis (vendor-id=4491)
|
||||
|
Reference in New Issue
Block a user