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

15
#include <config.h>
16 17 18

#include <vector>

19 20
#include <boost/shared_ptr.hpp>

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

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

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

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

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

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

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

68
class AuthSrvTest : public SrvTestBase {
69
protected:
70 71 72
    AuthSrvTest() :
        dnss_(ios_, NULL, NULL, NULL),
        server(true, xfrout),
73 74
        rrclass(RRClass::IN()),
        sock_requestor_(dnss_, address_store_, 53210)
75 76
    {
        server.setDNSService(dnss_);
77
        server.setXfrinSession(&notify_session);
78
        server.setStatisticsSession(&statistics_session);
79
    }
80 81 82 83
    virtual void processMessage() {
        server.processMessage(*io_message, parse_message, response_obuffer,
                              &dnsserv);
    }
84 85
    IOService ios_;
    DNSService dnss_;
86
    MockSession statistics_session;
87
    MockXfroutClient xfrout;
88
    AuthSrv server;
JINMEI Tatuya's avatar
JINMEI Tatuya committed
89
    const RRClass rrclass;
90
    vector<uint8_t> response_data;
91
    AddressList address_store_;
92
    TestSocketRequestor sock_requestor_;
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 160 161 162
// 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,
163
                                     response_message,
164 165
                                     response_obuffer, &dnsserv);
    (*server.getDNSAnswerProvider())(*io_message, parse_message,
166
                                     response_message, response_obuffer);
167 168 169 170 171 172 173 174 175 176 177 178

    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,
179
                                     response_message,
180 181
                                     response_obuffer, &dnsserv);
    (*server.getDNSAnswerProvider())(*io_message, parse_message,
182
                                     response_message, response_obuffer);
183 184 185 186 187 188 189 190 191

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

192 193
// Unsupported requests.  Should result in NOTIMP.
TEST_F(AuthSrvTest, unsupportedRequest) {
194
    unsupportedRequest();
195
}
196 197 198

// Multiple questions.  Should result in FORMERR.
TEST_F(AuthSrvTest, multiQuestion) {
199
    multiQuestion();
200 201
}

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

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

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

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

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

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

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

246 247 248 249
// Try giving the server a TSIG signed request and see it can anwer signed as
// well
TEST_F(AuthSrvTest, TSIGSigned) {
    // Prepare key, the client message, etc
250
    const TSIGKey key("key:c2VjcmV0Cg==:hmac-sha1");
251 252
    TSIGContext context(key);
    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
Jelte Jansen's avatar
Jelte Jansen committed
253 254
                                       Name("version.bind"), RRClass::CH(),
                                       RRType::TXT());
255 256
    createRequestPacket(request_message, IPPROTO_UDP, &context);

257
    // Run the message through the server
258
    boost::shared_ptr<TSIGKeyRing> keyring(new TSIGKeyRing);
259 260
    keyring->add(key);
    server.setTSIGKeyRing(&keyring);
261 262 263 264 265 266 267 268 269 270
    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);
271
    m.fromWire(ib);
272 273

    const TSIGRecord* tsig = m.getTSIGRecord();
274
    ASSERT_TRUE(tsig != NULL) << "Missing TSIG signature";
275 276 277 278 279 280 281 282
    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";
}

// Give the server a signed request, but don't give it the key. It will
// not be able to verify it, returning BADKEY
283
TEST_F(AuthSrvTest, TSIGSignedBadKey) {
284 285 286
    TSIGKey key("key:c2VjcmV0Cg==:hmac-sha1");
    TSIGContext context(key);
    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
Jelte Jansen's avatar
Jelte Jansen committed
287 288
                                       Name("version.bind"), RRClass::CH(),
                                       RRType::TXT());
289 290 291
    createRequestPacket(request_message, IPPROTO_UDP, &context);

    // Process the message, but use a different key there
292
    boost::shared_ptr<TSIGKeyRing> keyring(new TSIGKeyRing);
293
    server.setTSIGKeyRing(&keyring);
294 295 296 297 298 299 300 301 302
    server.processMessage(*io_message, parse_message, response_obuffer,
                          &dnsserv);

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

    const TSIGRecord* tsig = m.getTSIGRecord();
306
    ASSERT_TRUE(tsig != NULL) <<
