auth_srv_unittest.cc 89.8 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
#include <util/io/sockaddr_util.h>
18
#include <util/memory_segment_local.h>
19
20
21
22

#include <dns/message.h>
#include <dns/messagerenderer.h>
#include <dns/name.h>
23
#include <dns/opcode.h>
24
25
26
27
#include <dns/rrclass.h>
#include <dns/rrtype.h>
#include <dns/rrttl.h>
#include <dns/rdataclass.h>
28
#include <dns/tsig.h>
29

30
#include <server_common/portconfig.h>
31
#include <server_common/keyring.h>
32

JINMEI Tatuya's avatar
JINMEI Tatuya committed
33
#include <datasrc/memory_datasrc.h>
34
#include <datasrc/client_list.h>
35
#include <auth/auth_srv.h>
36
#include <auth/command.h>
37
#include <auth/common.h>
38
#include <auth/statistics.h>
39
#include <auth/statistics_items.h>
40
#include <auth/datasrc_configurator.h>
41

42
#include <util/unittests/mock_socketsession.h>
43
#include <dns/tests/unittest_util.h>
JINMEI Tatuya's avatar
JINMEI Tatuya committed
44
#include <testutils/dnsmessage_test.h>
45
#include <testutils/srv_test.h>
46
#include <testutils/mockups.h>
47
#include <testutils/portconfig.h>
48
#include <testutils/socket_request.h>
49

50
51
#include <gtest/gtest.h>

52
#include <boost/lexical_cast.hpp>
53
54
#include <boost/shared_ptr.hpp>
#include <boost/scoped_ptr.hpp>
55
#include <boost/foreach.hpp>
56
57
58

#include <vector>

59
60
61
62
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>

JINMEI Tatuya's avatar
JINMEI Tatuya committed
63
using namespace std;
64
using namespace isc::cc;
65
using namespace isc::dns;
66
using namespace isc::util;
67
using namespace isc::util::io::internal;
68
using namespace isc::util::unittests;
69
using namespace isc::dns::rdata;
70
using namespace isc::data;
71
using namespace isc::xfr;
72
73
using namespace isc::asiodns;
using namespace isc::asiolink;
74
using namespace isc::testutils;
75
using namespace isc::server_common::portconfig;
Evan Hunt's avatar
Evan Hunt committed
76
using isc::UnitTestUtil;
77
using boost::scoped_ptr;
78
using isc::auth::statistics::Counters;
79
80

