auth_srv_unittest.cc 44.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.

15
#include <config.h>
16 17 18

#include <vector>

19 20
#include <boost/shared_ptr.hpp>

21 22 23 24 25
#include <gtest/gtest.h>

#include <dns/message.h>
#include <dns/messagerenderer.h>
#include <dns/name.h>
26
#include <dns/opcode.h>
27 28 29 30
#include <dns/rrclass.h>
#include <dns/rrtype.h>
#include <dns/rrttl.h>
#include <dns/rdataclass.h>
31
#include <dns/tsig.h>
32

33
#include <server_common/portconfig.h>
34
#include <server_common/keyring.h>
35

JINMEI Tatuya's avatar
JINMEI Tatuya committed
36
#include <datasrc/memory_datasrc.h>
37
#include <auth/auth_srv.h>
38
#include <auth/common.h>
39
#include <auth/statistics.h>
40

41
#include <dns/tests/unittest_util.h>
JINMEI Tatuya's avatar
JINMEI Tatuya committed
42
#include <testutils/dnsmessage_test.h>
43
#include <testutils/srv_test.h>
44
#include <testutils/portconfig.h>
45
#include <testutils/socket_request.h>
46

JINMEI Tatuya's avatar
JINMEI Tatuya committed
47
using namespace std;
48
using namespace isc::cc;
49
using namespace isc::dns;
50
using namespace isc::util;
51
using namespace isc::dns::rdata;
52
using namespace isc::data;
53
using namespace isc::xfr;
54 55
using namespace isc::asiodns;
using namespace isc::asiolink;
56
using namespace isc::testutils;
57
using namespace isc::server_common::portconfig;
Evan Hunt's avatar
Evan Hunt committed
58
using isc::UnitTestUtil;
59 60

namespace {
61
const char* const CONFIG_TESTDB =
62
    "{\"database_file\": \"" TEST_DATA_DIR "/example.sqlite3\"}";
63 64
// The following file must be non existent and must be non"creatable" (see
// the sqlite3 test).
65
const char* const BADCONFIG_TESTDB =
66
    "{ \"database_file\": \"" TEST_DATA_DIR "/nodir/notexist\"}";
67

68 69 70 71 72 73 74
// 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\"}]}]}";

75
class AuthSrvTest : public SrvTestBase {
76
protected:
77 78 79
    AuthSrvTest() :
        dnss_(ios_, NULL, NULL, NULL),
        server(true, xfrout),
80
        rrclass(RRClass::IN()),
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
81 82 83
        // 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).
84
        sock_requestor_(dnss_, address_store_, 53210, "")
85 86
    {
        server.setDNSService(dnss_);
87
        server.setXfrinSession(&notify_session);
88
        server.setStatisticsSession(&statistics_session);
89
    }
90 91 92 93
    virtual void processMessage() {
        server.processMessage(*io_message, parse_message, response_obuffer,
                              &dnsserv);
    }
94

95 96
    // Helper for checking Rcode statistic counters;
    // Checks for one specific Rcode statistics counter value
JINMEI Tatuya's avatar
JINMEI Tatuya committed
97
    void checkRcodeCounter(const Rcode& rcode, int expected_value) const {
98 99 100 101 102
        EXPECT_EQ(expected_value, server.getCounter(rcode)) <<
                  "Expected Rcode count for " << rcode.toText() <<
                  " " << expected_value << ", was: " <<
                  server.getCounter(rcode);
    }
103

104
    // Checks whether all Rcode counters are set to zero
JINMEI Tatuya's avatar
JINMEI Tatuya committed
105
    void checkAllRcodeCountersZero() const {
106 107 108 109
        for (int i = 0; i < 17; i++) {
            checkRcodeCounter(Rcode(i), 0);
        }
    }
110

111 112
    // Checks whether all Rcode counters are set to zero except the given
    // rcode (it is checked to be set to 'value')
JINMEI Tatuya's avatar
JINMEI Tatuya committed
113
    void checkAllRcodeCountersZeroExcept(const Rcode& rcode, int value) const {
114 115 116 117 118 119 120 121 122
        for (int i = 0; i < 17; i++) {
            const Rcode rc(i);
            if (rc == rcode) {
                checkRcodeCounter(Rcode(i), value);
            } else {
                checkRcodeCounter(Rcode(i), 0);
            }
        }
    }
123 124
    IOService ios_;
    DNSService dnss_;
125
    MockSession statistics_session;
126
    MockXfroutClient xfrout;
127
    AuthSrv server;
JINMEI Tatuya's avatar
JINMEI Tatuya committed
128
    const RRClass rrclass;
129
    vector<uint8_t> response_data;
130
    AddressList address_store_;
131
    TestSocketRequestor sock_requestor_;
132 133
};

134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
// A helper function that builds a response to version.bind/TXT/CH that
// should be identical to the response from our builtin (static) data source
// by default.  The resulting wire-format data will be stored in 'data'.
void
createBuiltinVersionResponse(const qid_t qid, vector<uint8_t>& data) {
    const Name version_name("version.bind");
    Message message(Message::RENDER);

    UnitTestUtil::createRequestMessage(message, Opcode::QUERY(),
                                       qid, version_name,
                                       RRClass::CH(), RRType::TXT());
    message.setHeaderFlag(Message::HEADERFLAG_QR);
    message.setHeaderFlag(Message::HEADERFLAG_AA);
    RRsetPtr rrset_version = RRsetPtr(new RRset(version_name, RRClass::CH(),
                                                RRType::TXT(), RRTTL(0)));
    rrset_version->addRdata(generic::TXT(PACKAGE_STRING));
    message.addRRset(Message::SECTION_ANSWER, rrset_version);

    RRsetPtr rrset_version_ns = RRsetPtr(new RRset(version_name, RRClass::CH(),
                                                   RRType::NS(), RRTTL(0)));
    rrset_version_ns->addRdata(generic::NS(version_name));
    message.addRRset(Message::SECTION_AUTHORITY, rrset_version_ns);

    OutputBuffer obuffer(0);
    MessageRenderer renderer(obuffer);
    message.toWire(renderer);

    data.clear();
    data.assign(static_cast<const uint8_t*>(renderer.getData()),
                static_cast<const uint8_t*>(renderer.getData()) +
                renderer.getLength());
}

// In the following tests we confirm the response data is rendered in
// wire format in the expected way.

// The most primitive check: checking the result of the processMessage()
// method
TEST_F(AuthSrvTest, builtInQuery) {
    UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
                                       default_qid, Name("version.bind"),
                                       RRClass::CH(), RRType::TXT());
    createRequestPacket(request_message, IPPROTO_UDP);
    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());
