resolver.cc 26.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
// Copyright (C) 2009  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.

#include <config.h>

17
#include <stdint.h>
18 19 20 21
#include <netinet/in.h>

#include <algorithm>
#include <vector>
Michal Vaner's avatar
Michal Vaner committed
22
#include <cassert>
23

24 25 26
#include <boost/shared_ptr.hpp>
#include <boost/foreach.hpp>

27 28
#include <exceptions/exceptions.h>

29
#include <acl/dns.h>
30 31
#include <acl/loader.h>

32
#include <asiodns/asiodns.h>
33 34 35 36 37 38
#include <asiolink/asiolink.h>

#include <config/ccsession.h>

#include <exceptions/exceptions.h>

39
#include <util/buffer.h>
40

Michal Vaner's avatar
Michal Vaner committed
41 42
#include <dns/opcode.h>
#include <dns/rcode.h>
43 44 45 46 47 48
#include <dns/exceptions.h>
#include <dns/name.h>
#include <dns/question.h>
#include <dns/rrset.h>
#include <dns/rrttl.h>
#include <dns/message.h>
49
#include <dns/messagerenderer.h>
50 51

#include <server_common/client.h>
52
#include <server_common/portconfig.h>
53

54 55
#include <resolve/recursive_query.h>

56 57
#include "resolver.h"
#include "resolver_log.h"
58 59 60

using namespace std;
using namespace isc;
61
using namespace isc::util;
62
using namespace isc::acl;
63
using isc::acl::dns::RequestACL;
64 65 66
using namespace isc::dns;
using namespace isc::data;
using namespace isc::config;
67 68
using namespace isc::asiodns;
using namespace isc::asiolink;
69
using namespace isc::server_common;
70
using namespace isc::server_common::portconfig;
71

72
class ResolverImpl {
73 74
private:
    // prohibit copy
75 76
    ResolverImpl(const ResolverImpl& source);
    ResolverImpl& operator=(const ResolverImpl& source);
77
public:
78
    ResolverImpl() :
79
        config_session_(NULL),
80 81 82
        query_timeout_(2000),
        client_timeout_(4000),
        lookup_timeout_(30000),
83
        retries_(3),
84 85
        // we apply "reject all" (implicit default of the loader) ACL by
        // default:
86
        query_acl_(acl::dns::getRequestLoader().load(Element::fromJSON("[]"))),
Michal Vaner's avatar
Michal Vaner committed
87
        rec_query_(NULL)
88 89
    {}

90
    ~ResolverImpl() {
91 92 93
        queryShutdown();
    }

94 95 96 97
    void querySetup(DNSService& dnss,
                    isc::nsas::NameserverAddressStore& nsas,
                    isc::cache::ResolverCache& cache)
    {
Michal Vaner's avatar
Michal Vaner committed
98
        assert(!rec_query_); // queryShutdown must be called first
99
        LOG_DEBUG(resolver_logger, RESOLVER_DBG_INIT, RESOLVER_QUERY_SETUP);
100 101 102
        rec_query_ = new RecursiveQuery(dnss, 
                                        nsas, cache,
                                        upstream_,
103
                                        upstream_root_,
Jelte Jansen's avatar
Jelte Jansen committed
104 105 106 107
                                        query_timeout_,
                                        client_timeout_,
                                        lookup_timeout_,
                                        retries_);
108 109 110
    }

