resolver_config_unittest.cc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. // Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <config.h>
  15. #include <string>
  16. #include <boost/scoped_ptr.hpp>
  17. #include <gtest/gtest.h>
  18. #include <cc/data.h>
  19. #include <config/ccsession.h>
  20. #include <asiodns/asiodns.h>
  21. #include <asiolink/asiolink.h>
  22. #include <asiolink/io_address.h>
  23. #include <asiolink/io_socket.h>
  24. #include <asiolink/io_message.h>
  25. #include <acl/acl.h>
  26. #include <server_common/client.h>
  27. #include <resolver/resolver.h>
  28. #include <dns/tests/unittest_util.h>
  29. #include <testutils/srv_test.h>
  30. #include <testutils/portconfig.h>
  31. using namespace std;
  32. using boost::scoped_ptr;
  33. using namespace isc::acl;
  34. using isc::acl::dns::RequestContext;
  35. using namespace isc::data;
  36. using namespace isc::testutils;
  37. using namespace isc::asiodns;
  38. using namespace isc::asiolink;
  39. using namespace isc::server_common;
  40. using isc::UnitTestUtil;
  41. namespace {
  42. class ResolverConfig : public ::testing::Test {
  43. protected:
  44. IOService ios;
  45. DNSService dnss;
  46. Resolver server;
  47. scoped_ptr<const IOEndpoint> endpoint;
  48. scoped_ptr<const IOMessage> query_message;
  49. scoped_ptr<const Client> client;
  50. scoped_ptr<const RequestContext> request;
  51. ResolverConfig() : dnss(ios, NULL, NULL, NULL) {
  52. server.setDNSService(dnss);
  53. server.setConfigured();
  54. }
  55. const RequestContext& createRequest(const string& source_addr) {
  56. endpoint.reset(IOEndpoint::create(IPPROTO_UDP, IOAddress(source_addr),
  57. 53210));
  58. query_message.reset(new IOMessage(NULL, 0,
  59. IOSocket::getDummyUDPSocket(),
  60. *endpoint));
  61. client.reset(new Client(*query_message));
  62. request.reset(new RequestContext(client->getRequestSourceIPAddress(),
  63. NULL));
  64. return (*request);
  65. }
  66. void invalidTest(const string &JSON, const string& name);
  67. };
  68. TEST_F(ResolverConfig, forwardAddresses) {
  69. // Default value should be fully recursive
  70. EXPECT_TRUE(server.getForwardAddresses().empty());
  71. EXPECT_FALSE(server.isForwarding());
  72. // Try putting there some addresses
  73. vector<pair<string, uint16_t> > addresses;
  74. addresses.push_back(pair<string, uint16_t>(DEFAULT_REMOTE_ADDRESS, 53));
  75. addresses.push_back(pair<string, uint16_t>("::1", 53));
  76. server.setForwardAddresses(addresses);
  77. EXPECT_EQ(2, server.getForwardAddresses().size());
  78. EXPECT_EQ("::1", server.getForwardAddresses()[1].first);
  79. EXPECT_TRUE(server.isForwarding());
  80. // Is it independent from what we do with the vector later?
  81. addresses.clear();
  82. EXPECT_EQ(2, server.getForwardAddresses().size());
  83. // Did it return to fully recursive?
  84. server.setForwardAddresses(addresses);
  85. EXPECT_TRUE(server.getForwardAddresses().empty());
  86. EXPECT_FALSE(server.isForwarding());
  87. }
  88. TEST_F(ResolverConfig, forwardAddressConfig) {
  89. // Try putting there some address
  90. ConstElementPtr config(Element::fromJSON("{"
  91. "\"forward_addresses\": ["
  92. " {"
  93. " \"address\": \"192.0.2.1\","
  94. " \"port\": 53"
  95. " }"
  96. "]"
  97. "}"));
  98. ConstElementPtr result(server.updateConfig(config));
  99. EXPECT_EQ(result->toWire(), isc::config::createAnswer()->toWire());
  100. EXPECT_TRUE(server.isForwarding());
  101. ASSERT_EQ(1, server.getForwardAddresses().size());
  102. EXPECT_EQ("192.0.2.1", server.getForwardAddresses()[0].first);
  103. EXPECT_EQ(53, server.getForwardAddresses()[0].second);
  104. // And then remove all addresses
  105. config = Element::fromJSON("{"
  106. "\"forward_addresses\": null"
  107. "}");
  108. result = server.updateConfig(config);
  109. EXPECT_EQ(result->toWire(), isc::config::createAnswer()->toWire());
  110. EXPECT_FALSE(server.isForwarding());
  111. EXPECT_EQ(0, server.getForwardAddresses().size());
  112. }
  113. TEST_F(ResolverConfig, rootAddressConfig) {
  114. // Try putting there some address
  115. ConstElementPtr config(Element::fromJSON("{"
  116. "\"root_addresses\": ["
  117. " {"
  118. " \"address\": \"192.0.2.1\","
  119. " \"port\": 53"
  120. " }"
  121. "]"
  122. "}"));
  123. ConstElementPtr result(server.updateConfig(config));
  124. EXPECT_EQ(result->toWire(), isc::config::createAnswer()->toWire());
  125. ASSERT_EQ(1, server.getRootAddresses().size());
  126. EXPECT_EQ("192.0.2.1", server.getRootAddresses()[0].first);
  127. EXPECT_EQ(53, server.getRootAddresses()[0].second);
  128. // And then remove all addresses
  129. config = Element::fromJSON("{"
  130. "\"root_addresses\": null"
  131. "}");
  132. result = server.updateConfig(config);
  133. EXPECT_EQ(result->toWire(), isc::config::createAnswer()->toWire());
  134. EXPECT_EQ(0, server.getRootAddresses().size());
  135. }
  136. void
  137. ResolverConfig::invalidTest(const string &JSON, const string& name) {
  138. isc::testutils::portconfig::configRejected(server, JSON, name);
  139. }
  140. TEST_F(ResolverConfig, invalidForwardAddresses) {
  141. // Try torturing it with some invalid inputs
  142. invalidTest("{"
  143. "\"forward_addresses\": \"error\""
  144. "}", "Invalid type");
  145. invalidTest("{"
  146. "\"forward_addresses\": [{}]"
  147. "}", "Empty element");
  148. invalidTest("{"
  149. "\"forward_addresses\": [{"
  150. " \"port\": 1.5,"
  151. " \"address\": \"192.0.2.1\""
  152. "}]}", "Float port");
  153. invalidTest("{"
  154. "\"forward_addresses\": [{"
  155. " \"port\": -5,"
  156. " \"address\": \"192.0.2.1\""
  157. "}]}", "Negative port");
  158. invalidTest("{"
  159. "\"forward_addresses\": [{"
  160. " \"port\": 53,"
  161. " \"address\": \"bad_address\""
  162. "}]}", "Bad address");
  163. }
  164. // Try setting the addresses directly
  165. TEST_F(ResolverConfig, listenAddresses) {
  166. isc::testutils::portconfig::listenAddresses(server);
  167. }
  168. // Try setting some addresses and a rollback
  169. TEST_F(ResolverConfig, listenAddressConfig) {
  170. isc::testutils::portconfig::listenAddressConfig(server);
  171. }
  172. // Try some invalid configs are rejected
  173. TEST_F(ResolverConfig, invalidListenAddresses) {
  174. isc::testutils::portconfig::invalidListenAddressConfig(server);
  175. }
  176. // Just test it sets and gets the values correctly
  177. TEST_F(ResolverConfig, timeouts) {
  178. server.setTimeouts(0, 1, 2, 3);
  179. EXPECT_EQ(0, server.getQueryTimeout());
  180. EXPECT_EQ(1, server.getClientTimeout());
  181. EXPECT_EQ(2, server.getLookupTimeout());
  182. EXPECT_EQ(3, server.getRetries());
  183. server.setTimeouts();
  184. EXPECT_EQ(2000, server.getQueryTimeout());
  185. EXPECT_EQ(4000, server.getClientTimeout());
  186. EXPECT_EQ(30000, server.getLookupTimeout());
  187. EXPECT_EQ(3, server.getRetries());
  188. }
  189. TEST_F(ResolverConfig, timeoutsConfig) {
  190. ConstElementPtr config = Element::fromJSON("{"
  191. "\"timeout_query\": 1000,"
  192. "\"timeout_client\": 2000,"
  193. "\"timeout_lookup\": 3000,"
  194. "\"retries\": 4"
  195. "}");
  196. ConstElementPtr result(server.updateConfig(config));
  197. EXPECT_EQ(result->toWire(), isc::config::createAnswer()->toWire());
  198. EXPECT_EQ(1000, server.getQueryTimeout());
  199. EXPECT_EQ(2000, server.getClientTimeout());
  200. EXPECT_EQ(3000, server.getLookupTimeout());
  201. EXPECT_EQ(4, server.getRetries());
  202. }
  203. TEST_F(ResolverConfig, invalidTimeoutsConfig) {
  204. invalidTest("{"
  205. "\"timeout_query\": \"error\""
  206. "}", "Wrong query element type");
  207. invalidTest("{"
  208. "\"timeout_query\": -2"
  209. "}", "Negative query timeout");
  210. invalidTest("{"
  211. "\"timeout_client\": \"error\""
  212. "}", "Wrong client element type");
  213. invalidTest("{"
  214. "\"timeout_client\": -2"
  215. "}", "Negative client timeout");
  216. invalidTest("{"
  217. "\"timeout_lookup\": \"error\""
  218. "}", "Wrong lookup element type");
  219. invalidTest("{"
  220. "\"timeout_lookup\": -2"
  221. "}", "Negative lookup timeout");
  222. invalidTest("{"
  223. "\"retries\": \"error\""
  224. "}", "Wrong retries element type");
  225. invalidTest("{"
  226. "\"retries\": -1"
  227. "}", "Negative number of retries");
  228. }
  229. TEST_F(ResolverConfig, defaultQueryACL) {
  230. // If no configuration is loaded, the default ACL should reject everything.
  231. EXPECT_EQ(REJECT, server.getQueryACL().execute(createRequest("192.0.2.1")));
  232. EXPECT_EQ(REJECT, server.getQueryACL().execute(
  233. createRequest("2001:db8::1")));
  234. // The following would be allowed if the server had loaded the default
  235. // configuration from the spec file. In this context it should not have
  236. // happened, and they should be rejected just like the above cases.
  237. EXPECT_EQ(REJECT, server.getQueryACL().execute(createRequest("127.0.0.1")));
  238. EXPECT_EQ(REJECT, server.getQueryACL().execute(createRequest("::1")));
  239. }
  240. TEST_F(ResolverConfig, emptyQueryACL) {
  241. // Explicitly configured empty ACL should have the same effect.
  242. ConstElementPtr config(Element::fromJSON("{ \"query_acl\": [] }"));
  243. ConstElementPtr result(server.updateConfig(config));
  244. EXPECT_EQ(result->toWire(), isc::config::createAnswer()->toWire());
  245. EXPECT_EQ(REJECT, server.getQueryACL().execute(createRequest("192.0.2.1")));
  246. EXPECT_EQ(REJECT, server.getQueryACL().execute(
  247. createRequest("2001:db8::1")));
  248. }
  249. TEST_F(ResolverConfig, queryACLIPv4) {
  250. // A simple "accept" query for a specific IPv4 address
  251. ConstElementPtr config(Element::fromJSON(
  252. "{ \"query_acl\": "
  253. " [ {\"action\": \"ACCEPT\","
  254. " \"from\": \"192.0.2.1\"} ] }"));
  255. ConstElementPtr result(server.updateConfig(config));
  256. EXPECT_EQ(result->toWire(), isc::config::createAnswer()->toWire());
  257. EXPECT_EQ(ACCEPT, server.getQueryACL().execute(createRequest("192.0.2.1")));
  258. EXPECT_EQ(REJECT, server.getQueryACL().execute(
  259. createRequest("2001:db8::1")));
  260. }
  261. TEST_F(ResolverConfig, queryACLIPv6) {
  262. // same for IPv6
  263. ConstElementPtr config(Element::fromJSON(
  264. "{ \"query_acl\": "
  265. " [ {\"action\": \"ACCEPT\","
  266. " \"from\": \"2001:db8::1\"} ] }"));
  267. ConstElementPtr result(server.updateConfig(config));
  268. EXPECT_EQ(result->toWire(), isc::config::createAnswer()->toWire());
  269. EXPECT_EQ(REJECT, server.getQueryACL().execute(createRequest("192.0.2.1")));
  270. EXPECT_EQ(ACCEPT, server.getQueryACL().execute(
  271. createRequest("2001:db8::1")));
  272. }
  273. TEST_F(ResolverConfig, multiEntryACL) {
  274. // A bit more complicated one: mixture of IPv4 and IPv6 with 3 rules
  275. // in total. We shouldn't have to check so many variations of rules
  276. // as it should have been tested in the underlying ACL module. All we
  277. // have to do to check is a reasonably complicated ACL configuration is
  278. // loaded as expected.
  279. ConstElementPtr config(Element::fromJSON(
  280. "{ \"query_acl\": "
  281. " [ {\"action\": \"ACCEPT\","
  282. " \"from\": \"192.0.2.1\"},"
  283. " {\"action\": \"REJECT\","
  284. " \"from\": \"192.0.2.0/24\"},"
  285. " {\"action\": \"DROP\","
  286. " \"from\": \"2001:db8::1\"},"
  287. "] }"));
  288. ConstElementPtr result(server.updateConfig(config));
  289. EXPECT_EQ(result->toWire(), isc::config::createAnswer()->toWire());
  290. EXPECT_EQ(ACCEPT, server.getQueryACL().execute(createRequest("192.0.2.1")));
  291. EXPECT_EQ(REJECT, server.getQueryACL().execute(createRequest("192.0.2.2")));
  292. EXPECT_EQ(DROP, server.getQueryACL().execute(
  293. createRequest("2001:db8::1")));
  294. EXPECT_EQ(REJECT, server.getQueryACL().execute(
  295. createRequest("2001:db8::2"))); // match the default rule
  296. }
  297. int
  298. getResultCode(ConstElementPtr result) {
  299. int rcode;
  300. isc::config::parseAnswer(rcode, result);
  301. return (rcode);
  302. }
  303. TEST_F(ResolverConfig, queryACLActionOnly) {
  304. // "action only" rule will be accepted by the loader, which can
  305. // effectively change the default action.
  306. ConstElementPtr config(Element::fromJSON(
  307. "{ \"query_acl\": "
  308. " [ {\"action\": \"ACCEPT\","
  309. " \"from\": \"192.0.2.1\"},"
  310. " {\"action\": \"DROP\"} ] }"));
  311. EXPECT_EQ(0, getResultCode(server.updateConfig(config)));
  312. EXPECT_EQ(ACCEPT, server.getQueryACL().execute(createRequest("192.0.2.1")));
  313. // We reject non matching queries by default, but the last resort
  314. // rule should have changed the action in that case to "DROP".
  315. EXPECT_EQ(DROP, server.getQueryACL().execute(createRequest("192.0.2.2")));
  316. }
  317. TEST_F(ResolverConfig, badQueryACL) {
  318. // Most of these cases shouldn't happen in practice because the syntax
  319. // check should be performed before updateConfig(). But we check at
  320. // least the server code won't crash even if an unexpected input is given.
  321. // ACL must be a list
  322. EXPECT_EQ(1, getResultCode(
  323. server.updateConfig(
  324. Element::fromJSON("{ \"query_acl\": 1 }"))));
  325. // Each rule must have "action" and "from"
  326. EXPECT_EQ(1, getResultCode(
  327. server.updateConfig(
  328. Element::fromJSON("{ \"query_acl\":"
  329. " [ {\"from\": \"192.0.2.1\"} ] }"))));
  330. // invalid "action"
  331. EXPECT_EQ(1, getResultCode(
  332. server.updateConfig(
  333. Element::fromJSON("{ \"query_acl\":"
  334. " [ {\"action\": 1,"
  335. " \"from\": \"192.0.2.1\"}]}"))));
  336. EXPECT_EQ(1, getResultCode(
  337. server.updateConfig(
  338. Element::fromJSON("{ \"query_acl\":"
  339. " [ {\"action\": \"BADACTION\","
  340. " \"from\": \"192.0.2.1\"}]}"))));
  341. // invalid "from"
  342. EXPECT_EQ(1, getResultCode(
  343. server.updateConfig(
  344. Element::fromJSON("{ \"query_acl\":"
  345. " [ {\"action\": \"ACCEPT\","
  346. " \"from\": 53}]}"))));
  347. EXPECT_EQ(1, getResultCode(
  348. server.updateConfig(
  349. Element::fromJSON("{ \"query_acl\":"
  350. " [ {\"action\": \"ACCEPT\","
  351. " \"from\": \"1922.0.2.1\"}]}"))));
  352. }
  353. }