auth_srv_unittest.cc 28 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 19 20 21 22 23 24 25 26 27 28

#include <vector>

#include <gtest/gtest.h>

#include <dns/message.h>
#include <dns/messagerenderer.h>
#include <dns/name.h>
#include <dns/rrclass.h>
#include <dns/rrtype.h>
#include <dns/rrttl.h>
#include <dns/rdataclass.h>

29 30
#include <server_common/portconfig.h>

JINMEI Tatuya's avatar
JINMEI Tatuya committed
31
#include <datasrc/memory_datasrc.h>
32
#include <auth/auth_srv.h>
33
#include <auth/common.h>
34
#include <auth/statistics.h>
35

36
#include <dns/tests/unittest_util.h>
JINMEI Tatuya's avatar
JINMEI Tatuya committed
37
#include <testutils/dnsmessage_test.h>
38
#include <testutils/srv_test.h>
39
#include <testutils/portconfig.h>
40

JINMEI Tatuya's avatar
JINMEI Tatuya committed
41
using namespace std;
42
using namespace isc::cc;
43
using namespace isc::dns;
44
using namespace isc::dns::rdata;
45
using namespace isc::data;
46
using namespace isc::xfr;
47
using namespace asiolink;
48
using namespace isc::testutils;
49
using namespace isc::server_common::portconfig;
Evan Hunt's avatar
Evan Hunt committed
50
using isc::UnitTestUtil;
51 52

namespace {
53
const char* const CONFIG_TESTDB =
54
    "{\"database_file\": \"" TEST_DATA_DIR "/example.sqlite3\"}";
55 56
// The following file must be non existent and must be non"creatable" (see
// the sqlite3 test).
57
const char* const BADCONFIG_TESTDB =
58
    "{ \"database_file\": \"" TEST_DATA_DIR "/nodir/notexist\"}";
59

60
class AuthSrvTest : public SrvTestBase {
61
protected:
62 63 64 65 66 67
    AuthSrvTest() :
        dnss_(ios_, NULL, NULL, NULL),
        server(true, xfrout),
        rrclass(RRClass::IN())
    {
        server.setDNSService(dnss_);
68
        server.setXfrinSession(&notify_session);
69
        server.setStatisticsSession(&statistics_session);
70
    }
71 72 73 74
    virtual void processMessage() {
        server.processMessage(*io_message, parse_message, response_obuffer,
                              &dnsserv);
    }
75 76
    IOService ios_;
    DNSService dnss_;
77
    MockSession statistics_session;
78
    MockXfroutClient xfrout;
79
    AuthSrv server;
JINMEI Tatuya's avatar
JINMEI Tatuya committed
80
    const RRClass rrclass;
81
    vector<uint8_t> response_data;
82 83
};

84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
// 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());
}

// 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,
152
                                     response_message,
153 154
                                     response_obuffer, &dnsserv);
    (*server.getDNSAnswerProvider())(*io_message, parse_message,
155
                                     response_message, response_obuffer);
156 157 158 159 160 161 162 163 164 165 166 167

    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,
168
                                     response_message,
169 170
                                     response_obuffer, &dnsserv);
    (*server.getDNSAnswerProvider())(*io_message, parse_message,
171
                                     response_message, response_obuffer);
172 173 174 175 176 177 178 179 180

    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());
}

181 182
// Unsupported requests.  Should result in NOTIMP.
TEST_F(AuthSrvTest, unsupportedRequest) {
183
    unsupportedRequest();
184
}
185

186 187
// Simple API check
TEST_F(AuthSrvTest, verbose) {
188 189 190 191 192
    EXPECT_FALSE(server.getVerbose());
    server.setVerbose(true);
    EXPECT_TRUE(server.getVerbose());
    server.setVerbose(false);
    EXPECT_FALSE(server.getVerbose());
193 194
}

195 196
// Multiple questions.  Should result in FORMERR.
TEST_F(AuthSrvTest, multiQuestion) {
197
    multiQuestion();
198 199
}

200 201 202
// Incoming data doesn't even contain the complete header.  Must be silently
// dropped.
TEST_F(AuthSrvTest, shortMessage) {
203
    shortMessage();
204 205 206 207 208
}

// 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) {
209
    response();
210 211 212 213
}

// Query with a broken question
TEST_F(AuthSrvTest, shortQuestion) {
214
    shortQuestion();
215
}
216

217 218
// Query with a broken answer section
TEST_F(AuthSrvTest, shortAnswer) {
219
    shortAnswer();
220 221
}