307
        "Missing TSIG signature (we should have one even at error)";
308
    EXPECT_EQ(TSIGError::BAD_KEY_CODE, tsig->getRdata().getError());
309 310
    EXPECT_EQ(0, tsig->getRdata().getMACSize()) <<
        "It should be unsigned with this error";
311 312 313 314 315 316 317 318
}

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

323
    // Process the message, but use a different key there
324
    boost::shared_ptr<TSIGKeyRing> keyring(new TSIGKeyRing);
325 326
    keyring->add(TSIGKey("key:QkFECg==:hmac-sha1"));
    server.setTSIGKeyRing(&keyring);
327 328 329 330
    server.processMessage(*io_message, parse_message, response_obuffer,
                          &dnsserv);

    EXPECT_TRUE(dnsserv.hasAnswer());
331
    headerCheck(*parse_message, default_qid, TSIGError::BAD_SIG().toRcode(),
332 333 334 335
                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);
336
    m.fromWire(ib);
337 338

    const TSIGRecord* tsig = m.getTSIGRecord();
339
    ASSERT_TRUE(tsig != NULL) <<
340
        "Missing TSIG signature (we should have one even at error)";
341
    EXPECT_EQ(TSIGError::BAD_SIG_CODE, tsig->getRdata().getError());
342 343
    EXPECT_EQ(0, tsig->getRdata().getMACSize()) <<
        "It should be unsigned with this error";
344 345
}

346 347 348 349 350 351 352 353 354 355 356 357 358
// Give the server a signed unsupported request with a bad signature.
// This checks the server first verifies the signature before anything
// else.
TEST_F(AuthSrvTest, TSIGCheckFirst) {
    TSIGKey key("key:c2VjcmV0Cg==:hmac-sha1");
    TSIGContext context(key);
    // Pass a wrong opcode there. The server shouldn't know what to do
    // about it.
    UnitTestUtil::createRequestMessage(request_message, Opcode::RESERVED14(),
                                       default_qid, Name("version.bind"),
                                       RRClass::CH(), RRType::TXT());
    createRequestPacket(request_message, IPPROTO_UDP, &context);

359
    // Process the message, but use a different key there
360
    boost::shared_ptr<TSIGKeyRing> keyring(new TSIGKeyRing);
361 362
    keyring->add(TSIGKey("key:QkFECg==:hmac-sha1"));
    server.setTSIGKeyRing(&keyring);
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379
    server.processMessage(*io_message, parse_message, response_obuffer,
                          &dnsserv);

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

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

385 386 387
TEST_F(AuthSrvTest, AXFRConnectFail) {
    EXPECT_FALSE(xfrout.isConnected()); // check prerequisite
    xfrout.disableConnect();
Evan Hunt's avatar
Evan Hunt committed
388
    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
Jelte Jansen's avatar
Jelte Jansen committed
389 390
                                       Name("example.com"), RRClass::IN(),
                                       RRType::AXFR());
Evan Hunt's avatar
Evan Hunt committed
391 392 393
    createRequestPacket(request_message, IPPROTO_TCP);
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_TRUE(dnsserv.hasAnswer());
394
    headerCheck(*parse_message, default_qid, Rcode::SERVFAIL(),
395 396 397 398 399 400 401
                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
402
    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
Jelte Jansen's avatar
Jelte Jansen committed
403 404
                                       Name("example.com"), RRClass::IN(),
                                       RRType::AXFR());
Evan Hunt's avatar
Evan Hunt committed
405 406
    createRequestPacket(request_message, IPPROTO_TCP);
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
407
    EXPECT_TRUE(xfrout.isConnected());
408 409

    xfrout.disableSend();
410 411
    parse_message->clear(Message::PARSE);
    response_obuffer->clear();
Evan Hunt's avatar
Evan Hunt committed
412
    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
Jelte Jansen's avatar
Jelte Jansen committed
413 414
                                       Name("example.com"), RRClass::IN(),
                                       RRType::AXFR());
Evan Hunt's avatar
Evan Hunt committed
415 416 417
    createRequestPacket(request_message, IPPROTO_TCP);
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_TRUE(dnsserv.hasAnswer());
418
    headerCheck(*parse_message, default_qid, Rcode::SERVFAIL(),
419 420 421 422 423 424 425 426 427 428 429
                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
430
    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
Jelte Jansen's avatar
Jelte Jansen committed
431 432
                                       Name("example.com"), RRClass::IN(),
                                       RRType::AXFR());