184
    checkAllRcodeCountersZeroExcept(Rcode::NOERROR(), 1);
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
}

// Same test emulating the UDPServer class behavior (defined in libasiolink).
// This is not a good test in that it assumes internal implementation details
// of UDPServer, but we've encountered a regression due to the introduction
// of that class, so we add a test for that case to prevent such a regression
// in future.
// Besides, the generalization of UDPServer is probably too much for the
// authoritative only server in terms of performance, and it's quite likely
// we need to drop it for the authoritative server implementation.
// At that point we can drop this test, too.
TEST_F(AuthSrvTest, builtInQueryViaDNSServer) {
    UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
                                       default_qid, Name("version.bind"),
                                       RRClass::CH(), RRType::TXT());
    createRequestPacket(request_message, IPPROTO_UDP);

    (*server.getDNSLookupProvider())(*io_message, parse_message,
203
                                     response_message,
204 205
                                     response_obuffer, &dnsserv);
    (*server.getDNSAnswerProvider())(*io_message, parse_message,
206
                                     response_message, response_obuffer);
207 208 209 210 211 212 213 214 215 216 217 218

    createBuiltinVersionResponse(default_qid, response_data);
    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
                        response_obuffer->getData(),
                        response_obuffer->getLength(),
                        &response_data[0], response_data.size());
}

// Same type of test as builtInQueryViaDNSServer but for an error response.
TEST_F(AuthSrvTest, iqueryViaDNSServer) {
    createDataFromFile("iquery_fromWire.wire");
    (*server.getDNSLookupProvider())(*io_message, parse_message,
219
                                     response_message,
220 221
                                     response_obuffer, &dnsserv);
    (*server.getDNSAnswerProvider())(*io_message, parse_message,
222
                                     response_message, response_obuffer);
223 224 225 226 227 228 229 230 231

    UnitTestUtil::readWireData("iquery_response_fromWire.wire",
                               response_data);
    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
                        response_obuffer->getData(),
                        response_obuffer->getLength(),
                        &response_data[0], response_data.size());
}

232 233
// Unsupported requests.  Should result in NOTIMP.
TEST_F(AuthSrvTest, unsupportedRequest) {
234
    unsupportedRequest();
235 236
    // unsupportedRequest tries 14 different opcodes
    checkAllRcodeCountersZeroExcept(Rcode::NOTIMP(), 14);
237
}
238 239 240

// Multiple questions.  Should result in FORMERR.
TEST_F(AuthSrvTest, multiQuestion) {
241
    multiQuestion();
242
    checkAllRcodeCountersZeroExcept(Rcode::FORMERR(), 1);
243 244
}

245 246 247
// Incoming data doesn't even contain the complete header.  Must be silently
// dropped.
TEST_F(AuthSrvTest, shortMessage) {
248
    shortMessage();
249
    checkAllRcodeCountersZero();
250 251 252 253 254
}

// 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) {
255
    response();
256
    checkAllRcodeCountersZero();
257 258 259 260
}

// Query with a broken question
TEST_F(AuthSrvTest, shortQuestion) {
261
    shortQuestion();
262
    checkAllRcodeCountersZeroExcept(Rcode::FORMERR(), 1);
263
}
264

265 266
// Query with a broken answer section
TEST_F(AuthSrvTest, shortAnswer) {
267
    shortAnswer();
268
    checkAllRcodeCountersZeroExcept(Rcode::FORMERR(), 1);
269 270
}

271 272
// Query with unsupported version of EDNS.
TEST_F(AuthSrvTest, ednsBadVers) {
273
    ednsBadVers();
274
    checkAllRcodeCountersZeroExcept(Rcode::BADVERS(), 1);
275 276
}

