auth_srv_unittest.cc 45.4 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
    virtual void processMessage() {
91
        server.processMessage(*io_message, *parse_message, *response_obuffer,
92 93
                              &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
// 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);
177
    server.processMessage(*io_message, *parse_message, *response_obuffer,
178 179 180 181 182 183
                          &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.
289 290
    server.processMessage(*io_message, *parse_message, *response_obuffer,
                          &dnsserv);
Evan Hunt's avatar
Evan Hunt committed
291
    EXPECT_FALSE(dnsserv.hasAnswer());
292
    EXPECT_TRUE(xfrout.isConnected());
293
    checkAllRcodeCountersZero();
294 295
}

296 297 298 299
// 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
300
    const TSIGKey key("key:c2VjcmV0Cg==:hmac-sha1");
301 302
    TSIGContext context(key);
    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
Jelte Jansen's avatar
Jelte Jansen committed
303 304
                                       Name("version.bind"), RRClass::CH(),
                                       RRType::TXT());
305 306
    createRequestPacket(request_message, IPPROTO_UDP, &context);

307
    // Run the message through the server
308
    boost::shared_ptr<TSIGKeyRing> keyring(new TSIGKeyRing);
309 310
    keyring->add(key);
    server.setTSIGKeyRing(&keyring);
311
    server.processMessage(*io_message, *parse_message, *response_obuffer,
312 313 314 315 316 317 318 319 320
                          &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);
321
    m.fromWire(ib);
322 323

    const TSIGRecord* tsig = m.getTSIGRecord();
324
    ASSERT_TRUE(tsig != NULL) << "Missing TSIG signature";
325 326 327 328
    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";
329 330

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

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

    // Process the message, but use a different key there
344
    boost::shared_ptr<TSIGKeyRing> keyring(new TSIGKeyRing);
345
    server.setTSIGKeyRing(&keyring);
346
    server.processMessage(*io_message, *parse_message, *response_obuffer,
347 348 349 350 351 352 353 354
                          &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);
355
    m.fromWire(ib);
356 357

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

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

// 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
373 374
                                       Name("version.bind"), RRClass::CH(),
                                       RRType::TXT());
375 376
    createRequestPacket(request_message, IPPROTO_UDP, &context);

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

    EXPECT_TRUE(dnsserv.hasAnswer());
385
    headerCheck(*parse_message, default_qid, TSIGError::BAD_SIG().toRcode(),
386 387 388 389
                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);
390
    m.fromWire(ib);
391 392

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

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

402 403 404 405 406 407 408 409 410 411 412 413 414
// 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);

415
    // Process the message, but use a different key there
416
    boost::shared_ptr<TSIGKeyRing> keyring(new TSIGKeyRing);
417 418
    keyring->add(TSIGKey("key:QkFECg==:hmac-sha1"));
    server.setTSIGKeyRing(&keyring);
419
    server.processMessage(*io_message, *parse_message, *response_obuffer,
420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435
                          &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";
436 437 438
    // TSIG should have failed, and so the per opcode counter shouldn't be
    // incremented.
    EXPECT_EQ(0, server.getCounter(Opcode::RESERVED14()));
439 440

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

443 444 445
TEST_F(AuthSrvTest, AXFRConnectFail) {
    EXPECT_FALSE(xfrout.isConnected()); // check prerequisite
    xfrout.disableConnect();
Evan Hunt's avatar
Evan Hunt committed
446
    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
Jelte Jansen's avatar
Jelte Jansen committed
447 448
                                       Name("example.com"), RRClass::IN(),
                                       RRType::AXFR());
Evan Hunt's avatar
Evan Hunt committed
449
    createRequestPacket(request_message, IPPROTO_TCP);
450 451
    server.processMessage(*io_message, *parse_message, *response_obuffer,
                          &dnsserv);
Evan Hunt's avatar
Evan Hunt committed
452
    EXPECT_TRUE(dnsserv.hasAnswer());
453
    headerCheck(*parse_message, default_qid, Rcode::SERVFAIL(),
454 455 456 457 458 459 460
                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
461
    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
Jelte Jansen's avatar
Jelte Jansen committed
462 463
                                       Name("example.com"), RRClass::IN(),
                                       RRType::AXFR());
Evan Hunt's avatar
Evan Hunt committed
464
    createRequestPacket(request_message, IPPROTO_TCP);
465 466
    server.processMessage(*io_message, *parse_message, *response_obuffer,
                          &dnsserv);
467
    EXPECT_TRUE(xfrout.isConnected());
468 469

    xfrout.disableSend();
470 471
    parse_message->clear(Message::PARSE);
    response_obuffer->clear();
Evan Hunt's avatar
Evan Hunt committed
472
    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
Jelte Jansen's avatar
Jelte Jansen committed
473 474
                                       Name("example.com"), RRClass::IN(),
                                       RRType::AXFR());