namespace {
81
const char* const CONFIG_TESTDB =
82
    "{\"database_file\": \"" TEST_DATA_DIR "/example.sqlite3\"}";
83
84
// The following file must be non existent and must be non"creatable" (see
// the sqlite3 test).
85
const char* const BADCONFIG_TESTDB =
86
    "{ \"database_file\": \"" TEST_DATA_DIR "/nodir/notexist\"}";
87

88
89
const char* const STATIC_DSRC_FILE = DSRC_DIR "/static.zone";

90
91
// This is a configuration that uses the in-memory data source containing
// a signed example zone.
Yoshitaka Aharen's avatar
Yoshitaka Aharen committed
92
93
const char* const CONFIG_INMEMORY_EXAMPLE =
    TEST_DATA_DIR "/rfc5155-example.zone.signed";
94

95
class AuthSrvTest : public SrvTestBase {
96
protected:
97
    AuthSrvTest() :
98
        dnss_(),
99
        server(xfrout, ddns_forwarder),
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
100
101
102
        // 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).
103
        sock_requestor_(dnss_, address_store_, 53210, "")
104
105
    {
        server.setDNSService(dnss_);
106
        server.setXfrinSession(&notify_session);
107
        server.createDDNSForwarder();
108
    }
109

110
    ~AuthSrvTest() {
111
        server.destroyDDNSForwarder();
112
113
    }

114
    virtual void processMessage() {
115
116
117
        // If processMessage has been called before, parse_message needs
        // to be reset. If it hasn't, there's no harm in doing so
        parse_message->clear(Message::PARSE);
118
        server.processMessage(*io_message, *parse_message, *response_obuffer,
119
120
                              &dnsserv);
    }
121

122
123
    // Helper for checking Rcode statistic counters;
    // Checks for one specific Rcode statistics counter value
Yoshitaka Aharen's avatar
Yoshitaka Aharen committed
124
125
    void checkRcodeCounter(const std::string& rcode_name,
                           const int rcode_value,
126
127
128
129
130
131
                           const int expected_value) const
    {
            EXPECT_EQ(expected_value, rcode_value) <<
                      "Expected Rcode count for " << rcode_name <<
                      " " << expected_value << ", was: " <<
                      rcode_value;
132
    }
133

134
    // Checks whether all Rcode counters are set to zero
JINMEI Tatuya's avatar
JINMEI Tatuya committed
135
    void checkAllRcodeCountersZero() const {
136
137
        // with checking NOERROR == 0 and the others are 0
        checkAllRcodeCountersZeroExcept(Rcode::NOERROR(), 0);
138
    }
139

140
141
    // 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
142
    void checkAllRcodeCountersZeroExcept(const Rcode& rcode, int value) const {
143
        std::string target_rcode_name = rcode.toText();
144
145
146
147
        std::transform(target_rcode_name.begin(), target_rcode_name.end(),
                       target_rcode_name.begin(), ::tolower);

        const std::map<std::string, ConstElementPtr>
148
149
            stats_map(server.getStatistics()->get("zones")->get("_SERVER_")->
                      get("rcode")->mapValue());
150
151
152
153
154
155

        for (std::map<std::string, ConstElementPtr>::const_iterator
                 i = stats_map.begin(), e = stats_map.end();
             i != e;
             ++i)
        {
156
157
158
159
            if (i->first.compare(target_rcode_name) == 0) {
                checkRcodeCounter(i->first, i->second->intValue(), value);
            } else {
                checkRcodeCounter(i->first, i->second->intValue(), 0);
160
161
162
            }
        }
    }
163

164
165
166
167
    // Convenience method for tests that expect to return SERVFAIL
    // It calls processMessage, checks if there is an answer, and
    // check the header for default SERVFAIL data
    void processAndCheckSERVFAIL() {
Jelte Jansen's avatar
Jelte Jansen committed
168
        processMessage();
169
170
171
        EXPECT_TRUE(dnsserv.hasAnswer());
        headerCheck(*parse_message, default_qid, Rcode::SERVFAIL(),
                    opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
Jelte Jansen's avatar
Jelte Jansen committed
172
173
    }

174
175
176
177
178
    // Convenient shortcut of creating a simple request and having the
    // server process it.
    void createAndSendRequest(RRType req_type, Opcode opcode = Opcode::QUERY(),
                              const Name& req_name = Name("example.com"),
                              RRClass req_class = RRClass::IN(),
179
180
181
182
                              int protocol = IPPROTO_UDP,
                              const char* const remote_address =
                              DEFAULT_REMOTE_ADDRESS,
                              uint16_t remote_port = DEFAULT_REMOTE_PORT)
183
184
185
186
    {
        UnitTestUtil::createRequestMessage(request_message, opcode,
                                           default_qid, req_name,
                                           req_class, req_type);
187
188
        createRequestPacket(request_message, protocol, NULL,
                            remote_address, remote_port);
189
190
191
192
193
        parse_message->clear(Message::PARSE);
        server.processMessage(*io_message, *parse_message, *response_obuffer,
                              &dnsserv);
    }

194
    MockDNSService dnss_;
195
    MockXfroutClient xfrout;
196
    MockSocketSessionForwarder ddns_forwarder;
197
    AuthSrv server;
198
    vector<uint8_t> response_data;
199
    AddressList address_store_;
200
    TestSocketRequestor sock_requestor_;
201
202
};

203
204
205
206
207
// 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) {
208
209
    const Name version_name("VERSION.BIND.");
    const Name apex_name("BIND.");
210
211
212
213
214
215
216
217
218
219
220
221
    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);

222
    RRsetPtr rrset_version_ns = RRsetPtr(new RRset(apex_name, RRClass::CH(),
223
                                                   RRType::NS(), RRTTL(0)));
224
    rrset_version_ns->addRdata(generic::NS(apex_name));
225
226
    message.addRRset(Message::SECTION_AUTHORITY, rrset_version_ns);

227
    MessageRenderer renderer;
228
229
230
231
232
233
234
235
    message.toWire(renderer);

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

236
237
// Check if the item has expected value.
// Before reading the item, check the item exists.
238
239
240
241
void
expectCounterItem(ConstElementPtr stats,
                  const std::string& item, const int expected) {
    ConstElementPtr value(Element::create(0));
242
243
244
    ASSERT_TRUE(stats->find(item, value)) << "    Item: " << item;
    value = stats->find(item);
    EXPECT_EQ(expected, value->intValue()) << "    Item: " << item;
245
246
}

247
248
// We did not configure any client lists. Therefore it should be REFUSED
TEST_F(AuthSrvTest, noClientList) {
Yoshitaka Aharen's avatar
Yoshitaka Aharen committed
249
250
251
252
253
254
255
    // The counters should be initialized to 0.
    ConstElementPtr stats_init = server.getStatistics()->
        get("zones")->get("_SERVER_");
    expectCounterItem(stats_init->get("opcode"), "query", 0);
    expectCounterItem(stats_init, "responses", 0);
    expectCounterItem(stats_init->get("rcode"), "refused", 0);

256
257
258
259
    UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
                                       default_qid, Name("version.bind"),
                                       RRClass::CH(), RRType::TXT());
    createRequestPacket(request_message, IPPROTO_UDP);
260
    server.processMessage(*io_message, *parse_message, *response_obuffer,
261
262
                          &dnsserv);

263
264
265
    EXPECT_TRUE(dnsserv.hasAnswer());
    headerCheck(*parse_message, default_qid, Rcode::REFUSED(),
                opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
Yoshitaka Aharen's avatar
Yoshitaka Aharen committed
266
267
268
269
270
271

    ConstElementPtr stats_after = server.getStatistics()->get("zones")->
        get("_SERVER_");
    expectCounterItem(stats_after->get("opcode"), "query", 1);
    expectCounterItem(stats_after, "responses", 1);
    expectCounterItem(stats_after->get("rcode"), "refused", 1);
272
273
}

274
275
// Unsupported requests.  Should result in NOTIMP.
TEST_F(AuthSrvTest, unsupportedRequest) {
276
    unsupportedRequest();
277
278
    // unsupportedRequest tries 13 different opcodes
    checkAllRcodeCountersZeroExcept(Rcode::NOTIMP(), 13);
279
}
280
281
282

// Multiple questions.  Should result in FORMERR.
TEST_F(AuthSrvTest, multiQuestion) {
283
    multiQuestion();
284
    checkAllRcodeCountersZeroExcept(Rcode::FORMERR(), 1);
285
286
}

287
288
289
// Incoming data doesn't even contain the complete header.  Must be silently
// dropped.
TEST_F(AuthSrvTest, shortMessage) {
Yoshitaka Aharen's avatar
Yoshitaka Aharen committed
290
291
292
293
294
    // The counters should be initialized to 0.
    ConstElementPtr stats_init = server.getStatistics()->get("zones")->
        get("_SERVER_");
    expectCounterItem(stats_init, "responses", 0);

295
    shortMessage();
Yoshitaka Aharen's avatar
Yoshitaka Aharen committed
296

297
    checkAllRcodeCountersZero();
Yoshitaka Aharen's avatar
Yoshitaka Aharen committed
298
299
300
    ConstElementPtr stats_after = server.getStatistics()->get("zones")->
        get("_SERVER_");
    expectCounterItem(stats_after, "responses", 0);
301
302
303
304
305
}

// 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) {
Yoshitaka Aharen's avatar
Yoshitaka Aharen committed
306
307
308
309
310
    // The counters should be initialized to 0.
    ConstElementPtr stats_init = server.getStatistics()->get("zones")->
        get("_SERVER_");
    expectCounterItem(stats_init, "responses", 0);

311
    response();
Yoshitaka Aharen's avatar
Yoshitaka Aharen committed
312

313
    checkAllRcodeCountersZero();
Yoshitaka Aharen's avatar
Yoshitaka Aharen committed
314
315
316
    ConstElementPtr stats_after = server.getStatistics()->get("zones")->
        get("_SERVER_");
    expectCounterItem(stats_after, "responses", 0);
317
318
319
320
}