222 223
// Query with unsupported version of EDNS.
TEST_F(AuthSrvTest, ednsBadVers) {
224
    ednsBadVers();
225 226
}

JINMEI Tatuya's avatar
JINMEI Tatuya committed
227
TEST_F(AuthSrvTest, AXFROverUDP) {
228
    axfrOverUDP();
JINMEI Tatuya's avatar
JINMEI Tatuya committed
229 230
}

231 232
TEST_F(AuthSrvTest, AXFRSuccess) {
    EXPECT_FALSE(xfrout.isConnected());
Evan Hunt's avatar
Evan Hunt committed
233 234 235
    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
                         Name("example.com"), RRClass::IN(), RRType::AXFR());
    createRequestPacket(request_message, IPPROTO_TCP);
236 237
    // 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
238 239
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_FALSE(dnsserv.hasAnswer());
240
    EXPECT_TRUE(xfrout.isConnected());
241 242 243 244 245
}

TEST_F(AuthSrvTest, AXFRConnectFail) {
    EXPECT_FALSE(xfrout.isConnected()); // check prerequisite
    xfrout.disableConnect();
Evan Hunt's avatar
Evan Hunt committed
246 247 248 249 250
    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
                         Name("example.com"), RRClass::IN(), RRType::AXFR());
    createRequestPacket(request_message, IPPROTO_TCP);
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_TRUE(dnsserv.hasAnswer());
251
    headerCheck(*parse_message, default_qid, Rcode::SERVFAIL(),
252 253 254 255 256 257 258
                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
259 260 261 262
    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
                         Name("example.com"), RRClass::IN(), RRType::AXFR());
    createRequestPacket(request_message, IPPROTO_TCP);
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
263
    EXPECT_TRUE(xfrout.isConnected());
264 265

    xfrout.disableSend();
266 267
    parse_message->clear(Message::PARSE);
    response_obuffer->clear();
Evan Hunt's avatar
Evan Hunt committed
268 269 270 271 272
    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
                         Name("example.com"), RRClass::IN(), RRType::AXFR());
    createRequestPacket(request_message, IPPROTO_TCP);
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_TRUE(dnsserv.hasAnswer());
273
    headerCheck(*parse_message, default_qid, Rcode::SERVFAIL(),
274 275 276 277 278 279 280 281 282 283 284
                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
285 286 287
    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
                         Name("example.com"), RRClass::IN(), RRType::AXFR());
    createRequestPacket(request_message, IPPROTO_TCP);
288
    EXPECT_THROW(server.processMessage(*io_message, parse_message,
Evan Hunt's avatar
Evan Hunt committed
289
                                       response_obuffer, &dnsserv),
290 291 292 293 294 295 296
                 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();
}

297
TEST_F(AuthSrvTest, notify) {
Evan Hunt's avatar
Evan Hunt committed
298 299
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(), default_qid,
                         Name("example.com"), RRClass::IN(), RRType::SOA());
300
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
Evan Hunt's avatar
Evan Hunt committed
301 302 303
    createRequestPacket(request_message, IPPROTO_UDP);
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_TRUE(dnsserv.hasAnswer());
304 305 306

    // An internal command message should have been created and sent to an
    // external module.  Check them.
Evan Hunt's avatar
Evan Hunt committed
307
    EXPECT_EQ("Zonemgr", notify_session.getMessageDest());
308
    EXPECT_EQ("notify",
Evan Hunt's avatar
Evan Hunt committed
309
              notify_session.getSentMessage()->get("command")->get(0)->stringValue());
310
    ConstElementPtr notify_args =
Evan Hunt's avatar
Evan Hunt committed
311
        notify_session.getSentMessage()->get("command")->get(1);
312 313 314
    EXPECT_EQ("example.com.", notify_args->get("zone_name")->stringValue());
    EXPECT_EQ(DEFAULT_REMOTE_ADDRESS,
              notify_args->get("master")->stringValue());
315
    EXPECT_EQ("IN", notify_args->get("zone_class")->stringValue());
316 317

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

321
    // The question must be identical to that of the received notify
322
    ConstQuestionPtr question = *parse_message->beginQuestion();
323 324 325 326 327
    EXPECT_EQ(Name("example.com"), question->getName());
    EXPECT_EQ(RRClass::IN(), question->getClass());
    EXPECT_EQ(RRType::SOA(), question->getType());
}

328 329
TEST_F(AuthSrvTest, notifyForCHClass) {
    // Same as the previous test, but for the CH RRClass.
Evan Hunt's avatar
Evan Hunt committed
330 331
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(), default_qid,
                         Name("example.com"), RRClass::CH(), RRType::SOA());
