resolver.cc 21.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
// 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>

#include <netinet/in.h>

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

#include <asiolink/asiolink.h>

25
#include <boost/foreach.hpp>
26
#include <boost/lexical_cast.hpp>
27

28 29 30 31
#include <config/ccsession.h>

#include <exceptions/exceptions.h>

32 33
#include <util/buffer.h>

Michal Vaner's avatar
Michal Vaner committed
34 35
#include <dns/opcode.h>
#include <dns/rcode.h>
36 37 38 39 40 41
#include <dns/exceptions.h>
#include <dns/name.h>
#include <dns/question.h>
#include <dns/rrset.h>
#include <dns/rrttl.h>
#include <dns/message.h>
42
#include <dns/messagerenderer.h>
43
#include <server_common/portconfig.h>
44

45 46
#include <resolve/recursive_query.h>

47 48
#include <log/dummylog.h>

49
#include <resolver/resolver.h>
50 51 52 53

using namespace std;

using namespace isc;
54
using namespace isc::util;
55 56 57
using namespace isc::dns;
using namespace isc::data;
using namespace isc::config;
58
using isc::log::dlog;
59
using namespace asiolink;
60
using namespace isc::server_common::portconfig;
61

62
class ResolverImpl {
63 64
private:
    // prohibit copy
65 66
    ResolverImpl(const ResolverImpl& source);
    ResolverImpl& operator=(const ResolverImpl& source);
67
public:
68
    ResolverImpl() :
69
        config_session_(NULL),
70 71 72
        query_timeout_(2000),
        client_timeout_(4000),
        lookup_timeout_(30000),
73
        retries_(3),
Michal Vaner's avatar
Michal Vaner committed
74
        rec_query_(NULL)
75 76
    {}

77
    ~ResolverImpl() {
78 79 80
        queryShutdown();
    }

81 82 83 84
    void querySetup(DNSService& dnss,
                    isc::nsas::NameserverAddressStore& nsas,
                    isc::cache::ResolverCache& cache)
    {
Michal Vaner's avatar
Michal Vaner committed
85
        assert(!rec_query_); // queryShutdown must be called first
86
        dlog("Query setup");
87 88 89
        rec_query_ = new RecursiveQuery(dnss, 
                                        nsas, cache,
                                        upstream_,
90
                                        upstream_root_,
Jelte Jansen's avatar
Jelte Jansen committed
91 92 93 94
                                        query_timeout_,
                                        client_timeout_,
                                        lookup_timeout_,
                                        retries_);
95 96 97
    }

    void queryShutdown() {
98 99 100 101 102 103 104 105
        // 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_) {
            dlog("Query shutdown");
            delete rec_query_;
            rec_query_ = NULL;
        }
106 107
    }

108
    void setForwardAddresses(const AddressList& upstream,
Michal Vaner's avatar
Michal Vaner committed
109
        DNSService *dnss)
110 111
    {
        upstream_ = upstream;
Michal Vaner's avatar
Michal Vaner committed
112
        if (dnss) {
Jelte Jansen's avatar
Jelte Jansen committed
113
            if (!upstream_.empty()) {
114
                dlog("Setting forward addresses:");
115
                BOOST_FOREACH(const AddressPair& address, upstream) {
116 117 118
                    dlog(" " + address.first + ":" +
                        boost::lexical_cast<string>(address.second));
                }
Jelte Jansen's avatar
Jelte Jansen committed
119 120
            } else {
                dlog("No forward addresses, running in recursive mode");
121
            }
122 123 124
        }
    }

125
    void setRootAddresses(const AddressList& upstream_root,
chenzhengzhang's avatar
chenzhengzhang committed
126 127 128 129 130 131
                          DNSService *dnss)
    {
        upstream_root_ = upstream_root;
        if (dnss) {
            if (!upstream_root_.empty()) {
                dlog("Setting root addresses:");
132
                BOOST_FOREACH(const AddressPair& address, upstream_root) {
chenzhengzhang's avatar
chenzhengzhang committed
133 134 135 136 137 138 139 140
                    dlog(" " + address.first + ":" +
                        boost::lexical_cast<string>(address.second));
                }
            } else {
                dlog("No root addresses");
            }
        }
    }
141
    
142
    void resolve(const isc::dns::QuestionPtr& question,
143
        const isc::resolve::ResolverInterface::CallbackPtr& callback);
144

145 146
    void processNormalQuery(const Question& question,
                            MessagePtr answer_message,
147
                            OutputBufferPtr buffer,
148
                            DNSServer* server);