// Query with a broken question
TEST_F(AuthSrvTest, shortQuestion) {
321
    shortQuestion();
322
    checkAllRcodeCountersZeroExcept(Rcode::FORMERR(), 1);
323
}
324

325
326
// Query with a broken answer section
TEST_F(AuthSrvTest, shortAnswer) {
327
    shortAnswer();
328
    checkAllRcodeCountersZeroExcept(Rcode::FORMERR(), 1);
329
330
}

331
332
// Query with unsupported version of EDNS.
TEST_F(AuthSrvTest, ednsBadVers) {
Yoshitaka Aharen's avatar
Yoshitaka Aharen committed
333
334
335
336
337
338
    // The counters should be initialized to 0.
    ConstElementPtr stats_init = server.getStatistics()->get("zones")->
        get("_SERVER_");
    expectCounterItem(stats_init, "responses", 0);
    expectCounterItem(stats_init->get("request"), "badednsver", 0);

339
    ednsBadVers();
Yoshitaka Aharen's avatar
Yoshitaka Aharen committed
340

341
    checkAllRcodeCountersZeroExcept(Rcode::BADVERS(), 1);
Yoshitaka Aharen's avatar
Yoshitaka Aharen committed
342
343
344
345
    ConstElementPtr stats_after = server.getStatistics()->get("zones")->
        get("_SERVER_");
    expectCounterItem(stats_after, "responses", 1);
    expectCounterItem(stats_after->get("request"), "badednsver", 1);
346
347
}

JINMEI Tatuya's avatar
JINMEI Tatuya committed
348
TEST_F(AuthSrvTest, AXFROverUDP) {
349
    axfrOverUDP();
JINMEI Tatuya's avatar
JINMEI Tatuya committed
350
351
}

352
TEST_F(AuthSrvTest, AXFRSuccess) {
Yoshitaka Aharen's avatar
Yoshitaka Aharen committed
353
354
355
356
357
358
359
    // The counters should be initialized to 0.
    ConstElementPtr stats_init = server.getStatistics()->get("zones")->
        get("_SERVER_");
    expectCounterItem(stats_init->get("opcode"), "query", 0);
    expectCounterItem(stats_init, "responses", 0);
    expectCounterItem(stats_init->get("response"), "truncated", 0);

360
    EXPECT_FALSE(xfrout.isConnected());
Evan Hunt's avatar
Evan Hunt committed
361
    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
Jelte Jansen's avatar
Jelte Jansen committed
362
363
                                       Name("example.com"), RRClass::IN(),
                                       RRType::AXFR());
Evan Hunt's avatar
Evan Hunt committed
364
    createRequestPacket(request_message, IPPROTO_TCP);
365
366
    // On success, the AXFR query has been passed to a separate process,
    // so we shouldn't have to respond.
367
368
    server.processMessage(*io_message, *parse_message, *response_obuffer,
                          &dnsserv);
Evan Hunt's avatar
Evan Hunt committed
369
    EXPECT_FALSE(dnsserv.hasAnswer());
370
    EXPECT_TRUE(xfrout.isConnected());
Yoshitaka Aharen's avatar
Yoshitaka Aharen committed
371

372
    checkAllRcodeCountersZero();
Yoshitaka Aharen's avatar
Yoshitaka Aharen committed
373
374
375
376
377
    ConstElementPtr stats_after = server.getStatistics()->get("zones")->
        get("_SERVER_");
    expectCounterItem(stats_after->get("opcode"), "query", 1);
    expectCounterItem(stats_after, "responses", 0);
    expectCounterItem(stats_after->get("response"), "truncated", 0);
378
379
}