Evan Hunt's avatar
Evan Hunt committed
433
    createRequestPacket(request_message, IPPROTO_TCP);
434
    EXPECT_THROW(server.processMessage(*io_message, parse_message,
Evan Hunt's avatar
Evan Hunt committed
435
                                       response_obuffer, &dnsserv),
436 437 438 439 440 441 442
                 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();
}

443 444 445 446
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
447 448
                                       Name("example.com"), RRClass::IN(),
                                       RRType::IXFR());
449 450 451 452 453 454 455 456 457 458 459 460
    createRequestPacket(request_message, IPPROTO_TCP);
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_TRUE(dnsserv.hasAnswer());
    headerCheck(*parse_message, default_qid, Rcode::SERVFAIL(),
                opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
    EXPECT_FALSE(xfrout.isConnected());
}

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

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

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

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

501
TEST_F(AuthSrvTest, notify) {
Jelte Jansen's avatar
Jelte Jansen committed
502 503 504
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
                                       default_qid, Name("example.com"),
                                       RRClass::IN(), RRType::SOA());
505
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
Evan Hunt's avatar
Evan Hunt committed
506 507 508
    createRequestPacket(request_message, IPPROTO_UDP);
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_TRUE(dnsserv.hasAnswer());
509 510 511

    // An internal command message should have been created and sent to an
    // external module.  Check them.
Evan Hunt's avatar
Evan Hunt committed
512
    EXPECT_EQ("Zonemgr", notify_session.getMessageDest());
513
    EXPECT_EQ("notify",
Evan Hunt's avatar
Evan Hunt committed
514
              notify_session.getSentMessage()->get("command")->get(0)->stringValue());
515
    ConstElementPtr notify_args =
Evan Hunt's avatar
Evan Hunt committed
516
        notify_session.getSentMessage()->get("command")->get(1);
517 518 519
    EXPECT_EQ("example.com.", notify_args->get("zone_name")->stringValue());
    EXPECT_EQ(DEFAULT_REMOTE_ADDRESS,
              notify_args->get("master")->stringValue());
520
    EXPECT_EQ("IN", notify_args->get("zone_class")->stringValue());
521 522

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

526
    // The question must be identical to that of the received notify
527
    ConstQuestionPtr question = *parse_message->beginQuestion();
528 529 530 531 532
    EXPECT_EQ(Name("example.com"), question->getName());
    EXPECT_EQ(RRClass::IN(), question->getClass());
    EXPECT_EQ(RRType::SOA(), question->getType());
}

533 534
TEST_F(AuthSrvTest, notifyForCHClass) {
    // Same as the previous test, but for the CH RRClass.
Jelte Jansen's avatar
Jelte Jansen committed
535 536 537
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
                                       default_qid, Name("example.com"),
                                       RRClass::CH(), RRType::SOA());
538
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
Evan Hunt's avatar
Evan Hunt committed
539 540 541
    createRequestPacket(request_message, IPPROTO_UDP);
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_TRUE(dnsserv.hasAnswer());
542 543 544

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

550 551 552
TEST_F(AuthSrvTest, notifyEmptyQuestion) {
    request_message.clear(Message::RENDER);
    request_message.setOpcode(Opcode::NOTIFY());
553
    request_message.setRcode(Rcode::NOERROR());
554
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
555 556
    request_message.setQid(default_qid);
    request_message.toWire(request_renderer);
Evan Hunt's avatar
Evan Hunt committed
557 558 559
    createRequestPacket(request_message, IPPROTO_UDP);
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_TRUE(dnsserv.hasAnswer());
560
    headerCheck(*parse_message, default_qid, Rcode::FORMERR(),
561 562 563 564
                Opcode::NOTIFY().getCode(), QR_FLAG, 0, 0, 0, 0);
}

TEST_F(AuthSrvTest, notifyMultiQuestions) {
Jelte Jansen's avatar
Jelte Jansen committed
565 566 567
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
                                       default_qid, Name("example.com"),
                                       RRClass::IN(), RRType::SOA());