149

Evan Hunt's avatar
Evan Hunt committed
150 151
    /// Currently non-configurable, but will be.
    static const uint16_t DEFAULT_LOCAL_UDPSIZE = 4096;
152

153
    /// These members are public because Resolver accesses them directly.
Evan Hunt's avatar
Evan Hunt committed
154
    ModuleCCSession* config_session_;
chenzhengzhang's avatar
chenzhengzhang committed
155
    /// Addresses of the root nameserver(s)
156
    AddressList upstream_root_;
157
    /// Addresses of the forward nameserver
158
    AddressList upstream_;
Michal Vaner's avatar
Michal Vaner committed
159
    /// Addresses we listen on
160
    AddressList listen_;
161

162 163 164 165 166 167 168
    /// 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
169 170 171
    /// Number of retries after timeout
    unsigned retries_;

Evan Hunt's avatar
Evan Hunt committed
172
private:
173

174
    /// Object to handle upstream queries
175
    RecursiveQuery* rec_query_;
176 177
};

178 179 180 181 182
/*
 * 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.
 */
183 184 185 186
class QuestionInserter {
public:
    QuestionInserter(MessagePtr message) : message_(message) {}
    void operator()(const QuestionPtr question) {
187 188
        dlog(string("Adding question ") + question->getName().toText() +
            " to message");
189 190 191 192 193
        message_->addQuestion(question);
    }
    MessagePtr message_;
};

194 195

// TODO: REMOVE, USE isc::resolve::MakeErrorMessage?
196
void
197 198
makeErrorMessage(MessagePtr message, MessagePtr answer_message,
                 OutputBufferPtr buffer, const Rcode& rcode)
199 200 201 202 203
{
    // 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
204 205
    const bool rd = message->getHeaderFlag(Message::HEADERFLAG_RD);
    const bool cd = message->getHeaderFlag(Message::HEADERFLAG_CD);
206 207 208
    const Opcode& opcode = message->getOpcode();
    vector<QuestionPtr> questions;

209 210 211 212 213 214
    // answer_message is actually ignored right now,
    // see the comment in #607
    answer_message->setRcode(rcode);
    answer_message->setOpcode(opcode);
    answer_message->setQid(qid);

215 216 217 218 219 220 221 222 223
    // 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
224
    message->setHeaderFlag(Message::HEADERFLAG_QR);
225
    if (rd) {
Michal Vaner's avatar
Michal Vaner committed
226
        message->setHeaderFlag(Message::HEADERFLAG_RD);
227 228
    }
    if (cd) {
Michal Vaner's avatar
Michal Vaner committed
229
        message->setHeaderFlag(Message::HEADERFLAG_CD);
230 231 232 233 234 235
    }
    for_each(questions.begin(), questions.end(), QuestionInserter(message));
    message->setRcode(rcode);
    MessageRenderer renderer(*buffer);
    message->toWire(renderer);

236 237 238
    dlog(string("Sending an error response (") +
        boost::lexical_cast<string>(renderer.getLength()) + " bytes):\n" +
        message->toText());
239
}
240

241
// This is a derived class of \c DNSLookup, to serve as a
242
// callback in the asiolink module.  It calls
243
// Resolver::processMessage() on a single DNS message.
244
class MessageLookup : public DNSLookup {
245
public:
246
    MessageLookup(Resolver* srv) : server_(srv) {}
247 248

    // \brief Handle the DNS Lookup
249
    virtual void operator()(const IOMessage& io_message,
250
                            MessagePtr query_message,
251 252 253
                            MessagePtr answer_message,
                            OutputBufferPtr buffer,
                            DNSServer* server) const
254
    {
255 256
        server_->processMessage(io_message, query_message,
                                answer_message, buffer, server);
257 258
    }
private:
259
    Resolver* server_;
260 261 262 263 264 265 266 267 268
};

// 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,
269
                            MessagePtr query_message,
270
                            MessagePtr answer_message,
271
                            OutputBufferPtr buffer) const
272
    {
273 274 275
        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);
276 277 278
        
        // The opcode and question section should have already been set,
        // fill in the final details of the answer message
279
        answer_message->setQid(qid);
280

281 282
        answer_message->setHeaderFlag(Message::HEADERFLAG_QR);
        answer_message->setHeaderFlag(Message::HEADERFLAG_RA);
283 284
        answer_message->setHeaderFlag(Message::HEADERFLAG_RD, rd);
        answer_message->setHeaderFlag(Message::HEADERFLAG_CD, cd);
285 286 287 288 289

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