380
381
// Give the server a signed request, but don't give it the key. It will
// not be able to verify it, returning BADKEY
382
TEST_F(AuthSrvTest, TSIGSignedBadKey) {
Yoshitaka Aharen's avatar
Yoshitaka Aharen committed
383
384
385
386
387
388
389
390
    // The counters should be initialized to 0.
    ConstElementPtr stats_init = server.getStatistics()->get("zones")->
        get("_SERVER_");
    expectCounterItem(stats_init->get("request"), "tsig", 0);
    expectCounterItem(stats_init->get("request"), "badsig", 0);
    expectCounterItem(stats_init, "responses", 0);
    expectCounterItem(stats_init->get("response"), "tsig", 0);

391
392
393
    TSIGKey key("key:c2VjcmV0Cg==:hmac-sha1");
    TSIGContext context(key);
    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
Jelte Jansen's avatar
Jelte Jansen committed
394
395
                                       Name("version.bind"), RRClass::CH(),
                                       RRType::TXT());
396
397
398
    createRequestPacket(request_message, IPPROTO_UDP, &context);

    // Process the message, but use a different key there
399
    boost::shared_ptr<TSIGKeyRing> keyring(new TSIGKeyRing);
400
    server.setTSIGKeyRing(&keyring);
401
    server.processMessage(*io_message, *parse_message, *response_obuffer,
402
403
404
405
406
407
408
409
                          &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);
410
    m.fromWire(ib);
411
412

    const TSIGRecord* tsig = m.getTSIGRecord();
413
    ASSERT_TRUE(tsig != NULL) <<
414
        "Missing TSIG signature (we should have one even at error)";
415
    EXPECT_EQ(TSIGError::BAD_KEY_CODE, tsig->getRdata().getError());
416
417
    EXPECT_EQ(0, tsig->getRdata().getMACSize()) <<
        "It should be unsigned with this error";
418

Yoshitaka Aharen's avatar
Yoshitaka Aharen committed
419
    // check Rcode counters and TSIG counters
420
    checkAllRcodeCountersZeroExcept(Rcode::NOTAUTH(), 1);
Yoshitaka Aharen's avatar
Yoshitaka Aharen committed
421
422
423
424
425
426
    ConstElementPtr stats_after = server.getStatistics()->get("zones")->
        get("_SERVER_");
    expectCounterItem(stats_after->get("request"), "tsig", 1);
    expectCounterItem(stats_after->get("request"), "badsig", 1);
    expectCounterItem(stats_after, "responses", 1);
    expectCounterItem(stats_after->get("response"), "tsig", 1);
427
428
429
430
431
}

// Give the server a signed request, but signed by a different key
// (with the same name). It should return BADSIG
TEST_F(AuthSrvTest, TSIGBadSig) {
Yoshitaka Aharen's avatar
Yoshitaka Aharen committed
432
433
434
435
436
437
438
439
    // The counters should be initialized to 0.
    ConstElementPtr stats_init = server.getStatistics()->get("zones")->
        get("_SERVER_");
    expectCounterItem(stats_init->get("request"), "tsig", 0);
    expectCounterItem(stats_init->get("request"), "badsig", 0);
    expectCounterItem(stats_init, "responses", 0);
    expectCounterItem(stats_init->get("response"), "tsig", 0);

440
441
442
    TSIGKey key("key:c2VjcmV0Cg==:hmac-sha1");
    TSIGContext context(key);
    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
Jelte Jansen's avatar
Jelte Jansen committed
443
444
                                       Name("version.bind"), RRClass::CH(),
                                       RRType::TXT());
445
446
    createRequestPacket(request_message, IPPROTO_UDP, &context);

447
    // Process the message, but use a different key there
448
    boost::shared_ptr<TSIGKeyRing> keyring(new TSIGKeyRing);
449
450
    keyring->add(TSIGKey("key:QkFECg==:hmac-sha1"));
    server.setTSIGKeyRing(&keyring);
451
    server.processMessage(*io_message, *parse_message, *response_obuffer,
452
453
454
                          &dnsserv);

    EXPECT_TRUE(dnsserv.hasAnswer());
455
    headerCheck(*parse_message, default_qid, TSIGError::BAD_SIG().toRcode(),
456
457
458
459
                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);
460
    m.fromWire(ib);
461
462

    const TSIGRecord* tsig = m.getTSIGRecord();
463
    ASSERT_TRUE(tsig != NULL) <<
464
        "Missing TSIG signature (we should have one even at error)";
465
    EXPECT_EQ(TSIGError::BAD_SIG_CODE, tsig->getRdata().getError());
466
467
    EXPECT_EQ(0, tsig->getRdata().getMACSize()) <<
        "It should be unsigned with this error";
468
469

    checkAllRcodeCountersZeroExcept(Rcode::NOTAUTH(), 1);
Yoshitaka Aharen's avatar
Yoshitaka Aharen committed
470
471
472
473
474
475
    ConstElementPtr stats_after = server.getStatistics()->get("zones")->
        get("_SERVER_");
    expectCounterItem(stats_after->get("request"), "tsig", 1);
    expectCounterItem(stats_after->get("request"), "badsig", 1);
    expectCounterItem(stats_after, "responses", 1);
    expectCounterItem(stats_after->get("response"), "tsig", 1);
476
477
}

478
479
480
481
// 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) {
Yoshitaka Aharen's avatar
Yoshitaka Aharen committed
482
483
484
485
486
487
488
489
490
    // The counters should be initialized to 0.
    ConstElementPtr stats_init = server.getStatistics()->get("zones")->
        get("_SERVER_");
    expectCounterItem(stats_init->get("request"), "tsig", 0);
    expectCounterItem(stats_init->get("request"), "badsig", 0);
    expectCounterItem(stats_init, "responses", 0);
    expectCounterItem(stats_init->get("response"), "tsig", 0);
    expectCounterItem(stats_init->get("opcode"), "other", 0);