    void queryShutdown() {
111 112 113 114
        // only shut down if we have actually called querySetup before
        // (this is not a safety check, just to prevent logging of
        // actions that are not performed
        if (rec_query_) {
115 116
            LOG_DEBUG(resolver_logger, RESOLVER_DBG_INIT,
                      RESOLVER_QUERY_SHUTDOWN);
117 118 119
            delete rec_query_;
            rec_query_ = NULL;
        }
120 121
    }

122
    void setForwardAddresses(const AddressList& upstream,
Michal Vaner's avatar
Michal Vaner committed
123
        DNSService *dnss)
124 125
    {
        upstream_ = upstream;
Michal Vaner's avatar
Michal Vaner committed
126
        if (dnss) {
Jelte Jansen's avatar
Jelte Jansen committed
127
            if (!upstream_.empty()) {
128
                BOOST_FOREACH(const AddressPair& address, upstream) {
129
                    LOG_INFO(resolver_logger, RESOLVER_FORWARD_ADDRESS)
130
                             .arg(address.first).arg(address.second);
131
                }
Jelte Jansen's avatar
Jelte Jansen committed
132
            } else {
133
                LOG_INFO(resolver_logger, RESOLVER_RECURSIVE);
134
            }
135 136 137
        }
    }

138
    void setRootAddresses(const AddressList& upstream_root,
chenzhengzhang's avatar
chenzhengzhang committed
139 140 141 142 143
                          DNSService *dnss)
    {
        upstream_root_ = upstream_root;
        if (dnss) {
            if (!upstream_root_.empty()) {
144
                BOOST_FOREACH(const AddressPair& address, upstream_root) {
145
                    LOG_INFO(resolver_logger, RESOLVER_SET_ROOT_ADDRESS)
146
                             .arg(address.first).arg(address.second);
chenzhengzhang's avatar
chenzhengzhang committed
147 148
                }
            } else {
149
                LOG_WARN(resolver_logger, RESOLVER_NO_ROOT_ADDRESS);
chenzhengzhang's avatar
chenzhengzhang committed
150 151 152
            }
        }
    }
153
    
154
    void resolve(const isc::dns::QuestionPtr& question,
155
        const isc::resolve::ResolverInterface::CallbackPtr& callback);
156

157 158 159 160 161 162
    enum NormalQueryResult { RECURSION, DROPPED, ERROR };
    NormalQueryResult processNormalQuery(const IOMessage& io_message,
                                         MessagePtr query_message,
                                         MessagePtr answer_message,
                                         OutputBufferPtr buffer,
                                         DNSServer* server);
163

164
    const RequestACL& getQueryACL() const {
165 166 167
        return (*query_acl_);
    }

168
    void setQueryACL(boost::shared_ptr<const RequestACL> new_acl) {
169 170
        query_acl_ = new_acl;
    }
171

Evan Hunt's avatar
Evan Hunt committed
172 173
    /// Currently non-configurable, but will be.
    static const uint16_t DEFAULT_LOCAL_UDPSIZE = 4096;
174

175
    /// These members are public because Resolver accesses them directly.
Evan Hunt's avatar
Evan Hunt committed
176
    ModuleCCSession* config_session_;
chenzhengzhang's avatar
chenzhengzhang committed
177
    /// Addresses of the root nameserver(s)
178
    AddressList upstream_root_;
179
    /// Addresses of the forward nameserver
180
    AddressList upstream_;
Michal Vaner's avatar
Michal Vaner committed
181
    /// Addresses we listen on
182
    AddressList listen_;
183

184 185 186 187 188 189 190
    /// Timeout for outgoing queries in milliseconds
    int query_timeout_;
    /// Timeout for incoming client queries in milliseconds
    int client_timeout_;
    /// Timeout for lookup processing in milliseconds
    int lookup_timeout_;
    
Michal Vaner's avatar
Michal Vaner committed
191 192 193
    /// Number of retries after timeout
    unsigned retries_;

Evan Hunt's avatar
Evan Hunt committed
194
private:
195
    /// ACL on incoming queries
196
    boost::shared_ptr<const RequestACL> query_acl_;
197

198
    /// Object to handle upstream queries
199
    RecursiveQuery* rec_query_;
200 201
};

202 203 204 205 206
/*
 * std::for_each has a broken interface. It makes no sense in a language
 * without lambda functions/closures. These two classes emulate the lambda
 * functions so for_each can be used.
 */
207 208 209 210 211 212 213 214 215
class QuestionInserter {
public:
    QuestionInserter(MessagePtr message) : message_(message) {}
    void operator()(const QuestionPtr question) {
        message_->addQuestion(question);
    }
    MessagePtr message_;
};

216 217

// TODO: REMOVE, USE isc::resolve::MakeErrorMessage?
218
void
219 220
makeErrorMessage(MessagePtr message, MessagePtr answer_message,
                 OutputBufferPtr buffer, const Rcode& rcode)