Evan Hunt's avatar
Evan Hunt committed
475
    createRequestPacket(request_message, IPPROTO_TCP);
476 477
    server.processMessage(*io_message, *parse_message, *response_obuffer,
                          &dnsserv);
Evan Hunt's avatar
Evan Hunt committed
478
    EXPECT_TRUE(dnsserv.hasAnswer());
479
    headerCheck(*parse_message, default_qid, Rcode::SERVFAIL(),
480 481 482 483 484 485 486 487 488 489 490
                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
491
    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
Jelte Jansen's avatar
Jelte Jansen committed
492 493
                                       Name("example.com"), RRClass::IN(),
                                       RRType::AXFR());
Evan Hunt's avatar
Evan Hunt committed
494
    createRequestPacket(request_message, IPPROTO_TCP);
495 496
    EXPECT_THROW(server.processMessage(*io_message, *parse_message,
                                       *response_obuffer, &dnsserv),
497 498 499 500 501 502 503
                 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();
}

504 505 506 507
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
508 509
                                       Name("example.com"), RRClass::IN(),
                                       RRType::IXFR());
510
    createRequestPacket(request_message, IPPROTO_TCP);
511 512
    server.processMessage(*io_message, *parse_message, *response_obuffer,
                          &dnsserv);
513 514 515 516 517 518 519 520 521 522
    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
523 524
                                       Name("example.com"), RRClass::IN(),
                                       RRType::IXFR());
525
    createRequestPacket(request_message, IPPROTO_TCP);
526 527
    server.processMessage(*io_message, *parse_message, *response_obuffer,
                          &dnsserv);
528 529 530 531 532 533
    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
534 535
                                       Name("example.com"), RRClass::IN(),
                                       RRType::IXFR());
536
    createRequestPacket(request_message, IPPROTO_TCP);
537 538
    server.processMessage(*io_message, *parse_message, *response_obuffer,
                          &dnsserv);
539 540 541 542 543 544 545 546 547 548 549 550 551 552
    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
553 554
                                       Name("example.com"), RRClass::IN(),
                                       RRType::IXFR());
555
    createRequestPacket(request_message, IPPROTO_TCP);
556 557
    EXPECT_THROW(server.processMessage(*io_message, *parse_message,
                                       *response_obuffer, &dnsserv),
558 559 560 561 562 563 564
                 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();
}

565
TEST_F(AuthSrvTest, notify) {
Jelte Jansen's avatar
Jelte Jansen committed
566 567 568
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
                                       default_qid, Name("example.com"),
                                       RRClass::IN(), RRType::SOA());
569
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
Evan Hunt's avatar
Evan Hunt committed
570
    createRequestPacket(request_message, IPPROTO_UDP);
571 572
    server.processMessage(*io_message, *parse_message, *response_obuffer,
                          &dnsserv);
Evan Hunt's avatar
Evan Hunt committed
573
    EXPECT_TRUE(dnsserv.hasAnswer());
574 575 576

    // An internal command message should have been created and sent to an
    // external module.  Check them.
Evan Hunt's avatar
Evan Hunt committed
577
    EXPECT_EQ("Zonemgr", notify_session.getMessageDest());
578
    EXPECT_EQ("notify",
Evan Hunt's avatar
Evan Hunt committed
579
              notify_session.getSentMessage()->get("command")->get(0)->stringValue());
580
    ConstElementPtr notify_args =
Evan Hunt's avatar
Evan Hunt committed
581
        notify_session.getSentMessage()->get("command")->get(1);
582 583 584
    EXPECT_EQ("example.com.", notify_args->get("zone_name")->stringValue());
    EXPECT_EQ(DEFAULT_REMOTE_ADDRESS,
              notify_args->get("master")->stringValue());
585
    EXPECT_EQ("IN", notify_args->get("zone_class")->stringValue());
586 587

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

591
    // The question must be identical to that of the received notify
592
    ConstQuestionPtr question = *parse_message->beginQuestion();
593 594 595
    EXPECT_EQ(Name("example.com"), question->getName());
    EXPECT_EQ(RRClass::IN(), question->getClass());
    EXPECT_EQ(RRType::SOA(), question->getType());
596 597

    checkAllRcodeCountersZeroExcept(Rcode::NOERROR(), 1);
598 599
}

600 601
TEST_F(AuthSrvTest, notifyForCHClass) {
    // Same as the previous test, but for the CH RRClass.
Jelte Jansen's avatar
Jelte Jansen committed
602 603 604
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
                                       default_qid, Name("example.com"),
                                       RRClass::CH(), RRType::SOA());
