mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-31 05:55:28 +00:00
[3220] Moved DHCPv6 Client FQDN specific tests to a separate file.
This commit is contained in:
@@ -69,6 +69,7 @@ libco2_la_LDFLAGS = -avoid-version -export-dynamic -module
|
||||
TESTS += dhcp6_unittests
|
||||
dhcp6_unittests_SOURCES = dhcp6_unittests.cc
|
||||
dhcp6_unittests_SOURCES += dhcp6_srv_unittest.cc
|
||||
dhcp6_unittests_SOURCES += fqdn_unittest.cc
|
||||
dhcp6_unittests_SOURCES += hooks_unittest.cc
|
||||
dhcp6_unittests_SOURCES += dhcp6_test_utils.cc dhcp6_test_utils.h
|
||||
dhcp6_unittests_SOURCES += ctrl_dhcp6_srv_unittest.cc
|
||||
|
@@ -15,19 +15,16 @@
|
||||
#include <config.h>
|
||||
|
||||
#include <asiolink/io_address.h>
|
||||
#include <dhcp_ddns/ncr_msg.h>
|
||||
#include <dhcp/dhcp6.h>
|
||||
#include <dhcp/duid.h>
|
||||
#include <dhcp/option.h>
|
||||
#include <dhcp/option_custom.h>
|
||||
#include <dhcp/option6_addrlst.h>
|
||||
#include <dhcp/option6_client_fqdn.h>
|
||||
#include <dhcp/option6_ia.h>
|
||||
#include <dhcp/option6_iaaddr.h>
|
||||
#include <dhcp/option_int.h>
|
||||
#include <dhcp/option_vendor.h>
|
||||
#include <dhcp/option_int_array.h>
|
||||
#include <dhcp/option_string.h>
|
||||
#include <dhcp/option_vendor.h>
|
||||
#include <dhcp/iface_mgr.h>
|
||||
#include <dhcp6/config_parser.h>
|
||||
#include <dhcp/dhcp6.h>
|
||||
@@ -53,267 +50,12 @@ using namespace isc;
|
||||
using namespace isc::test;
|
||||
using namespace isc::asiolink;
|
||||
using namespace isc::dhcp;
|
||||
using namespace isc::dhcp_ddns;
|
||||
using namespace isc::util;
|
||||
using namespace isc::hooks;
|
||||
using namespace std;
|
||||
|
||||
// namespace has to be named, because friends are defined in Dhcpv6Srv class
|
||||
// Maybe it should be isc::test?
|
||||
namespace {
|
||||
|
||||
// This is a test fixture class for testing the processing of the DHCPv6 Client
|
||||
// FQDN Option.
|
||||
class FqdnDhcpv6SrvTest : public Dhcpv6SrvTest {
|
||||
public:
|
||||
// Constructor
|
||||
FqdnDhcpv6SrvTest()
|
||||
: Dhcpv6SrvTest() {
|
||||
// generateClientId assigns DUID to duid_.
|
||||
generateClientId();
|
||||
lease_.reset(new Lease6(Lease::TYPE_NA, IOAddress("2001:db8:1::1"),
|
||||
duid_, 1234, 501, 502, 503,
|
||||
504, 1, 0));
|
||||
|
||||
}
|
||||
|
||||
// Destructor
|
||||
virtual ~FqdnDhcpv6SrvTest() {
|
||||
}
|
||||
|
||||
// Construct the DHCPv6 Client FQDN Option using flags and domain-name.
|
||||
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 which optionally holds DHCPv6 Client FQDN Option.
|
||||
Pkt6Ptr generateMessage(uint8_t msg_type,
|
||||
const uint8_t fqdn_flags,
|
||||
const std::string& fqdn_domain_name,
|
||||
const Option6ClientFqdn::DomainNameType
|
||||
fqdn_type,
|
||||
const bool include_oro,
|
||||
const bool include_fqdn = true,
|
||||
OptionPtr srvid = OptionPtr()) {
|
||||
Pkt6Ptr pkt = Pkt6Ptr(new Pkt6(msg_type, 1234));
|
||||
pkt->setRemoteAddr(IOAddress("fe80::abcd"));
|
||||
Option6IAPtr ia = generateIA(D6O_IA_NA, 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);
|
||||
}
|
||||
|
||||
if (include_fqdn) {
|
||||
pkt->addOption(createClientFqdn(fqdn_flags, fqdn_domain_name,
|
||||
fqdn_type));
|
||||
}
|
||||
|
||||
if (include_oro) {
|
||||
OptionUint16ArrayPtr oro(new OptionUint16Array(Option::V6,
|
||||
D6O_ORO));
|
||||
oro->addValue(D6O_CLIENT_FQDN);
|
||||
pkt->addOption(oro);
|
||||
}
|
||||
|
||||
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(D6O_IA_NA, 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(D6O_IA_NA, 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,
|
||||
const std::string& in_domain_name,
|
||||
const Option6ClientFqdn::DomainNameType in_domain_type,
|
||||
const uint8_t exp_flags,
|
||||
const std::string& exp_domain_name) {
|
||||
NakedDhcpv6Srv srv(0);
|
||||
Pkt6Ptr question = generateMessage(msg_type,
|
||||
in_flags,
|
||||
in_domain_name,
|
||||
in_domain_type,
|
||||
use_oro);
|
||||
ASSERT_TRUE(getClientFqdnOption(question));
|
||||
|
||||
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;
|
||||
const bool flag_s = (exp_flags & Option6ClientFqdn::FLAG_S) != 0;
|
||||
const bool flag_o = (exp_flags & Option6ClientFqdn::FLAG_O) != 0;
|
||||
|
||||
EXPECT_EQ(flag_n, answ_fqdn->getFlag(Option6ClientFqdn::FLAG_N));
|
||||
EXPECT_EQ(flag_s, answ_fqdn->getFlag(Option6ClientFqdn::FLAG_S));
|
||||
EXPECT_EQ(flag_o, answ_fqdn->getFlag(Option6ClientFqdn::FLAG_O));
|
||||
|
||||
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,
|
||||
const bool test_fqdn = true) {
|
||||
// Create a message of a specified type, add server id and
|
||||
// FQDN option.
|
||||
OptionPtr srvid = srv.getServerID();
|
||||
Pkt6Ptr req = generateMessage(msg_type, Option6ClientFqdn::FLAG_S,
|
||||
hostname,
|
||||
Option6ClientFqdn::FULL,
|
||||
true, test_fqdn, 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"),
|
||||
Lease::TYPE_NA);
|
||||
|
||||
if (msg_type != DHCPV6_SOLICIT) {
|
||||
// Check that the lease exists.
|
||||
Lease6Ptr lease =
|
||||
checkLease(duid_, reply->getOption(D6O_IA_NA), addr);
|
||||
ASSERT_TRUE(lease);
|
||||
}
|
||||
|
||||
if (test_fqdn) {
|
||||
ASSERT_TRUE(reply->getOption(D6O_CLIENT_FQDN));
|
||||
} else {
|
||||
ASSERT_FALSE(reply->getOption(D6O_CLIENT_FQDN));
|
||||
}
|
||||
}
|
||||
|
||||
// Verify that NameChangeRequest holds valid values.
|
||||
void verifyNameChangeRequest(NakedDhcpv6Srv& srv,
|
||||
const isc::dhcp_ddns::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::dhcp_ddns::ST_NEW, ncr.getStatus());
|
||||
srv.name_change_reqs_.pop();
|
||||
}
|
||||
|
||||
// Holds a lease used by a test.
|
||||
Lease6Ptr lease_;
|
||||
|
||||
};
|
||||
|
||||
// This test verifies that incoming SOLICIT can be handled properly when
|
||||
// there are no subnets configured.
|
||||
//
|
||||
@@ -1584,390 +1326,6 @@ TEST_F(Dhcpv6SrvTest, ServerID) {
|
||||
EXPECT_EQ(duid1_text, text);
|
||||
}
|
||||
|
||||
// A set of tests verifying server's behaviour when it receives the DHCPv6
|
||||
// Client Fqdn Option.
|
||||
// @todo: Extend these tests once appropriate configuration parameters are
|
||||
// implemented (ticket #3034).
|
||||
|
||||
// Test server's response when client requests that server performs AAAA update.
|
||||
TEST_F(FqdnDhcpv6SrvTest, serverAAAAUpdate) {
|
||||
testFqdn(DHCPV6_SOLICIT, true, Option6ClientFqdn::FLAG_S,
|
||||
"myhost.example.com",
|
||||
Option6ClientFqdn::FULL, Option6ClientFqdn::FLAG_S,
|
||||
"myhost.example.com.");
|
||||
}
|
||||
|
||||
// Test server's response when client provides partial domain-name and requests
|
||||
// that server performs AAAA update.
|
||||
TEST_F(FqdnDhcpv6SrvTest, serverAAAAUpdatePartialName) {
|
||||
testFqdn(DHCPV6_SOLICIT, true, Option6ClientFqdn::FLAG_S, "myhost",
|
||||
Option6ClientFqdn::PARTIAL, Option6ClientFqdn::FLAG_S,
|
||||
"myhost.example.com.");
|
||||
}
|
||||
|
||||
// Test server's response when client provides empty domain-name and requests
|
||||
// that server performs AAAA update.
|
||||
TEST_F(FqdnDhcpv6SrvTest, serverAAAAUpdateNoName) {
|
||||
testFqdn(DHCPV6_SOLICIT, true, Option6ClientFqdn::FLAG_S, "",
|
||||
Option6ClientFqdn::PARTIAL, Option6ClientFqdn::FLAG_S,
|
||||
"myhost.example.com.");
|
||||
}
|
||||
|
||||
// Test server's response when client requests no DNS update.
|
||||
TEST_F(FqdnDhcpv6SrvTest, noUpdate) {
|
||||
testFqdn(DHCPV6_SOLICIT, true, Option6ClientFqdn::FLAG_N,
|
||||
"myhost.example.com",
|
||||
Option6ClientFqdn::FULL, Option6ClientFqdn::FLAG_N,
|
||||
"myhost.example.com.");
|
||||
}
|
||||
|
||||
// Test server's response when client requests that server delegates the AAAA
|
||||
// update to the client and this delegation is not allowed.
|
||||
TEST_F(FqdnDhcpv6SrvTest, clientAAAAUpdateNotAllowed) {
|
||||
testFqdn(DHCPV6_SOLICIT, true, 0, "myhost.example.com.",
|
||||
Option6ClientFqdn::FULL,
|
||||
Option6ClientFqdn::FLAG_S | Option6ClientFqdn::FLAG_O,
|
||||
"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);
|
||||
|
||||
// Use domain name in upper case. It should be converted to lower-case
|
||||
// before DHCID is calculated. So, we should get the same result as if
|
||||
// we typed domain name in lower-case.
|
||||
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::dhcp_ddns::CHG_ADD, true, true,
|
||||
"2001:db8:1::1",
|
||||
"000201415AA33D1187D148275136FA30300478"
|
||||
"FAAAA3EBD29826B5C907B2C9268A6F52",
|
||||
0, 500);
|
||||
|
||||
verifyNameChangeRequest(srv, isc::dhcp_ddns::CHG_ADD, true, true,
|
||||
"2001:db8:1::2",
|
||||
"000201415AA33D1187D148275136FA30300478"
|
||||
"FAAAA3EBD29826B5C907B2C9268A6F52",
|
||||
0, 500);
|
||||
|
||||
verifyNameChangeRequest(srv, isc::dhcp_ddns::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;
|
||||
// Part of the domain name is in upper case, to test that it gets converted
|
||||
// to lower case before DHCID is computed. So, we should get the same DHCID
|
||||
// as if we typed domain-name in lower case.
|
||||
lease_->hostname_ = "MYHOST.example.com.";
|
||||
|
||||
ASSERT_NO_THROW(srv.createRemovalNameChangeRequest(lease_));
|
||||
|
||||
ASSERT_EQ(1, srv.name_change_reqs_.size());
|
||||
|
||||
verifyNameChangeRequest(srv, isc::dhcp_ddns::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::dhcp_ddns::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 processSolicit function.
|
||||
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::dhcp_ddns::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::dhcp_ddns::CHG_REMOVE, true, true,
|
||||
"2001:db8:1:1::dead:beef",
|
||||
"000201415AA33D1187D148275136FA30300478"
|
||||
"FAAAA3EBD29826B5C907B2C9268A6F52",
|
||||
0, 4000);
|
||||
verifyNameChangeRequest(srv, isc::dhcp_ddns::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::dhcp_ddns::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::dhcp_ddns::CHG_REMOVE, true, true,
|
||||
"2001:db8:1:1::dead:beef",
|
||||
"000201415AA33D1187D148275136FA30300478"
|
||||
"FAAAA3EBD29826B5C907B2C9268A6F52",
|
||||
0, 4000);
|
||||
verifyNameChangeRequest(srv, isc::dhcp_ddns::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::dhcp_ddns::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::dhcp_ddns::CHG_REMOVE, true, true,
|
||||
"2001:db8:1:1::dead:beef",
|
||||
"000201415AA33D1187D148275136FA30300478"
|
||||
"FAAAA3EBD29826B5C907B2C9268A6F52",
|
||||
0, 4000);
|
||||
|
||||
}
|
||||
|
||||
// Checks that the server does not include DHCPv6 Client FQDN option in its
|
||||
// response when client doesn't include this option in a Request.
|
||||
TEST_F(FqdnDhcpv6SrvTest, processRequestWithoutFqdn) {
|
||||
NakedDhcpv6Srv srv(0);
|
||||
|
||||
// The last parameter disables the use of DHCPv6 Client FQDN option
|
||||
// in the client's Request. In this case, we expect that the FQDN
|
||||
// option will not be included in the server's response. The
|
||||
// testProcessMessage will check that.
|
||||
testProcessMessage(DHCPV6_REQUEST, "myhost.example.com", srv, false);
|
||||
ASSERT_TRUE(srv.name_change_reqs_.empty());
|
||||
}
|
||||
|
||||
// Checks if server responses are sent to the proper port.
|
||||
TEST_F(Dhcpv6SrvTest, portsDirectTraffic) {
|
||||
|
||||
|
777
src/bin/dhcp6/tests/fqdn_unittest.cc
Normal file
777
src/bin/dhcp6/tests/fqdn_unittest.cc
Normal file
@@ -0,0 +1,777 @@
|
||||
// Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <asiolink/io_address.h>
|
||||
#include <dhcp_ddns/ncr_msg.h>
|
||||
#include <dhcp/dhcp6.h>
|
||||
#include <dhcp/option.h>
|
||||
#include <dhcp/option_custom.h>
|
||||
#include <dhcp/option6_client_fqdn.h>
|
||||
#include <dhcp/option6_ia.h>
|
||||
#include <dhcp/option6_iaaddr.h>
|
||||
#include <dhcp/option_int_array.h>
|
||||
#include <dhcpsrv/lease.h>
|
||||
|
||||
#include <dhcp6/tests/dhcp6_test_utils.h>
|
||||
#include <boost/pointer_cast.hpp>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using namespace isc;
|
||||
using namespace isc::test;
|
||||
using namespace isc::asiolink;
|
||||
using namespace isc::dhcp;
|
||||
using namespace isc::dhcp_ddns;
|
||||
using namespace isc::util;
|
||||
using namespace isc::hooks;
|
||||
using namespace std;
|
||||
|
||||
namespace {
|
||||
|
||||
/// @brief A test fixture class for testing DHCPv6 Client FQDN Option handling.
|
||||
class FqdnDhcpv6SrvTest : public Dhcpv6SrvTest {
|
||||
public:
|
||||
|
||||
/// @brief Constructor
|
||||
FqdnDhcpv6SrvTest()
|
||||
: Dhcpv6SrvTest() {
|
||||
// generateClientId assigns DUID to duid_.
|
||||
generateClientId();
|
||||
lease_.reset(new Lease6(Lease::TYPE_NA, IOAddress("2001:db8:1::1"),
|
||||
duid_, 1234, 501, 502, 503,
|
||||
504, 1, 0));
|
||||
|
||||
}
|
||||
|
||||
/// @brief Destructor
|
||||
virtual ~FqdnDhcpv6SrvTest() {
|
||||
}
|
||||
|
||||
/// @brief Construct the DHCPv6 Client FQDN option using flags and
|
||||
/// domain-name.
|
||||
///
|
||||
/// @param flags Flags to be set for the created option.
|
||||
/// @param fqdn_name A name which should be stored in the option.
|
||||
/// @param fqdn_type A type of the name carried by the option: partial
|
||||
/// or fully qualified.
|
||||
///
|
||||
/// @return A pointer to the created option.
|
||||
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)));
|
||||
}
|
||||
|
||||
/// @brief Create a message with or without DHCPv6 Client FQDN Option.
|
||||
///
|
||||
/// @param msg_type A type of the DHCPv6 message to be created.
|
||||
/// @param fqdn_flags Flags to be carried in the FQDN option.
|
||||
/// @param fqdn_domain_name A name to be carried in the FQDN option.
|
||||
/// @param fqdn_type A type of the name carried by the option: partial
|
||||
/// or fully qualified.
|
||||
/// @param include_oro A boolean value which indicates whether the ORO
|
||||
/// option should be added to the message (if true).
|
||||
/// @param srvid server id to be stored in the message.
|
||||
///
|
||||
/// @return An object representing the created message.
|
||||
Pkt6Ptr generateMessage(uint8_t msg_type,
|
||||
const uint8_t fqdn_flags,
|
||||
const std::string& fqdn_domain_name,
|
||||
const Option6ClientFqdn::DomainNameType
|
||||
fqdn_type,
|
||||
const bool include_oro,
|
||||
const bool include_fqdn = true,
|
||||
OptionPtr srvid = OptionPtr()) {
|
||||
Pkt6Ptr pkt = Pkt6Ptr(new Pkt6(msg_type, 1234));
|
||||
pkt->setRemoteAddr(IOAddress("fe80::abcd"));
|
||||
Option6IAPtr ia = generateIA(D6O_IA_NA, 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);
|
||||
}
|
||||
|
||||
if (include_fqdn) {
|
||||
pkt->addOption(createClientFqdn(fqdn_flags, fqdn_domain_name,
|
||||
fqdn_type));
|
||||
}
|
||||
|
||||
if (include_oro) {
|
||||
OptionUint16ArrayPtr oro(new OptionUint16Array(Option::V6,
|
||||
D6O_ORO));
|
||||
oro->addValue(D6O_CLIENT_FQDN);
|
||||
pkt->addOption(oro);
|
||||
}
|
||||
|
||||
return (pkt);
|
||||
}
|
||||
|
||||
/// @brief Creates instance of the DHCPv6 message with client id and
|
||||
/// server id.
|
||||
///
|
||||
/// @param msg_type A type of the message to be created.
|
||||
/// @param srv An object representing the DHCPv6 server, which
|
||||
/// is used to generate the client identifier.
|
||||
///
|
||||
/// @return An object representing the created message.
|
||||
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);
|
||||
}
|
||||
|
||||
/// @brief Returns an instance of the option carrying FQDN.
|
||||
///
|
||||
/// @param pkt A message holding FQDN option to be returned.
|
||||
///
|
||||
/// @return An object representing DHCPv6 Client FQDN option.
|
||||
Option6ClientFqdnPtr getClientFqdnOption(const Pkt6Ptr& pkt) {
|
||||
return (boost::dynamic_pointer_cast<Option6ClientFqdn>
|
||||
(pkt->getOption(D6O_CLIENT_FQDN)));
|
||||
}
|
||||
|
||||
/// @brief Adds IA option to the message.
|
||||
///
|
||||
/// Addded option holds an address.
|
||||
///
|
||||
/// @param iaid IAID
|
||||
/// @param pkt A DHCPv6 message to which the IA option should be added.
|
||||
void addIA(const uint32_t iaid, const IOAddress& addr, Pkt6Ptr& pkt) {
|
||||
Option6IAPtr opt_ia = generateIA(D6O_IA_NA, iaid, 1500, 3000);
|
||||
Option6IAAddrPtr opt_iaaddr(new Option6IAAddr(D6O_IAADDR, addr,
|
||||
300, 500));
|
||||
opt_ia->addOption(opt_iaaddr);
|
||||
pkt->addOption(opt_ia);
|
||||
}
|
||||
|
||||
|
||||
/// @brief Adds IA option to the message.
|
||||
///
|
||||
/// Added option holds status code.
|
||||
///
|
||||
/// @param iaid IAID
|
||||
/// @param status_code Status code
|
||||
/// @param pkt A DHCPv6 message to which the option should be added.
|
||||
void addIA(const uint32_t iaid, const uint16_t status_code, Pkt6Ptr& pkt) {
|
||||
Option6IAPtr opt_ia = generateIA(D6O_IA_NA, iaid, 1500, 3000);
|
||||
addStatusCode(status_code, "", opt_ia);
|
||||
pkt->addOption(opt_ia);
|
||||
}
|
||||
|
||||
/// @brief Creates status code with the specified code and message.
|
||||
///
|
||||
/// @param code A status code.
|
||||
/// @param msg A string representation of the message to be added to the
|
||||
/// Status Code option.
|
||||
///
|
||||
/// @return An object representing the Status Code option.
|
||||
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);
|
||||
}
|
||||
|
||||
/// @brief Adds Status Code option to the IA.
|
||||
///
|
||||
/// @param code A status code value.
|
||||
/// @param msg A string representation of the message to be added to the
|
||||
/// Status Code option.
|
||||
void addStatusCode(const uint16_t code, const std::string& msg,
|
||||
Option6IAPtr& opt_ia) {
|
||||
opt_ia->addOption(createStatusCode(code, msg));
|
||||
}
|
||||
|
||||
/// @brief Verifies if the DHCPv6 server processes DHCPv6 Client FQDN option
|
||||
/// as expected.
|
||||
///
|
||||
/// This function simulates generation of the client's message holding FQDN.
|
||||
/// It then calls the server's @c Dhcpv6Srv::processClientFqdn option to
|
||||
/// generate server's response to the FQDN. This function returns the FQDN
|
||||
/// which should be appended to the server's response to the client.
|
||||
/// This function verifies that the FQDN option returned is correct.
|
||||
///
|
||||
/// @param msg_type A type of the client's message.
|
||||
/// @param use_oro A boolean value which indicates whether the DHCPv6 ORO
|
||||
/// option (requesting return of the FQDN option by the server) should be
|
||||
/// included in the client's message (if true), or not included (if false).
|
||||
/// @param in_flags A value of flags field to be set for the FQDN carried
|
||||
/// in the client's message.
|
||||
/// @param in_domain_name A domain name to be carried in the client's FQDN
|
||||
/// option.
|
||||
/// @param in_domain_type A type of the domain name to be carried in the
|
||||
/// client's FQDM option (partial or fully qualified).
|
||||
/// @param exp_flags A value of flags expected in the FQDN sent by a server.
|
||||
/// @param exp_domain_name A domain name expected in the FQDN sent by a
|
||||
/// server.
|
||||
void testFqdn(const uint16_t msg_type,
|
||||
const bool use_oro,
|
||||
const uint8_t in_flags,
|
||||
const std::string& in_domain_name,
|
||||
const Option6ClientFqdn::DomainNameType in_domain_type,
|
||||
const uint8_t exp_flags,
|
||||
const std::string& exp_domain_name) {
|
||||
NakedDhcpv6Srv srv(0);
|
||||
Pkt6Ptr question = generateMessage(msg_type,
|
||||
in_flags,
|
||||
in_domain_name,
|
||||
in_domain_type,
|
||||
use_oro);
|
||||
ASSERT_TRUE(getClientFqdnOption(question));
|
||||
|
||||
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;
|
||||
const bool flag_s = (exp_flags & Option6ClientFqdn::FLAG_S) != 0;
|
||||
const bool flag_o = (exp_flags & Option6ClientFqdn::FLAG_O) != 0;
|
||||
|
||||
EXPECT_EQ(flag_n, answ_fqdn->getFlag(Option6ClientFqdn::FLAG_N));
|
||||
EXPECT_EQ(flag_s, answ_fqdn->getFlag(Option6ClientFqdn::FLAG_S));
|
||||
EXPECT_EQ(flag_o, answ_fqdn->getFlag(Option6ClientFqdn::FLAG_O));
|
||||
|
||||
EXPECT_EQ(exp_domain_name, answ_fqdn->getDomainName());
|
||||
EXPECT_EQ(Option6ClientFqdn::FULL, answ_fqdn->getDomainNameType());
|
||||
}
|
||||
|
||||
/// @brief Tests that the client's message holding an FQDN is processed
|
||||
/// and that lease is acquired.
|
||||
///
|
||||
/// @param msg_type A type of the client's message.
|
||||
/// @param hostname A domain name in the client's FQDN.
|
||||
/// @param srv A server object, used to process the message.
|
||||
/// @param test_fqdn A boolean value which indicates whether the FQDN
|
||||
/// option should be included in the client's message (if true) or not
|
||||
/// (if false). In the former case, the function will expect that server
|
||||
/// responds with the FQDN option. In the latter case, the function expects
|
||||
/// that the server doesn't respond with the FQDN.
|
||||
void testProcessMessage(const uint8_t msg_type,
|
||||
const std::string& hostname,
|
||||
NakedDhcpv6Srv& srv,
|
||||
const bool test_fqdn = true) {
|
||||
// Create a message of a specified type, add server id and
|
||||
// FQDN option.
|
||||
OptionPtr srvid = srv.getServerID();
|
||||
Pkt6Ptr req = generateMessage(msg_type, Option6ClientFqdn::FLAG_S,
|
||||
hostname,
|
||||
Option6ClientFqdn::FULL,
|
||||
true, test_fqdn, 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"),
|
||||
Lease::TYPE_NA);
|
||||
|
||||
if (msg_type != DHCPV6_SOLICIT) {
|
||||
// Check that the lease exists.
|
||||
Lease6Ptr lease =
|
||||
checkLease(duid_, reply->getOption(D6O_IA_NA), addr);
|
||||
ASSERT_TRUE(lease);
|
||||
}
|
||||
|
||||
if (test_fqdn) {
|
||||
ASSERT_TRUE(reply->getOption(D6O_CLIENT_FQDN));
|
||||
} else {
|
||||
ASSERT_FALSE(reply->getOption(D6O_CLIENT_FQDN));
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Verify that NameChangeRequest holds valid values.
|
||||
///
|
||||
/// This function picks first NameChangeRequest from the internal server's
|
||||
/// queue and checks that it holds valid parameters. The NameChangeRequest
|
||||
/// is removed from the queue.
|
||||
///
|
||||
/// @param srv A server object holding a queue of NameChangeRequests.
|
||||
/// @param type An expected type of the NameChangeRequest (Add or Remove).
|
||||
/// @param reverse An expected setting of the reverse update flag.
|
||||
/// @param forward An expected setting of the forward udpate flag.
|
||||
/// @param addr A string representation of the IPv6 address held in the
|
||||
/// NameChangeRequest.
|
||||
/// @param dhcid An expected DHCID value.
|
||||
/// @param expires A timestamp when the lease associated with the
|
||||
/// NameChangeRequest expires.
|
||||
/// @param len A valid lifetime of the lease associated with the
|
||||
/// NameChangeRequest.
|
||||
void verifyNameChangeRequest(NakedDhcpv6Srv& srv,
|
||||
const isc::dhcp_ddns::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::dhcp_ddns::ST_NEW, ncr.getStatus());
|
||||
srv.name_change_reqs_.pop();
|
||||
}
|
||||
|
||||
// Holds a lease used by a test.
|
||||
Lease6Ptr lease_;
|
||||
|
||||
};
|
||||
|
||||
// A set of tests verifying server's behaviour when it receives the DHCPv6
|
||||
// Client Fqdn Option.
|
||||
// @todo: Extend these tests once appropriate configuration parameters are
|
||||
// implemented (ticket #3034).
|
||||
|
||||
// Test server's response when client requests that server performs AAAA update.
|
||||
TEST_F(FqdnDhcpv6SrvTest, serverAAAAUpdate) {
|
||||
testFqdn(DHCPV6_SOLICIT, true, Option6ClientFqdn::FLAG_S,
|
||||
"myhost.example.com",
|
||||
Option6ClientFqdn::FULL, Option6ClientFqdn::FLAG_S,
|
||||
"myhost.example.com.");
|
||||
}
|
||||
|
||||
// Test server's response when client provides partial domain-name and requests
|
||||
// that server performs AAAA update.
|
||||
TEST_F(FqdnDhcpv6SrvTest, serverAAAAUpdatePartialName) {
|
||||
testFqdn(DHCPV6_SOLICIT, true, Option6ClientFqdn::FLAG_S, "myhost",
|
||||
Option6ClientFqdn::PARTIAL, Option6ClientFqdn::FLAG_S,
|
||||
"myhost.example.com.");
|
||||
}
|
||||
|
||||
// Test server's response when client provides empty domain-name and requests
|
||||
// that server performs AAAA update.
|
||||
TEST_F(FqdnDhcpv6SrvTest, serverAAAAUpdateNoName) {
|
||||
testFqdn(DHCPV6_SOLICIT, true, Option6ClientFqdn::FLAG_S, "",
|
||||
Option6ClientFqdn::PARTIAL, Option6ClientFqdn::FLAG_S,
|
||||
"myhost.example.com.");
|
||||
}
|
||||
|
||||
// Test server's response when client requests no DNS update.
|
||||
TEST_F(FqdnDhcpv6SrvTest, noUpdate) {
|
||||
testFqdn(DHCPV6_SOLICIT, true, Option6ClientFqdn::FLAG_N,
|
||||
"myhost.example.com",
|
||||
Option6ClientFqdn::FULL, Option6ClientFqdn::FLAG_N,
|
||||
"myhost.example.com.");
|
||||
}
|
||||
|
||||
// Test server's response when client requests that server delegates the AAAA
|
||||
// update to the client and this delegation is not allowed.
|
||||
TEST_F(FqdnDhcpv6SrvTest, clientAAAAUpdateNotAllowed) {
|
||||
testFqdn(DHCPV6_SOLICIT, true, 0, "myhost.example.com.",
|
||||
Option6ClientFqdn::FULL,
|
||||
Option6ClientFqdn::FLAG_S | Option6ClientFqdn::FLAG_O,
|
||||
"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);
|
||||
|
||||
// Use domain name in upper case. It should be converted to lower-case
|
||||
// before DHCID is calculated. So, we should get the same result as if
|
||||
// we typed domain name in lower-case.
|
||||
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::dhcp_ddns::CHG_ADD, true, true,
|
||||
"2001:db8:1::1",
|
||||
"000201415AA33D1187D148275136FA30300478"
|
||||
"FAAAA3EBD29826B5C907B2C9268A6F52",
|
||||
0, 500);
|
||||
|
||||
verifyNameChangeRequest(srv, isc::dhcp_ddns::CHG_ADD, true, true,
|
||||
"2001:db8:1::2",
|
||||
"000201415AA33D1187D148275136FA30300478"
|
||||
"FAAAA3EBD29826B5C907B2C9268A6F52",
|
||||
0, 500);
|
||||
|
||||
verifyNameChangeRequest(srv, isc::dhcp_ddns::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;
|
||||
// Part of the domain name is in upper case, to test that it gets converted
|
||||
// to lower case before DHCID is computed. So, we should get the same DHCID
|
||||
// as if we typed domain-name in lower case.
|
||||
lease_->hostname_ = "MYHOST.example.com.";
|
||||
|
||||
ASSERT_NO_THROW(srv.createRemovalNameChangeRequest(lease_));
|
||||
|
||||
ASSERT_EQ(1, srv.name_change_reqs_.size());
|
||||
|
||||
verifyNameChangeRequest(srv, isc::dhcp_ddns::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::dhcp_ddns::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 processSolicit function.
|
||||
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::dhcp_ddns::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::dhcp_ddns::CHG_REMOVE, true, true,
|
||||
"2001:db8:1:1::dead:beef",
|
||||
"000201415AA33D1187D148275136FA30300478"
|
||||
"FAAAA3EBD29826B5C907B2C9268A6F52",
|
||||
0, 4000);
|
||||
verifyNameChangeRequest(srv, isc::dhcp_ddns::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::dhcp_ddns::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::dhcp_ddns::CHG_REMOVE, true, true,
|
||||
"2001:db8:1:1::dead:beef",
|
||||
"000201415AA33D1187D148275136FA30300478"
|
||||
"FAAAA3EBD29826B5C907B2C9268A6F52",
|
||||
0, 4000);
|
||||
verifyNameChangeRequest(srv, isc::dhcp_ddns::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::dhcp_ddns::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::dhcp_ddns::CHG_REMOVE, true, true,
|
||||
"2001:db8:1:1::dead:beef",
|
||||
"000201415AA33D1187D148275136FA30300478"
|
||||
"FAAAA3EBD29826B5C907B2C9268A6F52",
|
||||
0, 4000);
|
||||
|
||||
}
|
||||
|
||||
// Checks that the server does not include DHCPv6 Client FQDN option in its
|
||||
// response when client doesn't include this option in a Request.
|
||||
TEST_F(FqdnDhcpv6SrvTest, processRequestWithoutFqdn) {
|
||||
NakedDhcpv6Srv srv(0);
|
||||
|
||||
// The last parameter disables the use of DHCPv6 Client FQDN option
|
||||
// in the client's Request. In this case, we expect that the FQDN
|
||||
// option will not be included in the server's response. The
|
||||
// testProcessMessage will check that.
|
||||
testProcessMessage(DHCPV6_REQUEST, "myhost.example.com", srv, false);
|
||||
ASSERT_TRUE(srv.name_change_reqs_.empty());
|
||||
}
|
||||
|
||||
} // end of anonymous namespace
|
Reference in New Issue
Block a user