|
@@ -65,22 +65,76 @@ const char* const CONFIG_TESTDB =
|
|
|
const char* const BADCONFIG_TESTDB =
|
|
|
"{ \"database_file\": \"" TEST_DATA_DIR "/nodir/notexist\"}";
|
|
|
|
|
|
+// This is a configuration that uses the in-memory data source containing
|
|
|
+// a signed example zone.
|
|
|
+const char* const CONFIG_INMEMORY_EXAMPLE =
|
|
|
+ "{\"datasources\": [{\"type\": \"memory\","
|
|
|
+ "\"zones\": [{\"origin\": \"example\","
|
|
|
+ "\"file\": \"" TEST_DATA_DIR "/rfc5155-example.zone.signed\"}]}]}";
|
|
|
+
|
|
|
class AuthSrvTest : public SrvTestBase {
|
|
|
protected:
|
|
|
AuthSrvTest() :
|
|
|
dnss_(ios_, NULL, NULL, NULL),
|
|
|
server(true, xfrout),
|
|
|
rrclass(RRClass::IN()),
|
|
|
- sock_requestor_(dnss_, address_store_, 53210)
|
|
|
+ // The empty string is expected value of the parameter of
|
|
|
+ // requestSocket, not the app_name (there's no fallback, it checks
|
|
|
+ // the empty string is passed).
|
|
|
+ sock_requestor_(dnss_, address_store_, 53210, "")
|
|
|
{
|
|
|
server.setDNSService(dnss_);
|
|
|
server.setXfrinSession(¬ify_session);
|
|
|
server.setStatisticsSession(&statistics_session);
|
|
|
}
|
|
|
+
|
|
|
virtual void processMessage() {
|
|
|
- server.processMessage(*io_message, parse_message, response_obuffer,
|
|
|
+ // If processMessage has been called before, parse_message needs
|
|
|
+ // to be reset. If it hasn't, there's no harm in doing so
|
|
|
+ parse_message->clear(Message::PARSE);
|
|
|
+ server.processMessage(*io_message, *parse_message, *response_obuffer,
|
|
|
&dnsserv);
|
|
|
}
|
|
|
+
|
|
|
+ // Helper for checking Rcode statistic counters;
|
|
|
+ // Checks for one specific Rcode statistics counter value
|
|
|
+ void checkRcodeCounter(const Rcode& rcode, int expected_value) const {
|
|
|
+ EXPECT_EQ(expected_value, server.getCounter(rcode)) <<
|
|
|
+ "Expected Rcode count for " << rcode.toText() <<
|
|
|
+ " " << expected_value << ", was: " <<
|
|
|
+ server.getCounter(rcode);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Checks whether all Rcode counters are set to zero
|
|
|
+ void checkAllRcodeCountersZero() const {
|
|
|
+ for (int i = 0; i < 17; i++) {
|
|
|
+ checkRcodeCounter(Rcode(i), 0);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Checks whether all Rcode counters are set to zero except the given
|
|
|
+ // rcode (it is checked to be set to 'value')
|
|
|
+ void checkAllRcodeCountersZeroExcept(const Rcode& rcode, int value) const {
|
|
|
+ for (int i = 0; i < 17; i++) {
|
|
|
+ const Rcode rc(i);
|
|
|
+ if (rc == rcode) {
|
|
|
+ checkRcodeCounter(Rcode(i), value);
|
|
|
+ } else {
|
|
|
+ checkRcodeCounter(Rcode(i), 0);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Convenience method for tests that expect to return SERVFAIL
|
|
|
+ // It calls processMessage, checks if there is an answer, and
|
|
|
+ // check the header for default SERVFAIL data
|
|
|
+ void processAndCheckSERVFAIL() {
|
|
|
+ processMessage();
|
|
|
+ EXPECT_TRUE(dnsserv.hasAnswer());
|
|
|
+ headerCheck(*parse_message, default_qid, Rcode::SERVFAIL(),
|
|
|
+ opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
|
|
|
+ }
|
|
|
+
|
|
|
IOService ios_;
|
|
|
DNSService dnss_;
|
|
|
MockSession statistics_session;
|
|
@@ -115,8 +169,7 @@ createBuiltinVersionResponse(const qid_t qid, vector<uint8_t>& data) {
|
|
|
rrset_version_ns->addRdata(generic::NS(version_name));
|
|
|
message.addRRset(Message::SECTION_AUTHORITY, rrset_version_ns);
|
|
|
|
|
|
- OutputBuffer obuffer(0);
|
|
|
- MessageRenderer renderer(obuffer);
|
|
|
+ MessageRenderer renderer;
|
|
|
message.toWire(renderer);
|
|
|
|
|
|
data.clear();
|
|
@@ -135,13 +188,14 @@ TEST_F(AuthSrvTest, builtInQuery) {
|
|
|
default_qid, Name("version.bind"),
|
|
|
RRClass::CH(), RRType::TXT());
|
|
|
createRequestPacket(request_message, IPPROTO_UDP);
|
|
|
- server.processMessage(*io_message, parse_message, response_obuffer,
|
|
|
+ server.processMessage(*io_message, *parse_message, *response_obuffer,
|
|
|
&dnsserv);
|
|
|
createBuiltinVersionResponse(default_qid, response_data);
|
|
|
EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
|
|
|
response_obuffer->getData(),
|
|
|
response_obuffer->getLength(),
|
|
|
&response_data[0], response_data.size());
|
|
|
+ checkAllRcodeCountersZeroExcept(Rcode::NOERROR(), 1);
|
|
|
}
|
|
|
|
|
|
// Same test emulating the UDPServer class behavior (defined in libasiolink).
|
|
@@ -192,38 +246,46 @@ TEST_F(AuthSrvTest, iqueryViaDNSServer) {
|
|
|
// Unsupported requests. Should result in NOTIMP.
|
|
|
TEST_F(AuthSrvTest, unsupportedRequest) {
|
|
|
unsupportedRequest();
|
|
|
+ // unsupportedRequest tries 14 different opcodes
|
|
|
+ checkAllRcodeCountersZeroExcept(Rcode::NOTIMP(), 14);
|
|
|
}
|
|
|
|
|
|
// Multiple questions. Should result in FORMERR.
|
|
|
TEST_F(AuthSrvTest, multiQuestion) {
|
|
|
multiQuestion();
|
|
|
+ checkAllRcodeCountersZeroExcept(Rcode::FORMERR(), 1);
|
|
|
}
|
|
|
|
|
|
// Incoming data doesn't even contain the complete header. Must be silently
|
|
|
// dropped.
|
|
|
TEST_F(AuthSrvTest, shortMessage) {
|
|
|
shortMessage();
|
|
|
+ checkAllRcodeCountersZero();
|
|
|
}
|
|
|
|
|
|
// Response messages. Must be silently dropped, whether it's a valid response
|
|
|
// or malformed or could otherwise cause a protocol error.
|
|
|
TEST_F(AuthSrvTest, response) {
|
|
|
response();
|
|
|
+ checkAllRcodeCountersZero();
|
|
|
}
|
|
|
|
|
|
// Query with a broken question
|
|
|
TEST_F(AuthSrvTest, shortQuestion) {
|
|
|
shortQuestion();
|
|
|
+ checkAllRcodeCountersZeroExcept(Rcode::FORMERR(), 1);
|
|
|
}
|
|
|
|
|
|
// Query with a broken answer section
|
|
|
TEST_F(AuthSrvTest, shortAnswer) {
|
|
|
shortAnswer();
|
|
|
+ checkAllRcodeCountersZeroExcept(Rcode::FORMERR(), 1);
|
|
|
}
|
|
|
|
|
|
// Query with unsupported version of EDNS.
|
|
|
TEST_F(AuthSrvTest, ednsBadVers) {
|
|
|
ednsBadVers();
|
|
|
+ checkAllRcodeCountersZeroExcept(Rcode::BADVERS(), 1);
|
|
|
}
|
|
|
|
|
|
TEST_F(AuthSrvTest, AXFROverUDP) {
|
|
@@ -238,9 +300,11 @@ TEST_F(AuthSrvTest, AXFRSuccess) {
|
|
|
createRequestPacket(request_message, IPPROTO_TCP);
|
|
|
// On success, the AXFR query has been passed to a separate process,
|
|
|
// so we shouldn't have to respond.
|
|
|
- server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
|
|
|
+ server.processMessage(*io_message, *parse_message, *response_obuffer,
|
|
|
+ &dnsserv);
|
|
|
EXPECT_FALSE(dnsserv.hasAnswer());
|
|
|
EXPECT_TRUE(xfrout.isConnected());
|
|
|
+ checkAllRcodeCountersZero();
|
|
|
}
|
|
|
|
|
|
// Try giving the server a TSIG signed request and see it can anwer signed as
|
|
@@ -258,7 +322,7 @@ TEST_F(AuthSrvTest, TSIGSigned) {
|
|
|
boost::shared_ptr<TSIGKeyRing> keyring(new TSIGKeyRing);
|
|
|
keyring->add(key);
|
|
|
server.setTSIGKeyRing(&keyring);
|
|
|
- server.processMessage(*io_message, parse_message, response_obuffer,
|
|
|
+ server.processMessage(*io_message, *parse_message, *response_obuffer,
|
|
|
&dnsserv);
|
|
|
|
|
|
// What did we get?
|
|
@@ -276,6 +340,8 @@ TEST_F(AuthSrvTest, TSIGSigned) {
|
|
|
response_obuffer->getLength()));
|
|
|
EXPECT_EQ(TSIGError::NOERROR(), error) <<
|
|
|
"The server signed the response, but it doesn't seem to be valid";
|
|
|
+
|
|
|
+ checkAllRcodeCountersZeroExcept(Rcode::NOERROR(), 1);
|
|
|
}
|
|
|
|
|
|
// Give the server a signed request, but don't give it the key. It will
|
|
@@ -291,7 +357,7 @@ TEST_F(AuthSrvTest, TSIGSignedBadKey) {
|
|
|
// Process the message, but use a different key there
|
|
|
boost::shared_ptr<TSIGKeyRing> keyring(new TSIGKeyRing);
|
|
|
server.setTSIGKeyRing(&keyring);
|
|
|
- server.processMessage(*io_message, parse_message, response_obuffer,
|
|
|
+ server.processMessage(*io_message, *parse_message, *response_obuffer,
|
|
|
&dnsserv);
|
|
|
|
|
|
EXPECT_TRUE(dnsserv.hasAnswer());
|
|
@@ -308,6 +374,8 @@ TEST_F(AuthSrvTest, TSIGSignedBadKey) {
|
|
|
EXPECT_EQ(TSIGError::BAD_KEY_CODE, tsig->getRdata().getError());
|
|
|
EXPECT_EQ(0, tsig->getRdata().getMACSize()) <<
|
|
|
"It should be unsigned with this error";
|
|
|
+
|
|
|
+ checkAllRcodeCountersZeroExcept(Rcode::NOTAUTH(), 1);
|
|
|
}
|
|
|
|
|
|
// Give the server a signed request, but signed by a different key
|
|
@@ -324,7 +392,7 @@ TEST_F(AuthSrvTest, TSIGBadSig) {
|
|
|
boost::shared_ptr<TSIGKeyRing> keyring(new TSIGKeyRing);
|
|
|
keyring->add(TSIGKey("key:QkFECg==:hmac-sha1"));
|
|
|
server.setTSIGKeyRing(&keyring);
|
|
|
- server.processMessage(*io_message, parse_message, response_obuffer,
|
|
|
+ server.processMessage(*io_message, *parse_message, *response_obuffer,
|
|
|
&dnsserv);
|
|
|
|
|
|
EXPECT_TRUE(dnsserv.hasAnswer());
|
|
@@ -341,6 +409,8 @@ TEST_F(AuthSrvTest, TSIGBadSig) {
|
|
|
EXPECT_EQ(TSIGError::BAD_SIG_CODE, tsig->getRdata().getError());
|
|
|
EXPECT_EQ(0, tsig->getRdata().getMACSize()) <<
|
|
|
"It should be unsigned with this error";
|
|
|
+
|
|
|
+ checkAllRcodeCountersZeroExcept(Rcode::NOTAUTH(), 1);
|
|
|
}
|
|
|
|
|
|
// Give the server a signed unsupported request with a bad signature.
|
|
@@ -360,7 +430,7 @@ TEST_F(AuthSrvTest, TSIGCheckFirst) {
|
|
|
boost::shared_ptr<TSIGKeyRing> keyring(new TSIGKeyRing);
|
|
|
keyring->add(TSIGKey("key:QkFECg==:hmac-sha1"));
|
|
|
server.setTSIGKeyRing(&keyring);
|
|
|
- server.processMessage(*io_message, parse_message, response_obuffer,
|
|
|
+ server.processMessage(*io_message, *parse_message, *response_obuffer,
|
|
|
&dnsserv);
|
|
|
|
|
|
EXPECT_TRUE(dnsserv.hasAnswer());
|
|
@@ -380,6 +450,8 @@ TEST_F(AuthSrvTest, TSIGCheckFirst) {
|
|
|
// TSIG should have failed, and so the per opcode counter shouldn't be
|
|
|
// incremented.
|
|
|
EXPECT_EQ(0, server.getCounter(Opcode::RESERVED14()));
|
|
|
+
|
|
|
+ checkAllRcodeCountersZeroExcept(Rcode::NOTAUTH(), 1);
|
|
|
}
|
|
|
|
|
|
TEST_F(AuthSrvTest, AXFRConnectFail) {
|
|
@@ -389,7 +461,8 @@ TEST_F(AuthSrvTest, AXFRConnectFail) {
|
|
|
Name("example.com"), RRClass::IN(),
|
|
|
RRType::AXFR());
|
|
|
createRequestPacket(request_message, IPPROTO_TCP);
|
|
|
- server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
|
|
|
+ server.processMessage(*io_message, *parse_message, *response_obuffer,
|
|
|
+ &dnsserv);
|
|
|
EXPECT_TRUE(dnsserv.hasAnswer());
|
|
|
headerCheck(*parse_message, default_qid, Rcode::SERVFAIL(),
|
|
|
opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
|
|
@@ -403,7 +476,8 @@ TEST_F(AuthSrvTest, AXFRSendFail) {
|
|
|
Name("example.com"), RRClass::IN(),
|
|
|
RRType::AXFR());
|
|
|
createRequestPacket(request_message, IPPROTO_TCP);
|
|
|
- server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
|
|
|
+ server.processMessage(*io_message, *parse_message, *response_obuffer,
|
|
|
+ &dnsserv);
|
|
|
EXPECT_TRUE(xfrout.isConnected());
|
|
|
|
|
|
xfrout.disableSend();
|
|
@@ -413,7 +487,8 @@ TEST_F(AuthSrvTest, AXFRSendFail) {
|
|
|
Name("example.com"), RRClass::IN(),
|
|
|
RRType::AXFR());
|
|
|
createRequestPacket(request_message, IPPROTO_TCP);
|
|
|
- server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
|
|
|
+ server.processMessage(*io_message, *parse_message, *response_obuffer,
|
|
|
+ &dnsserv);
|
|
|
EXPECT_TRUE(dnsserv.hasAnswer());
|
|
|
headerCheck(*parse_message, default_qid, Rcode::SERVFAIL(),
|
|
|
opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
|
|
@@ -423,17 +498,17 @@ TEST_F(AuthSrvTest, AXFRSendFail) {
|
|
|
}
|
|
|
|
|
|
TEST_F(AuthSrvTest, AXFRDisconnectFail) {
|
|
|
- // In our usage disconnect() shouldn't fail. So we'll see the exception
|
|
|
- // should it be thrown.
|
|
|
+ // In our usage disconnect() shouldn't fail. But even if it does,
|
|
|
+ // it should not disrupt service (so processMessage should have caught it)
|
|
|
xfrout.disableSend();
|
|
|
xfrout.disableDisconnect();
|
|
|
UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
|
|
|
Name("example.com"), RRClass::IN(),
|
|
|
RRType::AXFR());
|
|
|
createRequestPacket(request_message, IPPROTO_TCP);
|
|
|
- EXPECT_THROW(server.processMessage(*io_message, parse_message,
|
|
|
- response_obuffer, &dnsserv),
|
|
|
- XfroutError);
|
|
|
+ EXPECT_NO_THROW(server.processMessage(*io_message, *parse_message,
|
|
|
+ *response_obuffer, &dnsserv));
|
|
|
+ // Since the disconnect failed, we should still be 'connected'
|
|
|
EXPECT_TRUE(xfrout.isConnected());
|
|
|
// XXX: we need to re-enable disconnect. otherwise an exception would be
|
|
|
// thrown via the destructor of the server.
|
|
@@ -447,7 +522,8 @@ TEST_F(AuthSrvTest, IXFRConnectFail) {
|
|
|
Name("example.com"), RRClass::IN(),
|
|
|
RRType::IXFR());
|
|
|
createRequestPacket(request_message, IPPROTO_TCP);
|
|
|
- server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
|
|
|
+ server.processMessage(*io_message, *parse_message, *response_obuffer,
|
|
|
+ &dnsserv);
|
|
|
EXPECT_TRUE(dnsserv.hasAnswer());
|
|
|
headerCheck(*parse_message, default_qid, Rcode::SERVFAIL(),
|
|
|
opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
|
|
@@ -461,7 +537,8 @@ TEST_F(AuthSrvTest, IXFRSendFail) {
|
|
|
Name("example.com"), RRClass::IN(),
|
|
|
RRType::IXFR());
|
|
|
createRequestPacket(request_message, IPPROTO_TCP);
|
|
|
- server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
|
|
|
+ server.processMessage(*io_message, *parse_message, *response_obuffer,
|
|
|
+ &dnsserv);
|
|
|
EXPECT_TRUE(xfrout.isConnected());
|
|
|
|
|
|
xfrout.disableSend();
|
|
@@ -471,7 +548,8 @@ TEST_F(AuthSrvTest, IXFRSendFail) {
|
|
|
Name("example.com"), RRClass::IN(),
|
|
|
RRType::IXFR());
|
|
|
createRequestPacket(request_message, IPPROTO_TCP);
|
|
|
- server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
|
|
|
+ server.processMessage(*io_message, *parse_message, *response_obuffer,
|
|
|
+ &dnsserv);
|
|
|
EXPECT_TRUE(dnsserv.hasAnswer());
|
|
|
headerCheck(*parse_message, default_qid, Rcode::SERVFAIL(),
|
|
|
opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
|
|
@@ -481,17 +559,16 @@ TEST_F(AuthSrvTest, IXFRSendFail) {
|
|
|
}
|
|
|
|
|
|
TEST_F(AuthSrvTest, IXFRDisconnectFail) {
|
|
|
- // In our usage disconnect() shouldn't fail. So we'll see the exception
|
|
|
- // should it be thrown.
|
|
|
+ // In our usage disconnect() shouldn't fail, but even if it does,
|
|
|
+ // procesMessage() should catch it.
|
|
|
xfrout.disableSend();
|
|
|
xfrout.disableDisconnect();
|
|
|
UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
|
|
|
Name("example.com"), RRClass::IN(),
|
|
|
RRType::IXFR());
|
|
|
createRequestPacket(request_message, IPPROTO_TCP);
|
|
|
- EXPECT_THROW(server.processMessage(*io_message, parse_message,
|
|
|
- response_obuffer, &dnsserv),
|
|
|
- XfroutError);
|
|
|
+ EXPECT_NO_THROW(server.processMessage(*io_message, *parse_message,
|
|
|
+ *response_obuffer, &dnsserv));
|
|
|
EXPECT_TRUE(xfrout.isConnected());
|
|
|
// XXX: we need to re-enable disconnect. otherwise an exception would be
|
|
|
// thrown via the destructor of the server.
|
|
@@ -504,7 +581,8 @@ TEST_F(AuthSrvTest, notify) {
|
|
|
RRClass::IN(), RRType::SOA());
|
|
|
request_message.setHeaderFlag(Message::HEADERFLAG_AA);
|
|
|
createRequestPacket(request_message, IPPROTO_UDP);
|
|
|
- server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
|
|
|
+ server.processMessage(*io_message, *parse_message, *response_obuffer,
|
|
|
+ &dnsserv);
|
|
|
EXPECT_TRUE(dnsserv.hasAnswer());
|
|
|
|
|
|
// An internal command message should have been created and sent to an
|
|
@@ -528,6 +606,8 @@ TEST_F(AuthSrvTest, notify) {
|
|
|
EXPECT_EQ(Name("example.com"), question->getName());
|
|
|
EXPECT_EQ(RRClass::IN(), question->getClass());
|
|
|
EXPECT_EQ(RRType::SOA(), question->getType());
|
|
|
+
|
|
|
+ checkAllRcodeCountersZeroExcept(Rcode::NOERROR(), 1);
|
|
|
}
|
|
|
|
|
|
TEST_F(AuthSrvTest, notifyForCHClass) {
|
|
@@ -537,7 +617,8 @@ TEST_F(AuthSrvTest, notifyForCHClass) {
|
|
|
RRClass::CH(), RRType::SOA());
|
|
|
request_message.setHeaderFlag(Message::HEADERFLAG_AA);
|
|
|
createRequestPacket(request_message, IPPROTO_UDP);
|
|
|
- server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
|
|
|
+ server.processMessage(*io_message, *parse_message, *response_obuffer,
|
|
|
+ &dnsserv);
|
|
|
EXPECT_TRUE(dnsserv.hasAnswer());
|
|
|
|
|
|
// Other conditions should be the same, so simply confirm the RR class is
|
|
@@ -555,7 +636,8 @@ TEST_F(AuthSrvTest, notifyEmptyQuestion) {
|
|
|
request_message.setQid(default_qid);
|
|
|
request_message.toWire(request_renderer);
|
|
|
createRequestPacket(request_message, IPPROTO_UDP);
|
|
|
- server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
|
|
|
+ server.processMessage(*io_message, *parse_message, *response_obuffer,
|
|
|
+ &dnsserv);
|
|
|
EXPECT_TRUE(dnsserv.hasAnswer());
|
|
|
headerCheck(*parse_message, default_qid, Rcode::FORMERR(),
|
|
|
Opcode::NOTIFY().getCode(), QR_FLAG, 0, 0, 0, 0);
|
|
@@ -570,7 +652,8 @@ TEST_F(AuthSrvTest, notifyMultiQuestions) {
|
|
|
RRType::SOA()));
|
|
|
request_message.setHeaderFlag(Message::HEADERFLAG_AA);
|
|
|
createRequestPacket(request_message, IPPROTO_UDP);
|
|
|
- server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
|
|
|
+ server.processMessage(*io_message, *parse_message, *response_obuffer,
|
|
|
+ &dnsserv);
|
|
|
EXPECT_TRUE(dnsserv.hasAnswer());
|
|
|
headerCheck(*parse_message, default_qid, Rcode::FORMERR(),
|
|
|
Opcode::NOTIFY().getCode(), QR_FLAG, 2, 0, 0, 0);
|
|
@@ -582,7 +665,8 @@ TEST_F(AuthSrvTest, notifyNonSOAQuestion) {
|
|
|
RRClass::IN(), RRType::NS());
|
|
|
request_message.setHeaderFlag(Message::HEADERFLAG_AA);
|
|
|
createRequestPacket(request_message, IPPROTO_UDP);
|
|
|
- server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
|
|
|
+ server.processMessage(*io_message, *parse_message, *response_obuffer,
|
|
|
+ &dnsserv);
|
|
|
EXPECT_TRUE(dnsserv.hasAnswer());
|
|
|
headerCheck(*parse_message, default_qid, Rcode::FORMERR(),
|
|
|
Opcode::NOTIFY().getCode(), QR_FLAG, 1, 0, 0, 0);
|
|
@@ -594,7 +678,8 @@ TEST_F(AuthSrvTest, notifyWithoutAA) {
|
|
|
default_qid, Name("example.com"),
|
|
|
RRClass::IN(), RRType::SOA());
|
|
|
createRequestPacket(request_message, IPPROTO_UDP);
|
|
|
- server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
|
|
|
+ server.processMessage(*io_message, *parse_message, *response_obuffer,
|
|
|
+ &dnsserv);
|
|
|
EXPECT_TRUE(dnsserv.hasAnswer());
|
|
|
headerCheck(*parse_message, default_qid, Rcode::NOERROR(),
|
|
|
Opcode::NOTIFY().getCode(), QR_FLAG | AA_FLAG, 1, 0, 0, 0);
|
|
@@ -607,7 +692,8 @@ TEST_F(AuthSrvTest, notifyWithErrorRcode) {
|
|
|
request_message.setHeaderFlag(Message::HEADERFLAG_AA);
|
|
|
request_message.setRcode(Rcode::SERVFAIL());
|
|
|
createRequestPacket(request_message, IPPROTO_UDP);
|
|
|
- server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
|
|
|
+ server.processMessage(*io_message, *parse_message, *response_obuffer,
|
|
|
+ &dnsserv);
|
|
|
EXPECT_TRUE(dnsserv.hasAnswer());
|
|
|
headerCheck(*parse_message, default_qid, Rcode::NOERROR(),
|
|
|
Opcode::NOTIFY().getCode(), QR_FLAG | AA_FLAG, 1, 0, 0, 0);
|
|
@@ -624,7 +710,8 @@ TEST_F(AuthSrvTest, notifyWithoutSession) {
|
|
|
|
|
|
// we simply ignore the notify and let it be resent if an internal error
|
|
|
// happens.
|
|
|
- server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
|
|
|
+ server.processMessage(*io_message, *parse_message, *response_obuffer,
|
|
|
+ &dnsserv);
|
|
|
EXPECT_FALSE(dnsserv.hasAnswer());
|
|
|
}
|
|
|
|
|
@@ -637,7 +724,8 @@ TEST_F(AuthSrvTest, notifySendFail) {
|
|
|
request_message.setHeaderFlag(Message::HEADERFLAG_AA);
|
|
|
createRequestPacket(request_message, IPPROTO_UDP);
|
|
|
|
|
|
- server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
|
|
|
+ server.processMessage(*io_message, *parse_message, *response_obuffer,
|
|
|
+ &dnsserv);
|
|
|
EXPECT_FALSE(dnsserv.hasAnswer());
|
|
|
}
|
|
|
|
|
@@ -649,7 +737,8 @@ TEST_F(AuthSrvTest, notifyReceiveFail) {
|
|
|
RRClass::IN(), RRType::SOA());
|
|
|
request_message.setHeaderFlag(Message::HEADERFLAG_AA);
|
|
|
createRequestPacket(request_message, IPPROTO_UDP);
|
|
|
- server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
|
|
|
+ server.processMessage(*io_message, *parse_message, *response_obuffer,
|
|
|
+ &dnsserv);
|
|
|
EXPECT_FALSE(dnsserv.hasAnswer());
|
|
|
}
|
|
|
|
|
@@ -661,7 +750,8 @@ TEST_F(AuthSrvTest, notifyWithBogusSessionMessage) {
|
|
|
RRClass::IN(), RRType::SOA());
|
|
|
request_message.setHeaderFlag(Message::HEADERFLAG_AA);
|
|
|
createRequestPacket(request_message, IPPROTO_UDP);
|
|
|
- server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
|
|
|
+ server.processMessage(*io_message, *parse_message, *response_obuffer,
|
|
|
+ &dnsserv);
|
|
|
EXPECT_FALSE(dnsserv.hasAnswer());
|
|
|
}
|
|
|
|
|
@@ -674,7 +764,8 @@ TEST_F(AuthSrvTest, notifyWithSessionMessageError) {
|
|
|
RRClass::IN(), RRType::SOA());
|
|
|
request_message.setHeaderFlag(Message::HEADERFLAG_AA);
|
|
|
createRequestPacket(request_message, IPPROTO_UDP);
|
|
|
- server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
|
|
|
+ server.processMessage(*io_message, *parse_message, *response_obuffer,
|
|
|
+ &dnsserv);
|
|
|
EXPECT_FALSE(dnsserv.hasAnswer());
|
|
|
}
|
|
|
|
|
@@ -689,7 +780,8 @@ updateConfig(AuthSrv* server, const char* const config_data,
|
|
|
|
|
|
ConstElementPtr result = config_answer->get("result");
|
|
|
EXPECT_EQ(Element::list, result->getType());
|
|
|
- EXPECT_EQ(expect_success ? 0 : 1, result->get(0)->intValue());
|
|
|
+ EXPECT_EQ(expect_success ? 0 : 1, result->get(0)->intValue()) <<
|
|
|
+ "Bad result from updateConfig: " << result->str();
|
|
|
}
|
|
|
|
|
|
// Install a Sqlite3 data source with testing data.
|
|
@@ -700,7 +792,8 @@ TEST_F(AuthSrvTest, updateConfig) {
|
|
|
// response should have the AA flag on, and have an RR in each answer
|
|
|
// and authority section.
|
|
|
createDataFromFile("examplequery_fromWire.wire");
|
|
|
- server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
|
|
|
+ server.processMessage(*io_message, *parse_message, *response_obuffer,
|
|
|
+ &dnsserv);
|
|
|
EXPECT_TRUE(dnsserv.hasAnswer());
|
|
|
headerCheck(*parse_message, default_qid, Rcode::NOERROR(), opcode.getCode(),
|
|
|
QR_FLAG | AA_FLAG, 1, 1, 1, 0);
|
|
@@ -714,7 +807,8 @@ TEST_F(AuthSrvTest, datasourceFail) {
|
|
|
// in a SERVFAIL response, and the answer and authority sections should
|
|
|
// be empty.
|
|
|
createDataFromFile("badExampleQuery_fromWire.wire");
|
|
|
- server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
|
|
|
+ server.processMessage(*io_message, *parse_message, *response_obuffer,
|
|
|
+ &dnsserv);
|
|
|
EXPECT_TRUE(dnsserv.hasAnswer());
|
|
|
headerCheck(*parse_message, default_qid, Rcode::SERVFAIL(),
|
|
|
opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
|
|
@@ -729,7 +823,8 @@ TEST_F(AuthSrvTest, updateConfigFail) {
|
|
|
|
|
|
// The original data source should still exist.
|
|
|
createDataFromFile("examplequery_fromWire.wire");
|
|
|
- server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
|
|
|
+ server.processMessage(*io_message, *parse_message, *response_obuffer,
|
|
|
+ &dnsserv);
|
|
|
EXPECT_TRUE(dnsserv.hasAnswer());
|
|
|
headerCheck(*parse_message, default_qid, Rcode::NOERROR(), opcode.getCode(),
|
|
|
QR_FLAG | AA_FLAG, 1, 1, 1, 0);
|
|
@@ -749,13 +844,48 @@ TEST_F(AuthSrvTest, updateWithInMemoryClient) {
|
|
|
|
|
|
// The memory data source is empty, should return REFUSED rcode.
|
|
|
createDataFromFile("examplequery_fromWire.wire");
|
|
|
- server.processMessage(*io_message, parse_message, response_obuffer,
|
|
|
+ server.processMessage(*io_message, *parse_message, *response_obuffer,
|
|
|
&dnsserv);
|
|
|
EXPECT_TRUE(dnsserv.hasAnswer());
|
|
|
headerCheck(*parse_message, default_qid, Rcode::REFUSED(),
|
|
|
opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
|
|
|
}
|
|
|
|
|
|
+TEST_F(AuthSrvTest, queryWithInMemoryClientNoDNSSEC) {
|
|
|
+ // In this example, we do simple check that query is handled from the
|
|
|
+ // query handler class, and confirm it returns no error and a non empty
|
|
|
+ // answer section. Detailed examination on the response content
|
|
|
+ // for various types of queries are tested in the query tests.
|
|
|
+ updateConfig(&server, CONFIG_INMEMORY_EXAMPLE, true);
|
|
|
+ ASSERT_NE(AuthSrv::InMemoryClientPtr(), server.getInMemoryClient(rrclass));
|
|
|
+ EXPECT_EQ(1, server.getInMemoryClient(rrclass)->getZoneCount());
|
|
|
+
|
|
|
+ createDataFromFile("nsec3query_nodnssec_fromWire.wire");
|
|
|
+ server.processMessage(*io_message, *parse_message, *response_obuffer,
|
|
|
+ &dnsserv);
|
|
|
+
|
|
|
+ EXPECT_TRUE(dnsserv.hasAnswer());
|
|
|
+ headerCheck(*parse_message, default_qid, Rcode::NOERROR(),
|
|
|
+ opcode.getCode(), QR_FLAG | AA_FLAG, 1, 1, 2, 1);
|
|
|
+}
|
|
|
+
|
|
|
+TEST_F(AuthSrvTest, queryWithInMemoryClientDNSSEC) {
|
|
|
+ // Similar to the previous test, but the query has the DO bit on.
|
|
|
+ // The response should contain RRSIGs, and should have more RRs than
|
|
|
+ // the previous case.
|
|
|
+ updateConfig(&server, CONFIG_INMEMORY_EXAMPLE, true);
|
|
|
+ ASSERT_NE(AuthSrv::InMemoryClientPtr(), server.getInMemoryClient(rrclass));
|
|
|
+ EXPECT_EQ(1, server.getInMemoryClient(rrclass)->getZoneCount());
|
|
|
+
|
|
|
+ createDataFromFile("nsec3query_fromWire.wire");
|
|
|
+ server.processMessage(*io_message, *parse_message, *response_obuffer,
|
|
|
+ &dnsserv);
|
|
|
+
|
|
|
+ EXPECT_TRUE(dnsserv.hasAnswer());
|
|
|
+ headerCheck(*parse_message, default_qid, Rcode::NOERROR(),
|
|
|
+ opcode.getCode(), QR_FLAG | AA_FLAG, 1, 2, 3, 3);
|
|
|
+}
|
|
|
+
|
|
|
TEST_F(AuthSrvTest, chQueryWithInMemoryClient) {
|
|
|
// Configure memory data source for class IN
|
|
|
updateConfig(&server, "{\"datasources\": "
|
|
@@ -766,7 +896,7 @@ TEST_F(AuthSrvTest, chQueryWithInMemoryClient) {
|
|
|
default_qid, Name("version.bind"),
|
|
|
RRClass::CH(), RRType::TXT());
|
|
|
createRequestPacket(request_message, IPPROTO_UDP);
|
|
|
- server.processMessage(*io_message, parse_message, response_obuffer,
|
|
|
+ server.processMessage(*io_message, *parse_message, *response_obuffer,
|
|
|
&dnsserv);
|
|
|
EXPECT_TRUE(dnsserv.hasAnswer());
|
|
|
headerCheck(*parse_message, default_qid, Rcode::NOERROR(),
|
|
@@ -792,10 +922,14 @@ TEST_F(AuthSrvTest, queryCounterUDPNormal) {
|
|
|
default_qid, Name("example.com"),
|
|
|
RRClass::IN(), RRType::NS());
|
|
|
createRequestPacket(request_message, IPPROTO_UDP);
|
|
|
- server.processMessage(*io_message, parse_message, response_obuffer,
|
|
|
+ server.processMessage(*io_message, *parse_message, *response_obuffer,
|
|
|
&dnsserv);
|
|
|
// After processing UDP query, the counter should be 1.
|
|
|
EXPECT_EQ(1, server.getCounter(AuthCounters::SERVER_UDP_QUERY));
|
|
|
+ // The counter for opcode Query should also be one
|
|
|
+ EXPECT_EQ(1, server.getCounter(Opcode::QUERY()));
|
|
|
+ // The counter for REFUSED responses should also be one, the rest zero
|
|
|
+ checkAllRcodeCountersZeroExcept(Rcode::REFUSED(), 1);
|
|
|
}
|
|
|
|
|
|
// Submit TCP normal query and check query counter
|
|
@@ -807,10 +941,14 @@ TEST_F(AuthSrvTest, queryCounterTCPNormal) {
|
|
|
default_qid, Name("example.com"),
|
|
|
RRClass::IN(), RRType::NS());
|
|
|
createRequestPacket(request_message, IPPROTO_TCP);
|
|
|
- server.processMessage(*io_message, parse_message, response_obuffer,
|
|
|
+ server.processMessage(*io_message, *parse_message, *response_obuffer,
|
|
|
&dnsserv);
|
|
|
// After processing TCP query, the counter should be 1.
|
|
|
EXPECT_EQ(1, server.getCounter(AuthCounters::SERVER_TCP_QUERY));
|
|
|
+ // The counter for SUCCESS responses should also be one
|
|
|
+ EXPECT_EQ(1, server.getCounter(Opcode::QUERY()));
|
|
|
+ // The counter for REFUSED responses should also be one, the rest zero
|
|
|
+ checkAllRcodeCountersZeroExcept(Rcode::REFUSED(), 1);
|
|
|
}
|
|
|
|
|
|
// Submit TCP AXFR query and check query counter
|
|
@@ -822,10 +960,13 @@ TEST_F(AuthSrvTest, queryCounterTCPAXFR) {
|
|
|
createRequestPacket(request_message, IPPROTO_TCP);
|
|
|
// On success, the AXFR query has been passed to a separate process,
|
|
|
// so auth itself shouldn't respond.
|
|
|
- server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
|
|
|
+ server.processMessage(*io_message, *parse_message, *response_obuffer,
|
|
|
+ &dnsserv);
|
|
|
EXPECT_FALSE(dnsserv.hasAnswer());
|
|
|
// After processing TCP AXFR query, the counter should be 1.
|
|
|
EXPECT_EQ(1, server.getCounter(AuthCounters::SERVER_TCP_QUERY));
|
|
|
+ // No rcodes should be incremented
|
|
|
+ checkAllRcodeCountersZero();
|
|
|
}
|
|
|
|
|
|
// Submit TCP IXFR query and check query counter
|
|
@@ -837,7 +978,8 @@ TEST_F(AuthSrvTest, queryCounterTCPIXFR) {
|
|
|
createRequestPacket(request_message, IPPROTO_TCP);
|
|
|
// On success, the IXFR query has been passed to a separate process,
|
|
|
// so auth itself shouldn't respond.
|
|
|
- server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
|
|
|
+ server.processMessage(*io_message, *parse_message, *response_obuffer,
|
|
|
+ &dnsserv);
|
|
|
EXPECT_FALSE(dnsserv.hasAnswer());
|
|
|
// After processing TCP IXFR query, the counter should be 1.
|
|
|
EXPECT_EQ(1, server.getCounter(AuthCounters::SERVER_TCP_QUERY));
|
|
@@ -858,7 +1000,8 @@ TEST_F(AuthSrvTest, queryCounterOpcodes) {
|
|
|
// we intentionally use different values for each code
|
|
|
for (int j = 0; j <= i; ++j) {
|
|
|
parse_message->clear(Message::PARSE);
|
|
|
- server.processMessage(*io_message, parse_message, response_obuffer,
|
|
|
+ server.processMessage(*io_message, *parse_message,
|
|
|
+ *response_obuffer,
|
|
|
&dnsserv);
|
|
|
}
|
|
|
|
|
@@ -884,11 +1027,10 @@ getDummyUnknownSocket() {
|
|
|
return (socket);
|
|
|
}
|
|
|
|
|
|
-// Submit unexpected type of query and check it throws isc::Unexpected
|
|
|
+// Submit unexpected type of query and check it is ignored
|
|
|
TEST_F(AuthSrvTest, queryCounterUnexpected) {
|
|
|
// This code isn't exception safe, but we'd rather keep the code
|
|
|
- // simpler and more readable as this is only for tests and if it throws
|
|
|
- // the program would immediately terminate anyway.
|
|
|
+ // simpler and more readable as this is only for tests
|
|
|
|
|
|
// Create UDP query packet.
|
|
|
UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
|
|
@@ -904,9 +1046,7 @@ TEST_F(AuthSrvTest, queryCounterUnexpected) {
|
|
|
request_renderer.getLength(),
|
|
|
getDummyUnknownSocket(), *endpoint);
|
|
|
|
|
|
- EXPECT_THROW(server.processMessage(*io_message, parse_message,
|
|
|
- response_obuffer, &dnsserv),
|
|
|
- isc::Unexpected);
|
|
|
+ EXPECT_FALSE(dnsserv.hasAnswer());
|
|
|
}
|
|
|
|
|
|
TEST_F(AuthSrvTest, stop) {
|
|
@@ -935,4 +1075,231 @@ TEST_F(AuthSrvTest, listenAddresses) {
|
|
|
"Released tokens");
|
|
|
}
|
|
|
|
|
|
+//
|
|
|
+// Tests for catching exceptions in various stages of the query processing
|
|
|
+//
|
|
|
+// These tests work by defining two proxy classes, that act as an in-memory
|
|
|
+// client by default, but can throw exceptions at various points.
|
|
|
+//
|
|
|
+namespace {
|
|
|
+
|
|
|
+/// A the possible methods to throw in, either in FakeInMemoryClient or
|
|
|
+/// FakeZoneFinder
|
|
|
+enum ThrowWhen {
|
|
|
+ THROW_NEVER,
|
|
|
+ THROW_AT_FIND_ZONE,
|
|
|
+ THROW_AT_GET_ORIGIN,
|
|
|
+ THROW_AT_GET_CLASS,
|
|
|
+ THROW_AT_FIND,
|
|
|
+ THROW_AT_FIND_ALL,
|
|
|
+ THROW_AT_FIND_NSEC3
|
|
|
+};
|
|
|
+
|
|
|
+/// convenience function to check whether and what to throw
|
|
|
+void
|
|
|
+checkThrow(ThrowWhen method, ThrowWhen throw_at, bool isc_exception) {
|
|
|
+ if (method == throw_at) {
|
|
|
+ if (isc_exception) {
|
|
|
+ isc_throw(isc::Exception, "foo");
|
|
|
+ } else {
|
|
|
+ throw std::exception();
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/// \brief proxy class for the ZoneFinder returned by the InMemoryClient
|
|
|
+/// proxied by FakeInMemoryClient
|
|
|
+///
|
|
|
+/// See the documentation for FakeInMemoryClient for more information,
|
|
|
+/// all methods simply check whether they should throw, and if not, call
|
|
|
+/// their proxied equivalent.
|
|
|
+class FakeZoneFinder : public isc::datasrc::ZoneFinder {
|
|
|
+public:
|
|
|
+ FakeZoneFinder(isc::datasrc::ZoneFinderPtr zone_finder,
|
|
|
+ ThrowWhen throw_when,
|
|
|
+ bool isc_exception) :
|
|
|
+ real_zone_finder_(zone_finder),
|
|
|
+ throw_when_(throw_when),
|
|
|
+ isc_exception_(isc_exception)
|
|
|
+ {}
|
|
|
+
|
|
|
+ virtual isc::dns::Name
|
|
|
+ getOrigin() const {
|
|
|
+ checkThrow(THROW_AT_GET_ORIGIN, throw_when_, isc_exception_);
|
|
|
+ return (real_zone_finder_->getOrigin());
|
|
|
+ }
|
|
|
+
|
|
|
+ virtual isc::dns::RRClass
|
|
|
+ getClass() const {
|
|
|
+ checkThrow(THROW_AT_GET_CLASS, throw_when_, isc_exception_);
|
|
|
+ return (real_zone_finder_->getClass());
|
|
|
+ }
|
|
|
+
|
|
|
+ virtual isc::datasrc::ZoneFinderContextPtr
|
|
|
+ find(const isc::dns::Name& name,
|
|
|
+ const isc::dns::RRType& type,
|
|
|
+ isc::datasrc::ZoneFinder::FindOptions options)
|
|
|
+ {
|
|
|
+ checkThrow(THROW_AT_FIND, throw_when_, isc_exception_);
|
|
|
+ return (real_zone_finder_->find(name, type, options));
|
|
|
+ }
|
|
|
+
|
|
|
+ virtual isc::datasrc::ZoneFinderContextPtr
|
|
|
+ findAll(const isc::dns::Name& name,
|
|
|
+ std::vector<isc::dns::ConstRRsetPtr> &target,
|
|
|
+ const FindOptions options = FIND_DEFAULT)
|
|
|
+ {
|
|
|
+ checkThrow(THROW_AT_FIND_ALL, throw_when_, isc_exception_);
|
|
|
+ return (real_zone_finder_->findAll(name, target, options));
|
|
|
+ }
|
|
|
+
|
|
|
+ virtual FindNSEC3Result
|
|
|
+ findNSEC3(const isc::dns::Name& name, bool recursive) {
|
|
|
+ checkThrow(THROW_AT_FIND_NSEC3, throw_when_, isc_exception_);
|
|
|
+ return (real_zone_finder_->findNSEC3(name, recursive));
|
|
|
+ }
|
|
|
+
|
|
|
+ virtual isc::dns::Name
|
|
|
+ findPreviousName(const isc::dns::Name& query) const {
|
|
|
+ return (real_zone_finder_->findPreviousName(query));
|
|
|
+ }
|
|
|
+
|
|
|
+private:
|
|
|
+ isc::datasrc::ZoneFinderPtr real_zone_finder_;
|
|
|
+ ThrowWhen throw_when_;
|
|
|
+ bool isc_exception_;
|
|
|
+};
|
|
|
+
|
|
|
+/// \brief Proxy InMemoryClient that can throw exceptions at specified times
|
|
|
+///
|
|
|
+/// It is based on the memory client since that one is easy to override
|
|
|
+/// (with setInMemoryClient) with the current design of AuthSrv.
|
|
|
+class FakeInMemoryClient : public isc::datasrc::InMemoryClient {
|
|
|
+public:
|
|
|
+ /// \brief Create a proxy memory client
|
|
|
+ ///
|
|
|
+ /// \param real_client The real in-memory client to proxy
|
|
|
+ /// \param throw_when if set to any value other than never, that is
|
|
|
+ /// the method that will throw an exception (either in this
|
|
|
+ /// class or the related FakeZoneFinder)
|
|
|
+ /// \param isc_exception if true, throw isc::Exception, otherwise,
|
|
|
+ /// throw std::exception
|
|
|
+ FakeInMemoryClient(AuthSrv::InMemoryClientPtr real_client,
|
|
|
+ ThrowWhen throw_when,
|
|
|
+ bool isc_exception) :
|
|
|
+ real_client_(real_client),
|
|
|
+ throw_when_(throw_when),
|
|
|
+ isc_exception_(isc_exception)
|
|
|
+ {}
|
|
|
+
|
|
|
+ /// \brief proxy call for findZone
|
|
|
+ ///
|
|
|
+ /// if this instance was constructed with throw_when set to find_zone,
|
|
|
+ /// this method will throw. Otherwise, it will return a FakeZoneFinder
|
|
|
+ /// instance which will throw at the method specified at the
|
|
|
+ /// construction of this instance.
|
|
|
+ virtual FindResult
|
|
|
+ findZone(const isc::dns::Name& name) const {
|
|
|
+ checkThrow(THROW_AT_FIND_ZONE, throw_when_, isc_exception_);
|
|
|
+ const FindResult result = real_client_->findZone(name);
|
|
|
+ return (FindResult(result.code, isc::datasrc::ZoneFinderPtr(
|
|
|
+ new FakeZoneFinder(result.zone_finder,
|
|
|
+ throw_when_,
|
|
|
+ isc_exception_))));
|
|
|
+ }
|
|
|
+
|
|
|
+private:
|
|
|
+ AuthSrv::InMemoryClientPtr real_client_;
|
|
|
+ ThrowWhen throw_when_;
|
|
|
+ bool isc_exception_;
|
|
|
+};
|
|
|
+
|
|
|
+} // end anonymous namespace for throwing proxy classes
|
|
|
+
|
|
|
+// Test for the tests
|
|
|
+//
|
|
|
+// Set the proxies to never throw, this should have the same result as
|
|
|
+// queryWithInMemoryClientNoDNSSEC, and serves to test the two proxy classes
|
|
|
+TEST_F(AuthSrvTest, queryWithInMemoryClientProxy) {
|
|
|
+ // Set real inmem client to proxy
|
|
|
+ updateConfig(&server, CONFIG_INMEMORY_EXAMPLE, true);
|
|
|
+
|
|
|
+ AuthSrv::InMemoryClientPtr fake_client(
|
|
|
+ new FakeInMemoryClient(server.getInMemoryClient(rrclass),
|
|
|
+ THROW_NEVER,
|
|
|
+ false));
|
|
|
+
|
|
|
+ ASSERT_NE(AuthSrv::InMemoryClientPtr(), server.getInMemoryClient(rrclass));
|
|
|
+ server.setInMemoryClient(rrclass, fake_client);
|
|
|
+
|
|
|
+ createDataFromFile("nsec3query_nodnssec_fromWire.wire");
|
|
|
+ server.processMessage(*io_message, *parse_message, *response_obuffer,
|
|
|
+ &dnsserv);
|
|
|
+
|
|
|
+ EXPECT_TRUE(dnsserv.hasAnswer());
|
|
|
+ headerCheck(*parse_message, default_qid, Rcode::NOERROR(),
|
|
|
+ opcode.getCode(), QR_FLAG | AA_FLAG, 1, 1, 2, 1);
|
|
|
+}
|
|
|
+
|
|
|
+// Convenience function for the rest of the tests, set up a proxy
|
|
|
+// to throw in the given method
|
|
|
+// If isc_exception is true, it will throw isc::Exception, otherwise
|
|
|
+// it will throw std::exception
|
|
|
+void
|
|
|
+setupThrow(AuthSrv* server, const char *config, ThrowWhen throw_when,
|
|
|
+ bool isc_exception)
|
|
|
+{
|
|
|
+ // Set real inmem client to proxy
|
|
|
+ updateConfig(server, config, true);
|
|
|
+
|
|
|
+ // Set it to throw on findZone(), this should result in
|
|
|
+ // SERVFAIL on any exception
|
|
|
+ AuthSrv::InMemoryClientPtr fake_client(
|
|
|
+ new FakeInMemoryClient(
|
|
|
+ server->getInMemoryClient(isc::dns::RRClass::IN()),
|
|
|
+ throw_when,
|
|
|
+ isc_exception));
|
|
|
+
|
|
|
+ ASSERT_NE(AuthSrv::InMemoryClientPtr(),
|
|
|
+ server->getInMemoryClient(isc::dns::RRClass::IN()));
|
|
|
+ server->setInMemoryClient(isc::dns::RRClass::IN(), fake_client);
|
|
|
+}
|
|
|
+
|
|
|
+TEST_F(AuthSrvTest, queryWithThrowingProxyServfails) {
|
|
|
+ // Test the common cases, all of which should simply return SERVFAIL
|
|
|
+ // Use THROW_NEVER as end marker
|
|
|
+ ThrowWhen throws[] = { THROW_AT_FIND_ZONE,
|
|
|
+ THROW_AT_GET_ORIGIN,
|
|
|
+ THROW_AT_FIND,
|
|
|
+ THROW_AT_FIND_NSEC3,
|
|
|
+ THROW_NEVER };
|
|
|
+ UnitTestUtil::createDNSSECRequestMessage(request_message, opcode,
|
|
|
+ default_qid, Name("foo.example."),
|
|
|
+ RRClass::IN(), RRType::TXT());
|
|
|
+ for (ThrowWhen* when(throws); *when != THROW_NEVER; ++when) {
|
|
|
+ createRequestPacket(request_message, IPPROTO_UDP);
|
|
|
+ setupThrow(&server, CONFIG_INMEMORY_EXAMPLE, *when, true);
|
|
|
+ processAndCheckSERVFAIL();
|
|
|
+ // To be sure, check same for non-isc-exceptions
|
|
|
+ createRequestPacket(request_message, IPPROTO_UDP);
|
|
|
+ setupThrow(&server, CONFIG_INMEMORY_EXAMPLE, *when, false);
|
|
|
+ processAndCheckSERVFAIL();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// Throw isc::Exception in getClass(). (Currently?) getClass is not called
|
|
|
+// in the processMessage path, so this should result in a normal answer
|
|
|
+TEST_F(AuthSrvTest, queryWithInMemoryClientProxyGetClass) {
|
|
|
+ createDataFromFile("nsec3query_nodnssec_fromWire.wire");
|
|
|
+ setupThrow(&server, CONFIG_INMEMORY_EXAMPLE, THROW_AT_GET_CLASS, true);
|
|
|
+
|
|
|
+ // getClass is not called so it should just answer
|
|
|
+ server.processMessage(*io_message, *parse_message, *response_obuffer,
|
|
|
+ &dnsserv);
|
|
|
+
|
|
|
+ EXPECT_TRUE(dnsserv.hasAnswer());
|
|
|
+ headerCheck(*parse_message, default_qid, Rcode::NOERROR(),
|
|
|
+ opcode.getCode(), QR_FLAG | AA_FLAG, 1, 1, 2, 1);
|
|
|
+}
|
|
|
+
|
|
|
}
|