auth_srv_unittest.cc 26.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
// 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.

// $Id$

17
#include <config.h>
18 19 20 21 22 23 24 25 26 27 28 29 30

#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>

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

36
using namespace isc::cc;
37
using namespace isc::dns;
38
using namespace isc::dns::rdata;
39
using namespace isc::data;
40
using namespace isc::xfr;
41
using namespace asiolink;
Evan Hunt's avatar
Evan Hunt committed
42
using isc::UnitTestUtil;
43 44

namespace {
45
const char* const CONFIG_TESTDB =
46
    "{\"database_file\": \"" TEST_DATA_DIR "/example.sqlite3\"}";
47 48
// The following file must be non existent and must be non"creatable" (see
// the sqlite3 test).
49
const char* const BADCONFIG_TESTDB =
50
    "{ \"database_file\": \"" TEST_DATA_DIR "/nodir/notexist\"}";
51

52
class AuthSrvTest : public SrvTestBase {
53
protected:
JINMEI Tatuya's avatar
JINMEI Tatuya committed
54
    AuthSrvTest() : server(true, xfrout), rrclass(RRClass::IN()) {
55
        server.setXfrinSession(&notify_session);
56
        server.setStatisticsSession(&statistics_session);
57
    }
58
    MockSession statistics_session;
59
    MockXfroutClient xfrout;
60
    AuthSrv server;
JINMEI Tatuya's avatar
JINMEI Tatuya committed
61
    const RRClass rrclass;
62
    vector<uint8_t> response_data;
63 64
};

65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 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 152 153 154 155 156 157 158 159
// 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,
                                     response_obuffer, &dnsserv);
    (*server.getDNSAnswerProvider())(*io_message, parse_message,
                                     response_obuffer);

    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,
                                     response_obuffer, &dnsserv);
    (*server.getDNSAnswerProvider())(*io_message, parse_message,
                                     response_obuffer);

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

160 161
// Unsupported requests.  Should result in NOTIMP.
TEST_F(AuthSrvTest, unsupportedRequest) {
162
    UNSUPPORTED_REQUEST_TEST;
163
}
164

165 166
// Simple API check
TEST_F(AuthSrvTest, verbose) {
167
    VERBOSE_TEST;
168 169
}

170 171
// Multiple questions.  Should result in FORMERR.
TEST_F(AuthSrvTest, multiQuestion) {
172
    MULTI_QUESTION_TEST;
173 174
}

175 176 177
// Incoming data doesn't even contain the complete header.  Must be silently
// dropped.
TEST_F(AuthSrvTest, shortMessage) {
178
    SHORT_MESSAGE_TEST;
179 180 181 182 183
}

// 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) {
184
    RESPONSE_TEST;
185 186 187 188
}

// Query with a broken question
TEST_F(AuthSrvTest, shortQuestion) {
189
    SHORT_QUESTION_TEST;
190
}
191

192 193
// Query with a broken answer section
TEST_F(AuthSrvTest, shortAnswer) {
194
    SHORT_ANSWER_TEST;
195 196
}

197 198
// Query with unsupported version of EDNS.
TEST_F(AuthSrvTest, ednsBadVers) {
199
    EDNS_BADVERS_TEST;
200 201
}

JINMEI Tatuya's avatar
JINMEI Tatuya committed
202
TEST_F(AuthSrvTest, AXFROverUDP) {
203
    AXFR_OVER_UDP_TEST;
JINMEI Tatuya's avatar
JINMEI Tatuya committed
204 205
}

206 207
TEST_F(AuthSrvTest, AXFRSuccess) {
    EXPECT_FALSE(xfrout.isConnected());
Evan Hunt's avatar
Evan Hunt committed
208 209 210
    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
                         Name("example.com"), RRClass::IN(), RRType::AXFR());
    createRequestPacket(request_message, IPPROTO_TCP);
211 212
    // 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
213 214
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_FALSE(dnsserv.hasAnswer());
215
    EXPECT_TRUE(xfrout.isConnected());
216 217 218 219 220
}

TEST_F(AuthSrvTest, AXFRConnectFail) {
    EXPECT_FALSE(xfrout.isConnected()); // check prerequisite
    xfrout.disableConnect();
Evan Hunt's avatar
Evan Hunt committed
221 222 223 224 225
    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());