491
492
493
494
495
496
497
498
499
    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);

500
    // Process the message, but use a different key there
501
    boost::shared_ptr<TSIGKeyRing> keyring(new TSIGKeyRing);
502
503
    keyring->add(TSIGKey("key:QkFECg==:hmac-sha1"));
    server.setTSIGKeyRing(&keyring);
504
    server.processMessage(*io_message, *parse_message, *response_obuffer,
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
                          &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";
Yoshitaka Aharen's avatar
Yoshitaka Aharen committed
521
522
523
524
525
526
527

    ConstElementPtr stats_after = server.getStatistics()->get("zones")->
        get("_SERVER_");
    expectCounterItem(stats_after->get("request"), "tsig", 1);
    expectCounterItem(stats_after->get("request"), "badsig", 1);
    expectCounterItem(stats_after, "responses", 1);
    expectCounterItem(stats_after->get("response"), "tsig", 1);
528
529
    // TSIG should have failed, and so the per opcode counter shouldn't be
    // incremented.
Yoshitaka Aharen's avatar
Yoshitaka Aharen committed
530
    expectCounterItem(stats_after->get("opcode"), "other", 0);
531
    checkAllRcodeCountersZeroExcept(Rcode::NOTAUTH(), 1);
532
533
}

534
535
536
TEST_F(AuthSrvTest, AXFRConnectFail) {
    EXPECT_FALSE(xfrout.isConnected()); // check prerequisite
    xfrout.disableConnect();
Evan Hunt's avatar
Evan Hunt committed
537
    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
Jelte Jansen's avatar
Jelte Jansen committed
538
539
                                       Name("example.com"), RRClass::IN(),
                                       RRType::AXFR());
Evan Hunt's avatar
Evan Hunt committed
540
    createRequestPacket(request_message, IPPROTO_TCP);
541
542
    server.processMessage(*io_message, *parse_message, *response_obuffer,
                          &dnsserv);
Evan Hunt's avatar
Evan Hunt committed
543
    EXPECT_TRUE(dnsserv.hasAnswer());
544
    headerCheck(*parse_message, default_qid, Rcode::SERVFAIL(),
545
546
547
548
549
550
551
                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
552
    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
Jelte Jansen's avatar
Jelte Jansen committed
553
554
                                       Name("example.com"), RRClass::IN(),
                                       RRType::AXFR());
Evan Hunt's avatar
Evan Hunt committed
555
    createRequestPacket(request_message, IPPROTO_TCP);
556
557
    server.processMessage(*io_message, *parse_message, *response_obuffer,
                          &dnsserv);
558
    EXPECT_TRUE(xfrout.isConnected());
559
560

    xfrout.disableSend();
561
562
    parse_message->clear(Message::PARSE);
    response_obuffer->clear();
Evan Hunt's avatar
Evan Hunt committed
563
    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
Jelte Jansen's avatar
Jelte Jansen committed
564
565
                                       Name("example.com"), RRClass::IN(),
                                       RRType::AXFR());
Evan Hunt's avatar
Evan Hunt committed
566
    createRequestPacket(request_message, IPPROTO_TCP);
567
568
    server.processMessage(*io_message, *parse_message, *response_obuffer,
                          &dnsserv);
Evan Hunt's avatar
Evan Hunt committed
569
    EXPECT_TRUE(dnsserv.hasAnswer());
570
    headerCheck(*parse_message, default_qid, Rcode::SERVFAIL(),
571
572
573
574
575
576
577
                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) {
578
579
    // In our usage disconnect() shouldn't fail. But even if it does,
    // it should not disrupt service (so processMessage should have caught it)
580
581
    xfrout.disableSend();
    xfrout.disableDisconnect();
Evan Hunt's avatar
Evan Hunt committed
582
    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
Jelte Jansen's avatar
Jelte Jansen committed
583
584
                                       Name("example.com"), RRClass::IN(),
                                       RRType::AXFR());
Evan Hunt's avatar
Evan Hunt committed
585
    createRequestPacket(request_message, IPPROTO_TCP);
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
586
587
    EXPECT_NO_THROW(server.processMessage(*io_message, *parse_message,
                                          *response_obuffer, &dnsserv));
588
    // Since the disconnect failed, we should still be 'connected'
589
590
591
592
593
594
    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();
}

595
596
597
598
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
599
600
                                       Name("example.com"), RRClass::IN(),
                                       RRType::IXFR());
601
    createRequestPacket(request_message, IPPROTO_TCP);
602
603
    server.processMessage(*io_message, *parse_message, *response_obuffer,
                          &dnsserv);
604
605
606
607
608
609
610
611
612
613
    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
614
615
                                       Name("example.com"), RRClass::IN(),
                                       RRType::IXFR());
616
    createRequestPacket(request_message, IPPROTO_TCP);
617
618
    server.processMessage(*io_message, *parse_message, *response_obuffer,
                          &dnsserv);
619
620
621
622
623
624
    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
625
626
                                       Name("example.com"), RRClass::IN(),
                                       RRType::IXFR());
627
    createRequestPacket(request_message, IPPROTO_TCP);
628
629
    server.processMessage(*io_message, *parse_message, *response_obuffer,
                          &dnsserv);
630
631
632
633
634
635
636
637
638
    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) {
639
640
    // In our usage disconnect() shouldn't fail, but even if it does,
    // procesMessage() should catch it.
641
642
643
    xfrout.disableSend();
    xfrout.disableDisconnect();
    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
Jelte Jansen's avatar
Jelte Jansen committed
644
645
                                       Name("example.com"), RRClass::IN(),
                                       RRType::IXFR());