221 222 223 224 225
{
    // extract the parameters that should be kept.
    // XXX: with the current implementation, it's not easy to set EDNS0
    // depending on whether the query had it.  So we'll simply omit it.
    const qid_t qid = message->getQid();
Michal Vaner's avatar
Michal Vaner committed
226 227
    const bool rd = message->getHeaderFlag(Message::HEADERFLAG_RD);
    const bool cd = message->getHeaderFlag(Message::HEADERFLAG_CD);
228 229 230
    const Opcode& opcode = message->getOpcode();
    vector<QuestionPtr> questions;

231 232 233 234 235 236
    // answer_message is actually ignored right now,
    // see the comment in #607
    answer_message->setRcode(rcode);
    answer_message->setOpcode(opcode);
    answer_message->setQid(qid);

237 238 239 240 241 242 243 244 245
    // If this is an error to a query or notify, we should also copy the
    // question section.
    if (opcode == Opcode::QUERY() || opcode == Opcode::NOTIFY()) {
        questions.assign(message->beginQuestion(), message->endQuestion());
    }

    message->clear(Message::RENDER);
    message->setQid(qid);
    message->setOpcode(opcode);
Michal Vaner's avatar
Michal Vaner committed
246
    message->setHeaderFlag(Message::HEADERFLAG_QR);
247
    if (rd) {
Michal Vaner's avatar
Michal Vaner committed
248
        message->setHeaderFlag(Message::HEADERFLAG_RD);
249 250
    }
    if (cd) {
Michal Vaner's avatar
Michal Vaner committed
251
        message->setHeaderFlag(Message::HEADERFLAG_CD);
252 253 254 255 256 257
    }
    for_each(questions.begin(), questions.end(), QuestionInserter(message));
    message->setRcode(rcode);
    MessageRenderer renderer(*buffer);
    message->toWire(renderer);
}
258

259
// This is a derived class of \c DNSLookup, to serve as a
260
// callback in the asiolink module.  It calls
261
// Resolver::processMessage() on a single DNS message.
262
class MessageLookup : public DNSLookup {
263
public:
264
    MessageLookup(Resolver* srv) : server_(srv) {}
265 266

    // \brief Handle the DNS Lookup
267
    virtual void operator()(const IOMessage& io_message,
268
                            MessagePtr query_message,
269 270 271
                            MessagePtr answer_message,
                            OutputBufferPtr buffer,
                            DNSServer* server) const
272
    {
273 274
        server_->processMessage(io_message, query_message,
                                answer_message, buffer, server);
275 276
    }
private:
277
    Resolver* server_;
278 279 280 281 282 283 284 285 286
};

// This is a derived class of \c DNSAnswer, to serve as a
// callback in the asiolink module.  It takes a completed
// set of answer data from the DNS lookup and assembles it
// into a wire-format response.
class MessageAnswer : public DNSAnswer {
public:
    virtual void operator()(const IOMessage& io_message,
287
                            MessagePtr query_message,
288
                            MessagePtr answer_message,
289
                            OutputBufferPtr buffer) const
290
    {
291 292 293
        const qid_t qid = query_message->getQid();
        const bool rd = query_message->getHeaderFlag(Message::HEADERFLAG_RD);
        const bool cd = query_message->getHeaderFlag(Message::HEADERFLAG_CD);
294 295 296
        
        // The opcode and question section should have already been set,
        // fill in the final details of the answer message
297
        answer_message->setQid(qid);
298

299 300
        answer_message->setHeaderFlag(Message::HEADERFLAG_QR);
        answer_message->setHeaderFlag(Message::HEADERFLAG_RA);
301 302
        answer_message->setHeaderFlag(Message::HEADERFLAG_RD, rd);
        answer_message->setHeaderFlag(Message::HEADERFLAG_CD, cd);
303 304 305 306 307

        // Now we can clear the buffer and render the new message into it
        buffer->clear();
        MessageRenderer renderer(*buffer);

308 309 310 311 312 313 314 315 316 317
        ConstEDNSPtr edns(query_message->getEDNS());
        const bool dnssec_ok = edns && edns->getDNSSECAwareness();
        if (edns) {
            EDNSPtr edns_response(new EDNS());
            edns_response->setDNSSECAwareness(dnssec_ok);

            // TODO: We should make our own edns bufsize length configurable
            edns_response->setUDPSize(Message::DEFAULT_MAX_EDNS0_UDPSIZE);
            answer_message->setEDNS(edns_response);
        }
318

319
        if (io_message.getSocket().getProtocol() == IPPROTO_UDP) {
320 321 322 323 324
            if (edns) {
                renderer.setLengthLimit(edns->getUDPSize());
            } else {
                renderer.setLengthLimit(Message::DEFAULT_MAX_UDPSIZE);
            }
325 326 327
        } else {
            renderer.setLengthLimit(65535);
        }
328

329
        answer_message->toWire(renderer);
330

331 332
        LOG_DEBUG(resolver_logger, RESOLVER_DBG_DETAIL,
                  RESOLVER_DNS_MESSAGE_SENT)
333
                  .arg(renderer.getLength()).arg(*answer_message);
334 335 336
    }
};

