fqdn_unittest.cc 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775
  1. // Copyright (C) 2013-2014 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <config.h>
  15. #include <asiolink/io_address.h>
  16. #include <dhcp_ddns/ncr_msg.h>
  17. #include <dhcp/dhcp6.h>
  18. #include <dhcp/option.h>
  19. #include <dhcp/option_custom.h>
  20. #include <dhcp/option6_client_fqdn.h>
  21. #include <dhcp/option6_ia.h>
  22. #include <dhcp/option6_iaaddr.h>
  23. #include <dhcp/option_int_array.h>
  24. #include <dhcpsrv/lease.h>
  25. #include <dhcp6/tests/dhcp6_test_utils.h>
  26. #include <boost/pointer_cast.hpp>
  27. #include <gtest/gtest.h>
  28. using namespace isc;
  29. using namespace isc::test;
  30. using namespace isc::asiolink;
  31. using namespace isc::dhcp;
  32. using namespace isc::dhcp_ddns;
  33. using namespace isc::util;
  34. using namespace isc::hooks;
  35. using namespace std;
  36. namespace {
  37. /// @brief A test fixture class for testing DHCPv6 Client FQDN Option handling.
  38. class FqdnDhcpv6SrvTest : public Dhcpv6SrvTest {
  39. public:
  40. /// @brief Constructor
  41. FqdnDhcpv6SrvTest()
  42. : Dhcpv6SrvTest() {
  43. // generateClientId assigns DUID to duid_.
  44. generateClientId();
  45. lease_.reset(new Lease6(Lease::TYPE_NA, IOAddress("2001:db8:1::1"),
  46. duid_, 1234, 501, 502, 503,
  47. 504, 1, 0));
  48. }
  49. /// @brief Destructor
  50. virtual ~FqdnDhcpv6SrvTest() {
  51. }
  52. /// @brief Construct the DHCPv6 Client FQDN option using flags and
  53. /// domain-name.
  54. ///
  55. /// @param flags Flags to be set for the created option.
  56. /// @param fqdn_name A name which should be stored in the option.
  57. /// @param fqdn_type A type of the name carried by the option: partial
  58. /// or fully qualified.
  59. ///
  60. /// @return A pointer to the created option.
  61. Option6ClientFqdnPtr
  62. createClientFqdn(const uint8_t flags,
  63. const std::string& fqdn_name,
  64. const Option6ClientFqdn::DomainNameType fqdn_type) {
  65. return (Option6ClientFqdnPtr(new Option6ClientFqdn(flags,
  66. fqdn_name,
  67. fqdn_type)));
  68. }
  69. /// @brief Create a message with or without DHCPv6 Client FQDN Option.
  70. ///
  71. /// @param msg_type A type of the DHCPv6 message to be created.
  72. /// @param fqdn_flags Flags to be carried in the FQDN option.
  73. /// @param fqdn_domain_name A name to be carried in the FQDN option.
  74. /// @param fqdn_type A type of the name carried by the option: partial
  75. /// or fully qualified.
  76. /// @param include_oro A boolean value which indicates whether the ORO
  77. /// option should be added to the message (if true).
  78. /// @param srvid server id to be stored in the message.
  79. ///
  80. /// @return An object representing the created message.
  81. Pkt6Ptr generateMessage(uint8_t msg_type,
  82. const uint8_t fqdn_flags,
  83. const std::string& fqdn_domain_name,
  84. const Option6ClientFqdn::DomainNameType
  85. fqdn_type,
  86. const bool include_oro,
  87. OptionPtr srvid = OptionPtr()) {
  88. Pkt6Ptr pkt = Pkt6Ptr(new Pkt6(msg_type, 1234));
  89. pkt->setRemoteAddr(IOAddress("fe80::abcd"));
  90. Option6IAPtr ia = generateIA(D6O_IA_NA, 234, 1500, 3000);
  91. if (msg_type != DHCPV6_REPLY) {
  92. IOAddress hint("2001:db8:1:1::dead:beef");
  93. OptionPtr hint_opt(new Option6IAAddr(D6O_IAADDR, hint, 300, 500));
  94. ia->addOption(hint_opt);
  95. pkt->addOption(ia);
  96. }
  97. OptionPtr clientid = generateClientId();
  98. pkt->addOption(clientid);
  99. if (srvid && (msg_type != DHCPV6_SOLICIT)) {
  100. pkt->addOption(srvid);
  101. }
  102. pkt->addOption(createClientFqdn(fqdn_flags, fqdn_domain_name,
  103. fqdn_type));
  104. if (include_oro) {
  105. OptionUint16ArrayPtr oro(new OptionUint16Array(Option::V6,
  106. D6O_ORO));
  107. oro->addValue(D6O_CLIENT_FQDN);
  108. pkt->addOption(oro);
  109. }
  110. return (pkt);
  111. }
  112. /// @brief Creates instance of the DHCPv6 message with client id and
  113. /// server id.
  114. ///
  115. /// @param msg_type A type of the message to be created.
  116. /// @param srv An object representing the DHCPv6 server, which
  117. /// is used to generate the client identifier.
  118. ///
  119. /// @return An object representing the created message.
  120. Pkt6Ptr generateMessageWithIds(const uint8_t msg_type,
  121. NakedDhcpv6Srv& srv) {
  122. Pkt6Ptr pkt = Pkt6Ptr(new Pkt6(msg_type, 1234));
  123. // Generate client-id.
  124. OptionPtr opt_clientid = generateClientId();
  125. pkt->addOption(opt_clientid);
  126. if (msg_type != DHCPV6_SOLICIT) {
  127. // Generate server-id.
  128. pkt->addOption(srv.getServerID());
  129. }
  130. return (pkt);
  131. }
  132. /// @brief Returns an instance of the option carrying FQDN.
  133. ///
  134. /// @param pkt A message holding FQDN option to be returned.
  135. ///
  136. /// @return An object representing DHCPv6 Client FQDN option.
  137. Option6ClientFqdnPtr getClientFqdnOption(const Pkt6Ptr& pkt) {
  138. return (boost::dynamic_pointer_cast<Option6ClientFqdn>
  139. (pkt->getOption(D6O_CLIENT_FQDN)));
  140. }
  141. /// @brief Adds IA option to the message.
  142. ///
  143. /// Addded option holds an address.
  144. ///
  145. /// @param iaid IAID
  146. /// @param pkt A DHCPv6 message to which the IA option should be added.
  147. void addIA(const uint32_t iaid, const IOAddress& addr, Pkt6Ptr& pkt) {
  148. Option6IAPtr opt_ia = generateIA(D6O_IA_NA, iaid, 1500, 3000);
  149. Option6IAAddrPtr opt_iaaddr(new Option6IAAddr(D6O_IAADDR, addr,
  150. 300, 500));
  151. opt_ia->addOption(opt_iaaddr);
  152. pkt->addOption(opt_ia);
  153. }
  154. /// @brief Adds IA option to the message.
  155. ///
  156. /// Added option holds status code.
  157. ///
  158. /// @param iaid IAID
  159. /// @param status_code Status code
  160. /// @param pkt A DHCPv6 message to which the option should be added.
  161. void addIA(const uint32_t iaid, const uint16_t status_code, Pkt6Ptr& pkt) {
  162. Option6IAPtr opt_ia = generateIA(D6O_IA_NA, iaid, 1500, 3000);
  163. addStatusCode(status_code, "", opt_ia);
  164. pkt->addOption(opt_ia);
  165. }
  166. /// @brief Creates status code with the specified code and message.
  167. ///
  168. /// @param code A status code.
  169. /// @param msg A string representation of the message to be added to the
  170. /// Status Code option.
  171. ///
  172. /// @return An object representing the Status Code option.
  173. OptionCustomPtr createStatusCode(const uint16_t code,
  174. const std::string& msg) {
  175. OptionDefinition def("status-code", D6O_STATUS_CODE, "record");
  176. def.addRecordField("uint16");
  177. def.addRecordField("string");
  178. OptionCustomPtr opt_status(new OptionCustom(def, Option::V6));
  179. opt_status->writeInteger(code);
  180. if (!msg.empty()) {
  181. opt_status->writeString(msg, 1);
  182. }
  183. return (opt_status);
  184. }
  185. /// @brief Adds Status Code option to the IA.
  186. ///
  187. /// @param code A status code value.
  188. /// @param msg A string representation of the message to be added to the
  189. /// Status Code option.
  190. void addStatusCode(const uint16_t code, const std::string& msg,
  191. Option6IAPtr& opt_ia) {
  192. opt_ia->addOption(createStatusCode(code, msg));
  193. }
  194. /// @brief Verifies if the DHCPv6 server processes DHCPv6 Client FQDN option
  195. /// as expected.
  196. ///
  197. /// This function simulates generation of the client's message holding FQDN.
  198. /// It then calls the server's @c Dhcpv6Srv::processClientFqdn option to
  199. /// generate server's response to the FQDN. This function returns the FQDN
  200. /// which should be appended to the server's response to the client.
  201. /// This function verifies that the FQDN option returned is correct.
  202. ///
  203. /// @param msg_type A type of the client's message.
  204. /// @param in_flags A value of flags field to be set for the FQDN carried
  205. /// in the client's message.
  206. /// @param in_domain_name A domain name to be carried in the client's FQDN
  207. /// option.
  208. /// @param in_domain_type A type of the domain name to be carried in the
  209. /// client's FQDM option (partial or fully qualified).
  210. /// @param exp_flags A value of flags expected in the FQDN sent by a server.
  211. /// @param exp_domain_name A domain name expected in the FQDN sent by a
  212. /// server.
  213. void testFqdn(const uint16_t msg_type,
  214. const uint8_t in_flags,
  215. const std::string& in_domain_name,
  216. const Option6ClientFqdn::DomainNameType in_domain_type,
  217. const uint8_t exp_flags,
  218. const std::string& exp_domain_name) {
  219. NakedDhcpv6Srv srv(0);
  220. Pkt6Ptr question = generateMessage(msg_type,
  221. in_flags,
  222. in_domain_name,
  223. in_domain_type,
  224. true);
  225. ASSERT_TRUE(getClientFqdnOption(question));
  226. Pkt6Ptr answer(new Pkt6(msg_type == DHCPV6_SOLICIT ? DHCPV6_ADVERTISE :
  227. DHCPV6_REPLY, question->getTransid()));
  228. ASSERT_NO_THROW(srv.processClientFqdn(question, answer));
  229. Option6ClientFqdnPtr answ_fqdn = boost::dynamic_pointer_cast<
  230. Option6ClientFqdn>(answer->getOption(D6O_CLIENT_FQDN));
  231. ASSERT_TRUE(answ_fqdn);
  232. const bool flag_n = (exp_flags & Option6ClientFqdn::FLAG_N) != 0;
  233. const bool flag_s = (exp_flags & Option6ClientFqdn::FLAG_S) != 0;
  234. const bool flag_o = (exp_flags & Option6ClientFqdn::FLAG_O) != 0;
  235. EXPECT_EQ(flag_n, answ_fqdn->getFlag(Option6ClientFqdn::FLAG_N));
  236. EXPECT_EQ(flag_s, answ_fqdn->getFlag(Option6ClientFqdn::FLAG_S));
  237. EXPECT_EQ(flag_o, answ_fqdn->getFlag(Option6ClientFqdn::FLAG_O));
  238. EXPECT_EQ(exp_domain_name, answ_fqdn->getDomainName());
  239. EXPECT_EQ(Option6ClientFqdn::FULL, answ_fqdn->getDomainNameType());
  240. }
  241. /// @brief Tests that the client's message holding an FQDN is processed
  242. /// and that lease is acquired.
  243. ///
  244. /// @param msg_type A type of the client's message.
  245. /// @param hostname A domain name in the client's FQDN.
  246. /// @param srv A server object, used to process the message.
  247. /// @param include_oro A boolean value which indicates whether the ORO
  248. /// option should be included in the client's message (if true) or not
  249. /// (if false). In the former case, the function will expect that server
  250. /// responds with the FQDN option. In the latter case, the function expects
  251. /// that the server doesn't respond with the FQDN.
  252. void testProcessMessage(const uint8_t msg_type,
  253. const std::string& hostname,
  254. NakedDhcpv6Srv& srv,
  255. const bool include_oro = true) {
  256. // Create a message of a specified type, add server id and
  257. // FQDN option.
  258. OptionPtr srvid = srv.getServerID();
  259. Pkt6Ptr req = generateMessage(msg_type, Option6ClientFqdn::FLAG_S,
  260. hostname,
  261. Option6ClientFqdn::FULL,
  262. include_oro, srvid);
  263. // For different client's message types we have to invoke different
  264. // functions to generate response.
  265. Pkt6Ptr reply;
  266. if (msg_type == DHCPV6_SOLICIT) {
  267. ASSERT_NO_THROW(reply = srv.processSolicit(req));
  268. } else if (msg_type == DHCPV6_REQUEST) {
  269. ASSERT_NO_THROW(reply = srv.processRequest(req));
  270. } else if (msg_type == DHCPV6_RENEW) {
  271. ASSERT_NO_THROW(reply = srv.processRequest(req));
  272. } else if (msg_type == DHCPV6_RELEASE) {
  273. // For Release no lease will be acquired so we have to leave
  274. // function here.
  275. ASSERT_NO_THROW(reply = srv.processRelease(req));
  276. return;
  277. } else {
  278. // We are not interested in testing other message types.
  279. return;
  280. }
  281. // For Solicit, we will get different message type obviously.
  282. if (msg_type == DHCPV6_SOLICIT) {
  283. checkResponse(reply, DHCPV6_ADVERTISE, 1234);
  284. } else {
  285. checkResponse(reply, DHCPV6_REPLY, 1234);
  286. }
  287. // Check verify that IA_NA is correct.
  288. Option6IAAddrPtr addr =
  289. checkIA_NA(reply, 234, subnet_->getT1(), subnet_->getT2());
  290. ASSERT_TRUE(addr);
  291. // Check that we have got the address we requested.
  292. checkIAAddr(addr, IOAddress("2001:db8:1:1::dead:beef"),
  293. Lease::TYPE_NA);
  294. if (msg_type != DHCPV6_SOLICIT) {
  295. // Check that the lease exists.
  296. Lease6Ptr lease =
  297. checkLease(duid_, reply->getOption(D6O_IA_NA), addr);
  298. ASSERT_TRUE(lease);
  299. }
  300. // The Client FQDN option should be always present in the server's
  301. // response, regardless if requested using ORO or not.
  302. ASSERT_TRUE(reply->getOption(D6O_CLIENT_FQDN));
  303. }
  304. /// @brief Verify that NameChangeRequest holds valid values.
  305. ///
  306. /// This function picks first NameChangeRequest from the internal server's
  307. /// queue and checks that it holds valid parameters. The NameChangeRequest
  308. /// is removed from the queue.
  309. ///
  310. /// @param srv A server object holding a queue of NameChangeRequests.
  311. /// @param type An expected type of the NameChangeRequest (Add or Remove).
  312. /// @param reverse An expected setting of the reverse update flag.
  313. /// @param forward An expected setting of the forward udpate flag.
  314. /// @param addr A string representation of the IPv6 address held in the
  315. /// NameChangeRequest.
  316. /// @param dhcid An expected DHCID value.
  317. /// @param expires A timestamp when the lease associated with the
  318. /// NameChangeRequest expires.
  319. /// @param len A valid lifetime of the lease associated with the
  320. /// NameChangeRequest.
  321. void verifyNameChangeRequest(NakedDhcpv6Srv& srv,
  322. const isc::dhcp_ddns::NameChangeType type,
  323. const bool reverse, const bool forward,
  324. const std::string& addr,
  325. const std::string& dhcid,
  326. const uint16_t expires,
  327. const uint16_t len) {
  328. NameChangeRequest ncr = srv.name_change_reqs_.front();
  329. EXPECT_EQ(type, ncr.getChangeType());
  330. EXPECT_EQ(forward, ncr.isForwardChange());
  331. EXPECT_EQ(reverse, ncr.isReverseChange());
  332. EXPECT_EQ(addr, ncr.getIpAddress());
  333. EXPECT_EQ(dhcid, ncr.getDhcid().toStr());
  334. EXPECT_EQ(expires, ncr.getLeaseExpiresOn());
  335. EXPECT_EQ(len, ncr.getLeaseLength());
  336. EXPECT_EQ(isc::dhcp_ddns::ST_NEW, ncr.getStatus());
  337. srv.name_change_reqs_.pop();
  338. }
  339. // Holds a lease used by a test.
  340. Lease6Ptr lease_;
  341. };
  342. // A set of tests verifying server's behaviour when it receives the DHCPv6
  343. // Client Fqdn Option.
  344. // @todo: Extend these tests once appropriate configuration parameters are
  345. // implemented (ticket #3034).
  346. // Test server's response when client requests that server performs AAAA update.
  347. TEST_F(FqdnDhcpv6SrvTest, serverAAAAUpdate) {
  348. testFqdn(DHCPV6_SOLICIT, Option6ClientFqdn::FLAG_S,
  349. "myhost.example.com",
  350. Option6ClientFqdn::FULL, Option6ClientFqdn::FLAG_S,
  351. "myhost.example.com.");
  352. }
  353. // Test server's response when client provides partial domain-name and requests
  354. // that server performs AAAA update.
  355. TEST_F(FqdnDhcpv6SrvTest, serverAAAAUpdatePartialName) {
  356. testFqdn(DHCPV6_SOLICIT, Option6ClientFqdn::FLAG_S, "myhost",
  357. Option6ClientFqdn::PARTIAL, Option6ClientFqdn::FLAG_S,
  358. "myhost.example.com.");
  359. }
  360. // Test server's response when client provides empty domain-name and requests
  361. // that server performs AAAA update.
  362. TEST_F(FqdnDhcpv6SrvTest, serverAAAAUpdateNoName) {
  363. testFqdn(DHCPV6_SOLICIT, Option6ClientFqdn::FLAG_S, "",
  364. Option6ClientFqdn::PARTIAL, Option6ClientFqdn::FLAG_S,
  365. "myhost.example.com.");
  366. }
  367. // Test server's response when client requests no DNS update.
  368. TEST_F(FqdnDhcpv6SrvTest, noUpdate) {
  369. testFqdn(DHCPV6_SOLICIT, Option6ClientFqdn::FLAG_N,
  370. "myhost.example.com",
  371. Option6ClientFqdn::FULL, Option6ClientFqdn::FLAG_N,
  372. "myhost.example.com.");
  373. }
  374. // Test server's response when client requests that server delegates the AAAA
  375. // update to the client and this delegation is not allowed.
  376. TEST_F(FqdnDhcpv6SrvTest, clientAAAAUpdateNotAllowed) {
  377. testFqdn(DHCPV6_SOLICIT, 0, "myhost.example.com.",
  378. Option6ClientFqdn::FULL,
  379. Option6ClientFqdn::FLAG_S | Option6ClientFqdn::FLAG_O,
  380. "myhost.example.com.");
  381. }
  382. // Test that exception is thrown if supplied NULL answer packet when
  383. // creating NameChangeRequests.
  384. TEST_F(FqdnDhcpv6SrvTest, createNameChangeRequestsNoAnswer) {
  385. NakedDhcpv6Srv srv(0);
  386. Pkt6Ptr answer;
  387. Option6ClientFqdnPtr fqdn = createClientFqdn(Option6ClientFqdn::FLAG_S,
  388. "myhost.example.com",
  389. Option6ClientFqdn::FULL);
  390. EXPECT_THROW(srv.createNameChangeRequests(answer, fqdn),
  391. isc::Unexpected);
  392. }
  393. // Test that exception is thrown if supplied answer from the server
  394. // contains no DUID when creating NameChangeRequests.
  395. TEST_F(FqdnDhcpv6SrvTest, createNameChangeRequestsNoDUID) {
  396. NakedDhcpv6Srv srv(0);
  397. Pkt6Ptr answer = Pkt6Ptr(new Pkt6(DHCPV6_REPLY, 1234));
  398. Option6ClientFqdnPtr fqdn = createClientFqdn(Option6ClientFqdn::FLAG_S,
  399. "myhost.example.com",
  400. Option6ClientFqdn::FULL);
  401. EXPECT_THROW(srv.createNameChangeRequests(answer, fqdn),
  402. isc::Unexpected);
  403. }
  404. // Test no NameChangeRequests are added if FQDN option is NULL.
  405. TEST_F(FqdnDhcpv6SrvTest, createNameChangeRequestsNoFQDN) {
  406. NakedDhcpv6Srv srv(0);
  407. // Create Reply message with Client Id and Server id.
  408. Pkt6Ptr answer = generateMessageWithIds(DHCPV6_REPLY, srv);
  409. // Pass NULL FQDN option. No NameChangeRequests should be created.
  410. Option6ClientFqdnPtr fqdn;
  411. ASSERT_NO_THROW(srv.createNameChangeRequests(answer, fqdn));
  412. // There should be no new NameChangeRequests.
  413. EXPECT_TRUE(srv.name_change_reqs_.empty());
  414. }
  415. // Test that NameChangeRequests are not generated if an answer message
  416. // contains no addresses.
  417. TEST_F(FqdnDhcpv6SrvTest, createNameChangeRequestsNoAddr) {
  418. NakedDhcpv6Srv srv(0);
  419. // Create Reply message with Client Id and Server id.
  420. Pkt6Ptr answer = generateMessageWithIds(DHCPV6_REPLY, srv);
  421. Option6ClientFqdnPtr fqdn = createClientFqdn(Option6ClientFqdn::FLAG_S,
  422. "myhost.example.com",
  423. Option6ClientFqdn::FULL);
  424. ASSERT_NO_THROW(srv.createNameChangeRequests(answer, fqdn));
  425. // We didn't add any IAs, so there should be no NameChangeRequests in th
  426. // queue.
  427. ASSERT_TRUE(srv.name_change_reqs_.empty());
  428. }
  429. // Test that a number of NameChangeRequests is created as a result of
  430. // processing the answer message which holds 3 IAs and when FQDN is
  431. // specified.
  432. TEST_F(FqdnDhcpv6SrvTest, createNameChangeRequests) {
  433. NakedDhcpv6Srv srv(0);
  434. // Create Reply message with Client Id and Server id.
  435. Pkt6Ptr answer = generateMessageWithIds(DHCPV6_REPLY, srv);
  436. // Create three IAs, each having different address.
  437. addIA(1234, IOAddress("2001:db8:1::1"), answer);
  438. addIA(2345, IOAddress("2001:db8:1::2"), answer);
  439. addIA(3456, IOAddress("2001:db8:1::3"), answer);
  440. // Use domain name in upper case. It should be converted to lower-case
  441. // before DHCID is calculated. So, we should get the same result as if
  442. // we typed domain name in lower-case.
  443. Option6ClientFqdnPtr fqdn = createClientFqdn(Option6ClientFqdn::FLAG_S,
  444. "MYHOST.EXAMPLE.COM",
  445. Option6ClientFqdn::FULL);
  446. // Create NameChangeRequests. Since we have added 3 IAs, it should
  447. // result in generation of 3 distinct NameChangeRequests.
  448. ASSERT_NO_THROW(srv.createNameChangeRequests(answer, fqdn));
  449. ASSERT_EQ(3, srv.name_change_reqs_.size());
  450. // Verify that NameChangeRequests are correct. Each call to the
  451. // verifyNameChangeRequest will pop verified request from the queue.
  452. verifyNameChangeRequest(srv, isc::dhcp_ddns::CHG_ADD, true, true,
  453. "2001:db8:1::1",
  454. "000201415AA33D1187D148275136FA30300478"
  455. "FAAAA3EBD29826B5C907B2C9268A6F52",
  456. 0, 500);
  457. verifyNameChangeRequest(srv, isc::dhcp_ddns::CHG_ADD, true, true,
  458. "2001:db8:1::2",
  459. "000201415AA33D1187D148275136FA30300478"
  460. "FAAAA3EBD29826B5C907B2C9268A6F52",
  461. 0, 500);
  462. verifyNameChangeRequest(srv, isc::dhcp_ddns::CHG_ADD, true, true,
  463. "2001:db8:1::3",
  464. "000201415AA33D1187D148275136FA30300478"
  465. "FAAAA3EBD29826B5C907B2C9268A6F52",
  466. 0, 500);
  467. }
  468. // Test creation of the NameChangeRequest to remove both forward and reverse
  469. // mapping for the given lease.
  470. TEST_F(FqdnDhcpv6SrvTest, createRemovalNameChangeRequestFwdRev) {
  471. NakedDhcpv6Srv srv(0);
  472. lease_->fqdn_fwd_ = true;
  473. lease_->fqdn_rev_ = true;
  474. // Part of the domain name is in upper case, to test that it gets converted
  475. // to lower case before DHCID is computed. So, we should get the same DHCID
  476. // as if we typed domain-name in lower case.
  477. lease_->hostname_ = "MYHOST.example.com.";
  478. ASSERT_NO_THROW(srv.createRemovalNameChangeRequest(lease_));
  479. ASSERT_EQ(1, srv.name_change_reqs_.size());
  480. verifyNameChangeRequest(srv, isc::dhcp_ddns::CHG_REMOVE, true, true,
  481. "2001:db8:1::1",
  482. "000201415AA33D1187D148275136FA30300478"
  483. "FAAAA3EBD29826B5C907B2C9268A6F52",
  484. 0, 502);
  485. }
  486. // Test creation of the NameChangeRequest to remove reverse mapping for the
  487. // given lease.
  488. TEST_F(FqdnDhcpv6SrvTest, createRemovalNameChangeRequestRev) {
  489. NakedDhcpv6Srv srv(0);
  490. lease_->fqdn_fwd_ = false;
  491. lease_->fqdn_rev_ = true;
  492. lease_->hostname_ = "myhost.example.com.";
  493. ASSERT_NO_THROW(srv.createRemovalNameChangeRequest(lease_));
  494. ASSERT_EQ(1, srv.name_change_reqs_.size());
  495. verifyNameChangeRequest(srv, isc::dhcp_ddns::CHG_REMOVE, true, false,
  496. "2001:db8:1::1",
  497. "000201415AA33D1187D148275136FA30300478"
  498. "FAAAA3EBD29826B5C907B2C9268A6F52",
  499. 0, 502);
  500. }
  501. // Test that NameChangeRequest to remove DNS records is not generated when
  502. // neither forward nor reverse DNS update has been performed for a lease.
  503. TEST_F(FqdnDhcpv6SrvTest, createRemovalNameChangeRequestNoUpdate) {
  504. NakedDhcpv6Srv srv(0);
  505. lease_->fqdn_fwd_ = false;
  506. lease_->fqdn_rev_ = false;
  507. ASSERT_NO_THROW(srv.createRemovalNameChangeRequest(lease_));
  508. EXPECT_TRUE(srv.name_change_reqs_.empty());
  509. }
  510. // Test that NameChangeRequest is not generated if the hostname hasn't been
  511. // specified for a lease for which forward and reverse mapping has been set.
  512. TEST_F(FqdnDhcpv6SrvTest, createRemovalNameChangeRequestNoHostname) {
  513. NakedDhcpv6Srv srv(0);
  514. lease_->fqdn_fwd_ = true;
  515. lease_->fqdn_rev_ = true;
  516. lease_->hostname_ = "";
  517. ASSERT_NO_THROW(srv.createRemovalNameChangeRequest(lease_));
  518. EXPECT_TRUE(srv.name_change_reqs_.empty());
  519. }
  520. // Test that NameChangeRequest is not generated if the invalid hostname has
  521. // been specified for a lease for which forward and reverse mapping has been
  522. // set.
  523. TEST_F(FqdnDhcpv6SrvTest, createRemovalNameChangeRequestWrongHostname) {
  524. NakedDhcpv6Srv srv(0);
  525. lease_->fqdn_fwd_ = true;
  526. lease_->fqdn_rev_ = true;
  527. lease_->hostname_ = "myhost..example.com.";
  528. ASSERT_NO_THROW(srv.createRemovalNameChangeRequest(lease_));
  529. EXPECT_TRUE(srv.name_change_reqs_.empty());
  530. }
  531. // Test that Advertise message generated in a response to the Solicit will
  532. // not result in generation if the NameChangeRequests.
  533. TEST_F(FqdnDhcpv6SrvTest, processSolicit) {
  534. NakedDhcpv6Srv srv(0);
  535. // Create a Solicit message with FQDN option and generate server's
  536. // response using processSolicit function.
  537. testProcessMessage(DHCPV6_SOLICIT, "myhost.example.com", srv);
  538. EXPECT_TRUE(srv.name_change_reqs_.empty());
  539. }
  540. // Test that client may send two requests, each carrying FQDN option with
  541. // a different domain-name. Server should use existing lease for the second
  542. // request but modify the DNS entries for the lease according to the contents
  543. // of the FQDN sent in the second request.
  544. TEST_F(FqdnDhcpv6SrvTest, processTwoRequests) {
  545. NakedDhcpv6Srv srv(0);
  546. // Create a Request message with FQDN option and generate server's
  547. // response using processRequest function. This will result in the
  548. // creation of a new lease and the appropriate NameChangeRequest
  549. // to add both reverse and forward mapping to DNS.
  550. testProcessMessage(DHCPV6_REQUEST, "myhost.example.com", srv);
  551. ASSERT_EQ(1, srv.name_change_reqs_.size());
  552. verifyNameChangeRequest(srv, isc::dhcp_ddns::CHG_ADD, true, true,
  553. "2001:db8:1:1::dead:beef",
  554. "000201415AA33D1187D148275136FA30300478"
  555. "FAAAA3EBD29826B5C907B2C9268A6F52",
  556. 0, 4000);
  557. // Client may send another request message with a new domain-name. In this
  558. // case the same lease will be returned. The existing DNS entry needs to
  559. // be replaced with a new one. Server should determine that the different
  560. // FQDN has been already added to the DNS. As a result, the old DNS
  561. // entries should be removed and the entries for the new domain-name
  562. // should be added. Therefore, we expect two NameChangeRequests. One to
  563. // remove the existing entries, one to add new entries.
  564. testProcessMessage(DHCPV6_REQUEST, "otherhost.example.com", srv);
  565. ASSERT_EQ(2, srv.name_change_reqs_.size());
  566. verifyNameChangeRequest(srv, isc::dhcp_ddns::CHG_REMOVE, true, true,
  567. "2001:db8:1:1::dead:beef",
  568. "000201415AA33D1187D148275136FA30300478"
  569. "FAAAA3EBD29826B5C907B2C9268A6F52",
  570. 0, 4000);
  571. verifyNameChangeRequest(srv, isc::dhcp_ddns::CHG_ADD, true, true,
  572. "2001:db8:1:1::dead:beef",
  573. "000201D422AA463306223D269B6CB7AFE7AAD265FC"
  574. "EA97F93623019B2E0D14E5323D5A",
  575. 0, 4000);
  576. }
  577. // Test that client may send Request followed by the Renew, both holding
  578. // FQDN options, but each option holding different domain-name. The Renew
  579. // should result in generation of the two NameChangeRequests, one to remove
  580. // DNS entry added previously when Request was processed, another one to
  581. // add a new entry for the FQDN held in the Renew.
  582. TEST_F(FqdnDhcpv6SrvTest, processRequestRenew) {
  583. NakedDhcpv6Srv srv(0);
  584. // Create a Request message with FQDN option and generate server's
  585. // response using processRequest function. This will result in the
  586. // creation of a new lease and the appropriate NameChangeRequest
  587. // to add both reverse and forward mapping to DNS.
  588. testProcessMessage(DHCPV6_REQUEST, "myhost.example.com", srv);
  589. ASSERT_EQ(1, srv.name_change_reqs_.size());
  590. verifyNameChangeRequest(srv, isc::dhcp_ddns::CHG_ADD, true, true,
  591. "2001:db8:1:1::dead:beef",
  592. "000201415AA33D1187D148275136FA30300478"
  593. "FAAAA3EBD29826B5C907B2C9268A6F52",
  594. 0, 4000);
  595. // Client may send Renew message with a new domain-name. In this
  596. // case the same lease will be returned. The existing DNS entry needs to
  597. // be replaced with a new one. Server should determine that the different
  598. // FQDN has been already added to the DNS. As a result, the old DNS
  599. // entries should be removed and the entries for the new domain-name
  600. // should be added. Therefore, we expect two NameChangeRequests. One to
  601. // remove the existing entries, one to add new entries.
  602. testProcessMessage(DHCPV6_RENEW, "otherhost.example.com", srv);
  603. ASSERT_EQ(2, srv.name_change_reqs_.size());
  604. verifyNameChangeRequest(srv, isc::dhcp_ddns::CHG_REMOVE, true, true,
  605. "2001:db8:1:1::dead:beef",
  606. "000201415AA33D1187D148275136FA30300478"
  607. "FAAAA3EBD29826B5C907B2C9268A6F52",
  608. 0, 4000);
  609. verifyNameChangeRequest(srv, isc::dhcp_ddns::CHG_ADD, true, true,
  610. "2001:db8:1:1::dead:beef",
  611. "000201D422AA463306223D269B6CB7AFE7AAD265FC"
  612. "EA97F93623019B2E0D14E5323D5A",
  613. 0, 4000);
  614. }
  615. TEST_F(FqdnDhcpv6SrvTest, processRequestRelease) {
  616. NakedDhcpv6Srv srv(0);
  617. // Create a Request message with FQDN option and generate server's
  618. // response using processRequest function. This will result in the
  619. // creation of a new lease and the appropriate NameChangeRequest
  620. // to add both reverse and forward mapping to DNS.
  621. testProcessMessage(DHCPV6_REQUEST, "myhost.example.com", srv);
  622. ASSERT_EQ(1, srv.name_change_reqs_.size());
  623. verifyNameChangeRequest(srv, isc::dhcp_ddns::CHG_ADD, true, true,
  624. "2001:db8:1:1::dead:beef",
  625. "000201415AA33D1187D148275136FA30300478"
  626. "FAAAA3EBD29826B5C907B2C9268A6F52",
  627. 0, 4000);
  628. // Client may send Release message. In this case the lease should be
  629. // removed and all existing DNS entries for this lease should be
  630. // also removed. Therefore, we expect that single NameChangeRequest to
  631. // remove DNS entries is generated.
  632. testProcessMessage(DHCPV6_RELEASE, "otherhost.example.com", srv);
  633. ASSERT_EQ(1, srv.name_change_reqs_.size());
  634. verifyNameChangeRequest(srv, isc::dhcp_ddns::CHG_REMOVE, true, true,
  635. "2001:db8:1:1::dead:beef",
  636. "000201415AA33D1187D148275136FA30300478"
  637. "FAAAA3EBD29826B5C907B2C9268A6F52",
  638. 0, 4000);
  639. }
  640. // Checks that the server include DHCPv6 Client FQDN option in its
  641. // response even when client doesn't request this option using ORO.
  642. TEST_F(FqdnDhcpv6SrvTest, processRequestWithoutFqdn) {
  643. NakedDhcpv6Srv srv(0);
  644. // The last parameter disables use of the ORO to request FQDN option
  645. // In this case, we expect that the FQDN option will not be included
  646. // in the server's response. The testProcessMessage will check that.
  647. testProcessMessage(DHCPV6_REQUEST, "myhost.example.com", srv, false);
  648. ASSERT_EQ(1, srv.name_change_reqs_.size());
  649. verifyNameChangeRequest(srv, isc::dhcp_ddns::CHG_ADD, true, true,
  650. "2001:db8:1:1::dead:beef",
  651. "000201415AA33D1187D148275136FA30300478"
  652. "FAAAA3EBD29826B5C907B2C9268A6F52",
  653. 0, 4000);
  654. }
  655. } // end of anonymous namespace