646
    createRequestPacket(request_message, IPPROTO_TCP);
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
647
648
    EXPECT_NO_THROW(server.processMessage(*io_message, *parse_message,
                                          *response_obuffer, &dnsserv));
649
650
651
652
653
654
    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();
}

655
TEST_F(AuthSrvTest, notify) {
Yoshitaka Aharen's avatar
Yoshitaka Aharen committed
656
657
658
659
660
661
    // The counters should be initialized to 0.
    ConstElementPtr stats_init = server.getStatistics()->get("zones")->
        get("_SERVER_");
    expectCounterItem(stats_init->get("opcode"), "notify", 0);
    expectCounterItem(stats_init, "responses", 0);

Jelte Jansen's avatar
Jelte Jansen committed
662
663
664
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
                                       default_qid, Name("example.com"),
                                       RRClass::IN(), RRType::SOA());
665
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
Evan Hunt's avatar
Evan Hunt committed
666
    createRequestPacket(request_message, IPPROTO_UDP);
667
668
    server.processMessage(*io_message, *parse_message, *response_obuffer,
                          &dnsserv);
Evan Hunt's avatar
Evan Hunt committed
669
    EXPECT_TRUE(dnsserv.hasAnswer());
670
671
672

    // An internal command message should have been created and sent to an
    // external module.  Check them.
Evan Hunt's avatar
Evan Hunt committed
673
    EXPECT_EQ("Zonemgr", notify_session.getMessageDest());
674
    EXPECT_EQ("notify",
Yoshitaka Aharen's avatar
Yoshitaka Aharen committed
675
676
              notify_session.getSentMessage()->get("command")->get(0)->
                  stringValue());
677
    ConstElementPtr notify_args =
Evan Hunt's avatar
Evan Hunt committed
678
        notify_session.getSentMessage()->get("command")->get(1);
679
680
681
    EXPECT_EQ("example.com.", notify_args->get("zone_name")->stringValue());
    EXPECT_EQ(DEFAULT_REMOTE_ADDRESS,
              notify_args->get("master")->stringValue());
682
    EXPECT_EQ("IN", notify_args->get("zone_class")->stringValue());
683
684

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

688
    // The question must be identical to that of the received notify
689
    ConstQuestionPtr question = *parse_message->beginQuestion();
690
691
692
    EXPECT_EQ(Name("example.com"), question->getName());
    EXPECT_EQ(RRClass::IN(), question->getClass());
    EXPECT_EQ(RRType::SOA(), question->getType());
693
694

    checkAllRcodeCountersZeroExcept(Rcode::NOERROR(), 1);
Yoshitaka Aharen's avatar
Yoshitaka Aharen committed
695
696
697
698
    ConstElementPtr stats_after = server.getStatistics()->get("zones")->
        get("_SERVER_");
    expectCounterItem(stats_after->get("opcode"), "notify", 1);
    expectCounterItem(stats_after, "responses", 1);
699
700
}

701
TEST_F(AuthSrvTest, notifyForCHClass) {
Yoshitaka Aharen's avatar
Yoshitaka Aharen committed
702
703
704
705
706
707
    // The counters should be initialized to 0.
    ConstElementPtr stats_init = server.getStatistics()->get("zones")->
        get("_SERVER_");
    expectCounterItem(stats_init->get("opcode"), "notify", 0);
    expectCounterItem(stats_init, "responses", 0);

708
    // Same as the previous test, but for the CH RRClass.
Jelte Jansen's avatar
Jelte Jansen committed
709
710
711
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
                                       default_qid, Name("example.com"),
                                       RRClass::CH(), RRType::SOA());
712
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
Evan Hunt's avatar
Evan Hunt committed
713
    createRequestPacket(request_message, IPPROTO_UDP);
714
715
    server.processMessage(*io_message, *parse_message, *response_obuffer,
                          &dnsserv);
Evan Hunt's avatar
Evan Hunt committed
716
    EXPECT_TRUE(dnsserv.hasAnswer());
717
718
719

    // Other conditions should be the same, so simply confirm the RR class is
    // set correctly.
720
    ConstElementPtr notify_args =
Evan Hunt's avatar
Evan Hunt committed
721
        notify_session.getSentMessage()->get("command")->get(1);
722
    EXPECT_EQ("CH", notify_args->get("zone_class")->stringValue());
Yoshitaka Aharen's avatar
Yoshitaka Aharen committed
723
724
725
726
727
728

    checkAllRcodeCountersZeroExcept(Rcode::NOERROR(), 1);
    ConstElementPtr stats_after = server.getStatistics()->get("zones")->
        get("_SERVER_");
    expectCounterItem(stats_after->get("opcode"), "notify", 1);
    expectCounterItem(stats_after, "responses", 1);
729
730
}