337
// This is a derived class of \c SimpleCallback, to serve
338 339
// as a callback in the asiolink module.  It checks for queued
// configuration messages, and executes them if found.
340
class ConfigCheck : public SimpleCallback {
341
public:
342
    ConfigCheck(Resolver* srv) : server_(srv) {}
Michal Vaner's avatar
Michal Vaner committed
343
    virtual void operator()(const IOMessage&) const {
344 345
        if (server_->getConfigSession()->hasQueuedMsgs()) {
            server_->getConfigSession()->checkCommand();
346 347 348
        }
    }
private:
349
    Resolver* server_;
350 351
};

352 353
Resolver::Resolver() :
    impl_(new ResolverImpl()),
354
    dnss_(NULL),
355 356
    checkin_(NULL),
    dns_lookup_(NULL),
357
    dns_answer_(new MessageAnswer),
358 359
    nsas_(NULL),
    cache_(NULL),
360
    configured_(false)
361 362 363 364 365 366 367
{
    // Operations referring to "this" must be done in the constructor body
    // (some compilers will issue warnings if "this" is referred to in the
    // initialization list).
    checkin_ = new ConfigCheck(this);
    dns_lookup_ = new MessageLookup(this);
}
368

369
Resolver::~Resolver() {
370
    delete impl_;
371 372 373
    delete checkin_;
    delete dns_lookup_;
    delete dns_answer_;
374 375 376
}

void
377
Resolver::setDNSService(isc::asiodns::DNSService& dnss) {
378
    dnss_ = &dnss;
379 380
}

381 382 383 384 385 386 387 388 389 390 391 392 393
void
Resolver::setNameserverAddressStore(isc::nsas::NameserverAddressStore& nsas)
{
    nsas_ = &nsas;
}

void
Resolver::setCache(isc::cache::ResolverCache& cache)
{
    cache_ = &cache;
}


394
void
395
Resolver::setConfigSession(ModuleCCSession* config_session) {
396 397 398 399
    impl_->config_session_ = config_session;
}

ModuleCCSession*
400
Resolver::getConfigSession() const {
401 402 403
    return (impl_->config_session_);
}

404 405
void
Resolver::resolve(const isc::dns::QuestionPtr& question,
406
    const isc::resolve::ResolverInterface::CallbackPtr& callback)
407 408 409 410 411
{
    impl_->resolve(question, callback);
}


412
void
413
Resolver::processMessage(const IOMessage& io_message,
414
                         MessagePtr query_message,
415 416 417
                         MessagePtr answer_message,
                         OutputBufferPtr buffer,
                         DNSServer* server)
