fqdn_unittest.cc 64 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575
  1. // Copyright (C) 2013-2017 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this
  5. // file, You can obtain one at http://mozilla.org/MPL/2.0/.
  6. #include <config.h>
  7. #include <asiolink/io_address.h>
  8. #include <dhcp/option4_client_fqdn.h>
  9. #include <dhcp/option_int_array.h>
  10. #include <dhcp/tests/iface_mgr_test_config.h>
  11. #include <dhcp4/tests/dhcp4_client.h>
  12. #include <dhcp4/tests/dhcp4_test_utils.h>
  13. #include <dhcp_ddns/ncr_msg.h>
  14. #include <dhcpsrv/cfgmgr.h>
  15. #include <dhcpsrv/lease_mgr.h>
  16. #include <dhcpsrv/lease_mgr_factory.h>
  17. #include <gtest/gtest.h>
  18. #include <boost/scoped_ptr.hpp>
  19. using namespace isc;
  20. using namespace isc::asiolink;
  21. using namespace isc::dhcp;
  22. using namespace isc::dhcp::test;
  23. using namespace isc::dhcp_ddns;
  24. namespace {
  25. /// @brief Set of JSON configurations used by the FQDN tests.
  26. const char* CONFIGS[] = {
  27. "{ \"interfaces-config\": {"
  28. " \"interfaces\": [ \"*\" ]"
  29. "},"
  30. "\"valid-lifetime\": 3000,"
  31. "\"subnet4\": [ { "
  32. " \"subnet\": \"10.0.0.0/24\", "
  33. " \"id\": 1,"
  34. " \"pools\": [ { \"pool\": \"10.0.0.10-10.0.0.100\" } ],"
  35. " \"option-data\": [ {"
  36. " \"name\": \"routers\","
  37. " \"data\": \"10.0.0.200,10.0.0.201\""
  38. " } ],"
  39. " \"reservations\": ["
  40. " {"
  41. " \"hw-address\": \"aa:bb:cc:dd:ee:ff\","
  42. " \"hostname\": \"unique-host.example.org\""
  43. " }"
  44. " ]"
  45. " }],"
  46. "\"dhcp-ddns\": {"
  47. "\"enable-updates\": true,"
  48. "\"qualifying-suffix\": \"\""
  49. "}"
  50. "}",
  51. "{ \"interfaces-config\": {"
  52. " \"interfaces\": [ \"*\" ]"
  53. "},"
  54. "\"valid-lifetime\": 3000,"
  55. "\"subnet4\": [ { "
  56. " \"subnet\": \"10.0.0.0/24\", "
  57. " \"id\": 1,"
  58. " \"pools\": [ { \"pool\": \"10.0.0.10-10.0.0.100\" } ],"
  59. " \"option-data\": [ {"
  60. " \"name\": \"routers\","
  61. " \"data\": \"10.0.0.200,10.0.0.201\""
  62. " } ],"
  63. " \"reservations\": ["
  64. " {"
  65. " \"hw-address\": \"aa:bb:cc:dd:ee:ff\","
  66. " \"hostname\": \"foobar\""
  67. " }"
  68. " ]"
  69. " }],"
  70. "\"dhcp-ddns\": {"
  71. "\"enable-updates\": true,"
  72. "\"qualifying-suffix\": \"fake-suffix.isc.org.\""
  73. "}"
  74. "}",
  75. // Simple config with DDNS updates disabled. Note pool is one address
  76. // large to ensure we get a specific address back.
  77. "{ \"interfaces-config\": {"
  78. " \"interfaces\": [ \"*\" ]"
  79. "},"
  80. "\"valid-lifetime\": 3000,"
  81. "\"subnet4\": [ { "
  82. " \"subnet\": \"10.0.0.0/24\", "
  83. " \"id\": 1,"
  84. " \"pools\": [ { \"pool\": \"10.0.0.10-10.0.0.10\" } ]"
  85. " }],"
  86. "\"dhcp-ddns\": {"
  87. "\"enable-updates\": false,"
  88. "\"qualifying-suffix\": \"fake-suffix.isc.org.\""
  89. "}"
  90. "}",
  91. // Simple config with DDNS updates enabled. Note pool is one address
  92. // large to ensure we get a specific address back.
  93. "{ \"interfaces-config\": {"
  94. " \"interfaces\": [ \"*\" ]"
  95. "},"
  96. "\"valid-lifetime\": 3000,"
  97. "\"subnet4\": [ { "
  98. " \"subnet\": \"10.0.0.0/24\", "
  99. " \"id\": 1,"
  100. " \"pools\": [ { \"pool\": \"10.0.0.10-10.0.0.10\" } ]"
  101. " }],"
  102. "\"dhcp-ddns\": {"
  103. "\"enable-updates\": true,"
  104. "\"qualifying-suffix\": \"fake-suffix.isc.org.\""
  105. "}"
  106. "}",
  107. // Configuration which disables DNS updates but contains a reservation
  108. // for a hostname. Reserved hostname should be assigned to a client if
  109. // the client includes it in the Parameter Request List option.
  110. "{ \"interfaces-config\": {"
  111. " \"interfaces\": [ \"*\" ]"
  112. "},"
  113. "\"valid-lifetime\": 3000,"
  114. "\"subnet4\": [ { "
  115. " \"subnet\": \"10.0.0.0/24\", "
  116. " \"id\": 1,"
  117. " \"pools\": [ { \"pool\": \"10.0.0.10-10.0.0.100\" } ],"
  118. " \"option-data\": [ {"
  119. " \"name\": \"routers\","
  120. " \"data\": \"10.0.0.200,10.0.0.201\""
  121. " } ],"
  122. " \"reservations\": ["
  123. " {"
  124. " \"hw-address\": \"aa:bb:cc:dd:ee:ff\","
  125. " \"hostname\": \"reserved.example.org\""
  126. " }"
  127. " ]"
  128. " }],"
  129. "\"dhcp-ddns\": {"
  130. "\"enable-updates\": false,"
  131. "\"qualifying-suffix\": \"\""
  132. "}"
  133. "}",
  134. // Configuration which disables DNS updates but contains a reservation
  135. // for a hostname and the qualifying-suffix which should be appended to
  136. // the reserved hostname in the Hostname option returned to a client.
  137. "{ \"interfaces-config\": {"
  138. " \"interfaces\": [ \"*\" ]"
  139. "},"
  140. "\"valid-lifetime\": 3000,"
  141. "\"subnet4\": [ { "
  142. " \"subnet\": \"10.0.0.0/24\", "
  143. " \"id\": 1,"
  144. " \"pools\": [ { \"pool\": \"10.0.0.10-10.0.0.100\" } ],"
  145. " \"option-data\": [ {"
  146. " \"name\": \"routers\","
  147. " \"data\": \"10.0.0.200,10.0.0.201\""
  148. " } ],"
  149. " \"reservations\": ["
  150. " {"
  151. " \"hw-address\": \"aa:bb:cc:dd:ee:ff\","
  152. " \"hostname\": \"foo-bar\""
  153. " }"
  154. " ]"
  155. " }],"
  156. "\"dhcp-ddns\": {"
  157. "\"enable-updates\": false,"
  158. "\"qualifying-suffix\": \"example.isc.org\""
  159. "}"
  160. "}"
  161. };
  162. class NameDhcpv4SrvTest : public Dhcpv4SrvTest {
  163. public:
  164. // Reference to D2ClientMgr singleton
  165. D2ClientMgr& d2_mgr_;
  166. /// @brief Pointer to the DHCP server instance.
  167. NakedDhcpv4Srv* srv_;
  168. /// @brief Interface Manager's fake configuration control.
  169. IfaceMgrTestConfig iface_mgr_test_config_;
  170. // Bit Constants for turning on and off DDNS configuration options.
  171. static const uint16_t ALWAYS_INCLUDE_FQDN = 1;
  172. static const uint16_t OVERRIDE_NO_UPDATE = 2;
  173. static const uint16_t OVERRIDE_CLIENT_UPDATE = 4;
  174. static const uint16_t REPLACE_CLIENT_NAME = 8;
  175. // Enum used to specify whether a client (packet) should include
  176. // the hostname option
  177. enum ClientNameFlag {
  178. CLIENT_NAME_PRESENT,
  179. CLIENT_NAME_NOT_PRESENT
  180. };
  181. // Enum used to specify whether the server should replace/supply
  182. // the hostname or not
  183. enum ReplacementFlag {
  184. NAME_REPLACED,
  185. NAME_NOT_REPLACED
  186. };
  187. NameDhcpv4SrvTest()
  188. : Dhcpv4SrvTest(),
  189. d2_mgr_(CfgMgr::instance().getD2ClientMgr()),
  190. srv_(NULL),
  191. iface_mgr_test_config_(true)
  192. {
  193. srv_ = new NakedDhcpv4Srv(0);
  194. IfaceMgr::instance().openSockets4();
  195. // Config DDNS to be enabled, all controls off
  196. enableD2();
  197. }
  198. virtual ~NameDhcpv4SrvTest() {
  199. delete srv_;
  200. // CfgMgr singleton doesn't get wiped between tests, so we'll
  201. // disable D2 explicitly between tests.
  202. disableD2();
  203. }
  204. /// @brief Sets the server's DDNS configuration to ddns updates disabled.
  205. void disableD2() {
  206. // Default constructor creates a config with DHCP-DDNS updates
  207. // disabled.
  208. D2ClientConfigPtr cfg(new D2ClientConfig());
  209. CfgMgr::instance().setD2ClientConfig(cfg);
  210. }
  211. /// @brief Enables DHCP-DDNS updates with the given options enabled.
  212. ///
  213. /// Replaces the current D2ClientConfiguration with a configuration
  214. /// which as updates enabled and the control options set based upon
  215. /// the bit mask of options.
  216. ///
  217. /// @param mask Bit mask of configuration options that should be enabled.
  218. void enableD2(const uint16_t mask = 0) {
  219. D2ClientConfigPtr cfg;
  220. ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true,
  221. isc::asiolink::IOAddress("127.0.0.1"), 53001,
  222. isc::asiolink::IOAddress("0.0.0.0"), 0, 1024,
  223. dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
  224. (mask & ALWAYS_INCLUDE_FQDN),
  225. (mask & OVERRIDE_NO_UPDATE),
  226. (mask & OVERRIDE_CLIENT_UPDATE),
  227. ((mask & REPLACE_CLIENT_NAME) ?
  228. D2ClientConfig::RCM_WHEN_PRESENT
  229. : D2ClientConfig::RCM_NEVER),
  230. "myhost", "example.com")));
  231. ASSERT_NO_THROW(CfgMgr::instance().setD2ClientConfig(cfg));
  232. ASSERT_NO_THROW(srv_->startD2());
  233. }
  234. // Create a lease to be used by various tests.
  235. Lease4Ptr createLease(const isc::asiolink::IOAddress& addr,
  236. const std::string& hostname,
  237. const bool fqdn_fwd,
  238. const bool fqdn_rev) {
  239. const uint8_t hwaddr_data[] = { 0, 1, 2, 3, 4, 5, 6 };
  240. HWAddrPtr hwaddr(new HWAddr(hwaddr_data, sizeof(hwaddr_data),
  241. HTYPE_ETHER));
  242. Lease4Ptr lease(new Lease4(addr, hwaddr,
  243. &generateClientId()->getData()[0],
  244. generateClientId()->getData().size(),
  245. 100, 50, 75, time(NULL), subnet_->getID()));
  246. // @todo Set this through the Lease4 constructor.
  247. lease->hostname_ = hostname;
  248. lease->fqdn_fwd_ = fqdn_fwd;
  249. lease->fqdn_rev_ = fqdn_rev;
  250. return (lease);
  251. }
  252. // Create an instance of the DHCPv4 Client FQDN Option.
  253. Option4ClientFqdnPtr
  254. createClientFqdn(const uint8_t flags,
  255. const std::string& fqdn_name,
  256. Option4ClientFqdn::DomainNameType fqdn_type) {
  257. return (Option4ClientFqdnPtr(new Option4ClientFqdn(flags,
  258. Option4ClientFqdn::
  259. RCODE_CLIENT(),
  260. fqdn_name,
  261. fqdn_type)));
  262. }
  263. // Create an instance of the Hostname option.
  264. OptionStringPtr
  265. createHostname(const std::string& hostname) {
  266. OptionStringPtr opt_hostname(new OptionString(Option::V4,
  267. DHO_HOST_NAME,
  268. hostname));
  269. return (opt_hostname);
  270. }
  271. /// @brief Convenience method for generating an FQDN from an IP address.
  272. ///
  273. /// This is just a wrapper method around the D2ClientMgr's method for
  274. /// generating domain names from the configured prefix, suffix, and a
  275. /// given IP address. This is useful for verifying that fully generated
  276. /// names are correct.
  277. ///
  278. /// @param addr IP address used in the lease.
  279. /// @param trailing_dot A boolean flag which indicates whether the
  280. /// trailing dot should be appended to the end of the hostname.
  281. /// The default value is "true" which means that it should.
  282. ///
  283. /// @return An std::string contained the generated FQDN.
  284. std::string generatedNameFromAddress(const IOAddress& addr,
  285. const bool trailing_dot = true) {
  286. return(CfgMgr::instance().getD2ClientMgr()
  287. .generateFqdn(addr, trailing_dot));
  288. }
  289. // Get the Client FQDN Option from the given message.
  290. Option4ClientFqdnPtr getClientFqdnOption(const Pkt4Ptr& pkt) {
  291. return (boost::dynamic_pointer_cast<
  292. Option4ClientFqdn>(pkt->getOption(DHO_FQDN)));
  293. }
  294. // get the Hostname option from the given message.
  295. OptionStringPtr getHostnameOption(const Pkt4Ptr& pkt) {
  296. return (boost::dynamic_pointer_cast<
  297. OptionString>(pkt->getOption(DHO_HOST_NAME)));
  298. }
  299. // Create a message holding DHCPv4 Client FQDN Option.
  300. Pkt4Ptr generatePktWithFqdn(const uint8_t msg_type,
  301. const uint8_t fqdn_flags,
  302. const std::string& fqdn_domain_name,
  303. Option4ClientFqdn::DomainNameType fqdn_type,
  304. const bool include_prl,
  305. const bool include_clientid = true) {
  306. Pkt4Ptr pkt = Pkt4Ptr(new Pkt4(msg_type, 1234));
  307. pkt->setRemoteAddr(IOAddress("192.0.2.3"));
  308. pkt->setIface("eth1");
  309. // For DISCOVER we don't include server id, because client broadcasts
  310. // the message to all servers.
  311. if (msg_type != DHCPDISCOVER) {
  312. pkt->addOption(srv_->getServerID());
  313. }
  314. if (include_clientid) {
  315. pkt->addOption(generateClientId());
  316. }
  317. // Create Client FQDN Option with the specified flags and
  318. // domain-name.
  319. pkt->addOption(createClientFqdn(fqdn_flags, fqdn_domain_name,
  320. fqdn_type));
  321. // Control whether or not to request that server returns the FQDN
  322. // option. Server may be configured to always return it or return
  323. // only in case client requested it.
  324. if (include_prl) {
  325. OptionUint8ArrayPtr option_prl =
  326. OptionUint8ArrayPtr(new OptionUint8Array(Option::V4,
  327. DHO_DHCP_PARAMETER_REQUEST_LIST));
  328. option_prl->addValue(DHO_FQDN);
  329. }
  330. return (pkt);
  331. }
  332. // Create a message holding a Hostname option.
  333. Pkt4Ptr generatePktWithHostname(const uint8_t msg_type,
  334. const std::string& hostname) {
  335. Pkt4Ptr pkt = Pkt4Ptr(new Pkt4(msg_type, 1234));
  336. pkt->setRemoteAddr(IOAddress("192.0.2.3"));
  337. // For DISCOVER we don't include server id, because client broadcasts
  338. // the message to all servers.
  339. if (msg_type != DHCPDISCOVER) {
  340. pkt->addOption(srv_->getServerID());
  341. }
  342. pkt->addOption(generateClientId());
  343. // Create Client FQDN Option with the specified flags and
  344. // domain-name.
  345. pkt->addOption(createHostname(hostname));
  346. return (pkt);
  347. }
  348. // Create a message holding of a given type
  349. Pkt4Ptr generatePkt(const uint8_t msg_type) {
  350. Pkt4Ptr pkt = Pkt4Ptr(new Pkt4(msg_type, 1234));
  351. pkt->setRemoteAddr(IOAddress("192.0.2.3"));
  352. // For DISCOVER we don't include server id, because client broadcasts
  353. // the message to all servers.
  354. if (msg_type != DHCPDISCOVER) {
  355. pkt->addOption(srv_->getServerID());
  356. }
  357. pkt->addOption(generateClientId());
  358. return (pkt);
  359. }
  360. // Test that server generates the appropriate FQDN option in response to
  361. // client's FQDN option.
  362. void testProcessFqdn(const Pkt4Ptr& query, const uint8_t exp_flags,
  363. const std::string& exp_domain_name,
  364. Option4ClientFqdn::DomainNameType
  365. exp_domain_type = Option4ClientFqdn::FULL) {
  366. ASSERT_TRUE(getClientFqdnOption(query));
  367. Pkt4Ptr answer;
  368. if (query->getType() == DHCPDISCOVER) {
  369. answer.reset(new Pkt4(DHCPOFFER, 1234));
  370. } else {
  371. answer.reset(new Pkt4(DHCPACK, 1234));
  372. }
  373. Dhcpv4Exchange ex = createExchange(query);
  374. ASSERT_NO_THROW(srv_->processClientName(ex));
  375. Option4ClientFqdnPtr fqdn = getClientFqdnOption(ex.getResponse());
  376. ASSERT_TRUE(fqdn);
  377. checkFqdnFlags(ex.getResponse(), exp_flags);
  378. EXPECT_EQ(exp_domain_name, fqdn->getDomainName());
  379. EXPECT_EQ(exp_domain_type, fqdn->getDomainNameType());
  380. }
  381. // Test that the server's processes the hostname (or lack thereof)
  382. // in a client request correctly, according to the replace-client-name
  383. // mode configuration parameter.
  384. //
  385. // @param mode - value to use client-name-replacment parameter - for
  386. // mode labels such as NEVER and ALWAYS must incluce enclosing quotes:
  387. // "\"NEVER\"". This allows us to also pass in boolean literals which
  388. // are unquoted.
  389. // @param client_name_flag - specifies whether or not the client request
  390. // should contain a hostname option
  391. // @param exp_replacement_flag - specifies whether or not the server is
  392. // expected to replace (or supply) the hostname in its response
  393. void testReplaceClientNameMode(const char* mode,
  394. enum ClientNameFlag client_name_flag,
  395. enum ReplacementFlag exp_replacement_flag) {
  396. // Configuration "template" with a replaceable mode parameter
  397. const char* config_template =
  398. "{ \"interfaces-config\": {"
  399. " \"interfaces\": [ \"*\" ]"
  400. "},"
  401. "\"valid-lifetime\": 3000,"
  402. "\"subnet4\": [ { "
  403. " \"subnet\": \"10.0.0.0/24\", "
  404. " \"id\": 1,"
  405. " \"pools\": [ { \"pool\": \"10.0.0.10-10.0.0.10\" } ]"
  406. " }],"
  407. "\"dhcp-ddns\": {"
  408. "\"enable-updates\": true,"
  409. "\"qualifying-suffix\": \"fake-suffix.isc.org.\","
  410. "\"replace-client-name\": %s"
  411. "}}";
  412. // Create the configuration and configure the server
  413. char config_buf[1024];
  414. sprintf(config_buf, config_template, mode);
  415. ASSERT_NO_THROW(configure(config_buf, srv_)) << "configuration failed";
  416. // Build our client packet
  417. Pkt4Ptr query;
  418. if (client_name_flag == CLIENT_NAME_PRESENT) {
  419. ASSERT_NO_THROW(query = generatePktWithHostname(DHCPREQUEST,
  420. "my.example.com."));
  421. } else {
  422. ASSERT_NO_THROW(query = generatePkt(DHCPREQUEST));
  423. }
  424. // Run the packet through the server, extracting the hostname option
  425. // from the response. If the option isn't present the returned pointer
  426. // will be null.
  427. OptionStringPtr hostname;
  428. ASSERT_NO_THROW(
  429. hostname = processHostname(query,
  430. client_name_flag == CLIENT_NAME_PRESENT)
  431. ) << "processHostname throw an exception";
  432. // Verify the contents (or lack thereof) of the hostname
  433. if (exp_replacement_flag == NAME_REPLACED) {
  434. ASSERT_TRUE(hostname)
  435. << "No host name, it should have the replacement name \".\"";
  436. EXPECT_EQ(".", hostname->getValue());
  437. } else {
  438. if (client_name_flag == CLIENT_NAME_PRESENT) {
  439. ASSERT_TRUE(hostname)
  440. << "No host name, expected original from client";
  441. EXPECT_EQ("my.example.com.", hostname->getValue());
  442. } else {
  443. ASSERT_FALSE(hostname)
  444. << "Host name is: " << hostname
  445. << ", it should have been null";
  446. }
  447. }
  448. }
  449. /// @brief Checks the packet's FQDN option flags against a given mask
  450. ///
  451. /// @param pkt IPv4 packet whose FQDN flags should be checked.
  452. /// @param exp_flags Bit mask of flags that are expected to be true.
  453. void checkFqdnFlags(const Pkt4Ptr& pkt, const uint8_t exp_flags) {
  454. Option4ClientFqdnPtr fqdn = getClientFqdnOption(pkt);
  455. ASSERT_TRUE(fqdn);
  456. const bool flag_n = (exp_flags & Option4ClientFqdn::FLAG_N) != 0;
  457. const bool flag_s = (exp_flags & Option4ClientFqdn::FLAG_S) != 0;
  458. const bool flag_o = (exp_flags & Option4ClientFqdn::FLAG_O) != 0;
  459. const bool flag_e = (exp_flags & Option4ClientFqdn::FLAG_E) != 0;
  460. EXPECT_EQ(flag_n, fqdn->getFlag(Option4ClientFqdn::FLAG_N));
  461. EXPECT_EQ(flag_s, fqdn->getFlag(Option4ClientFqdn::FLAG_S));
  462. EXPECT_EQ(flag_o, fqdn->getFlag(Option4ClientFqdn::FLAG_O));
  463. EXPECT_EQ(flag_e, fqdn->getFlag(Option4ClientFqdn::FLAG_E));
  464. }
  465. /// @brief Invokes Dhcpv4Srv::processHostname on the given packet
  466. ///
  467. /// Processes the Hostname option in the client's message and returns
  468. /// the hostname option which would be sent to the client. It will
  469. /// return empty if the hostname option is not to be included
  470. /// server's response.
  471. /// @param query - client packet to process
  472. /// @param must_have_host - flag indicating whether or not the client
  473. /// packet must contain the hostname option
  474. ///
  475. /// @return a pointer to the hostname option constructed by the server
  476. OptionStringPtr processHostname(const Pkt4Ptr& query,
  477. bool must_have_host = true) {
  478. if (!getHostnameOption(query) && must_have_host) {
  479. ADD_FAILURE() << "Hostname option not carried in the query";
  480. }
  481. Pkt4Ptr answer;
  482. if (query->getType() == DHCPDISCOVER) {
  483. answer.reset(new Pkt4(DHCPOFFER, 1234));
  484. } else {
  485. answer.reset(new Pkt4(DHCPACK, 1234));
  486. }
  487. Dhcpv4Exchange ex = createExchange(query);
  488. srv_->processClientName(ex);
  489. OptionStringPtr hostname = getHostnameOption(ex.getResponse());
  490. return (hostname);
  491. }
  492. ///@brief Verify that NameChangeRequest holds valid values.
  493. ///
  494. /// Pulls the NCR from the top of the send queue and checks it's content
  495. /// against a number of expected parameters.
  496. ///
  497. /// @param type - expected NCR change type, CHG_ADD or CHG_REMOVE
  498. /// @param reverse - flag indicating whether or not the NCR specifies
  499. /// reverse change
  500. /// @param forward - flag indication whether or not the NCR specifies
  501. /// forward change
  502. /// @param addr - expected lease address in the NCR
  503. /// @param fqdn - expected FQDN in the NCR
  504. /// @param dhcid - expected DHCID in the NCR (comparison is performed only
  505. /// if the value supplied is not empty):w
  506. /// @param cltt - cltt value from the lease the NCR for which the NCR
  507. /// was generated expected value for
  508. /// @param len - expected lease length in the NCR
  509. /// @param not_strict_expire_check - when true the comparison of the NCR
  510. /// lease expiration time is conducted as greater than or equal to rather
  511. /// equal to CLTT plus lease lenght.
  512. void verifyNameChangeRequest(const isc::dhcp_ddns::NameChangeType type,
  513. const bool reverse, const bool forward,
  514. const std::string& addr,
  515. const std::string& fqdn,
  516. const std::string& dhcid,
  517. const time_t cltt,
  518. const uint16_t len,
  519. const bool not_strict_expire_check = false) {
  520. NameChangeRequestPtr ncr;
  521. ASSERT_NO_THROW(ncr = d2_mgr_.peekAt(0));
  522. ASSERT_TRUE(ncr);
  523. EXPECT_EQ(type, ncr->getChangeType());
  524. EXPECT_EQ(forward, ncr->isForwardChange());
  525. EXPECT_EQ(reverse, ncr->isReverseChange());
  526. EXPECT_EQ(addr, ncr->getIpAddress());
  527. EXPECT_EQ(fqdn, ncr->getFqdn());
  528. // Compare dhcid if it is not empty. In some cases, the DHCID is
  529. // not known in advance and can't be compared.
  530. if (!dhcid.empty()) {
  531. EXPECT_EQ(dhcid, ncr->getDhcid().toStr());
  532. }
  533. // In some cases, the test doesn't have access to the last transmission
  534. // time for the particular client. In such cases, the test can use the
  535. // current time as cltt but the it may not check the lease expiration
  536. // time for equality but rather check that the lease expiration time
  537. // is not greater than the current time + lease lifetime.
  538. if (not_strict_expire_check) {
  539. EXPECT_GE(cltt + len, ncr->getLeaseExpiresOn());
  540. } else {
  541. EXPECT_EQ(cltt + len, ncr->getLeaseExpiresOn());
  542. }
  543. EXPECT_EQ(len, ncr->getLeaseLength());
  544. EXPECT_EQ(isc::dhcp_ddns::ST_NEW, ncr->getStatus());
  545. // Process the message off the queue
  546. ASSERT_NO_THROW(d2_mgr_.runReadyIO());
  547. }
  548. /// @brief Tests processing a request with the given client flags
  549. ///
  550. /// This method creates a request with its FQDN flags set to the given
  551. /// value and submits it to the server for processing. It then checks
  552. /// the following:
  553. /// 1. Did the server generate an ACK with the correct FQDN flags
  554. /// 2. If the server should have generated an NCR, did it? and If
  555. /// so was it correct?
  556. ///
  557. /// @param client_flags Mask of client FQDN flags which are true
  558. /// @param response_flags Mask of expected FQDN flags in the response
  559. void flagVsConfigScenario(const uint8_t client_flags,
  560. const uint8_t response_flags) {
  561. // Create fake interfaces and open fake sockets.
  562. IfaceMgrTestConfig iface_config(true);
  563. IfaceMgr::instance().openSockets4();
  564. Pkt4Ptr req = generatePktWithFqdn(DHCPREQUEST, client_flags,
  565. "myhost.example.com.",
  566. Option4ClientFqdn::FULL, true);
  567. // Process the request.
  568. Pkt4Ptr reply;
  569. ASSERT_NO_THROW(reply = srv_->processRequest(req));
  570. // Verify the response and flags.
  571. checkResponse(reply, DHCPACK, 1234);
  572. checkFqdnFlags(reply, response_flags);
  573. // NCRs cannot be sent to the d2_mgr unless updates are enabled.
  574. if (d2_mgr_.ddnsEnabled()) {
  575. // There should be an NCR if response S flag is 1 or N flag is 0.
  576. bool exp_fwd = (response_flags & Option4ClientFqdn::FLAG_S);
  577. bool exp_rev = (!(response_flags & Option4ClientFqdn::FLAG_N));
  578. if (!exp_fwd && !exp_rev) {
  579. ASSERT_EQ(0, d2_mgr_.getQueueSize());
  580. } else {
  581. // Verify that there is one NameChangeRequest as expected.
  582. ASSERT_EQ(1, d2_mgr_.getQueueSize());
  583. verifyNameChangeRequest(isc::dhcp_ddns::CHG_ADD,
  584. exp_rev, exp_fwd,
  585. reply->getYiaddr().toText(),
  586. "myhost.example.com.",
  587. "", // empty DHCID means don't check it
  588. time(NULL) + subnet_->getValid(),
  589. subnet_->getValid(), true);
  590. }
  591. }
  592. }
  593. };
  594. // Tests the following scenario:
  595. // - Updates are enabled
  596. // - All overrides are off
  597. // - Client requests forward update (N = 0, S = 1)
  598. //
  599. // Server should perform the update:
  600. // - Response flags should N = 0, S = 1, O = 0
  601. // - Should queue an NCR
  602. TEST_F(NameDhcpv4SrvTest, updatesEnabled) {
  603. flagVsConfigScenario((Option4ClientFqdn::FLAG_E |
  604. Option4ClientFqdn::FLAG_S),
  605. (Option4ClientFqdn::FLAG_E |
  606. Option4ClientFqdn::FLAG_S));
  607. }
  608. // Tests the following scenario
  609. // - Updates are disabled
  610. // - Client requests forward update (N = 0, S = 1)
  611. //
  612. // Server should NOT perform updates:
  613. // - Response flags should N = 1, S = 0, O = 1
  614. // - Should not queue any NCRs
  615. TEST_F(NameDhcpv4SrvTest, updatesDisabled) {
  616. disableD2();
  617. flagVsConfigScenario((Option4ClientFqdn::FLAG_E |
  618. Option4ClientFqdn::FLAG_S),
  619. (Option4ClientFqdn::FLAG_E |
  620. Option4ClientFqdn::FLAG_N |
  621. Option4ClientFqdn::FLAG_O));
  622. }
  623. // Tests the following scenario:
  624. // - Updates are enabled
  625. // - All overrides are off.
  626. // - Client requests no updates (N = 1, S = 0)
  627. //
  628. // Server should NOT perform updates:
  629. // - Response flags should N = 1, S = 0, O = 0
  630. // - Should not queue any NCRs
  631. TEST_F(NameDhcpv4SrvTest, respectNoUpdate) {
  632. flagVsConfigScenario((Option4ClientFqdn::FLAG_E |
  633. Option4ClientFqdn::FLAG_N),
  634. (Option4ClientFqdn::FLAG_E |
  635. Option4ClientFqdn::FLAG_N));
  636. }
  637. // Tests the following scenario:
  638. // - Updates are enabled
  639. // - override-no-update is on
  640. // - Client requests no updates (N = 1, S = 0)
  641. //
  642. // Server should override "no update" request and perform updates:
  643. // - Response flags should be N = 0, S = 1, O = 1
  644. // - Should queue an NCR
  645. TEST_F(NameDhcpv4SrvTest, overrideNoUpdate) {
  646. enableD2(OVERRIDE_NO_UPDATE);
  647. flagVsConfigScenario((Option4ClientFqdn::FLAG_E |
  648. Option4ClientFqdn::FLAG_N),
  649. (Option4ClientFqdn::FLAG_E |
  650. Option4ClientFqdn::FLAG_S |
  651. Option4ClientFqdn::FLAG_O));
  652. }
  653. // Tests the following scenario:
  654. // - Updates are enabled
  655. // - All overrides are off.
  656. // - Client requests delegation (N = 0, S = 0)
  657. //
  658. // Server should respect client's delegation request and NOT do updates:
  659. // - Response flags should be N = 0, S = 0, O = 0
  660. // - Should not queue any NCRs
  661. TEST_F(NameDhcpv4SrvTest, respectClientDelegation) {
  662. flagVsConfigScenario(Option4ClientFqdn::FLAG_E,
  663. Option4ClientFqdn::FLAG_E);
  664. }
  665. // Tests the following scenario:
  666. // - Updates are enabled
  667. // - override-client-update is on.
  668. // - Client requests delegation (N = 0, S = 0)
  669. //
  670. // Server should override client's delegation request and do updates:
  671. // - Response flags should be N = 0, S = 1, O = 1
  672. // - Should queue an NCR
  673. TEST_F(NameDhcpv4SrvTest, overrideClientDelegation) {
  674. // Turn on override-client-update.
  675. enableD2(OVERRIDE_CLIENT_UPDATE);
  676. flagVsConfigScenario(Option4ClientFqdn::FLAG_E,
  677. (Option4ClientFqdn::FLAG_E |
  678. Option4ClientFqdn::FLAG_S |
  679. Option4ClientFqdn::FLAG_O));
  680. }
  681. // Test that server processes the Hostname option sent by a client and
  682. // responds with the Hostname option to confirm that the server has
  683. // taken responsibility for the update.
  684. TEST_F(NameDhcpv4SrvTest, serverUpdateHostname) {
  685. Pkt4Ptr query;
  686. ASSERT_NO_THROW(query = generatePktWithHostname(DHCPREQUEST,
  687. "myhost.example.com."));
  688. OptionStringPtr hostname;
  689. ASSERT_NO_THROW(hostname = processHostname(query));
  690. ASSERT_TRUE(hostname);
  691. EXPECT_EQ("myhost.example.com.", hostname->getValue());
  692. }
  693. // Test that the server skips processing of a wrong Hostname option.
  694. TEST_F(NameDhcpv4SrvTest, serverUpdateWrongHostname) {
  695. Pkt4Ptr query;
  696. ASSERT_NO_THROW(query = generatePktWithHostname(DHCPREQUEST,
  697. "abc..example.com"));
  698. OptionStringPtr hostname;
  699. ASSERT_NO_THROW(hostname = processHostname(query));
  700. EXPECT_FALSE(hostname);
  701. }
  702. // Test that server generates the fully qualified domain name for the client
  703. // if client supplies the partial name.
  704. TEST_F(NameDhcpv4SrvTest, serverUpdateForwardPartialNameFqdn) {
  705. Pkt4Ptr query = generatePktWithFqdn(DHCPREQUEST,
  706. Option4ClientFqdn::FLAG_E |
  707. Option4ClientFqdn::FLAG_S,
  708. "myhost",
  709. Option4ClientFqdn::PARTIAL,
  710. true);
  711. testProcessFqdn(query,
  712. Option4ClientFqdn::FLAG_E | Option4ClientFqdn::FLAG_S,
  713. "myhost.example.com.");
  714. }
  715. // Test that server generates the fully qualified domain name for the client
  716. // if client supplies the unqualified name in the Hostname option.
  717. TEST_F(NameDhcpv4SrvTest, serverUpdateUnqualifiedHostname) {
  718. Pkt4Ptr query;
  719. ASSERT_NO_THROW(query = generatePktWithHostname(DHCPREQUEST, "myhost"));
  720. OptionStringPtr hostname;
  721. ASSERT_NO_THROW(hostname = processHostname(query));
  722. ASSERT_TRUE(hostname);
  723. EXPECT_EQ("myhost.example.com", hostname->getValue());
  724. }
  725. // Test that server sets empty domain-name in the FQDN option when client
  726. // supplied no domain-name. The domain-name is supposed to be set after the
  727. // lease is acquired. The domain-name is then generated from the IP address
  728. // assigned to a client.
  729. TEST_F(NameDhcpv4SrvTest, serverUpdateForwardNoNameFqdn) {
  730. Pkt4Ptr query = generatePktWithFqdn(DHCPREQUEST,
  731. Option4ClientFqdn::FLAG_E |
  732. Option4ClientFqdn::FLAG_S,
  733. "",
  734. Option4ClientFqdn::PARTIAL,
  735. true);
  736. testProcessFqdn(query,
  737. Option4ClientFqdn::FLAG_E | Option4ClientFqdn::FLAG_S,
  738. "", Option4ClientFqdn::PARTIAL);
  739. }
  740. // Test that exactly one NameChangeRequest is generated when the new lease
  741. // has been acquired (old lease is NULL).
  742. TEST_F(NameDhcpv4SrvTest, createNameChangeRequestsNewLease) {
  743. Lease4Ptr lease = createLease(IOAddress("192.0.2.3"), "myhost.example.com.",
  744. true, true);
  745. Lease4Ptr old_lease;
  746. ASSERT_NO_THROW(srv_->createNameChangeRequests(lease, old_lease));
  747. ASSERT_EQ(1, d2_mgr_.getQueueSize());
  748. verifyNameChangeRequest(isc::dhcp_ddns::CHG_ADD, true, true,
  749. "192.0.2.3", "myhost.example.com.",
  750. "00010132E91AA355CFBB753C0F0497A5A940436965"
  751. "B68B6D438D98E680BF10B09F3BCF",
  752. lease->cltt_, 100);
  753. }
  754. // Test that no NameChangeRequest is generated when a lease is renewed and
  755. // the FQDN data hasn't changed.
  756. TEST_F(NameDhcpv4SrvTest, createNameChangeRequestsRenewNoChange) {
  757. Lease4Ptr lease = createLease(IOAddress("192.0.2.3"), "myhost.example.com.",
  758. true, true);
  759. Lease4Ptr old_lease = createLease(IOAddress("192.0.2.3"),
  760. "myhost.example.com.", true, true);
  761. old_lease->valid_lft_ += 100;
  762. ASSERT_NO_THROW(srv_->createNameChangeRequests(lease, old_lease));
  763. ASSERT_EQ(0, d2_mgr_.getQueueSize());
  764. }
  765. // Test that the OFFER message generated as a result of the DISCOVER message
  766. // processing will not result in generation of the NameChangeRequests.
  767. TEST_F(NameDhcpv4SrvTest, processDiscover) {
  768. IfaceMgrTestConfig test_config(true);
  769. IfaceMgr::instance().openSockets4();
  770. Pkt4Ptr req = generatePktWithFqdn(DHCPDISCOVER, Option4ClientFqdn::FLAG_S |
  771. Option4ClientFqdn::FLAG_E,
  772. "myhost.example.com.",
  773. Option4ClientFqdn::FULL, true);
  774. Pkt4Ptr reply;
  775. ASSERT_NO_THROW(reply = srv_->processDiscover(req));
  776. checkResponse(reply, DHCPOFFER, 1234);
  777. EXPECT_EQ(0, d2_mgr_.getQueueSize());
  778. }
  779. // Test that server generates client's hostname from the IP address assigned
  780. // to it when DHCPv4 Client FQDN option specifies an empty domain-name.
  781. TEST_F(NameDhcpv4SrvTest, processRequestFqdnEmptyDomainName) {
  782. IfaceMgrTestConfig test_config(true);
  783. IfaceMgr::instance().openSockets4();
  784. Pkt4Ptr req = generatePktWithFqdn(DHCPREQUEST, Option4ClientFqdn::FLAG_S |
  785. Option4ClientFqdn::FLAG_E,
  786. "", Option4ClientFqdn::PARTIAL, true);
  787. Pkt4Ptr reply;
  788. ASSERT_NO_THROW(reply = srv_->processRequest(req));
  789. checkResponse(reply, DHCPACK, 1234);
  790. // Verify that there is one NameChangeRequest generated.
  791. ASSERT_EQ(1, d2_mgr_.getQueueSize());
  792. // The hostname is generated from the IP address acquired (yiaddr).
  793. std::string hostname = generatedNameFromAddress(reply->getYiaddr());
  794. verifyNameChangeRequest(isc::dhcp_ddns::CHG_ADD, true, true,
  795. reply->getYiaddr().toText(), hostname,
  796. "", // empty DHCID forces that it is not checked
  797. time(NULL) + subnet_->getValid(),
  798. subnet_->getValid(), true);
  799. }
  800. // Test that server generates client's hostname from the IP address assigned
  801. // to it when DHCPv4 Client FQDN option specifies an empty domain-name AND
  802. // ddns updates are disabled.
  803. TEST_F(NameDhcpv4SrvTest, processRequestEmptyDomainNameDisabled) {
  804. // Create fake interfaces and open fake sockets.
  805. IfaceMgrTestConfig test_config(true);
  806. IfaceMgr::instance().openSockets4();
  807. disableD2();
  808. Pkt4Ptr req = generatePktWithFqdn(DHCPREQUEST, Option4ClientFqdn::FLAG_S |
  809. Option4ClientFqdn::FLAG_E,
  810. "", Option4ClientFqdn::PARTIAL, true);
  811. Pkt4Ptr reply;
  812. ASSERT_NO_THROW(reply = srv_->processRequest(req));
  813. checkResponse(reply, DHCPACK, 1234);
  814. Option4ClientFqdnPtr fqdn = getClientFqdnOption(reply);
  815. ASSERT_TRUE(fqdn);
  816. // The hostname is generated from the IP address acquired (yiaddr).
  817. std::string hostname = generatedNameFromAddress(reply->getYiaddr());
  818. EXPECT_EQ(hostname, fqdn->getDomainName());
  819. EXPECT_EQ(Option4ClientFqdn::FULL, fqdn->getDomainNameType());
  820. }
  821. // Test that server generates client's hostname from the IP address assigned
  822. // to it when Hostname option carries the top level domain-name.
  823. TEST_F(NameDhcpv4SrvTest, processRequestTopLevelHostname) {
  824. IfaceMgrTestConfig test_config(true);
  825. IfaceMgr::instance().openSockets4();
  826. Pkt4Ptr req = generatePktWithHostname(DHCPREQUEST, ".");
  827. // Set interface for the incoming packet. The server requires it to
  828. // generate client id.
  829. req->setIface("eth1");
  830. Pkt4Ptr reply;
  831. ASSERT_NO_THROW(reply = srv_->processRequest(req));
  832. checkResponse(reply, DHCPACK, 1234);
  833. // Verify that there is one NameChangeRequest generated.
  834. ASSERT_EQ(1, d2_mgr_.getQueueSize());
  835. // The hostname is generated from the IP address acquired (yiaddr).
  836. std::string hostname = generatedNameFromAddress(reply->getYiaddr());
  837. verifyNameChangeRequest(isc::dhcp_ddns::CHG_ADD, true, true,
  838. reply->getYiaddr().toText(), hostname,
  839. "", // empty DHCID forces that it is not checked
  840. time(NULL), subnet_->getValid(), true);
  841. }
  842. // Test that client may send two requests, each carrying FQDN option with
  843. // a different domain-name. Server should use existing lease for the second
  844. // request but modify the DNS entries for the lease according to the contents
  845. // of the FQDN sent in the second request.
  846. TEST_F(NameDhcpv4SrvTest, processTwoRequestsFqdn) {
  847. IfaceMgrTestConfig test_config(true);
  848. IfaceMgr::instance().openSockets4();
  849. Pkt4Ptr req1 = generatePktWithFqdn(DHCPREQUEST, Option4ClientFqdn::FLAG_S |
  850. Option4ClientFqdn::FLAG_E,
  851. "myhost.example.com.",
  852. Option4ClientFqdn::FULL, true);
  853. Pkt4Ptr reply;
  854. ASSERT_NO_THROW(reply = srv_->processRequest(req1));
  855. checkResponse(reply, DHCPACK, 1234);
  856. // Verify that there is one NameChangeRequest generated.
  857. ASSERT_EQ(1, d2_mgr_.getQueueSize());
  858. verifyNameChangeRequest(isc::dhcp_ddns::CHG_ADD, true, true,
  859. reply->getYiaddr().toText(), "myhost.example.com.",
  860. "00010132E91AA355CFBB753C0F0497A5A940436"
  861. "965B68B6D438D98E680BF10B09F3BCF",
  862. time(NULL), subnet_->getValid(), true);
  863. // Create another Request message but with a different FQDN. Server
  864. // should generate two NameChangeRequests: one to remove existing entry,
  865. // another one to add new entry with updated domain-name.
  866. Pkt4Ptr req2 = generatePktWithFqdn(DHCPREQUEST, Option4ClientFqdn::FLAG_S |
  867. Option4ClientFqdn::FLAG_E,
  868. "otherhost.example.com.",
  869. Option4ClientFqdn::FULL, true);
  870. ASSERT_NO_THROW(reply = srv_->processRequest(req2));
  871. checkResponse(reply, DHCPACK, 1234);
  872. // There should be two NameChangeRequests. Verify that they are valid.
  873. ASSERT_EQ(2, d2_mgr_.getQueueSize());
  874. verifyNameChangeRequest(isc::dhcp_ddns::CHG_REMOVE, true, true,
  875. reply->getYiaddr().toText(),
  876. "myhost.example.com.",
  877. "00010132E91AA355CFBB753C0F0497A5A940436"
  878. "965B68B6D438D98E680BF10B09F3BCF",
  879. time(NULL), subnet_->getValid(), true);
  880. verifyNameChangeRequest(isc::dhcp_ddns::CHG_ADD, true, true,
  881. reply->getYiaddr().toText(),
  882. "otherhost.example.com.",
  883. "000101A5AEEA7498BD5AD9D3BF600E49FF39A7E3"
  884. "AFDCE8C3D0E53F35CC584DD63C89CA",
  885. time(NULL), subnet_->getValid(), true);
  886. }
  887. // Test that client may send two requests, each carrying Hostname option with
  888. // a different name. Server should use existing lease for the second request
  889. // but modify the DNS entries for the lease according to the contents of the
  890. // Hostname sent in the second request.
  891. TEST_F(NameDhcpv4SrvTest, processTwoRequestsHostname) {
  892. IfaceMgrTestConfig test_config(true);
  893. IfaceMgr::instance().openSockets4();
  894. Pkt4Ptr req1 = generatePktWithHostname(DHCPREQUEST, "myhost.example.com.");
  895. // Set interface for the incoming packet. The server requires it to
  896. // generate client id.
  897. req1->setIface("eth1");
  898. Pkt4Ptr reply;
  899. ASSERT_NO_THROW(reply = srv_->processRequest(req1));
  900. checkResponse(reply, DHCPACK, 1234);
  901. // Verify that there is one NameChangeRequest generated.
  902. ASSERT_EQ(1, d2_mgr_.getQueueSize());
  903. verifyNameChangeRequest(isc::dhcp_ddns::CHG_ADD, true, true,
  904. reply->getYiaddr().toText(), "myhost.example.com.",
  905. "00010132E91AA355CFBB753C0F0497A5A940436"
  906. "965B68B6D438D98E680BF10B09F3BCF",
  907. time(NULL), subnet_->getValid(), true);
  908. // Create another Request message but with a different Hostname. Server
  909. // should generate two NameChangeRequests: one to remove existing entry,
  910. // another one to add new entry with updated domain-name.
  911. Pkt4Ptr req2 = generatePktWithHostname(DHCPREQUEST, "otherhost");
  912. // Set interface for the incoming packet. The server requires it to
  913. // generate client id.
  914. req2->setIface("eth1");
  915. ASSERT_NO_THROW(reply = srv_->processRequest(req2));
  916. checkResponse(reply, DHCPACK, 1234);
  917. // There should be two NameChangeRequests. Verify that they are valid.
  918. ASSERT_EQ(2, d2_mgr_.getQueueSize());
  919. verifyNameChangeRequest(isc::dhcp_ddns::CHG_REMOVE, true, true,
  920. reply->getYiaddr().toText(),
  921. "myhost.example.com.",
  922. "00010132E91AA355CFBB753C0F0497A5A940436"
  923. "965B68B6D438D98E680BF10B09F3BCF",
  924. time(NULL), subnet_->getValid(), true);
  925. verifyNameChangeRequest(isc::dhcp_ddns::CHG_ADD, true, true,
  926. reply->getYiaddr().toText(),
  927. "otherhost.example.com.",
  928. "000101A5AEEA7498BD5AD9D3BF600E49FF39A7E3"
  929. "AFDCE8C3D0E53F35CC584DD63C89CA",
  930. time(NULL), subnet_->getValid(), true);
  931. }
  932. // Test that when a release message is sent for a previously acquired lease,
  933. // DDNS updates are enabled that the server generates a NameChangeRequest
  934. // to remove entries corresponding to the released lease.
  935. TEST_F(NameDhcpv4SrvTest, processRequestRelease) {
  936. IfaceMgrTestConfig test_config(true);
  937. IfaceMgr::instance().openSockets4();
  938. // Verify the updates are enabled.
  939. ASSERT_TRUE(CfgMgr::instance().ddnsEnabled());
  940. // Create and process a lease request so we have a lease to release.
  941. Pkt4Ptr req = generatePktWithFqdn(DHCPREQUEST, Option4ClientFqdn::FLAG_S |
  942. Option4ClientFqdn::FLAG_E,
  943. "myhost.example.com.",
  944. Option4ClientFqdn::FULL, true);
  945. Pkt4Ptr reply;
  946. ASSERT_NO_THROW(reply = srv_->processRequest(req));
  947. checkResponse(reply, DHCPACK, 1234);
  948. // Verify that there is one NameChangeRequest generated for lease.
  949. ASSERT_EQ(1, d2_mgr_.getQueueSize());
  950. verifyNameChangeRequest(isc::dhcp_ddns::CHG_ADD, true, true,
  951. reply->getYiaddr().toText(), "myhost.example.com.",
  952. "00010132E91AA355CFBB753C0F0497A5A940436"
  953. "965B68B6D438D98E680BF10B09F3BCF",
  954. time(NULL), subnet_->getValid(), true);
  955. // Create and process the Release message.
  956. Pkt4Ptr rel = Pkt4Ptr(new Pkt4(DHCPRELEASE, 1234));
  957. rel->setCiaddr(reply->getYiaddr());
  958. rel->setRemoteAddr(IOAddress("192.0.2.3"));
  959. rel->addOption(generateClientId());
  960. rel->addOption(srv_->getServerID());
  961. ASSERT_NO_THROW(srv_->processRelease(rel));
  962. // The lease has been removed, so there should be a NameChangeRequest to
  963. // remove corresponding DNS entries.
  964. ASSERT_EQ(1, d2_mgr_.getQueueSize());
  965. verifyNameChangeRequest(isc::dhcp_ddns::CHG_REMOVE, true, true,
  966. reply->getYiaddr().toText(), "myhost.example.com.",
  967. "00010132E91AA355CFBB753C0F0497A5A940436"
  968. "965B68B6D438D98E680BF10B09F3BCF",
  969. time(NULL), subnet_->getValid(), true);
  970. }
  971. // Test that when the Release message is sent for a previously acquired lease
  972. // and DDNS updates are disabled that server does NOT generate a
  973. // NameChangeRequest to remove entries corresponding to the released lease.
  974. // Queue size is not available when updates are not enabled, however,
  975. // attempting to send a NCR when updates disabled will result in a throw.
  976. // If no throws are experienced then no attempt was made to send a NCR.
  977. TEST_F(NameDhcpv4SrvTest, processRequestReleaseUpdatesDisabled) {
  978. // Create fake interfaces and open fake sockets.
  979. IfaceMgrTestConfig test_config(true);
  980. IfaceMgr::instance().openSockets4();
  981. // Disable DDNS.
  982. disableD2();
  983. ASSERT_FALSE(CfgMgr::instance().ddnsEnabled());
  984. // Create and process a lease request so we have a lease to release.
  985. Pkt4Ptr req = generatePktWithFqdn(DHCPREQUEST, Option4ClientFqdn::FLAG_S |
  986. Option4ClientFqdn::FLAG_E,
  987. "myhost.example.com.",
  988. Option4ClientFqdn::FULL, true);
  989. Pkt4Ptr reply;
  990. ASSERT_NO_THROW(reply = srv_->processRequest(req));
  991. checkResponse(reply, DHCPACK, 1234);
  992. // Create and process the Release message.
  993. Pkt4Ptr rel = Pkt4Ptr(new Pkt4(DHCPRELEASE, 1234));
  994. rel->setCiaddr(reply->getYiaddr());
  995. rel->setRemoteAddr(IOAddress("192.0.2.3"));
  996. rel->addOption(generateClientId());
  997. rel->addOption(srv_->getServerID());
  998. ASSERT_NO_THROW(srv_->processRelease(rel));
  999. }
  1000. // This test verifies that the server sends the FQDN option to the client
  1001. // with the reserved hostname.
  1002. TEST_F(NameDhcpv4SrvTest, fqdnReservation) {
  1003. Dhcp4Client client(Dhcp4Client::SELECTING);
  1004. // Use HW address that matches the reservation entry in the configuration.
  1005. client.setHWAddress("aa:bb:cc:dd:ee:ff");
  1006. // Configure DHCP server.
  1007. configure(CONFIGS[0], *client.getServer());
  1008. // Make sure that DDNS is enabled.
  1009. ASSERT_TRUE(CfgMgr::instance().ddnsEnabled());
  1010. ASSERT_NO_THROW(client.getServer()->startD2());
  1011. // Include the Client FQDN option.
  1012. ASSERT_NO_THROW(client.includeFQDN(Option4ClientFqdn::FLAG_S | Option4ClientFqdn::FLAG_E,
  1013. "client-name", Option4ClientFqdn::PARTIAL));
  1014. // Send the DHCPDISCOVER.
  1015. ASSERT_NO_THROW(client.doDiscover());
  1016. // Make sure that the server responded.
  1017. Pkt4Ptr resp = client.getContext().response_;
  1018. ASSERT_TRUE(resp);
  1019. ASSERT_EQ(DHCPOFFER, static_cast<int>(resp->getType()));
  1020. // Obtain the FQDN option sent in the response and make sure that the server
  1021. // has used the hostname reserved for this client.
  1022. Option4ClientFqdnPtr fqdn;
  1023. fqdn = boost::dynamic_pointer_cast<Option4ClientFqdn>(resp->getOption(DHO_FQDN));
  1024. ASSERT_TRUE(fqdn);
  1025. EXPECT_EQ("unique-host.example.org.", fqdn->getDomainName());
  1026. // When receiving DHCPDISCOVER, no NCRs should be generated.
  1027. EXPECT_EQ(0, d2_mgr_.getQueueSize());
  1028. // Now send the DHCPREQUEST with including the FQDN option.
  1029. ASSERT_NO_THROW(client.doRequest());
  1030. resp = client.getContext().response_;
  1031. ASSERT_TRUE(resp);
  1032. ASSERT_EQ(DHCPACK, static_cast<int>(resp->getType()));
  1033. // Once again check that the FQDN is as expected.
  1034. fqdn = boost::dynamic_pointer_cast<Option4ClientFqdn>(resp->getOption(DHO_FQDN));
  1035. ASSERT_TRUE(fqdn);
  1036. EXPECT_EQ("unique-host.example.org.", fqdn->getDomainName());
  1037. {
  1038. SCOPED_TRACE("Verify the correctness of the NCR for the"
  1039. "unique-host.example.org");
  1040. // Because this is a new lease, there should be one NCR which adds the
  1041. // new DNS entry.
  1042. ASSERT_EQ(1, CfgMgr::instance().getD2ClientMgr().getQueueSize());
  1043. verifyNameChangeRequest(isc::dhcp_ddns::CHG_ADD, true, true,
  1044. resp->getYiaddr().toText(),
  1045. "unique-host.example.org.",
  1046. "000001ACB52196C8F3BCC1DF3BA1F40BAC39BF23"
  1047. "0D280858B1ED7696E174C4479E3372",
  1048. time(NULL), subnet_->getValid(), true);
  1049. }
  1050. // And that this FQDN has been stored in the lease database.
  1051. Lease4Ptr lease = LeaseMgrFactory::instance().getLease4(client.config_.lease_.addr_);
  1052. ASSERT_TRUE(lease);
  1053. EXPECT_EQ("unique-host.example.org.", lease->hostname_);
  1054. // Reconfigure DHCP server to use a different hostname for the client.
  1055. configure(CONFIGS[1], *client.getServer());
  1056. // Make sure that DDNS is enabled.
  1057. ASSERT_TRUE(CfgMgr::instance().ddnsEnabled());
  1058. ASSERT_NO_THROW(client.getServer()->startD2());
  1059. // Client is in the renewing state.
  1060. client.setState(Dhcp4Client::RENEWING);
  1061. client.doRequest();
  1062. resp = client.getContext().response_;
  1063. ASSERT_TRUE(resp);
  1064. ASSERT_EQ(DHCPACK, static_cast<int>(resp->getType()));
  1065. // The new FQDN should contain a different name this time.
  1066. fqdn = boost::dynamic_pointer_cast<Option4ClientFqdn>(resp->getOption(DHO_FQDN));
  1067. ASSERT_TRUE(fqdn);
  1068. EXPECT_EQ("foobar.fake-suffix.isc.org.", fqdn->getDomainName());
  1069. // And the lease in the lease database should also contain this new FQDN.
  1070. lease = LeaseMgrFactory::instance().getLease4(client.config_.lease_.addr_);
  1071. ASSERT_TRUE(lease);
  1072. EXPECT_EQ("foobar.fake-suffix.isc.org.", lease->hostname_);
  1073. // Now there should be two name NCRs. One that removes the previous entry
  1074. // and the one that adds a new entry for the new hostname.
  1075. ASSERT_EQ(2, CfgMgr::instance().getD2ClientMgr().getQueueSize());
  1076. {
  1077. SCOPED_TRACE("Verify the correctness of the CHG_REMOVE NCR for the "
  1078. "unique-host.example.org");
  1079. verifyNameChangeRequest(isc::dhcp_ddns::CHG_REMOVE, true, true,
  1080. resp->getYiaddr().toText(),
  1081. "unique-host.example.org.",
  1082. "000001ACB52196C8F3BCC1DF3BA1F40BAC39BF23"
  1083. "0D280858B1ED7696E174C4479E3372",
  1084. time(NULL), subnet_->getValid(), true);
  1085. }
  1086. {
  1087. SCOPED_TRACE("Verify the correctness of the CHG_ADD NCR for the "
  1088. "foobar.fake-suffix.isc.org");
  1089. verifyNameChangeRequest(isc::dhcp_ddns::CHG_ADD, true, true,
  1090. resp->getYiaddr().toText(),
  1091. "foobar.fake-suffix.isc.org.",
  1092. "0000017C29B3C236344924E448E247F3FD56C7E9"
  1093. "167B3397B1305FB664C160B967CE1F",
  1094. time(NULL), subnet_->getValid(), true);
  1095. }
  1096. }
  1097. // This test verifies that the server sends the Hostname option to the client
  1098. // with the reserved hostname.
  1099. TEST_F(NameDhcpv4SrvTest, hostnameReservation) {
  1100. Dhcp4Client client(Dhcp4Client::SELECTING);
  1101. // Use HW address that matches the reservation entry in the configuration.
  1102. client.setHWAddress("aa:bb:cc:dd:ee:ff");
  1103. // Configure DHCP server.
  1104. configure(CONFIGS[0], *client.getServer());
  1105. // Make sure that DDNS is enabled.
  1106. ASSERT_TRUE(CfgMgr::instance().ddnsEnabled());
  1107. ASSERT_NO_THROW(client.getServer()->startD2());
  1108. // Include the Hostname option.
  1109. ASSERT_NO_THROW(client.includeHostname("client-name"));
  1110. // Send the DHCPDISCOVER
  1111. ASSERT_NO_THROW(client.doDiscover());
  1112. // Make sure that the server responded.
  1113. Pkt4Ptr resp = client.getContext().response_;
  1114. ASSERT_TRUE(resp);
  1115. ASSERT_EQ(DHCPOFFER, static_cast<int>(resp->getType()));
  1116. // Obtain the Hostname option sent in the response and make sure that the server
  1117. // has used the hostname reserved for this client.
  1118. OptionStringPtr hostname;
  1119. hostname = boost::dynamic_pointer_cast<OptionString>(resp->getOption(DHO_HOST_NAME));
  1120. ASSERT_TRUE(hostname);
  1121. EXPECT_EQ("unique-host.example.org", hostname->getValue());
  1122. // Now send the DHCPREQUEST with including the Hostname option.
  1123. ASSERT_NO_THROW(client.doRequest());
  1124. resp = client.getContext().response_;
  1125. ASSERT_TRUE(resp);
  1126. ASSERT_EQ(DHCPACK, static_cast<int>(resp->getType()));
  1127. // Once again check that the Hostname is as expected.
  1128. hostname = boost::dynamic_pointer_cast<OptionString>(resp->getOption(DHO_HOST_NAME));
  1129. ASSERT_TRUE(hostname);
  1130. EXPECT_EQ("unique-host.example.org", hostname->getValue());
  1131. // And that this hostname has been stored in the lease database.
  1132. Lease4Ptr lease = LeaseMgrFactory::instance().getLease4(client.config_.lease_.addr_);
  1133. ASSERT_TRUE(lease);
  1134. EXPECT_EQ("unique-host.example.org", lease->hostname_);
  1135. // Because this is a new lease, there should be one NCR which adds the
  1136. // new DNS entry.
  1137. ASSERT_EQ(1, CfgMgr::instance().getD2ClientMgr().getQueueSize());
  1138. {
  1139. SCOPED_TRACE("Verify the correctness of the NCR for the"
  1140. "unique-host.example.org");
  1141. verifyNameChangeRequest(isc::dhcp_ddns::CHG_ADD, true, true,
  1142. resp->getYiaddr().toText(),
  1143. "unique-host.example.org.",
  1144. "000001ACB52196C8F3BCC1DF3BA1F40BAC39BF23"
  1145. "0D280858B1ED7696E174C4479E3372",
  1146. time(NULL), subnet_->getValid(), true);
  1147. }
  1148. // Reconfigure DHCP server to use a different hostname for the client.
  1149. configure(CONFIGS[1], *client.getServer());
  1150. // Make sure that DDNS is enabled.
  1151. ASSERT_TRUE(CfgMgr::instance().ddnsEnabled());
  1152. ASSERT_NO_THROW(client.getServer()->startD2());
  1153. // Client is in the renewing state.
  1154. client.setState(Dhcp4Client::RENEWING);
  1155. client.doRequest();
  1156. resp = client.getContext().response_;
  1157. ASSERT_TRUE(resp);
  1158. ASSERT_EQ(DHCPACK, static_cast<int>(resp->getType()));
  1159. // The new hostname should be different than previously.
  1160. hostname = boost::dynamic_pointer_cast<OptionString>(resp->getOption(DHO_HOST_NAME));
  1161. ASSERT_TRUE(hostname);
  1162. EXPECT_EQ("foobar.fake-suffix.isc.org", hostname->getValue());
  1163. // And the lease in the lease database should also contain this new FQDN.
  1164. lease = LeaseMgrFactory::instance().getLease4(client.config_.lease_.addr_);
  1165. ASSERT_TRUE(lease);
  1166. EXPECT_EQ("foobar.fake-suffix.isc.org", lease->hostname_);
  1167. // Now there should be two name NCRs. One that removes the previous entry
  1168. // and the one that adds a new entry for the new hostname.
  1169. ASSERT_EQ(2, CfgMgr::instance().getD2ClientMgr().getQueueSize());
  1170. {
  1171. SCOPED_TRACE("Verify the correctness of the CHG_REMOVE NCR for the "
  1172. "unique-host.example.org");
  1173. verifyNameChangeRequest(isc::dhcp_ddns::CHG_REMOVE, true, true,
  1174. resp->getYiaddr().toText(),
  1175. "unique-host.example.org.",
  1176. "000001ACB52196C8F3BCC1DF3BA1F40BAC39BF23"
  1177. "0D280858B1ED7696E174C4479E3372",
  1178. time(NULL), subnet_->getValid(), true);
  1179. }
  1180. {
  1181. SCOPED_TRACE("Verify the correctness of the CHG_ADD NCR for the "
  1182. "foobar.fake-suffix.isc.org");
  1183. verifyNameChangeRequest(isc::dhcp_ddns::CHG_ADD, true, true,
  1184. resp->getYiaddr().toText(),
  1185. "foobar.fake-suffix.isc.org.",
  1186. "0000017C29B3C236344924E448E247F3FD56C7E9"
  1187. "167B3397B1305FB664C160B967CE1F",
  1188. time(NULL), subnet_->getValid(), true);
  1189. }
  1190. }
  1191. // This test verifies that the server sends the Hostname option to the client
  1192. // with hostname reservation and which included hostname option code in the
  1193. // Parameter Request List.
  1194. TEST_F(NameDhcpv4SrvTest, hostnameReservationPRL) {
  1195. Dhcp4Client client(Dhcp4Client::SELECTING);
  1196. // Use HW address that matches the reservation entry in the configuration.
  1197. client.setHWAddress("aa:bb:cc:dd:ee:ff");
  1198. // Configure DHCP server.
  1199. configure(CONFIGS[4], *client.getServer());
  1200. // Make sure that DDNS is enabled.
  1201. ASSERT_FALSE(CfgMgr::instance().ddnsEnabled());
  1202. // Request Hostname option.
  1203. ASSERT_NO_THROW(client.requestOption(DHO_HOST_NAME));
  1204. // Send the DHCPDISCOVER
  1205. ASSERT_NO_THROW(client.doDiscover());
  1206. // Make sure that the server responded.
  1207. Pkt4Ptr resp = client.getContext().response_;
  1208. ASSERT_TRUE(resp);
  1209. ASSERT_EQ(DHCPOFFER, static_cast<int>(resp->getType()));
  1210. // Obtain the Hostname option sent in the response and make sure that the server
  1211. // has used the hostname reserved for this client.
  1212. OptionStringPtr hostname;
  1213. hostname = boost::dynamic_pointer_cast<OptionString>(resp->getOption(DHO_HOST_NAME));
  1214. ASSERT_TRUE(hostname);
  1215. EXPECT_EQ("reserved.example.org", hostname->getValue());
  1216. // Now send the DHCPREQUEST with including the Hostname option.
  1217. ASSERT_NO_THROW(client.doRequest());
  1218. resp = client.getContext().response_;
  1219. ASSERT_TRUE(resp);
  1220. ASSERT_EQ(DHCPACK, static_cast<int>(resp->getType()));
  1221. // Once again check that the Hostname is as expected.
  1222. hostname = boost::dynamic_pointer_cast<OptionString>(resp->getOption(DHO_HOST_NAME));
  1223. ASSERT_TRUE(hostname);
  1224. EXPECT_EQ("reserved.example.org", hostname->getValue());
  1225. }
  1226. // This test verifies that the server sends the Hostname option to the client
  1227. // with partial hostname reservation and with the global qualifying-suffix set.
  1228. TEST_F(NameDhcpv4SrvTest, hostnameReservationNoDNSQualifyingSuffix) {
  1229. Dhcp4Client client(Dhcp4Client::SELECTING);
  1230. // Use HW address that matches the reservation entry in the configuration.
  1231. client.setHWAddress("aa:bb:cc:dd:ee:ff");
  1232. // Configure DHCP server.
  1233. configure(CONFIGS[5], *client.getServer());
  1234. // Make sure that DDNS is enabled.
  1235. ASSERT_FALSE(CfgMgr::instance().ddnsEnabled());
  1236. // Include the Hostname option.
  1237. ASSERT_NO_THROW(client.includeHostname("client-name"));
  1238. // Send the DHCPDISCOVER
  1239. ASSERT_NO_THROW(client.doDiscover());
  1240. // Make sure that the server responded.
  1241. Pkt4Ptr resp = client.getContext().response_;
  1242. ASSERT_TRUE(resp);
  1243. ASSERT_EQ(DHCPOFFER, static_cast<int>(resp->getType()));
  1244. // Obtain the Hostname option sent in the response and make sure that the server
  1245. // has used the hostname reserved for this client.
  1246. OptionStringPtr hostname;
  1247. hostname = boost::dynamic_pointer_cast<OptionString>(resp->getOption(DHO_HOST_NAME));
  1248. ASSERT_TRUE(hostname);
  1249. EXPECT_EQ("foo-bar.example.isc.org", hostname->getValue());
  1250. // Now send the DHCPREQUEST with including the Hostname option.
  1251. ASSERT_NO_THROW(client.doRequest());
  1252. resp = client.getContext().response_;
  1253. ASSERT_TRUE(resp);
  1254. ASSERT_EQ(DHCPACK, static_cast<int>(resp->getType()));
  1255. // Once again check that the Hostname is as expected.
  1256. hostname = boost::dynamic_pointer_cast<OptionString>(resp->getOption(DHO_HOST_NAME));
  1257. ASSERT_TRUE(hostname);
  1258. EXPECT_EQ("foo-bar.example.isc.org", hostname->getValue());
  1259. }
  1260. // Test verifies that the server properly generates a FQDN when the client
  1261. // FQDN name is blank, whether or not DDNS updates are enabled. It also
  1262. // verifies that the lease is only in the database following a DHCPREQUEST and
  1263. // that the lesae contains the generated FQDN.
  1264. TEST_F(NameDhcpv4SrvTest, emptyFqdn) {
  1265. Dhcp4Client client(Dhcp4Client::SELECTING);
  1266. isc::asiolink::IOAddress expected_address("10.0.0.10");
  1267. std::string expected_fqdn("myhost-10-0-0-10.fake-suffix.isc.org.");
  1268. // Load a configuration with DDNS updates disabled
  1269. configure(CONFIGS[2], *client.getServer());
  1270. ASSERT_FALSE(CfgMgr::instance().ddnsEnabled());
  1271. // Include the Client FQDN option.
  1272. ASSERT_NO_THROW(client.includeFQDN((Option4ClientFqdn::FLAG_S
  1273. | Option4ClientFqdn::FLAG_E),
  1274. "", Option4ClientFqdn::PARTIAL));
  1275. // Send the DHCPDISCOVER
  1276. ASSERT_NO_THROW(client.doDiscover());
  1277. // Make sure that the server responded.
  1278. Pkt4Ptr resp = client.getContext().response_;
  1279. ASSERT_TRUE(resp);
  1280. ASSERT_EQ(DHCPOFFER, static_cast<int>(resp->getType()));
  1281. // Make sure the response FQDN has the generated name and FQDN flags are
  1282. // correct for updated disabled.
  1283. Option4ClientFqdnPtr fqdn;
  1284. fqdn = boost::dynamic_pointer_cast<Option4ClientFqdn>(resp->getOption(DHO_FQDN));
  1285. ASSERT_TRUE(fqdn);
  1286. EXPECT_EQ(expected_fqdn, fqdn->getDomainName());
  1287. checkFqdnFlags(resp, (Option4ClientFqdn::FLAG_N |
  1288. Option4ClientFqdn::FLAG_E |
  1289. Option4ClientFqdn::FLAG_O));
  1290. // Make sure the lease is NOT in the database.
  1291. Lease4Ptr lease = LeaseMgrFactory::instance().getLease4(IOAddress(expected_address));
  1292. ASSERT_FALSE(lease);
  1293. // Now test with updates enabled
  1294. configure(CONFIGS[3], *client.getServer());
  1295. ASSERT_TRUE(CfgMgr::instance().ddnsEnabled());
  1296. ASSERT_NO_THROW(client.getServer()->startD2());
  1297. // Send the DHCPDISCOVER
  1298. ASSERT_NO_THROW(client.doDiscover());
  1299. // Make sure that the server responded.
  1300. resp = client.getContext().response_;
  1301. ASSERT_TRUE(resp);
  1302. ASSERT_EQ(DHCPOFFER, static_cast<int>(resp->getType()));
  1303. // Make sure the response FQDN has the generated name and FQDN flags are
  1304. // correct for updates enabled.
  1305. fqdn = boost::dynamic_pointer_cast<Option4ClientFqdn>(resp->getOption(DHO_FQDN));
  1306. ASSERT_TRUE(fqdn);
  1307. EXPECT_EQ(expected_fqdn, fqdn->getDomainName());
  1308. checkFqdnFlags(resp, (Option4ClientFqdn::FLAG_E |
  1309. Option4ClientFqdn::FLAG_S));
  1310. // Make sure the lease is NOT in the database.
  1311. lease = LeaseMgrFactory::instance().getLease4(IOAddress(expected_address));
  1312. ASSERT_FALSE(lease);
  1313. // Do a DORA and verify that the lease exists and the name is correct.
  1314. ASSERT_NO_THROW(client.doDORA());
  1315. // Make sure that the server responded.
  1316. resp = client.getContext().response_;
  1317. ASSERT_TRUE(resp);
  1318. ASSERT_EQ(DHCPACK, static_cast<int>(resp->getType()));
  1319. // Make sure the response FQDN has the generated name and FQDN flags are
  1320. // correct for updates enabled.
  1321. fqdn = boost::dynamic_pointer_cast<Option4ClientFqdn>(resp->getOption(DHO_FQDN));
  1322. ASSERT_TRUE(fqdn);
  1323. EXPECT_EQ(expected_fqdn, fqdn->getDomainName());
  1324. checkFqdnFlags(resp, (Option4ClientFqdn::FLAG_E |
  1325. Option4ClientFqdn::FLAG_S));
  1326. // Make sure the lease is in the database and hostname is correct.
  1327. lease = LeaseMgrFactory::instance().getLease4(IOAddress(expected_address));
  1328. ASSERT_TRUE(lease);
  1329. EXPECT_EQ(expected_fqdn, lease->hostname_);
  1330. }
  1331. // Verifies that the replace-client-name behavior is correct for each of
  1332. // the supported modes.
  1333. TEST_F(NameDhcpv4SrvTest, replaceClientNameModeTest) {
  1334. testReplaceClientNameMode("\"never\"",
  1335. CLIENT_NAME_NOT_PRESENT, NAME_NOT_REPLACED);
  1336. testReplaceClientNameMode("\"never\"",
  1337. CLIENT_NAME_PRESENT, NAME_NOT_REPLACED);
  1338. testReplaceClientNameMode("\"always\"",
  1339. CLIENT_NAME_NOT_PRESENT, NAME_REPLACED);
  1340. testReplaceClientNameMode("\"always\"",
  1341. CLIENT_NAME_PRESENT, NAME_REPLACED);
  1342. testReplaceClientNameMode("\"when-present\"",
  1343. CLIENT_NAME_NOT_PRESENT, NAME_NOT_REPLACED);
  1344. testReplaceClientNameMode("\"when-present\"",
  1345. CLIENT_NAME_PRESENT, NAME_REPLACED);
  1346. testReplaceClientNameMode("\"when-not-present\"",
  1347. CLIENT_NAME_NOT_PRESENT, NAME_REPLACED);
  1348. testReplaceClientNameMode("\"when-not-present\"",
  1349. CLIENT_NAME_PRESENT, NAME_NOT_REPLACED);
  1350. }
  1351. } // end of anonymous namespace