JINMEI Tatuya's avatar
JINMEI Tatuya committed
277
TEST_F(AuthSrvTest, AXFROverUDP) {
278
    axfrOverUDP();
JINMEI Tatuya's avatar
JINMEI Tatuya committed
279 280
}

281 282
TEST_F(AuthSrvTest, AXFRSuccess) {
    EXPECT_FALSE(xfrout.isConnected());
Evan Hunt's avatar
Evan Hunt committed
283
    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
Jelte Jansen's avatar
Jelte Jansen committed
284 285
                                       Name("example.com"), RRClass::IN(),
                                       RRType::AXFR());
Evan Hunt's avatar
Evan Hunt committed
286
    createRequestPacket(request_message, IPPROTO_TCP);
287 288
    // On success, the AXFR query has been passed to a separate process,
    // so we shouldn't have to respond.
Evan Hunt's avatar
Evan Hunt committed
289 290
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_FALSE(dnsserv.hasAnswer());
291
    EXPECT_TRUE(xfrout.isConnected());
292
    checkAllRcodeCountersZero();
293 294
}

295 296 297 298
// Try giving the server a TSIG signed request and see it can anwer signed as
// well
TEST_F(AuthSrvTest, TSIGSigned) {
    // Prepare key, the client message, etc
299
    const TSIGKey key("key:c2VjcmV0Cg==:hmac-sha1");
300 301
    TSIGContext context(key);
    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
Jelte Jansen's avatar
Jelte Jansen committed
302 303
                                       Name("version.bind"), RRClass::CH(),
                                       RRType::TXT());
304 305
    createRequestPacket(request_message, IPPROTO_UDP, &context);

306
    // Run the message through the server
307
    boost::shared_ptr<TSIGKeyRing> keyring(new TSIGKeyRing);
308 309
    keyring->add(key);
    server.setTSIGKeyRing(&keyring);
310 311 312 313 314 315 316 317 318 319
    server.processMessage(*io_message, parse_message, response_obuffer,
                          &dnsserv);

    // What did we get?
    EXPECT_TRUE(dnsserv.hasAnswer());
    headerCheck(*parse_message, default_qid, Rcode::NOERROR(),
                opcode.getCode(), QR_FLAG | AA_FLAG, 1, 1, 1, 0);
    // We need to parse the message ourself, or getTSIGRecord won't work
    InputBuffer ib(response_obuffer->getData(), response_obuffer->getLength());
    Message m(Message::PARSE);
320
    m.fromWire(ib);
321 322

    const TSIGRecord* tsig = m.getTSIGRecord();
323
    ASSERT_TRUE(tsig != NULL) << "Missing TSIG signature";
324 325 326 327
    TSIGError error(context.verify(tsig, response_obuffer->getData(),
                                   response_obuffer->getLength()));
    EXPECT_EQ(TSIGError::NOERROR(), error) <<
        "The server signed the response, but it doesn't seem to be valid";
328 329

    checkAllRcodeCountersZeroExcept(Rcode::NOERROR(), 1);
330 331 332 333
}

// Give the server a signed request, but don't give it the key. It will
// not be able to verify it, returning BADKEY
334
TEST_F(AuthSrvTest, TSIGSignedBadKey) {
335 336 337
    TSIGKey key("key:c2VjcmV0Cg==:hmac-sha1");
    TSIGContext context(key);
    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
Jelte Jansen's avatar
Jelte Jansen committed
338 339
                                       Name("version.bind"), RRClass::CH(),
                                       RRType::TXT());
340 341 342
    createRequestPacket(request_message, IPPROTO_UDP, &context);

    // Process the message, but use a different key there
343
    boost::shared_ptr<TSIGKeyRing> keyring(new TSIGKeyRing);
344
    server.setTSIGKeyRing(&keyring);
345 346 347 348 349 350 351 352 353
    server.processMessage(*io_message, parse_message, response_obuffer,
                          &dnsserv);

    EXPECT_TRUE(dnsserv.hasAnswer());
    headerCheck(*parse_message, default_qid, TSIGError::BAD_KEY().toRcode(),
                opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
    // We need to parse the message ourself, or getTSIGRecord won't work
    InputBuffer ib(response_obuffer->getData(), response_obuffer->getLength());
    Message m(Message::PARSE);
354
    m.fromWire(ib);
355 356

    const TSIGRecord* tsig = m.getTSIGRecord();
357
    ASSERT_TRUE(tsig != NULL) <<
358
        "Missing TSIG signature (we should have one even at error)";
359
    EXPECT_EQ(TSIGError::BAD_KEY_CODE, tsig->getRdata().getError());
360 361
    EXPECT_EQ(0, tsig->getRdata().getMACSize()) <<
        "It should be unsigned with this error";
362 363

    checkAllRcodeCountersZeroExcept(Rcode::NOTAUTH(), 1);
364 365 366 367 368 369 370 371
}