332
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
Evan Hunt's avatar
Evan Hunt committed
333 334 335
    createRequestPacket(request_message, IPPROTO_UDP);
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_TRUE(dnsserv.hasAnswer());
336 337 338

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

344 345 346
TEST_F(AuthSrvTest, notifyEmptyQuestion) {
    request_message.clear(Message::RENDER);
    request_message.setOpcode(Opcode::NOTIFY());
347
    request_message.setRcode(Rcode::NOERROR());
348
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
349 350
    request_message.setQid(default_qid);
    request_message.toWire(request_renderer);
Evan Hunt's avatar
Evan Hunt committed
351 352 353
    createRequestPacket(request_message, IPPROTO_UDP);
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_TRUE(dnsserv.hasAnswer());
354
    headerCheck(*parse_message, default_qid, Rcode::FORMERR(),
355 356 357 358
                Opcode::NOTIFY().getCode(), QR_FLAG, 0, 0, 0, 0);
}

TEST_F(AuthSrvTest, notifyMultiQuestions) {
Evan Hunt's avatar
Evan Hunt committed
359 360
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(), default_qid,
                         Name("example.com"), RRClass::IN(), RRType::SOA());
361 362 363
    // add one more SOA question
    request_message.addQuestion(Question(Name("example.com"), RRClass::IN(),
                                         RRType::SOA()));
364
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
Evan Hunt's avatar
Evan Hunt committed
365 366 367
    createRequestPacket(request_message, IPPROTO_UDP);
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_TRUE(dnsserv.hasAnswer());
368
    headerCheck(*parse_message, default_qid, Rcode::FORMERR(),
369 370 371 372
                Opcode::NOTIFY().getCode(), QR_FLAG, 2, 0, 0, 0);
}

TEST_F(AuthSrvTest, notifyNonSOAQuestion) {
Evan Hunt's avatar
Evan Hunt committed
373 374
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(), default_qid,
                         Name("example.com"), RRClass::IN(), RRType::NS());
375
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
Evan Hunt's avatar
Evan Hunt committed
376 377 378
    createRequestPacket(request_message, IPPROTO_UDP);
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_TRUE(dnsserv.hasAnswer());
379
    headerCheck(*parse_message, default_qid, Rcode::FORMERR(),
380 381 382 383 384
                Opcode::NOTIFY().getCode(), QR_FLAG, 1, 0, 0, 0);
}

TEST_F(AuthSrvTest, notifyWithoutAA) {
    // implicitly leave the AA bit off.  our implementation will accept it.
Evan Hunt's avatar
Evan Hunt committed
385 386 387 388 389
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(), default_qid,
                         Name("example.com"), RRClass::IN(), RRType::SOA());
    createRequestPacket(request_message, IPPROTO_UDP);
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_TRUE(dnsserv.hasAnswer());
390
    headerCheck(*parse_message, default_qid, Rcode::NOERROR(),
391 392 393 394
                Opcode::NOTIFY().getCode(), QR_FLAG | AA_FLAG, 1, 0, 0, 0);
}

TEST_F(AuthSrvTest, notifyWithErrorRcode) {
Evan Hunt's avatar
Evan Hunt committed
395 396
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(), default_qid,
                         Name("example.com"), RRClass::IN(), RRType::SOA());
397
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
398
    request_message.setRcode(Rcode::SERVFAIL());
Evan Hunt's avatar
Evan Hunt committed
399 400 401
    createRequestPacket(request_message, IPPROTO_UDP);
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_TRUE(dnsserv.hasAnswer());
402
    headerCheck(*parse_message, default_qid, Rcode::NOERROR(),
403
                Opcode::NOTIFY().getCode(), QR_FLAG | AA_FLAG, 1, 0, 0, 0);
Han Feng's avatar
Han Feng committed
404 405
}

406
TEST_F(AuthSrvTest, notifyWithoutSession) {
407
    server.setXfrinSession(NULL);
408

Evan Hunt's avatar
Evan Hunt committed
409 410
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(), default_qid,
                         Name("example.com"), RRClass::IN(), RRType::SOA());
411
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
Evan Hunt's avatar
Evan Hunt committed
412
    createRequestPacket(request_message, IPPROTO_UDP);
413 414 415

    // we simply ignore the notify and let it be resent if an internal error
    // happens.
Evan Hunt's avatar
Evan Hunt committed
416 417
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_FALSE(dnsserv.hasAnswer());
418 419 420 421 422
}

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

Evan Hunt's avatar
Evan Hunt committed
423 424
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(), default_qid,
                         Name("example.com"), RRClass::IN(), RRType::SOA());