226
    headerCheck(*parse_message, default_qid, Rcode::SERVFAIL(),
227 228 229 230 231 232 233
                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
234 235 236 237
    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);
238
    EXPECT_TRUE(xfrout.isConnected());
239 240

    xfrout.disableSend();
241 242
    parse_message->clear(Message::PARSE);
    response_obuffer->clear();
Evan Hunt's avatar
Evan Hunt committed
243 244 245 246 247
    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());
248
    headerCheck(*parse_message, default_qid, Rcode::SERVFAIL(),
249 250 251 252 253 254 255 256 257 258 259
                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
260 261 262
    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
                         Name("example.com"), RRClass::IN(), RRType::AXFR());
    createRequestPacket(request_message, IPPROTO_TCP);
263
    EXPECT_THROW(server.processMessage(*io_message, parse_message,
Evan Hunt's avatar
Evan Hunt committed
264
                                       response_obuffer, &dnsserv),
265 266 267 268 269 270 271
                 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();
}

272
TEST_F(AuthSrvTest, notify) {
Evan Hunt's avatar
Evan Hunt committed
273 274
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(), default_qid,
                         Name("example.com"), RRClass::IN(), RRType::SOA());
275
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
Evan Hunt's avatar
Evan Hunt committed
276 277 278
    createRequestPacket(request_message, IPPROTO_UDP);
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_TRUE(dnsserv.hasAnswer());
279 280 281

    // An internal command message should have been created and sent to an
    // external module.  Check them.
Evan Hunt's avatar
Evan Hunt committed
282
    EXPECT_EQ("Zonemgr", notify_session.getMessageDest());
283
    EXPECT_EQ("notify",
Evan Hunt's avatar
Evan Hunt committed
284
              notify_session.getSentMessage()->get("command")->get(0)->stringValue());
285
    ConstElementPtr notify_args =
Evan Hunt's avatar
Evan Hunt committed
286
        notify_session.getSentMessage()->get("command")->get(1);
287 288 289
    EXPECT_EQ("example.com.", notify_args->get("zone_name")->stringValue());
    EXPECT_EQ(DEFAULT_REMOTE_ADDRESS,
              notify_args->get("master")->stringValue());
290
    EXPECT_EQ("IN", notify_args->get("zone_class")->stringValue());
291 292

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

296
    // The question must be identical to that of the received notify
297
    ConstQuestionPtr question = *parse_message->beginQuestion();
298 299 300 301 302
    EXPECT_EQ(Name("example.com"), question->getName());
    EXPECT_EQ(RRClass::IN(), question->getClass());
    EXPECT_EQ(RRType::SOA(), question->getType());
}

303 304
TEST_F(AuthSrvTest, notifyForCHClass) {
    // Same as the previous test, but for the CH RRClass.
Evan Hunt's avatar
Evan Hunt committed
305 306
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(), default_qid,
                         Name("example.com"), RRClass::CH(), RRType::SOA());
307
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
Evan Hunt's avatar
Evan Hunt committed
308 309 310
    createRequestPacket(request_message, IPPROTO_UDP);
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_TRUE(dnsserv.hasAnswer());
311 312 313

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

319 320 321
TEST_F(AuthSrvTest, notifyEmptyQuestion) {
    request_message.clear(Message::RENDER);
    request_message.setOpcode(Opcode::NOTIFY());
322
    request_message.setRcode(Rcode::NOERROR());
323
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
324 325
    request_message.setQid(default_qid);
    request_message.toWire(request_renderer);
Evan Hunt's avatar
Evan Hunt committed
326 327 328
    createRequestPacket(request_message, IPPROTO_UDP);
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_TRUE(dnsserv.hasAnswer());
329
    headerCheck(*parse_message, default_qid, Rcode::FORMERR(),
330 331 332 333
                Opcode::NOTIFY().getCode(), QR_FLAG, 0, 0, 0, 0);
}

TEST_F(AuthSrvTest, notifyMultiQuestions) {
Evan Hunt's avatar
Evan Hunt committed
334 335
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(), default_qid,
                         Name("example.com"), RRClass::IN(), RRType::SOA());
336 337 338
    // add one more SOA question
    request_message.addQuestion(Question(Name("example.com"), RRClass::IN(),
                                         RRType::SOA()));