731
TEST_F(AuthSrvTest, notifyEmptyQuestion) {
Yoshitaka Aharen's avatar
Yoshitaka Aharen committed
732
733
734
735
736
737
738
    // The counters should be initialized to 0.
    ConstElementPtr stats_init = server.getStatistics()->get("zones")->
        get("_SERVER_");
    expectCounterItem(stats_init->get("opcode"), "notify", 0);
    expectCounterItem(stats_init, "responses", 0);
    expectCounterItem(stats_init->get("rcode"), "formerr", 0);

739
740
    request_message.clear(Message::RENDER);
    request_message.setOpcode(Opcode::NOTIFY());
741
    request_message.setRcode(Rcode::NOERROR());
742
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
743
744
    request_message.setQid(default_qid);
    request_message.toWire(request_renderer);
Evan Hunt's avatar
Evan Hunt committed
745
    createRequestPacket(request_message, IPPROTO_UDP);
746
747
    server.processMessage(*io_message, *parse_message, *response_obuffer,
                          &dnsserv);
Evan Hunt's avatar
Evan Hunt committed
748
    EXPECT_TRUE(dnsserv.hasAnswer());
749
    headerCheck(*parse_message, default_qid, Rcode::FORMERR(),
750
                Opcode::NOTIFY().getCode(), QR_FLAG, 0, 0, 0, 0);
Yoshitaka Aharen's avatar
Yoshitaka Aharen committed
751
752
753
754
755
756

    ConstElementPtr stats_after = server.getStatistics()->get("zones")->
        get("_SERVER_");
    expectCounterItem(stats_after->get("opcode"), "notify", 1);
    expectCounterItem(stats_after, "responses", 1);
    expectCounterItem(stats_after->get("rcode"), "formerr", 1);
757
758
759
}

TEST_F(AuthSrvTest, notifyMultiQuestions) {
Jelte Jansen's avatar
Jelte Jansen committed
760
761
762
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
                                       default_qid, Name("example.com"),
                                       RRClass::IN(), RRType::SOA());
763
764
765
    // add one more SOA question
    request_message.addQuestion(Question(Name("example.com"), RRClass::IN(),
                                         RRType::SOA()));
766
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
Evan Hunt's avatar
Evan Hunt committed
767
    createRequestPacket(request_message, IPPROTO_UDP);
768
769
    server.processMessage(*io_message, *parse_message, *response_obuffer,
                          &dnsserv);
Evan Hunt's avatar
Evan Hunt committed
770
    EXPECT_TRUE(dnsserv.hasAnswer());
771
    headerCheck(*parse_message, default_qid, Rcode::FORMERR(),
772
773
774
775
                Opcode::NOTIFY().getCode(), QR_FLAG, 2, 0, 0, 0);
}

TEST_F(AuthSrvTest, notifyNonSOAQuestion) {
Jelte Jansen's avatar
Jelte Jansen committed
776
777
778
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
                                       default_qid, Name("example.com"),
                                       RRClass::IN(), RRType::NS());
779
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
Evan Hunt's avatar
Evan Hunt committed
780
    createRequestPacket(request_message, IPPROTO_UDP);
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::FORMERR(),
785
786
787
788
789
                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
790
791
792
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
                                       default_qid, Name("example.com"),
                                       RRClass::IN(), RRType::SOA());
Evan Hunt's avatar
Evan Hunt committed
793
    createRequestPacket(request_message, IPPROTO_UDP);
794
795
    server.processMessage(*io_message, *parse_message, *response_obuffer,
                          &dnsserv);
Evan Hunt's avatar
Evan Hunt committed
796
    EXPECT_TRUE(dnsserv.hasAnswer());
797
    headerCheck(*parse_message, default_qid, Rcode::NOERROR(),
798
799
800
801
                Opcode::NOTIFY().getCode(), QR_FLAG | AA_FLAG, 1, 0, 0, 0);
}

TEST_F(AuthSrvTest, notifyWithErrorRcode) {
Jelte Jansen's avatar
Jelte Jansen committed
802
803
804
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
                                       default_qid, Name("example.com"),
                                       RRClass::IN(), RRType::SOA());
805
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
806
    request_message.setRcode(Rcode::SERVFAIL());
Evan Hunt's avatar
Evan Hunt committed
807
    createRequestPacket(request_message, IPPROTO_UDP);
808
809
    server.processMessage(*io_message, *parse_message, *response_obuffer,
                          &dnsserv);
Evan Hunt's avatar
Evan Hunt committed
810
    EXPECT_TRUE(dnsserv.hasAnswer());
811
    headerCheck(*parse_message, default_qid, Rcode::NOERROR(),
812
                Opcode::NOTIFY().getCode(), QR_FLAG | AA_FLAG, 1, 0, 0, 0);
Han Feng's avatar
Han Feng committed
813
814
}

815
TEST_F(AuthSrvTest, notifyWithoutSession) {
816
    server.setXfrinSession(NULL);
817

Jelte Jansen's avatar
Jelte Jansen committed
818
819
820
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
                                       default_qid, Name("example.com"),
                                       RRClass::IN(), RRType::SOA());
821
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
Evan Hunt's avatar
Evan Hunt committed
822
    createRequestPacket(request_message, IPPROTO_UDP);
823
824
825

    // we simply ignore the notify and let it be resent if an internal error
    // happens.
826
827
    server.processMessage(*io_message, *parse_message, *response_obuffer,
                          &dnsserv);
Evan Hunt's avatar
Evan Hunt committed
828
    EXPECT_FALSE(dnsserv.hasAnswer());
829
830
831
832
833
}

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

Jelte Jansen's avatar
Jelte Jansen committed
834
835
836
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
                                       default_qid, Name("example.com"),
                                       RRClass::IN(), RRType::SOA());
837
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
Evan Hunt's avatar
Evan Hunt committed
838
    createRequestPacket(request_message, IPPROTO_UDP);
839

840
841
    server.processMessage(*io_message, *parse_message, *response_obuffer,
                          &dnsserv);
Evan Hunt's avatar
Evan Hunt committed
842
    EXPECT_FALSE(dnsserv.hasAnswer());
843
844
845
846
847
}

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

