fqdn_unittest.cc 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781
  1. // Copyright (C) 2013 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/option4_client_fqdn.h>
  17. #include <dhcp/option_int_array.h>
  18. #include <dhcp4/tests/dhcp4_test_utils.h>
  19. #include <dhcp_ddns/ncr_msg.h>
  20. #include <gtest/gtest.h>
  21. #include <boost/scoped_ptr.hpp>
  22. using namespace isc;
  23. using namespace isc::asiolink;
  24. using namespace isc::dhcp;
  25. using namespace isc::dhcp::test;
  26. using namespace isc::dhcp_ddns;
  27. namespace {
  28. class NameDhcpv4SrvTest : public Dhcpv4SrvFakeIfaceTest {
  29. public:
  30. NameDhcpv4SrvTest() : Dhcpv4SrvFakeIfaceTest() {
  31. srv_ = new NakedDhcpv4Srv(0);
  32. }
  33. virtual ~NameDhcpv4SrvTest() {
  34. delete srv_;
  35. }
  36. // Create a lease to be used by various tests.
  37. Lease4Ptr createLease(const isc::asiolink::IOAddress& addr,
  38. const std::string& hostname,
  39. const bool fqdn_fwd,
  40. const bool fqdn_rev) {
  41. const uint8_t hwaddr[] = { 0, 1, 2, 3, 4, 5, 6 };
  42. Lease4Ptr lease(new Lease4(addr, hwaddr, sizeof(hwaddr),
  43. &generateClientId()->getData()[0],
  44. generateClientId()->getData().size(),
  45. 100, 50, 75, time(NULL), subnet_->getID()));
  46. // @todo Set this through the Lease4 constructor.
  47. lease->hostname_ = hostname;
  48. lease->fqdn_fwd_ = fqdn_fwd;
  49. lease->fqdn_rev_ = fqdn_rev;
  50. return (lease);
  51. }
  52. // Create an instance of the DHCPv4 Client FQDN Option.
  53. Option4ClientFqdnPtr
  54. createClientFqdn(const uint8_t flags,
  55. const std::string& fqdn_name,
  56. Option4ClientFqdn::DomainNameType fqdn_type) {
  57. return (Option4ClientFqdnPtr(new Option4ClientFqdn(flags,
  58. Option4ClientFqdn::
  59. RCODE_CLIENT(),
  60. fqdn_name,
  61. fqdn_type)));
  62. }
  63. // Create an instance of the Hostname option.
  64. OptionCustomPtr
  65. createHostname(const std::string& hostname) {
  66. OptionDefinition def("hostname", DHO_HOST_NAME, "string");
  67. OptionCustomPtr opt_hostname(new OptionCustom(def, Option::V4));
  68. opt_hostname->writeString(hostname);
  69. return (opt_hostname);
  70. }
  71. // Generates partial hostname from the address. The format of the
  72. // generated address is: host-A-B-C-D, where A.B.C.D is an IP
  73. // address.
  74. std::string generatedNameFromAddress(const IOAddress& addr) {
  75. std::string gen_name = addr.toText();
  76. std::replace(gen_name.begin(), gen_name.end(), '.', '-');
  77. std::ostringstream hostname;
  78. hostname << "host-" << gen_name;
  79. return (hostname.str());
  80. }
  81. // Get the Client FQDN Option from the given message.
  82. Option4ClientFqdnPtr getClientFqdnOption(const Pkt4Ptr& pkt) {
  83. return (boost::dynamic_pointer_cast<
  84. Option4ClientFqdn>(pkt->getOption(DHO_FQDN)));
  85. }
  86. // get the Hostname option from the given message.
  87. OptionCustomPtr getHostnameOption(const Pkt4Ptr& pkt) {
  88. return (boost::dynamic_pointer_cast<
  89. OptionCustom>(pkt->getOption(DHO_HOST_NAME)));
  90. }
  91. // Create a message holding DHCPv4 Client FQDN Option.
  92. Pkt4Ptr generatePktWithFqdn(const uint8_t msg_type,
  93. const uint8_t fqdn_flags,
  94. const std::string& fqdn_domain_name,
  95. Option4ClientFqdn::DomainNameType fqdn_type,
  96. const bool include_prl,
  97. const bool include_clientid = true) {
  98. Pkt4Ptr pkt = Pkt4Ptr(new Pkt4(msg_type, 1234));
  99. pkt->setRemoteAddr(IOAddress("192.0.2.3"));
  100. pkt->setIface("eth0");
  101. // For DISCOVER we don't include server id, because client broadcasts
  102. // the message to all servers.
  103. if (msg_type != DHCPDISCOVER) {
  104. pkt->addOption(srv_->getServerID());
  105. }
  106. if (include_clientid) {
  107. pkt->addOption(generateClientId());
  108. }
  109. // Create Client FQDN Option with the specified flags and
  110. // domain-name.
  111. pkt->addOption(createClientFqdn(fqdn_flags, fqdn_domain_name,
  112. fqdn_type));
  113. // Control whether or not to request that server returns the FQDN
  114. // option. Server may be configured to always return it or return
  115. // only in case client requested it.
  116. if (include_prl) {
  117. OptionUint8ArrayPtr option_prl =
  118. OptionUint8ArrayPtr(new OptionUint8Array(Option::V4,
  119. DHO_DHCP_PARAMETER_REQUEST_LIST));
  120. option_prl->addValue(DHO_FQDN);
  121. }
  122. return (pkt);
  123. }
  124. // Create a message holding a Hostname option.
  125. Pkt4Ptr generatePktWithHostname(const uint8_t msg_type,
  126. const std::string& hostname) {
  127. Pkt4Ptr pkt = Pkt4Ptr(new Pkt4(msg_type, 1234));
  128. pkt->setRemoteAddr(IOAddress("192.0.2.3"));
  129. // For DISCOVER we don't include server id, because client broadcasts
  130. // the message to all servers.
  131. if (msg_type != DHCPDISCOVER) {
  132. pkt->addOption(srv_->getServerID());
  133. }
  134. pkt->addOption(generateClientId());
  135. // Create Client FQDN Option with the specified flags and
  136. // domain-name.
  137. pkt->addOption(createHostname(hostname));
  138. return (pkt);
  139. }
  140. // Test that server generates the appropriate FQDN option in response to
  141. // client's FQDN option.
  142. void testProcessFqdn(const Pkt4Ptr& query, const uint8_t exp_flags,
  143. const std::string& exp_domain_name,
  144. Option4ClientFqdn::DomainNameType
  145. exp_domain_type = Option4ClientFqdn::FULL) {
  146. ASSERT_TRUE(getClientFqdnOption(query));
  147. Pkt4Ptr answer;
  148. if (query->getType() == DHCPDISCOVER) {
  149. answer.reset(new Pkt4(DHCPOFFER, 1234));
  150. } else {
  151. answer.reset(new Pkt4(DHCPACK, 1234));
  152. }
  153. ASSERT_NO_THROW(srv_->processClientName(query, answer));
  154. Option4ClientFqdnPtr fqdn = getClientFqdnOption(answer);
  155. ASSERT_TRUE(fqdn);
  156. const bool flag_n = (exp_flags & Option4ClientFqdn::FLAG_N) != 0;
  157. const bool flag_s = (exp_flags & Option4ClientFqdn::FLAG_S) != 0;
  158. const bool flag_o = (exp_flags & Option4ClientFqdn::FLAG_O) != 0;
  159. const bool flag_e = (exp_flags & Option4ClientFqdn::FLAG_E) != 0;
  160. EXPECT_EQ(flag_n, fqdn->getFlag(Option4ClientFqdn::FLAG_N));
  161. EXPECT_EQ(flag_s, fqdn->getFlag(Option4ClientFqdn::FLAG_S));
  162. EXPECT_EQ(flag_o, fqdn->getFlag(Option4ClientFqdn::FLAG_O));
  163. EXPECT_EQ(flag_e, fqdn->getFlag(Option4ClientFqdn::FLAG_E));
  164. EXPECT_EQ(exp_domain_name, fqdn->getDomainName());
  165. EXPECT_EQ(exp_domain_type, fqdn->getDomainNameType());
  166. }
  167. // Processes the Hostname option in the client's message and returns
  168. // the hostname option which would be sent to the client. It will
  169. // throw NULL pointer if the hostname option is not to be included
  170. // in the response.
  171. OptionCustomPtr processHostname(const Pkt4Ptr& query) {
  172. if (!getHostnameOption(query)) {
  173. ADD_FAILURE() << "Hostname option not carried in the query";
  174. }
  175. Pkt4Ptr answer;
  176. if (query->getType() == DHCPDISCOVER) {
  177. answer.reset(new Pkt4(DHCPOFFER, 1234));
  178. } else {
  179. answer.reset(new Pkt4(DHCPACK, 1234));
  180. }
  181. srv_->processClientName(query, answer);
  182. OptionCustomPtr hostname = getHostnameOption(answer);
  183. return (hostname);
  184. }
  185. // Test that the client message holding an FQDN is processed and the
  186. // NameChangeRequests are generated.
  187. void testProcessMessageWithFqdn(const uint8_t msg_type,
  188. const std::string& hostname) {
  189. Pkt4Ptr req = generatePktWithFqdn(msg_type, Option4ClientFqdn::FLAG_S |
  190. Option4ClientFqdn::FLAG_E, hostname,
  191. Option4ClientFqdn::FULL, true);
  192. Pkt4Ptr reply;
  193. if (msg_type == DHCPDISCOVER) {
  194. ASSERT_NO_THROW(reply = srv_->processDiscover(req));
  195. } else if (msg_type == DHCPREQUEST) {
  196. ASSERT_NO_THROW(reply = srv_->processRequest(req));
  197. } else if (msg_type == DHCPRELEASE) {
  198. ASSERT_NO_THROW(srv_->processRelease(req));
  199. return;
  200. } else {
  201. return;
  202. }
  203. if (msg_type == DHCPDISCOVER) {
  204. checkResponse(reply, DHCPOFFER, 1234);
  205. } else {
  206. checkResponse(reply, DHCPACK, 1234);
  207. }
  208. }
  209. // Verify that NameChangeRequest holds valid values.
  210. void verifyNameChangeRequest(const isc::dhcp_ddns::NameChangeType type,
  211. const bool reverse, const bool forward,
  212. const std::string& addr,
  213. const std::string& fqdn,
  214. const std::string& dhcid,
  215. const time_t cltt,
  216. const uint16_t len,
  217. const bool not_strict_expire_check = false) {
  218. NameChangeRequest ncr = srv_->name_change_reqs_.front();
  219. EXPECT_EQ(type, ncr.getChangeType());
  220. EXPECT_EQ(forward, ncr.isForwardChange());
  221. EXPECT_EQ(reverse, ncr.isReverseChange());
  222. EXPECT_EQ(addr, ncr.getIpAddress());
  223. EXPECT_EQ(fqdn, ncr.getFqdn());
  224. // Compare dhcid if it is not empty. In some cases, the DHCID is
  225. // not known in advance and can't be compared.
  226. if (!dhcid.empty()) {
  227. EXPECT_EQ(dhcid, ncr.getDhcid().toStr());
  228. }
  229. // In some cases, the test doesn't have access to the last transmission
  230. // time for the particular client. In such cases, the test can use the
  231. // current time as cltt but the it may not check the lease expiration time
  232. // for equality but rather check that the lease expiration time is not
  233. // greater than the current time + lease lifetime.
  234. if (not_strict_expire_check) {
  235. EXPECT_GE(cltt + len, ncr.getLeaseExpiresOn());
  236. } else {
  237. EXPECT_EQ(cltt + len, ncr.getLeaseExpiresOn());
  238. }
  239. EXPECT_EQ(len, ncr.getLeaseLength());
  240. EXPECT_EQ(isc::dhcp_ddns::ST_NEW, ncr.getStatus());
  241. srv_->name_change_reqs_.pop();
  242. }
  243. NakedDhcpv4Srv* srv_;
  244. };
  245. // Test that the exception is thrown if lease pointer specified as the argument
  246. // of computeDhcid function is NULL.
  247. TEST_F(NameDhcpv4SrvTest, dhcidNullLease) {
  248. Lease4Ptr lease;
  249. EXPECT_THROW(srv_->computeDhcid(lease), isc::dhcp::DhcidComputeError);
  250. }
  251. // Test that the appropriate exception is thrown if the lease object used
  252. // to compute DHCID comprises wrong hostname.
  253. TEST_F(NameDhcpv4SrvTest, dhcidWrongHostname) {
  254. // First, make sure that the lease with the correct hostname is accepted.
  255. Lease4Ptr lease = createLease(IOAddress("192.0.2.3"),
  256. "myhost.example.com.", true, true);
  257. ASSERT_NO_THROW(srv_->computeDhcid(lease));
  258. // Now, use the wrong hostname. It should result in the exception.
  259. lease->hostname_ = "myhost...example.com.";
  260. EXPECT_THROW(srv_->computeDhcid(lease), isc::dhcp::DhcidComputeError);
  261. // Also, empty hostname is wrong.
  262. lease->hostname_ = "";
  263. EXPECT_THROW(srv_->computeDhcid(lease), isc::dhcp::DhcidComputeError);
  264. }
  265. // Test that the DHCID is computed correctly, when the lease holds
  266. // correct hostname and non-NULL client id.
  267. TEST_F(NameDhcpv4SrvTest, dhcidComputeFromClientId) {
  268. Lease4Ptr lease = createLease(IOAddress("192.0.2.3"),
  269. "myhost.example.com.",
  270. true, true);
  271. isc::dhcp_ddns::D2Dhcid dhcid;
  272. ASSERT_NO_THROW(dhcid = srv_->computeDhcid(lease));
  273. // Make sure that the computed DHCID is valid.
  274. std::string dhcid_ref = "00010132E91AA355CFBB753C0F0497A5A9404"
  275. "36965B68B6D438D98E680BF10B09F3BCF";
  276. EXPECT_EQ(dhcid_ref, dhcid.toStr());
  277. }
  278. // Test that the DHCID is computed correctly, when the lease holds correct
  279. // hostname and NULL client id.
  280. TEST_F(NameDhcpv4SrvTest, dhcidComputeFromHWAddr) {
  281. Lease4Ptr lease = createLease(IOAddress("192.0.2.3"),
  282. "myhost.example.com.",
  283. true, true);
  284. lease->client_id_.reset();
  285. isc::dhcp_ddns::D2Dhcid dhcid;
  286. ASSERT_NO_THROW(dhcid = srv_->computeDhcid(lease));
  287. // Make sure that the computed DHCID is valid.
  288. std::string dhcid_ref = "0000012247F6DC4423C3E8627434A9D6868609"
  289. "D88948F78018B215EDCAA30C0C135035";
  290. EXPECT_EQ(dhcid_ref, dhcid.toStr());
  291. }
  292. // Test that server confirms to perform the forward and reverse DNS update,
  293. // when client asks for it.
  294. TEST_F(NameDhcpv4SrvTest, serverUpdateForwardFqdn) {
  295. Pkt4Ptr query = generatePktWithFqdn(DHCPREQUEST,
  296. Option4ClientFqdn::FLAG_E |
  297. Option4ClientFqdn::FLAG_S,
  298. "myhost.example.com.",
  299. Option4ClientFqdn::FULL,
  300. true);
  301. testProcessFqdn(query,
  302. Option4ClientFqdn::FLAG_E | Option4ClientFqdn::FLAG_S,
  303. "myhost.example.com.");
  304. }
  305. // Test that server processes the Hostname option sent by a client and
  306. // responds with the Hostname option to confirm that the server has
  307. // taken responsibility for the update.
  308. TEST_F(NameDhcpv4SrvTest, serverUpdateHostname) {
  309. Pkt4Ptr query;
  310. ASSERT_NO_THROW(query = generatePktWithHostname(DHCPREQUEST,
  311. "myhost.example.com."));
  312. OptionCustomPtr hostname;
  313. ASSERT_NO_THROW(hostname = processHostname(query));
  314. ASSERT_TRUE(hostname);
  315. EXPECT_EQ("myhost.example.com.", hostname->readString());
  316. }
  317. // Test that the server skips processing of the empty Hostname option.
  318. TEST_F(NameDhcpv4SrvTest, serverUpdateEmptyHostname) {
  319. Pkt4Ptr query;
  320. ASSERT_NO_THROW(query = generatePktWithHostname(DHCPREQUEST, ""));
  321. OptionCustomPtr hostname;
  322. ASSERT_NO_THROW(hostname = processHostname(query));
  323. EXPECT_FALSE(hostname);
  324. }
  325. // Test that the server skips processing of a wrong Hostname option.
  326. TEST_F(NameDhcpv4SrvTest, serverUpdateWrongHostname) {
  327. Pkt4Ptr query;
  328. ASSERT_NO_THROW(query = generatePktWithHostname(DHCPREQUEST,
  329. "abc..example.com"));
  330. OptionCustomPtr hostname;
  331. ASSERT_NO_THROW(hostname = processHostname(query));
  332. EXPECT_FALSE(hostname);
  333. }
  334. // Test that server generates the fully qualified domain name for the client
  335. // if client supplies the partial name.
  336. TEST_F(NameDhcpv4SrvTest, serverUpdateForwardPartialNameFqdn) {
  337. Pkt4Ptr query = generatePktWithFqdn(DHCPREQUEST,
  338. Option4ClientFqdn::FLAG_E |
  339. Option4ClientFqdn::FLAG_S,
  340. "myhost",
  341. Option4ClientFqdn::PARTIAL,
  342. true);
  343. testProcessFqdn(query,
  344. Option4ClientFqdn::FLAG_E | Option4ClientFqdn::FLAG_S,
  345. "myhost.example.com.");
  346. }
  347. // Test that server generates the fully qualified domain name for the client
  348. // if client supplies the unqualified name in the Hostname option.
  349. TEST_F(NameDhcpv4SrvTest, serverUpdateUnqualifiedHostname) {
  350. Pkt4Ptr query;
  351. ASSERT_NO_THROW(query = generatePktWithHostname(DHCPREQUEST, "myhost"));
  352. OptionCustomPtr hostname;
  353. ASSERT_NO_THROW(hostname = processHostname(query));
  354. ASSERT_TRUE(hostname);
  355. EXPECT_EQ("myhost.example.com.", hostname->readString());
  356. }
  357. // Test that server sets empty domain-name in the FQDN option when client
  358. // supplied no domain-name. The domain-name is supposed to be set after the
  359. // lease is acquired. The domain-name is then generated from the IP address
  360. // assigned to a client.
  361. TEST_F(NameDhcpv4SrvTest, serverUpdateForwardNoNameFqdn) {
  362. Pkt4Ptr query = generatePktWithFqdn(DHCPREQUEST,
  363. Option4ClientFqdn::FLAG_E |
  364. Option4ClientFqdn::FLAG_S,
  365. "",
  366. Option4ClientFqdn::PARTIAL,
  367. true);
  368. testProcessFqdn(query,
  369. Option4ClientFqdn::FLAG_E | Option4ClientFqdn::FLAG_S,
  370. "", Option4ClientFqdn::PARTIAL);
  371. }
  372. // Test server's response when client requests no DNS update.
  373. TEST_F(NameDhcpv4SrvTest, noUpdateFqdn) {
  374. Pkt4Ptr query = generatePktWithFqdn(DHCPREQUEST,
  375. Option4ClientFqdn::FLAG_E |
  376. Option4ClientFqdn::FLAG_N,
  377. "myhost.example.com.",
  378. Option4ClientFqdn::FULL,
  379. true);
  380. testProcessFqdn(query, Option4ClientFqdn::FLAG_E |
  381. Option4ClientFqdn::FLAG_N,
  382. "myhost.example.com.");
  383. }
  384. // Test that server does not accept delegation of the forward DNS update
  385. // to a client.
  386. TEST_F(NameDhcpv4SrvTest, clientUpdateNotAllowedFqdn) {
  387. Pkt4Ptr query = generatePktWithFqdn(DHCPREQUEST,
  388. Option4ClientFqdn::FLAG_E,
  389. "myhost.example.com.",
  390. Option4ClientFqdn::FULL,
  391. true);
  392. testProcessFqdn(query, Option4ClientFqdn::FLAG_E |
  393. Option4ClientFqdn::FLAG_S | Option4ClientFqdn::FLAG_O,
  394. "myhost.example.com.");
  395. }
  396. // Test that exactly one NameChangeRequest is generated when the new lease
  397. // has been acquired (old lease is NULL).
  398. TEST_F(NameDhcpv4SrvTest, createNameChangeRequestsNewLease) {
  399. Lease4Ptr lease = createLease(IOAddress("192.0.2.3"), "myhost.example.com.",
  400. true, true);
  401. Lease4Ptr old_lease;
  402. ASSERT_NO_THROW(srv_->createNameChangeRequests(lease, old_lease));
  403. ASSERT_EQ(1, srv_->name_change_reqs_.size());
  404. verifyNameChangeRequest(isc::dhcp_ddns::CHG_ADD, true, true,
  405. "192.0.2.3", "myhost.example.com.",
  406. "00010132E91AA355CFBB753C0F0497A5A940436965"
  407. "B68B6D438D98E680BF10B09F3BCF",
  408. lease->cltt_, 100);
  409. }
  410. // Test that no NameChangeRequest is generated when a lease is renewed and
  411. // the FQDN data hasn't changed.
  412. TEST_F(NameDhcpv4SrvTest, createNameChangeRequestsRenewNoChange) {
  413. Lease4Ptr lease = createLease(IOAddress("192.0.2.3"), "myhost.example.com.",
  414. true, true);
  415. Lease4Ptr old_lease = createLease(IOAddress("192.0.2.3"),
  416. "myhost.example.com.", true, true);
  417. old_lease->valid_lft_ += 100;
  418. ASSERT_NO_THROW(srv_->createNameChangeRequests(lease, old_lease));
  419. EXPECT_TRUE(srv_->name_change_reqs_.empty());
  420. }
  421. // Test that no NameChangeRequest is generated when forward and reverse
  422. // DNS update flags are not set in the lease.
  423. TEST_F(NameDhcpv4SrvTest, createNameChangeRequestsNoUpdate) {
  424. Lease4Ptr lease1 = createLease(IOAddress("192.0.2.3"),
  425. "lease1.example.com.",
  426. true, true);
  427. Lease4Ptr lease2 = createLease(IOAddress("192.0.2.3"),
  428. "lease2.example.com.",
  429. false, false);
  430. ASSERT_NO_THROW(srv_->createNameChangeRequests(lease2, lease1));
  431. EXPECT_EQ(1, srv_->name_change_reqs_.size());
  432. verifyNameChangeRequest(isc::dhcp_ddns::CHG_REMOVE, true, true,
  433. "192.0.2.3", "lease1.example.com.",
  434. "0001013A5B311F5B9FB10DDF8E53689B874F25D"
  435. "62CC147C2FF237A64C90E5A597C9B7A",
  436. lease1->cltt_, 100);
  437. lease2->hostname_ = "";
  438. lease2->fqdn_rev_ = true;
  439. lease2->fqdn_fwd_ = true;
  440. ASSERT_NO_THROW(srv_->createNameChangeRequests(lease2, lease1));
  441. EXPECT_EQ(1, srv_->name_change_reqs_.size());
  442. }
  443. // Test that two NameChangeRequests are generated when the lease is being
  444. // renewed and the new lease has updated FQDN data.
  445. TEST_F(NameDhcpv4SrvTest, createNameChangeRequestsRenew) {
  446. Lease4Ptr lease1 = createLease(IOAddress("192.0.2.3"),
  447. "lease1.example.com.",
  448. true, true);
  449. Lease4Ptr lease2 = createLease(IOAddress("192.0.2.3"),
  450. "lease2.example.com.",
  451. true, true);
  452. ASSERT_NO_THROW(srv_->createNameChangeRequests(lease2, lease1));
  453. ASSERT_EQ(2, srv_->name_change_reqs_.size());
  454. verifyNameChangeRequest(isc::dhcp_ddns::CHG_REMOVE, true, true,
  455. "192.0.2.3", "lease1.example.com.",
  456. "0001013A5B311F5B9FB10DDF8E53689B874F25D"
  457. "62CC147C2FF237A64C90E5A597C9B7A",
  458. lease1->cltt_, 100);
  459. verifyNameChangeRequest(isc::dhcp_ddns::CHG_ADD, true, true,
  460. "192.0.2.3", "lease2.example.com.",
  461. "000101F906D2BB752E1B2EECC5FF2BF434C0B2D"
  462. "D6D7F7BD873F4F280165DB8C9DBA7CB",
  463. lease2->cltt_, 100);
  464. }
  465. // This test verifies that exception is thrown when leases passed to the
  466. // createNameChangeRequests function do not match, i.e. they comprise
  467. // different IP addresses, client ids etc.
  468. TEST_F(NameDhcpv4SrvTest, createNameChangeRequestsLeaseMismatch) {
  469. Lease4Ptr lease1 = createLease(IOAddress("192.0.2.3"),
  470. "lease1.example.com.",
  471. true, true);
  472. Lease4Ptr lease2 = createLease(IOAddress("192.0.2.4"),
  473. "lease2.example.com.",
  474. true, true);
  475. EXPECT_THROW(srv_->createNameChangeRequests(lease2, lease1),
  476. isc::Unexpected);
  477. }
  478. // Test that the OFFER message generated as a result of the DISCOVER message
  479. // processing will not result in generation of the NameChangeRequests.
  480. TEST_F(NameDhcpv4SrvTest, processDiscover) {
  481. Pkt4Ptr req = generatePktWithFqdn(DHCPDISCOVER, Option4ClientFqdn::FLAG_S |
  482. Option4ClientFqdn::FLAG_E,
  483. "myhost.example.com.",
  484. Option4ClientFqdn::FULL, true);
  485. Pkt4Ptr reply;
  486. ASSERT_NO_THROW(reply = srv_->processDiscover(req));
  487. checkResponse(reply, DHCPOFFER, 1234);
  488. EXPECT_TRUE(srv_->name_change_reqs_.empty());
  489. }
  490. // Test that server generates client's hostname from the IP address assigned
  491. // to it when DHCPv4 Client FQDN option specifies an empty domain-name.
  492. TEST_F(NameDhcpv4SrvTest, processRequestFqdnEmptyDomainName) {
  493. Pkt4Ptr req = generatePktWithFqdn(DHCPREQUEST, Option4ClientFqdn::FLAG_S |
  494. Option4ClientFqdn::FLAG_E,
  495. "", Option4ClientFqdn::PARTIAL, true);
  496. Pkt4Ptr reply;
  497. ASSERT_NO_THROW(reply = srv_->processRequest(req));
  498. checkResponse(reply, DHCPACK, 1234);
  499. // Verify that there is one NameChangeRequest generated.
  500. ASSERT_EQ(1, srv_->name_change_reqs_.size());
  501. // The hostname is generated from the IP address acquired (yiaddr).
  502. std::ostringstream hostname;
  503. hostname << generatedNameFromAddress(reply->getYiaddr())
  504. << ".example.com.";
  505. verifyNameChangeRequest(isc::dhcp_ddns::CHG_ADD, true, true,
  506. reply->getYiaddr().toText(), hostname.str(),
  507. "", // empty DHCID forces that it is not checked
  508. time(NULL) + subnet_->getValid(),
  509. subnet_->getValid(), true);
  510. }
  511. // Test that server generates client's hostname from the IP address assigned
  512. // to it when Hostname option carries the top level domain-name.
  513. TEST_F(NameDhcpv4SrvTest, processRequestEmptyHostname) {
  514. Pkt4Ptr req = generatePktWithHostname(DHCPREQUEST, ".");
  515. // Set interface for the incoming packet. The server requires it to
  516. // generate client id.
  517. req->setIface("eth0");
  518. Pkt4Ptr reply;
  519. ASSERT_NO_THROW(reply = srv_->processRequest(req));
  520. checkResponse(reply, DHCPACK, 1234);
  521. // Verify that there is one NameChangeRequest generated.
  522. ASSERT_EQ(1, srv_->name_change_reqs_.size());
  523. // The hostname is generated from the IP address acquired (yiaddr).
  524. std::ostringstream hostname;
  525. hostname << generatedNameFromAddress(reply->getYiaddr()) << ".example.com.";
  526. verifyNameChangeRequest(isc::dhcp_ddns::CHG_ADD, true, true,
  527. reply->getYiaddr().toText(), hostname.str(),
  528. "", // empty DHCID forces that it is not checked
  529. time(NULL), subnet_->getValid(), true);
  530. }
  531. // Test that client may send two requests, each carrying FQDN option with
  532. // a different domain-name. Server should use existing lease for the second
  533. // request but modify the DNS entries for the lease according to the contents
  534. // of the FQDN sent in the second request.
  535. TEST_F(NameDhcpv4SrvTest, processTwoRequestsFqdn) {
  536. Pkt4Ptr req1 = generatePktWithFqdn(DHCPREQUEST, Option4ClientFqdn::FLAG_S |
  537. Option4ClientFqdn::FLAG_E,
  538. "myhost.example.com.",
  539. Option4ClientFqdn::FULL, true);
  540. Pkt4Ptr reply;
  541. ASSERT_NO_THROW(reply = srv_->processRequest(req1));
  542. checkResponse(reply, DHCPACK, 1234);
  543. // Verify that there is one NameChangeRequest generated.
  544. ASSERT_EQ(1, srv_->name_change_reqs_.size());
  545. verifyNameChangeRequest(isc::dhcp_ddns::CHG_ADD, true, true,
  546. reply->getYiaddr().toText(), "myhost.example.com.",
  547. "00010132E91AA355CFBB753C0F0497A5A940436"
  548. "965B68B6D438D98E680BF10B09F3BCF",
  549. time(NULL), subnet_->getValid(), true);
  550. // Create another Request message but with a different FQDN. Server
  551. // should generate two NameChangeRequests: one to remove existing entry,
  552. // another one to add new entry with updated domain-name.
  553. Pkt4Ptr req2 = generatePktWithFqdn(DHCPREQUEST, Option4ClientFqdn::FLAG_S |
  554. Option4ClientFqdn::FLAG_E,
  555. "otherhost.example.com.",
  556. Option4ClientFqdn::FULL, true);
  557. ASSERT_NO_THROW(reply = srv_->processRequest(req2));
  558. checkResponse(reply, DHCPACK, 1234);
  559. // There should be two NameChangeRequests. Verify that they are valid.
  560. ASSERT_EQ(2, srv_->name_change_reqs_.size());
  561. verifyNameChangeRequest(isc::dhcp_ddns::CHG_REMOVE, true, true,
  562. reply->getYiaddr().toText(),
  563. "myhost.example.com.",
  564. "00010132E91AA355CFBB753C0F0497A5A940436"
  565. "965B68B6D438D98E680BF10B09F3BCF",
  566. time(NULL), subnet_->getValid(), true);
  567. verifyNameChangeRequest(isc::dhcp_ddns::CHG_ADD, true, true,
  568. reply->getYiaddr().toText(),
  569. "otherhost.example.com.",
  570. "000101A5AEEA7498BD5AD9D3BF600E49FF39A7E3"
  571. "AFDCE8C3D0E53F35CC584DD63C89CA",
  572. time(NULL), subnet_->getValid(), true);
  573. }
  574. // Test that client may send two requests, each carrying Hostname option with
  575. // a different name. Server should use existing lease for the second request
  576. // but modify the DNS entries for the lease according to the contents of the
  577. // Hostname sent in the second request.
  578. TEST_F(NameDhcpv4SrvTest, processTwoRequestsHostname) {
  579. Pkt4Ptr req1 = generatePktWithHostname(DHCPREQUEST, "myhost.example.com.");
  580. // Set interface for the incoming packet. The server requires it to
  581. // generate client id.
  582. req1->setIface("eth0");
  583. Pkt4Ptr reply;
  584. ASSERT_NO_THROW(reply = srv_->processRequest(req1));
  585. checkResponse(reply, DHCPACK, 1234);
  586. // Verify that there is one NameChangeRequest generated.
  587. ASSERT_EQ(1, srv_->name_change_reqs_.size());
  588. verifyNameChangeRequest(isc::dhcp_ddns::CHG_ADD, true, true,
  589. reply->getYiaddr().toText(), "myhost.example.com.",
  590. "00010132E91AA355CFBB753C0F0497A5A940436"
  591. "965B68B6D438D98E680BF10B09F3BCF",
  592. time(NULL), subnet_->getValid(), true);
  593. // Create another Request message but with a different Hostname. Server
  594. // should generate two NameChangeRequests: one to remove existing entry,
  595. // another one to add new entry with updated domain-name.
  596. Pkt4Ptr req2 = generatePktWithHostname(DHCPREQUEST, "otherhost");
  597. // Set interface for the incoming packet. The server requires it to
  598. // generate client id.
  599. req2->setIface("eth0");
  600. ASSERT_NO_THROW(reply = srv_->processRequest(req2));
  601. checkResponse(reply, DHCPACK, 1234);
  602. // There should be two NameChangeRequests. Verify that they are valid.
  603. ASSERT_EQ(2, srv_->name_change_reqs_.size());
  604. verifyNameChangeRequest(isc::dhcp_ddns::CHG_REMOVE, true, true,
  605. reply->getYiaddr().toText(),
  606. "myhost.example.com.",
  607. "00010132E91AA355CFBB753C0F0497A5A940436"
  608. "965B68B6D438D98E680BF10B09F3BCF",
  609. time(NULL), subnet_->getValid(), true);
  610. verifyNameChangeRequest(isc::dhcp_ddns::CHG_ADD, true, true,
  611. reply->getYiaddr().toText(),
  612. "otherhost.example.com.",
  613. "000101A5AEEA7498BD5AD9D3BF600E49FF39A7E3"
  614. "AFDCE8C3D0E53F35CC584DD63C89CA",
  615. time(NULL), subnet_->getValid(), true);
  616. }
  617. // Test that when the Release message is sent for the previously acquired
  618. // lease, then server genenerates a NameChangeRequest to remove the entries
  619. // corresponding to the lease being released.
  620. TEST_F(NameDhcpv4SrvTest, processRequestRelease) {
  621. Pkt4Ptr req = generatePktWithFqdn(DHCPREQUEST, Option4ClientFqdn::FLAG_S |
  622. Option4ClientFqdn::FLAG_E,
  623. "myhost.example.com.",
  624. Option4ClientFqdn::FULL, true);
  625. Pkt4Ptr reply;
  626. ASSERT_NO_THROW(reply = srv_->processRequest(req));
  627. checkResponse(reply, DHCPACK, 1234);
  628. // Verify that there is one NameChangeRequest generated.
  629. ASSERT_EQ(1, srv_->name_change_reqs_.size());
  630. verifyNameChangeRequest(isc::dhcp_ddns::CHG_ADD, true, true,
  631. reply->getYiaddr().toText(), "myhost.example.com.",
  632. "00010132E91AA355CFBB753C0F0497A5A940436"
  633. "965B68B6D438D98E680BF10B09F3BCF",
  634. time(NULL), subnet_->getValid(), true);
  635. // Create a Release message.
  636. Pkt4Ptr rel = Pkt4Ptr(new Pkt4(DHCPRELEASE, 1234));
  637. rel->setCiaddr(reply->getYiaddr());
  638. rel->setRemoteAddr(IOAddress("192.0.2.3"));
  639. rel->addOption(generateClientId());
  640. rel->addOption(srv_->getServerID());
  641. ASSERT_NO_THROW(srv_->processRelease(rel));
  642. // The lease has been removed, so there should be a NameChangeRequest to
  643. // remove corresponding DNS entries.
  644. ASSERT_EQ(1, srv_->name_change_reqs_.size());
  645. }
  646. } // end of anonymous namespace