// Give the server a signed request, but signed by a different key
// (with the same name). It should return BADSIG
TEST_F(AuthSrvTest, TSIGBadSig) {
    TSIGKey key("key:c2VjcmV0Cg==:hmac-sha1");
    TSIGContext context(key);
    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
Jelte Jansen's avatar
Jelte Jansen committed
372 373
                                       Name("version.bind"), RRClass::CH(),
                                       RRType::TXT());
374 375
    createRequestPacket(request_message, IPPROTO_UDP, &context);

376
    // Process the message, but use a different key there
377
    boost::shared_ptr<TSIGKeyRing> keyring(new TSIGKeyRing);
378 379
    keyring->add(TSIGKey("key:QkFECg==:hmac-sha1"));
    server.setTSIGKeyRing(&keyring);
380 381 382 383
    server.processMessage(*io_message, parse_message, response_obuffer,
                          &dnsserv);

    EXPECT_TRUE(dnsserv.hasAnswer());
384
    headerCheck(*parse_message, default_qid, TSIGError::BAD_SIG().toRcode(),
385 386 387 388
                opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
    // We need to parse the message ourself, or getTSIGRecord won't work
    InputBuffer ib(response_obuffer->getData(), response_obuffer->getLength());
    Message m(Message::PARSE);
389
    m.fromWire(ib);
390 391

    const TSIGRecord* tsig = m.getTSIGRecord();
392
    ASSERT_TRUE(tsig != NULL) <<
393
        "Missing TSIG signature (we should have one even at error)";
394
    EXPECT_EQ(TSIGError::BAD_SIG_CODE, tsig->getRdata().getError());
395 396
    EXPECT_EQ(0, tsig->getRdata().getMACSize()) <<
        "It should be unsigned with this error";
397 398

    checkAllRcodeCountersZeroExcept(Rcode::NOTAUTH(), 1);
399 400
}

401 402 403 404 405 406 407 408 409 410 411 412 413
// Give the server a signed unsupported request with a bad signature.
// This checks the server first verifies the signature before anything
// else.
TEST_F(AuthSrvTest, TSIGCheckFirst) {
    TSIGKey key("key:c2VjcmV0Cg==:hmac-sha1");
    TSIGContext context(key);
    // Pass a wrong opcode there. The server shouldn't know what to do
    // about it.
    UnitTestUtil::createRequestMessage(request_message, Opcode::RESERVED14(),
                                       default_qid, Name("version.bind"),
                                       RRClass::CH(), RRType::TXT());
    createRequestPacket(request_message, IPPROTO_UDP, &context);

414
    // Process the message, but use a different key there
415
    boost::shared_ptr<TSIGKeyRing> keyring(new TSIGKeyRing);
416 417
    keyring->add(TSIGKey("key:QkFECg==:hmac-sha1"));
    server.setTSIGKeyRing(&keyring);
418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434
    server.processMessage(*io_message, parse_message, response_obuffer,
                          &dnsserv);

    EXPECT_TRUE(dnsserv.hasAnswer());
    headerCheck(*parse_message, default_qid, TSIGError::BAD_SIG().toRcode(),
                Opcode::RESERVED14().getCode(), QR_FLAG, 0, 0, 0, 0);
    // We need to parse the message ourself, or getTSIGRecord won't work
    InputBuffer ib(response_obuffer->getData(), response_obuffer->getLength());
    Message m(Message::PARSE);
    m.fromWire(ib);

    const TSIGRecord* tsig = m.getTSIGRecord();
    ASSERT_TRUE(tsig != NULL) <<
        "Missing TSIG signature (we should have one even at error)";
    EXPECT_EQ(TSIGError::BAD_SIG_CODE, tsig->getRdata().getError());
    EXPECT_EQ(0, tsig->getRdata().getMACSize()) <<
        "It should be unsigned with this error";
435 436 437
    // TSIG should have failed, and so the per opcode counter shouldn't be
    // incremented.
    EXPECT_EQ(0, server.getCounter(Opcode::RESERVED14()));
438 439

    checkAllRcodeCountersZeroExcept(Rcode::NOTAUTH(), 1);
440 441
}

442 443 444
TEST_F(AuthSrvTest, AXFRConnectFail) {
    EXPECT_FALSE(xfrout.isConnected()); // check prerequisite
    xfrout.disableConnect();
Evan Hunt's avatar
Evan Hunt committed
445
    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
Jelte Jansen's avatar
Jelte Jansen committed
446 447
                                       Name("example.com"), RRClass::IN(),
                                       RRType::AXFR());
Evan Hunt's avatar
Evan Hunt committed
448 449 450
    createRequestPacket(request_message, IPPROTO_TCP);
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_TRUE(dnsserv.hasAnswer());
451
    headerCheck(*parse_message, default_qid, Rcode::SERVFAIL(),
452 453 454 455 456 457 458
                opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
    EXPECT_FALSE(xfrout.isConnected());
}

TEST_F(AuthSrvTest, AXFRSendFail) {
    // first send a valid query, making the connection with the xfr process
    // open.
Evan Hunt's avatar
Evan Hunt committed
459
    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
Jelte Jansen's avatar
Jelte Jansen committed
460 461
                                       Name("example.com"), RRClass::IN(),
                                       RRType::AXFR());