568 569 570
    // add one more SOA question
    request_message.addQuestion(Question(Name("example.com"), RRClass::IN(),
                                         RRType::SOA()));
571
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
Evan Hunt's avatar
Evan Hunt committed
572 573 574
    createRequestPacket(request_message, IPPROTO_UDP);
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_TRUE(dnsserv.hasAnswer());
575
    headerCheck(*parse_message, default_qid, Rcode::FORMERR(),
576 577 578 579
                Opcode::NOTIFY().getCode(), QR_FLAG, 2, 0, 0, 0);
}

TEST_F(AuthSrvTest, notifyNonSOAQuestion) {
Jelte Jansen's avatar
Jelte Jansen committed
580 581 582
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
                                       default_qid, Name("example.com"),
                                       RRClass::IN(), RRType::NS());
583
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
Evan Hunt's avatar
Evan Hunt committed
584 585 586
    createRequestPacket(request_message, IPPROTO_UDP);
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_TRUE(dnsserv.hasAnswer());
587
    headerCheck(*parse_message, default_qid, Rcode::FORMERR(),
588 589 590 591 592
                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
593 594 595
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
                                       default_qid, Name("example.com"),
                                       RRClass::IN(), RRType::SOA());
Evan Hunt's avatar
Evan Hunt committed
596 597 598
    createRequestPacket(request_message, IPPROTO_UDP);
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_TRUE(dnsserv.hasAnswer());
599
    headerCheck(*parse_message, default_qid, Rcode::NOERROR(),
600 601 602 603
                Opcode::NOTIFY().getCode(), QR_FLAG | AA_FLAG, 1, 0, 0, 0);
}

TEST_F(AuthSrvTest, notifyWithErrorRcode) {
Jelte Jansen's avatar
Jelte Jansen committed
604 605 606
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
                                       default_qid, Name("example.com"),
                                       RRClass::IN(), RRType::SOA());
607
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
608
    request_message.setRcode(Rcode::SERVFAIL());
Evan Hunt's avatar
Evan Hunt committed
609 610 611
    createRequestPacket(request_message, IPPROTO_UDP);
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_TRUE(dnsserv.hasAnswer());
612
    headerCheck(*parse_message, default_qid, Rcode::NOERROR(),
613
                Opcode::NOTIFY().getCode(), QR_FLAG | AA_FLAG, 1, 0, 0, 0);
Han Feng's avatar
Han Feng committed
614 615
}

616
TEST_F(AuthSrvTest, notifyWithoutSession) {
617
    server.setXfrinSession(NULL);
618

Jelte Jansen's avatar
Jelte Jansen committed
619 620 621
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
                                       default_qid, Name("example.com"),
                                       RRClass::IN(), RRType::SOA());
622
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
Evan Hunt's avatar
Evan Hunt committed
623
    createRequestPacket(request_message, IPPROTO_UDP);
624 625 626

    // we simply ignore the notify and let it be resent if an internal error
    // happens.
Evan Hunt's avatar
Evan Hunt committed
627 628
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_FALSE(dnsserv.hasAnswer());
629 630 631 632 633
}

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

Jelte Jansen's avatar
Jelte Jansen committed
634 635 636
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
                                       default_qid, Name("example.com"),
                                       RRClass::IN(), RRType::SOA());
637
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
Evan Hunt's avatar
Evan Hunt committed
638
    createRequestPacket(request_message, IPPROTO_UDP);
639

Evan Hunt's avatar
Evan Hunt committed
640 641
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_FALSE(dnsserv.hasAnswer());
642 643 644 645 646
}

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

Jelte Jansen's avatar
Jelte Jansen committed
647 648 649
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
                                       default_qid, Name("example.com"),
                                       RRClass::IN(), RRType::SOA());
650
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
Evan Hunt's avatar
Evan Hunt committed
651 652 653
    createRequestPacket(request_message, IPPROTO_UDP);
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_FALSE(dnsserv.hasAnswer());
654 655 656
}

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

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

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

Jelte Jansen's avatar
Jelte Jansen committed
672 673 674
    UnitTestUtil::createRequestMessage(request_message, Opcode::NOTIFY(),
                                       default_qid, Name("example.com"),
                                       RRClass::IN(), RRType::SOA());