290 291 292 293 294 295 296 297 298 299 300
        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);
        }
        
301
        if (io_message.getSocket().getProtocol() == IPPROTO_UDP) {
302 303 304 305 306
            if (edns) {
                renderer.setLengthLimit(edns->getUDPSize());
            } else {
                renderer.setLengthLimit(Message::DEFAULT_MAX_UDPSIZE);
            }
307 308 309
        } else {
            renderer.setLengthLimit(65535);
        }
310

311
        answer_message->toWire(renderer);
312

313 314
        dlog(string("sending a response (") +
            boost::lexical_cast<string>(renderer.getLength()) + "bytes): \n" +
315
            answer_message->toText());
316 317 318
    }
};

319
// This is a derived class of \c SimpleCallback, to serve
320 321
// as a callback in the asiolink module.  It checks for queued
// configuration messages, and executes them if found.
322
class ConfigCheck : public SimpleCallback {
323
public:
324
    ConfigCheck(Resolver* srv) : server_(srv) {}
Michal Vaner's avatar
Michal Vaner committed
325
    virtual void operator()(const IOMessage&) const {
326 327
        if (server_->getConfigSession()->hasQueuedMsgs()) {
            server_->getConfigSession()->checkCommand();
328 329 330
        }
    }
private:
331
    Resolver* server_;
332 333
};

334 335
Resolver::Resolver() :
    impl_(new ResolverImpl()),
336
    checkin_(new ConfigCheck(this)),
337
    dns_lookup_(new MessageLookup(this)),
338 339
    dns_answer_(new MessageAnswer),
    configured_(false)
340 341
{}

342
Resolver::~Resolver() {
343
    delete impl_;
344 345 346
    delete checkin_;
    delete dns_lookup_;
    delete dns_answer_;
347 348 349
}

void
350
Resolver::setDNSService(asiolink::DNSService& dnss) {
351
    dnss_ = &dnss;
352 353
}

354 355 356 357 358 359 360 361 362 363 364 365 366
void
Resolver::setNameserverAddressStore(isc::nsas::NameserverAddressStore& nsas)
{
    nsas_ = &nsas;
}

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


367
void
368
Resolver::setConfigSession(ModuleCCSession* config_session) {
369 370 371 372
    impl_->config_session_ = config_session;
}

ModuleCCSession*
373
Resolver::getConfigSession() const {
374 375 376
    return (impl_->config_session_);
}

377 378
void
Resolver::resolve(const isc::dns::QuestionPtr& question,
379
    const isc::resolve::ResolverInterface::CallbackPtr& callback)
380 381 382 383 384
{
    impl_->resolve(question, callback);
}


385
void
386
Resolver::processMessage(const IOMessage& io_message,
387
                         MessagePtr query_message,
388 389 390
                         MessagePtr answer_message,
                         OutputBufferPtr buffer,
                         DNSServer* server)