605
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
Evan Hunt's avatar
Evan Hunt committed
606
    createRequestPacket(request_message, IPPROTO_UDP);
607 608
    server.processMessage(*io_message, *parse_message, *response_obuffer,
                          &dnsserv);
Evan Hunt's avatar
Evan Hunt committed
609
    EXPECT_TRUE(dnsserv.hasAnswer());
610 611 612

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

618 619 620
TEST_F(AuthSrvTest, notifyEmptyQuestion) {
    request_message.clear(Message::RENDER);
    request_message.setOpcode(Opcode::NOTIFY());
621
    request_message.setRcode(Rcode::NOERROR());
622
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
623 624
    request_message.setQid(default_qid);
    request_message.toWire(request_renderer);
Evan Hunt's avatar
Evan Hunt committed
625
    createRequestPacket(request_message, IPPROTO_UDP);
626 627
    server.processMessage(*io_message, *parse_message, *response_obuffer,
                          &dnsserv);
Evan Hunt's avatar
Evan Hunt committed
628
    EXPECT_TRUE(dnsserv.hasAnswer());
629
    headerCheck(*parse_message, default_qid, Rcode::FORMERR(),
630 631 632 633
                Opcode::NOTIFY().getCode(), QR_FLAG, 0, 0, 0, 0);
}

TEST_F(AuthSrvTest, notifyMultiQuestions) {
Jelte Jansen's avatar
Jelte Jansen committed
634 635 636
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
                                       default_qid, Name("example.com"),
                                       RRClass::IN(), RRType::SOA());
637 638 639
    // add one more SOA question
    request_message.addQuestion(Question(Name("example.com"), RRClass::IN(),
                                         RRType::SOA()));
640
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
Evan Hunt's avatar
Evan Hunt committed
641
    createRequestPacket(request_message, IPPROTO_UDP);
642 643
    server.processMessage(*io_message, *parse_message, *response_obuffer,
                          &dnsserv);
Evan Hunt's avatar
Evan Hunt committed
644
    EXPECT_TRUE(dnsserv.hasAnswer());
645
    headerCheck(*parse_message, default_qid, Rcode::FORMERR(),
646 647 648 649
                Opcode::NOTIFY().getCode(), QR_FLAG, 2, 0, 0, 0);
}

TEST_F(AuthSrvTest, notifyNonSOAQuestion) {
Jelte Jansen's avatar
Jelte Jansen committed
650 651 652
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
                                       default_qid, Name("example.com"),
                                       RRClass::IN(), RRType::NS());
653
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
Evan Hunt's avatar
Evan Hunt committed
654
    createRequestPacket(request_message, IPPROTO_UDP);
655 656
    server.processMessage(*io_message, *parse_message, *response_obuffer,
                          &dnsserv);
Evan Hunt's avatar
Evan Hunt committed
657
    EXPECT_TRUE(dnsserv.hasAnswer());
658
    headerCheck(*parse_message, default_qid, Rcode::FORMERR(),
659 660 661 662 663
                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
664 665 666
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
                                       default_qid, Name("example.com"),
                                       RRClass::IN(), RRType::SOA());
Evan Hunt's avatar
Evan Hunt committed
667
    createRequestPacket(request_message, IPPROTO_UDP);
668 669
    server.processMessage(*io_message, *parse_message, *response_obuffer,
                          &dnsserv);
Evan Hunt's avatar
Evan Hunt committed
670
    EXPECT_TRUE(dnsserv.hasAnswer());
671
    headerCheck(*parse_message, default_qid, Rcode::NOERROR(),
672 673 674 675
                Opcode::NOTIFY().getCode(), QR_FLAG | AA_FLAG, 1, 0, 0, 0);
}

TEST_F(AuthSrvTest, notifyWithErrorRcode) {
Jelte Jansen's avatar
Jelte Jansen committed
676 677 678
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
                                       default_qid, Name("example.com"),
                                       RRClass::IN(), RRType::SOA());
679
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
680
    request_message.setRcode(Rcode::SERVFAIL());
Evan Hunt's avatar
Evan Hunt committed
681
    createRequestPacket(request_message, IPPROTO_UDP);
682 683
    server.processMessage(*io_message, *parse_message, *response_obuffer,
                          &dnsserv);
Evan Hunt's avatar
Evan Hunt committed
684
    EXPECT_TRUE(dnsserv.hasAnswer());
685
    headerCheck(*parse_message, default_qid, Rcode::NOERROR(),
686
                Opcode::NOTIFY().getCode(), QR_FLAG | AA_FLAG, 1, 0, 0, 0);