675
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
Evan Hunt's avatar
Evan Hunt committed
676 677 678
    createRequestPacket(request_message, IPPROTO_UDP);
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_FALSE(dnsserv.hasAnswer());
679 680
}

681
void
JINMEI Tatuya's avatar
JINMEI Tatuya committed
682
updateConfig(AuthSrv* server, const char* const config_data,
683 684
             const bool expect_success)
{
685
    ConstElementPtr config_answer =
JINMEI Tatuya's avatar
JINMEI Tatuya committed
686
        server->updateConfig(Element::fromJSON(config_data));
687 688 689
    EXPECT_EQ(Element::map, config_answer->getType());
    EXPECT_TRUE(config_answer->contains("result"));

690
    ConstElementPtr result = config_answer->get("result");
691
    EXPECT_EQ(Element::list, result->getType());
692
    EXPECT_EQ(expect_success ? 0 : 1, result->get(0)->intValue());
693 694 695 696
}

// Install a Sqlite3 data source with testing data.
TEST_F(AuthSrvTest, updateConfig) {
697
    updateConfig(&server, CONFIG_TESTDB, true);
698 699 700 701

    // 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.
702
    createDataFromFile("examplequery_fromWire.wire");
Evan Hunt's avatar
Evan Hunt committed
703 704
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_TRUE(dnsserv.hasAnswer());
705
    headerCheck(*parse_message, default_qid, Rcode::NOERROR(), opcode.getCode(),
706 707 708 709
                QR_FLAG | AA_FLAG, 1, 1, 1, 0);
}

TEST_F(AuthSrvTest, datasourceFail) {
710
    updateConfig(&server, CONFIG_TESTDB, true);
711 712 713 714 715

    // 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.
716
    createDataFromFile("badExampleQuery_fromWire.wire");
Evan Hunt's avatar
Evan Hunt committed
717 718
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_TRUE(dnsserv.hasAnswer());
719
    headerCheck(*parse_message, default_qid, Rcode::SERVFAIL(),
720
                opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
721
}
722 723 724 725 726 727 728 729 730

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.
731
    createDataFromFile("examplequery_fromWire.wire");
Evan Hunt's avatar
Evan Hunt committed
732 733
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
    EXPECT_TRUE(dnsserv.hasAnswer());
734
    headerCheck(*parse_message, default_qid, Rcode::NOERROR(), opcode.getCode(),
735 736
                QR_FLAG | AA_FLAG, 1, 1, 1, 0);
}
JINMEI Tatuya's avatar
JINMEI Tatuya committed
737

738
TEST_F(AuthSrvTest, updateWithInMemoryClient) {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
739 740 741 742
    // 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
743
    EXPECT_EQ(AuthSrv::InMemoryClientPtr(), server.getInMemoryClient(rrclass));
JINMEI Tatuya's avatar
JINMEI Tatuya committed
744 745 746
    updateConfig(&server,
                 "{\"datasources\": [{\"type\": \"memory\"}]}", true);
    // after successful configuration, we should have one (with empty zoneset).
747 748
    ASSERT_NE(AuthSrv::InMemoryClientPtr(), server.getInMemoryClient(rrclass));
    EXPECT_EQ(0, server.getInMemoryClient(rrclass)->getZoneCount());
Jerry's avatar
Jerry committed
749

750
    // The memory data source is empty, should return REFUSED rcode.
Jerry's avatar
Jerry committed
751
    createDataFromFile("examplequery_fromWire.wire");
752 753 754 755 756 757 758
    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);
}

759
TEST_F(AuthSrvTest, chQueryWithInMemoryClient) {
760 761 762 763 764 765 766 767 768 769 770
    // 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);
771
    EXPECT_TRUE(dnsserv.hasAnswer());
772 773
    headerCheck(*parse_message, default_qid, Rcode::NOERROR(),
                opcode.getCode(), QR_FLAG | AA_FLAG, 1, 1, 1, 0);
JINMEI Tatuya's avatar
JINMEI Tatuya committed
774 775
}

JINMEI Tatuya's avatar
JINMEI Tatuya committed
776 777 778 779 780 781 782 783 784
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());
}
785