391
{
392
    dlog("Got a DNS message");
393 394 395 396
    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.
    try {
397
        query_message->parseHeader(request_buffer);
398 399

        // Ignore all responses.
400
        if (query_message->getHeaderFlag(Message::HEADERFLAG_QR)) {
401
            dlog("Received unexpected response, ignoring");
402
            server->resume(false);
403
            return;
404 405
        }
    } catch (const Exception& ex) {
Scott Mann's avatar
Scott Mann committed
406
        dlog(string("DNS packet exception: ") + ex.what(),true);
407
        server->resume(false);
408
        return;
409 410 411 412
    }

    // Parse the message.  On failure, return an appropriate error.
    try {
413
        query_message->fromWire(request_buffer);
414
    } catch (const DNSProtocolError& error) {
415 416
        dlog(string("returning ") + error.getRcode().toText() + ": " + 
            error.what());
417 418
        makeErrorMessage(query_message, answer_message,
                         buffer, error.getRcode());
419
        server->resume(true);
420
        return;
421
    } catch (const Exception& ex) {
422
        dlog(string("returning SERVFAIL: ") + ex.what());
423 424
        makeErrorMessage(query_message, answer_message,
                         buffer, Rcode::SERVFAIL());
425
        server->resume(true);
426
        return;
427 428
    } // other exceptions will be handled at a higher layer.

429
    dlog("received a message:\n" + query_message->toText());
430 431

    // Perform further protocol-level validation.
432
    bool sendAnswer = true;
433
    if (query_message->getOpcode() == Opcode::NOTIFY()) {
434 435
        makeErrorMessage(query_message, answer_message,
                         buffer, Rcode::NOTAUTH());
Michal Vaner's avatar
Michal Vaner committed
436
        dlog("Notify arrived, but we are not authoritative");
437 438
    } else if (query_message->getOpcode() != Opcode::QUERY()) {
        dlog("Unsupported opcode (got: " + query_message->getOpcode().toText() +
Michal Vaner's avatar
Michal Vaner committed
439
            ", expected: " + Opcode::QUERY().toText());
440 441
        makeErrorMessage(query_message, answer_message,
                         buffer, Rcode::NOTIMP());
442
    } else if (query_message->getRRCount(Message::SECTION_QUESTION) != 1) {
Michal Vaner's avatar
Michal Vaner committed
443
        dlog("The query contained " +
444
            boost::lexical_cast<string>(query_message->getRRCount(
Michal Vaner's avatar
Michal Vaner committed
445
            Message::SECTION_QUESTION) + " questions, exactly one expected"));
446 447
        makeErrorMessage(query_message, answer_message,
                         buffer, Rcode::FORMERR());
448
    } else {
449
        ConstQuestionPtr question = *query_message->beginQuestion();
450 451 452
        const RRType &qtype = question->getType();
        if (qtype == RRType::AXFR()) {
            if (io_message.getSocket().getProtocol() == IPPROTO_UDP) {
453 454
                makeErrorMessage(query_message, answer_message,
                                 buffer, Rcode::FORMERR());
455
            } else {
456 457
                makeErrorMessage(query_message, answer_message,
                                 buffer, Rcode::NOTIMP());
458 459
            }
        } else if (qtype == RRType::IXFR()) {
460 461
            makeErrorMessage(query_message, answer_message,
                             buffer, Rcode::NOTIMP());
462 463 464
        } else if (question->getClass() != RRClass::IN()) {
            makeErrorMessage(query_message, answer_message,
                             buffer, Rcode::REFUSED());
465
        } else {
466 467
            // The RecursiveQuery object will post the "resume" event to the
            // DNSServer when an answer arrives, so we don't have to do it now.
468
            sendAnswer = false;
469 470
            impl_->processNormalQuery(*question, answer_message,
                                      buffer, server);
471 472
        }
    }
473

474 475 476
    if (sendAnswer) {
        server->resume(true);
    }
477 478
}

479 480
void
ResolverImpl::resolve(const QuestionPtr& question,
481
    const isc::resolve::ResolverInterface::CallbackPtr& callback)
482
{
483
    rec_query_->resolve(question, callback);
484 485
}

486
void
487 488 489 490
ResolverImpl::processNormalQuery(const Question& question,
                                 MessagePtr answer_message,
                                 OutputBufferPtr buffer,
                                 DNSServer* server)
491
{
492
    dlog("Processing normal query");
493
    rec_query_->resolve(question, answer_message, buffer, server);
494 495 496
}