Evan Hunt's avatar
Evan Hunt committed
462 463
    createRequestPacket(request_message, IPPROTO_TCP);
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
464
    EXPECT_TRUE(xfrout.isConnected());
465 466

    xfrout.disableSend();
467 468
    parse_message->clear(Message::PARSE);
    response_obuffer->clear();
Evan Hunt's avatar
Evan Hunt committed
469
    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
Jelte Jansen's avatar
Jelte Jansen committed
470 471
                                       Name("example.com"), RRClass::IN(),
                                       RRType::AXFR());
Evan Hunt's avatar
Evan Hunt committed
472 473 474
    createRequestPacket(request_message, IPPROTO_TCP);
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_TRUE(dnsserv.hasAnswer());
475
    headerCheck(*parse_message, default_qid, Rcode::SERVFAIL(),
476 477 478 479 480 481 482 483 484 485 486
                opcode.getCode(), QR_FLAG, 1, 0, 0, 0);

    // The connection should have been closed due to the send failure.
    EXPECT_FALSE(xfrout.isConnected());
}

TEST_F(AuthSrvTest, AXFRDisconnectFail) {
    // In our usage disconnect() shouldn't fail.  So we'll see the exception
    // should it be thrown.
    xfrout.disableSend();
    xfrout.disableDisconnect();
Evan Hunt's avatar
Evan Hunt committed
487
    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
Jelte Jansen's avatar
Jelte Jansen committed
488 489
                                       Name("example.com"), RRClass::IN(),
                                       RRType::AXFR());
Evan Hunt's avatar
Evan Hunt committed
490
    createRequestPacket(request_message, IPPROTO_TCP);
491
    EXPECT_THROW(server.processMessage(*io_message, parse_message,
Evan Hunt's avatar
Evan Hunt committed
492
                                       response_obuffer, &dnsserv),
493 494 495 496 497 498 499
                 XfroutError);
    EXPECT_TRUE(xfrout.isConnected());
    // XXX: we need to re-enable disconnect.  otherwise an exception would be
    // thrown via the destructor of the server.
    xfrout.enableDisconnect();
}

500 501 502 503
TEST_F(AuthSrvTest, IXFRConnectFail) {
    EXPECT_FALSE(xfrout.isConnected()); // check prerequisite
    xfrout.disableConnect();
    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
Jelte Jansen's avatar
Jelte Jansen committed
504 505
                                       Name("example.com"), RRClass::IN(),
                                       RRType::IXFR());
506 507 508 509 510 511 512 513 514 515 516 517
    createRequestPacket(request_message, IPPROTO_TCP);
    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);
    EXPECT_FALSE(xfrout.isConnected());
}

TEST_F(AuthSrvTest, IXFRSendFail) {
    // first send a valid query, making the connection with the xfr process
    // open.
    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
Jelte Jansen's avatar
Jelte Jansen committed
518 519
                                       Name("example.com"), RRClass::IN(),
                                       RRType::IXFR());
520 521 522 523 524 525 526 527
    createRequestPacket(request_message, IPPROTO_TCP);
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_TRUE(xfrout.isConnected());

    xfrout.disableSend();
    parse_message->clear(Message::PARSE);
    response_obuffer->clear();
    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
Jelte Jansen's avatar
Jelte Jansen committed
528 529
                                       Name("example.com"), RRClass::IN(),
                                       RRType::IXFR());
530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545
    createRequestPacket(request_message, IPPROTO_TCP);
    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);

    // The connection should have been closed due to the send failure.
    EXPECT_FALSE(xfrout.isConnected());
}

TEST_F(AuthSrvTest, IXFRDisconnectFail) {
    // In our usage disconnect() shouldn't fail.  So we'll see the exception
    // should it be thrown.
    xfrout.disableSend();
    xfrout.disableDisconnect();
    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
Jelte Jansen's avatar
Jelte Jansen committed
546 547
                                       Name("example.com"), RRClass::IN(),
                                       RRType::IXFR());
548 549 550 551 552 553 554 555 556 557
    createRequestPacket(request_message, IPPROTO_TCP);
    EXPECT_THROW(server.processMessage(*io_message, parse_message,
                                       response_obuffer, &dnsserv),
                 XfroutError);
    EXPECT_TRUE(xfrout.isConnected());
    // XXX: we need to re-enable disconnect.  otherwise an exception would be
    // thrown via the destructor of the server.
    xfrout.enableDisconnect();
}

558
TEST_F(AuthSrvTest, notify) {
Jelte Jansen's avatar
Jelte Jansen committed
559 560 561
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
                                       default_qid, Name("example.com"),
                                       RRClass::IN(), RRType::SOA());
562
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
Evan Hunt's avatar
Evan Hunt committed
563 564 565
    createRequestPacket(request_message, IPPROTO_UDP);
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_TRUE(dnsserv.hasAnswer());
566 567 568

    // An internal command message should have been created and sent to an
    // external module.  Check them.
Evan Hunt's avatar
Evan Hunt committed
569
    EXPECT_EQ("Zonemgr", notify_session.getMessageDest());
