auth_srv_unittest.cc 61 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457
  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 <gtest/gtest.h>
  16. #include <dns/message.h>
  17. #include <dns/messagerenderer.h>
  18. #include <dns/name.h>
  19. #include <dns/opcode.h>
  20. #include <dns/rrclass.h>
  21. #include <dns/rrtype.h>
  22. #include <dns/rrttl.h>
  23. #include <dns/rdataclass.h>
  24. #include <dns/tsig.h>
  25. #include <server_common/portconfig.h>
  26. #include <server_common/keyring.h>
  27. #include <datasrc/memory_datasrc.h>
  28. #include <auth/auth_srv.h>
  29. #include <auth/common.h>
  30. #include <auth/statistics.h>
  31. #include <dns/tests/unittest_util.h>
  32. #include <testutils/dnsmessage_test.h>
  33. #include <testutils/srv_test.h>
  34. #include <testutils/mockups.h>
  35. #include <testutils/portconfig.h>
  36. #include <testutils/socket_request.h>
  37. #include <boost/shared_ptr.hpp>
  38. #include <boost/scoped_ptr.hpp>
  39. #include <vector>
  40. using namespace std;
  41. using namespace isc::cc;
  42. using namespace isc::dns;
  43. using namespace isc::util;
  44. using namespace isc::dns::rdata;
  45. using namespace isc::data;
  46. using namespace isc::xfr;
  47. using namespace isc::asiodns;
  48. using namespace isc::asiolink;
  49. using namespace isc::testutils;
  50. using namespace isc::server_common::portconfig;
  51. using isc::UnitTestUtil;
  52. using boost::scoped_ptr;
  53. namespace {
  54. const char* const CONFIG_TESTDB =
  55. "{\"database_file\": \"" TEST_DATA_DIR "/example.sqlite3\"}";
  56. // The following file must be non existent and must be non"creatable" (see
  57. // the sqlite3 test).
  58. const char* const BADCONFIG_TESTDB =
  59. "{ \"database_file\": \"" TEST_DATA_DIR "/nodir/notexist\"}";
  60. // This is a configuration that uses the in-memory data source containing
  61. // a signed example zone.
  62. const char* const CONFIG_INMEMORY_EXAMPLE =
  63. "{\"datasources\": [{\"type\": \"memory\","
  64. "\"zones\": [{\"origin\": \"example\","
  65. "\"file\": \"" TEST_DATA_DIR "/rfc5155-example.zone.signed\"}]}]}";
  66. class AuthSrvTest : public SrvTestBase {
  67. protected:
  68. AuthSrvTest() :
  69. dnss_(),
  70. server(true, xfrout, ddns_forwarder),
  71. rrclass(RRClass::IN()),
  72. // The empty string is expected value of the parameter of
  73. // requestSocket, not the app_name (there's no fallback, it checks
  74. // the empty string is passed).
  75. sock_requestor_(dnss_, address_store_, 53210, "")
  76. {
  77. server.setDNSService(dnss_);
  78. server.setXfrinSession(&notify_session);
  79. server.setStatisticsSession(&statistics_session);
  80. }
  81. virtual void processMessage() {
  82. // If processMessage has been called before, parse_message needs
  83. // to be reset. If it hasn't, there's no harm in doing so
  84. parse_message->clear(Message::PARSE);
  85. server.processMessage(*io_message, *parse_message, *response_obuffer,
  86. &dnsserv);
  87. }
  88. // Helper for checking Rcode statistic counters;
  89. // Checks for one specific Rcode statistics counter value
  90. void checkRcodeCounter(const Rcode& rcode, int expected_value) const {
  91. EXPECT_EQ(expected_value, server.getCounter(rcode)) <<
  92. "Expected Rcode count for " << rcode.toText() <<
  93. " " << expected_value << ", was: " <<
  94. server.getCounter(rcode);
  95. }
  96. // Checks whether all Rcode counters are set to zero
  97. void checkAllRcodeCountersZero() const {
  98. for (int i = 0; i < 17; i++) {
  99. checkRcodeCounter(Rcode(i), 0);
  100. }
  101. }
  102. // Checks whether all Rcode counters are set to zero except the given
  103. // rcode (it is checked to be set to 'value')
  104. void checkAllRcodeCountersZeroExcept(const Rcode& rcode, int value) const {
  105. for (int i = 0; i < 17; i++) {
  106. const Rcode rc(i);
  107. if (rc == rcode) {
  108. checkRcodeCounter(Rcode(i), value);
  109. } else {
  110. checkRcodeCounter(Rcode(i), 0);
  111. }
  112. }
  113. }
  114. // Convenience method for tests that expect to return SERVFAIL
  115. // It calls processMessage, checks if there is an answer, and
  116. // check the header for default SERVFAIL data
  117. void processAndCheckSERVFAIL() {
  118. processMessage();
  119. EXPECT_TRUE(dnsserv.hasAnswer());
  120. headerCheck(*parse_message, default_qid, Rcode::SERVFAIL(),
  121. opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
  122. }
  123. // Convenient shortcut of creating a simple request and having the
  124. // server process it.
  125. void createAndSendRequest(RRType req_type, Opcode opcode = Opcode::QUERY(),
  126. const Name& req_name = Name("example.com"),
  127. RRClass req_class = RRClass::IN(),
  128. int protocol = IPPROTO_UDP)
  129. {
  130. UnitTestUtil::createRequestMessage(request_message, opcode,
  131. default_qid, req_name,
  132. req_class, req_type);
  133. createRequestPacket(request_message, protocol);
  134. parse_message->clear(Message::PARSE);
  135. server.processMessage(*io_message, *parse_message, *response_obuffer,
  136. &dnsserv);
  137. }
  138. MockDNSService dnss_;
  139. MockSession statistics_session;
  140. MockXfroutClient xfrout;
  141. MockSocketSessionForwarder ddns_forwarder;
  142. AuthSrv server;
  143. const RRClass rrclass;
  144. vector<uint8_t> response_data;
  145. AddressList address_store_;
  146. TestSocketRequestor sock_requestor_;
  147. };
  148. // A helper function that builds a response to version.bind/TXT/CH that
  149. // should be identical to the response from our builtin (static) data source
  150. // by default. The resulting wire-format data will be stored in 'data'.
  151. void
  152. createBuiltinVersionResponse(const qid_t qid, vector<uint8_t>& data) {
  153. const Name version_name("version.bind");
  154. Message message(Message::RENDER);
  155. UnitTestUtil::createRequestMessage(message, Opcode::QUERY(),
  156. qid, version_name,
  157. RRClass::CH(), RRType::TXT());
  158. message.setHeaderFlag(Message::HEADERFLAG_QR);
  159. message.setHeaderFlag(Message::HEADERFLAG_AA);
  160. RRsetPtr rrset_version = RRsetPtr(new RRset(version_name, RRClass::CH(),
  161. RRType::TXT(), RRTTL(0)));
  162. rrset_version->addRdata(generic::TXT(PACKAGE_STRING));
  163. message.addRRset(Message::SECTION_ANSWER, rrset_version);
  164. RRsetPtr rrset_version_ns = RRsetPtr(new RRset(version_name, RRClass::CH(),
  165. RRType::NS(), RRTTL(0)));
  166. rrset_version_ns->addRdata(generic::NS(version_name));
  167. message.addRRset(Message::SECTION_AUTHORITY, rrset_version_ns);
  168. MessageRenderer renderer;
  169. message.toWire(renderer);
  170. data.clear();
  171. data.assign(static_cast<const uint8_t*>(renderer.getData()),
  172. static_cast<const uint8_t*>(renderer.getData()) +
  173. renderer.getLength());
  174. }
  175. // In the following tests we confirm the response data is rendered in
  176. // wire format in the expected way.
  177. // The most primitive check: checking the result of the processMessage()
  178. // method
  179. TEST_F(AuthSrvTest, builtInQuery) {
  180. UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
  181. default_qid, Name("version.bind"),
  182. RRClass::CH(), RRType::TXT());
  183. createRequestPacket(request_message, IPPROTO_UDP);
  184. server.processMessage(*io_message, *parse_message, *response_obuffer,
  185. &dnsserv);
  186. createBuiltinVersionResponse(default_qid, response_data);
  187. EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
  188. response_obuffer->getData(),
  189. response_obuffer->getLength(),
  190. &response_data[0], response_data.size());
  191. checkAllRcodeCountersZeroExcept(Rcode::NOERROR(), 1);
  192. }
  193. // Same test emulating the UDPServer class behavior (defined in libasiolink).
  194. // This is not a good test in that it assumes internal implementation details
  195. // of UDPServer, but we've encountered a regression due to the introduction
  196. // of that class, so we add a test for that case to prevent such a regression
  197. // in future.
  198. // Besides, the generalization of UDPServer is probably too much for the
  199. // authoritative only server in terms of performance, and it's quite likely
  200. // we need to drop it for the authoritative server implementation.
  201. // At that point we can drop this test, too.
  202. TEST_F(AuthSrvTest, builtInQueryViaDNSServer) {
  203. UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
  204. default_qid, Name("version.bind"),
  205. RRClass::CH(), RRType::TXT());
  206. createRequestPacket(request_message, IPPROTO_UDP);
  207. (*server.getDNSLookupProvider())(*io_message, parse_message,
  208. response_message,
  209. response_obuffer, &dnsserv);
  210. (*server.getDNSAnswerProvider())(*io_message, parse_message,
  211. response_message, response_obuffer);
  212. createBuiltinVersionResponse(default_qid, response_data);
  213. EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
  214. response_obuffer->getData(),
  215. response_obuffer->getLength(),
  216. &response_data[0], response_data.size());
  217. }
  218. // Same type of test as builtInQueryViaDNSServer but for an error response.
  219. TEST_F(AuthSrvTest, iqueryViaDNSServer) {
  220. createDataFromFile("iquery_fromWire.wire");
  221. (*server.getDNSLookupProvider())(*io_message, parse_message,
  222. response_message,
  223. response_obuffer, &dnsserv);
  224. (*server.getDNSAnswerProvider())(*io_message, parse_message,
  225. response_message, response_obuffer);
  226. UnitTestUtil::readWireData("iquery_response_fromWire.wire",
  227. response_data);
  228. EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
  229. response_obuffer->getData(),
  230. response_obuffer->getLength(),
  231. &response_data[0], response_data.size());
  232. }
  233. // Unsupported requests. Should result in NOTIMP.
  234. TEST_F(AuthSrvTest, unsupportedRequest) {
  235. unsupportedRequest();
  236. // unsupportedRequest tries 13 different opcodes
  237. checkAllRcodeCountersZeroExcept(Rcode::NOTIMP(), 13);
  238. }
  239. // Multiple questions. Should result in FORMERR.
  240. TEST_F(AuthSrvTest, multiQuestion) {
  241. multiQuestion();
  242. checkAllRcodeCountersZeroExcept(Rcode::FORMERR(), 1);
  243. }
  244. // Incoming data doesn't even contain the complete header. Must be silently
  245. // dropped.
  246. TEST_F(AuthSrvTest, shortMessage) {
  247. shortMessage();
  248. checkAllRcodeCountersZero();
  249. }
  250. // Response messages. Must be silently dropped, whether it's a valid response
  251. // or malformed or could otherwise cause a protocol error.
  252. TEST_F(AuthSrvTest, response) {
  253. response();
  254. checkAllRcodeCountersZero();
  255. }
  256. // Query with a broken question
  257. TEST_F(AuthSrvTest, shortQuestion) {
  258. shortQuestion();
  259. checkAllRcodeCountersZeroExcept(Rcode::FORMERR(), 1);
  260. }
  261. // Query with a broken answer section
  262. TEST_F(AuthSrvTest, shortAnswer) {
  263. shortAnswer();
  264. checkAllRcodeCountersZeroExcept(Rcode::FORMERR(), 1);
  265. }
  266. // Query with unsupported version of EDNS.
  267. TEST_F(AuthSrvTest, ednsBadVers) {
  268. ednsBadVers();
  269. checkAllRcodeCountersZeroExcept(Rcode::BADVERS(), 1);
  270. }
  271. TEST_F(AuthSrvTest, AXFROverUDP) {
  272. axfrOverUDP();
  273. }
  274. TEST_F(AuthSrvTest, AXFRSuccess) {
  275. EXPECT_FALSE(xfrout.isConnected());
  276. UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
  277. Name("example.com"), RRClass::IN(),
  278. RRType::AXFR());
  279. createRequestPacket(request_message, IPPROTO_TCP);
  280. // On success, the AXFR query has been passed to a separate process,
  281. // so we shouldn't have to respond.
  282. server.processMessage(*io_message, *parse_message, *response_obuffer,
  283. &dnsserv);
  284. EXPECT_FALSE(dnsserv.hasAnswer());
  285. EXPECT_TRUE(xfrout.isConnected());
  286. checkAllRcodeCountersZero();
  287. }
  288. // Try giving the server a TSIG signed request and see it can anwer signed as
  289. // well
  290. TEST_F(AuthSrvTest, TSIGSigned) {
  291. // Prepare key, the client message, etc
  292. const TSIGKey key("key:c2VjcmV0Cg==:hmac-sha1");
  293. TSIGContext context(key);
  294. UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
  295. Name("version.bind"), RRClass::CH(),
  296. RRType::TXT());
  297. createRequestPacket(request_message, IPPROTO_UDP, &context);
  298. // Run the message through the server
  299. boost::shared_ptr<TSIGKeyRing> keyring(new TSIGKeyRing);
  300. keyring->add(key);
  301. server.setTSIGKeyRing(&keyring);
  302. server.processMessage(*io_message, *parse_message, *response_obuffer,
  303. &dnsserv);
  304. // What did we get?
  305. EXPECT_TRUE(dnsserv.hasAnswer());
  306. headerCheck(*parse_message, default_qid, Rcode::NOERROR(),
  307. opcode.getCode(), QR_FLAG | AA_FLAG, 1, 1, 1, 0);
  308. // We need to parse the message ourself, or getTSIGRecord won't work
  309. InputBuffer ib(response_obuffer->getData(), response_obuffer->getLength());
  310. Message m(Message::PARSE);
  311. m.fromWire(ib);
  312. const TSIGRecord* tsig = m.getTSIGRecord();
  313. ASSERT_TRUE(tsig != NULL) << "Missing TSIG signature";
  314. TSIGError error(context.verify(tsig, response_obuffer->getData(),
  315. response_obuffer->getLength()));
  316. EXPECT_EQ(TSIGError::NOERROR(), error) <<
  317. "The server signed the response, but it doesn't seem to be valid";
  318. checkAllRcodeCountersZeroExcept(Rcode::NOERROR(), 1);
  319. }
  320. // Give the server a signed request, but don't give it the key. It will
  321. // not be able to verify it, returning BADKEY
  322. TEST_F(AuthSrvTest, TSIGSignedBadKey) {
  323. TSIGKey key("key:c2VjcmV0Cg==:hmac-sha1");
  324. TSIGContext context(key);
  325. UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
  326. Name("version.bind"), RRClass::CH(),
  327. RRType::TXT());
  328. createRequestPacket(request_message, IPPROTO_UDP, &context);
  329. // Process the message, but use a different key there
  330. boost::shared_ptr<TSIGKeyRing> keyring(new TSIGKeyRing);
  331. server.setTSIGKeyRing(&keyring);
  332. server.processMessage(*io_message, *parse_message, *response_obuffer,
  333. &dnsserv);
  334. EXPECT_TRUE(dnsserv.hasAnswer());
  335. headerCheck(*parse_message, default_qid, TSIGError::BAD_KEY().toRcode(),
  336. opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
  337. // We need to parse the message ourself, or getTSIGRecord won't work
  338. InputBuffer ib(response_obuffer->getData(), response_obuffer->getLength());
  339. Message m(Message::PARSE);
  340. m.fromWire(ib);
  341. const TSIGRecord* tsig = m.getTSIGRecord();
  342. ASSERT_TRUE(tsig != NULL) <<
  343. "Missing TSIG signature (we should have one even at error)";
  344. EXPECT_EQ(TSIGError::BAD_KEY_CODE, tsig->getRdata().getError());
  345. EXPECT_EQ(0, tsig->getRdata().getMACSize()) <<
  346. "It should be unsigned with this error";
  347. checkAllRcodeCountersZeroExcept(Rcode::NOTAUTH(), 1);
  348. }
  349. // Give the server a signed request, but signed by a different key
  350. // (with the same name). It should return BADSIG
  351. TEST_F(AuthSrvTest, TSIGBadSig) {
  352. TSIGKey key("key:c2VjcmV0Cg==:hmac-sha1");
  353. TSIGContext context(key);
  354. UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
  355. Name("version.bind"), RRClass::CH(),
  356. RRType::TXT());
  357. createRequestPacket(request_message, IPPROTO_UDP, &context);
  358. // Process the message, but use a different key there
  359. boost::shared_ptr<TSIGKeyRing> keyring(new TSIGKeyRing);
  360. keyring->add(TSIGKey("key:QkFECg==:hmac-sha1"));
  361. server.setTSIGKeyRing(&keyring);
  362. server.processMessage(*io_message, *parse_message, *response_obuffer,
  363. &dnsserv);
  364. EXPECT_TRUE(dnsserv.hasAnswer());
  365. headerCheck(*parse_message, default_qid, TSIGError::BAD_SIG().toRcode(),
  366. opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
  367. // We need to parse the message ourself, or getTSIGRecord won't work
  368. InputBuffer ib(response_obuffer->getData(), response_obuffer->getLength());
  369. Message m(Message::PARSE);
  370. m.fromWire(ib);
  371. const TSIGRecord* tsig = m.getTSIGRecord();
  372. ASSERT_TRUE(tsig != NULL) <<
  373. "Missing TSIG signature (we should have one even at error)";
  374. EXPECT_EQ(TSIGError::BAD_SIG_CODE, tsig->getRdata().getError());
  375. EXPECT_EQ(0, tsig->getRdata().getMACSize()) <<
  376. "It should be unsigned with this error";
  377. checkAllRcodeCountersZeroExcept(Rcode::NOTAUTH(), 1);
  378. }
  379. // Give the server a signed unsupported request with a bad signature.
  380. // This checks the server first verifies the signature before anything
  381. // else.
  382. TEST_F(AuthSrvTest, TSIGCheckFirst) {
  383. TSIGKey key("key:c2VjcmV0Cg==:hmac-sha1");
  384. TSIGContext context(key);
  385. // Pass a wrong opcode there. The server shouldn't know what to do
  386. // about it.
  387. UnitTestUtil::createRequestMessage(request_message, Opcode::RESERVED14(),
  388. default_qid, Name("version.bind"),
  389. RRClass::CH(), RRType::TXT());
  390. createRequestPacket(request_message, IPPROTO_UDP, &context);
  391. // Process the message, but use a different key there
  392. boost::shared_ptr<TSIGKeyRing> keyring(new TSIGKeyRing);
  393. keyring->add(TSIGKey("key:QkFECg==:hmac-sha1"));
  394. server.setTSIGKeyRing(&keyring);
  395. server.processMessage(*io_message, *parse_message, *response_obuffer,
  396. &dnsserv);
  397. EXPECT_TRUE(dnsserv.hasAnswer());
  398. headerCheck(*parse_message, default_qid, TSIGError::BAD_SIG().toRcode(),
  399. Opcode::RESERVED14().getCode(), QR_FLAG, 0, 0, 0, 0);
  400. // We need to parse the message ourself, or getTSIGRecord won't work
  401. InputBuffer ib(response_obuffer->getData(), response_obuffer->getLength());
  402. Message m(Message::PARSE);
  403. m.fromWire(ib);
  404. const TSIGRecord* tsig = m.getTSIGRecord();
  405. ASSERT_TRUE(tsig != NULL) <<
  406. "Missing TSIG signature (we should have one even at error)";
  407. EXPECT_EQ(TSIGError::BAD_SIG_CODE, tsig->getRdata().getError());
  408. EXPECT_EQ(0, tsig->getRdata().getMACSize()) <<
  409. "It should be unsigned with this error";
  410. // TSIG should have failed, and so the per opcode counter shouldn't be
  411. // incremented.
  412. EXPECT_EQ(0, server.getCounter(Opcode::RESERVED14()));
  413. checkAllRcodeCountersZeroExcept(Rcode::NOTAUTH(), 1);
  414. }
  415. TEST_F(AuthSrvTest, AXFRConnectFail) {
  416. EXPECT_FALSE(xfrout.isConnected()); // check prerequisite
  417. xfrout.disableConnect();
  418. UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
  419. Name("example.com"), RRClass::IN(),
  420. RRType::AXFR());
  421. createRequestPacket(request_message, IPPROTO_TCP);
  422. server.processMessage(*io_message, *parse_message, *response_obuffer,
  423. &dnsserv);
  424. EXPECT_TRUE(dnsserv.hasAnswer());
  425. headerCheck(*parse_message, default_qid, Rcode::SERVFAIL(),
  426. opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
  427. EXPECT_FALSE(xfrout.isConnected());
  428. }
  429. TEST_F(AuthSrvTest, AXFRSendFail) {
  430. // first send a valid query, making the connection with the xfr process
  431. // open.
  432. UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
  433. Name("example.com"), RRClass::IN(),
  434. RRType::AXFR());
  435. createRequestPacket(request_message, IPPROTO_TCP);
  436. server.processMessage(*io_message, *parse_message, *response_obuffer,
  437. &dnsserv);
  438. EXPECT_TRUE(xfrout.isConnected());
  439. xfrout.disableSend();
  440. parse_message->clear(Message::PARSE);
  441. response_obuffer->clear();
  442. UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
  443. Name("example.com"), RRClass::IN(),
  444. RRType::AXFR());
  445. createRequestPacket(request_message, IPPROTO_TCP);
  446. server.processMessage(*io_message, *parse_message, *response_obuffer,
  447. &dnsserv);
  448. EXPECT_TRUE(dnsserv.hasAnswer());
  449. headerCheck(*parse_message, default_qid, Rcode::SERVFAIL(),
  450. opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
  451. // The connection should have been closed due to the send failure.
  452. EXPECT_FALSE(xfrout.isConnected());
  453. }
  454. TEST_F(AuthSrvTest, AXFRDisconnectFail) {
  455. // In our usage disconnect() shouldn't fail. But even if it does,
  456. // it should not disrupt service (so processMessage should have caught it)
  457. xfrout.disableSend();
  458. xfrout.disableDisconnect();
  459. UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
  460. Name("example.com"), RRClass::IN(),
  461. RRType::AXFR());
  462. createRequestPacket(request_message, IPPROTO_TCP);
  463. EXPECT_NO_THROW(server.processMessage(*io_message, *parse_message,
  464. *response_obuffer, &dnsserv));
  465. // Since the disconnect failed, we should still be 'connected'
  466. EXPECT_TRUE(xfrout.isConnected());
  467. // XXX: we need to re-enable disconnect. otherwise an exception would be
  468. // thrown via the destructor of the server.
  469. xfrout.enableDisconnect();
  470. }
  471. TEST_F(AuthSrvTest, IXFRConnectFail) {
  472. EXPECT_FALSE(xfrout.isConnected()); // check prerequisite
  473. xfrout.disableConnect();
  474. UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
  475. Name("example.com"), RRClass::IN(),
  476. RRType::IXFR());
  477. createRequestPacket(request_message, IPPROTO_TCP);
  478. server.processMessage(*io_message, *parse_message, *response_obuffer,
  479. &dnsserv);
  480. EXPECT_TRUE(dnsserv.hasAnswer());
  481. headerCheck(*parse_message, default_qid, Rcode::SERVFAIL(),
  482. opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
  483. EXPECT_FALSE(xfrout.isConnected());
  484. }
  485. TEST_F(AuthSrvTest, IXFRSendFail) {
  486. // first send a valid query, making the connection with the xfr process
  487. // open.
  488. UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
  489. Name("example.com"), RRClass::IN(),
  490. RRType::IXFR());
  491. createRequestPacket(request_message, IPPROTO_TCP);
  492. server.processMessage(*io_message, *parse_message, *response_obuffer,
  493. &dnsserv);
  494. EXPECT_TRUE(xfrout.isConnected());
  495. xfrout.disableSend();
  496. parse_message->clear(Message::PARSE);
  497. response_obuffer->clear();
  498. UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
  499. Name("example.com"), RRClass::IN(),
  500. RRType::IXFR());
  501. createRequestPacket(request_message, IPPROTO_TCP);
  502. server.processMessage(*io_message, *parse_message, *response_obuffer,
  503. &dnsserv);
  504. EXPECT_TRUE(dnsserv.hasAnswer());
  505. headerCheck(*parse_message, default_qid, Rcode::SERVFAIL(),
  506. opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
  507. // The connection should have been closed due to the send failure.
  508. EXPECT_FALSE(xfrout.isConnected());
  509. }
  510. TEST_F(AuthSrvTest, IXFRDisconnectFail) {
  511. // In our usage disconnect() shouldn't fail, but even if it does,
  512. // procesMessage() should catch it.
  513. xfrout.disableSend();
  514. xfrout.disableDisconnect();
  515. UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
  516. Name("example.com"), RRClass::IN(),
  517. RRType::IXFR());
  518. createRequestPacket(request_message, IPPROTO_TCP);
  519. EXPECT_NO_THROW(server.processMessage(*io_message, *parse_message,
  520. *response_obuffer, &dnsserv));
  521. EXPECT_TRUE(xfrout.isConnected());
  522. // XXX: we need to re-enable disconnect. otherwise an exception would be
  523. // thrown via the destructor of the server.
  524. xfrout.enableDisconnect();
  525. }
  526. TEST_F(AuthSrvTest, notify) {
  527. UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
  528. default_qid, Name("example.com"),
  529. RRClass::IN(), RRType::SOA());
  530. request_message.setHeaderFlag(Message::HEADERFLAG_AA);
  531. createRequestPacket(request_message, IPPROTO_UDP);
  532. server.processMessage(*io_message, *parse_message, *response_obuffer,
  533. &dnsserv);
  534. EXPECT_TRUE(dnsserv.hasAnswer());
  535. // An internal command message should have been created and sent to an
  536. // external module. Check them.
  537. EXPECT_EQ("Zonemgr", notify_session.getMessageDest());
  538. EXPECT_EQ("notify",
  539. notify_session.getSentMessage()->get("command")->get(0)->stringValue());
  540. ConstElementPtr notify_args =
  541. notify_session.getSentMessage()->get("command")->get(1);
  542. EXPECT_EQ("example.com.", notify_args->get("zone_name")->stringValue());
  543. EXPECT_EQ(DEFAULT_REMOTE_ADDRESS,
  544. notify_args->get("master")->stringValue());
  545. EXPECT_EQ("IN", notify_args->get("zone_class")->stringValue());
  546. // On success, the server should return a response to the notify.
  547. headerCheck(*parse_message, default_qid, Rcode::NOERROR(),
  548. Opcode::NOTIFY().getCode(), QR_FLAG | AA_FLAG, 1, 0, 0, 0);
  549. // The question must be identical to that of the received notify
  550. ConstQuestionPtr question = *parse_message->beginQuestion();
  551. EXPECT_EQ(Name("example.com"), question->getName());
  552. EXPECT_EQ(RRClass::IN(), question->getClass());
  553. EXPECT_EQ(RRType::SOA(), question->getType());
  554. checkAllRcodeCountersZeroExcept(Rcode::NOERROR(), 1);
  555. }
  556. TEST_F(AuthSrvTest, notifyForCHClass) {
  557. // Same as the previous test, but for the CH RRClass.
  558. UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
  559. default_qid, Name("example.com"),
  560. RRClass::CH(), RRType::SOA());
  561. request_message.setHeaderFlag(Message::HEADERFLAG_AA);
  562. createRequestPacket(request_message, IPPROTO_UDP);
  563. server.processMessage(*io_message, *parse_message, *response_obuffer,
  564. &dnsserv);
  565. EXPECT_TRUE(dnsserv.hasAnswer());
  566. // Other conditions should be the same, so simply confirm the RR class is
  567. // set correctly.
  568. ConstElementPtr notify_args =
  569. notify_session.getSentMessage()->get("command")->get(1);
  570. EXPECT_EQ("CH", notify_args->get("zone_class")->stringValue());
  571. }
  572. TEST_F(AuthSrvTest, notifyEmptyQuestion) {
  573. request_message.clear(Message::RENDER);
  574. request_message.setOpcode(Opcode::NOTIFY());
  575. request_message.setRcode(Rcode::NOERROR());
  576. request_message.setHeaderFlag(Message::HEADERFLAG_AA);
  577. request_message.setQid(default_qid);
  578. request_message.toWire(request_renderer);
  579. createRequestPacket(request_message, IPPROTO_UDP);
  580. server.processMessage(*io_message, *parse_message, *response_obuffer,
  581. &dnsserv);
  582. EXPECT_TRUE(dnsserv.hasAnswer());
  583. headerCheck(*parse_message, default_qid, Rcode::FORMERR(),
  584. Opcode::NOTIFY().getCode(), QR_FLAG, 0, 0, 0, 0);
  585. }
  586. TEST_F(AuthSrvTest, notifyMultiQuestions) {
  587. UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
  588. default_qid, Name("example.com"),
  589. RRClass::IN(), RRType::SOA());
  590. // add one more SOA question
  591. request_message.addQuestion(Question(Name("example.com"), RRClass::IN(),
  592. RRType::SOA()));
  593. request_message.setHeaderFlag(Message::HEADERFLAG_AA);
  594. createRequestPacket(request_message, IPPROTO_UDP);
  595. server.processMessage(*io_message, *parse_message, *response_obuffer,
  596. &dnsserv);
  597. EXPECT_TRUE(dnsserv.hasAnswer());
  598. headerCheck(*parse_message, default_qid, Rcode::FORMERR(),
  599. Opcode::NOTIFY().getCode(), QR_FLAG, 2, 0, 0, 0);
  600. }
  601. TEST_F(AuthSrvTest, notifyNonSOAQuestion) {
  602. UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
  603. default_qid, Name("example.com"),
  604. RRClass::IN(), RRType::NS());
  605. request_message.setHeaderFlag(Message::HEADERFLAG_AA);
  606. createRequestPacket(request_message, IPPROTO_UDP);
  607. server.processMessage(*io_message, *parse_message, *response_obuffer,
  608. &dnsserv);
  609. EXPECT_TRUE(dnsserv.hasAnswer());
  610. headerCheck(*parse_message, default_qid, Rcode::FORMERR(),
  611. Opcode::NOTIFY().getCode(), QR_FLAG, 1, 0, 0, 0);
  612. }
  613. TEST_F(AuthSrvTest, notifyWithoutAA) {
  614. // implicitly leave the AA bit off. our implementation will accept it.
  615. UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
  616. default_qid, Name("example.com"),
  617. RRClass::IN(), RRType::SOA());
  618. createRequestPacket(request_message, IPPROTO_UDP);
  619. server.processMessage(*io_message, *parse_message, *response_obuffer,
  620. &dnsserv);
  621. EXPECT_TRUE(dnsserv.hasAnswer());
  622. headerCheck(*parse_message, default_qid, Rcode::NOERROR(),
  623. Opcode::NOTIFY().getCode(), QR_FLAG | AA_FLAG, 1, 0, 0, 0);
  624. }
  625. TEST_F(AuthSrvTest, notifyWithErrorRcode) {
  626. UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
  627. default_qid, Name("example.com"),
  628. RRClass::IN(), RRType::SOA());
  629. request_message.setHeaderFlag(Message::HEADERFLAG_AA);
  630. request_message.setRcode(Rcode::SERVFAIL());
  631. createRequestPacket(request_message, IPPROTO_UDP);
  632. server.processMessage(*io_message, *parse_message, *response_obuffer,
  633. &dnsserv);
  634. EXPECT_TRUE(dnsserv.hasAnswer());
  635. headerCheck(*parse_message, default_qid, Rcode::NOERROR(),
  636. Opcode::NOTIFY().getCode(), QR_FLAG | AA_FLAG, 1, 0, 0, 0);
  637. }
  638. TEST_F(AuthSrvTest, notifyWithoutSession) {
  639. server.setXfrinSession(NULL);
  640. UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
  641. default_qid, Name("example.com"),
  642. RRClass::IN(), RRType::SOA());
  643. request_message.setHeaderFlag(Message::HEADERFLAG_AA);
  644. createRequestPacket(request_message, IPPROTO_UDP);
  645. // we simply ignore the notify and let it be resent if an internal error
  646. // happens.
  647. server.processMessage(*io_message, *parse_message, *response_obuffer,
  648. &dnsserv);
  649. EXPECT_FALSE(dnsserv.hasAnswer());
  650. }
  651. TEST_F(AuthSrvTest, notifySendFail) {
  652. notify_session.disableSend();
  653. UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
  654. default_qid, Name("example.com"),
  655. RRClass::IN(), RRType::SOA());
  656. request_message.setHeaderFlag(Message::HEADERFLAG_AA);
  657. createRequestPacket(request_message, IPPROTO_UDP);
  658. server.processMessage(*io_message, *parse_message, *response_obuffer,
  659. &dnsserv);
  660. EXPECT_FALSE(dnsserv.hasAnswer());
  661. }
  662. TEST_F(AuthSrvTest, notifyReceiveFail) {
  663. notify_session.disableReceive();
  664. UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
  665. default_qid, Name("example.com"),
  666. RRClass::IN(), RRType::SOA());
  667. request_message.setHeaderFlag(Message::HEADERFLAG_AA);
  668. createRequestPacket(request_message, IPPROTO_UDP);
  669. server.processMessage(*io_message, *parse_message, *response_obuffer,
  670. &dnsserv);
  671. EXPECT_FALSE(dnsserv.hasAnswer());
  672. }
  673. TEST_F(AuthSrvTest, notifyWithBogusSessionMessage) {
  674. notify_session.setMessage(Element::fromJSON("{\"foo\": 1}"));
  675. UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
  676. default_qid, Name("example.com"),
  677. RRClass::IN(), RRType::SOA());
  678. request_message.setHeaderFlag(Message::HEADERFLAG_AA);
  679. createRequestPacket(request_message, IPPROTO_UDP);
  680. server.processMessage(*io_message, *parse_message, *response_obuffer,
  681. &dnsserv);
  682. EXPECT_FALSE(dnsserv.hasAnswer());
  683. }
  684. TEST_F(AuthSrvTest, notifyWithSessionMessageError) {
  685. notify_session.setMessage(
  686. Element::fromJSON("{\"result\": [1, \"FAIL\"]}"));
  687. UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
  688. default_qid, Name("example.com"),
  689. RRClass::IN(), RRType::SOA());
  690. request_message.setHeaderFlag(Message::HEADERFLAG_AA);
  691. createRequestPacket(request_message, IPPROTO_UDP);
  692. server.processMessage(*io_message, *parse_message, *response_obuffer,
  693. &dnsserv);
  694. EXPECT_FALSE(dnsserv.hasAnswer());
  695. }
  696. void
  697. updateConfig(AuthSrv* server, const char* const config_data,
  698. const bool expect_success)
  699. {
  700. ConstElementPtr config_answer =
  701. server->updateConfig(Element::fromJSON(config_data));
  702. EXPECT_EQ(Element::map, config_answer->getType());
  703. EXPECT_TRUE(config_answer->contains("result"));
  704. ConstElementPtr result = config_answer->get("result");
  705. EXPECT_EQ(Element::list, result->getType());
  706. EXPECT_EQ(expect_success ? 0 : 1, result->get(0)->intValue()) <<
  707. "Bad result from updateConfig: " << result->str();
  708. }
  709. // Install a Sqlite3 data source with testing data.
  710. TEST_F(AuthSrvTest, updateConfig) {
  711. updateConfig(&server, CONFIG_TESTDB, true);
  712. // query for existent data in the installed data source. The resulting
  713. // response should have the AA flag on, and have an RR in each answer
  714. // and authority section.
  715. createDataFromFile("examplequery_fromWire.wire");
  716. server.processMessage(*io_message, *parse_message, *response_obuffer,
  717. &dnsserv);
  718. EXPECT_TRUE(dnsserv.hasAnswer());
  719. headerCheck(*parse_message, default_qid, Rcode::NOERROR(), opcode.getCode(),
  720. QR_FLAG | AA_FLAG, 1, 1, 1, 0);
  721. }
  722. TEST_F(AuthSrvTest, datasourceFail) {
  723. updateConfig(&server, CONFIG_TESTDB, true);
  724. // This query will hit a corrupted entry of the data source (the zoneload
  725. // tool and the data source itself naively accept it). This will result
  726. // in a SERVFAIL response, and the answer and authority sections should
  727. // be empty.
  728. createDataFromFile("badExampleQuery_fromWire.wire");
  729. server.processMessage(*io_message, *parse_message, *response_obuffer,
  730. &dnsserv);
  731. EXPECT_TRUE(dnsserv.hasAnswer());
  732. headerCheck(*parse_message, default_qid, Rcode::SERVFAIL(),
  733. opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
  734. }
  735. TEST_F(AuthSrvTest, updateConfigFail) {
  736. // First, load a valid data source.
  737. updateConfig(&server, CONFIG_TESTDB, true);
  738. // Next, try to update it with a non-existent one. This should fail.
  739. updateConfig(&server, BADCONFIG_TESTDB, false);
  740. // The original data source should still exist.
  741. createDataFromFile("examplequery_fromWire.wire");
  742. server.processMessage(*io_message, *parse_message, *response_obuffer,
  743. &dnsserv);
  744. EXPECT_TRUE(dnsserv.hasAnswer());
  745. headerCheck(*parse_message, default_qid, Rcode::NOERROR(), opcode.getCode(),
  746. QR_FLAG | AA_FLAG, 1, 1, 1, 0);
  747. }
  748. TEST_F(AuthSrvTest, updateWithInMemoryClient) {
  749. // Test configuring memory data source. Detailed test cases are covered
  750. // in the configuration tests. We only check the AuthSrv interface here.
  751. // By default memory data source isn't enabled
  752. EXPECT_EQ(AuthSrv::InMemoryClientPtr(), server.getInMemoryClient(rrclass));
  753. updateConfig(&server,
  754. "{\"datasources\": [{\"type\": \"memory\"}]}", true);
  755. // after successful configuration, we should have one (with empty zoneset).
  756. ASSERT_NE(AuthSrv::InMemoryClientPtr(), server.getInMemoryClient(rrclass));
  757. EXPECT_EQ(0, server.getInMemoryClient(rrclass)->getZoneCount());
  758. // The memory data source is empty, should return REFUSED rcode.
  759. createDataFromFile("examplequery_fromWire.wire");
  760. server.processMessage(*io_message, *parse_message, *response_obuffer,
  761. &dnsserv);
  762. EXPECT_TRUE(dnsserv.hasAnswer());
  763. headerCheck(*parse_message, default_qid, Rcode::REFUSED(),
  764. opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
  765. }
  766. TEST_F(AuthSrvTest, queryWithInMemoryClientNoDNSSEC) {
  767. // In this example, we do simple check that query is handled from the
  768. // query handler class, and confirm it returns no error and a non empty
  769. // answer section. Detailed examination on the response content
  770. // for various types of queries are tested in the query tests.
  771. updateConfig(&server, CONFIG_INMEMORY_EXAMPLE, true);
  772. ASSERT_NE(AuthSrv::InMemoryClientPtr(), server.getInMemoryClient(rrclass));
  773. EXPECT_EQ(1, server.getInMemoryClient(rrclass)->getZoneCount());
  774. createDataFromFile("nsec3query_nodnssec_fromWire.wire");
  775. server.processMessage(*io_message, *parse_message, *response_obuffer,
  776. &dnsserv);
  777. EXPECT_TRUE(dnsserv.hasAnswer());
  778. headerCheck(*parse_message, default_qid, Rcode::NOERROR(),
  779. opcode.getCode(), QR_FLAG | AA_FLAG, 1, 1, 2, 1);
  780. }
  781. TEST_F(AuthSrvTest, queryWithInMemoryClientDNSSEC) {
  782. // Similar to the previous test, but the query has the DO bit on.
  783. // The response should contain RRSIGs, and should have more RRs than
  784. // the previous case.
  785. updateConfig(&server, CONFIG_INMEMORY_EXAMPLE, true);
  786. ASSERT_NE(AuthSrv::InMemoryClientPtr(), server.getInMemoryClient(rrclass));
  787. EXPECT_EQ(1, server.getInMemoryClient(rrclass)->getZoneCount());
  788. createDataFromFile("nsec3query_fromWire.wire");
  789. server.processMessage(*io_message, *parse_message, *response_obuffer,
  790. &dnsserv);
  791. EXPECT_TRUE(dnsserv.hasAnswer());
  792. headerCheck(*parse_message, default_qid, Rcode::NOERROR(),
  793. opcode.getCode(), QR_FLAG | AA_FLAG, 1, 2, 3, 3);
  794. }
  795. TEST_F(AuthSrvTest, chQueryWithInMemoryClient) {
  796. // Configure memory data source for class IN
  797. updateConfig(&server, "{\"datasources\": "
  798. "[{\"class\": \"IN\", \"type\": \"memory\"}]}", true);
  799. // This shouldn't affect the result of class CH query
  800. UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
  801. default_qid, Name("version.bind"),
  802. RRClass::CH(), RRType::TXT());
  803. createRequestPacket(request_message, IPPROTO_UDP);
  804. server.processMessage(*io_message, *parse_message, *response_obuffer,
  805. &dnsserv);
  806. EXPECT_TRUE(dnsserv.hasAnswer());
  807. headerCheck(*parse_message, default_qid, Rcode::NOERROR(),
  808. opcode.getCode(), QR_FLAG | AA_FLAG, 1, 1, 1, 0);
  809. }
  810. TEST_F(AuthSrvTest, cacheSlots) {
  811. // simple check for the get/set operations
  812. server.setCacheSlots(10); // 10 = arbitrary choice
  813. EXPECT_EQ(10, server.getCacheSlots());
  814. // 0 is a valid size
  815. server.setCacheSlots(0);
  816. EXPECT_EQ(00, server.getCacheSlots());
  817. }
  818. // Submit UDP normal query and check query counter
  819. TEST_F(AuthSrvTest, queryCounterUDPNormal) {
  820. // The counter should be initialized to 0.
  821. EXPECT_EQ(0, server.getCounter(AuthCounters::SERVER_UDP_QUERY));
  822. // Create UDP message and process.
  823. UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
  824. default_qid, Name("example.com"),
  825. RRClass::IN(), RRType::NS());
  826. createRequestPacket(request_message, IPPROTO_UDP);
  827. server.processMessage(*io_message, *parse_message, *response_obuffer,
  828. &dnsserv);
  829. // After processing UDP query, the counter should be 1.
  830. EXPECT_EQ(1, server.getCounter(AuthCounters::SERVER_UDP_QUERY));
  831. // The counter for opcode Query should also be one
  832. EXPECT_EQ(1, server.getCounter(Opcode::QUERY()));
  833. // The counter for REFUSED responses should also be one, the rest zero
  834. checkAllRcodeCountersZeroExcept(Rcode::REFUSED(), 1);
  835. }
  836. // Submit TCP normal query and check query counter
  837. TEST_F(AuthSrvTest, queryCounterTCPNormal) {
  838. // The counter should be initialized to 0.
  839. EXPECT_EQ(0, server.getCounter(AuthCounters::SERVER_TCP_QUERY));
  840. // Create TCP message and process.
  841. UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
  842. default_qid, Name("example.com"),
  843. RRClass::IN(), RRType::NS());
  844. createRequestPacket(request_message, IPPROTO_TCP);
  845. server.processMessage(*io_message, *parse_message, *response_obuffer,
  846. &dnsserv);
  847. // After processing TCP query, the counter should be 1.
  848. EXPECT_EQ(1, server.getCounter(AuthCounters::SERVER_TCP_QUERY));
  849. // The counter for SUCCESS responses should also be one
  850. EXPECT_EQ(1, server.getCounter(Opcode::QUERY()));
  851. // The counter for REFUSED responses should also be one, the rest zero
  852. checkAllRcodeCountersZeroExcept(Rcode::REFUSED(), 1);
  853. }
  854. // Submit TCP AXFR query and check query counter
  855. TEST_F(AuthSrvTest, queryCounterTCPAXFR) {
  856. // The counter should be initialized to 0.
  857. EXPECT_EQ(0, server.getCounter(AuthCounters::SERVER_TCP_QUERY));
  858. UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
  859. Name("example.com"), RRClass::IN(), RRType::AXFR());
  860. createRequestPacket(request_message, IPPROTO_TCP);
  861. // On success, the AXFR query has been passed to a separate process,
  862. // so auth itself shouldn't respond.
  863. server.processMessage(*io_message, *parse_message, *response_obuffer,
  864. &dnsserv);
  865. EXPECT_FALSE(dnsserv.hasAnswer());
  866. // After processing TCP AXFR query, the counter should be 1.
  867. EXPECT_EQ(1, server.getCounter(AuthCounters::SERVER_TCP_QUERY));
  868. // No rcodes should be incremented
  869. checkAllRcodeCountersZero();
  870. }
  871. // Submit TCP IXFR query and check query counter
  872. TEST_F(AuthSrvTest, queryCounterTCPIXFR) {
  873. // The counter should be initialized to 0.
  874. EXPECT_EQ(0, server.getCounter(AuthCounters::SERVER_TCP_QUERY));
  875. UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
  876. Name("example.com"), RRClass::IN(), RRType::IXFR());
  877. createRequestPacket(request_message, IPPROTO_TCP);
  878. // On success, the IXFR query has been passed to a separate process,
  879. // so auth itself shouldn't respond.
  880. server.processMessage(*io_message, *parse_message, *response_obuffer,
  881. &dnsserv);
  882. EXPECT_FALSE(dnsserv.hasAnswer());
  883. // After processing TCP IXFR query, the counter should be 1.
  884. EXPECT_EQ(1, server.getCounter(AuthCounters::SERVER_TCP_QUERY));
  885. }
  886. TEST_F(AuthSrvTest, queryCounterOpcodes) {
  887. for (int i = 0; i < 16; ++i) {
  888. // The counter should be initialized to 0.
  889. EXPECT_EQ(0, server.getCounter(Opcode(i)));
  890. // For each possible opcode, create a request message and send it
  891. UnitTestUtil::createRequestMessage(request_message, Opcode(i),
  892. default_qid, Name("example.com"),
  893. RRClass::IN(), RRType::NS());
  894. createRequestPacket(request_message, IPPROTO_UDP);
  895. // "send" the request N-th times where N is i + 1 for i-th code.
  896. // we intentionally use different values for each code
  897. for (int j = 0; j <= i; ++j) {
  898. parse_message->clear(Message::PARSE);
  899. server.processMessage(*io_message, *parse_message,
  900. *response_obuffer,
  901. &dnsserv);
  902. }
  903. // Confirm the counter.
  904. EXPECT_EQ(i + 1, server.getCounter(Opcode(i)));
  905. }
  906. }
  907. // class for queryCounterUnexpected test
  908. // getProtocol() returns IPPROTO_IP
  909. class DummyUnknownSocket : public IOSocket {
  910. public:
  911. DummyUnknownSocket() {}
  912. virtual int getNative() const { return (0); }
  913. virtual int getProtocol() const { return (IPPROTO_IP); }
  914. };
  915. // function for queryCounterUnexpected test
  916. // returns a reference to a static object of DummyUnknownSocket
  917. IOSocket&
  918. getDummyUnknownSocket() {
  919. static DummyUnknownSocket socket;
  920. return (socket);
  921. }
  922. // Submit unexpected type of query and check it is ignored
  923. TEST_F(AuthSrvTest, queryCounterUnexpected) {
  924. // This code isn't exception safe, but we'd rather keep the code
  925. // simpler and more readable as this is only for tests
  926. // Create UDP query packet.
  927. UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
  928. default_qid, Name("example.com"),
  929. RRClass::IN(), RRType::NS());
  930. createRequestPacket(request_message, IPPROTO_UDP);
  931. // Modify the message.
  932. delete io_message;
  933. endpoint = IOEndpoint::create(IPPROTO_UDP,
  934. IOAddress(DEFAULT_REMOTE_ADDRESS), 53210);
  935. io_message = new IOMessage(request_renderer.getData(),
  936. request_renderer.getLength(),
  937. getDummyUnknownSocket(), *endpoint);
  938. EXPECT_FALSE(dnsserv.hasAnswer());
  939. }
  940. TEST_F(AuthSrvTest, stop) {
  941. // normal case is covered in command_unittest.cc. we should primarily
  942. // test it here, but the current design of the stop test takes time,
  943. // so we consolidate the cases in the command tests.
  944. // If/when the interval timer has finer granularity we'll probably add
  945. // our own tests here, so we keep this empty test case.
  946. }
  947. TEST_F(AuthSrvTest, listenAddresses) {
  948. isc::testutils::portconfig::listenAddresses(server);
  949. // Check it requests the correct addresses
  950. const char* tokens[] = {
  951. "TCP:127.0.0.1:53210:1",
  952. "UDP:127.0.0.1:53210:2",
  953. "TCP:::1:53210:3",
  954. "UDP:::1:53210:4",
  955. NULL
  956. };
  957. sock_requestor_.checkTokens(tokens, sock_requestor_.given_tokens_,
  958. "Given tokens");
  959. // It returns back to empty set of addresses afterwards, so
  960. // they should be released
  961. sock_requestor_.checkTokens(tokens, sock_requestor_.released_tokens_,
  962. "Released tokens");
  963. }
  964. TEST_F(AuthSrvTest, processNormalQuery_reuseRenderer1) {
  965. UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
  966. default_qid, Name("example.com"),
  967. RRClass::IN(), RRType::NS());
  968. request_message.setHeaderFlag(Message::HEADERFLAG_AA);
  969. createRequestPacket(request_message, IPPROTO_UDP);
  970. server.processMessage(*io_message, *parse_message, *response_obuffer,
  971. &dnsserv);
  972. EXPECT_NE(request_message.getRcode(), parse_message->getRcode());
  973. }
  974. TEST_F(AuthSrvTest, processNormalQuery_reuseRenderer2) {
  975. UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
  976. default_qid, Name("example.com"),
  977. RRClass::IN(), RRType::SOA());
  978. request_message.setHeaderFlag(Message::HEADERFLAG_AA);
  979. createRequestPacket(request_message, IPPROTO_UDP);
  980. server.processMessage(*io_message, *parse_message, *response_obuffer,
  981. &dnsserv);
  982. ConstQuestionPtr question = *parse_message->beginQuestion();
  983. EXPECT_STRNE(question->getType().toText().c_str(),
  984. RRType::NS().toText().c_str());
  985. }
  986. //
  987. // Tests for catching exceptions in various stages of the query processing
  988. //
  989. // These tests work by defining two proxy classes, that act as an in-memory
  990. // client by default, but can throw exceptions at various points.
  991. //
  992. namespace {
  993. /// A the possible methods to throw in, either in FakeInMemoryClient or
  994. /// FakeZoneFinder
  995. enum ThrowWhen {
  996. THROW_NEVER,
  997. THROW_AT_FIND_ZONE,
  998. THROW_AT_GET_ORIGIN,
  999. THROW_AT_GET_CLASS,
  1000. THROW_AT_FIND,
  1001. THROW_AT_FIND_ALL,
  1002. THROW_AT_FIND_NSEC3
  1003. };
  1004. /// convenience function to check whether and what to throw
  1005. void
  1006. checkThrow(ThrowWhen method, ThrowWhen throw_at, bool isc_exception) {
  1007. if (method == throw_at) {
  1008. if (isc_exception) {
  1009. isc_throw(isc::Exception, "foo");
  1010. } else {
  1011. throw std::exception();
  1012. }
  1013. }
  1014. }
  1015. /// \brief proxy class for the ZoneFinder returned by the InMemoryClient
  1016. /// proxied by FakeInMemoryClient
  1017. ///
  1018. /// See the documentation for FakeInMemoryClient for more information,
  1019. /// all methods simply check whether they should throw, and if not, call
  1020. /// their proxied equivalent.
  1021. class FakeZoneFinder : public isc::datasrc::ZoneFinder {
  1022. public:
  1023. FakeZoneFinder(isc::datasrc::ZoneFinderPtr zone_finder,
  1024. ThrowWhen throw_when, bool isc_exception,
  1025. ConstRRsetPtr fake_rrset) :
  1026. real_zone_finder_(zone_finder),
  1027. throw_when_(throw_when),
  1028. isc_exception_(isc_exception),
  1029. fake_rrset_(fake_rrset)
  1030. {}
  1031. virtual isc::dns::Name
  1032. getOrigin() const {
  1033. checkThrow(THROW_AT_GET_ORIGIN, throw_when_, isc_exception_);
  1034. return (real_zone_finder_->getOrigin());
  1035. }
  1036. virtual isc::dns::RRClass
  1037. getClass() const {
  1038. checkThrow(THROW_AT_GET_CLASS, throw_when_, isc_exception_);
  1039. return (real_zone_finder_->getClass());
  1040. }
  1041. virtual isc::datasrc::ZoneFinderContextPtr
  1042. find(const isc::dns::Name& name,
  1043. const isc::dns::RRType& type,
  1044. isc::datasrc::ZoneFinder::FindOptions options)
  1045. {
  1046. using namespace isc::datasrc;
  1047. checkThrow(THROW_AT_FIND, throw_when_, isc_exception_);
  1048. // If faked RRset was specified on construction and it matches the
  1049. // query, return it instead of searching the real data source.
  1050. if (fake_rrset_ && fake_rrset_->getName() == name &&
  1051. fake_rrset_->getType() == type)
  1052. {
  1053. return (ZoneFinderContextPtr(new ZoneFinder::Context(
  1054. *this, options,
  1055. ResultContext(SUCCESS,
  1056. fake_rrset_))));
  1057. }
  1058. return (real_zone_finder_->find(name, type, options));
  1059. }
  1060. virtual isc::datasrc::ZoneFinderContextPtr
  1061. findAll(const isc::dns::Name& name,
  1062. std::vector<isc::dns::ConstRRsetPtr> &target,
  1063. const FindOptions options = FIND_DEFAULT)
  1064. {
  1065. checkThrow(THROW_AT_FIND_ALL, throw_when_, isc_exception_);
  1066. return (real_zone_finder_->findAll(name, target, options));
  1067. }
  1068. virtual FindNSEC3Result
  1069. findNSEC3(const isc::dns::Name& name, bool recursive) {
  1070. checkThrow(THROW_AT_FIND_NSEC3, throw_when_, isc_exception_);
  1071. return (real_zone_finder_->findNSEC3(name, recursive));
  1072. }
  1073. virtual isc::dns::Name
  1074. findPreviousName(const isc::dns::Name& query) const {
  1075. return (real_zone_finder_->findPreviousName(query));
  1076. }
  1077. private:
  1078. isc::datasrc::ZoneFinderPtr real_zone_finder_;
  1079. ThrowWhen throw_when_;
  1080. bool isc_exception_;
  1081. ConstRRsetPtr fake_rrset_;
  1082. };
  1083. /// \brief Proxy InMemoryClient that can throw exceptions at specified times
  1084. ///
  1085. /// It is based on the memory client since that one is easy to override
  1086. /// (with setInMemoryClient) with the current design of AuthSrv.
  1087. class FakeInMemoryClient : public isc::datasrc::InMemoryClient {
  1088. public:
  1089. /// \brief Create a proxy memory client
  1090. ///
  1091. /// \param real_client The real in-memory client to proxy
  1092. /// \param throw_when if set to any value other than never, that is
  1093. /// the method that will throw an exception (either in this
  1094. /// class or the related FakeZoneFinder)
  1095. /// \param isc_exception if true, throw isc::Exception, otherwise,
  1096. /// throw std::exception
  1097. /// \param fake_rrset If non NULL, it will be used as an answer to
  1098. /// find() for that name and type.
  1099. FakeInMemoryClient(AuthSrv::InMemoryClientPtr real_client,
  1100. ThrowWhen throw_when, bool isc_exception,
  1101. ConstRRsetPtr fake_rrset = ConstRRsetPtr()) :
  1102. real_client_(real_client),
  1103. throw_when_(throw_when),
  1104. isc_exception_(isc_exception),
  1105. fake_rrset_(fake_rrset)
  1106. {}
  1107. /// \brief proxy call for findZone
  1108. ///
  1109. /// if this instance was constructed with throw_when set to find_zone,
  1110. /// this method will throw. Otherwise, it will return a FakeZoneFinder
  1111. /// instance which will throw at the method specified at the
  1112. /// construction of this instance.
  1113. virtual FindResult
  1114. findZone(const isc::dns::Name& name) const {
  1115. checkThrow(THROW_AT_FIND_ZONE, throw_when_, isc_exception_);
  1116. const FindResult result = real_client_->findZone(name);
  1117. return (FindResult(result.code, isc::datasrc::ZoneFinderPtr(
  1118. new FakeZoneFinder(result.zone_finder,
  1119. throw_when_,
  1120. isc_exception_,
  1121. fake_rrset_))));
  1122. }
  1123. private:
  1124. AuthSrv::InMemoryClientPtr real_client_;
  1125. ThrowWhen throw_when_;
  1126. bool isc_exception_;
  1127. ConstRRsetPtr fake_rrset_;
  1128. };
  1129. } // end anonymous namespace for throwing proxy classes
  1130. // Test for the tests
  1131. //
  1132. // Set the proxies to never throw, this should have the same result as
  1133. // queryWithInMemoryClientNoDNSSEC, and serves to test the two proxy classes
  1134. TEST_F(AuthSrvTest, queryWithInMemoryClientProxy) {
  1135. // Set real inmem client to proxy
  1136. updateConfig(&server, CONFIG_INMEMORY_EXAMPLE, true);
  1137. AuthSrv::InMemoryClientPtr fake_client(
  1138. new FakeInMemoryClient(server.getInMemoryClient(rrclass),
  1139. THROW_NEVER, false));
  1140. ASSERT_NE(AuthSrv::InMemoryClientPtr(), server.getInMemoryClient(rrclass));
  1141. server.setInMemoryClient(rrclass, fake_client);
  1142. createDataFromFile("nsec3query_nodnssec_fromWire.wire");
  1143. server.processMessage(*io_message, *parse_message, *response_obuffer,
  1144. &dnsserv);
  1145. EXPECT_TRUE(dnsserv.hasAnswer());
  1146. headerCheck(*parse_message, default_qid, Rcode::NOERROR(),
  1147. opcode.getCode(), QR_FLAG | AA_FLAG, 1, 1, 2, 1);
  1148. }
  1149. // Convenience function for the rest of the tests, set up a proxy
  1150. // to throw in the given method
  1151. // If isc_exception is true, it will throw isc::Exception, otherwise
  1152. // it will throw std::exception
  1153. // If non null rrset is given, it will be passed to the proxy so it can
  1154. // return some faked response.
  1155. void
  1156. setupThrow(AuthSrv* server, const char *config, ThrowWhen throw_when,
  1157. bool isc_exception, ConstRRsetPtr rrset = ConstRRsetPtr())
  1158. {
  1159. // Set real inmem client to proxy
  1160. updateConfig(server, config, true);
  1161. // Set it to throw on findZone(), this should result in
  1162. // SERVFAIL on any exception
  1163. AuthSrv::InMemoryClientPtr fake_client(
  1164. new FakeInMemoryClient(
  1165. server->getInMemoryClient(isc::dns::RRClass::IN()),
  1166. throw_when, isc_exception, rrset));
  1167. ASSERT_NE(AuthSrv::InMemoryClientPtr(),
  1168. server->getInMemoryClient(isc::dns::RRClass::IN()));
  1169. server->setInMemoryClient(isc::dns::RRClass::IN(), fake_client);
  1170. }
  1171. TEST_F(AuthSrvTest, queryWithThrowingProxyServfails) {
  1172. // Test the common cases, all of which should simply return SERVFAIL
  1173. // Use THROW_NEVER as end marker
  1174. ThrowWhen throws[] = { THROW_AT_FIND_ZONE,
  1175. THROW_AT_GET_ORIGIN,
  1176. THROW_AT_FIND,
  1177. THROW_AT_FIND_NSEC3,
  1178. THROW_NEVER };
  1179. UnitTestUtil::createDNSSECRequestMessage(request_message, opcode,
  1180. default_qid, Name("foo.example."),
  1181. RRClass::IN(), RRType::TXT());
  1182. for (ThrowWhen* when(throws); *when != THROW_NEVER; ++when) {
  1183. createRequestPacket(request_message, IPPROTO_UDP);
  1184. setupThrow(&server, CONFIG_INMEMORY_EXAMPLE, *when, true);
  1185. processAndCheckSERVFAIL();
  1186. // To be sure, check same for non-isc-exceptions
  1187. createRequestPacket(request_message, IPPROTO_UDP);
  1188. setupThrow(&server, CONFIG_INMEMORY_EXAMPLE, *when, false);
  1189. processAndCheckSERVFAIL();
  1190. }
  1191. }
  1192. // Throw isc::Exception in getClass(). (Currently?) getClass is not called
  1193. // in the processMessage path, so this should result in a normal answer
  1194. TEST_F(AuthSrvTest, queryWithInMemoryClientProxyGetClass) {
  1195. createDataFromFile("nsec3query_nodnssec_fromWire.wire");
  1196. setupThrow(&server, CONFIG_INMEMORY_EXAMPLE, THROW_AT_GET_CLASS, true);
  1197. // getClass is not called so it should just answer
  1198. server.processMessage(*io_message, *parse_message, *response_obuffer,
  1199. &dnsserv);
  1200. EXPECT_TRUE(dnsserv.hasAnswer());
  1201. headerCheck(*parse_message, default_qid, Rcode::NOERROR(),
  1202. opcode.getCode(), QR_FLAG | AA_FLAG, 1, 1, 2, 1);
  1203. }
  1204. TEST_F(AuthSrvTest, queryWithThrowingInToWire) {
  1205. // Set up a faked data source. It will return an empty RRset for the
  1206. // query.
  1207. ConstRRsetPtr empty_rrset(new RRset(Name("foo.example"),
  1208. RRClass::IN(), RRType::TXT(),
  1209. RRTTL(0)));
  1210. setupThrow(&server, CONFIG_INMEMORY_EXAMPLE, THROW_NEVER, true,
  1211. empty_rrset);
  1212. // Repeat the query processing two times. Due to the faked RRset,
  1213. // toWire() should throw, and it should result in SERVFAIL.
  1214. OutputBufferPtr orig_buffer;
  1215. for (int i = 0; i < 2; ++i) {
  1216. UnitTestUtil::createDNSSECRequestMessage(request_message, opcode,
  1217. default_qid,
  1218. Name("foo.example."),
  1219. RRClass::IN(), RRType::TXT());
  1220. createRequestPacket(request_message, IPPROTO_UDP);
  1221. server.processMessage(*io_message, *parse_message, *response_obuffer,
  1222. &dnsserv);
  1223. headerCheck(*parse_message, default_qid, Rcode::SERVFAIL(),
  1224. opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
  1225. // Make a backup of the original buffer for latest tests and replace
  1226. // it with a new one
  1227. if (!orig_buffer) {
  1228. orig_buffer = response_obuffer;
  1229. response_obuffer.reset(new OutputBuffer(0));
  1230. }
  1231. request_message.clear(Message::RENDER);
  1232. parse_message->clear(Message::PARSE);
  1233. }
  1234. // Now check if the original buffer is intact
  1235. parse_message->clear(Message::PARSE);
  1236. InputBuffer ibuffer(orig_buffer->getData(), orig_buffer->getLength());
  1237. parse_message->fromWire(ibuffer);
  1238. headerCheck(*parse_message, default_qid, Rcode::SERVFAIL(),
  1239. opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
  1240. }
  1241. //
  1242. // DDNS related tests
  1243. //
  1244. TEST_F(AuthSrvTest, DDNSForward) {
  1245. EXPECT_FALSE(ddns_forwarder.isConnected());
  1246. // Repeat sending an update request two times. By doing that we'll
  1247. // confirm the forwarder connection will be established exactly once,
  1248. // and kept established.
  1249. for (size_t i = 0; i < 2; ++i) {
  1250. createAndSendRequest(RRType::SOA(), Opcode::UPDATE());
  1251. EXPECT_FALSE(dnsserv.hasAnswer());
  1252. EXPECT_TRUE(ddns_forwarder.isConnected());
  1253. }
  1254. }
  1255. TEST_F(AuthSrvTest, DDNSForwardConnectFail) {
  1256. // make connect attempt fail. It should result in SERVFAIL. Note that
  1257. // the question (zone) section should be cleared for opcode of update.
  1258. ddns_forwarder.disableConnect();
  1259. createAndSendRequest(RRType::SOA(), Opcode::UPDATE());
  1260. EXPECT_TRUE(dnsserv.hasAnswer());
  1261. headerCheck(*parse_message, default_qid, Rcode::SERVFAIL(),
  1262. Opcode::UPDATE().getCode(), QR_FLAG, 0, 0, 0, 0);
  1263. EXPECT_FALSE(ddns_forwarder.isConnected());
  1264. // Now make connect okay again. Despite the previous failure the new
  1265. // connection should now be established.
  1266. ddns_forwarder.enableConnect();
  1267. createAndSendRequest(RRType::SOA(), Opcode::UPDATE());
  1268. EXPECT_FALSE(dnsserv.hasAnswer());
  1269. EXPECT_TRUE(ddns_forwarder.isConnected());
  1270. }
  1271. TEST_F(AuthSrvTest, DDNSForwardClose) {
  1272. scoped_ptr<AuthSrv> tmp_server(new AuthSrv(true, xfrout, ddns_forwarder));
  1273. UnitTestUtil::createRequestMessage(request_message, Opcode::UPDATE(),
  1274. default_qid, Name("example.com"),
  1275. RRClass::IN(), RRType::SOA());
  1276. createRequestPacket(request_message, IPPROTO_UDP);
  1277. tmp_server->processMessage(*io_message, *parse_message, *response_obuffer,
  1278. &dnsserv);
  1279. EXPECT_FALSE(dnsserv.hasAnswer());
  1280. EXPECT_TRUE(ddns_forwarder.isConnected());
  1281. // Destroy the server. The forwarder should close the connection.
  1282. tmp_server.reset();
  1283. EXPECT_FALSE(ddns_forwarder.isConnected());
  1284. }
  1285. }