d2_cfg_mgr_unittests.cc 58 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562
  1. // Copyright (C) 2013-2014 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <config/module_spec.h>
  15. #include <d2/d2_config.h>
  16. #include <d2/d2_cfg_mgr.h>
  17. #include <d_test_stubs.h>
  18. #include <test_data_files_config.h>
  19. #include <util/encode/base64.h>
  20. #include <boost/foreach.hpp>
  21. #include <gtest/gtest.h>
  22. using namespace std;
  23. using namespace isc;
  24. using namespace isc::d2;
  25. namespace {
  26. std::string specfile(const std::string& name) {
  27. return (std::string(D2_SRC_DIR) + "/" + name);
  28. }
  29. /// @brief Test fixture class for testing D2CfgMgr class.
  30. /// It maintains an member instance of D2CfgMgr and provides methods for
  31. /// converting JSON strings to configuration element sets, checking parse
  32. /// results, and accessing the configuration context.
  33. class D2CfgMgrTest : public ConfigParseTest {
  34. public:
  35. /// @brief Constructor
  36. D2CfgMgrTest():cfg_mgr_(new D2CfgMgr()), d2_params_() {
  37. }
  38. /// @brief Destructor
  39. ~D2CfgMgrTest() {
  40. }
  41. /// @brief Configuration manager instance.
  42. D2CfgMgrPtr cfg_mgr_;
  43. /// @brief Build JSON configuration string for a D2Params element
  44. ///
  45. /// Constructs a JSON string for "params" element using replacable
  46. /// parameters.
  47. ///
  48. /// @param ip_address string to insert as ip_address value
  49. /// @param port integer to insert as port value
  50. /// @param dns_server_timeout integer to insert as dns_server_timeout value
  51. /// @param ncr_protocol string to insert as ncr_protocol value
  52. /// @param ncr_format string to insert as ncr_format value
  53. ///
  54. /// @return std::string containing the JSON configuration text
  55. std::string makeParamsConfigString(const std::string& ip_address,
  56. const int port,
  57. const int dns_server_timeout,
  58. const std::string& ncr_protocol,
  59. const std::string& ncr_format) {
  60. std::ostringstream config;
  61. config <<
  62. "{"
  63. " \"ip_address\": \"" << ip_address << "\" , "
  64. " \"port\": " << port << " , "
  65. " \"dns_server_timeout\": " << dns_server_timeout << " , "
  66. " \"ncr_protocol\": \"" << ncr_protocol << "\" , "
  67. " \"ncr_format\": \"" << ncr_format << "\", "
  68. "\"tsig_keys\": [], "
  69. "\"forward_ddns\" : {}, "
  70. "\"reverse_ddns\" : {} "
  71. "}";
  72. return (config.str());
  73. }
  74. /// @brief Enumeration to select between expected configuration outcomes
  75. enum RunConfigMode {
  76. SHOULD_PASS,
  77. SHOULD_FAIL
  78. };
  79. /// @brief Parses a configuration string and tests against a given outcome
  80. ///
  81. /// Convenience method which accepts JSON text and an expected pass or fail
  82. /// outcome. It converts the text into an ElementPtr and passes that to
  83. /// configuration manager's parseConfig method. It then tests the
  84. /// parse result against the expected outcome If they do not match it
  85. /// the method asserts a failure. If they do match, it refreshes the
  86. /// the D2Params pointer with the newly parsed instance.
  87. ///
  88. /// @param config_str the JSON configuration text to parse
  89. /// @param mode indicator if the parsing should fail or not. It defaults
  90. /// defaults to SHOULD_PASS.
  91. ///
  92. void runConfig(std::string config_str, RunConfigMode mode=SHOULD_PASS) {
  93. // We assume the config string is valid JSON.
  94. ASSERT_TRUE(fromJSON(config_str));
  95. // Parse the configuration and verify we got the expected outcome.
  96. answer_ = cfg_mgr_->parseConfig(config_set_);
  97. ASSERT_TRUE(checkAnswer(mode == SHOULD_FAIL));
  98. // Verify that the D2 context can be retrieved and is not null.
  99. D2CfgContextPtr context;
  100. ASSERT_NO_THROW(context = cfg_mgr_->getD2CfgContext());
  101. // Verify that the global scalars have the proper values.
  102. d2_params_ = context->getD2Params();
  103. ASSERT_TRUE(d2_params_);
  104. }
  105. /// @brief Pointer the D2Params most recently parsed.
  106. D2ParamsPtr d2_params_;
  107. };
  108. /// @brief Tests that the spec file is valid.
  109. /// Verifies that the BIND10 DHCP-DDNS configuration specification file
  110. // is valid.
  111. TEST(D2SpecTest, basicSpec) {
  112. ASSERT_NO_THROW(isc::config::
  113. moduleSpecFromFile(specfile("dhcp-ddns.spec")));
  114. }
  115. /// @brief Convenience function which compares the contents of the given
  116. /// DnsServerInfo against the given set of values.
  117. ///
  118. /// It is structured in such a way that each value is checked, and output
  119. /// is generate for all that do not match.
  120. ///
  121. /// @param server is a pointer to the server to check against.
  122. /// @param hostname is the value to compare against server's hostname_.
  123. /// @param ip_address is the string value to compare against server's
  124. /// ip_address_.
  125. /// @param port is the value to compare against server's port.
  126. ///
  127. /// @return returns true if there is a match across the board, otherwise it
  128. /// returns false.
  129. bool checkServer(DnsServerInfoPtr server, const char* hostname,
  130. const char *ip_address, uint32_t port)
  131. {
  132. // Return value, assume its a match.
  133. bool result = true;
  134. if (!server) {
  135. EXPECT_TRUE(server);
  136. return false;
  137. }
  138. // Check hostname.
  139. if (server->getHostname() != hostname) {
  140. EXPECT_EQ(hostname, server->getHostname());
  141. result = false;
  142. }
  143. // Check IP address.
  144. if (server->getIpAddress().toText() != ip_address) {
  145. EXPECT_EQ(ip_address, server->getIpAddress().toText());
  146. result = false;
  147. }
  148. // Check port.
  149. if (server->getPort() != port) {
  150. EXPECT_EQ (port, server->getPort());
  151. result = false;
  152. }
  153. return (result);
  154. }
  155. /// @brief Convenience function which compares the contents of the given
  156. /// TSIGKeyInfo against the given set of values, and that the TSIGKey
  157. /// member points to a key.
  158. ///
  159. /// @param key is a pointer to the TSIGKeyInfo instance to verify
  160. /// @param name is the value to compare against key's name_.
  161. /// @param algorithm is the string value to compare against key's algorithm.
  162. /// @param secret is the value to compare against key's secret.
  163. ///
  164. /// @return returns true if there is a match across the board, otherwise it
  165. /// returns false.
  166. bool checkKey(TSIGKeyInfoPtr key, const std::string& name,
  167. const std::string& algorithm, const std::string& secret) {
  168. // Return value, assume its a match.
  169. return (((key) &&
  170. (key->getName() == name) &&
  171. (key->getAlgorithm() == algorithm) &&
  172. (key->getSecret() == secret) &&
  173. (key->getTSIGKey())));
  174. }
  175. /// @brief Test fixture class for testing DnsServerInfo parsing.
  176. class TSIGKeyInfoTest : public ConfigParseTest {
  177. public:
  178. /// @brief Constructor
  179. TSIGKeyInfoTest() {
  180. reset();
  181. }
  182. /// @brief Destructor
  183. ~TSIGKeyInfoTest() {
  184. }
  185. /// @brief Wipe out the current storage and parser and replace
  186. /// them with new ones.
  187. void reset() {
  188. keys_.reset(new TSIGKeyInfoMap());
  189. parser_.reset(new TSIGKeyInfoParser("test", keys_));
  190. }
  191. /// @brief Storage for "committing" keys.
  192. TSIGKeyInfoMapPtr keys_;
  193. /// @brief Pointer to the current parser instance.
  194. isc::dhcp::ParserPtr parser_;
  195. };
  196. /// @brief Test fixture class for testing DnsServerInfo parsing.
  197. class DnsServerInfoTest : public ConfigParseTest {
  198. public:
  199. /// @brief Constructor
  200. DnsServerInfoTest() {
  201. reset();
  202. }
  203. /// @brief Destructor
  204. ~DnsServerInfoTest() {
  205. }
  206. /// @brief Wipe out the current storage and parser and replace
  207. /// them with new ones.
  208. void reset() {
  209. servers_.reset(new DnsServerInfoStorage());
  210. parser_.reset(new DnsServerInfoParser("test", servers_));
  211. }
  212. /// @brief Storage for "committing" servers.
  213. DnsServerInfoStoragePtr servers_;
  214. /// @brief Pointer to the current parser instance.
  215. isc::dhcp::ParserPtr parser_;
  216. };
  217. /// @brief Test fixture class for testing DDnsDomain parsing.
  218. class DdnsDomainTest : public ConfigParseTest {
  219. public:
  220. /// @brief Constructor
  221. DdnsDomainTest() {
  222. reset();
  223. }
  224. /// @brief Destructor
  225. ~DdnsDomainTest() {
  226. }
  227. /// @brief Wipe out the current storage and parser and replace
  228. /// them with new ones.
  229. void reset() {
  230. keys_.reset(new TSIGKeyInfoMap());
  231. domains_.reset(new DdnsDomainMap());
  232. parser_.reset(new DdnsDomainParser("test", domains_, keys_));
  233. }
  234. /// @brief Add TSIGKeyInfos to the key map
  235. ///
  236. /// @param name the name of the key
  237. /// @param algorithm the algorithm of the key
  238. /// @param secret the secret value of the key
  239. void addKey(const std::string& name, const std::string& algorithm,
  240. const std::string& secret) {
  241. TSIGKeyInfoPtr key_info(new TSIGKeyInfo(name, algorithm, secret));
  242. (*keys_)[name]=key_info;
  243. }
  244. /// @brief Storage for "committing" domains.
  245. DdnsDomainMapPtr domains_;
  246. /// @brief Storage for TSIGKeys
  247. TSIGKeyInfoMapPtr keys_;
  248. /// @brief Pointer to the current parser instance.
  249. isc::dhcp::ParserPtr parser_;
  250. };
  251. /// @brief Tests a basic valid configuration for D2Param.
  252. TEST_F(D2CfgMgrTest, validParamsEntry) {
  253. // Verify that ip_address can be valid v4 address.
  254. std::string config = makeParamsConfigString ("192.0.0.1", 777, 333,
  255. "UDP", "JSON");
  256. runConfig(config);
  257. EXPECT_EQ(isc::asiolink::IOAddress("192.0.0.1"),
  258. d2_params_->getIpAddress());
  259. EXPECT_EQ(777, d2_params_->getPort());
  260. EXPECT_EQ(333, d2_params_->getDnsServerTimeout());
  261. EXPECT_EQ(dhcp_ddns::NCR_UDP, d2_params_->getNcrProtocol());
  262. EXPECT_EQ(dhcp_ddns::FMT_JSON, d2_params_->getNcrFormat());
  263. // Verify that ip_address can be valid v6 address.
  264. config = makeParamsConfigString ("3001::5", 777, 333, "UDP", "JSON");
  265. runConfig(config);
  266. // Verify that the global scalars have the proper values.
  267. EXPECT_EQ(isc::asiolink::IOAddress("3001::5"),
  268. d2_params_->getIpAddress());
  269. }
  270. /// @brief Tests default values for D2Params.
  271. /// It verifies that D2Params is populated with default value for optional
  272. /// parameter if not supplied in the configuration.
  273. /// Currently they are all optional.
  274. TEST_F(D2CfgMgrTest, defaultValues) {
  275. // Check that omitting ip_address gets you its default
  276. std::string config =
  277. "{"
  278. " \"port\": 777 , "
  279. " \"dns_server_timeout\": 333 , "
  280. " \"ncr_protocol\": \"UDP\" , "
  281. " \"ncr_format\": \"JSON\", "
  282. "\"tsig_keys\": [], "
  283. "\"forward_ddns\" : {}, "
  284. "\"reverse_ddns\" : {} "
  285. "}";
  286. runConfig(config);
  287. EXPECT_EQ(isc::asiolink::IOAddress(D2Params::DFT_IP_ADDRESS),
  288. d2_params_->getIpAddress());
  289. // Check that omitting port gets you its default
  290. config =
  291. "{"
  292. " \"ip_address\": \"192.0.0.1\" , "
  293. " \"dns_server_timeout\": 333 , "
  294. " \"ncr_protocol\": \"UDP\" , "
  295. " \"ncr_format\": \"JSON\", "
  296. "\"tsig_keys\": [], "
  297. "\"forward_ddns\" : {}, "
  298. "\"reverse_ddns\" : {} "
  299. "}";
  300. runConfig(config);
  301. EXPECT_EQ(D2Params::DFT_PORT, d2_params_->getPort());
  302. // Check that omitting timeout gets you its default
  303. config =
  304. "{"
  305. " \"ip_address\": \"192.0.0.1\" , "
  306. " \"port\": 777 , "
  307. " \"ncr_protocol\": \"UDP\" , "
  308. " \"ncr_format\": \"JSON\", "
  309. "\"tsig_keys\": [], "
  310. "\"forward_ddns\" : {}, "
  311. "\"reverse_ddns\" : {} "
  312. "}";
  313. runConfig(config);
  314. EXPECT_EQ(D2Params::DFT_DNS_SERVER_TIMEOUT,
  315. d2_params_->getDnsServerTimeout());
  316. // Check that protocol timeout gets you its default
  317. config =
  318. "{"
  319. " \"ip_address\": \"192.0.0.1\" , "
  320. " \"port\": 777 , "
  321. " \"dns_server_timeout\": 333 , "
  322. " \"ncr_format\": \"JSON\", "
  323. "\"tsig_keys\": [], "
  324. "\"forward_ddns\" : {}, "
  325. "\"reverse_ddns\" : {} "
  326. "}";
  327. runConfig(config);
  328. EXPECT_EQ(dhcp_ddns::stringToNcrProtocol(D2Params::DFT_NCR_PROTOCOL),
  329. d2_params_->getNcrProtocol());
  330. // Check that format timeout gets you its default
  331. config =
  332. "{"
  333. " \"ip_address\": \"192.0.0.1\" , "
  334. " \"port\": 777 , "
  335. " \"dns_server_timeout\": 333 , "
  336. " \"ncr_protocol\": \"UDP\", "
  337. "\"tsig_keys\": [], "
  338. "\"forward_ddns\" : {}, "
  339. "\"reverse_ddns\" : {} "
  340. "}";
  341. runConfig(config);
  342. EXPECT_EQ(dhcp_ddns::stringToNcrFormat(D2Params::DFT_NCR_FORMAT),
  343. d2_params_->getNcrFormat());
  344. }
  345. /// @brief Tests the unsupported scalar parameters and objects are detected.
  346. TEST_F(D2CfgMgrTest, unsupportedTopLevelItems) {
  347. // Check that an unsupported top level parameter fails.
  348. std::string config =
  349. "{"
  350. " \"ip_address\": \"127.0.0.1\", "
  351. " \"port\": 777 , "
  352. " \"dns_server_timeout\": 333 , "
  353. " \"ncr_protocol\": \"UDP\" , "
  354. " \"ncr_format\": \"JSON\", "
  355. "\"tsig_keys\": [], "
  356. "\"forward_ddns\" : {}, "
  357. "\"reverse_ddns\" : {}, "
  358. "\"bogus_param\" : true "
  359. "}";
  360. runConfig(config, SHOULD_FAIL);
  361. // Check that unsupported top level objects fails. For
  362. // D2 these fail as they are not in the parse order.
  363. config =
  364. "{"
  365. " \"ip_address\": \"127.0.0.1\", "
  366. " \"port\": 777 , "
  367. " \"dns_server_timeout\": 333 , "
  368. " \"ncr_protocol\": \"UDP\" , "
  369. " \"ncr_format\": \"JSON\", "
  370. "\"tsig_keys\": [], "
  371. "\"bogus_object_one\" : {}, "
  372. "\"forward_ddns\" : {}, "
  373. "\"reverse_ddns\" : {}, "
  374. "\"bogus_object_two\" : {} "
  375. "}";
  376. runConfig(config, SHOULD_FAIL);
  377. }
  378. /// @brief Tests the enforcement of data validation when parsing D2Params.
  379. /// It verifies that:
  380. /// -# ip_address cannot be "0.0.0.0"
  381. /// -# ip_address cannot be "::"
  382. /// -# port cannot be 0
  383. /// -# dns_server_timeout cannat be 0
  384. /// -# ncr_protocol must be valid
  385. /// -# ncr_format must be valid
  386. TEST_F(D2CfgMgrTest, invalidEntry) {
  387. // Cannot use IPv4 ANY address
  388. std::string config = makeParamsConfigString ("0.0.0.0", 777, 333,
  389. "UDP", "JSON");
  390. runConfig(config, SHOULD_FAIL);
  391. // Cannot use IPv6 ANY address
  392. config = makeParamsConfigString ("::", 777, 333, "UDP", "JSON");
  393. runConfig(config, SHOULD_FAIL);
  394. // Cannot use port 0
  395. config = makeParamsConfigString ("127.0.0.1", 0, 333, "UDP", "JSON");
  396. runConfig(config, SHOULD_FAIL);
  397. // Cannot use dns server timeout of 0
  398. config = makeParamsConfigString ("127.0.0.1", 777, 0, "UDP", "JSON");
  399. runConfig(config, SHOULD_FAIL);
  400. // Invalid protocol
  401. config = makeParamsConfigString ("127.0.0.1", 777, 333, "BOGUS", "JSON");
  402. runConfig(config, SHOULD_FAIL);
  403. // Invalid format
  404. config = makeParamsConfigString ("127.0.0.1", 777, 333, "UDP", "BOGUS");
  405. runConfig(config, SHOULD_FAIL);
  406. }
  407. /// @brief Tests the enforcement of data validation when parsing TSIGKeyInfos.
  408. /// It verifies that:
  409. /// 1. Name cannot be blank.
  410. /// 2. Algorithm cannot be blank.
  411. /// 3. Secret cannot be blank.
  412. TEST_F(TSIGKeyInfoTest, invalidEntry) {
  413. // Config with a blank name entry.
  414. std::string config = "{"
  415. " \"name\": \"\" , "
  416. " \"algorithm\": \"HMAC-MD5\" , "
  417. " \"secret\": \"LSWXnfkKZjdPJI5QxlpnfQ==\" "
  418. "}";
  419. ASSERT_TRUE(fromJSON(config));
  420. // Verify that build fails on blank name.
  421. EXPECT_THROW(parser_->build(config_set_), D2CfgError);
  422. // Config with a blank algorithm entry.
  423. config = "{"
  424. " \"name\": \"d2_key_one\" , "
  425. " \"algorithm\": \"\" , "
  426. " \"secret\": \"LSWXnfkKZjdPJI5QxlpnfQ==\" "
  427. "}";
  428. ASSERT_TRUE(fromJSON(config));
  429. // Verify that build fails on blank algorithm.
  430. EXPECT_THROW(parser_->build(config_set_), D2CfgError);
  431. // Config with an invalid algorithm entry.
  432. config = "{"
  433. " \"name\": \"d2_key_one\" , "
  434. " \"algorithm\": \"bogus\" , "
  435. " \"secret\": \"LSWXnfkKZjdPJI5QxlpnfQ==\" "
  436. "}";
  437. ASSERT_TRUE(fromJSON(config));
  438. // Verify that build fails on blank algorithm.
  439. EXPECT_THROW(parser_->build(config_set_), D2CfgError);
  440. // Config with a blank secret entry.
  441. config = "{"
  442. " \"name\": \"d2_key_one\" , "
  443. " \"algorithm\": \"HMAC-MD5\" , "
  444. " \"secret\": \"\" "
  445. "}";
  446. ASSERT_TRUE(fromJSON(config));
  447. // Verify that build fails blank secret
  448. EXPECT_THROW(parser_->build(config_set_), D2CfgError);
  449. // Config with an invalid secret entry.
  450. config = "{"
  451. " \"name\": \"d2_key_one\" , "
  452. " \"algorithm\": \"HMAC-MD5\" , "
  453. " \"secret\": \"bogus\" "
  454. "}";
  455. ASSERT_TRUE(fromJSON(config));
  456. // Verify that build fails an invalid secret
  457. EXPECT_THROW(parser_->build(config_set_), D2CfgError);
  458. }
  459. /// @brief Verifies that TSIGKeyInfo parsing creates a proper TSIGKeyInfo
  460. /// when given a valid combination of entries.
  461. TEST_F(TSIGKeyInfoTest, validEntry) {
  462. // Valid entries for TSIG key, all items are required.
  463. std::string config = "{"
  464. " \"name\": \"d2_key_one\" , "
  465. " \"algorithm\": \"HMAC-MD5\" , "
  466. " \"secret\": \"dGhpcyBrZXkgd2lsbCBtYXRjaA==\" "
  467. "}";
  468. ASSERT_TRUE(fromJSON(config));
  469. // Verify that it builds and commits without throwing.
  470. //ASSERT_NO_THROW(parser_->build(config_set_));
  471. (parser_->build(config_set_));
  472. ASSERT_NO_THROW(parser_->commit());
  473. // Verify the correct number of keys are present
  474. int count = keys_->size();
  475. EXPECT_EQ(1, count);
  476. // Find the key and retrieve it.
  477. TSIGKeyInfoMap::iterator gotit = keys_->find("d2_key_one");
  478. ASSERT_TRUE(gotit != keys_->end());
  479. TSIGKeyInfoPtr& key = gotit->second;
  480. // Verify the key contents.
  481. EXPECT_TRUE(checkKey(key, "d2_key_one", "HMAC-MD5",
  482. "dGhpcyBrZXkgd2lsbCBtYXRjaA=="));
  483. }
  484. /// @brief Verifies that attempting to parse an invalid list of TSIGKeyInfo
  485. /// entries is detected.
  486. TEST_F(TSIGKeyInfoTest, invalidTSIGKeyList) {
  487. // Construct a list of keys with an invalid key entry.
  488. std::string config = "["
  489. " { \"name\": \"key1\" , "
  490. " \"algorithm\": \"HMAC-MD5\" ,"
  491. " \"secret\": \"GWG/Xfbju4O2iXGqkSu4PQ==\" "
  492. " },"
  493. // this entry has an invalid algorithm
  494. " { \"name\": \"key2\" , "
  495. " \"algorithm\": \"\" ,"
  496. " \"secret\": \"GWG/Xfbju4O2iXGqkSu4PQ==\" "
  497. " },"
  498. " { \"name\": \"key3\" , "
  499. " \"algorithm\": \"HMAC-MD5\" ,"
  500. " \"secret\": \"GWG/Xfbju4O2iXGqkSu4PQ==\" "
  501. " }"
  502. " ]";
  503. ASSERT_TRUE(fromJSON(config));
  504. // Create the list parser.
  505. isc::dhcp::ParserPtr parser;
  506. ASSERT_NO_THROW(parser.reset(new TSIGKeyInfoListParser("test", keys_)));
  507. // Verify that the list builds without errors.
  508. EXPECT_THROW(parser->build(config_set_), D2CfgError);
  509. }
  510. /// @brief Verifies that attempting to parse an invalid list of TSIGKeyInfo
  511. /// entries is detected.
  512. TEST_F(TSIGKeyInfoTest, duplicateTSIGKey) {
  513. // Construct a list of keys with an invalid key entry.
  514. std::string config = "["
  515. " { \"name\": \"key1\" , "
  516. " \"algorithm\": \"HMAC-MD5\" ,"
  517. " \"secret\": \"GWG/Xfbju4O2iXGqkSu4PQ==\" "
  518. " },"
  519. " { \"name\": \"key2\" , "
  520. " \"algorithm\": \"HMAC-MD5\" ,"
  521. " \"secret\": \"GWG/Xfbju4O2iXGqkSu4PQ==\" "
  522. " },"
  523. " { \"name\": \"key1\" , "
  524. " \"algorithm\": \"HMAC-MD5\" ,"
  525. " \"secret\": \"GWG/Xfbju4O2iXGqkSu4PQ==\" "
  526. " }"
  527. " ]";
  528. ASSERT_TRUE(fromJSON(config));
  529. // Create the list parser.
  530. isc::dhcp::ParserPtr parser;
  531. ASSERT_NO_THROW(parser.reset(new TSIGKeyInfoListParser("test", keys_)));
  532. // Verify that the list builds without errors.
  533. EXPECT_THROW(parser->build(config_set_), D2CfgError);
  534. }
  535. /// @brief Verifies a valid list of TSIG Keys parses correctly.
  536. /// Also verifies that all of the supported algorithm names work.
  537. TEST_F(TSIGKeyInfoTest, validTSIGKeyList) {
  538. // Construct a valid list of keys.
  539. std::string config = "["
  540. " { \"name\": \"key1\" , "
  541. " \"algorithm\": \"HMAC-MD5\" ,"
  542. " \"secret\": \"dGhpcyBrZXkgd2lsbCBtYXRjaA==\" "
  543. " },"
  544. " { \"name\": \"key2\" , "
  545. " \"algorithm\": \"HMAC-SHA1\" ,"
  546. " \"secret\": \"dGhpcyBrZXkgd2lsbCBtYXRjaA==\" "
  547. " },"
  548. " { \"name\": \"key3\" , "
  549. " \"algorithm\": \"HMAC-SHA256\" ,"
  550. " \"secret\": \"dGhpcyBrZXkgd2lsbCBtYXRjaA==\" "
  551. " },"
  552. " { \"name\": \"key4\" , "
  553. " \"algorithm\": \"HMAC-SHA224\" ,"
  554. " \"secret\": \"dGhpcyBrZXkgd2lsbCBtYXRjaA==\" "
  555. " },"
  556. " { \"name\": \"key5\" , "
  557. " \"algorithm\": \"HMAC-SHA384\" ,"
  558. " \"secret\": \"dGhpcyBrZXkgd2lsbCBtYXRjaA==\" "
  559. " },"
  560. " { \"name\": \"key6\" , "
  561. " \"algorithm\": \"HMAC-SHA512\" ,"
  562. " \"secret\": \"dGhpcyBrZXkgd2lsbCBtYXRjaA==\" "
  563. " }"
  564. " ]";
  565. ASSERT_TRUE(fromJSON(config));
  566. // Verify that the list builds and commits without errors.
  567. // Create the list parser.
  568. isc::dhcp::ParserPtr parser;
  569. ASSERT_NO_THROW(parser.reset(new TSIGKeyInfoListParser("test", keys_)));
  570. ASSERT_NO_THROW(parser->build(config_set_));
  571. ASSERT_NO_THROW(parser->commit());
  572. std::string ref_secret = "dGhpcyBrZXkgd2lsbCBtYXRjaA==";
  573. // Verify the correct number of keys are present
  574. int count = keys_->size();
  575. ASSERT_EQ(6, count);
  576. // Find the 1st key and retrieve it.
  577. TSIGKeyInfoMap::iterator gotit = keys_->find("key1");
  578. ASSERT_TRUE(gotit != keys_->end());
  579. TSIGKeyInfoPtr& key = gotit->second;
  580. // Verify the key contents.
  581. EXPECT_TRUE(checkKey(key, "key1", TSIGKeyInfo::HMAC_MD5_STR, ref_secret));
  582. // Find the 2nd key and retrieve it.
  583. gotit = keys_->find("key2");
  584. ASSERT_TRUE(gotit != keys_->end());
  585. key = gotit->second;
  586. // Verify the key contents.
  587. EXPECT_TRUE(checkKey(key, "key2", TSIGKeyInfo::HMAC_SHA1_STR, ref_secret));
  588. // Find the 3rd key and retrieve it.
  589. gotit = keys_->find("key3");
  590. ASSERT_TRUE(gotit != keys_->end());
  591. key = gotit->second;
  592. // Verify the key contents.
  593. EXPECT_TRUE(checkKey(key, "key3", TSIGKeyInfo::HMAC_SHA256_STR,
  594. ref_secret));
  595. // Find the 4th key and retrieve it.
  596. gotit = keys_->find("key4");
  597. ASSERT_TRUE(gotit != keys_->end());
  598. key = gotit->second;
  599. // Verify the key contents.
  600. EXPECT_TRUE(checkKey(key, "key4", TSIGKeyInfo::HMAC_SHA224_STR,
  601. ref_secret));
  602. // Find the 5th key and retrieve it.
  603. gotit = keys_->find("key5");
  604. ASSERT_TRUE(gotit != keys_->end());
  605. key = gotit->second;
  606. // Verify the key contents.
  607. EXPECT_TRUE(checkKey(key, "key5", TSIGKeyInfo::HMAC_SHA384_STR,
  608. ref_secret));
  609. // Find the 6th key and retrieve it.
  610. gotit = keys_->find("key6");
  611. ASSERT_TRUE(gotit != keys_->end());
  612. key = gotit->second;
  613. // Verify the key contents.
  614. EXPECT_TRUE(checkKey(key, "key6", TSIGKeyInfo::HMAC_SHA512_STR,
  615. ref_secret));
  616. }
  617. /// @brief Tests the enforcement of data validation when parsing DnsServerInfos.
  618. /// It verifies that:
  619. /// 1. Specifying both a hostname and an ip address is not allowed.
  620. /// 2. Specifying both blank a hostname and blank ip address is not allowed.
  621. /// 3. Specifying a negative port number is not allowed.
  622. TEST_F(DnsServerInfoTest, invalidEntry) {
  623. // Create a config in which both host and ip address are supplied.
  624. // Verify that build fails.
  625. std::string config = "{ \"hostname\": \"pegasus.tmark\", "
  626. " \"ip_address\": \"127.0.0.1\" } ";
  627. ASSERT_TRUE(fromJSON(config));
  628. EXPECT_THROW(parser_->build(config_set_), D2CfgError);
  629. // Neither host nor ip address supplied
  630. // Verify that builds fails.
  631. config = "{ \"hostname\": \"\", "
  632. " \"ip_address\": \"\" } ";
  633. ASSERT_TRUE(fromJSON(config));
  634. EXPECT_THROW(parser_->build(config_set_), D2CfgError);
  635. // Create a config with a negative port number.
  636. // Verify that build fails.
  637. config = "{ \"ip_address\": \"192.168.5.6\" ,"
  638. " \"port\": -100 }";
  639. ASSERT_TRUE(fromJSON(config));
  640. EXPECT_THROW (parser_->build(config_set_), isc::BadValue);
  641. }
  642. /// @brief Verifies that DnsServerInfo parsing creates a proper DnsServerInfo
  643. /// when given a valid combination of entries.
  644. /// It verifies that:
  645. /// 1. A DnsServerInfo entry is correctly made, when given only a hostname.
  646. /// 2. A DnsServerInfo entry is correctly made, when given ip address and port.
  647. /// 3. A DnsServerInfo entry is correctly made, when given only an ip address.
  648. TEST_F(DnsServerInfoTest, validEntry) {
  649. // Valid entries for dynamic host
  650. std::string config = "{ \"hostname\": \"pegasus.tmark\" }";
  651. ASSERT_TRUE(fromJSON(config));
  652. // Verify that it builds and commits without throwing.
  653. ASSERT_NO_THROW(parser_->build(config_set_));
  654. ASSERT_NO_THROW(parser_->commit());
  655. // Verify the correct number of servers are present
  656. int count = servers_->size();
  657. EXPECT_EQ(1, count);
  658. // Verify the server exists and has the correct values.
  659. DnsServerInfoPtr server = (*servers_)[0];
  660. EXPECT_TRUE(checkServer(server, "pegasus.tmark",
  661. DnsServerInfo::EMPTY_IP_STR,
  662. DnsServerInfo::STANDARD_DNS_PORT));
  663. // Start over for a new test.
  664. reset();
  665. // Valid entries for static ip
  666. config = " { \"ip_address\": \"127.0.0.1\" , "
  667. " \"port\": 100 }";
  668. ASSERT_TRUE(fromJSON(config));
  669. // Verify that it builds and commits without throwing.
  670. ASSERT_NO_THROW(parser_->build(config_set_));
  671. ASSERT_NO_THROW(parser_->commit());
  672. // Verify the correct number of servers are present
  673. count = servers_->size();
  674. EXPECT_EQ(1, count);
  675. // Verify the server exists and has the correct values.
  676. server = (*servers_)[0];
  677. EXPECT_TRUE(checkServer(server, "", "127.0.0.1", 100));
  678. // Start over for a new test.
  679. reset();
  680. // Valid entries for static ip, no port
  681. config = " { \"ip_address\": \"192.168.2.5\" }";
  682. ASSERT_TRUE(fromJSON(config));
  683. // Verify that it builds and commits without throwing.
  684. ASSERT_NO_THROW(parser_->build(config_set_));
  685. ASSERT_NO_THROW(parser_->commit());
  686. // Verify the correct number of servers are present
  687. count = servers_->size();
  688. EXPECT_EQ(1, count);
  689. // Verify the server exists and has the correct values.
  690. server = (*servers_)[0];
  691. EXPECT_TRUE(checkServer(server, "", "192.168.2.5",
  692. DnsServerInfo::STANDARD_DNS_PORT));
  693. }
  694. /// @brief Verifies that attempting to parse an invalid list of DnsServerInfo
  695. /// entries is detected.
  696. TEST_F(ConfigParseTest, invalidServerList) {
  697. // Construct a list of servers with an invalid server entry.
  698. std::string config = "[ { \"hostname\": \"one.tmark\" }, "
  699. "{ \"hostname\": \"\" }, "
  700. "{ \"hostname\": \"three.tmark\" } ]";
  701. ASSERT_TRUE(fromJSON(config));
  702. // Create the server storage and list parser.
  703. DnsServerInfoStoragePtr servers(new DnsServerInfoStorage());
  704. isc::dhcp::ParserPtr parser;
  705. ASSERT_NO_THROW(parser.reset(new DnsServerInfoListParser("test", servers)));
  706. // Verify that build fails.
  707. EXPECT_THROW(parser->build(config_set_), D2CfgError);
  708. }
  709. /// @brief Verifies that a list of DnsServerInfo entries parses correctly given
  710. /// a valid configuration.
  711. TEST_F(ConfigParseTest, validServerList) {
  712. // Create a valid list of servers.
  713. std::string config = "[ { \"hostname\": \"one.tmark\" }, "
  714. "{ \"hostname\": \"two.tmark\" }, "
  715. "{ \"hostname\": \"three.tmark\" } ]";
  716. ASSERT_TRUE(fromJSON(config));
  717. // Create the server storage and list parser.
  718. DnsServerInfoStoragePtr servers(new DnsServerInfoStorage());
  719. isc::dhcp::ParserPtr parser;
  720. ASSERT_NO_THROW(parser.reset(new DnsServerInfoListParser("test", servers)));
  721. // Verfiy that the list builds and commits without error.
  722. ASSERT_NO_THROW(parser->build(config_set_));
  723. ASSERT_NO_THROW(parser->commit());
  724. // Verify that the server storage contains the correct number of servers.
  725. int count = servers->size();
  726. EXPECT_EQ(3, count);
  727. // Verify the first server exists and has the correct values.
  728. DnsServerInfoPtr server = (*servers)[0];
  729. EXPECT_TRUE(checkServer(server, "one.tmark", DnsServerInfo::EMPTY_IP_STR,
  730. DnsServerInfo::STANDARD_DNS_PORT));
  731. // Verify the second server exists and has the correct values.
  732. server = (*servers)[1];
  733. EXPECT_TRUE(checkServer(server, "two.tmark", DnsServerInfo::EMPTY_IP_STR,
  734. DnsServerInfo::STANDARD_DNS_PORT));
  735. // Verify the third server exists and has the correct values.
  736. server = (*servers)[2];
  737. EXPECT_TRUE(checkServer(server, "three.tmark", DnsServerInfo::EMPTY_IP_STR,
  738. DnsServerInfo::STANDARD_DNS_PORT));
  739. }
  740. /// @brief Tests the enforcement of data validation when parsing DdnsDomains.
  741. /// It verifies that:
  742. /// 1. Domain storage cannot be null when constructing a DdnsDomainParser.
  743. /// 2. The name entry is not optional.
  744. /// 3. The server list man not be empty.
  745. /// 4. That a mal-formed server entry is detected.
  746. /// 5. That an undefined key name is detected.
  747. TEST_F(DdnsDomainTest, invalidDdnsDomainEntry) {
  748. // Verify that attempting to construct the parser with null storage fails.
  749. DdnsDomainMapPtr domains;
  750. ASSERT_THROW(isc::dhcp::ParserPtr(
  751. new DdnsDomainParser("test", domains, keys_)), D2CfgError);
  752. // Create a domain configuration without a name
  753. std::string config = "{ \"key_name\": \"d2_key.tmark.org\" , "
  754. " \"dns_servers\" : [ "
  755. " { \"ip_address\": \"127.0.0.1\" , "
  756. " \"port\": 100 },"
  757. " { \"ip_address\": \"127.0.0.2\" , "
  758. " \"port\": 200 },"
  759. " { \"ip_address\": \"127.0.0.3\" , "
  760. " \"port\": 300 } ] } ";
  761. ASSERT_TRUE(fromJSON(config));
  762. // Verify that the domain configuration builds fails.
  763. EXPECT_THROW(parser_->build(config_set_), isc::dhcp::DhcpConfigError);
  764. // Create a domain configuration with an empty server list.
  765. config = "{ \"name\": \"tmark.org\" , "
  766. " \"key_name\": \"d2_key.tmark.org\" , "
  767. " \"dns_servers\" : [ "
  768. " ] } ";
  769. ASSERT_TRUE(fromJSON(config));
  770. // Verify that the domain configuration build fails.
  771. EXPECT_THROW(parser_->build(config_set_), D2CfgError);
  772. // Create a domain configuration with a mal-formed server entry.
  773. config = "{ \"name\": \"tmark.org\" , "
  774. " \"key_name\": \"d2_key.tmark.org\" , "
  775. " \"dns_servers\" : [ "
  776. " { \"ip_address\": \"127.0.0.3\" , "
  777. " \"port\": -1 } ] } ";
  778. ASSERT_TRUE(fromJSON(config));
  779. // Verify that the domain configuration build fails.
  780. EXPECT_THROW(parser_->build(config_set_), isc::BadValue);
  781. // Create a domain configuration without an defined key name
  782. config = "{ \"name\": \"tmark.org\" , "
  783. " \"key_name\": \"d2_key.tmark.org\" , "
  784. " \"dns_servers\" : [ "
  785. " { \"ip_address\": \"127.0.0.3\" , "
  786. " \"port\": 300 } ] } ";
  787. ASSERT_TRUE(fromJSON(config));
  788. // Verify that the domain configuration build fails.
  789. EXPECT_THROW(parser_->build(config_set_), D2CfgError);
  790. }
  791. /// @brief Verifies the basics of parsing DdnsDomains.
  792. /// It verifies that:
  793. /// 1. Valid construction of DdnsDomainParser functions.
  794. /// 2. Given a valid, configuration entry, DdnsDomainParser parses
  795. /// correctly.
  796. /// (It indirectly verifies the operation of DdnsDomainMap).
  797. TEST_F(DdnsDomainTest, ddnsDomainParsing) {
  798. // Create a valid domain configuration entry containing three valid
  799. // servers.
  800. std::string config =
  801. "{ \"name\": \"tmark.org\" , "
  802. " \"key_name\": \"d2_key.tmark.org\" , "
  803. " \"dns_servers\" : [ "
  804. " { \"ip_address\": \"127.0.0.1\" , "
  805. " \"port\": 100 },"
  806. " { \"ip_address\": \"127.0.0.2\" , "
  807. " \"port\": 200 },"
  808. " { \"ip_address\": \"127.0.0.3\" , "
  809. " \"port\": 300 } ] } ";
  810. ASSERT_TRUE(fromJSON(config));
  811. // Add a TSIG key to the test key map, so key validation will pass.
  812. addKey("d2_key.tmark.org", "HMAC-MD5", "GWG/Xfbju4O2iXGqkSu4PQ==");
  813. // Verify that the domain configuration builds and commits without error.
  814. ASSERT_NO_THROW(parser_->build(config_set_));
  815. ASSERT_NO_THROW(parser_->commit());
  816. // Verify that the domain storage contains the correct number of domains.
  817. int count = domains_->size();
  818. EXPECT_EQ(1, count);
  819. // Verify that the expected domain exists and can be retrieved from
  820. // the storage.
  821. DdnsDomainMap::iterator gotit = domains_->find("tmark.org");
  822. ASSERT_TRUE(gotit != domains_->end());
  823. DdnsDomainPtr& domain = gotit->second;
  824. // Verify the name and key_name values.
  825. EXPECT_EQ("tmark.org", domain->getName());
  826. EXPECT_EQ("d2_key.tmark.org", domain->getKeyName());
  827. ASSERT_TRUE(domain->getTSIGKeyInfo());
  828. ASSERT_TRUE(domain->getTSIGKeyInfo()->getTSIGKey());
  829. // Verify that the server list exists and contains the correct number of
  830. // servers.
  831. const DnsServerInfoStoragePtr& servers = domain->getServers();
  832. EXPECT_TRUE(servers);
  833. count = servers->size();
  834. EXPECT_EQ(3, count);
  835. // Fetch each server and verify its contents.
  836. DnsServerInfoPtr server = (*servers)[0];
  837. EXPECT_TRUE(server);
  838. EXPECT_TRUE(checkServer(server, "", "127.0.0.1", 100));
  839. server = (*servers)[1];
  840. EXPECT_TRUE(server);
  841. EXPECT_TRUE(checkServer(server, "", "127.0.0.2", 200));
  842. server = (*servers)[2];
  843. EXPECT_TRUE(server);
  844. EXPECT_TRUE(checkServer(server, "", "127.0.0.3", 300));
  845. }
  846. /// @brief Tests the fundamentals of parsing DdnsDomain lists.
  847. /// This test verifies that given a valid domain list configuration
  848. /// it will accurately parse and populate each domain in the list.
  849. TEST_F(DdnsDomainTest, DdnsDomainListParsing) {
  850. // Create a valid domain list configuration, with two domains
  851. // that have three servers each.
  852. std::string config =
  853. "[ "
  854. "{ \"name\": \"tmark.org\" , "
  855. " \"key_name\": \"d2_key.tmark.org\" , "
  856. " \"dns_servers\" : [ "
  857. " { \"ip_address\": \"127.0.0.1\" , "
  858. " \"port\": 100 },"
  859. " { \"ip_address\": \"127.0.0.2\" , "
  860. " \"port\": 200 },"
  861. " { \"ip_address\": \"127.0.0.3\" , "
  862. " \"port\": 300 } ] } "
  863. ", "
  864. "{ \"name\": \"billcat.net\" , "
  865. " \"key_name\": \"d2_key.billcat.net\" , "
  866. " \"dns_servers\" : [ "
  867. " { \"ip_address\": \"127.0.0.4\" , "
  868. " \"port\": 400 },"
  869. " { \"ip_address\": \"127.0.0.5\" , "
  870. " \"port\": 500 },"
  871. " { \"ip_address\": \"127.0.0.6\" , "
  872. " \"port\": 600 } ] } "
  873. "] ";
  874. ASSERT_TRUE(fromJSON(config));
  875. // Add keys to key map so key validation passes.
  876. addKey("d2_key.tmark.org", "HMAC-MD5", "GWG/Xfbju4O2iXGqkSu4PQ==");
  877. addKey("d2_key.billcat.net", "HMAC-MD5", "GWG/Xfbju4O2iXGqkSu4PQ==");
  878. // Create the list parser
  879. isc::dhcp::ParserPtr list_parser;
  880. ASSERT_NO_THROW(list_parser.reset(
  881. new DdnsDomainListParser("test", domains_, keys_)));
  882. // Verify that the domain configuration builds and commits without error.
  883. ASSERT_NO_THROW(list_parser->build(config_set_));
  884. ASSERT_NO_THROW(list_parser->commit());
  885. // Verify that the domain storage contains the correct number of domains.
  886. int count = domains_->size();
  887. EXPECT_EQ(2, count);
  888. // Verify that the first domain exists and can be retrieved.
  889. DdnsDomainMap::iterator gotit = domains_->find("tmark.org");
  890. ASSERT_TRUE(gotit != domains_->end());
  891. DdnsDomainPtr& domain = gotit->second;
  892. // Verify the name and key_name values of the first domain.
  893. EXPECT_EQ("tmark.org", domain->getName());
  894. EXPECT_EQ("d2_key.tmark.org", domain->getKeyName());
  895. ASSERT_TRUE(domain->getTSIGKeyInfo());
  896. ASSERT_TRUE(domain->getTSIGKeyInfo()->getTSIGKey());
  897. // Verify the each of the first domain's servers
  898. DnsServerInfoStoragePtr servers = domain->getServers();
  899. EXPECT_TRUE(servers);
  900. count = servers->size();
  901. EXPECT_EQ(3, count);
  902. DnsServerInfoPtr server = (*servers)[0];
  903. EXPECT_TRUE(server);
  904. EXPECT_TRUE(checkServer(server, "", "127.0.0.1", 100));
  905. server = (*servers)[1];
  906. EXPECT_TRUE(server);
  907. EXPECT_TRUE(checkServer(server, "", "127.0.0.2", 200));
  908. server = (*servers)[2];
  909. EXPECT_TRUE(server);
  910. EXPECT_TRUE(checkServer(server, "", "127.0.0.3", 300));
  911. // Verify second domain
  912. gotit = domains_->find("billcat.net");
  913. ASSERT_TRUE(gotit != domains_->end());
  914. domain = gotit->second;
  915. // Verify the name and key_name values of the second domain.
  916. EXPECT_EQ("billcat.net", domain->getName());
  917. EXPECT_EQ("d2_key.billcat.net", domain->getKeyName());
  918. ASSERT_TRUE(domain->getTSIGKeyInfo());
  919. ASSERT_TRUE(domain->getTSIGKeyInfo()->getTSIGKey());
  920. // Verify the each of second domain's servers
  921. servers = domain->getServers();
  922. EXPECT_TRUE(servers);
  923. count = servers->size();
  924. EXPECT_EQ(3, count);
  925. server = (*servers)[0];
  926. EXPECT_TRUE(server);
  927. EXPECT_TRUE(checkServer(server, "", "127.0.0.4", 400));
  928. server = (*servers)[1];
  929. EXPECT_TRUE(server);
  930. EXPECT_TRUE(checkServer(server, "", "127.0.0.5", 500));
  931. server = (*servers)[2];
  932. EXPECT_TRUE(server);
  933. EXPECT_TRUE(checkServer(server, "", "127.0.0.6", 600));
  934. }
  935. /// @brief Tests that a domain list configuration cannot contain duplicates.
  936. TEST_F(DdnsDomainTest, duplicateDomain) {
  937. // Create a domain list configuration that contains two domains with
  938. // the same name.
  939. std::string config =
  940. "[ "
  941. "{ \"name\": \"tmark.org\" , "
  942. " \"dns_servers\" : [ "
  943. " { \"ip_address\": \"127.0.0.3\" , "
  944. " \"port\": 300 } ] } "
  945. ", "
  946. "{ \"name\": \"tmark.org\" , "
  947. " \"dns_servers\" : [ "
  948. " { \"ip_address\": \"127.0.0.3\" , "
  949. " \"port\": 300 } ] } "
  950. "] ";
  951. ASSERT_TRUE(fromJSON(config));
  952. // Create the list parser
  953. isc::dhcp::ParserPtr list_parser;
  954. ASSERT_NO_THROW(list_parser.reset(
  955. new DdnsDomainListParser("test", domains_, keys_)));
  956. // Verify that the parse build fails.
  957. EXPECT_THROW(list_parser->build(config_set_), D2CfgError);
  958. }
  959. /// @brief Tests construction of D2CfgMgr
  960. /// This test verifies that a D2CfgMgr constructs properly.
  961. TEST(D2CfgMgr, construction) {
  962. D2CfgMgr *cfg_mgr = NULL;
  963. // Verify that configuration manager constructions without error.
  964. ASSERT_NO_THROW(cfg_mgr = new D2CfgMgr());
  965. // Verify that the context can be retrieved and is not null.
  966. D2CfgContextPtr context;
  967. ASSERT_NO_THROW(context = cfg_mgr->getD2CfgContext());
  968. EXPECT_TRUE(context);
  969. // Verify that the forward manager can be retrieved and is not null.
  970. EXPECT_TRUE(context->getForwardMgr());
  971. // Verify that the reverse manager can be retrieved and is not null.
  972. EXPECT_TRUE(context->getReverseMgr());
  973. // Verify that the manager can be destructed without error.
  974. EXPECT_NO_THROW(delete cfg_mgr);
  975. }
  976. /// @brief Tests the parsing of a complete, valid DHCP-DDNS configuration.
  977. /// This tests passes the configuration into an instance of D2CfgMgr just
  978. /// as it would be done by d2_process in response to a configuration update
  979. /// event.
  980. TEST_F(D2CfgMgrTest, fullConfig) {
  981. // Create a configuration with all of application level parameters, plus
  982. // both the forward and reverse ddns managers. Both managers have two
  983. // domains with three servers per domain.
  984. std::string config = "{ "
  985. "\"ip_address\" : \"192.168.1.33\" , "
  986. "\"port\" : 88 , "
  987. " \"dns_server_timeout\": 333 , "
  988. " \"ncr_protocol\": \"UDP\" , "
  989. " \"ncr_format\": \"JSON\", "
  990. "\"tsig_keys\": ["
  991. "{"
  992. " \"name\": \"d2_key.tmark.org\" , "
  993. " \"algorithm\": \"hmac-md5\" , "
  994. " \"secret\": \"LSWXnfkKZjdPJI5QxlpnfQ==\" "
  995. "},"
  996. "{"
  997. " \"name\": \"d2_key.billcat.net\" , "
  998. " \"algorithm\": \"hmac-md5\" , "
  999. " \"secret\": \"LSWXnfkKZjdPJI5QxlpnfQ==\" "
  1000. "}"
  1001. "],"
  1002. "\"forward_ddns\" : {"
  1003. "\"ddns_domains\": [ "
  1004. "{ \"name\": \"tmark.org\" , "
  1005. " \"key_name\": \"d2_key.tmark.org\" , "
  1006. " \"dns_servers\" : [ "
  1007. " { \"hostname\": \"one.tmark\" } , "
  1008. " { \"hostname\": \"two.tmark\" } , "
  1009. " { \"hostname\": \"three.tmark\"} "
  1010. " ] } "
  1011. ", "
  1012. "{ \"name\": \"billcat.net\" , "
  1013. " \"key_name\": \"d2_key.billcat.net\" , "
  1014. " \"dns_servers\" : [ "
  1015. " { \"hostname\": \"four.billcat\" } , "
  1016. " { \"hostname\": \"five.billcat\" } , "
  1017. " { \"hostname\": \"six.billcat\" } "
  1018. " ] } "
  1019. "] },"
  1020. "\"reverse_ddns\" : {"
  1021. "\"ddns_domains\": [ "
  1022. "{ \"name\": \" 0.168.192.in.addr.arpa.\" , "
  1023. " \"key_name\": \"d2_key.tmark.org\" , "
  1024. " \"dns_servers\" : [ "
  1025. " { \"hostname\": \"one.rev\" } , "
  1026. " { \"hostname\": \"two.rev\" } , "
  1027. " { \"hostname\": \"three.rev\" } "
  1028. " ] } "
  1029. ", "
  1030. "{ \"name\": \" 0.247.106.in.addr.arpa.\" , "
  1031. " \"key_name\": \"d2_key.billcat.net\" , "
  1032. " \"dns_servers\" : [ "
  1033. " { \"hostname\": \"four.rev\" }, "
  1034. " { \"hostname\": \"five.rev\" } , "
  1035. " { \"hostname\": \"six.rev\" } "
  1036. " ] } "
  1037. "] } }";
  1038. ASSERT_TRUE(fromJSON(config));
  1039. // Verify that we can parse the configuration.
  1040. answer_ = cfg_mgr_->parseConfig(config_set_);
  1041. ASSERT_TRUE(checkAnswer(0));
  1042. // Verify that the D2 context can be retrieved and is not null.
  1043. D2CfgContextPtr context;
  1044. ASSERT_NO_THROW(context = cfg_mgr_->getD2CfgContext());
  1045. // Verify that the global scalars have the proper values.
  1046. D2ParamsPtr& d2_params = context->getD2Params();
  1047. ASSERT_TRUE(d2_params);
  1048. EXPECT_EQ(isc::asiolink::IOAddress("192.168.1.33"),
  1049. d2_params->getIpAddress());
  1050. EXPECT_EQ(88, d2_params->getPort());
  1051. EXPECT_EQ(333, d2_params->getDnsServerTimeout());
  1052. EXPECT_EQ(dhcp_ddns::NCR_UDP, d2_params->getNcrProtocol());
  1053. EXPECT_EQ(dhcp_ddns::FMT_JSON, d2_params->getNcrFormat());
  1054. // Verify that the forward manager can be retrieved.
  1055. DdnsDomainListMgrPtr mgr = context->getForwardMgr();
  1056. ASSERT_TRUE(mgr);
  1057. // Verify that the forward manager has the correct number of domains.
  1058. DdnsDomainMapPtr domains = mgr->getDomains();
  1059. ASSERT_TRUE(domains);
  1060. int count = domains->size();
  1061. EXPECT_EQ(2, count);
  1062. // Verify that the server count in each of the forward manager domains.
  1063. // NOTE that since prior tests have validated server parsing, we are are
  1064. // assuming that the servers did in fact parse correctly if the correct
  1065. // number of them are there.
  1066. DdnsDomainMapPair domain_pair;
  1067. BOOST_FOREACH(domain_pair, (*domains)) {
  1068. DdnsDomainPtr domain = domain_pair.second;
  1069. DnsServerInfoStoragePtr servers = domain->getServers();
  1070. count = servers->size();
  1071. EXPECT_TRUE(servers);
  1072. EXPECT_EQ(3, count);
  1073. }
  1074. // Verify that the reverse manager can be retrieved.
  1075. mgr = context->getReverseMgr();
  1076. ASSERT_TRUE(mgr);
  1077. // Verify that the reverse manager has the correct number of domains.
  1078. domains = mgr->getDomains();
  1079. count = domains->size();
  1080. EXPECT_EQ(2, count);
  1081. // Verify that the server count in each of the reverse manager domains.
  1082. // NOTE that since prior tests have validated server parsing, we are are
  1083. // assuming that the servers did in fact parse correctly if the correct
  1084. // number of them are there.
  1085. BOOST_FOREACH(domain_pair, (*domains)) {
  1086. DdnsDomainPtr domain = domain_pair.second;
  1087. DnsServerInfoStoragePtr servers = domain->getServers();
  1088. count = servers->size();
  1089. EXPECT_TRUE(servers);
  1090. EXPECT_EQ(3, count);
  1091. }
  1092. // Test directional update flags.
  1093. EXPECT_TRUE(cfg_mgr_->forwardUpdatesEnabled());
  1094. EXPECT_TRUE(cfg_mgr_->reverseUpdatesEnabled());
  1095. // Verify that parsing the exact same configuration a second time
  1096. // does not cause a duplicate value errors.
  1097. answer_ = cfg_mgr_->parseConfig(config_set_);
  1098. ASSERT_TRUE(checkAnswer(0));
  1099. }
  1100. /// @brief Tests the basics of the D2CfgMgr FQDN-domain matching
  1101. /// This test uses a valid configuration to exercise the D2CfgMgr
  1102. /// forward FQDN-to-domain matching.
  1103. /// It verifies that:
  1104. /// 1. Given an FQDN which exactly matches a domain's name, that domain is
  1105. /// returned as match.
  1106. /// 2. Given a FQDN for sub-domain in the list, returns the proper match.
  1107. /// 3. Given a FQDN that matches no domain name, returns the wild card domain
  1108. /// as a match.
  1109. TEST_F(D2CfgMgrTest, forwardMatch) {
  1110. // Create configuration with one domain, one sub domain, and the wild
  1111. // card.
  1112. std::string config = "{ "
  1113. "\"ip_address\" : \"192.168.1.33\" , "
  1114. "\"port\" : 88 , "
  1115. "\"tsig_keys\": [] ,"
  1116. "\"forward_ddns\" : {"
  1117. "\"ddns_domains\": [ "
  1118. "{ \"name\": \"tmark.org\" , "
  1119. " \"dns_servers\" : [ "
  1120. " { \"ip_address\": \"127.0.0.1\" } "
  1121. " ] } "
  1122. ", "
  1123. "{ \"name\": \"one.tmark.org\" , "
  1124. " \"dns_servers\" : [ "
  1125. " { \"ip_address\": \"127.0.0.2\" } "
  1126. " ] } "
  1127. ", "
  1128. "{ \"name\": \"*\" , "
  1129. " \"dns_servers\" : [ "
  1130. " { \"hostname\": \"global.net\" } "
  1131. " ] } "
  1132. "] }, "
  1133. "\"reverse_ddns\" : {} "
  1134. "}";
  1135. ASSERT_TRUE(fromJSON(config));
  1136. // Verify that we can parse the configuration.
  1137. answer_ = cfg_mgr_->parseConfig(config_set_);
  1138. ASSERT_TRUE(checkAnswer(0));
  1139. // Verify that the D2 context can be retrieved and is not null.
  1140. D2CfgContextPtr context;
  1141. ASSERT_NO_THROW(context = cfg_mgr_->getD2CfgContext());
  1142. // Test directional update flags.
  1143. EXPECT_TRUE(cfg_mgr_->forwardUpdatesEnabled());
  1144. EXPECT_FALSE(cfg_mgr_->reverseUpdatesEnabled());
  1145. DdnsDomainPtr match;
  1146. // Verify that an exact match works.
  1147. EXPECT_TRUE(cfg_mgr_->matchForward("tmark.org", match));
  1148. EXPECT_EQ("tmark.org", match->getName());
  1149. // Verify that search is case insensisitive.
  1150. EXPECT_TRUE(cfg_mgr_->matchForward("TMARK.ORG", match));
  1151. EXPECT_EQ("tmark.org", match->getName());
  1152. // Verify that an exact match works.
  1153. EXPECT_TRUE(cfg_mgr_->matchForward("one.tmark.org", match));
  1154. EXPECT_EQ("one.tmark.org", match->getName());
  1155. // Verify that a FQDN for sub-domain matches.
  1156. EXPECT_TRUE(cfg_mgr_->matchForward("blue.tmark.org", match));
  1157. EXPECT_EQ("tmark.org", match->getName());
  1158. // Verify that a FQDN for sub-domain matches.
  1159. EXPECT_TRUE(cfg_mgr_->matchForward("red.one.tmark.org", match));
  1160. EXPECT_EQ("one.tmark.org", match->getName());
  1161. // Verify that an FQDN with no match, returns the wild card domain.
  1162. EXPECT_TRUE(cfg_mgr_->matchForward("shouldbe.wildcard", match));
  1163. EXPECT_EQ("*", match->getName());
  1164. // Verify that an attempt to match an empty FQDN throws.
  1165. ASSERT_THROW(cfg_mgr_->matchForward("", match), D2CfgError);
  1166. }
  1167. /// @brief Tests domain matching when there is no wild card domain.
  1168. /// This test verifies that matches are found only for FQDNs that match
  1169. /// some or all of a domain name. FQDNs without matches should not return
  1170. /// a match.
  1171. TEST_F(D2CfgMgrTest, matchNoWildcard) {
  1172. // Create a configuration with one domain, one sub-domain, and NO wild card.
  1173. std::string config = "{ "
  1174. "\"ip_address\" : \"192.168.1.33\" , "
  1175. "\"port\" : 88 , "
  1176. "\"tsig_keys\": [] ,"
  1177. "\"forward_ddns\" : {"
  1178. "\"ddns_domains\": [ "
  1179. "{ \"name\": \"tmark.org\" , "
  1180. " \"dns_servers\" : [ "
  1181. " { \"ip_address\": \"127.0.0.1\" } "
  1182. " ] } "
  1183. ", "
  1184. "{ \"name\": \"one.tmark.org\" , "
  1185. " \"dns_servers\" : [ "
  1186. " { \"ip_address\": \"127.0.0.2\" } "
  1187. " ] } "
  1188. "] }, "
  1189. "\"reverse_ddns\" : {} "
  1190. " }";
  1191. ASSERT_TRUE(fromJSON(config));
  1192. // Verify that we can parse the configuration.
  1193. answer_ = cfg_mgr_->parseConfig(config_set_);
  1194. ASSERT_TRUE(checkAnswer(0));
  1195. // Verify that the D2 context can be retrieved and is not null.
  1196. D2CfgContextPtr context;
  1197. ASSERT_NO_THROW(context = cfg_mgr_->getD2CfgContext());
  1198. DdnsDomainPtr match;
  1199. // Verify that full or partial matches, still match.
  1200. EXPECT_TRUE(cfg_mgr_->matchForward("tmark.org", match));
  1201. EXPECT_EQ("tmark.org", match->getName());
  1202. EXPECT_TRUE(cfg_mgr_->matchForward("blue.tmark.org", match));
  1203. EXPECT_EQ("tmark.org", match->getName());
  1204. EXPECT_TRUE(cfg_mgr_->matchForward("red.one.tmark.org", match));
  1205. EXPECT_EQ("one.tmark.org", match->getName());
  1206. // Verify that a FQDN with no match, fails to match.
  1207. EXPECT_FALSE(cfg_mgr_->matchForward("shouldbe.wildcard", match));
  1208. }
  1209. /// @brief Tests domain matching when there is ONLY a wild card domain.
  1210. /// This test verifies that any FQDN matches the wild card.
  1211. TEST_F(D2CfgMgrTest, matchAll) {
  1212. std::string config = "{ "
  1213. "\"ip_address\" : \"192.168.1.33\" , "
  1214. "\"port\" : 88 , "
  1215. "\"tsig_keys\": [] ,"
  1216. "\"forward_ddns\" : {"
  1217. "\"ddns_domains\": [ "
  1218. "{ \"name\": \"*\" , "
  1219. " \"dns_servers\" : [ "
  1220. " { \"ip_address\": \"127.0.0.1\" } "
  1221. " ] } "
  1222. "] }, "
  1223. "\"reverse_ddns\" : {} "
  1224. "}";
  1225. ASSERT_TRUE(fromJSON(config));
  1226. // Verify that we can parse the configuration.
  1227. answer_ = cfg_mgr_->parseConfig(config_set_);
  1228. ASSERT_TRUE(checkAnswer(0));
  1229. // Verify that the D2 context can be retrieved and is not null.
  1230. D2CfgContextPtr context;
  1231. ASSERT_NO_THROW(context = cfg_mgr_->getD2CfgContext());
  1232. // Verify that wild card domain is returned for any FQDN.
  1233. DdnsDomainPtr match;
  1234. EXPECT_TRUE(cfg_mgr_->matchForward("tmark.org", match));
  1235. EXPECT_EQ("*", match->getName());
  1236. EXPECT_TRUE(cfg_mgr_->matchForward("shouldbe.wildcard", match));
  1237. EXPECT_EQ("*", match->getName());
  1238. // Verify that an attempt to match an empty FQDN still throws.
  1239. ASSERT_THROW(cfg_mgr_->matchReverse("", match), D2CfgError);
  1240. }
  1241. /// @brief Tests the basics of the D2CfgMgr reverse FQDN-domain matching
  1242. /// This test uses a valid configuration to exercise the D2CfgMgr's
  1243. /// reverse FQDN-to-domain matching.
  1244. /// It verifies that:
  1245. /// 1. Given an FQDN which exactly matches a domain's name, that domain is
  1246. /// returned as match.
  1247. /// 2. Given a FQDN for sub-domain in the list, returns the proper match.
  1248. /// 3. Given a FQDN that matches no domain name, returns the wild card domain
  1249. /// as a match.
  1250. TEST_F(D2CfgMgrTest, matchReverse) {
  1251. std::string config = "{ "
  1252. "\"ip_address\" : \"192.168.1.33\" , "
  1253. "\"port\" : 88 , "
  1254. "\"tsig_keys\": [] ,"
  1255. "\"forward_ddns\" : {}, "
  1256. "\"reverse_ddns\" : {"
  1257. "\"ddns_domains\": [ "
  1258. "{ \"name\": \"5.100.168.192.in-addr.arpa.\" , "
  1259. " \"dns_servers\" : [ "
  1260. " { \"ip_address\": \"127.0.0.1\" } "
  1261. " ] }, "
  1262. "{ \"name\": \"100.200.192.in-addr.arpa.\" , "
  1263. " \"dns_servers\" : [ "
  1264. " { \"ip_address\": \"127.0.0.1\" } "
  1265. " ] }, "
  1266. "{ \"name\": \"170.192.in-addr.arpa.\" , "
  1267. " \"dns_servers\" : [ "
  1268. " { \"ip_address\": \"127.0.0.1\" } "
  1269. " ] }, "
  1270. // Note mixed case to test case insensitivity.
  1271. "{ \"name\": \"2.0.3.0.8.b.d.0.1.0.0.2.IP6.ARPA.\" , "
  1272. " \"dns_servers\" : [ "
  1273. " { \"ip_address\": \"127.0.0.1\" } "
  1274. " ] },"
  1275. "{ \"name\": \"*\" , "
  1276. " \"dns_servers\" : [ "
  1277. " { \"ip_address\": \"127.0.0.1\" } "
  1278. " ] } "
  1279. "] } }";
  1280. ASSERT_TRUE(fromJSON(config));
  1281. // Verify that we can parse the configuration.
  1282. answer_ = cfg_mgr_->parseConfig(config_set_);
  1283. ASSERT_TRUE(checkAnswer(0));
  1284. // Verify that the D2 context can be retrieved and is not null.
  1285. D2CfgContextPtr context;
  1286. ASSERT_NO_THROW(context = cfg_mgr_->getD2CfgContext());
  1287. // Test directional update flags.
  1288. EXPECT_FALSE(cfg_mgr_->forwardUpdatesEnabled());
  1289. EXPECT_TRUE(cfg_mgr_->reverseUpdatesEnabled());
  1290. DdnsDomainPtr match;
  1291. // Verify an exact match.
  1292. EXPECT_TRUE(cfg_mgr_->matchReverse("192.168.100.5", match));
  1293. EXPECT_EQ("5.100.168.192.in-addr.arpa.", match->getName());
  1294. // Verify a sub-domain match.
  1295. EXPECT_TRUE(cfg_mgr_->matchReverse("192.200.100.27", match));
  1296. EXPECT_EQ("100.200.192.in-addr.arpa.", match->getName());
  1297. // Verify a sub-domain match.
  1298. EXPECT_TRUE(cfg_mgr_->matchReverse("192.170.50.30", match));
  1299. EXPECT_EQ("170.192.in-addr.arpa.", match->getName());
  1300. // Verify a wild card match.
  1301. EXPECT_TRUE(cfg_mgr_->matchReverse("1.1.1.1", match));
  1302. EXPECT_EQ("*", match->getName());
  1303. // Verify a IPv6 match.
  1304. EXPECT_TRUE(cfg_mgr_->matchReverse("2001:db8:302:99::",match));
  1305. EXPECT_EQ("2.0.3.0.8.b.d.0.1.0.0.2.IP6.ARPA.", match->getName());
  1306. // Verify a IPv6 wild card match.
  1307. EXPECT_TRUE(cfg_mgr_->matchReverse("2001:db8:99:302::",match));
  1308. EXPECT_EQ("*", match->getName());
  1309. // Verify that an attempt to match an invalid IP address throws.
  1310. ASSERT_THROW(cfg_mgr_->matchReverse("", match), D2CfgError);
  1311. }
  1312. } // end of anonymous namespace