570
    EXPECT_EQ("notify",
Evan Hunt's avatar
Evan Hunt committed
571
              notify_session.getSentMessage()->get("command")->get(0)->stringValue());
572
    ConstElementPtr notify_args =
Evan Hunt's avatar
Evan Hunt committed
573
        notify_session.getSentMessage()->get("command")->get(1);
574 575 576
    EXPECT_EQ("example.com.", notify_args->get("zone_name")->stringValue());
    EXPECT_EQ(DEFAULT_REMOTE_ADDRESS,
              notify_args->get("master")->stringValue());
577
    EXPECT_EQ("IN", notify_args->get("zone_class")->stringValue());
578 579

    // On success, the server should return a response to the notify.
580
    headerCheck(*parse_message, default_qid, Rcode::NOERROR(),
581 582
                Opcode::NOTIFY().getCode(), QR_FLAG | AA_FLAG, 1, 0, 0, 0);

583
    // The question must be identical to that of the received notify
584
    ConstQuestionPtr question = *parse_message->beginQuestion();
585 586 587
    EXPECT_EQ(Name("example.com"), question->getName());
    EXPECT_EQ(RRClass::IN(), question->getClass());
    EXPECT_EQ(RRType::SOA(), question->getType());
588 589

    checkAllRcodeCountersZeroExcept(Rcode::NOERROR(), 1);
590 591
}

592 593
TEST_F(AuthSrvTest, notifyForCHClass) {
    // Same as the previous test, but for the CH RRClass.
Jelte Jansen's avatar
Jelte Jansen committed
594 595 596
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
                                       default_qid, Name("example.com"),
                                       RRClass::CH(), RRType::SOA());
597
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
Evan Hunt's avatar
Evan Hunt committed
598 599 600
    createRequestPacket(request_message, IPPROTO_UDP);
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_TRUE(dnsserv.hasAnswer());
601 602 603

    // Other conditions should be the same, so simply confirm the RR class is
    // set correctly.
604
    ConstElementPtr notify_args =
Evan Hunt's avatar
Evan Hunt committed
605
        notify_session.getSentMessage()->get("command")->get(1);
606
    EXPECT_EQ("CH", notify_args->get("zone_class")->stringValue());
607 608
}

609 610 611
TEST_F(AuthSrvTest, notifyEmptyQuestion) {
    request_message.clear(Message::RENDER);
    request_message.setOpcode(Opcode::NOTIFY());
612
    request_message.setRcode(Rcode::NOERROR());
613
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
614 615
    request_message.setQid(default_qid);
    request_message.toWire(request_renderer);
Evan Hunt's avatar
Evan Hunt committed
616 617 618
    createRequestPacket(request_message, IPPROTO_UDP);
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_TRUE(dnsserv.hasAnswer());
619
    headerCheck(*parse_message, default_qid, Rcode::FORMERR(),
620 621 622 623
                Opcode::NOTIFY().getCode(), QR_FLAG, 0, 0, 0, 0);
}

TEST_F(AuthSrvTest, notifyMultiQuestions) {
Jelte Jansen's avatar
Jelte Jansen committed
624 625 626
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
                                       default_qid, Name("example.com"),
                                       RRClass::IN(), RRType::SOA());
627 628 629
    // add one more SOA question
    request_message.addQuestion(Question(Name("example.com"), RRClass::IN(),
                                         RRType::SOA()));
630
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
Evan Hunt's avatar
Evan Hunt committed
631 632 633
    createRequestPacket(request_message, IPPROTO_UDP);
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_TRUE(dnsserv.hasAnswer());
634
    headerCheck(*parse_message, default_qid, Rcode::FORMERR(),
635 636 637 638
                Opcode::NOTIFY().getCode(), QR_FLAG, 2, 0, 0, 0);
}

TEST_F(AuthSrvTest, notifyNonSOAQuestion) {
Jelte Jansen's avatar
Jelte Jansen committed
639 640 641
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
                                       default_qid, Name("example.com"),
                                       RRClass::IN(), RRType::NS());
642
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
Evan Hunt's avatar
Evan Hunt committed
643 644 645
    createRequestPacket(request_message, IPPROTO_UDP);
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_TRUE(dnsserv.hasAnswer());
646
    headerCheck(*parse_message, default_qid, Rcode::FORMERR(),
647 648 649 650 651
                Opcode::NOTIFY().getCode(), QR_FLAG, 1, 0, 0, 0);
}

TEST_F(AuthSrvTest, notifyWithoutAA) {
    // implicitly leave the AA bit off.  our implementation will accept it.
Jelte Jansen's avatar
Jelte Jansen committed
652 653 654
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
                                       default_qid, Name("example.com"),
                                       RRClass::IN(), RRType::SOA());
Evan Hunt's avatar
Evan Hunt committed
655 656 657
    createRequestPacket(request_message, IPPROTO_UDP);
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_TRUE(dnsserv.hasAnswer());
658
    headerCheck(*parse_message, default_qid, Rcode::NOERROR(),
659 660 661 662
                Opcode::NOTIFY().getCode(), QR_FLAG | AA_FLAG, 1, 0, 0, 0);
}