418 419 420 421
{
    InputBuffer request_buffer(io_message.getData(), io_message.getDataSize());
    // First, check the header part.  If we fail even for the base header,
    // just drop the message.
422 423 424 425

    // In the following code, the debug output is such that there should only be
    // one debug message if packet processing failed.  There could be two if
    // it succeeded.
426
    try {
427
        query_message->parseHeader(request_buffer);
428 429

        // Ignore all responses.
430
        if (query_message->getHeaderFlag(Message::HEADERFLAG_QR)) {
431
            LOG_DEBUG(resolver_logger, RESOLVER_DBG_IO, RESOLVER_UNEXPECTED_RESPONSE);
432
            server->resume(false);
433
            return;
434 435
        }
    } catch (const Exception& ex) {
436
        LOG_DEBUG(resolver_logger, RESOLVER_DBG_IO, RESOLVER_HEADER_ERROR)
437
                  .arg(ex.what());
438
        server->resume(false);
439
        return;
440 441 442 443
    }

    // Parse the message.  On failure, return an appropriate error.
    try {
444
        query_message->fromWire(request_buffer);
445
    } catch (const DNSProtocolError& error) {
446
        LOG_DEBUG(resolver_logger, RESOLVER_DBG_IO, RESOLVER_PROTOCOL_ERROR)
447
                  .arg(error.what()).arg(error.getRcode());
448 449
        makeErrorMessage(query_message, answer_message,
                         buffer, error.getRcode());
450
        server->resume(true);
451
        return;
452
    } catch (const Exception& ex) {
453
        LOG_DEBUG(resolver_logger, RESOLVER_DBG_IO, RESOLVER_MESSAGE_ERROR)
454
                  .arg(ex.what()).arg(Rcode::SERVFAIL());
455 456
        makeErrorMessage(query_message, answer_message,
                         buffer, Rcode::SERVFAIL());
457
        server->resume(true);
458
        return;
459
    } // Other exceptions will be handled at a higher layer.
460

461 462 463
    // Note:  there appears to be no LOG_DEBUG for a successfully-received
    // message.  This is not an oversight - it is handled below.  In the
    // meantime, output the full message for debug purposes (if requested).
464 465
    LOG_DEBUG(resolver_logger, RESOLVER_DBG_DETAIL,
              RESOLVER_DNS_MESSAGE_RECEIVED).arg(*query_message);
466 467

    // Perform further protocol-level validation.
468
    bool send_answer = true;
469
    if (query_message->getOpcode() == Opcode::NOTIFY()) {
470

471 472
        makeErrorMessage(query_message, answer_message,
                         buffer, Rcode::NOTAUTH());
473
        // Notify arrived, but we are not authoritative.
474 475
        LOG_DEBUG(resolver_logger, RESOLVER_DBG_PROCESS,
                  RESOLVER_NOTIFY_RECEIVED);
476
    } else if (query_message->getOpcode() != Opcode::QUERY()) {
477
        // Unsupported opcode.
478 479
        LOG_DEBUG(resolver_logger, RESOLVER_DBG_PROCESS,
                  RESOLVER_UNSUPPORTED_OPCODE).arg(query_message->getOpcode());
480 481
        makeErrorMessage(query_message, answer_message,
                         buffer, Rcode::NOTIMP());
482
    } else if (query_message->getRRCount(Message::SECTION_QUESTION) != 1) {
483
        // Not one question
484 485
        LOG_DEBUG(resolver_logger, RESOLVER_DBG_PROCESS,
                  RESOLVER_NOT_ONE_QUESTION)
486
                  .arg(query_message->getRRCount(Message::SECTION_QUESTION));
487 488
        makeErrorMessage(query_message, answer_message, buffer,
                         Rcode::FORMERR());
489
    } else {
490 491 492 493
        const ResolverImpl::NormalQueryResult result =
            impl_->processNormalQuery(io_message, query_message,
                                      answer_message, buffer, server);
        if (result == ResolverImpl::RECURSION) {
494 495
            // The RecursiveQuery object will post the "resume" event to the
            // DNSServer when an answer arrives, so we don't have to do it now.
496 497 498
            return;
        } else if (result == ResolverImpl::DROPPED) {
            send_answer = false;
499 500
        }
    }
501

502
    server->resume(send_answer);
503 504
}

505 506
void
ResolverImpl::resolve(const QuestionPtr& question,
507
    const isc::resolve::ResolverInterface::CallbackPtr& callback)
508
{
509
    rec_query_->resolve(question, callback);
510 511
}