Han Feng's avatar
Han Feng committed
687 688
}

689
TEST_F(AuthSrvTest, notifyWithoutSession) {
690
    server.setXfrinSession(NULL);
691

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

    // we simply ignore the notify and let it be resent if an internal error
    // happens.
700 701
    server.processMessage(*io_message, *parse_message, *response_obuffer,
                          &dnsserv);
Evan Hunt's avatar
Evan Hunt committed
702
    EXPECT_FALSE(dnsserv.hasAnswer());
703 704 705 706 707
}

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

Jelte Jansen's avatar
Jelte Jansen committed
708 709 710
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
                                       default_qid, Name("example.com"),
                                       RRClass::IN(), RRType::SOA());
711
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
Evan Hunt's avatar
Evan Hunt committed
712
    createRequestPacket(request_message, IPPROTO_UDP);
713

714 715
    server.processMessage(*io_message, *parse_message, *response_obuffer,
                          &dnsserv);
Evan Hunt's avatar
Evan Hunt committed
716
    EXPECT_FALSE(dnsserv.hasAnswer());
717 718 719 720 721
}

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

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

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

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

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

Jelte Jansen's avatar
Jelte Jansen committed
749 750 751
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
                                       default_qid, Name("example.com"),
                                       RRClass::IN(), RRType::SOA());
752
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
Evan Hunt's avatar
Evan Hunt committed
753
    createRequestPacket(request_message, IPPROTO_UDP);
754 755
    server.processMessage(*io_message, *parse_message, *response_obuffer,
                          &dnsserv);
Evan Hunt's avatar
Evan Hunt committed
756
    EXPECT_FALSE(dnsserv.hasAnswer());
757 758
}

759
void
JINMEI Tatuya's avatar
JINMEI Tatuya committed
760
updateConfig(AuthSrv* server, const char* const config_data,
761 762
             const bool expect_success)
{
763
    ConstElementPtr config_answer =
JINMEI Tatuya's avatar
JINMEI Tatuya committed
764
        server->updateConfig(Element::fromJSON(config_data));
765 766 767
    EXPECT_EQ(Element::map, config_answer->getType());
    EXPECT_TRUE(config_answer->contains("result"));

768
    ConstElementPtr result = config_answer->get("result");
769
    EXPECT_EQ(Element::list, result->getType());
770
    EXPECT_EQ(expect_success ? 0 : 1, result->get(0)->intValue());
771 772 773 774
}

// Install a Sqlite3 data source with testing data.
TEST_F(AuthSrvTest, updateConfig) {
775
    updateConfig(&server, CONFIG_TESTDB, true);
776 777 778 779

    // 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.
780
    createDataFromFile("examplequery_fromWire.wire");
781 782
    server.processMessage(*io_message, *parse_message, *response_obuffer,
                          &dnsserv);
Evan Hunt's avatar
Evan Hunt committed
783
    EXPECT_TRUE(dnsserv.hasAnswer());
784
    headerCheck(*parse_message, default_qid, Rcode::NOERROR(), opcode.getCode(),
785 786 787 788
                QR_FLAG | AA_FLAG, 1, 1, 1, 0);
}

TEST_F(AuthSrvTest, datasourceFail) {
789
    updateConfig(&server, CONFIG_TESTDB, true);
790 791 792 793 794

    // 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.
795
    createDataFromFile("badExampleQuery_fromWire.wire");
796 797
    server.processMessage(*io_message, *parse_message, *response_obuffer,
                          &dnsserv);
Evan Hunt's avatar
Evan Hunt committed
798
    EXPECT_TRUE(dnsserv.hasAnswer());
799
    headerCheck(*parse_message, default_qid, Rcode::SERVFAIL(),
800
                opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
801
}
802 803 804 805 806 807 808 809 810

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.
811
    createDataFromFile("examplequery_fromWire.wire");
812 813
    server.processMessage(*io_message, *parse_message, *response_obuffer,
                          &dnsserv);
Evan Hunt's avatar
Evan Hunt committed
814
    EXPECT_TRUE(dnsserv.hasAnswer());
815
    headerCheck(*parse_message, default_qid, Rcode::NOERROR(), opcode.getCode(),
816 817
                QR_FLAG | AA_FLAG, 1, 1, 1, 0);
}
JINMEI Tatuya's avatar
JINMEI Tatuya committed
818

819
TEST_F(AuthSrvTest, updateWithInMemoryClient) {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
820 821 822 823
    // 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
824
    EXPECT_EQ(AuthSrv::InMemoryClientPtr(), server.getInMemoryClient(rrclass));