TEST_F(AuthSrvTest, notifyWithErrorRcode) {
Jelte Jansen's avatar
Jelte Jansen committed
663 664 665
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
                                       default_qid, Name("example.com"),
                                       RRClass::IN(), RRType::SOA());
666
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
667
    request_message.setRcode(Rcode::SERVFAIL());
Evan Hunt's avatar
Evan Hunt committed
668 669 670
    createRequestPacket(request_message, IPPROTO_UDP);
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_TRUE(dnsserv.hasAnswer());
671
    headerCheck(*parse_message, default_qid, Rcode::NOERROR(),
672
                Opcode::NOTIFY().getCode(), QR_FLAG | AA_FLAG, 1, 0, 0, 0);
Han Feng's avatar
Han Feng committed
673 674
}

675
TEST_F(AuthSrvTest, notifyWithoutSession) {
676
    server.setXfrinSession(NULL);
677

Jelte Jansen's avatar
Jelte Jansen committed
678 679 680
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
                                       default_qid, Name("example.com"),
                                       RRClass::IN(), RRType::SOA());
681
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
Evan Hunt's avatar
Evan Hunt committed
682
    createRequestPacket(request_message, IPPROTO_UDP);
683 684 685

    // we simply ignore the notify and let it be resent if an internal error
    // happens.
Evan Hunt's avatar
Evan Hunt committed
686 687
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_FALSE(dnsserv.hasAnswer());
688 689 690 691 692
}

TEST_F(AuthSrvTest, notifySendFail) {
    notify_session.disableSend();

Jelte Jansen's avatar
Jelte Jansen committed
693 694 695
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
                                       default_qid, Name("example.com"),
                                       RRClass::IN(), RRType::SOA());
696
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
Evan Hunt's avatar
Evan Hunt committed
697
    createRequestPacket(request_message, IPPROTO_UDP);
698

Evan Hunt's avatar
Evan Hunt committed
699 700
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_FALSE(dnsserv.hasAnswer());
701 702 703 704 705
}

TEST_F(AuthSrvTest, notifyReceiveFail) {
    notify_session.disableReceive();

Jelte Jansen's avatar
Jelte Jansen committed
706 707 708
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
                                       default_qid, Name("example.com"),
                                       RRClass::IN(), RRType::SOA());
709
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
Evan Hunt's avatar
Evan Hunt committed
710 711 712
    createRequestPacket(request_message, IPPROTO_UDP);
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_FALSE(dnsserv.hasAnswer());
713 714 715
}

TEST_F(AuthSrvTest, notifyWithBogusSessionMessage) {
716
    notify_session.setMessage(Element::fromJSON("{\"foo\": 1}"));
717

Jelte Jansen's avatar
Jelte Jansen committed
718 719 720
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
                                       default_qid, Name("example.com"),
                                       RRClass::IN(), RRType::SOA());
721
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
Evan Hunt's avatar
Evan Hunt committed
722 723 724
    createRequestPacket(request_message, IPPROTO_UDP);
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_FALSE(dnsserv.hasAnswer());
725 726 727 728
}

TEST_F(AuthSrvTest, notifyWithSessionMessageError) {
    notify_session.setMessage(
729
        Element::fromJSON("{\"result\": [1, \"FAIL\"]}"));
730

Jelte Jansen's avatar
Jelte Jansen committed
731 732 733
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
                                       default_qid, Name("example.com"),
                                       RRClass::IN(), RRType::SOA());
734
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
Evan Hunt's avatar
Evan Hunt committed
735 736 737
    createRequestPacket(request_message, IPPROTO_UDP);
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_FALSE(dnsserv.hasAnswer());
738 739
}

740
void
JINMEI Tatuya's avatar
JINMEI Tatuya committed
741
updateConfig(AuthSrv* server, const char* const config_data,
742 743
             const bool expect_success)
{
744
    ConstElementPtr config_answer =
JINMEI Tatuya's avatar
JINMEI Tatuya committed
745
        server->updateConfig(Element::fromJSON(config_data));
746 747 748
    EXPECT_EQ(Element::map, config_answer->getType());
    EXPECT_TRUE(config_answer->contains("result"));

749
    ConstElementPtr result = config_answer->get("result");
750
    EXPECT_EQ(Element::list, result->getType());
751
    EXPECT_EQ(expect_success ? 0 : 1, result->get(0)->intValue());
752 753 754 755
}

// Install a Sqlite3 data source with testing data.
TEST_F(AuthSrvTest, updateConfig) {
756
    updateConfig(&server, CONFIG_TESTDB, true);
757 758 759 760

    // query for existent data in the installed data source.  The resulting
    // response should have the AA flag on, and have an RR in each answer
    // and authority section.
761
    createDataFromFile("examplequery_fromWire.wire");
Evan Hunt's avatar
Evan Hunt committed
762 763
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_TRUE(dnsserv.hasAnswer());
764
    headerCheck(*parse_message, default_qid, Rcode::NOERROR(), opcode.getCode(),
765 766 767 768
                QR_FLAG | AA_FLAG, 1, 1, 1, 0);
}

