|
@@ -79,11 +79,14 @@ public:
|
|
|
using Dhcpv6Srv::processRenew;
|
|
|
using Dhcpv6Srv::processRelease;
|
|
|
using Dhcpv6Srv::processClientFqdn;
|
|
|
+ using Dhcpv6Srv::createNameChangeRequests;
|
|
|
+ using Dhcpv6Srv::createRemovalNameChangeRequest;
|
|
|
using Dhcpv6Srv::createStatusCode;
|
|
|
using Dhcpv6Srv::selectSubnet;
|
|
|
using Dhcpv6Srv::sanityCheck;
|
|
|
using Dhcpv6Srv::loadServerID;
|
|
|
using Dhcpv6Srv::writeServerID;
|
|
|
+ using Dhcpv6Srv::name_change_reqs_;
|
|
|
};
|
|
|
|
|
|
static const char* DUID_FILE = "server-id-test.txt";
|
|
@@ -246,9 +249,6 @@ public:
|
|
|
|
|
|
int rcode_;
|
|
|
ConstElementPtr comment_;
|
|
|
-
|
|
|
- // A NameChangeRequest used in many tests.
|
|
|
- NameChangeRequestPtr ncr_;
|
|
|
};
|
|
|
|
|
|
// Provides suport for tests against a preconfigured subnet6
|
|
@@ -344,14 +344,31 @@ public:
|
|
|
|
|
|
};
|
|
|
|
|
|
-class FqdnDhcpv6SrvTest : public NakedDhcpv6SrvTest {
|
|
|
+class FqdnDhcpv6SrvTest : public Dhcpv6SrvTest {
|
|
|
public:
|
|
|
- FqdnDhcpv6SrvTest() {
|
|
|
+ FqdnDhcpv6SrvTest()
|
|
|
+ : Dhcpv6SrvTest() {
|
|
|
+ // generateClientId assigns DUID to duid_.
|
|
|
+ generateClientId();
|
|
|
+ lease_.reset(new Lease6(Lease6::LEASE_IA_NA, IOAddress("2001:db8:1::1"),
|
|
|
+ duid_, 1234, 501, 502, 503,
|
|
|
+ 504, 1, 0));
|
|
|
+
|
|
|
}
|
|
|
|
|
|
virtual ~FqdnDhcpv6SrvTest() {
|
|
|
}
|
|
|
|
|
|
+ Option6ClientFqdnPtr
|
|
|
+ createClientFqdn(const uint8_t flags,
|
|
|
+ const std::string& fqdn_name,
|
|
|
+ const Option6ClientFqdn::DomainNameType fqdn_type) {
|
|
|
+ return (Option6ClientFqdnPtr(new Option6ClientFqdn(flags,
|
|
|
+ fqdn_name,
|
|
|
+ fqdn_type)));
|
|
|
+ }
|
|
|
+
|
|
|
+ // Create a message holding DHCPv6 Client FQDN Option.
|
|
|
Pkt6Ptr generatePktWithFqdn(uint8_t msg_type,
|
|
|
const uint8_t fqdn_flags,
|
|
|
const std::string& fqdn_domain_name,
|
|
@@ -361,16 +378,23 @@ public:
|
|
|
OptionPtr srvid = OptionPtr()) {
|
|
|
Pkt6Ptr pkt = Pkt6Ptr(new Pkt6(msg_type, 1234));
|
|
|
pkt->setRemoteAddr(IOAddress("fe80::abcd"));
|
|
|
- pkt->addOption(generateIA(234, 1500, 3000));
|
|
|
+ Option6IAPtr ia = generateIA(234, 1500, 3000);
|
|
|
+
|
|
|
+ if (msg_type != DHCPV6_REPLY) {
|
|
|
+ IOAddress hint("2001:db8:1:1::dead:beef");
|
|
|
+ OptionPtr hint_opt(new Option6IAAddr(D6O_IAADDR, hint, 300, 500));
|
|
|
+ ia->addOption(hint_opt);
|
|
|
+ pkt->addOption(ia);
|
|
|
+ }
|
|
|
+
|
|
|
OptionPtr clientid = generateClientId();
|
|
|
pkt->addOption(clientid);
|
|
|
if (srvid && (msg_type != DHCPV6_SOLICIT)) {
|
|
|
pkt->addOption(srvid);
|
|
|
}
|
|
|
|
|
|
- pkt->addOption(OptionPtr(new Option6ClientFqdn(fqdn_flags,
|
|
|
- fqdn_domain_name,
|
|
|
- fqdn_type)));
|
|
|
+ pkt->addOption(createClientFqdn(fqdn_flags, fqdn_domain_name,
|
|
|
+ fqdn_type));
|
|
|
|
|
|
if (include_oro) {
|
|
|
OptionUint16ArrayPtr oro(new OptionUint16Array(Option::V6,
|
|
@@ -382,12 +406,65 @@ public:
|
|
|
return (pkt);
|
|
|
}
|
|
|
|
|
|
+ // Creates instance of the DHCPv6 message with client id and server id.
|
|
|
+ Pkt6Ptr generateMessageWithIds(const uint8_t msg_type,
|
|
|
+ NakedDhcpv6Srv& srv) {
|
|
|
+ Pkt6Ptr pkt = Pkt6Ptr(new Pkt6(msg_type, 1234));
|
|
|
+ // Generate client-id.
|
|
|
+ OptionPtr opt_clientid = generateClientId();
|
|
|
+ pkt->addOption(opt_clientid);
|
|
|
+
|
|
|
+ if (msg_type != DHCPV6_SOLICIT) {
|
|
|
+ // Generate server-id.
|
|
|
+ pkt->addOption(srv.getServerID());
|
|
|
+ }
|
|
|
+
|
|
|
+ return (pkt);
|
|
|
+ }
|
|
|
+
|
|
|
// Returns an instance of the option carrying FQDN.
|
|
|
Option6ClientFqdnPtr getClientFqdnOption(const Pkt6Ptr& pkt) {
|
|
|
return (boost::dynamic_pointer_cast<Option6ClientFqdn>
|
|
|
(pkt->getOption(D6O_CLIENT_FQDN)));
|
|
|
}
|
|
|
|
|
|
+ // Adds IA option to the message. Option holds an address.
|
|
|
+ void addIA(const uint32_t iaid, const IOAddress& addr, Pkt6Ptr& pkt) {
|
|
|
+ Option6IAPtr opt_ia = generateIA(iaid, 1500, 3000);
|
|
|
+ Option6IAAddrPtr opt_iaaddr(new Option6IAAddr(D6O_IAADDR, addr,
|
|
|
+ 300, 500));
|
|
|
+ opt_ia->addOption(opt_iaaddr);
|
|
|
+ pkt->addOption(opt_ia);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Adds IA option to the message. Option holds status code.
|
|
|
+ void addIA(const uint32_t iaid, const uint16_t status_code, Pkt6Ptr& pkt) {
|
|
|
+ Option6IAPtr opt_ia = generateIA(iaid, 1500, 3000);
|
|
|
+ addStatusCode(status_code, "", opt_ia);
|
|
|
+ pkt->addOption(opt_ia);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Creates status code with the specified code and message.
|
|
|
+ OptionCustomPtr createStatusCode(const uint16_t code,
|
|
|
+ const std::string& msg) {
|
|
|
+ OptionDefinition def("status-code", D6O_STATUS_CODE, "record");
|
|
|
+ def.addRecordField("uint16");
|
|
|
+ def.addRecordField("string");
|
|
|
+ OptionCustomPtr opt_status(new OptionCustom(def, Option::V6));
|
|
|
+ opt_status->writeInteger(code);
|
|
|
+ if (!msg.empty()) {
|
|
|
+ opt_status->writeString(msg, 1);
|
|
|
+ }
|
|
|
+ return (opt_status);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Adds Status Code option to the IA.
|
|
|
+ void addStatusCode(const uint16_t code, const std::string& msg,
|
|
|
+ Option6IAPtr& opt_ia) {
|
|
|
+ opt_ia->addOption(createStatusCode(code, msg));
|
|
|
+ }
|
|
|
+
|
|
|
+ // Test processing of the DHCPv6 Client FQDN Option.
|
|
|
void testFqdn(const uint16_t msg_type,
|
|
|
const bool use_oro,
|
|
|
const uint8_t in_flags,
|
|
@@ -403,18 +480,8 @@ public:
|
|
|
use_oro);
|
|
|
ASSERT_TRUE(getClientFqdnOption(question));
|
|
|
|
|
|
- Pkt6Ptr answer;
|
|
|
- if (msg_type == DHCPV6_SOLICIT) {
|
|
|
- answer.reset(new Pkt6(DHCPV6_ADVERTISE, 1234));
|
|
|
-
|
|
|
- } else {
|
|
|
- answer.reset(new Pkt6(DHCPV6_REPLY, 1234));
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- ASSERT_NO_THROW(srv.processClientFqdn(question, answer, ncr_));
|
|
|
-
|
|
|
- Option6ClientFqdnPtr answ_fqdn = getClientFqdnOption(answer);
|
|
|
+ Option6ClientFqdnPtr answ_fqdn;
|
|
|
+ ASSERT_NO_THROW(answ_fqdn = srv.processClientFqdn(question));
|
|
|
ASSERT_TRUE(answ_fqdn);
|
|
|
|
|
|
const bool flag_n = (exp_flags & Option6ClientFqdn::FLAG_N) != 0 ?
|
|
@@ -431,6 +498,89 @@ public:
|
|
|
EXPECT_EQ(exp_domain_name, answ_fqdn->getDomainName());
|
|
|
EXPECT_EQ(Option6ClientFqdn::FULL, answ_fqdn->getDomainNameType());
|
|
|
}
|
|
|
+
|
|
|
+ // Tests that the client message holding an FQDN is processed and the
|
|
|
+ // lease is acquired.
|
|
|
+ void testProcessMessage(const uint8_t msg_type,
|
|
|
+ const std::string& hostname,
|
|
|
+ NakedDhcpv6Srv& srv) {
|
|
|
+ // Create a message of a specified type, add server id and
|
|
|
+ // FQDN option.
|
|
|
+ OptionPtr srvid = srv.getServerID();
|
|
|
+ Pkt6Ptr req = generatePktWithFqdn(msg_type, FQDN_FLAG_S,
|
|
|
+ hostname,
|
|
|
+ Option6ClientFqdn::FULL,
|
|
|
+ true, srvid);
|
|
|
+
|
|
|
+ // For different client's message types we have to invoke different
|
|
|
+ // functions to generate response.
|
|
|
+ Pkt6Ptr reply;
|
|
|
+ if (msg_type == DHCPV6_SOLICIT) {
|
|
|
+ ASSERT_NO_THROW(reply = srv.processSolicit(req));
|
|
|
+
|
|
|
+ } else if (msg_type == DHCPV6_REQUEST) {
|
|
|
+ ASSERT_NO_THROW(reply = srv.processRequest(req));
|
|
|
+
|
|
|
+ } else if (msg_type == DHCPV6_RENEW) {
|
|
|
+ ASSERT_NO_THROW(reply = srv.processRequest(req));
|
|
|
+
|
|
|
+ } else if (msg_type == DHCPV6_RELEASE) {
|
|
|
+ // For Release no lease will be acquired so we have to leave
|
|
|
+ // function here.
|
|
|
+ ASSERT_NO_THROW(reply = srv.processRelease(req));
|
|
|
+ return;
|
|
|
+ } else {
|
|
|
+ // We are not interested in testing other message types.
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // For Solicit, we will get different message type obviously.
|
|
|
+ if (msg_type == DHCPV6_SOLICIT) {
|
|
|
+ checkResponse(reply, DHCPV6_ADVERTISE, 1234);
|
|
|
+
|
|
|
+ } else {
|
|
|
+ checkResponse(reply, DHCPV6_REPLY, 1234);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Check verify that IA_NA is correct.
|
|
|
+ Option6IAAddrPtr addr =
|
|
|
+ checkIA_NA(reply, 234, subnet_->getT1(), subnet_->getT2());
|
|
|
+ ASSERT_TRUE(addr);
|
|
|
+
|
|
|
+ // Check that we have got the address we requested.
|
|
|
+ checkIAAddr(addr, IOAddress("2001:db8:1:1::dead:beef"),
|
|
|
+ subnet_->getPreferred(),
|
|
|
+ subnet_->getValid());
|
|
|
+
|
|
|
+ if (msg_type != DHCPV6_SOLICIT) {
|
|
|
+ // Check that the lease exists.
|
|
|
+ Lease6Ptr lease =
|
|
|
+ checkLease(duid_, reply->getOption(D6O_IA_NA), addr);
|
|
|
+ ASSERT_TRUE(lease);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Verify that NameChangeRequest holds valid values.
|
|
|
+ void verifyNameChangeRequest(NakedDhcpv6Srv& srv,
|
|
|
+ const isc::d2::NameChangeType type,
|
|
|
+ const bool reverse, const bool forward,
|
|
|
+ const std::string& addr,
|
|
|
+ const std::string& dhcid,
|
|
|
+ const uint16_t expires,
|
|
|
+ const uint16_t len) {
|
|
|
+ NameChangeRequest ncr = srv.name_change_reqs_.front();
|
|
|
+ EXPECT_EQ(type, ncr.getChangeType());
|
|
|
+ EXPECT_EQ(forward, ncr.isForwardChange());
|
|
|
+ EXPECT_EQ(reverse, ncr.isReverseChange());
|
|
|
+ EXPECT_EQ(addr, ncr.getIpAddress());
|
|
|
+ EXPECT_EQ(dhcid, ncr.getDhcid().toStr());
|
|
|
+ EXPECT_EQ(expires, ncr.getLeaseExpiresOn());
|
|
|
+ EXPECT_EQ(len, ncr.getLeaseLength());
|
|
|
+ EXPECT_EQ(isc::d2::ST_NEW, ncr.getStatus());
|
|
|
+ srv.name_change_reqs_.pop();
|
|
|
+ }
|
|
|
+
|
|
|
+ Lease6Ptr lease_;
|
|
|
};
|
|
|
|
|
|
// This test verifies that incoming SOLICIT can be handled properly when
|
|
@@ -481,7 +631,7 @@ TEST_F(NakedDhcpv6SrvTest, RequestNoSubnet) {
|
|
|
req->addOption(srv.getServerID());
|
|
|
|
|
|
// Pass it to the server and hope for a REPLY
|
|
|
- Pkt6Ptr reply = srv.processRequest(req, ncr_);
|
|
|
+ Pkt6Ptr reply = srv.processRequest(req);
|
|
|
|
|
|
// check that we get the right NAK
|
|
|
checkNakResponse (reply, DHCPV6_REPLY, 1234, STATUS_NoAddrsAvail);
|
|
@@ -516,7 +666,7 @@ TEST_F(NakedDhcpv6SrvTest, RenewNoSubnet) {
|
|
|
req->addOption(srv.getServerID());
|
|
|
|
|
|
// Pass it to the server and hope for a REPLY
|
|
|
- Pkt6Ptr reply = srv.processRenew(req, ncr_);
|
|
|
+ Pkt6Ptr reply = srv.processRenew(req);
|
|
|
|
|
|
// check that we get the right NAK
|
|
|
checkNakResponse (reply, DHCPV6_REPLY, 1234, STATUS_NoBinding);
|
|
@@ -551,7 +701,7 @@ TEST_F(NakedDhcpv6SrvTest, ReleaseNoSubnet) {
|
|
|
req->addOption(srv.getServerID());
|
|
|
|
|
|
// Pass it to the server and hope for a REPLY
|
|
|
- Pkt6Ptr reply = srv.processRelease(req, ncr_);
|
|
|
+ Pkt6Ptr reply = srv.processRelease(req);
|
|
|
|
|
|
// check that we get the right NAK
|
|
|
checkNakResponse (reply, DHCPV6_REPLY, 1234, STATUS_NoBinding);
|
|
@@ -1019,7 +1169,7 @@ TEST_F(Dhcpv6SrvTest, RequestBasic) {
|
|
|
req->addOption(srv.getServerID());
|
|
|
|
|
|
// Pass it to the server and hope for a REPLY
|
|
|
- Pkt6Ptr reply = srv.processRequest(req, ncr_);
|
|
|
+ Pkt6Ptr reply = srv.processRequest(req);
|
|
|
|
|
|
// check if we get response at all
|
|
|
checkResponse(reply, DHCPV6_REPLY, 1234);
|
|
@@ -1084,9 +1234,9 @@ TEST_F(Dhcpv6SrvTest, ManyRequests) {
|
|
|
req3->addOption(srv.getServerID());
|
|
|
|
|
|
// Pass it to the server and get an advertise
|
|
|
- Pkt6Ptr reply1 = srv.processRequest(req1, ncr_);
|
|
|
- Pkt6Ptr reply2 = srv.processRequest(req2, ncr_);
|
|
|
- Pkt6Ptr reply3 = srv.processRequest(req3, ncr_);
|
|
|
+ Pkt6Ptr reply1 = srv.processRequest(req1);
|
|
|
+ Pkt6Ptr reply2 = srv.processRequest(req2);
|
|
|
+ Pkt6Ptr reply3 = srv.processRequest(req3);
|
|
|
|
|
|
// check if we get response at all
|
|
|
checkResponse(reply1, DHCPV6_REPLY, 1234);
|
|
@@ -1181,7 +1331,7 @@ TEST_F(Dhcpv6SrvTest, RenewBasic) {
|
|
|
req->addOption(srv.getServerID());
|
|
|
|
|
|
// Pass it to the server and hope for a REPLY
|
|
|
- Pkt6Ptr reply = srv.processRenew(req, ncr_);
|
|
|
+ Pkt6Ptr reply = srv.processRenew(req);
|
|
|
|
|
|
// Check if we get response at all
|
|
|
checkResponse(reply, DHCPV6_REPLY, 1234);
|
|
@@ -1267,7 +1417,7 @@ TEST_F(Dhcpv6SrvTest, RenewReject) {
|
|
|
// Case 1: No lease known to server
|
|
|
|
|
|
// Pass it to the server and hope for a REPLY
|
|
|
- Pkt6Ptr reply = srv.processRenew(req, ncr_);
|
|
|
+ Pkt6Ptr reply = srv.processRenew(req);
|
|
|
|
|
|
// Check if we get response at all
|
|
|
checkResponse(reply, DHCPV6_REPLY, transid);
|
|
@@ -1293,7 +1443,7 @@ TEST_F(Dhcpv6SrvTest, RenewReject) {
|
|
|
ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
|
|
|
|
|
|
// Pass it to the server and hope for a REPLY
|
|
|
- reply = srv.processRenew(req, ncr_);
|
|
|
+ reply = srv.processRenew(req);
|
|
|
checkResponse(reply, DHCPV6_REPLY, transid);
|
|
|
tmp = reply->getOption(D6O_IA_NA);
|
|
|
ASSERT_TRUE(tmp);
|
|
@@ -1312,7 +1462,7 @@ TEST_F(Dhcpv6SrvTest, RenewReject) {
|
|
|
req->addOption(generateClientId(13)); // generate different DUID
|
|
|
// (with length 13)
|
|
|
|
|
|
- reply = srv.processRenew(req, ncr_);
|
|
|
+ reply = srv.processRenew(req);
|
|
|
checkResponse(reply, DHCPV6_REPLY, transid);
|
|
|
tmp = reply->getOption(D6O_IA_NA);
|
|
|
ASSERT_TRUE(tmp);
|
|
@@ -1375,7 +1525,7 @@ TEST_F(Dhcpv6SrvTest, ReleaseBasic) {
|
|
|
req->addOption(srv.getServerID());
|
|
|
|
|
|
// Pass it to the server and hope for a REPLY
|
|
|
- Pkt6Ptr reply = srv.processRelease(req, ncr_);
|
|
|
+ Pkt6Ptr reply = srv.processRelease(req);
|
|
|
|
|
|
// Check if we get response at all
|
|
|
checkResponse(reply, DHCPV6_REPLY, 1234);
|
|
@@ -1453,7 +1603,7 @@ TEST_F(Dhcpv6SrvTest, ReleaseReject) {
|
|
|
SCOPED_TRACE("CASE 1: No lease known to server");
|
|
|
|
|
|
// Pass it to the server and hope for a REPLY
|
|
|
- Pkt6Ptr reply = srv.processRelease(req, ncr_);
|
|
|
+ Pkt6Ptr reply = srv.processRelease(req);
|
|
|
|
|
|
// Check if we get response at all
|
|
|
checkResponse(reply, DHCPV6_REPLY, transid);
|
|
@@ -1477,7 +1627,7 @@ TEST_F(Dhcpv6SrvTest, ReleaseReject) {
|
|
|
ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
|
|
|
|
|
|
// Pass it to the server and hope for a REPLY
|
|
|
- reply = srv.processRelease(req, ncr_);
|
|
|
+ reply = srv.processRelease(req);
|
|
|
checkResponse(reply, DHCPV6_REPLY, transid);
|
|
|
tmp = reply->getOption(D6O_IA_NA);
|
|
|
ASSERT_TRUE(tmp);
|
|
@@ -1500,7 +1650,7 @@ TEST_F(Dhcpv6SrvTest, ReleaseReject) {
|
|
|
req->addOption(generateClientId(13)); // generate different DUID
|
|
|
// (with length 13)
|
|
|
|
|
|
- reply = srv.processRelease(req, ncr_);
|
|
|
+ reply = srv.processRelease(req);
|
|
|
checkResponse(reply, DHCPV6_REPLY, transid);
|
|
|
tmp = reply->getOption(D6O_IA_NA);
|
|
|
ASSERT_TRUE(tmp);
|
|
@@ -1903,6 +2053,325 @@ TEST_F(FqdnDhcpv6SrvTest, clientAAAAUpdateNotAllowed) {
|
|
|
"myhost.example.com.");
|
|
|
}
|
|
|
|
|
|
+// Test that exception is thrown if supplied NULL answer packet when
|
|
|
+// creating NameChangeRequests.
|
|
|
+TEST_F(FqdnDhcpv6SrvTest, createNameChangeRequestsNoAnswer) {
|
|
|
+ NakedDhcpv6Srv srv(0);
|
|
|
+
|
|
|
+ Pkt6Ptr answer;
|
|
|
+ Option6ClientFqdnPtr fqdn = createClientFqdn(Option6ClientFqdn::FLAG_S,
|
|
|
+ "myhost.example.com",
|
|
|
+ Option6ClientFqdn::FULL);
|
|
|
+ EXPECT_THROW(srv.createNameChangeRequests(answer, fqdn),
|
|
|
+ isc::Unexpected);
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+// Test that exception is thrown if supplied answer from the server
|
|
|
+// contains no DUID when creating NameChangeRequests.
|
|
|
+TEST_F(FqdnDhcpv6SrvTest, createNameChangeRequestsNoDUID) {
|
|
|
+ NakedDhcpv6Srv srv(0);
|
|
|
+
|
|
|
+ Pkt6Ptr answer = Pkt6Ptr(new Pkt6(DHCPV6_REPLY, 1234));
|
|
|
+ Option6ClientFqdnPtr fqdn = createClientFqdn(Option6ClientFqdn::FLAG_S,
|
|
|
+ "myhost.example.com",
|
|
|
+ Option6ClientFqdn::FULL);
|
|
|
+
|
|
|
+ EXPECT_THROW(srv.createNameChangeRequests(answer, fqdn),
|
|
|
+ isc::Unexpected);
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+// Test no NameChangeRequests are added if FQDN option is NULL.
|
|
|
+TEST_F(FqdnDhcpv6SrvTest, createNameChangeRequestsNoFQDN) {
|
|
|
+ NakedDhcpv6Srv srv(0);
|
|
|
+
|
|
|
+ // Create Reply message with Client Id and Server id.
|
|
|
+ Pkt6Ptr answer = generateMessageWithIds(DHCPV6_REPLY, srv);
|
|
|
+
|
|
|
+ // Pass NULL FQDN option. No NameChangeRequests should be created.
|
|
|
+ Option6ClientFqdnPtr fqdn;
|
|
|
+ ASSERT_NO_THROW(srv.createNameChangeRequests(answer, fqdn));
|
|
|
+
|
|
|
+ // There should be no new NameChangeRequests.
|
|
|
+ EXPECT_TRUE(srv.name_change_reqs_.empty());
|
|
|
+}
|
|
|
+
|
|
|
+// Test that NameChangeRequests are not generated if an answer message
|
|
|
+// contains no addresses.
|
|
|
+TEST_F(FqdnDhcpv6SrvTest, createNameChangeRequestsNoAddr) {
|
|
|
+ NakedDhcpv6Srv srv(0);
|
|
|
+
|
|
|
+ // Create Reply message with Client Id and Server id.
|
|
|
+ Pkt6Ptr answer = generateMessageWithIds(DHCPV6_REPLY, srv);
|
|
|
+
|
|
|
+ Option6ClientFqdnPtr fqdn = createClientFqdn(Option6ClientFqdn::FLAG_S,
|
|
|
+ "myhost.example.com",
|
|
|
+ Option6ClientFqdn::FULL);
|
|
|
+
|
|
|
+ ASSERT_NO_THROW(srv.createNameChangeRequests(answer, fqdn));
|
|
|
+
|
|
|
+ // We didn't add any IAs, so there should be no NameChangeRequests in th
|
|
|
+ // queue.
|
|
|
+ ASSERT_TRUE(srv.name_change_reqs_.empty());
|
|
|
+}
|
|
|
+
|
|
|
+// Test that a number of NameChangeRequests is created as a result of
|
|
|
+// processing the answer message which holds 3 IAs and when FQDN is
|
|
|
+// specified.
|
|
|
+TEST_F(FqdnDhcpv6SrvTest, createNameChangeRequests) {
|
|
|
+ NakedDhcpv6Srv srv(0);
|
|
|
+
|
|
|
+ // Create Reply message with Client Id and Server id.
|
|
|
+ Pkt6Ptr answer = generateMessageWithIds(DHCPV6_REPLY, srv);
|
|
|
+
|
|
|
+ // Create three IAs, each having different address.
|
|
|
+ addIA(1234, IOAddress("2001:db8:1::1"), answer);
|
|
|
+ addIA(2345, IOAddress("2001:db8:1::2"), answer);
|
|
|
+ addIA(3456, IOAddress("2001:db8:1::3"), answer);
|
|
|
+
|
|
|
+ Option6ClientFqdnPtr fqdn = createClientFqdn(Option6ClientFqdn::FLAG_S,
|
|
|
+ "myhost.example.com",
|
|
|
+ Option6ClientFqdn::FULL);
|
|
|
+
|
|
|
+ // Create NameChangeRequests. Since we have added 3 IAs, it should
|
|
|
+ // result in generation of 3 distinct NameChangeRequests.
|
|
|
+ ASSERT_NO_THROW(srv.createNameChangeRequests(answer, fqdn));
|
|
|
+ ASSERT_EQ(3, srv.name_change_reqs_.size());
|
|
|
+
|
|
|
+ // Verify that NameChangeRequests are correct. Each call to the
|
|
|
+ // verifyNameChangeRequest will pop verified request from the queue.
|
|
|
+
|
|
|
+ verifyNameChangeRequest(srv, isc::d2::CHG_ADD, true, true, "2001:db8:1::1",
|
|
|
+ "000201415AA33D1187D148275136FA30300478"
|
|
|
+ "FAAAA3EBD29826B5C907B2C9268A6F52",
|
|
|
+ 0, 500);
|
|
|
+
|
|
|
+ verifyNameChangeRequest(srv, isc::d2::CHG_ADD, true, true, "2001:db8:1::2",
|
|
|
+ "000201415AA33D1187D148275136FA30300478"
|
|
|
+ "FAAAA3EBD29826B5C907B2C9268A6F52",
|
|
|
+ 0, 500);
|
|
|
+
|
|
|
+ verifyNameChangeRequest(srv, isc::d2::CHG_ADD, true, true, "2001:db8:1::3",
|
|
|
+ "000201415AA33D1187D148275136FA30300478"
|
|
|
+ "FAAAA3EBD29826B5C907B2C9268A6F52",
|
|
|
+ 0, 500);
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+// Test creation of the NameChangeRequest to remove both forward and reverse
|
|
|
+// mapping for the given lease.
|
|
|
+TEST_F(FqdnDhcpv6SrvTest, createRemovalNameChangeRequestFwdRev) {
|
|
|
+ NakedDhcpv6Srv srv(0);
|
|
|
+
|
|
|
+ lease_->fqdn_fwd_ = true;
|
|
|
+ lease_->fqdn_rev_ = true;
|
|
|
+ lease_->hostname_ = "myhost.example.com.";
|
|
|
+
|
|
|
+ ASSERT_NO_THROW(srv.createRemovalNameChangeRequest(lease_));
|
|
|
+
|
|
|
+ ASSERT_EQ(1, srv.name_change_reqs_.size());
|
|
|
+
|
|
|
+ verifyNameChangeRequest(srv, isc::d2::CHG_REMOVE, true, true,
|
|
|
+ "2001:db8:1::1",
|
|
|
+ "000201415AA33D1187D148275136FA30300478"
|
|
|
+ "FAAAA3EBD29826B5C907B2C9268A6F52",
|
|
|
+ 0, 502);
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+// Test creation of the NameChangeRequest to remove reverse mapping for the
|
|
|
+// given lease.
|
|
|
+TEST_F(FqdnDhcpv6SrvTest, createRemovalNameChangeRequestRev) {
|
|
|
+ NakedDhcpv6Srv srv(0);
|
|
|
+
|
|
|
+ lease_->fqdn_fwd_ = false;
|
|
|
+ lease_->fqdn_rev_ = true;
|
|
|
+ lease_->hostname_ = "myhost.example.com.";
|
|
|
+
|
|
|
+ ASSERT_NO_THROW(srv.createRemovalNameChangeRequest(lease_));
|
|
|
+
|
|
|
+ ASSERT_EQ(1, srv.name_change_reqs_.size());
|
|
|
+
|
|
|
+ verifyNameChangeRequest(srv, isc::d2::CHG_REMOVE, true, false,
|
|
|
+ "2001:db8:1::1",
|
|
|
+ "000201415AA33D1187D148275136FA30300478"
|
|
|
+ "FAAAA3EBD29826B5C907B2C9268A6F52",
|
|
|
+ 0, 502);
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+// Test that NameChangeRequest to remove DNS records is not generated when
|
|
|
+// neither forward nor reverse DNS update has been performed for a lease.
|
|
|
+TEST_F(FqdnDhcpv6SrvTest, createRemovalNameChangeRequestNoUpdate) {
|
|
|
+ NakedDhcpv6Srv srv(0);
|
|
|
+
|
|
|
+ lease_->fqdn_fwd_ = false;
|
|
|
+ lease_->fqdn_rev_ = false;
|
|
|
+
|
|
|
+ ASSERT_NO_THROW(srv.createRemovalNameChangeRequest(lease_));
|
|
|
+
|
|
|
+ EXPECT_TRUE(srv.name_change_reqs_.empty());
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+// Test that NameChangeRequest is not generated if the hostname hasn't been
|
|
|
+// specified for a lease for which forward and reverse mapping has been set.
|
|
|
+TEST_F(FqdnDhcpv6SrvTest, createRemovalNameChangeRequestNoHostname) {
|
|
|
+ NakedDhcpv6Srv srv(0);
|
|
|
+
|
|
|
+ lease_->fqdn_fwd_ = true;
|
|
|
+ lease_->fqdn_rev_ = true;
|
|
|
+ lease_->hostname_ = "";
|
|
|
+
|
|
|
+ ASSERT_NO_THROW(srv.createRemovalNameChangeRequest(lease_));
|
|
|
+
|
|
|
+ EXPECT_TRUE(srv.name_change_reqs_.empty());
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+// Test that NameChangeRequest is not generated if the invalid hostname has
|
|
|
+// been specified for a lease for which forward and reverse mapping has been
|
|
|
+// set.
|
|
|
+TEST_F(FqdnDhcpv6SrvTest, createRemovalNameChangeRequestWrongHostname) {
|
|
|
+ NakedDhcpv6Srv srv(0);
|
|
|
+
|
|
|
+ lease_->fqdn_fwd_ = true;
|
|
|
+ lease_->fqdn_rev_ = true;
|
|
|
+ lease_->hostname_ = "myhost..example.com.";
|
|
|
+
|
|
|
+ ASSERT_NO_THROW(srv.createRemovalNameChangeRequest(lease_));
|
|
|
+
|
|
|
+ EXPECT_TRUE(srv.name_change_reqs_.empty());
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+// Test that Advertise message generated in a response to the Solicit will
|
|
|
+// not result in generation if the NameChangeRequests.
|
|
|
+TEST_F(FqdnDhcpv6SrvTest, processSolicit) {
|
|
|
+ NakedDhcpv6Srv srv(0);
|
|
|
+
|
|
|
+ // Create a Solicit message with FQDN option and generate server's
|
|
|
+ // response using processRequest function. This will result in the
|
|
|
+ // creation of a new lease and the appropriate NameChangeRequest
|
|
|
+ // to add both reverse and forward mapping to DNS.
|
|
|
+ testProcessMessage(DHCPV6_SOLICIT, "myhost.example.com", srv);
|
|
|
+ EXPECT_TRUE(srv.name_change_reqs_.empty());
|
|
|
+}
|
|
|
+
|
|
|
+// Test that client may send two requests, each carrying FQDN option with
|
|
|
+// a different domain-name. Server should use existing lease for the second
|
|
|
+// request but modify the DNS entries for the lease according to the contents
|
|
|
+// of the FQDN sent in the second request.
|
|
|
+TEST_F(FqdnDhcpv6SrvTest, processTwoRequests) {
|
|
|
+ NakedDhcpv6Srv srv(0);
|
|
|
+
|
|
|
+ // Create a Request message with FQDN option and generate server's
|
|
|
+ // response using processRequest function. This will result in the
|
|
|
+ // creation of a new lease and the appropriate NameChangeRequest
|
|
|
+ // to add both reverse and forward mapping to DNS.
|
|
|
+ testProcessMessage(DHCPV6_REQUEST, "myhost.example.com", srv);
|
|
|
+ ASSERT_EQ(1, srv.name_change_reqs_.size());
|
|
|
+ verifyNameChangeRequest(srv, isc::d2::CHG_ADD, true, true,
|
|
|
+ "2001:db8:1:1::dead:beef",
|
|
|
+ "000201415AA33D1187D148275136FA30300478"
|
|
|
+ "FAAAA3EBD29826B5C907B2C9268A6F52",
|
|
|
+ 0, 4000);
|
|
|
+
|
|
|
+ // Client may send another request message with a new domain-name. In this
|
|
|
+ // case the same lease will be returned. The existing DNS entry needs to
|
|
|
+ // be replaced with a new one. Server should determine that the different
|
|
|
+ // FQDN has been already added to the DNS. As a result, the old DNS
|
|
|
+ // entries should be removed and the entries for the new domain-name
|
|
|
+ // should be added. Therefore, we expect two NameChangeRequests. One to
|
|
|
+ // remove the existing entries, one to add new entries.
|
|
|
+ testProcessMessage(DHCPV6_REQUEST, "otherhost.example.com", srv);
|
|
|
+ ASSERT_EQ(2, srv.name_change_reqs_.size());
|
|
|
+ verifyNameChangeRequest(srv, isc::d2::CHG_REMOVE, true, true,
|
|
|
+ "2001:db8:1:1::dead:beef",
|
|
|
+ "000201415AA33D1187D148275136FA30300478"
|
|
|
+ "FAAAA3EBD29826B5C907B2C9268A6F52",
|
|
|
+ 0, 4000);
|
|
|
+ verifyNameChangeRequest(srv, isc::d2::CHG_ADD, true, true,
|
|
|
+ "2001:db8:1:1::dead:beef",
|
|
|
+ "000201D422AA463306223D269B6CB7AFE7AAD265FC"
|
|
|
+ "EA97F93623019B2E0D14E5323D5A",
|
|
|
+ 0, 4000);
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+// Test that client may send Request followed by the Renew, both holding
|
|
|
+// FQDN options, but each option holding different domain-name. The Renew
|
|
|
+// should result in generation of the two NameChangeRequests, one to remove
|
|
|
+// DNS entry added previously when Request was processed, another one to
|
|
|
+// add a new entry for the FQDN held in the Renew.
|
|
|
+TEST_F(FqdnDhcpv6SrvTest, processRequestRenew) {
|
|
|
+ NakedDhcpv6Srv srv(0);
|
|
|
+
|
|
|
+ // Create a Request message with FQDN option and generate server's
|
|
|
+ // response using processRequest function. This will result in the
|
|
|
+ // creation of a new lease and the appropriate NameChangeRequest
|
|
|
+ // to add both reverse and forward mapping to DNS.
|
|
|
+ testProcessMessage(DHCPV6_REQUEST, "myhost.example.com", srv);
|
|
|
+ ASSERT_EQ(1, srv.name_change_reqs_.size());
|
|
|
+ verifyNameChangeRequest(srv, isc::d2::CHG_ADD, true, true,
|
|
|
+ "2001:db8:1:1::dead:beef",
|
|
|
+ "000201415AA33D1187D148275136FA30300478"
|
|
|
+ "FAAAA3EBD29826B5C907B2C9268A6F52",
|
|
|
+ 0, 4000);
|
|
|
+
|
|
|
+ // Client may send Renew message with a new domain-name. In this
|
|
|
+ // case the same lease will be returned. The existing DNS entry needs to
|
|
|
+ // be replaced with a new one. Server should determine that the different
|
|
|
+ // FQDN has been already added to the DNS. As a result, the old DNS
|
|
|
+ // entries should be removed and the entries for the new domain-name
|
|
|
+ // should be added. Therefore, we expect two NameChangeRequests. One to
|
|
|
+ // remove the existing entries, one to add new entries.
|
|
|
+ testProcessMessage(DHCPV6_RENEW, "otherhost.example.com", srv);
|
|
|
+ ASSERT_EQ(2, srv.name_change_reqs_.size());
|
|
|
+ verifyNameChangeRequest(srv, isc::d2::CHG_REMOVE, true, true,
|
|
|
+ "2001:db8:1:1::dead:beef",
|
|
|
+ "000201415AA33D1187D148275136FA30300478"
|
|
|
+ "FAAAA3EBD29826B5C907B2C9268A6F52",
|
|
|
+ 0, 4000);
|
|
|
+ verifyNameChangeRequest(srv, isc::d2::CHG_ADD, true, true,
|
|
|
+ "2001:db8:1:1::dead:beef",
|
|
|
+ "000201D422AA463306223D269B6CB7AFE7AAD265FC"
|
|
|
+ "EA97F93623019B2E0D14E5323D5A",
|
|
|
+ 0, 4000);
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+TEST_F(FqdnDhcpv6SrvTest, processRequestRelease) {
|
|
|
+ NakedDhcpv6Srv srv(0);
|
|
|
+
|
|
|
+ // Create a Request message with FQDN option and generate server's
|
|
|
+ // response using processRequest function. This will result in the
|
|
|
+ // creation of a new lease and the appropriate NameChangeRequest
|
|
|
+ // to add both reverse and forward mapping to DNS.
|
|
|
+ testProcessMessage(DHCPV6_REQUEST, "myhost.example.com", srv);
|
|
|
+ ASSERT_EQ(1, srv.name_change_reqs_.size());
|
|
|
+ verifyNameChangeRequest(srv, isc::d2::CHG_ADD, true, true,
|
|
|
+ "2001:db8:1:1::dead:beef",
|
|
|
+ "000201415AA33D1187D148275136FA30300478"
|
|
|
+ "FAAAA3EBD29826B5C907B2C9268A6F52",
|
|
|
+ 0, 4000);
|
|
|
+
|
|
|
+ // Client may send Release message. In this case the lease should be
|
|
|
+ // removed and all existing DNS entries for this lease should be
|
|
|
+ // also removed. Therefore, we expect that single NameChangeRequest to
|
|
|
+ // remove DNS entries is generated.
|
|
|
+ testProcessMessage(DHCPV6_RELEASE, "otherhost.example.com", srv);
|
|
|
+ ASSERT_EQ(1, srv.name_change_reqs_.size());
|
|
|
+ verifyNameChangeRequest(srv, isc::d2::CHG_REMOVE, true, true,
|
|
|
+ "2001:db8:1:1::dead:beef",
|
|
|
+ "000201415AA33D1187D148275136FA30300478"
|
|
|
+ "FAAAA3EBD29826B5C907B2C9268A6F52",
|
|
|
+ 0, 4000);
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
/// @todo: Add more negative tests for processX(), e.g. extend sanityCheck() test
|
|
|
/// to call processX() methods.
|
|
|
|