Jelte Jansen's avatar
Jelte Jansen committed
848
849
850
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
                                       default_qid, Name("example.com"),
                                       RRClass::IN(), RRType::SOA());
851
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
Evan Hunt's avatar
Evan Hunt committed
852
    createRequestPacket(request_message, IPPROTO_UDP);
853
854
    server.processMessage(*io_message, *parse_message, *response_obuffer,
                          &dnsserv);
Evan Hunt's avatar
Evan Hunt committed
855
    EXPECT_FALSE(dnsserv.hasAnswer());
856
857
858
}

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

Jelte Jansen's avatar
Jelte Jansen committed
861
862
863
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
                                       default_qid, Name("example.com"),
                                       RRClass::IN(), RRType::SOA());
864
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
Evan Hunt's avatar
Evan Hunt committed
865
    createRequestPacket(request_message, IPPROTO_UDP);
866
867
    server.processMessage(*io_message, *parse_message, *response_obuffer,
                          &dnsserv);
Evan Hunt's avatar
Evan Hunt committed
868
    EXPECT_FALSE(dnsserv.hasAnswer());
869
870
871
872
}

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

Jelte Jansen's avatar
Jelte Jansen committed
875
876
877
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
                                       default_qid, Name("example.com"),
                                       RRClass::IN(), RRType::SOA());
878
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
Evan Hunt's avatar
Evan Hunt committed
879
    createRequestPacket(request_message, IPPROTO_UDP);
880
881
    server.processMessage(*io_message, *parse_message, *response_obuffer,
                          &dnsserv);
Evan Hunt's avatar
Evan Hunt committed
882
    EXPECT_FALSE(dnsserv.hasAnswer());
883
884
}

885
886
887
888
889
890
891
892
893
894
void
updateDatabase(AuthSrv* server, const char* params) {
    const ConstElementPtr config(Element::fromJSON("{"
        "\"IN\": [{"
        "    \"type\": \"sqlite3\","
        "    \"params\": " + string(params) +
        "}]}"));
    DataSourceConfigurator::testReconfigure(server, config);
}

895
896
897
898
899
900
901
902
903
void
updateInMemory(AuthSrv* server, const char* origin, const char* filename) {
    const ConstElementPtr config(Element::fromJSON("{"
        "\"IN\": [{"
        "   \"type\": \"MasterFiles\","
        "   \"params\": {"
        "       \"" + string(origin) + "\": \"" + string(filename) + "\""
        "   },"
        "   \"cache-enable\": true"
904
905
906
907
908
909
910
911
912
913
914
915
916
917
        "}],"
        "\"CH\": [{"
        "   \"type\": \"static\","
        "   \"params\": \"" + string(STATIC_DSRC_FILE) + "\""
        "}]}"));
    DataSourceConfigurator::testReconfigure(server, config);
}

void
updateBuiltin(AuthSrv* server) {
    const ConstElementPtr config(Element::fromJSON("{"
        "\"CH\": [{"
        "   \"type\": \"static\","
        "   \"params\": \"" + string(STATIC_DSRC_FILE) + "\""
918
919
920
921
        "}]}"));
    DataSourceConfigurator::testReconfigure(server, config);
}

922
923
924
925
926
927
928
// Try giving the server a TSIG signed request and see it can anwer signed as
// well
#ifdef USE_STATIC_LINK
TEST_F(AuthSrvTest, DISABLED_TSIGSigned) { // Needs builtin
#else
TEST_F(AuthSrvTest, TSIGSigned) {
#endif
Yoshitaka Aharen's avatar
Yoshitaka Aharen committed
929
930
931
932
933
934
935
936
937
    // The counters should be initialized to 0.
    ConstElementPtr stats_init = server.getStatistics()->get("zones")->
        get("_SERVER_");
    expectCounterItem(stats_init->get("request"), "tsig", 0);
    expectCounterItem(stats_init->get("request"), "sig0", 0);
    expectCounterItem(stats_init->get("request"), "badsig", 0);
    expectCounterItem(stats_init, "responses", 0);
    expectCounterItem(stats_init, "qryauthans", 0);

938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
    // Prepare key, the client message, etc
    updateBuiltin(&server);
    const TSIGKey key("key:c2VjcmV0Cg==:hmac-sha1");
    TSIGContext context(key);
    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
                                       Name("VERSION.BIND."), RRClass::CH(),
                                       RRType::TXT());
    createRequestPacket(request_message, IPPROTO_UDP, &context);

    // Run the message through the server
    boost::shared_ptr<TSIGKeyRing> keyring(new TSIGKeyRing);
    keyring->add(key);
    server.setTSIGKeyRing(&keyring);
    server.processMessage(*io_message, *parse_message, *response_obuffer,
                          &dnsserv);

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

    const TSIGRecord* tsig = m.getTSIGRecord();
    ASSERT_TRUE(tsig != NULL) << "Missing TSIG signature";
    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";

    checkAllRcodeCountersZeroExcept(Rcode::NOERROR(), 1);
Yoshitaka Aharen's avatar
Yoshitaka Aharen committed
971
972
973
974
975
976
977
    ConstElementPtr stats_after = server.getStatistics()->get("zones")->
        get("_SERVER_");
    expectCounterItem(stats_after->get("request"), "tsig", 1);
    expectCounterItem(stats_after->get("request"), "sig0", 0);
    expectCounterItem(stats_after->get("request"), "badsig", 0);
    expectCounterItem(stats_after, "responses", 1);
    expectCounterItem(stats_after, "qryauthans", 1);