425
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
Evan Hunt's avatar
Evan Hunt committed
426
    createRequestPacket(request_message, IPPROTO_UDP);
427

Evan Hunt's avatar
Evan Hunt committed
428 429
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_FALSE(dnsserv.hasAnswer());
430 431 432 433 434
}

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

Evan Hunt's avatar
Evan Hunt committed
435 436
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(), default_qid,
                         Name("example.com"), RRClass::IN(), RRType::SOA());
437
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
Evan Hunt's avatar
Evan Hunt committed
438 439 440
    createRequestPacket(request_message, IPPROTO_UDP);
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_FALSE(dnsserv.hasAnswer());
441 442 443
}

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

Evan Hunt's avatar
Evan Hunt committed
446 447
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(), default_qid,
                         Name("example.com"), RRClass::IN(), RRType::SOA());
448
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
Evan Hunt's avatar
Evan Hunt committed
449 450 451
    createRequestPacket(request_message, IPPROTO_UDP);
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_FALSE(dnsserv.hasAnswer());
452 453 454 455
}

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

Evan Hunt's avatar
Evan Hunt committed
458 459
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(), default_qid,
                         Name("example.com"), RRClass::IN(), RRType::SOA());
460
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
Evan Hunt's avatar
Evan Hunt committed
461 462 463
    createRequestPacket(request_message, IPPROTO_UDP);
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_FALSE(dnsserv.hasAnswer());
464 465
}

466
void
JINMEI Tatuya's avatar
JINMEI Tatuya committed
467
updateConfig(AuthSrv* server, const char* const config_data,
468 469
             const bool expect_success)
{
470
    ConstElementPtr config_answer =
JINMEI Tatuya's avatar
JINMEI Tatuya committed
471
        server->updateConfig(Element::fromJSON(config_data));
472 473 474
    EXPECT_EQ(Element::map, config_answer->getType());
    EXPECT_TRUE(config_answer->contains("result"));

475
    ConstElementPtr result = config_answer->get("result");
476
    EXPECT_EQ(Element::list, result->getType());
477
    EXPECT_EQ(expect_success ? 0 : 1, result->get(0)->intValue());
478 479 480 481
}

// Install a Sqlite3 data source with testing data.
TEST_F(AuthSrvTest, updateConfig) {
482
    updateConfig(&server, CONFIG_TESTDB, true);
483 484 485 486

    // 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.
487
    createDataFromFile("examplequery_fromWire.wire");
Evan Hunt's avatar
Evan Hunt committed
488 489
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_TRUE(dnsserv.hasAnswer());
490
    headerCheck(*parse_message, default_qid, Rcode::NOERROR(), opcode.getCode(),
491 492 493 494
                QR_FLAG | AA_FLAG, 1, 1, 1, 0);
}

TEST_F(AuthSrvTest, datasourceFail) {
495
    updateConfig(&server, CONFIG_TESTDB, true);
496 497 498 499 500

    // 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.
501
    createDataFromFile("badExampleQuery_fromWire.wire");
Evan Hunt's avatar
Evan Hunt committed
502 503
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_TRUE(dnsserv.hasAnswer());
504
    headerCheck(*parse_message, default_qid, Rcode::SERVFAIL(),
505
                opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
506
}
507 508 509 510 511 512 513 514 515

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.
516
    createDataFromFile("examplequery_fromWire.wire");
Evan Hunt's avatar
Evan Hunt committed
517 518
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_TRUE(dnsserv.hasAnswer());
519
    headerCheck(*parse_message, default_qid, Rcode::NOERROR(), opcode.getCode(),
520 521
                QR_FLAG | AA_FLAG, 1, 1, 1, 0);
}
JINMEI Tatuya's avatar
JINMEI Tatuya committed
522

JINMEI Tatuya's avatar
JINMEI Tatuya committed
523 524 525 526 527 528 529 530 531 532 533
TEST_F(AuthSrvTest, updateWithMemoryDataSrc) {
    // 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
    EXPECT_EQ(AuthSrv::MemoryDataSrcPtr(), server.getMemoryDataSrc(rrclass));
    updateConfig(&server,
                 "{\"datasources\": [{\"type\": \"memory\"}]}", true);
    // after successful configuration, we should have one (with empty zoneset).
    ASSERT_NE(AuthSrv::MemoryDataSrcPtr(), server.getMemoryDataSrc(rrclass));
    EXPECT_EQ(0, server.getMemoryDataSrc(rrclass)->getZoneCount());
Jerry's avatar
Jerry committed
534

535
    // The memory data source is empty, should return REFUSED rcode.
Jerry's avatar
Jerry committed
536
    createDataFromFile("examplequery_fromWire.wire");
537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555
    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, chQueryWithMemoryDataSrc) {
    // 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);
556
    EXPECT_TRUE(dnsserv.hasAnswer());
557 558
    headerCheck(*parse_message, default_qid, Rcode::NOERROR(),
                opcode.getCode(), QR_FLAG | AA_FLAG, 1, 1, 1, 0);
JINMEI Tatuya's avatar
JINMEI Tatuya committed
559 560
}

