// Copyright (C) 2018-2022 Internet Systems Consortium, Inc. ("ISC") // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; using namespace isc::data; using namespace isc::asiolink; using namespace isc::dhcp; using namespace isc::dhcp::test; class SanityChecksTest : public ::testing::Test { public: SanityChecksTest() { LeaseMgrFactory::destroy(); } void startLeaseBackend(bool v6) { std::ostringstream s; s << "type=memfile " << (v6 ? "universe=6 " : "universe=4 ") << "persist=false lfc-interval=0"; LeaseMgrFactory::create(s.str()); } void setLeaseCheck(CfgConsistency::LeaseSanity sanity) { CfgMgr::instance().getCurrentCfg()->getConsistency()->setLeaseSanityCheck(sanity); } ~SanityChecksTest() { CfgMgr::instance().clear(); LeaseMgrFactory::destroy(); } /// @brief Generates a simple IPv4 lease. /// /// The HW address is randomly generated, subnet_id is specified. /// /// @param address Lease address. /// @param subnet_id ID of the subnet to use. /// /// @return new lease with random content Lease4Ptr newLease4(const IOAddress& address, SubnetID subnet_id) { // Randomize HW address. vector mac(6); isc::util::fillRandom(mac.begin(), mac.end()); HWAddrPtr hwaddr(new HWAddr(mac, HTYPE_ETHER)); vector clientid(1); time_t timestamp = time(0) - 86400 + random() % 86400; // Return created lease. return (Lease4Ptr(new Lease4(address, hwaddr, &clientid[0], 0, // no client-id 1200, // valid timestamp, subnet_id, false, false, ""))); } /// @brief Generates a simple IPv6 lease. /// /// The DUID and IAID are randomly generated, subnet_id is specified. /// /// @param address Lease address. /// @param subnet_id ID of the subnet to use. /// /// @return new lease with random content Lease6Ptr newLease6(const IOAddress& address, SubnetID subnet_id) { // Let's generate DUID of random length. std::vector duid_vec(8 + random()%20); // And then fill it with random value. isc::util::fillRandom(duid_vec.begin(), duid_vec.end()); DuidPtr duid(new DUID(duid_vec)); Lease::Type lease_type = Lease::TYPE_NA; uint32_t iaid = 1 + random()%100; std::ostringstream hostname; hostname << "hostname" << (random() % 2048); // Return created lease. Lease6Ptr lease(new Lease6(lease_type, address, duid, iaid, 1000, 1200, // pref, valid subnet_id, false, false, "")); // fqdn fwd, rev, hostname return (lease); } Subnet4Ptr createSubnet4(string subnet_txt, SubnetID id) { size_t pos = subnet_txt.find("/"); isc::asiolink::IOAddress addr(subnet_txt.substr(0, pos)); size_t len = boost::lexical_cast(subnet_txt.substr(pos + 1)); return (Subnet4Ptr(new Subnet4(addr, len, 1000, 2000, 3000, id))); } Subnet6Ptr createSubnet6(string subnet_txt, SubnetID id) { size_t pos = subnet_txt.find("/"); isc::asiolink::IOAddress addr(subnet_txt.substr(0, pos)); size_t len = boost::lexical_cast(subnet_txt.substr(pos + 1)); return (Subnet6Ptr(new Subnet6(addr, len, 1000, 2000, 3000, 4000, id))); } void parserCheck(SrvConfig& cfg, const string& txt, bool exp_throw, CfgConsistency::LeaseSanity exp_sanity, CfgConsistency::ExtendedInfoSanity exp_sanity2) { // Reset to defaults. cfg.getConsistency()->setLeaseSanityCheck(CfgConsistency::LEASE_CHECK_NONE); cfg.getConsistency()->setExtendedInfoSanityCheck(CfgConsistency::EXTENDED_INFO_CHECK_FIX); SanityChecksParser parser; ElementPtr json; EXPECT_NO_THROW(json = Element::fromJSON(txt)); if (exp_throw) { // Should throw DhcpConfigError. try { parser.parse(cfg, json); ADD_FAILURE() << "should throw not did not throw"; return; } catch (const DhcpConfigError&) { return; } catch (const exception& ex) { ADD_FAILURE() << "throw another exception with " << ex.what(); } } else { // Should not throw. try { parser.parse(cfg, json); } catch (const exception& ex) { ADD_FAILURE() << "throw an exception with " << ex.what(); } } EXPECT_EQ(cfg.getConsistency()->getLeaseSanityCheck(), exp_sanity); EXPECT_EQ(cfg.getConsistency()->getExtendedInfoSanityCheck(), exp_sanity2); } }; // Verify whether configuration parser is able to understand the values // that are valid and reject those that are not. TEST_F(SanityChecksTest, leaseCheck) { // These are valid and should be accepted. string valid1 = "{ \"lease-checks\": \"none\" }"; string valid2 = "{ \"lease-checks\": \"warn\" }"; string valid3 = "{ \"lease-checks\": \"fix\" }"; string valid4 = "{ \"lease-checks\": \"fix-del\" }"; string valid5 = "{ \"lease-checks\": \"del\" }"; // These are not valid values or types. string bogus1 = "{ \"lease-checks\": \"sanitize\" }"; string bogus2 = "{ \"lease-checks\": \"ignore\" }"; string bogus3 = "{ \"lease-checks\": true }"; string bogus4 = "{ \"lease-checks\": 42 }"; // These are valid and should be accepted. string valid6 = "{ \"extended-info-checks\": \"none\" }"; string valid7 = "{ \"extended-info-checks\": \"fix\" }"; string valid8 = "{ \"extended-info-checks\": \"strict\" }"; string valid9 = "{ \"extended-info-checks\": \"pedantic\" }"; string valid10 = "{ \"lease-checks\": \"fix\",\n" " \"extended-info-checks\": \"fix\" }"; string bogus5 = "{ \"extended-info-checks\": \"sanitize\" }"; string bogus6 = "{ \"extended-info-checks\": \"ignore\" }"; string bogus7 = "{ \"extended-info-checks\": true }"; string bogus8 = "{ \"extended-info-checks\": 42 }"; SrvConfig cfg; // The lease default should be to none. EXPECT_EQ(cfg.getConsistency()->getLeaseSanityCheck(), CfgConsistency::LEASE_CHECK_NONE); // The extended info default should be to fix. EXPECT_EQ(cfg.getConsistency()->getExtendedInfoSanityCheck(), CfgConsistency::EXTENDED_INFO_CHECK_FIX); parserCheck(cfg, valid1, false, CfgConsistency::LEASE_CHECK_NONE, CfgConsistency::EXTENDED_INFO_CHECK_FIX); parserCheck(cfg, valid2, false, CfgConsistency::LEASE_CHECK_WARN, CfgConsistency::EXTENDED_INFO_CHECK_FIX); parserCheck(cfg, valid3, false, CfgConsistency::LEASE_CHECK_FIX, CfgConsistency::EXTENDED_INFO_CHECK_FIX); parserCheck(cfg, valid4, false, CfgConsistency::LEASE_CHECK_FIX_DEL, CfgConsistency::EXTENDED_INFO_CHECK_FIX); parserCheck(cfg, valid5, false, CfgConsistency::LEASE_CHECK_DEL, CfgConsistency::EXTENDED_INFO_CHECK_FIX); parserCheck(cfg, bogus1, true, CfgConsistency::LEASE_CHECK_NONE, CfgConsistency::EXTENDED_INFO_CHECK_FIX); parserCheck(cfg, bogus2, true, CfgConsistency::LEASE_CHECK_NONE, CfgConsistency::EXTENDED_INFO_CHECK_FIX); parserCheck(cfg, bogus3, true, CfgConsistency::LEASE_CHECK_NONE, CfgConsistency::EXTENDED_INFO_CHECK_FIX); parserCheck(cfg, bogus4, true, CfgConsistency::LEASE_CHECK_NONE, CfgConsistency::EXTENDED_INFO_CHECK_FIX); parserCheck(cfg, valid6, false, CfgConsistency::LEASE_CHECK_NONE, CfgConsistency::EXTENDED_INFO_CHECK_NONE); parserCheck(cfg, valid7, false, CfgConsistency::LEASE_CHECK_NONE, CfgConsistency::EXTENDED_INFO_CHECK_FIX); parserCheck(cfg, valid8, false, CfgConsistency::LEASE_CHECK_NONE, CfgConsistency::EXTENDED_INFO_CHECK_STRICT); parserCheck(cfg, valid9, false, CfgConsistency::LEASE_CHECK_NONE, CfgConsistency::EXTENDED_INFO_CHECK_PEDANTIC); parserCheck(cfg, valid10, false, CfgConsistency::LEASE_CHECK_FIX, CfgConsistency::EXTENDED_INFO_CHECK_FIX); parserCheck(cfg, bogus5, true, CfgConsistency::LEASE_CHECK_NONE, CfgConsistency::EXTENDED_INFO_CHECK_FIX); parserCheck(cfg, bogus6, true, CfgConsistency::LEASE_CHECK_NONE, CfgConsistency::EXTENDED_INFO_CHECK_FIX); parserCheck(cfg, bogus7, true, CfgConsistency::LEASE_CHECK_NONE, CfgConsistency::EXTENDED_INFO_CHECK_FIX); parserCheck(cfg, bogus8, true, CfgConsistency::LEASE_CHECK_NONE, CfgConsistency::EXTENDED_INFO_CHECK_FIX); } // Verify whether sanity checker works as expected (valid v4). TEST_F(SanityChecksTest, valid4) { // Create network and lease. CfgMgr::instance().setFamily(AF_INET); Subnet4Ptr subnet = createSubnet4("192.168.1.0/24", 1); CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->add(subnet); IOAddress addr("192.168.1.1"); Lease4Ptr lease = newLease4(addr, 1); // Check the lease. setLeaseCheck(CfgConsistency::LEASE_CHECK_FIX_DEL); SanityChecker checker; checker.checkLease(lease); // Verify the lease is still here in the same subnet. ASSERT_TRUE(lease); EXPECT_EQ(subnet->getID(), lease->subnet_id_); } // Verify whether sanity checker works as expected (valid v6). TEST_F(SanityChecksTest, valid6) { // Create network and lease. CfgMgr::instance().setFamily(AF_INET6); Subnet6Ptr subnet = createSubnet6("2001:db8:1::/64", 1); CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->add(subnet); IOAddress addr("2001:db8:1::1"); Lease6Ptr lease = newLease6(addr, 1); // Check the lease. setLeaseCheck(CfgConsistency::LEASE_CHECK_FIX_DEL); SanityChecker checker; checker.checkLease(lease); // Verify the lease is still here in the same subnet. ASSERT_TRUE(lease); EXPECT_EQ(subnet->getID(), lease->subnet_id_); } // Verify whether sanity checker works as expected (wrong subnet v4). TEST_F(SanityChecksTest, wrongSubnet4) { // Create networks and lease in the second and wrong subnet. CfgMgr::instance().setFamily(AF_INET); Subnet4Ptr subnet1 = createSubnet4("192.168.1.0/24", 1); Subnet4Ptr subnet2 = createSubnet4("192.168.2.0/24", 2); CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->add(subnet1); CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->add(subnet2); IOAddress addr("192.168.1.1"); Lease4Ptr lease = newLease4(addr, 2); // Check the lease. setLeaseCheck(CfgConsistency::LEASE_CHECK_FIX_DEL); SanityChecker checker; checker.checkLease(lease); // Verify the lease is still here but was moved to the first and right subnet. ASSERT_TRUE(lease); EXPECT_EQ(subnet1->getID(), lease->subnet_id_); } // Verify whether sanity checker works as expected (wrong subnet v6). TEST_F(SanityChecksTest, wrongSubnet6) { // Create networks and lease in the second and wrong subnet. CfgMgr::instance().setFamily(AF_INET6); Subnet6Ptr subnet1 = createSubnet6("2001:db8:1::/64", 1); Subnet6Ptr subnet2 = createSubnet6("2001:db8:2::/64", 2); CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->add(subnet1); CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->add(subnet2); IOAddress addr("2001:db8:1::1"); Lease6Ptr lease = newLease6(addr, 2); // Check the lease. setLeaseCheck(CfgConsistency::LEASE_CHECK_FIX_DEL); SanityChecker checker; checker.checkLease(lease); // Verify the lease is still here but was moved to the first and right subnet. ASSERT_TRUE(lease); EXPECT_EQ(subnet1->getID(), lease->subnet_id_); } // Verify whether sanity checker works as expected (no subnet v4). TEST_F(SanityChecksTest, noSubnet4) { // Create network and lease in a wrong subnet. CfgMgr::instance().setFamily(AF_INET); Subnet4Ptr subnet = createSubnet4("192.168.2.0/24", 1); CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->add(subnet); IOAddress addr("192.168.1.1"); Lease4Ptr lease = newLease4(addr, 1); // Check the lease. setLeaseCheck(CfgConsistency::LEASE_CHECK_FIX_DEL); SanityChecker checker; checker.checkLease(lease); // Verify the lease was removed because its subnet does not exist, EXPECT_FALSE(lease); } // Verify whether sanity checker works as expected (no subnet v6). TEST_F(SanityChecksTest, noSubnet6) { // Create network and lease in a wrong subnet. CfgMgr::instance().setFamily(AF_INET6); Subnet6Ptr subnet = createSubnet6("2001:db8:2::/64", 1); CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->add(subnet); IOAddress addr("2001:db8:1::1"); Lease6Ptr lease = newLease6(addr, 1); // Check the lease. setLeaseCheck(CfgConsistency::LEASE_CHECK_FIX_DEL); SanityChecker checker; checker.checkLease(lease); // Verify the lease was removed because its subnet does not exist, EXPECT_FALSE(lease); } // Verify whether sanity checker works as expected (guard v4). TEST_F(SanityChecksTest, guard4) { // Create networks and lease in the first and guarded subnet. CfgMgr::instance().setFamily(AF_INET); Subnet4Ptr subnet1 = createSubnet4("192.168.1.0/24", 1); subnet1->allowClientClass("foo"); Subnet4Ptr subnet2 = createSubnet4("192.168.1.100/24", 2); CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->add(subnet1); CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->add(subnet2); IOAddress addr("192.168.1.1"); Lease4Ptr lease = newLease4(addr, 1); // Check the lease. setLeaseCheck(CfgConsistency::LEASE_CHECK_FIX_DEL); SanityChecker checker; checker.checkLease(lease); // Verify the lease is still here and in the guarded subnet. ASSERT_TRUE(lease); EXPECT_EQ(subnet1->getID(), lease->subnet_id_); } // Verify whether sanity checker works as expected (guard v6). TEST_F(SanityChecksTest, guard6) { // Create networks and lease in the first and guarded subnet. CfgMgr::instance().setFamily(AF_INET6); Subnet6Ptr subnet1 = createSubnet6("2001:db8:1::/64", 1); subnet1->allowClientClass("foo"); Subnet6Ptr subnet2 = createSubnet6("2001:db8:2::100/64", 2); CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->add(subnet1); CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->add(subnet2); IOAddress addr("2001:db8:1::1"); Lease6Ptr lease = newLease6(addr, 1); // Check the lease. setLeaseCheck(CfgConsistency::LEASE_CHECK_FIX_DEL); SanityChecker checker; checker.checkLease(lease); // Verify the lease is still here and in the guarded subnet. ASSERT_TRUE(lease); EXPECT_EQ(subnet1->getID(), lease->subnet_id_); } // Verify whether sanity checker works as expected (guard only v4). TEST_F(SanityChecksTest, guardOnly4) { // Create guarded network and lease. CfgMgr::instance().setFamily(AF_INET); Subnet4Ptr subnet = createSubnet4("192.168.1.0/24", 1); subnet->allowClientClass("foo"); CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->add(subnet); IOAddress addr("192.168.1.1"); Lease4Ptr lease = newLease4(addr, 1); // Check the lease. setLeaseCheck(CfgConsistency::LEASE_CHECK_FIX_DEL); SanityChecker checker; checker.checkLease(lease); // Verify the lease is still here in the same subnet. ASSERT_TRUE(lease); EXPECT_EQ(subnet->getID(), lease->subnet_id_); } // Verify whether sanity checker works as expected (valid v6). TEST_F(SanityChecksTest, guardOnly6) { // Create guarded network and lease. CfgMgr::instance().setFamily(AF_INET6); Subnet6Ptr subnet = createSubnet6("2001:db8:1::/64", 1); subnet->allowClientClass("foo"); CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->add(subnet); IOAddress addr("2001:db8:1::1"); Lease6Ptr lease = newLease6(addr, 1); // Check the lease. setLeaseCheck(CfgConsistency::LEASE_CHECK_FIX_DEL); SanityChecker checker; checker.checkLease(lease); // Verify the lease is still here in the same subnet. ASSERT_TRUE(lease); EXPECT_EQ(subnet->getID(), lease->subnet_id_); } class ExtendedInfoChecksTest : public LogContentTest { public: /// @brief Generates a simple IPv4 lease. /// /// The HW address is randomly generated, user context is specified. /// /// @param address Lease address. /// @param user_context User context to use. /// /// @return new lease with random content. Lease4Ptr newLease4(const IOAddress& address, ConstElementPtr user_context) { // Randomize HW address. vector mac(6); isc::util::fillRandom(mac.begin(), mac.end()); HWAddrPtr hwaddr(new HWAddr(mac, HTYPE_ETHER)); vector clientid(1); time_t timestamp = time(0) - 86400 + random() % 86400; // Return created lease. Lease4Ptr lease(new Lease4(address, hwaddr, &clientid[0], 0, // no client-id 1200, // valid timestamp, 1, false, false, "")); lease->setContext(user_context); return(lease); } /// @brief Generates a simple IPv6 lease. /// /// The DUID and IAID are randomly generated, user context is specified. /// /// @param address Lease address. /// @param user_context User context to use. /// /// @return new lease with random content. Lease6Ptr newLease6(const IOAddress& address, ConstElementPtr user_context) { // Let's generate DUID of random length. std::vector duid_vec(8 + random()%20); // And then fill it with random value. isc::util::fillRandom(duid_vec.begin(), duid_vec.end()); DuidPtr duid(new DUID(duid_vec)); Lease::Type lease_type = Lease::TYPE_NA; uint32_t iaid = 1 + random()%100; std::ostringstream hostname; hostname << "hostname" << (random() % 2048); // Return created lease. Lease6Ptr lease(new Lease6(lease_type, address, duid, iaid, 1000, 1200, // pref, valid 1, false, false, "")); lease->setContext(user_context); return(lease); } /// @brief Check IPv4 scenario. /// /// @brief original Original user context. /// @brief expected Expected user context. /// @brief sanity Extended info sanity level. /// @break logs Expected log messages. void check4(string description, string original, string expected, CfgConsistency::ExtendedInfoSanity sanity, vector logs = {}) { ElementPtr orig_context; if (!original.empty()) { ASSERT_NO_THROW(orig_context = Element::fromJSON(original)) << "invalid original user context, test " << description << " is broken"; } ElementPtr exp_context; if (!expected.empty()) { ASSERT_NO_THROW(exp_context = Element::fromJSON(expected)) << "invalid expected user context, test " << description << " is broken"; } Lease4Ptr lease = newLease4(IOAddress("192.168.1.1"), orig_context); ConstElementPtr before; if (orig_context) { before = isc::data::copy(orig_context); } for (const string& log : logs) { addString(log); } bool ret = LeaseMgr::upgradeLease4ExtendedInfo(lease, sanity); ConstElementPtr after = lease->getContext(); if (!before && !after) { EXPECT_FALSE(ret) << "null before and null after"; } else if ((before && !after) || (!before && after)) { EXPECT_TRUE(ret) << "only one of before and after is null"; } else if (before->equals(*after)) { EXPECT_FALSE(ret) << "before == after"; } else { EXPECT_TRUE(ret) << "before != after"; } if (!exp_context) { EXPECT_FALSE(after) << "expected null, got " << *after; } else { ASSERT_TRUE(after) << "expected not null, got null"; EXPECT_TRUE(exp_context->equals(*after)) << "expected: " << *exp_context << std::endl << "actual: " << *after << std::endl; } EXPECT_TRUE(checkFile()); } /// @brief Check IPv6 scenario. /// /// @brief original Original user context. /// @brief expected Expected user context. /// @brief sanity Extended info sanity level. /// @break logs Expected log messages. void check6(string description, string original, string expected, CfgConsistency::ExtendedInfoSanity sanity, vector logs = {}) { ElementPtr orig_context; if (!original.empty()) { ASSERT_NO_THROW(orig_context = Element::fromJSON(original)) << "invalid original user context, test " << description << " is broken"; } ElementPtr exp_context; if (!expected.empty()) { ASSERT_NO_THROW(exp_context = Element::fromJSON(expected)) << "invalid expected user context, test " << description << " is broken"; } Lease6Ptr lease = newLease6(IOAddress("2001::1"), orig_context); ConstElementPtr before; if (orig_context) { before = isc::data::copy(orig_context); } for (const string& log : logs) { addString(log); } bool ret = LeaseMgr::upgradeLease6ExtendedInfo(lease, sanity); ConstElementPtr after = lease->getContext(); if (!before && !after) { EXPECT_FALSE(ret) << "null before and null after"; } else if ((before && !after) || (!before && after)) { EXPECT_TRUE(ret) << "only one of before and after is null"; } else if (before->equals(*after)) { EXPECT_FALSE(ret) << "before == after"; } else { EXPECT_TRUE(ret) << "before != after"; } if (!exp_context) { EXPECT_FALSE(after) << "expected null, got " << *after; } else { ASSERT_TRUE(after) << "expected not null, got null"; EXPECT_TRUE(exp_context->equals(*after)) << "expected: " << *exp_context << std::endl << "actual: " << *after << std::endl; } EXPECT_TRUE(checkFile()); } }; // No user context is right for any sanity check level including the highest. TEST_F(ExtendedInfoChecksTest, noUserContext4) { string description = "no user context, pedantic"; check4(description, "", "", CfgConsistency::EXTENDED_INFO_CHECK_PEDANTIC); } // User context with a bad type is right only when no check is done. TEST_F(ExtendedInfoChecksTest, badTypeUserContext4none) { string description = "user context not a map, none"; check4(description, "1", "1", CfgConsistency::EXTENDED_INFO_CHECK_NONE); } // User context with a bad type is refused by all not none sanity check levels. TEST_F(ExtendedInfoChecksTest, badTypeUserContext4) { string description = "user context not a map, fix"; check4(description, "1", "", CfgConsistency::EXTENDED_INFO_CHECK_FIX, { "DHCPSRV_LEASE4_EXTENDED_INFO_SANITY_FAIL" " extended info for lease 192.168.1.1 failed checks" " (in user context a problem was found:" " user context is not a map)" }); } // Empty user context is right only when no check is done. TEST_F(ExtendedInfoChecksTest, emptyTypeUserContext4none) { string description = "empty user context, none"; check4(description, "{ }", "{ }", CfgConsistency::EXTENDED_INFO_CHECK_NONE); } // Empty user context is dropped by all not none sanity check levels. TEST_F(ExtendedInfoChecksTest, emptyTypeUserContext4) { string description = "empty user context, fix"; check4(description, "{ }", "", CfgConsistency::EXTENDED_INFO_CHECK_FIX); } // No ISC entry is right in all cases. TEST_F(ExtendedInfoChecksTest, noISC4) { string description = "no ISC entry, pedantic"; check4(description, "{ \"foo\": 1 }", "{ \"foo\": 1 }", CfgConsistency::EXTENDED_INFO_CHECK_PEDANTIC); } // ISC entry with a bad type is right only when no check is done. TEST_F(ExtendedInfoChecksTest, badTypeISC4none) { string description = "ISC entry no a map, none"; check4(description, "{ \"ISC\": 1 }", "{ \"ISC\": 1 }", CfgConsistency::EXTENDED_INFO_CHECK_NONE); } // ISC entry with a bad type is dropped by all not none sanity check levels. TEST_F(ExtendedInfoChecksTest, badTypeISC4) { string description = "ISC entry no a map, fix"; check4(description, "{ \"ISC\": 1 }", "", CfgConsistency::EXTENDED_INFO_CHECK_FIX, { "DHCPSRV_LEASE4_EXTENDED_INFO_SANITY_FAIL" " extended info for lease 192.168.1.1 failed checks" " (in isc a problem was found:" " ISC entry is not a map)" }); } // When the ISC entry is dropped other entries are kept. TEST_F(ExtendedInfoChecksTest, badTypeISC4other) { string description = "ISC entry no a map with others, fix"; check4(description, "{ \"ISC\": 1, \"foo\": 2 }", "{ \"foo\": 2 }", CfgConsistency::EXTENDED_INFO_CHECK_FIX, { "DHCPSRV_LEASE4_EXTENDED_INFO_SANITY_FAIL" " extended info for lease 192.168.1.1 failed checks" " (in isc a problem was found:" " ISC entry is not a map)" }); } // Empty ISC entry is kept only when no check is done. TEST_F(ExtendedInfoChecksTest, emptyISC4none) { string description = "empty ISC entry, none"; check4(description, "{ \"ISC\": { } }", "{ \"ISC\": { } }", CfgConsistency::EXTENDED_INFO_CHECK_NONE); } // Empty ISC entry is dropped by all not none sanity check levels. TEST_F(ExtendedInfoChecksTest, emptyISC4) { string description = "empty ISC entry, fix"; check4(description, "{ \"ISC\": { } }", "", CfgConsistency::EXTENDED_INFO_CHECK_FIX); } // No relay-agent-info entry is right at all sanity levels. TEST_F(ExtendedInfoChecksTest, noRAI) { string description = "no RAI, pedantic"; check4(description, "{ \"ISC\": { \"foo\": 1 } }", "{ \"ISC\": { \"foo\": 1 } }", CfgConsistency::EXTENDED_INFO_CHECK_PEDANTIC); } // relay-agent-info entry with a bad type is right only when no check is done. TEST_F(ExtendedInfoChecksTest, badTypeRAInone) { string description = "RAI is not a string or a map, none"; check4(description, "{ \"ISC\": { \"relay-agent-info\": true } }", "{ \"ISC\": { \"relay-agent-info\": true } }", CfgConsistency::EXTENDED_INFO_CHECK_NONE); } // relay-agent-info entry with a bad type is dropped by all not none sanity // check levels. TEST_F(ExtendedInfoChecksTest, badTypeRAI) { string description = "RAI is not a string or a map, fix"; check4(description, "{ \"ISC\": { \"relay-agent-info\": true } }", "", CfgConsistency::EXTENDED_INFO_CHECK_FIX, { "DHCPSRV_LEASE4_EXTENDED_INFO_SANITY_FAIL" " extended info for lease 192.168.1.1 failed checks" " (in relay-agent-info a problem was found:" " relay-agent-info is not a map or a string)" }); } // When relay-agent-info entry is dropped other entries are kept. TEST_F(ExtendedInfoChecksTest, badTypeRAIother) { string description = "RAI is not a string or a map with others, fix"; check4(description, "{ \"ISC\": { \"relay-agent-info\": true, \"foo\": 1 } }", "{ \"ISC\": { \"foo\": 1 } }", CfgConsistency::EXTENDED_INFO_CHECK_FIX, { "DHCPSRV_LEASE4_EXTENDED_INFO_SANITY_FAIL" " extended info for lease 192.168.1.1 failed checks" " (in relay-agent-info a problem was found:" " relay-agent-info is not a map or a string)" }); } // String relay-agent-info entry which can't be decoded is right // only when no check is done. TEST_F(ExtendedInfoChecksTest, badEncodingStringRAInone) { string description = "string RAI with a junk value, none"; check4(description, "{ \"ISC\": { \"relay-agent-info\": \"foo\" } }", "{ \"ISC\": { \"relay-agent-info\": \"foo\" } }", CfgConsistency::EXTENDED_INFO_CHECK_NONE); } // String relay-agent-info entry which can't be decoded is dropped // by all not none sanity check levels. TEST_F(ExtendedInfoChecksTest, badEncodingStringRAI) { string description = "string RAI with a junk value, fix"; check4(description, "{ \"ISC\": { \"relay-agent-info\": \"foo\" } }", "", CfgConsistency::EXTENDED_INFO_CHECK_FIX, { "DHCPSRV_LEASE4_EXTENDED_INFO_SANITY_FAIL" " extended info for lease 192.168.1.1 failed checks" " (in rai a problem was found:" " 'foo' is not a valid string of hexadecimal digits)" }); } // String relay-agent-info entry for an empty option is dropped // by all not none sanity check levels (this should not happen). TEST_F(ExtendedInfoChecksTest, emptyStringRAI) { string description = "string RAI with empty content, fix"; check4(description, "{ \"ISC\": { \"relay-agent-info\": \"0x\" } }", "", CfgConsistency::EXTENDED_INFO_CHECK_FIX, { "DHCPSRV_LEASE4_EXTENDED_INFO_SANITY_FAIL" " extended info for lease 192.168.1.1 failed checks" " (in rai a problem was found:" " '0x' is not a valid string of hexadecimal digits)" }); } // Valid string relay-agent-info entry is upgraded by all not none // sanity check levels. TEST_F(ExtendedInfoChecksTest, upgradedRAI) { string description = "valid string RAI, fix"; check4(description, "{ \"ISC\": { \"relay-agent-info\": \"0x0104AABBCCDD\" } }", "{ \"ISC\": { \"relay-agent-info\": { \"sub-options\":" " \"0x0104AABBCCDD\" } } }", CfgConsistency::EXTENDED_INFO_CHECK_FIX, { "DHCPSRV_LEASE4_EXTENDED_INFO_UPGRADED" " extended info for lease 192.168.1.1 was upgraded" }); } // Upgraded string relay-agent-info entry with ids. TEST_F(ExtendedInfoChecksTest, upgradedRAIwithIds) { string description = "valid string RAI with ids, fix"; check4(description, "{ \"ISC\": { \"relay-agent-info\": \"0x02030102030C03AABBCC\" } }", "{ \"ISC\": { \"relay-agent-info\": { \"sub-options\":" " \"0x02030102030C03AABBCC\", \"remote-id\": \"010203\"," " \"relay-id\": \"AABBCC\" } } }", CfgConsistency::EXTENDED_INFO_CHECK_FIX, { "DHCPSRV_LEASE4_EXTENDED_INFO_UPGRADED" " extended info for lease 192.168.1.1 was upgraded" }); } // sub-options entry with a bad type is right up to the fix sanity level. TEST_F(ExtendedInfoChecksTest, badTypeSubOptionsfix) { string description = "sub-options not a string, fix"; check4(description, "{ \"ISC\": { \"relay-agent-info\": { \"sub-options\": 1 } } }", "{ \"ISC\": { \"relay-agent-info\": { \"sub-options\": 1 } } }", CfgConsistency::EXTENDED_INFO_CHECK_FIX); } // sub-options entry with a bad type is dropped at strict or higher // sanity levels. TEST_F(ExtendedInfoChecksTest, badTypeSubOptionsstrict) { string description = "sub-options not a string, strict"; check4(description, "{ \"ISC\": { \"relay-agent-info\": { \"sub-options\": 1 } } }", "", CfgConsistency::EXTENDED_INFO_CHECK_STRICT, { "DHCPSRV_LEASE4_EXTENDED_INFO_SANITY_FAIL" " extended info for lease 192.168.1.1 failed checks" " (in sub-options a problem was found:" " sub-options is not a string)" }); } // sub-options entry which can't be decoded is right up to the fix // sanity level. TEST_F(ExtendedInfoChecksTest, badEncodingSubOptionsfix) { string description = "sub-options with a junk value, fix"; check4(description, "{ \"ISC\": { \"relay-agent-info\": { \"sub-options\":" " \"foo\" } } }", "{ \"ISC\": { \"relay-agent-info\": { \"sub-options\":" " \"foo\" } } }", CfgConsistency::EXTENDED_INFO_CHECK_FIX); } // sub-options entry which can't be decoded is dropped at strict or higher // sanity levels. TEST_F(ExtendedInfoChecksTest, badEncodingSubOptionsstrict) { string description = "sub-options with a junk value, strict"; check4(description, "{ \"ISC\": { \"relay-agent-info\": { \"sub-options\":" " \"foo\" } } }", "", CfgConsistency::EXTENDED_INFO_CHECK_STRICT, { "DHCPSRV_LEASE4_EXTENDED_INFO_SANITY_FAIL" " extended info for lease 192.168.1.1 failed checks" " (in sub-options a problem was found:" " 'foo' is not a valid string of hexadecimal digits)" }); } // remote-id entry with a bad type is right up to the fix sanity level. TEST_F(ExtendedInfoChecksTest, badTypeRemoteId4fix) { string description = "remote-id not a string, fix"; check4(description, "{ \"ISC\": { \"relay-agent-info\": { \"remote-id\": 1 } } }", "{ \"ISC\": { \"relay-agent-info\": { \"remote-id\": 1 } } }", CfgConsistency::EXTENDED_INFO_CHECK_FIX); } // remote-id entry with a bad type is dropped at strict or higher // sanity levels. TEST_F(ExtendedInfoChecksTest, badTypeRemoteId4strict) { string description = "remote-id not a string, strict"; check4(description, "{ \"ISC\": { \"relay-agent-info\": { \"remote-id\": 1 } } }", "", CfgConsistency::EXTENDED_INFO_CHECK_STRICT, { "DHCPSRV_LEASE4_EXTENDED_INFO_SANITY_FAIL" " extended info for lease 192.168.1.1 failed checks" " (in remote-id a problem was found:" " remote-id is not a string)" }); } // remote-id entry which can't be decoded is right up to the fix sanity level. TEST_F(ExtendedInfoChecksTest, badEncodingRemoteId4fix) { string description = "remote-id with a junk value, fix"; check4(description, "{ \"ISC\": { \"relay-agent-info\": { \"remote-id\":" " \"foo\" } } }", "{ \"ISC\": { \"relay-agent-info\": { \"remote-id\":" " \"foo\" } } }", CfgConsistency::EXTENDED_INFO_CHECK_FIX); } // remote-id entry which can't be decoded is dropped at strict or higher // sanity levels. TEST_F(ExtendedInfoChecksTest, badEncodingRemoteId4strict) { string description = "remote-id with a junk value, strict"; check4(description, "{ \"ISC\": { \"relay-agent-info\": { \"remote-id\":" " \"foo\" } } }", "", CfgConsistency::EXTENDED_INFO_CHECK_STRICT, { "DHCPSRV_LEASE4_EXTENDED_INFO_SANITY_FAIL" " extended info for lease 192.168.1.1 failed checks" " (in remote-id a problem was found:" " attempt to decode a value not in base16 char set)" }); } // Empty remote-id entry is right up to the fix sanity level. TEST_F(ExtendedInfoChecksTest, emptyRemoteId4fix) { string description = "empty remote-id, fix"; check4(description, "{ \"ISC\": { \"relay-agent-info\": { \"remote-id\": \"\" } } }", "{ \"ISC\": { \"relay-agent-info\": { \"remote-id\": \"\" } } }", CfgConsistency::EXTENDED_INFO_CHECK_FIX); } // Empty remote-id entry is dropped at strict or higher sanity levels. TEST_F(ExtendedInfoChecksTest, emptyRemoteId4strict) { string description = "empty remote-id, strict"; check4(description, "{ \"ISC\": { \"relay-agent-info\": { \"remote-id\": \"\" } } }", "", CfgConsistency::EXTENDED_INFO_CHECK_STRICT, { "DHCPSRV_LEASE4_EXTENDED_INFO_SANITY_FAIL" " extended info for lease 192.168.1.1 failed checks" " (in remote-id a problem was found:" " remote-id is empty)" }); } // Valid remote-id entry is right for all sanity levels. TEST_F(ExtendedInfoChecksTest, validRemoteId4strict) { string description = "valid remote-id, strict"; check4(description, "{ \"ISC\": { \"relay-agent-info\": { \"remote-id\":" " \"AABB\" } } }", "{ \"ISC\": { \"relay-agent-info\": { \"remote-id\":" " \"AABB\" } } }", CfgConsistency::EXTENDED_INFO_CHECK_STRICT); } // relay-id entry with a bad type is right up to the fix sanity level. TEST_F(ExtendedInfoChecksTest, badTypeRelayId4fix) { string description = "relay-id not a string, fix"; check4(description, "{ \"ISC\": { \"relay-agent-info\": { \"relay-id\": 1 } } }", "{ \"ISC\": { \"relay-agent-info\": { \"relay-id\": 1 } } }", CfgConsistency::EXTENDED_INFO_CHECK_FIX); } // relay-id entry with a bad type is dropped at strict or higher // sanity levels. TEST_F(ExtendedInfoChecksTest, badTypeRelayId4strict) { string description = "relay-id not a string, strict"; check4(description, "{ \"ISC\": { \"relay-agent-info\": { \"relay-id\": 1 } } }", "", CfgConsistency::EXTENDED_INFO_CHECK_STRICT, { "DHCPSRV_LEASE4_EXTENDED_INFO_SANITY_FAIL" " extended info for lease 192.168.1.1 failed checks" " (in relay-id a problem was found:" " relay-id is not a string)" }); } // relay-id entry which can't be decoded is right up to the fix sanity level. TEST_F(ExtendedInfoChecksTest, badEncodingRelayId4fix) { string description = "relay-id with a junk value, fix"; check4(description, "{ \"ISC\": { \"relay-agent-info\": { \"relay-id\":" " \"foo\" } } }", "{ \"ISC\": { \"relay-agent-info\": { \"relay-id\":" " \"foo\" } } }", CfgConsistency::EXTENDED_INFO_CHECK_FIX); } // relay-id entry which can't be decoded is dropped at strict or higher // sanity levels. TEST_F(ExtendedInfoChecksTest, badEncodingRelayId4strict) { string description = "relay-id with a junk value, strict"; check4(description, "{ \"ISC\": { \"relay-agent-info\": { \"relay-id\":" " \"foo\" } } }", "", CfgConsistency::EXTENDED_INFO_CHECK_STRICT, { "DHCPSRV_LEASE4_EXTENDED_INFO_SANITY_FAIL" " extended info for lease 192.168.1.1 failed checks" " (in relay-id a problem was found:" " attempt to decode a value not in base16 char set)" }); } // Empty relay-id entry is right up to the fix sanity level. TEST_F(ExtendedInfoChecksTest, emptyRelayId4fix) { string description = "empty relay-id, fix"; check4(description, "{ \"ISC\": { \"relay-agent-info\": { \"relay-id\": \"\" } } }", "{ \"ISC\": { \"relay-agent-info\": { \"relay-id\": \"\" } } }", CfgConsistency::EXTENDED_INFO_CHECK_FIX); } // Empty relay-id entry is dropped at strict or higher sanity levels. TEST_F(ExtendedInfoChecksTest, emptyRelayId4strict) { string description = "empty relay-id, strict"; check4(description, "{ \"ISC\": { \"relay-agent-info\": { \"relay-id\": \"\" } } }", "", CfgConsistency::EXTENDED_INFO_CHECK_STRICT, { "DHCPSRV_LEASE4_EXTENDED_INFO_SANITY_FAIL" " extended info for lease 192.168.1.1 failed checks" " (in relay-id a problem was found:" " relay-id is empty)" }); } // Valid relay-id entry is right for all sanity levels. TEST_F(ExtendedInfoChecksTest, validRelayId4strict) { string description = "valid relay-id, strict"; check4(description, "{ \"ISC\": { \"relay-agent-info\": { \"relay-id\":" " \"AABB\" } } }", "{ \"ISC\": { \"relay-agent-info\": { \"relay-id\":" " \"AABB\" } } }", CfgConsistency::EXTENDED_INFO_CHECK_STRICT); } // Junk entries are right up to the strict sanity level. TEST_F(ExtendedInfoChecksTest, junk4strict) { string description = "junk entry, strict"; check4(description, "{ \"ISC\": { \"relay-agent-info\": { \"foo\": 1 } } }", "{ \"ISC\": { \"relay-agent-info\": { \"foo\": 1 } } }", CfgConsistency::EXTENDED_INFO_CHECK_STRICT); } // Junk entries are dropped at the pedantic level. TEST_F(ExtendedInfoChecksTest, junk4pedantic) { string description = "junk entry, pedantic"; check4(description, "{ \"ISC\": { \"relay-agent-info\": { \"foo\": 1 } } }", "", CfgConsistency::EXTENDED_INFO_CHECK_PEDANTIC, { "DHCPSRV_LEASE4_EXTENDED_INFO_SANITY_FAIL" " extended info for lease 192.168.1.1 failed checks" " (in relay-agent-info a problem was found:" " spurious 'foo' entry in relay-agent-info)" }); } // comment is not considered as a junk entry. TEST_F(ExtendedInfoChecksTest, comment4) { string description = "comment entry, pedantic"; check4(description, "{ \"ISC\": { \"relay-agent-info\": { \"comment\": \"good\" } } }", "{ \"ISC\": { \"relay-agent-info\": { \"comment\": \"good\" } } }", CfgConsistency::EXTENDED_INFO_CHECK_PEDANTIC); } // No user context is right for any sanity check level including the highest. TEST_F(ExtendedInfoChecksTest, noUserContext6) { string description = "no user context, pedantic"; check6(description, "", "", CfgConsistency::EXTENDED_INFO_CHECK_PEDANTIC); } // User context with a bad type is right only when no check is done. TEST_F(ExtendedInfoChecksTest, badTypeUserContext6none) { string description = "user context not a map, none"; check6(description, "1", "1", CfgConsistency::EXTENDED_INFO_CHECK_NONE); } // User context with a bad type is refused by all not none sanity check levels. TEST_F(ExtendedInfoChecksTest, badTypeUserContext6) { string description = "user context not a map, fix"; check6(description, "1", "", CfgConsistency::EXTENDED_INFO_CHECK_FIX, { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL" " extended info for lease 2001::1 failed checks" " (in user context a problem was found:" " user context is not a map)" }); } // Empty user context is right only when no check is done. TEST_F(ExtendedInfoChecksTest, emptyTypeUserContext6none) { string description = "empty user context, none"; check6(description, "{ }", "{ }", CfgConsistency::EXTENDED_INFO_CHECK_NONE); } // Empty user context is dropped by all not none sanity check levels. TEST_F(ExtendedInfoChecksTest, emptyTypeUserContext6) { string description = "empty user context, fix"; check6(description, "{ }", "", CfgConsistency::EXTENDED_INFO_CHECK_FIX); } // No ISC entry is right in all cases. TEST_F(ExtendedInfoChecksTest, noISC6) { string description = "no ISC entry, pedantic"; check6(description, "{ \"foo\": 1 }", "{ \"foo\": 1 }", CfgConsistency::EXTENDED_INFO_CHECK_PEDANTIC); } // ISC entry with a bad type is right only when no check is done. TEST_F(ExtendedInfoChecksTest, badTypeISC6none) { string description = "ISC entry no a map, none"; check6(description, "{ \"ISC\": 1 }", "{ \"ISC\": 1 }", CfgConsistency::EXTENDED_INFO_CHECK_NONE); } // ISC entry with a bad type is dropped by all not none sanity check levels. TEST_F(ExtendedInfoChecksTest, badTypeISC6) { string description = "ISC entry no a map, fix"; check6(description, "{ \"ISC\": 1 }", "", CfgConsistency::EXTENDED_INFO_CHECK_FIX, { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL" " extended info for lease 2001::1 failed checks" " (in isc a problem was found:" " ISC entry is not a map)" }); } // When the ISC entry is dropped other entries are kept. TEST_F(ExtendedInfoChecksTest, badTypeISC6other) { string description = "ISC entry no a map with others, fix"; check6(description, "{ \"ISC\": 1, \"foo\": 2 }", "{ \"foo\": 2 }", CfgConsistency::EXTENDED_INFO_CHECK_FIX, { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL" " extended info for lease 2001::1 failed checks" " (in isc a problem was found:" " ISC entry is not a map)" }); } // Empty ISC entry is kept only when no check is done. TEST_F(ExtendedInfoChecksTest, emptyISC6none) { string description = "empty ISC entry, none"; check6(description, "{ \"ISC\": { } }", "{ \"ISC\": { } }", CfgConsistency::EXTENDED_INFO_CHECK_NONE); } // Empty ISC entry is dropped by all not none sanity check levels. TEST_F(ExtendedInfoChecksTest, emptyISC6) { string description = "empty ISC entry, fix"; check6(description, "{ \"ISC\": { } }", "", CfgConsistency::EXTENDED_INFO_CHECK_FIX); } // relays is not upgraded when no check is done. TEST_F(ExtendedInfoChecksTest, relaysnone) { string description = "relays, none"; check6(description, "{ \"ISC\": { \"relays\": true } }", "{ \"ISC\": { \"relays\": true } }", CfgConsistency::EXTENDED_INFO_CHECK_NONE); } // relays is dropped when relay-info is present by all not none sanity // check levels. TEST_F(ExtendedInfoChecksTest, relaysAndRelayInfo) { string description = "relays and relay-info, fix"; check6(description, "{ \"ISC\": { \"relays\": true, \"relay-info\":" " [ { \"foo\": 1 } ] } }", "{ \"ISC\": { \"relay-info\": [ { \"foo\": 1 } ] } }", CfgConsistency::EXTENDED_INFO_CHECK_FIX); } // relays with bad type is dropped by all not none sanity check levels. TEST_F(ExtendedInfoChecksTest, badTypeRelays) { string description = "relays is not a list, fix"; check6(description, "{ \"ISC\": { \"relays\": true } }", "", CfgConsistency::EXTENDED_INFO_CHECK_FIX, { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL" " extended info for lease 2001::1 failed checks" " (in relays a problem was found:" " relays is not a list)" }); } // Empty relays is dropped by all not none sanity check levels. TEST_F(ExtendedInfoChecksTest, emptyRelays) { string description = "empty relays, fix"; check6(description, "{ \"ISC\": { \"relays\": [ ] } }", "", CfgConsistency::EXTENDED_INFO_CHECK_FIX, { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL" " extended info for lease 2001::1 failed checks" " (in relays a problem was found:" " relays is empty)" }); } // Relay (element of relays) with bad type is dropped by all not none // sanity check levels. TEST_F(ExtendedInfoChecksTest, badTypeRelay) { string description = "relay is not a map, fix"; check6(description, "{ \"ISC\": { \"relays\": [ 1 ] } }", "", CfgConsistency::EXTENDED_INFO_CHECK_FIX, { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL" " extended info for lease 2001::1 failed checks" " (in relay [relay#0] a problem was found:" " relay#0 is not a map)" }); } // options with bad type is dropped by all not none sanity check levels. TEST_F(ExtendedInfoChecksTest, badTypeOptions) { string description = "options is not a string, fix"; check6(description, "{ \"ISC\": { \"relays\": [ { \"options\": 1 } ] } }", "", CfgConsistency::EXTENDED_INFO_CHECK_FIX, { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL" " extended info for lease 2001::1 failed checks" " (in options [relay#0] a problem was found:" " options is not a string)" }); } // options which can't be decoded is dropped by all not none sanity // check levels. TEST_F(ExtendedInfoChecksTest, badEncodingOptions) { string description = "options with junk value, fix"; check6(description, "{ \"ISC\": { \"relays\": [ { \"options\": \"foo\" } ] } }", "", CfgConsistency::EXTENDED_INFO_CHECK_FIX, { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL" " extended info for lease 2001::1 failed checks" " (in options [relay#0] a problem was found:" " 'foo' is not a valid string of hexadecimal digits)" }); } // Valid relays is upgraded by all not none sanity check levels. TEST_F(ExtendedInfoChecksTest, upgradedRelays) { string description = "upgraded relays, fix"; check6(description, "{ \"ISC\": { \"relays\": [ { \"hop\": 33," " \"link\": \"2001:db8::1\", \"peer\": \"2001:db8::2\"," " \"options\": \"0x00C800080102030405060708\" } ] } }", "{ \"ISC\": { \"relay-info\": [ { \"hop\": 33," " \"link\": \"2001:db8::1\", \"peer\": \"2001:db8::2\"," " \"options\": \"0x00C800080102030405060708\" } ] } }", CfgConsistency::EXTENDED_INFO_CHECK_FIX, { "DHCPSRV_LEASE6_EXTENDED_INFO_UPGRADED" " extended info for lease 2001::1 was upgraded" }); } // Valid relays with ids is upgraded by all not none sanity check levels. TEST_F(ExtendedInfoChecksTest, upgradedRelaysWithIds) { string description = "upgraded relays with ids, fix"; check6(description, "{ \"ISC\": { \"relays\": [ { \"hop\": 100," " \"options\": \"0x00250006010203040506003500086464646464646464\"," " \"link\": \"2001:db8::5\", \"peer\": \"2001:db8::6\" } ] } }", "{ \"ISC\": { \"relay-info\": [ { \"hop\": 100," " \"options\": \"0x00250006010203040506003500086464646464646464\"," " \"link\": \"2001:db8::5\", \"peer\": \"2001:db8::6\"," " \"remote-id\": \"010203040506\"," " \"relay-id\": \"6464646464646464\" } ] } }", CfgConsistency::EXTENDED_INFO_CHECK_FIX, { "DHCPSRV_LEASE6_EXTENDED_INFO_UPGRADED" " extended info for lease 2001::1 was upgraded" }); } // Valid relays with 2 relays is upgraded by all not none sanity check levels. TEST_F(ExtendedInfoChecksTest, upgradedRelays2) { string description = "upgraded relays with 2 relays, fix"; check6(description, "{ \"ISC\": { \"relays\": [ { \"hop\": 33," " \"link\": \"2001:db8::1\", \"peer\": \"2001:db8::2\"," " \"options\": \"0x00C800080102030405060708\" }, { \"hop\": 100," " \"options\": \"0x00250006010203040506003500086464646464646464\"," " \"link\": \"2001:db8::5\", \"peer\": \"2001:db8::6\" } ] } }", "{ \"ISC\": { \"relay-info\": [ { \"hop\": 33," " \"link\": \"2001:db8::1\", \"peer\": \"2001:db8::2\"," " \"options\": \"0x00C800080102030405060708\" }, { \"hop\": 100," " \"options\": \"0x00250006010203040506003500086464646464646464\"," " \"link\": \"2001:db8::5\", \"peer\": \"2001:db8::6\"," " \"remote-id\": \"010203040506\"," " \"relay-id\": \"6464646464646464\" } ] } }", CfgConsistency::EXTENDED_INFO_CHECK_FIX, { "DHCPSRV_LEASE6_EXTENDED_INFO_UPGRADED" " extended info for lease 2001::1 was upgraded" }); } // relayinfo with bad type is dropped by all not none sanity check levels. TEST_F(ExtendedInfoChecksTest, badTypeRelayInfo) { string description = "relayinfo is not a list, fix"; check6(description, "{ \"ISC\": { \"relay-info\": true } }", "", CfgConsistency::EXTENDED_INFO_CHECK_FIX, { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL" " extended info for lease 2001::1 failed checks" " (in relay-info a problem was found:" " relay-info is not a list)" }); } // Empty relay-info is dropped by all not none sanity check levels. TEST_F(ExtendedInfoChecksTest, emptyRelayInfo) { string description = "empty relay-info, fix"; check6(description, "{ \"ISC\": { \"relay-info\": [ ] } }", "", CfgConsistency::EXTENDED_INFO_CHECK_FIX, { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL" " extended info for lease 2001::1 failed checks" " (in relay-info a problem was found:" " relay-info is empty)" }); } // Relay (element of relay-info) with bad type is dropped by all not none // sanity check levels. TEST_F(ExtendedInfoChecksTest, badTypeRelay2) { string description = "relay is not a map, fix"; check6(description, "{ \"ISC\": { \"relay-info\": [ 1 ] } }", "", CfgConsistency::EXTENDED_INFO_CHECK_FIX, { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL" " extended info for lease 2001::1 failed checks" " (in relay [relay#0] a problem was found:" " relay#0 is not a map)" }); } // options with bad type is dropped by all not none sanity check levels. TEST_F(ExtendedInfoChecksTest, badTypeOptions2) { string description = "options is not a string, fix"; check6(description, "{ \"ISC\": { \"relay-info\": [ { \"options\": 1 } ] } }", "", CfgConsistency::EXTENDED_INFO_CHECK_FIX, { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL" " extended info for lease 2001::1 failed checks" " (in options [relay#0] a problem was found:" " options is not a string)" }); } // options which can't be decoded is dropped by all not none sanity // check levels. TEST_F(ExtendedInfoChecksTest, badEncodingOptions2) { string description = "options with junk value, fix"; check6(description, "{ \"ISC\": { \"relay-info\": [ { \"options\": \"foo\" } ] } }", "", CfgConsistency::EXTENDED_INFO_CHECK_FIX, { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL" " extended info for lease 2001::1 failed checks" " (in options [relay#0] a problem was found:" " 'foo' is not a valid string of hexadecimal digits)" }); } // Relay without a link entry is right up to fix sanity check level. TEST_F(ExtendedInfoChecksTest, noLinkfix) { string description = "no link, fix"; check6(description, "{ \"ISC\": { \"relay-info\": [ { \"foo\": 1 } ] } }", "{ \"ISC\": { \"relay-info\": [ { \"foo\": 1 } ] } }", CfgConsistency::EXTENDED_INFO_CHECK_FIX); } // Relay without a link entry is dropped by strict sanity check level and // higher. TEST_F(ExtendedInfoChecksTest, noLinkstrict) { string description = "no link, strict"; check6(description, "{ \"ISC\": { \"relay-info\": [ { \"foo\": 1 } ] } }", "", CfgConsistency::EXTENDED_INFO_CHECK_STRICT, { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL" " extended info for lease 2001::1 failed checks" " (in link [relay#0] a problem was found:" " no link)" }); } // link entry with bad type is dropped by strict sanity check level and higher. TEST_F(ExtendedInfoChecksTest, badTypeLink) { string description = "link is not a string, strict"; check6(description, "{ \"ISC\": { \"relay-info\": [ { \"link\": 1 } ] } }", "", CfgConsistency::EXTENDED_INFO_CHECK_STRICT, { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL" " extended info for lease 2001::1 failed checks" " (in link [relay#0] a problem was found:" " link is not a string)" }); } // link entry which is not an address is dropped by strict sanity check level // and higher. TEST_F(ExtendedInfoChecksTest, notAddressLink) { string description = "link is not an address, strict"; check6(description, "{ \"ISC\": { \"relay-info\": [ { \"link\": \"foo\" } ] } }", "", CfgConsistency::EXTENDED_INFO_CHECK_STRICT, { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL" " extended info for lease 2001::1 failed checks" " (in link [relay#0] a problem was found:" " Failed to convert string to address 'foo':" " Invalid argument)" }); } // link entry which is an IPv4 (vs IPv6) address is dropped by strict sanity // check level and higher. TEST_F(ExtendedInfoChecksTest, notV6Link) { string description = "link is v4, strict"; check6(description, "{ \"ISC\": { \"relay-info\": [ { \"link\":" " \"192.128.1.1\" } ] } }", "", CfgConsistency::EXTENDED_INFO_CHECK_STRICT, { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL" " extended info for lease 2001::1 failed checks" " (in link [relay#0] a problem was found:" " link is not an IPv6 address)" }); } // Valid link entry is right for all sanity levels. TEST_F(ExtendedInfoChecksTest, validLink) { string description = "valid link, strict"; check6(description, "{ \"ISC\": { \"relay-info\": [ { \"link\": \"2001::2\" } ] } }", "{ \"ISC\": { \"relay-info\": [ { \"link\": \"2001::2\" } ] } }", CfgConsistency::EXTENDED_INFO_CHECK_STRICT); } // remote-id entry with a bad type is right up to the fix sanity level. TEST_F(ExtendedInfoChecksTest, badTypeRemoteId6fix) { string description = "remote-id not a string, fix"; check6(description, "{ \"ISC\": { \"relay-info\": [ { \"remote-id\": 1 } ] } }", "{ \"ISC\": { \"relay-info\": [ { \"remote-id\": 1 } ] } }", CfgConsistency::EXTENDED_INFO_CHECK_FIX); } // remote-id entry with a bad type is dropped at strict or higher // sanity levels. TEST_F(ExtendedInfoChecksTest, badTypeRemoteId6strict) { string description = "remote-id not a string, strict"; check6(description, "{ \"ISC\": { \"relay-info\": [ { \"remote-id\": 1," " \"link\": \"2001::2\" } ] } }", "", CfgConsistency::EXTENDED_INFO_CHECK_STRICT, { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL" " extended info for lease 2001::1 failed checks" " (in remote-id [relay#0] a problem was found:" " remote-id is not a string)" }); } // remote-id entry which can't be decoded is dropped at strict or higher // sanity levels. TEST_F(ExtendedInfoChecksTest, badEncodingRemoteId6strict) { string description = "remote-id with a junk value, strict"; check6(description, "{ \"ISC\": { \"relay-info\": [ { \"remote-id\": \"foo\"," " \"link\": \"2001::2\" } ] } }", "", CfgConsistency::EXTENDED_INFO_CHECK_STRICT, { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL" " extended info for lease 2001::1 failed checks" " (in remote-id [relay#0] a problem was found:" " attempt to decode a value not in base16 char set)" }); } // Empty remote-id entry is dropped at strict or higher sanity levels. TEST_F(ExtendedInfoChecksTest, emptyRemoteId6strict) { string description = "empty remote-id, strict"; check6(description, "{ \"ISC\": { \"relay-info\": [ { \"remote-id\": \"\"," " \"link\": \"2001::2\" } ] } }", "", CfgConsistency::EXTENDED_INFO_CHECK_STRICT, { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL" " extended info for lease 2001::1 failed checks" " (in remote-id [relay#0] a problem was found:" " remote-id is empty)" }); } // Valid remote-id entry is right at all sanity levels. TEST_F(ExtendedInfoChecksTest, validRemoteId6strict) { string description = "valid remote-id, strict"; check6(description, "{ \"ISC\": { \"relay-info\": [ { \"remote-id\": \"AABB\"," " \"link\": \"2001::2\" } ] } }", "{ \"ISC\": { \"relay-info\": [ { \"remote-id\": \"AABB\"," " \"link\": \"2001::2\" } ] } }", CfgConsistency::EXTENDED_INFO_CHECK_STRICT); } // relay-id entry with a bad type is right up to the fix sanity level. TEST_F(ExtendedInfoChecksTest, badTypeRelayId6fix) { string description = "relay-id not a string, fix"; check6(description, "{ \"ISC\": { \"relay-info\": [ { \"relay-id\": 1 } ] } }", "{ \"ISC\": { \"relay-info\": [ { \"relay-id\": 1 } ] } }", CfgConsistency::EXTENDED_INFO_CHECK_FIX); } // relay-id entry with a bad type is dropped at strict or higher // sanity levels. TEST_F(ExtendedInfoChecksTest, badTypeRelayId6strict) { string description = "relay-id not a string, strict"; check6(description, "{ \"ISC\": { \"relay-info\": [ { \"relay-id\": 1," " \"link\": \"2001::2\" } ] } }", "", CfgConsistency::EXTENDED_INFO_CHECK_STRICT, { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL" " extended info for lease 2001::1 failed checks" " (in relay-id [relay#0] a problem was found:" " relay-id is not a string)" }); } // relay-id entry which can't be decoded is dropped at strict or higher // sanity levels. TEST_F(ExtendedInfoChecksTest, badEncodingRelayId6strict) { string description = "relay-id with a junk value, strict"; check6(description, "{ \"ISC\": { \"relay-info\": [ { \"relay-id\": \"foo\"," " \"link\": \"2001::2\" } ] } }", "", CfgConsistency::EXTENDED_INFO_CHECK_STRICT, { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL" " extended info for lease 2001::1 failed checks" " (in relay-id [relay#0] a problem was found:" " attempt to decode a value not in base16 char set)" }); } // Empty relay-id entry is dropped at strict or higher sanity levels. TEST_F(ExtendedInfoChecksTest, emptyRelayId6strict) { string description = "empty relay-id, strict"; check6(description, "{ \"ISC\": { \"relay-info\": [ { \"relay-id\": \"\"," " \"link\": \"2001::2\" } ] } }", "", CfgConsistency::EXTENDED_INFO_CHECK_STRICT, { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL" " extended info for lease 2001::1 failed checks" " (in relay-id [relay#0] a problem was found:" " relay-id is empty)" }); } // Valid relay-id entry is right at all sanity levels. TEST_F(ExtendedInfoChecksTest, validRelayId6strict) { string description = "valid relay-id, strict"; check6(description, "{ \"ISC\": { \"relay-info\": [ { \"relay-id\": \"AABB\"," " \"link\": \"2001::2\" } ] } }", "{ \"ISC\": { \"relay-info\": [ { \"relay-id\": \"AABB\"," " \"link\": \"2001::2\" } ] } }", CfgConsistency::EXTENDED_INFO_CHECK_STRICT); } // Pedantic requires a peer entry. TEST_F(ExtendedInfoChecksTest, noPeerpedantic) { string description = "no peer, pedantic"; check6(description, "{ \"ISC\": { \"relay-info\": [ { \"link\": \"2001::2\" } ] } }", "", CfgConsistency::EXTENDED_INFO_CHECK_PEDANTIC, { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL" " extended info for lease 2001::1 failed checks" " (in peer [relay#0] a problem was found:" " no peer)" }); } // peer entry with bad type is dropped by pedantic sanity check level. TEST_F(ExtendedInfoChecksTest, badTypePeer) { string description = "peer is not a string, pedantic"; check6(description, "{ \"ISC\": { \"relay-info\": [ { \"link\": \"2001::2\"," " \"peer\": 1 } ] } }", "", CfgConsistency::EXTENDED_INFO_CHECK_PEDANTIC, { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL" " extended info for lease 2001::1 failed checks" " (in peer [relay#0] a problem was found:" " peer is not a string)" }); } // peer entry which is not an address is dropped by pedantic sanity check level. TEST_F(ExtendedInfoChecksTest, notAddressPeer) { string description = "peer is not an address, pedantic"; check6(description, "{ \"ISC\": { \"relay-info\": [ { \"link\": \"2001::2\"," " \"peer\": \"foo\" } ] } }", "", CfgConsistency::EXTENDED_INFO_CHECK_PEDANTIC, { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL" " extended info for lease 2001::1 failed checks" " (in peer [relay#0] a problem was found:" " Failed to convert string to address 'foo':" " Invalid argument)" }); } // peer entry which is an IPv4 (vs IPv6) address is dropped by pedantic sanity // check level. TEST_F(ExtendedInfoChecksTest, notV6Peer) { string description = "peer is v4, pedantic"; check6(description, "{ \"ISC\": { \"relay-info\": [ { \"link\": \"2001::2\"," " \"peer\": \"192.128.1.1\" } ] } }", "", CfgConsistency::EXTENDED_INFO_CHECK_PEDANTIC, { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL" " extended info for lease 2001::1 failed checks" " (in peer [relay#0] a problem was found:" " peer is not an IPv6 address)" }); } // Pedantic requires a hop entry. TEST_F(ExtendedInfoChecksTest, noHop) { string description = "no hop, pedantic"; check6(description, "{ \"ISC\": { \"relay-info\": [ { \"link\": \"2001::2\"," " \"peer\": \"2001::3\" } ] } }", "", CfgConsistency::EXTENDED_INFO_CHECK_PEDANTIC, { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL" " extended info for lease 2001::1 failed checks" " (in hop [relay#0] a problem was found:" " no hop)" }); } // hop entry with bad type is dropped by pedantic sanity check level. TEST_F(ExtendedInfoChecksTest, badTypeHop) { string description = "hop is not an integer pedantic"; check6(description, "{ \"ISC\": { \"relay-info\": [ { \"link\": \"2001::2\"," " \"peer\": \"2001::3\", \"hop\": false } ] } }", "", CfgConsistency::EXTENDED_INFO_CHECK_PEDANTIC, { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL" " extended info for lease 2001::1 failed checks" " (in hop [relay#0] a problem was found:" " hop is not an integer)" }); } // Valid relay. TEST_F(ExtendedInfoChecksTest, valid6Pedantic) { string description = "valid, pedantic"; check6(description, "{ \"ISC\": { \"relay-info\": [ { \"link\": \"2001::2\"," " \"peer\": \"2001::3\", \"hop\": 10 } ] } }", "{ \"ISC\": { \"relay-info\": [ { \"link\": \"2001::2\"," " \"peer\": \"2001::3\", \"hop\": 10 } ] } }", CfgConsistency::EXTENDED_INFO_CHECK_PEDANTIC); } // Junk entries are dropped at the pedantic level. TEST_F(ExtendedInfoChecksTest, junk6pedantic) { string description = "junk entry, pedantic"; check6(description, "{ \"ISC\": { \"relay-info\": [ { \"link\": \"2001::2\"," " \"peer\": \"2001::3\", \"hop\": 10, \"foo\": 1 } ] } }", "", CfgConsistency::EXTENDED_INFO_CHECK_PEDANTIC, { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL" " extended info for lease 2001::1 failed checks" " (in relay-info [relay#0] a problem was found:" " spurious 'foo' entry)" }); } // Same with relays post upgrade checks. TEST_F(ExtendedInfoChecksTest, junkRelayspedantic) { string description = "junk entry, pedantic"; check6(description, "{ \"ISC\": { \"relays\": [ { \"link\": \"2001::2\"," " \"peer\": \"2001::3\", \"hop\": 10, \"foo\": 1 } ] } }", "", CfgConsistency::EXTENDED_INFO_CHECK_PEDANTIC, { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL" " extended info for lease 2001::1 failed checks" " (in relays [relay#0] a problem was found:" " spurious 'foo' entry)" }); }