512 513 514
ResolverImpl::NormalQueryResult
ResolverImpl::processNormalQuery(const IOMessage& io_message,
                                 MessagePtr query_message,
515 516 517
                                 MessagePtr answer_message,
                                 OutputBufferPtr buffer,
                                 DNSServer* server)
518
{
519 520 521 522 523
    const ConstQuestionPtr question = *query_message->beginQuestion();
    const RRType qtype = question->getType();
    const RRClass qclass = question->getClass();

    // Apply query ACL
524 525 526
    const Client client(io_message);
    const BasicAction query_action(
        getQueryACL().execute(acl::dns::RequestContext(
527 528
                                  client.getRequestSourceIPAddress(),
                                  query_message->getTSIGRecord())));
529
    if (query_action == isc::acl::REJECT) {
530
        LOG_INFO(resolver_logger, RESOLVER_QUERY_REJECTED)
531 532 533 534 535
            .arg(question->getName()).arg(qtype).arg(qclass).arg(client);
        makeErrorMessage(query_message, answer_message, buffer,
                         Rcode::REFUSED());
        return (ERROR);
    } else if (query_action == isc::acl::DROP) {
536
        LOG_INFO(resolver_logger, RESOLVER_QUERY_DROPPED)
537 538 539
            .arg(question->getName()).arg(qtype).arg(qclass).arg(client);
        return (DROPPED);
    }
540
    LOG_DEBUG(resolver_logger, RESOLVER_DBG_IO, RESOLVER_QUERY_ACCEPTED)
541 542 543 544 545 546
        .arg(question->getName()).arg(qtype).arg(question->getClass())
        .arg(client);

    // ACL passed.  Reject inappropriate queries for the resolver.
    if (qtype == RRType::AXFR()) {
        if (io_message.getSocket().getProtocol() == IPPROTO_UDP) {
Jeremy C. Reed's avatar
Jeremy C. Reed committed
547
            // Can't process AXFR request received over UDP
548
            LOG_DEBUG(resolver_logger, RESOLVER_DBG_PROCESS, RESOLVER_AXFR_UDP);
549 550 551 552
            makeErrorMessage(query_message, answer_message, buffer,
                             Rcode::FORMERR());
        } else {
            // ... or over TCP for that matter
553
            LOG_DEBUG(resolver_logger, RESOLVER_DBG_PROCESS, RESOLVER_AXFR_TCP);
554 555 556 557 558 559 560 561 562 563 564 565
            makeErrorMessage(query_message, answer_message, buffer,
                             Rcode::NOTIMP());
        }
        return (ERROR);
    } else if (qtype == RRType::IXFR()) {
        // Can't process IXFR request
        LOG_DEBUG(resolver_logger, RESOLVER_DBG_PROCESS, RESOLVER_IXFR);
        makeErrorMessage(query_message, answer_message, buffer,
                         Rcode::NOTIMP());
        return (ERROR);
    } else if (qclass != RRClass::IN()) {
        // Non-IN message received, refuse it.
566 567
        LOG_DEBUG(resolver_logger, RESOLVER_DBG_PROCESS, RESOLVER_NON_IN_PACKET)
            .arg(question->getClass());
568 569 570 571 572 573
        makeErrorMessage(query_message, answer_message, buffer,
                         Rcode::REFUSED());
        return (ERROR);
    }

    // Everything is okay.  Start resolver.
574
    if (upstream_.empty()) {
575
        // Processing normal query
576
        LOG_DEBUG(resolver_logger, RESOLVER_DBG_IO, RESOLVER_NORMAL_QUERY);
577 578
        rec_query_->resolve(*question, answer_message, buffer, server);
    } else {
579
        // Processing forward query
580
        LOG_DEBUG(resolver_logger, RESOLVER_DBG_IO, RESOLVER_FORWARD_QUERY);
581 582
        rec_query_->forward(query_message, answer_message, buffer, server);
    }
583 584

    return (RECURSION);
585 586 587
}