JINMEI Tatuya's avatar
JINMEI Tatuya committed
561 562 563 564 565 566 567 568 569
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());
}
570

571 572 573
// Submit UDP normal query and check query counter
TEST_F(AuthSrvTest, queryCounterUDPNormal) {
    // The counter should be initialized to 0.
574
    EXPECT_EQ(0, server.getCounter(AuthCounters::COUNTER_UDP_QUERY));
575 576 577 578 579 580 581
    // 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);
582
    // After processing UDP query, the counter should be 1.
583
    EXPECT_EQ(1, server.getCounter(AuthCounters::COUNTER_UDP_QUERY));
584 585
}

586 587 588
// Submit TCP normal query and check query counter
TEST_F(AuthSrvTest, queryCounterTCPNormal) {
    // The counter should be initialized to 0.
589
    EXPECT_EQ(0, server.getCounter(AuthCounters::COUNTER_TCP_QUERY));
590 591 592 593 594 595 596
    // Create TCP message and process.
    UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
                                       default_qid, Name("example.com"),
                                       RRClass::IN(), RRType::NS());
    createRequestPacket(request_message, IPPROTO_TCP);
    server.processMessage(*io_message, parse_message, response_obuffer,
                          &dnsserv);
597
    // After processing TCP query, the counter should be 1.
598
    EXPECT_EQ(1, server.getCounter(AuthCounters::COUNTER_TCP_QUERY));
599 600 601 602 603
}

// Submit TCP AXFR query and check query counter
TEST_F(AuthSrvTest, queryCounterTCPAXFR) {
    // The counter should be initialized to 0.
604
    EXPECT_EQ(0, server.getCounter(AuthCounters::COUNTER_TCP_QUERY));
605 606 607 608 609 610
    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
                         Name("example.com"), RRClass::IN(), RRType::AXFR());
    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);
611
    // After processing TCP AXFR query, the counter should be 1.
612
    EXPECT_EQ(1, server.getCounter(AuthCounters::COUNTER_TCP_QUERY));
613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631
}

// class for queryCounterUnexpected test
// getProtocol() returns IPPROTO_IP
class DummyUnknownSocket : public IOSocket {
public:
    DummyUnknownSocket() {}
    virtual int getNative() const { return (0); }
    virtual int getProtocol() const { return (IPPROTO_IP); }
};

// function for queryCounterUnexpected test
// returns a reference to a static object of DummyUnknownSocket
IOSocket&
getDummyUnknownSocket() {
    static DummyUnknownSocket socket;
    return (socket);
}

632
// Submit unexpected type of query and check it throws isc::Unexpected
633
TEST_F(AuthSrvTest, queryCounterUnexpected) {
634 635 636 637
    // 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.

638
    // Create UDP query packet.
639 640 641 642
    UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
                                       default_qid, Name("example.com"),
                                       RRClass::IN(), RRType::NS());
    createRequestPacket(request_message, IPPROTO_UDP);
643

644
    // Modify the message.
645 646
    delete io_message;
    endpoint = IOEndpoint::create(IPPROTO_UDP,
647
                                  IOAddress(DEFAULT_REMOTE_ADDRESS), 53210);
648 649 650 651 652
    io_message = new IOMessage(request_renderer.getData(),
                               request_renderer.getLength(),
                               getDummyUnknownSocket(), *endpoint);

    EXPECT_THROW(server.processMessage(*io_message, parse_message,
653
                                       response_obuffer, &dnsserv),
654
                 isc::Unexpected);
655
}
656 657 658 659 660

TEST_F(AuthSrvTest, stop) {
    // normal case is covered in command_unittest.cc.  we should primarily
    // test it here, but the current design of the stop test takes time,
    // so we consolidate the cases in the command tests.
661 662
    // If/when the interval timer has finer granularity we'll probably add
    // our own tests here, so we keep this empty test case.
663
}
664 665

TEST_F(AuthSrvTest, listenAddresses) {
666
    isc::testutils::portconfig::listenAddresses(server);
667
}
668

669
}