339
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
Evan Hunt's avatar
Evan Hunt committed
340 341 342
    createRequestPacket(request_message, IPPROTO_UDP);
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_TRUE(dnsserv.hasAnswer());
343
    headerCheck(*parse_message, default_qid, Rcode::FORMERR(),
344 345 346 347
                Opcode::NOTIFY().getCode(), QR_FLAG, 2, 0, 0, 0);
}

TEST_F(AuthSrvTest, notifyNonSOAQuestion) {
Evan Hunt's avatar
Evan Hunt committed
348 349
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(), default_qid,
                         Name("example.com"), RRClass::IN(), RRType::NS());
350
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
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 359
                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
360 361 362 363 364
    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());
365
    headerCheck(*parse_message, default_qid, Rcode::NOERROR(),
366 367 368 369
                Opcode::NOTIFY().getCode(), QR_FLAG | AA_FLAG, 1, 0, 0, 0);
}

TEST_F(AuthSrvTest, notifyWithErrorRcode) {
Evan Hunt's avatar
Evan Hunt committed
370 371
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(), default_qid,
                         Name("example.com"), RRClass::IN(), RRType::SOA());
372
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
373
    request_message.setRcode(Rcode::SERVFAIL());
Evan Hunt's avatar
Evan Hunt committed
374 375 376
    createRequestPacket(request_message, IPPROTO_UDP);
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_TRUE(dnsserv.hasAnswer());
377
    headerCheck(*parse_message, default_qid, Rcode::NOERROR(),
378
                Opcode::NOTIFY().getCode(), QR_FLAG | AA_FLAG, 1, 0, 0, 0);
Han Feng's avatar
Han Feng committed
379 380
}

381
TEST_F(AuthSrvTest, notifyWithoutSession) {
382
    server.setXfrinSession(NULL);
383

Evan Hunt's avatar
Evan Hunt committed
384 385
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(), default_qid,
                         Name("example.com"), RRClass::IN(), RRType::SOA());
386
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
Evan Hunt's avatar
Evan Hunt committed
387
    createRequestPacket(request_message, IPPROTO_UDP);
388 389 390

    // we simply ignore the notify and let it be resent if an internal error
    // happens.
Evan Hunt's avatar
Evan Hunt committed
391 392
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_FALSE(dnsserv.hasAnswer());
393 394 395 396 397
}

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

Evan Hunt's avatar
Evan Hunt committed
398 399
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(), default_qid,
                         Name("example.com"), RRClass::IN(), RRType::SOA());
400
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
Evan Hunt's avatar
Evan Hunt committed
401
    createRequestPacket(request_message, IPPROTO_UDP);
402

Evan Hunt's avatar
Evan Hunt committed
403 404
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_FALSE(dnsserv.hasAnswer());
405 406 407 408 409
}

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

Evan Hunt's avatar
Evan Hunt committed
410 411
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(), default_qid,
                         Name("example.com"), RRClass::IN(), RRType::SOA());
412
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
Evan Hunt's avatar
Evan Hunt committed
413 414 415
    createRequestPacket(request_message, IPPROTO_UDP);
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_FALSE(dnsserv.hasAnswer());
416 417 418
}

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

Evan Hunt's avatar
Evan Hunt committed
421 422
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(), default_qid,
                         Name("example.com"), RRClass::IN(), RRType::SOA());
423
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
Evan Hunt's avatar
Evan Hunt committed
424 425 426
    createRequestPacket(request_message, IPPROTO_UDP);
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_FALSE(dnsserv.hasAnswer());
427 428 429 430
}

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

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

441
void
JINMEI Tatuya's avatar
JINMEI Tatuya committed
442
updateConfig(AuthSrv* server, const char* const config_data,
443 444
             const bool expect_success)
{
445
    ConstElementPtr config_answer =
JINMEI Tatuya's avatar
JINMEI Tatuya committed
446
        server->updateConfig(Element::fromJSON(config_data));
447 448 449
    EXPECT_EQ(Element::map, config_answer->getType());
    EXPECT_TRUE(config_answer->contains("result"));

450
    ConstElementPtr result = config_answer->get("result");
451
    EXPECT_EQ(Element::list, result->getType());
452
    EXPECT_EQ(expect_success ? 0 : 1, result->get(0)->intValue());
453 454 455 456
}