ConstElementPtr
588
Resolver::updateConfig(ConstElementPtr config) {
589
    LOG_DEBUG(resolver_logger, RESOLVER_DBG_CONFIG, RESOLVER_CONFIG_UPDATED)
590
              .arg(*config);
Michal Vaner's avatar
Michal Vaner committed
591

592
    try {
593
        // Parse forward_addresses
chenzhengzhang's avatar
chenzhengzhang committed
594
        ConstElementPtr rootAddressesE(config->get("root_addresses"));
595
        AddressList rootAddresses(parseAddresses(rootAddressesE,
596
                                                    "root_addresses"));
Michal Vaner's avatar
Michal Vaner committed
597
        ConstElementPtr forwardAddressesE(config->get("forward_addresses"));
598 599
        AddressList forwardAddresses(parseAddresses(forwardAddressesE,
                                                       "forward_addresses"));
Michal Vaner's avatar
Michal Vaner committed
600
        ConstElementPtr listenAddressesE(config->get("listen_on"));
601
        AddressList listenAddresses(parseAddresses(listenAddressesE,
602
                                                      "listen_on"));
603
        const ConstElementPtr query_acl_cfg(config->get("query_acl"));
604
        const boost::shared_ptr<const RequestACL> query_acl =
605
            query_acl_cfg ? acl::dns::getRequestLoader().load(query_acl_cfg) :
606
            boost::shared_ptr<RequestACL>();
Michal Vaner's avatar
Michal Vaner committed
607
        bool set_timeouts(false);
608 609 610
        int qtimeout = impl_->query_timeout_;
        int ctimeout = impl_->client_timeout_;
        int ltimeout = impl_->lookup_timeout_;
Michal Vaner's avatar
Michal Vaner committed
611
        unsigned retries = impl_->retries_;
612 613 614 615 616
        ConstElementPtr qtimeoutE(config->get("timeout_query")),
                        ctimeoutE(config->get("timeout_client")),
                        ltimeoutE(config->get("timeout_lookup")),
                        retriesE(config->get("retries"));
        if (qtimeoutE) {
Michal Vaner's avatar
Michal Vaner committed
617 618
            // It should be safe to just get it, the config manager should
            // check for us
619 620
            qtimeout = qtimeoutE->intValue();
            if (qtimeout < -1) {
621 622
                LOG_ERROR(resolver_logger, RESOLVER_QUERY_TIME_SMALL)
                          .arg(qtimeout);
623 624 625 626 627 628 629
                isc_throw(BadValue, "Query timeout too small");
            }
            set_timeouts = true;
        }
        if (ctimeoutE) {
            ctimeout = ctimeoutE->intValue();
            if (ctimeout < -1) {
630 631
                LOG_ERROR(resolver_logger, RESOLVER_CLIENT_TIME_SMALL)
                          .arg(ctimeout);
632 633 634 635 636 637 638
                isc_throw(BadValue, "Client timeout too small");
            }
            set_timeouts = true;
        }
        if (ltimeoutE) {
            ltimeout = ltimeoutE->intValue();
            if (ltimeout < -1) {
639 640
                LOG_ERROR(resolver_logger, RESOLVER_LOOKUP_TIME_SMALL)
                          .arg(ltimeout);
641
                isc_throw(BadValue, "Lookup timeout too small");
Michal Vaner's avatar
Michal Vaner committed
642 643 644 645
            }
            set_timeouts = true;
        }
        if (retriesE) {
646 647 648
            // Do the assignment from "retriesE->intValue()" to "retries"
            // _after_ the comparison (as opposed to before it for the timeouts)
            // because "retries" is unsigned.
Michal Vaner's avatar
Michal Vaner committed
649
            if (retriesE->intValue() < 0) {
650
                LOG_ERROR(resolver_logger, RESOLVER_NEGATIVE_RETRIES)
651
                          .arg(retriesE->intValue());
Michal Vaner's avatar
Michal Vaner committed
652 653 654 655 656
                isc_throw(BadValue, "Negative number of retries");
            }
            retries = retriesE->intValue();
            set_timeouts = true;
        }
657
        // Everything OK, so commit the changes
658
        // listenAddresses can fail to bind, so try them first
659 660
        bool need_query_restart = false;
        
661 662
        if (listenAddressesE) {
            setListenAddresses(listenAddresses);
663
            need_query_restart = true;
664 665 666
        }
        if (forwardAddressesE) {
            setForwardAddresses(forwardAddresses);
667
            need_query_restart = true;
668
        }
chenzhengzhang's avatar
chenzhengzhang committed
669 670
        if (rootAddressesE) {
            setRootAddresses(rootAddresses);
671
            need_query_restart = true;
672
        }
Michal Vaner's avatar
Michal Vaner committed
673
        if (set_timeouts) {
674
            setTimeouts(qtimeout, ctimeout, ltimeout, retries);
675 676
            need_query_restart = true;
        }
677 678 679
        if (query_acl) {
            setQueryACL(query_acl);
        }
680 681 682

        if (need_query_restart) {
            impl_->queryShutdown();
683
            impl_->querySetup(*dnss_, *nsas_, *cache_);
Michal Vaner's avatar
Michal Vaner committed
684
        }
685
        setConfigured();
686
        return (isc::config::createAnswer());
687

688
    } catch (const isc::Exception& error) {
689 690

        // Configuration error
691
        LOG_ERROR(resolver_logger, RESOLVER_CONFIG_ERROR).arg(error.what());
692 693 694
        return (isc::config::createAnswer(1, error.what()));
    }
}
695 696