TEST_F(AuthSrvTest, datasourceFail) {
769
    updateConfig(&server, CONFIG_TESTDB, true);
770 771 772 773 774

    // This query will hit a corrupted entry of the data source (the zoneload
    // tool and the data source itself naively accept it).  This will result
    // in a SERVFAIL response, and the answer and authority sections should
    // be empty.
775
    createDataFromFile("badExampleQuery_fromWire.wire");
Evan Hunt's avatar
Evan Hunt committed
776 777
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_TRUE(dnsserv.hasAnswer());
778
    headerCheck(*parse_message, default_qid, Rcode::SERVFAIL(),
779
                opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
780
}
781 782 783 784 785 786 787 788 789

TEST_F(AuthSrvTest, updateConfigFail) {
    // First, load a valid data source.
    updateConfig(&server, CONFIG_TESTDB, true);

    // Next, try to update it with a non-existent one.  This should fail.
    updateConfig(&server, BADCONFIG_TESTDB, false);

    // The original data source should still exist.
790
    createDataFromFile("examplequery_fromWire.wire");
Evan Hunt's avatar
Evan Hunt committed
791 792
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_TRUE(dnsserv.hasAnswer());
793
    headerCheck(*parse_message, default_qid, Rcode::NOERROR(), opcode.getCode(),
794 795
                QR_FLAG | AA_FLAG, 1, 1, 1, 0);
}
JINMEI Tatuya's avatar
JINMEI Tatuya committed
796

797
TEST_F(AuthSrvTest, updateWithInMemoryClient) {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
798 799 800 801
    // Test configuring memory data source.  Detailed test cases are covered
    // in the configuration tests.  We only check the AuthSrv interface here.

    // By default memory data source isn't enabled
802
    EXPECT_EQ(AuthSrv::InMemoryClientPtr(), server.getInMemoryClient(rrclass));
JINMEI Tatuya's avatar
JINMEI Tatuya committed
803 804 805
    updateConfig(&server,
                 "{\"datasources\": [{\"type\": \"memory\"}]}", true);
    // after successful configuration, we should have one (with empty zoneset).
806 807
    ASSERT_NE(AuthSrv::InMemoryClientPtr(), server.getInMemoryClient(rrclass));
    EXPECT_EQ(0, server.getInMemoryClient(rrclass)->getZoneCount());
Jerry's avatar
Jerry committed
808

809
    // The memory data source is empty, should return REFUSED rcode.
Jerry's avatar
Jerry committed
810
    createDataFromFile("examplequery_fromWire.wire");
811 812 813 814 815 816 817
    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);
}

818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852
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);
}

853
TEST_F(AuthSrvTest, chQueryWithInMemoryClient) {
854 855 856 857 858 859 860 861 862 863 864
    // Configure memory data source for class IN
    updateConfig(&server, "{\"datasources\": "
                 "[{\"class\": \"IN\", \"type\": \"memory\"}]}", true);

    // This shouldn't affect the result of class CH query
    UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
                                       default_qid, Name("version.bind"),
                                       RRClass::CH(), RRType::TXT());
    createRequestPacket(request_message, IPPROTO_UDP);
    server.processMessage(*io_message, parse_message, response_obuffer,
                          &dnsserv);
865
    EXPECT_TRUE(dnsserv.hasAnswer());
866 867
    headerCheck(*parse_message, default_qid, Rcode::NOERROR(),
                opcode.getCode(), QR_FLAG | AA_FLAG, 1, 1, 1, 0);
JINMEI Tatuya's avatar
JINMEI Tatuya committed
868 869
}

JINMEI Tatuya's avatar
JINMEI Tatuya committed
870 871 872 873 874 875 876 877 878
TEST_F(AuthSrvTest, cacheSlots) {
    // simple check for the get/set operations
    server.setCacheSlots(10);    // 10 = arbitrary choice
    EXPECT_EQ(10, server.getCacheSlots());

    // 0 is a valid size
    server.setCacheSlots(0);
    EXPECT_EQ(00, server.getCacheSlots());
}
879

880 881 882
// Submit UDP normal query and check query counter
TEST_F(AuthSrvTest, queryCounterUDPNormal) {
    // The counter should be initialized to 0.
883
    EXPECT_EQ(0, server.getCounter(AuthCounters::SERVER_UDP_QUERY));
884 885 886 887 888 889 890
    // Create UDP message and process.
    UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
                                       default_qid, Name("example.com"),
                                       RRClass::IN(), RRType::NS());
    createRequestPacket(request_message, IPPROTO_UDP);
    server.processMessage(*io_message, parse_message, response_obuffer,
                          &dnsserv);
891
    // After processing UDP query, the counter should be 1.
892
    EXPECT_EQ(1, server.getCounter(AuthCounters::SERVER_UDP_QUERY));
Jelte Jansen's avatar
Jelte Jansen committed
893
    // The counter for opcode Query should also be one
894 895 896
    EXPECT_EQ(1, server.getCounter(Opcode::QUERY()));
    // The counter for REFUSED responses should also be one, the rest zero
    checkAllRcodeCountersZeroExcept(Rcode::REFUSED(), 1);