786 787 788
// Submit UDP normal query and check query counter
TEST_F(AuthSrvTest, queryCounterUDPNormal) {
    // The counter should be initialized to 0.
789
    EXPECT_EQ(0, server.getCounter(AuthCounters::SERVER_UDP_QUERY));
790 791 792 793 794 795 796
    // 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);
797
    // After processing UDP query, the counter should be 1.
798
    EXPECT_EQ(1, server.getCounter(AuthCounters::SERVER_UDP_QUERY));
799 800
}

801 802 803
// Submit TCP normal query and check query counter
TEST_F(AuthSrvTest, queryCounterTCPNormal) {
    // The counter should be initialized to 0.
804
    EXPECT_EQ(0, server.getCounter(AuthCounters::SERVER_TCP_QUERY));
805 806 807 808 809 810 811
    // 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);
812
    // After processing TCP query, the counter should be 1.
813
    EXPECT_EQ(1, server.getCounter(AuthCounters::SERVER_TCP_QUERY));
814 815 816 817 818
}

// Submit TCP AXFR query and check query counter
TEST_F(AuthSrvTest, queryCounterTCPAXFR) {
    // The counter should be initialized to 0.
819
    EXPECT_EQ(0, server.getCounter(AuthCounters::SERVER_TCP_QUERY));
820 821 822 823
    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,
Jelte Jansen's avatar
Jelte Jansen committed
824
    // so auth itself shouldn't respond.
825
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
Jelte Jansen's avatar
Jelte Jansen committed
826
    EXPECT_FALSE(dnsserv.hasAnswer());
827
    // After processing TCP AXFR query, the counter should be 1.
828
    EXPECT_EQ(1, server.getCounter(AuthCounters::SERVER_TCP_QUERY));
829 830
}

831 832 833
// Submit TCP IXFR query and check query counter
TEST_F(AuthSrvTest, queryCounterTCPIXFR) {
    // The counter should be initialized to 0.
834
    EXPECT_EQ(0, server.getCounter(AuthCounters::SERVER_TCP_QUERY));
835 836 837
    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
                         Name("example.com"), RRClass::IN(), RRType::IXFR());
    createRequestPacket(request_message, IPPROTO_TCP);
Jelte Jansen's avatar
Jelte Jansen committed
838 839
    // On success, the IXFR query has been passed to a separate process,
    // so auth itself shouldn't respond.
840
    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
Jelte Jansen's avatar
Jelte Jansen committed
841 842
    EXPECT_FALSE(dnsserv.hasAnswer());
    // After processing TCP IXFR query, the counter should be 1.
843
    EXPECT_EQ(1, server.getCounter(AuthCounters::SERVER_TCP_QUERY));
844 845
}

846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869
TEST_F(AuthSrvTest, queryCounterOpcodes) {
    for (int i = 0; i < 16; ++i) {
        // The counter should be initialized to 0.
        EXPECT_EQ(0, server.getCounter(Opcode(i)));

        // For each possible opcode, create a request message and send it
        UnitTestUtil::createRequestMessage(request_message, Opcode(i),
                                           default_qid, Name("example.com"),
                                           RRClass::IN(), RRType::NS());
        createRequestPacket(request_message, IPPROTO_UDP);

        // "send" the request N-th times where N is i + 1 for i-th code.
        // we intentionally use different values for each code
        for (int j = 0; j <= i; ++j) {
            parse_message->clear(Message::PARSE);
            server.processMessage(*io_message, parse_message, response_obuffer,
                                  &dnsserv);
        }

        // Confirm the counter.
        EXPECT_EQ(i + 1, server.getCounter(Opcode(i)));
    }
}

870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886
// 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);
}

887
// Submit unexpected type of query and check it throws isc::Unexpected
888
TEST_F(AuthSrvTest, queryCounterUnexpected) {
889 890 891 892
    // 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.

893
    // Create UDP query packet.
894 895 896 897
    UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
                                       default_qid, Name("example.com"),
                                       RRClass::IN(), RRType::NS());
    createRequestPacket(request_message, IPPROTO_UDP);
898

899
    // Modify the message.
900 901
    delete io_message;
    endpoint = IOEndpoint::create(IPPROTO_UDP,
902
                                  IOAddress(DEFAULT_REMOTE_ADDRESS), 53210);