// Install a Sqlite3 data source with testing data.
TEST_F(AuthSrvTest, updateConfig) {
457
    updateConfig(&server, CONFIG_TESTDB, true);
458 459 460 461

    // 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.
462
    createDataFromFile("examplequery_fromWire.wire");
Evan Hunt's avatar
Evan Hunt committed
463 464
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_TRUE(dnsserv.hasAnswer());
465
    headerCheck(*parse_message, default_qid, Rcode::NOERROR(), opcode.getCode(),
466 467 468 469
                QR_FLAG | AA_FLAG, 1, 1, 1, 0);
}

TEST_F(AuthSrvTest, datasourceFail) {
470
    updateConfig(&server, CONFIG_TESTDB, true);
471 472 473 474 475

    // 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.
476
    createDataFromFile("badExampleQuery_fromWire.wire");
Evan Hunt's avatar
Evan Hunt committed
477 478
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_TRUE(dnsserv.hasAnswer());
479
    headerCheck(*parse_message, default_qid, Rcode::SERVFAIL(),
480
                opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
481
}
482 483 484 485 486 487 488 489 490

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

JINMEI Tatuya's avatar
JINMEI Tatuya committed
498 499 500 501 502 503 504 505 506 507 508
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
509

510
    // The memory data source is empty, should return REFUSED rcode.
Jerry's avatar
Jerry committed
511
    createDataFromFile("examplequery_fromWire.wire");
512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530
    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);
531
    EXPECT_TRUE(dnsserv.hasAnswer());
532 533
    headerCheck(*parse_message, default_qid, Rcode::NOERROR(),
                opcode.getCode(), QR_FLAG | AA_FLAG, 1, 1, 1, 0);
JINMEI Tatuya's avatar
JINMEI Tatuya committed
534 535
}

JINMEI Tatuya's avatar
JINMEI Tatuya committed
536 537 538 539 540 541 542 543 544
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());
}
545

546 547 548
// Submit UDP normal query and check query counter
TEST_F(AuthSrvTest, queryCounterUDPNormal) {
    // The counter should be initialized to 0.
549
    EXPECT_EQ(0, server.getCounter(AuthCounters::COUNTER_UDP_QUERY));
550 551 552 553 554 555 556
    // 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);
557
    // After processing UDP query, the counter should be 1.
558
    EXPECT_EQ(1, server.getCounter(AuthCounters::COUNTER_UDP_QUERY));
559 560
}

561 562 563
// Submit TCP normal query and check query counter
TEST_F(AuthSrvTest, queryCounterTCPNormal) {
    // The counter should be initialized to 0.
564
    EXPECT_EQ(0, server.getCounter(AuthCounters::COUNTER_TCP_QUERY));
565 566 567 568 569 570 571
    // 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);
572
    // After processing TCP query, the counter should be 1.
573
    EXPECT_EQ(1, server.getCounter(AuthCounters::COUNTER_TCP_QUERY));
574 575 576 577 578
}

// Submit TCP AXFR query and check query counter
TEST_F(AuthSrvTest, queryCounterTCPAXFR) {
    // The counter should be initialized to 0.
579
    EXPECT_EQ(0, server.getCounter(AuthCounters::COUNTER_TCP_QUERY));
580 581 582 583 584 585
    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);
586
    // After processing TCP AXFR query, the counter should be 1.
587
    EXPECT_EQ(1, server.getCounter(AuthCounters::COUNTER_TCP_QUERY));
588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606
}

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

607
// Submit unexpected type of query and check it throws isc::Unexpected
608
TEST_F(AuthSrvTest, queryCounterUnexpected) {
609 610 611 612
    // 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.

613
    // Create UDP query packet.
614 615 616 617
    UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
                                       default_qid, Name("example.com"),
                                       RRClass::IN(), RRType::NS());
    createRequestPacket(request_message, IPPROTO_UDP);
618

619
    // Modify the message.
620 621 622 623 624 625 626 627
    delete io_message;
    endpoint = IOEndpoint::create(IPPROTO_UDP,
                                  IOAddress(DEFAULT_REMOTE_ADDRESS), 5300);
    io_message = new IOMessage(request_renderer.getData(),
                               request_renderer.getLength(),
                               getDummyUnknownSocket(), *endpoint);

    EXPECT_THROW(server.processMessage(*io_message, parse_message,
628
                                       response_obuffer, &dnsserv),
629
                 isc::Unexpected);
630
}
631
}