void
697
Resolver::setForwardAddresses(const AddressList& addresses)
698
{
Michal Vaner's avatar
Michal Vaner committed
699
    impl_->setForwardAddresses(addresses, dnss_);
700 701
}

chenzhengzhang's avatar
chenzhengzhang committed
702
void
703
Resolver::setRootAddresses(const AddressList& addresses)
chenzhengzhang's avatar
chenzhengzhang committed
704 705 706 707
{
    impl_->setRootAddresses(addresses, dnss_);
}

708
bool
709
Resolver::isForwarding() const {
710 711 712
    return (!impl_->upstream_.empty());
}

713
AddressList
714
Resolver::getForwardAddresses() const {
715 716
    return (impl_->upstream_);
}
717

718
AddressList
chenzhengzhang's avatar
chenzhengzhang committed
719 720 721 722
Resolver::getRootAddresses() const {
    return (impl_->upstream_root_);
}

723
void
724
Resolver::setListenAddresses(const AddressList& addresses) {
725
    installListenAddresses(addresses, impl_->listen_, *dnss_);
726 727
}

Michal Vaner's avatar
Michal Vaner committed
728
void
729 730
Resolver::setTimeouts(int query_timeout, int client_timeout,
                      int lookup_timeout, unsigned retries) {
731
    LOG_DEBUG(resolver_logger, RESOLVER_DBG_CONFIG, RESOLVER_SET_PARAMS)
732 733 734
              .arg(query_timeout).arg(client_timeout).arg(lookup_timeout)
              .arg(retries);

735 736 737
    impl_->query_timeout_ = query_timeout;
    impl_->client_timeout_ = client_timeout;
    impl_->lookup_timeout_ = lookup_timeout;
Michal Vaner's avatar
Michal Vaner committed
738 739
    impl_->retries_ = retries;
}
740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758

int
Resolver::getQueryTimeout() const {
    return impl_->query_timeout_;
}

int
Resolver::getClientTimeout() const {
    return impl_->client_timeout_;
}

int
Resolver::getLookupTimeout() const {
    return impl_->lookup_timeout_;
}

int
Resolver::getRetries() const {
    return impl_->retries_;
Michal Vaner's avatar
Michal Vaner committed
759 760
}

761
AddressList
762
Resolver::getListenAddresses() const {
763 764
    return (impl_->listen_);
}
765

766
const RequestACL&
767
Resolver::getQueryACL() const {
768
    return (impl_->getQueryACL());
769 770 771
}

void
772
Resolver::setQueryACL(boost::shared_ptr<const RequestACL> new_acl) {
773 774 775 776
    if (!new_acl) {
        isc_throw(InvalidParameter, "NULL pointer is passed to setQueryACL");
    }

777
    LOG_INFO(resolver_logger, RESOLVER_SET_QUERY_ACL);
778
    impl_->setQueryACL(new_acl);
779
}