ConstElementPtr
497
Resolver::updateConfig(ConstElementPtr config) {
Michal Vaner's avatar
Michal Vaner committed
498 499
    dlog("New config comes: " + config->toWire());

500
    try {
501
        // Parse forward_addresses
chenzhengzhang's avatar
chenzhengzhang committed
502
        ConstElementPtr rootAddressesE(config->get("root_addresses"));
503
        AddressList rootAddresses(parseAddresses(rootAddressesE,
504
                                                    "root_addresses"));
Michal Vaner's avatar
Michal Vaner committed
505
        ConstElementPtr forwardAddressesE(config->get("forward_addresses"));
506 507
        AddressList forwardAddresses(parseAddresses(forwardAddressesE,
                                                       "forward_addresses"));
Michal Vaner's avatar
Michal Vaner committed
508
        ConstElementPtr listenAddressesE(config->get("listen_on"));
509
        AddressList listenAddresses(parseAddresses(listenAddressesE,
510
                                                      "listen_on"));
Michal Vaner's avatar
Michal Vaner committed
511
        bool set_timeouts(false);
512 513 514
        int qtimeout = impl_->query_timeout_;
        int ctimeout = impl_->client_timeout_;
        int ltimeout = impl_->lookup_timeout_;
Michal Vaner's avatar
Michal Vaner committed
515
        unsigned retries = impl_->retries_;
516 517 518 519 520
        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
521 522
            // It should be safe to just get it, the config manager should
            // check for us
523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539
            qtimeout = qtimeoutE->intValue();
            if (qtimeout < -1) {
                isc_throw(BadValue, "Query timeout too small");
            }
            set_timeouts = true;
        }
        if (ctimeoutE) {
            ctimeout = ctimeoutE->intValue();
            if (ctimeout < -1) {
                isc_throw(BadValue, "Client timeout too small");
            }
            set_timeouts = true;
        }
        if (ltimeoutE) {
            ltimeout = ltimeoutE->intValue();
            if (ltimeout < -1) {
                isc_throw(BadValue, "Lookup timeout too small");
Michal Vaner's avatar
Michal Vaner committed
540 541 542 543 544 545 546 547 548 549
            }
            set_timeouts = true;
        }
        if (retriesE) {
            if (retriesE->intValue() < 0) {
                isc_throw(BadValue, "Negative number of retries");
            }
            retries = retriesE->intValue();
            set_timeouts = true;
        }
550
        // Everything OK, so commit the changes
551
        // listenAddresses can fail to bind, so try them first
552 553
        bool need_query_restart = false;
        
554 555
        if (listenAddressesE) {
            setListenAddresses(listenAddresses);
556
            need_query_restart = true;
557 558 559 560 561 562 563 564 565
        } else {
            if (!configured_) {
                // TODO: ModuleSpec needs getDefault()
                AddressList initial_addresses;
                initial_addresses.push_back(AddressPair("127.0.0.1", 53));
                initial_addresses.push_back(AddressPair("::1", 53));
                setListenAddresses(initial_addresses);
                need_query_restart = true;
            }
566 567 568
        }
        if (forwardAddressesE) {
            setForwardAddresses(forwardAddresses);
569
            need_query_restart = true;
570
        }
chenzhengzhang's avatar
chenzhengzhang committed
571 572
        if (rootAddressesE) {
            setRootAddresses(rootAddresses);
573
            need_query_restart = true;
574
        }
Michal Vaner's avatar
Michal Vaner committed
575
        if (set_timeouts) {
576
            setTimeouts(qtimeout, ctimeout, ltimeout, retries);
577 578 579 580 581
            need_query_restart = true;
        }

        if (need_query_restart) {
            impl_->queryShutdown();
582
            impl_->querySetup(*dnss_, *nsas_, *cache_);
Michal Vaner's avatar
Michal Vaner committed
583
        }
584
        setConfigured();
585 586
        return (isc::config::createAnswer());
    } catch (const isc::Exception& error) {
Scott Mann's avatar
Scott Mann committed
587
        dlog(string("error in config: ") + error.what(),true);
588 589 590
        return (isc::config::createAnswer(1, error.what()));
    }
}
591 592

void
593
Resolver::setForwardAddresses(const AddressList& addresses)
594
{
Michal Vaner's avatar
Michal Vaner committed
595
    impl_->setForwardAddresses(addresses, dnss_);
596 597
}

chenzhengzhang's avatar
chenzhengzhang committed
598
void
599
Resolver::setRootAddresses(const AddressList& addresses)
chenzhengzhang's avatar
chenzhengzhang committed
600 601 602 603
{
    impl_->setRootAddresses(addresses, dnss_);
}

604
bool
605
Resolver::isForwarding() const {
606 607 608
    return (!impl_->upstream_.empty());
}

609
AddressList
610
Resolver::getForwardAddresses() const {
611 612
    return (impl_->upstream_);
}
613

614
AddressList
chenzhengzhang's avatar
chenzhengzhang committed
615 616 617 618
Resolver::getRootAddresses() const {
    return (impl_->upstream_root_);
}

619
void
620
Resolver::setListenAddresses(const AddressList& addresses) {
621
    installListenAddresses(addresses, impl_->listen_, *dnss_);
622 623
}

Michal Vaner's avatar
Michal Vaner committed
624
void
625 626 627 628 629 630 631 632 633
Resolver::setTimeouts(int query_timeout, int client_timeout,
                      int lookup_timeout, unsigned retries) {
    dlog("Setting query timeout to " + boost::lexical_cast<string>(query_timeout) +
         ", client timeout to " + boost::lexical_cast<string>(client_timeout) +
         ", lookup timeout to " + boost::lexical_cast<string>(lookup_timeout) +
         " and retry count to " + boost::lexical_cast<string>(retries));
    impl_->query_timeout_ = query_timeout;
    impl_->client_timeout_ = client_timeout;
    impl_->lookup_timeout_ = lookup_timeout;
Michal Vaner's avatar
Michal Vaner committed
634 635
    impl_->retries_ = retries;
}
636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654

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
655 656
}

657
AddressList
658
Resolver::getListenAddresses() const {
659 660
    return (impl_->listen_);
}