LCOV - code coverage report
Current view: top level - home/jelte/repos/coverage_bind10/src/bin/resolver - resolver.cc (source / functions) Hit Total Coverage
Test: report.info Lines: 252 320 78.8 %
Date: 2012-05-15 Functions: 29 42 69.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 329 669 49.2 %

           Branch data     Line data    Source code
       1                 :            : // Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
       2                 :            : //
       3                 :            : // Permission to use, copy, modify, and/or distribute this software for any
       4                 :            : // purpose with or without fee is hereby granted, provided that the above
       5                 :            : // copyright notice and this permission notice appear in all copies.
       6                 :            : //
       7                 :            : // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
       8                 :            : // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
       9                 :            : // AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
      10                 :            : // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
      11                 :            : // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
      12                 :            : // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
      13                 :            : // PERFORMANCE OF THIS SOFTWARE.
      14                 :            : 
      15                 :            : #include <config.h>
      16                 :            : 
      17                 :            : #include <stdint.h>
      18                 :            : #include <sys/types.h>
      19                 :            : #include <netinet/in.h>
      20                 :            : 
      21                 :            : #include <algorithm>
      22                 :            : #include <vector>
      23                 :            : #include <cassert>
      24                 :            : 
      25                 :            : #include <boost/shared_ptr.hpp>
      26                 :            : #include <boost/foreach.hpp>
      27                 :            : 
      28                 :            : #include <exceptions/exceptions.h>
      29                 :            : 
      30                 :            : #include <acl/dns.h>
      31                 :            : #include <acl/loader.h>
      32                 :            : 
      33                 :            : #include <asiodns/asiodns.h>
      34                 :            : #include <asiolink/asiolink.h>
      35                 :            : 
      36                 :            : #include <config/ccsession.h>
      37                 :            : 
      38                 :            : #include <exceptions/exceptions.h>
      39                 :            : 
      40                 :            : #include <util/buffer.h>
      41                 :            : 
      42                 :            : #include <dns/opcode.h>
      43                 :            : #include <dns/rcode.h>
      44                 :            : #include <dns/exceptions.h>
      45                 :            : #include <dns/name.h>
      46                 :            : #include <dns/question.h>
      47                 :            : #include <dns/rrset.h>
      48                 :            : #include <dns/rrttl.h>
      49                 :            : #include <dns/message.h>
      50                 :            : #include <dns/messagerenderer.h>
      51                 :            : 
      52                 :            : #include <server_common/client.h>
      53                 :            : #include <server_common/portconfig.h>
      54                 :            : 
      55                 :            : #include <resolve/recursive_query.h>
      56                 :            : 
      57                 :            : #include "resolver.h"
      58                 :            : #include "resolver_log.h"
      59                 :            : 
      60                 :            : using namespace std;
      61                 :            : using namespace isc;
      62                 :            : using namespace isc::util;
      63                 :            : using namespace isc::acl;
      64                 :            : using isc::acl::dns::RequestACL;
      65                 :            : using namespace isc::dns;
      66                 :            : using namespace isc::data;
      67                 :            : using namespace isc::config;
      68                 :            : using namespace isc::asiodns;
      69                 :            : using namespace isc::asiolink;
      70                 :            : using namespace isc::server_common;
      71                 :            : using namespace isc::server_common::portconfig;
      72                 :            : 
      73                 :            : class ResolverImpl {
      74                 :            : private:
      75                 :            :     // prohibit copy
      76                 :            :     ResolverImpl(const ResolverImpl& source);
      77                 :            :     ResolverImpl& operator=(const ResolverImpl& source);
      78                 :            : public:
      79                 :         33 :     ResolverImpl() :
      80                 :            :         config_session_(NULL),
      81                 :            :         query_timeout_(2000),
      82                 :            :         client_timeout_(4000),
      83                 :            :         lookup_timeout_(30000),
      84                 :            :         retries_(3),
      85                 :            :         // we apply "reject all" (implicit default of the loader) ACL by
      86                 :            :         // default:
      87         [ +  - ]:         66 :         query_acl_(acl::dns::getRequestLoader().load(Element::fromJSON("[]"))),
      88 [ +  - ][ +  - ]:         66 :         rec_query_(NULL)
                 [ +  - ]
      89                 :         33 :     {}
      90                 :            : 
      91                 :         33 :     ~ResolverImpl() {
      92         [ +  - ]:         33 :         queryShutdown();
      93                 :            :     }
      94                 :            : 
      95                 :            :     void querySetup(DNSServiceBase& dnss,
      96                 :            :                     isc::nsas::NameserverAddressStore& nsas,
      97                 :            :                     isc::cache::ResolverCache& cache)
      98                 :            :     {
      99         [ -  + ]:          7 :         assert(!rec_query_); // queryShutdown must be called first
     100 [ +  - ][ +  - ]:          7 :         LOG_DEBUG(resolver_logger, RESOLVER_DBG_INIT, RESOLVER_QUERY_SETUP);
         [ +  - ][ +  - ]
     101                 :            :         rec_query_ = new RecursiveQuery(dnss, 
     102                 :            :                                         nsas, cache,
     103                 :            :                                         upstream_,
     104                 :            :                                         upstream_root_,
     105                 :            :                                         query_timeout_,
     106                 :            :                                         client_timeout_,
     107                 :            :                                         lookup_timeout_,
     108 [ +  - ][ +  - ]:          7 :                                         retries_);
     109                 :            :     }
     110                 :            : 
     111                 :         40 :     void queryShutdown() {
     112                 :            :         // only shut down if we have actually called querySetup before
     113                 :            :         // (this is not a safety check, just to prevent logging of
     114                 :            :         // actions that are not performed
     115         [ +  + ]:         40 :         if (rec_query_) {
     116         [ +  - ]:         14 :             LOG_DEBUG(resolver_logger, RESOLVER_DBG_INIT,
     117                 :          7 :                       RESOLVER_QUERY_SHUTDOWN);
     118         [ +  - ]:         14 :             delete rec_query_;
     119                 :          7 :             rec_query_ = NULL;
     120                 :            :         }
     121                 :         40 :     }
     122                 :            : 
     123                 :          4 :     void setForwardAddresses(const AddressList& upstream,
     124                 :            :                              DNSServiceBase* dnss)
     125                 :            :     {
     126                 :          4 :         upstream_ = upstream;
     127         [ +  - ]:          4 :         if (dnss != NULL) {
     128         [ +  + ]:          4 :             if (!upstream_.empty()) {
     129 [ +  + ][ +  - ]:         11 :                 BOOST_FOREACH(const AddressPair& address, upstream) {
         [ +  - ][ +  + ]
                 [ +  + ]
     130         [ +  - ]:          9 :                     LOG_INFO(resolver_logger, RESOLVER_FORWARD_ADDRESS)
     131 [ +  - ][ +  - ]:          3 :                              .arg(address.first).arg(address.second);
     132                 :            :                 }
     133                 :            :             } else {
     134         [ +  - ]:          2 :                 LOG_INFO(resolver_logger, RESOLVER_RECURSIVE);
     135                 :            :             }
     136                 :            :         }
     137                 :          4 :     }
     138                 :            : 
     139                 :          3 :     void setRootAddresses(const AddressList& upstream_root,
     140                 :            :                           DNSServiceBase* dnss)
     141                 :            :     {
     142                 :          3 :         upstream_root_ = upstream_root;
     143         [ +  - ]:          3 :         if (dnss != NULL) {
     144         [ +  + ]:          3 :             if (!upstream_root_.empty()) {
     145 [ +  + ][ +  - ]:          8 :                 BOOST_FOREACH(const AddressPair& address, upstream_root) {
         [ +  - ][ +  + ]
                 [ +  + ]
     146         [ +  - ]:          6 :                     LOG_INFO(resolver_logger, RESOLVER_SET_ROOT_ADDRESS)
     147 [ +  - ][ +  - ]:          2 :                              .arg(address.first).arg(address.second);
     148                 :            :                 }
     149                 :            :             } else {
     150         [ +  - ]:          1 :                 LOG_WARN(resolver_logger, RESOLVER_NO_ROOT_ADDRESS);
     151                 :            :             }
     152                 :            :         }
     153                 :          3 :     }
     154                 :            :     
     155                 :            :     void resolve(const isc::dns::QuestionPtr& question,
     156                 :            :         const isc::resolve::ResolverInterface::CallbackPtr& callback);
     157                 :            : 
     158                 :            :     enum NormalQueryResult { RECURSION, DROPPED, ERROR };
     159                 :            :     NormalQueryResult processNormalQuery(const IOMessage& io_message,
     160                 :            :                                          MessagePtr query_message,
     161                 :            :                                          MessagePtr answer_message,
     162                 :            :                                          OutputBufferPtr buffer,
     163                 :            :                                          DNSServer* server);
     164                 :            : 
     165                 :            :     const RequestACL& getQueryACL() const {
     166                 :            :         return (*query_acl_);
     167                 :            :     }
     168                 :            : 
     169                 :            :     void setQueryACL(boost::shared_ptr<const RequestACL> new_acl) {
     170                 :         20 :         query_acl_ = new_acl;
     171                 :            :     }
     172                 :            : 
     173                 :            :     /// Currently non-configurable, but will be.
     174                 :            :     static const uint16_t DEFAULT_LOCAL_UDPSIZE = 4096;
     175                 :            : 
     176                 :            :     /// These members are public because Resolver accesses them directly.
     177                 :            :     ModuleCCSession* config_session_;
     178                 :            :     /// Addresses of the root nameserver(s)
     179                 :            :     AddressList upstream_root_;
     180                 :            :     /// Addresses of the forward nameserver
     181                 :            :     AddressList upstream_;
     182                 :            :     /// Addresses we listen on
     183                 :            :     AddressList listen_;
     184                 :            : 
     185                 :            :     /// Timeout for outgoing queries in milliseconds
     186                 :            :     int query_timeout_;
     187                 :            :     /// Timeout for incoming client queries in milliseconds
     188                 :            :     int client_timeout_;
     189                 :            :     /// Timeout for lookup processing in milliseconds
     190                 :            :     int lookup_timeout_;
     191                 :            :     
     192                 :            :     /// Number of retries after timeout
     193                 :            :     unsigned retries_;
     194                 :            : 
     195                 :            : private:
     196                 :            :     /// ACL on incoming queries
     197                 :            :     boost::shared_ptr<const RequestACL> query_acl_;
     198                 :            : 
     199                 :            :     /// Object to handle upstream queries
     200                 :            :     RecursiveQuery* rec_query_;
     201                 :            : };
     202                 :            : 
     203                 :            : /*
     204                 :            :  * std::for_each has a broken interface. It makes no sense in a language
     205                 :            :  * without lambda functions/closures. These two classes emulate the lambda
     206                 :            :  * functions so for_each can be used.
     207                 :            :  */
     208                 :         69 : class QuestionInserter {
     209                 :            : public:
     210                 :         23 :     QuestionInserter(MessagePtr message) : message_(message) {}
     211                 :            :     void operator()(const QuestionPtr question) {
     212         [ +  - ]:          8 :         message_->addQuestion(question);
     213                 :            :     }
     214                 :            :     MessagePtr message_;
     215                 :            : };
     216                 :            : 
     217                 :            : 
     218                 :            : // TODO: REMOVE, USE isc::resolve::MakeErrorMessage?
     219                 :            : void
     220                 :         23 : makeErrorMessage(MessagePtr message, MessagePtr answer_message,
     221                 :            :                  OutputBufferPtr buffer, const Rcode& rcode)
     222                 :            : {
     223                 :            :     // extract the parameters that should be kept.
     224                 :            :     // XXX: with the current implementation, it's not easy to set EDNS0
     225                 :            :     // depending on whether the query had it.  So we'll simply omit it.
     226                 :         23 :     const qid_t qid = message->getQid();
     227                 :         23 :     const bool rd = message->getHeaderFlag(Message::HEADERFLAG_RD);
     228                 :         23 :     const bool cd = message->getHeaderFlag(Message::HEADERFLAG_CD);
     229                 :         23 :     const Opcode& opcode = message->getOpcode();
     230                 :         23 :     vector<QuestionPtr> questions;
     231                 :            : 
     232                 :            :     // answer_message is actually ignored right now,
     233                 :            :     // see the comment in #607
     234         [ +  - ]:         23 :     answer_message->setRcode(rcode);
     235         [ +  - ]:         23 :     answer_message->setOpcode(opcode);
     236         [ +  - ]:         23 :     answer_message->setQid(qid);
     237                 :            : 
     238                 :            :     // If this is an error to a query or notify, we should also copy the
     239                 :            :     // question section.
     240 [ +  - ][ +  + ]:         23 :     if (opcode == Opcode::QUERY() || opcode == Opcode::NOTIFY()) {
         [ +  - ][ +  + ]
                 [ +  + ]
     241 [ +  - ][ +  - ]:          9 :         questions.assign(message->beginQuestion(), message->endQuestion());
         [ +  - ][ +  - ]
                 [ +  - ]
     242                 :            :     }
     243                 :            : 
     244         [ +  - ]:         23 :     message->clear(Message::RENDER);
     245         [ +  - ]:         23 :     message->setQid(qid);
     246         [ +  - ]:         23 :     message->setOpcode(opcode);
     247         [ +  - ]:         23 :     message->setHeaderFlag(Message::HEADERFLAG_QR);
     248         [ -  + ]:         23 :     if (rd) {
     249         [ #  # ]:          0 :         message->setHeaderFlag(Message::HEADERFLAG_RD);
     250                 :            :     }
     251         [ -  + ]:         23 :     if (cd) {
     252         [ #  # ]:          0 :         message->setHeaderFlag(Message::HEADERFLAG_CD);
     253                 :            :     }
     254         [ +  - ]:         23 :     for_each(questions.begin(), questions.end(), QuestionInserter(message));
     255         [ +  - ]:         23 :     message->setRcode(rcode);
     256 [ +  - ][ +  - ]:         46 :     MessageRenderer renderer;
     257         [ +  - ]:         23 :     renderer.setBuffer(buffer.get());
     258         [ +  - ]:         23 :     message->toWire(renderer);
     259                 :         23 : }
     260                 :            : 
     261                 :            : // This is a derived class of \c DNSLookup, to serve as a
     262                 :            : // callback in the asiolink module.  It calls
     263                 :            : // Resolver::processMessage() on a single DNS message.
     264                 :         33 : class MessageLookup : public DNSLookup {
     265                 :            : public:
     266                 :         66 :     MessageLookup(Resolver* srv) : server_(srv) {}
     267                 :            : 
     268                 :            :     // \brief Handle the DNS Lookup
     269                 :          0 :     virtual void operator()(const IOMessage& io_message,
     270                 :            :                             MessagePtr query_message,
     271                 :            :                             MessagePtr answer_message,
     272                 :            :                             OutputBufferPtr buffer,
     273                 :            :                             DNSServer* server) const
     274                 :            :     {
     275                 :            :         server_->processMessage(io_message, query_message,
     276         [ #  # ]:          0 :                                 answer_message, buffer, server);
     277                 :          0 :     }
     278                 :            : private:
     279                 :            :     Resolver* server_;
     280                 :            : };
     281                 :            : 
     282                 :            : // This is a derived class of \c DNSAnswer, to serve as a
     283                 :            : // callback in the asiolink module.  It takes a completed
     284                 :            : // set of answer data from the DNS lookup and assembles it
     285                 :            : // into a wire-format response.
     286                 :         33 : class MessageAnswer : public DNSAnswer {
     287                 :            : public:
     288                 :          0 :     virtual void operator()(const IOMessage& io_message,
     289                 :            :                             MessagePtr query_message,
     290                 :            :                             MessagePtr answer_message,
     291                 :            :                             OutputBufferPtr buffer) const
     292                 :            :     {
     293                 :          0 :         const qid_t qid = query_message->getQid();
     294                 :          0 :         const bool rd = query_message->getHeaderFlag(Message::HEADERFLAG_RD);
     295                 :          0 :         const bool cd = query_message->getHeaderFlag(Message::HEADERFLAG_CD);
     296                 :            :         
     297                 :            :         // The opcode and question section should have already been set,
     298                 :            :         // fill in the final details of the answer message
     299                 :          0 :         answer_message->setQid(qid);
     300                 :            : 
     301                 :          0 :         answer_message->setHeaderFlag(Message::HEADERFLAG_QR);
     302                 :          0 :         answer_message->setHeaderFlag(Message::HEADERFLAG_RA);
     303                 :          0 :         answer_message->setHeaderFlag(Message::HEADERFLAG_RD, rd);
     304                 :          0 :         answer_message->setHeaderFlag(Message::HEADERFLAG_CD, cd);
     305                 :            : 
     306                 :            :         // Now we can clear the buffer and render the new message into it
     307                 :            :         buffer->clear();
     308                 :          0 :         MessageRenderer renderer;
     309         [ #  # ]:          0 :         renderer.setBuffer(buffer.get());
     310                 :            : 
     311         [ #  # ]:          0 :         ConstEDNSPtr edns(query_message->getEDNS());
     312 [ #  # ][ #  # ]:          0 :         const bool dnssec_ok = edns && edns->getDNSSECAwareness();
     313         [ #  # ]:          0 :         if (edns) {
     314 [ #  # ][ #  # ]:          0 :             EDNSPtr edns_response(new EDNS());
     315                 :          0 :             edns_response->setDNSSECAwareness(dnssec_ok);
     316                 :            : 
     317                 :            :             // TODO: We should make our own edns bufsize length configurable
     318                 :          0 :             edns_response->setUDPSize(Message::DEFAULT_MAX_EDNS0_UDPSIZE);
     319         [ #  # ]:          0 :             answer_message->setEDNS(edns_response);
     320                 :            :         }
     321                 :            : 
     322 [ #  # ][ #  # ]:          0 :         if (io_message.getSocket().getProtocol() == IPPROTO_UDP) {
     323         [ #  # ]:          0 :             if (edns) {
     324         [ #  # ]:          0 :                 renderer.setLengthLimit(edns->getUDPSize());
     325                 :            :             } else {
     326         [ #  # ]:          0 :                 renderer.setLengthLimit(Message::DEFAULT_MAX_UDPSIZE);
     327                 :            :             }
     328                 :            :         } else {
     329         [ #  # ]:          0 :             renderer.setLengthLimit(65535);
     330                 :            :         }
     331                 :            : 
     332         [ #  # ]:          0 :         answer_message->toWire(renderer);
     333         [ #  # ]:          0 :         renderer.setBuffer(NULL);
     334                 :            : 
     335 [ #  # ][ #  # ]:          0 :         LOG_DEBUG(resolver_logger, RESOLVER_DBG_DETAIL,
                 [ #  # ]
     336                 :            :                   RESOLVER_DNS_MESSAGE_SENT)
     337 [ #  # ][ #  # ]:          0 :                   .arg(renderer.getLength()).arg(*answer_message);
                 [ #  # ]
     338                 :          0 :     }
     339                 :            : };
     340                 :            : 
     341                 :            : // This is a derived class of \c SimpleCallback, to serve
     342                 :            : // as a callback in the asiolink module.  It checks for queued
     343                 :            : // configuration messages, and executes them if found.
     344                 :         33 : class ConfigCheck : public SimpleCallback {
     345                 :            : public:
     346                 :         66 :     ConfigCheck(Resolver* srv) : server_(srv) {}
     347                 :          0 :     virtual void operator()(const IOMessage&) const {
     348         [ #  # ]:          0 :         if (server_->getConfigSession()->hasQueuedMsgs()) {
     349                 :          0 :             server_->getConfigSession()->checkCommand();
     350                 :            :         }
     351                 :          0 :     }
     352                 :            : private:
     353                 :            :     Resolver* server_;
     354                 :            : };
     355                 :            : 
     356                 :         33 : Resolver::Resolver() :
     357                 :          0 :     impl_(new ResolverImpl()),
     358                 :            :     dnss_(NULL),
     359                 :            :     checkin_(NULL),
     360                 :            :     dns_lookup_(NULL),
     361                 :            :     dns_answer_(new MessageAnswer),
     362                 :            :     nsas_(NULL),
     363 [ +  - ][ +  - ]:         33 :     cache_(NULL)
                 [ +  - ]
     364                 :            : {
     365                 :            :     // Operations referring to "this" must be done in the constructor body
     366                 :            :     // (some compilers will issue warnings if "this" is referred to in the
     367                 :            :     // initialization list).
     368         [ +  - ]:         33 :     checkin_ = new ConfigCheck(this);
     369         [ +  - ]:         33 :     dns_lookup_ = new MessageLookup(this);
     370                 :         33 : }
     371                 :            : 
     372                 :         33 : Resolver::~Resolver() {
     373         [ +  - ]:         66 :     delete impl_;
     374 [ +  - ][ +  - ]:         33 :     delete checkin_;
     375 [ +  - ][ +  - ]:         33 :     delete dns_lookup_;
     376 [ +  - ][ +  - ]:         33 :     delete dns_answer_;
     377                 :         33 : }
     378                 :            : 
     379                 :            : void
     380                 :         20 : Resolver::setDNSService(isc::asiodns::DNSServiceBase& dnss) {
     381                 :         20 :     dnss_ = &dnss;
     382                 :         20 : }
     383                 :            : 
     384                 :            : void
     385                 :          0 : Resolver::setNameserverAddressStore(isc::nsas::NameserverAddressStore& nsas)
     386                 :            : {
     387                 :          0 :     nsas_ = &nsas;
     388                 :          0 : }
     389                 :            : 
     390                 :            : void
     391                 :          0 : Resolver::setCache(isc::cache::ResolverCache& cache)
     392                 :            : {
     393                 :          0 :     cache_ = &cache;
     394                 :          0 : }
     395                 :            : 
     396                 :            : 
     397                 :            : void
     398                 :          0 : Resolver::setConfigSession(ModuleCCSession* config_session) {
     399                 :          0 :     impl_->config_session_ = config_session;
     400                 :          0 : }
     401                 :            : 
     402                 :            : ModuleCCSession*
     403                 :          0 : Resolver::getConfigSession() const {
     404                 :          0 :     return (impl_->config_session_);
     405                 :            : }
     406                 :            : 
     407                 :            : void
     408                 :          0 : Resolver::resolve(const isc::dns::QuestionPtr& question,
     409                 :            :     const isc::resolve::ResolverInterface::CallbackPtr& callback)
     410                 :            : {
     411                 :          0 :     impl_->resolve(question, callback);
     412                 :          0 : }
     413                 :            : 
     414                 :            : 
     415                 :            : void
     416                 :         28 : Resolver::processMessage(const IOMessage& io_message,
     417                 :            :                          MessagePtr query_message,
     418                 :            :                          MessagePtr answer_message,
     419                 :            :                          OutputBufferPtr buffer,
     420                 :            :                          DNSServer* server)
     421                 :            : {
     422                 :         28 :     InputBuffer request_buffer(io_message.getData(), io_message.getDataSize());
     423                 :            :     // First, check the header part.  If we fail even for the base header,
     424                 :            :     // just drop the message.
     425                 :            : 
     426                 :            :     // In the following code, the debug output is such that there should only be
     427                 :            :     // one debug message if packet processing failed.  There could be two if
     428                 :            :     // it succeeded.
     429                 :            :     try {
     430         [ +  + ]:         28 :         query_message->parseHeader(request_buffer);
     431                 :            : 
     432                 :            :         // Ignore all responses.
     433 [ +  - ][ +  + ]:         27 :         if (query_message->getHeaderFlag(Message::HEADERFLAG_QR)) {
     434 [ +  - ][ +  - ]:          3 :             LOG_DEBUG(resolver_logger, RESOLVER_DBG_IO, RESOLVER_UNEXPECTED_RESPONSE);
         [ +  - ][ +  - ]
     435         [ +  - ]:          3 :             server->resume(false);
     436                 :            :             return;
     437                 :            :         }
     438         [ -  + ]:          2 :     } catch (const Exception& ex) {
     439 [ -  + ][ +  - ]:          2 :         LOG_DEBUG(resolver_logger, RESOLVER_DBG_IO, RESOLVER_HEADER_ERROR)
                 [ -  + ]
     440 [ -  + ][ -  + ]:          1 :                   .arg(ex.what());
     441         [ -  + ]:          1 :         server->resume(false);
     442                 :            :         return;
     443                 :            :     }
     444                 :            : 
     445                 :            :     // Parse the message.  On failure, return an appropriate error.
     446                 :            :     try {
     447         [ +  + ]:         24 :         query_message->fromWire(request_buffer);
     448                 :          6 :     } catch (const DNSProtocolError& error) {
     449 [ -  + ][ +  - ]:          6 :         LOG_DEBUG(resolver_logger, RESOLVER_DBG_IO, RESOLVER_PROTOCOL_ERROR)
                 [ -  + ]
     450 [ -  + ][ -  + ]:          3 :                   .arg(error.what()).arg(error.getRcode());
         [ -  + ][ -  + ]
     451                 :            :         makeErrorMessage(query_message, answer_message,
     452 [ -  + ][ -  + ]:          6 :                          buffer, error.getRcode());
     453         [ -  + ]:          3 :         server->resume(true);
     454                 :            :         return;
     455      [ -  +  - ]:          3 :     } catch (const Exception& ex) {
     456 [ #  # ][ #  # ]:          0 :         LOG_DEBUG(resolver_logger, RESOLVER_DBG_IO, RESOLVER_MESSAGE_ERROR)
                 [ #  # ]
     457 [ #  # ][ #  # ]:          0 :                   .arg(ex.what()).arg(Rcode::SERVFAIL());
         [ #  # ][ #  # ]
     458                 :            :         makeErrorMessage(query_message, answer_message,
     459 [ #  # ][ #  # ]:          0 :                          buffer, Rcode::SERVFAIL());
     460         [ #  # ]:          0 :         server->resume(true);
     461                 :            :         return;
     462                 :            :     } // Other exceptions will be handled at a higher layer.
     463                 :            : 
     464                 :            :     // Note:  there appears to be no LOG_DEBUG for a successfully-received
     465                 :            :     // message.  This is not an oversight - it is handled below.  In the
     466                 :            :     // meantime, output the full message for debug purposes (if requested).
     467         [ +  - ]:         42 :     LOG_DEBUG(resolver_logger, RESOLVER_DBG_DETAIL,
     468         [ +  - ]:         21 :               RESOLVER_DNS_MESSAGE_RECEIVED).arg(*query_message);
     469                 :            : 
     470                 :            :     // Perform further protocol-level validation.
     471                 :         21 :     bool send_answer = true;
     472         [ +  + ]:         21 :     if (query_message->getOpcode() == Opcode::NOTIFY()) {
     473                 :            : 
     474                 :            :         makeErrorMessage(query_message, answer_message,
     475         [ +  - ]:          1 :                          buffer, Rcode::NOTAUTH());
     476                 :            :         // Notify arrived, but we are not authoritative.
     477         [ +  - ]:          2 :         LOG_DEBUG(resolver_logger, RESOLVER_DBG_PROCESS,
     478                 :          1 :                   RESOLVER_NOTIFY_RECEIVED);
     479         [ +  + ]:         20 :     } else if (query_message->getOpcode() != Opcode::QUERY()) {
     480                 :            :         // Unsupported opcode.
     481         [ +  - ]:         28 :         LOG_DEBUG(resolver_logger, RESOLVER_DBG_PROCESS,
     482         [ +  - ]:         14 :                   RESOLVER_UNSUPPORTED_OPCODE).arg(query_message->getOpcode());
     483                 :            :         makeErrorMessage(query_message, answer_message,
     484         [ +  - ]:         28 :                          buffer, Rcode::NOTIMP());
     485         [ +  + ]:          6 :     } else if (query_message->getRRCount(Message::SECTION_QUESTION) != 1) {
     486                 :            :         // Not one question
     487         [ +  - ]:          2 :         LOG_DEBUG(resolver_logger, RESOLVER_DBG_PROCESS,
     488                 :            :                   RESOLVER_NOT_ONE_QUESTION)
     489         [ +  - ]:          1 :                   .arg(query_message->getRRCount(Message::SECTION_QUESTION));
     490                 :            :         makeErrorMessage(query_message, answer_message, buffer,
     491         [ +  - ]:          2 :                          Rcode::FORMERR());
     492                 :            :     } else {
     493                 :            :         const ResolverImpl::NormalQueryResult result =
     494                 :            :             impl_->processNormalQuery(io_message, query_message,
     495         [ +  - ]:          5 :                                       answer_message, buffer, server);
     496         [ +  - ]:          5 :         if (result == ResolverImpl::RECURSION) {
     497                 :            :             // The RecursiveQuery object will post the "resume" event to the
     498                 :            :             // DNSServer when an answer arrives, so we don't have to do it now.
     499                 :            :             return;
     500         [ +  + ]:          5 :         } else if (result == ResolverImpl::DROPPED) {
     501                 :          1 :             send_answer = false;
     502                 :            :         }
     503                 :            :     }
     504                 :            : 
     505                 :         28 :     server->resume(send_answer);
     506                 :            : }
     507                 :            : 
     508                 :            : void
     509                 :          0 : ResolverImpl::resolve(const QuestionPtr& question,
     510                 :            :     const isc::resolve::ResolverInterface::CallbackPtr& callback)
     511                 :            : {
     512         [ #  # ]:          0 :     rec_query_->resolve(question, callback);
     513                 :          0 : }
     514                 :            : 
     515                 :            : ResolverImpl::NormalQueryResult
     516                 :          5 : ResolverImpl::processNormalQuery(const IOMessage& io_message,
     517                 :            :                                  MessagePtr query_message,
     518                 :            :                                  MessagePtr answer_message,
     519                 :            :                                  OutputBufferPtr buffer,
     520                 :            :                                  DNSServer* server)
     521                 :            : {
     522 [ +  - ][ +  - ]:         10 :     const ConstQuestionPtr question = *query_message->beginQuestion();
     523                 :          5 :     const RRType qtype = question->getType();
     524                 :          5 :     const RRClass qclass = question->getClass();
     525                 :            : 
     526                 :            :     // Apply query ACL
     527 [ +  - ][ +  - ]:         10 :     const Client client(io_message);
     528                 :            :     const BasicAction query_action(
     529                 :          5 :         getQueryACL().execute(acl::dns::RequestContext(
     530         [ +  - ]:          5 :                                   client.getRequestSourceIPAddress(),
     531         [ +  - ]:          5 :                                   query_message->getTSIGRecord())));
     532         [ +  + ]:          5 :     if (query_action == isc::acl::REJECT) {
     533 [ +  - ][ +  - ]:          2 :         LOG_INFO(resolver_logger, RESOLVER_QUERY_REJECTED)
                 [ +  - ]
     534 [ +  - ][ +  - ]:          1 :             .arg(question->getName()).arg(qtype).arg(qclass).arg(client);
         [ +  - ][ +  - ]
                 [ +  - ]
     535                 :            :         makeErrorMessage(query_message, answer_message, buffer,
     536 [ +  - ][ +  - ]:          2 :                          Rcode::REFUSED());
     537                 :            :         return (ERROR);
     538         [ +  + ]:          4 :     } else if (query_action == isc::acl::DROP) {
     539 [ +  - ][ +  - ]:          2 :         LOG_INFO(resolver_logger, RESOLVER_QUERY_DROPPED)
                 [ +  - ]
     540 [ +  - ][ +  - ]:          1 :             .arg(question->getName()).arg(qtype).arg(qclass).arg(client);
         [ +  - ][ +  - ]
                 [ +  - ]
     541                 :            :         return (DROPPED);
     542                 :            :     }
     543 [ +  - ][ +  - ]:          6 :     LOG_DEBUG(resolver_logger, RESOLVER_DBG_IO, RESOLVER_QUERY_ACCEPTED)
                 [ +  - ]
     544 [ +  - ][ +  - ]:          3 :         .arg(question->getName()).arg(qtype).arg(question->getClass())
         [ +  - ][ +  - ]
     545         [ +  - ]:          3 :         .arg(client);
     546                 :            : 
     547                 :            :     // ACL passed.  Reject inappropriate queries for the resolver.
     548         [ +  + ]:          3 :     if (qtype == RRType::AXFR()) {
     549 [ +  - ][ +  + ]:          2 :         if (io_message.getSocket().getProtocol() == IPPROTO_UDP) {
     550                 :            :             // Can't process AXFR request received over UDP
     551 [ +  - ][ +  - ]:          1 :             LOG_DEBUG(resolver_logger, RESOLVER_DBG_PROCESS, RESOLVER_AXFR_UDP);
         [ +  - ][ +  - ]
     552                 :            :             makeErrorMessage(query_message, answer_message, buffer,
     553 [ +  - ][ +  - ]:          2 :                              Rcode::FORMERR());
     554                 :            :         } else {
     555                 :            :             // ... or over TCP for that matter
     556 [ +  - ][ +  - ]:          1 :             LOG_DEBUG(resolver_logger, RESOLVER_DBG_PROCESS, RESOLVER_AXFR_TCP);
         [ +  - ][ +  - ]
     557                 :            :             makeErrorMessage(query_message, answer_message, buffer,
     558 [ +  - ][ +  - ]:          2 :                              Rcode::NOTIMP());
     559                 :            :         }
     560                 :            :         return (ERROR);
     561         [ +  - ]:          1 :     } else if (qtype == RRType::IXFR()) {
     562                 :            :         // Can't process IXFR request
     563 [ +  - ][ +  - ]:          1 :         LOG_DEBUG(resolver_logger, RESOLVER_DBG_PROCESS, RESOLVER_IXFR);
         [ +  - ][ +  - ]
     564                 :            :         makeErrorMessage(query_message, answer_message, buffer,
     565 [ +  - ][ +  - ]:          2 :                          Rcode::NOTIMP());
     566                 :            :         return (ERROR);
     567         [ #  # ]:          0 :     } else if (qclass != RRClass::IN()) {
     568                 :            :         // Non-IN message received, refuse it.
     569 [ #  # ][ #  # ]:          0 :         LOG_DEBUG(resolver_logger, RESOLVER_DBG_PROCESS, RESOLVER_NON_IN_PACKET)
                 [ #  # ]
     570 [ #  # ][ #  # ]:          0 :             .arg(question->getClass());
     571                 :            :         makeErrorMessage(query_message, answer_message, buffer,
     572 [ #  # ][ #  # ]:          0 :                          Rcode::REFUSED());
     573                 :            :         return (ERROR);
     574                 :            :     }
     575                 :            : 
     576                 :            :     // Everything is okay.  Start resolver.
     577         [ #  # ]:          0 :     if (upstream_.empty()) {
     578                 :            :         // Processing normal query
     579 [ #  # ][ #  # ]:          0 :         LOG_DEBUG(resolver_logger, RESOLVER_DBG_IO, RESOLVER_NORMAL_QUERY);
         [ #  # ][ #  # ]
     580         [ #  # ]:          0 :         rec_query_->resolve(*question, answer_message, buffer, server);
     581                 :            :     } else {
     582                 :            :         // Processing forward query
     583 [ #  # ][ #  # ]:          0 :         LOG_DEBUG(resolver_logger, RESOLVER_DBG_IO, RESOLVER_FORWARD_QUERY);
         [ #  # ][ #  # ]
     584         [ #  # ]:          0 :         rec_query_->forward(query_message, answer_message, buffer, server);
     585                 :            :     }
     586                 :            : 
     587                 :            :     return (RECURSION);
     588                 :            : }
     589                 :            : 
     590                 :            : ConstElementPtr
     591                 :         56 : Resolver::updateConfig(ConstElementPtr config, bool startup) {
     592         [ +  - ]:        112 :     LOG_DEBUG(resolver_logger, RESOLVER_DBG_CONFIG, RESOLVER_CONFIG_UPDATED)
     593         [ +  - ]:         56 :               .arg(*config);
     594                 :            : 
     595                 :            :     try {
     596                 :            :         // Parse forward_addresses
     597 [ +  - ][ +  - ]:         56 :         ConstElementPtr rootAddressesE(config->get("root_addresses"));
     598                 :            :         AddressList rootAddresses(parseAddresses(rootAddressesE,
     599 [ +  - ][ +  - ]:        224 :                                                     "root_addresses"));
     600 [ +  - ][ +  - ]:         56 :         ConstElementPtr forwardAddressesE(config->get("forward_addresses"));
     601                 :            :         AddressList forwardAddresses(parseAddresses(forwardAddressesE,
     602 [ +  - ][ +  + ]:        219 :                                                        "forward_addresses"));
     603 [ +  - ][ +  - ]:         51 :         ConstElementPtr listenAddressesE(config->get("listen_on"));
     604                 :            :         AddressList listenAddresses(parseAddresses(listenAddressesE,
     605 [ +  - ][ +  + ]:        198 :                                                       "listen_on"));
     606 [ +  - ][ +  - ]:         45 :         const ConstElementPtr query_acl_cfg(config->get("query_acl"));
     607                 :            :         const boost::shared_ptr<const RequestACL> query_acl =
     608         [ +  - ]:         26 :             query_acl_cfg ? acl::dns::getRequestLoader().load(query_acl_cfg) :
     609 [ +  + ][ +  + ]:         71 :             boost::shared_ptr<RequestACL>();
     610                 :         39 :         bool set_timeouts(false);
     611                 :         39 :         int qtimeout = impl_->query_timeout_;
     612                 :         39 :         int ctimeout = impl_->client_timeout_;
     613                 :         39 :         int ltimeout = impl_->lookup_timeout_;
     614                 :         39 :         unsigned retries = impl_->retries_;
     615 [ +  - ][ +  - ]:         39 :         ConstElementPtr qtimeoutE(config->get("timeout_query")),
     616 [ +  - ][ +  - ]:         39 :                         ctimeoutE(config->get("timeout_client")),
     617 [ +  - ][ +  - ]:         39 :                         ltimeoutE(config->get("timeout_lookup")),
     618 [ +  - ][ +  - ]:         39 :                         retriesE(config->get("retries"));
     619         [ +  + ]:         39 :         if (qtimeoutE) {
     620                 :            :             // It should be safe to just get it, the config manager should
     621                 :            :             // check for us
     622         [ +  + ]:          3 :             qtimeout = qtimeoutE->intValue();
     623         [ +  + ]:          2 :             if (qtimeout < -1) {
     624 [ +  - ][ +  - ]:          2 :                 LOG_ERROR(resolver_logger, RESOLVER_QUERY_TIME_SMALL)
                 [ +  - ]
     625 [ +  - ][ +  - ]:          1 :                           .arg(qtimeout);
     626 [ +  - ][ +  - ]:          2 :                 isc_throw(BadValue, "Query timeout too small");
     627                 :            :             }
     628                 :            :             set_timeouts = true;
     629                 :            :         }
     630         [ +  + ]:         37 :         if (ctimeoutE) {
     631         [ +  + ]:          3 :             ctimeout = ctimeoutE->intValue();
     632         [ +  + ]:          2 :             if (ctimeout < -1) {
     633 [ +  - ][ +  - ]:          2 :                 LOG_ERROR(resolver_logger, RESOLVER_CLIENT_TIME_SMALL)
                 [ +  - ]
     634 [ +  - ][ +  - ]:          1 :                           .arg(ctimeout);
     635 [ +  - ][ +  - ]:          2 :                 isc_throw(BadValue, "Client timeout too small");
     636                 :            :             }
     637                 :            :             set_timeouts = true;
     638                 :            :         }
     639         [ +  + ]:         35 :         if (ltimeoutE) {
     640         [ +  + ]:          3 :             ltimeout = ltimeoutE->intValue();
     641         [ +  + ]:          2 :             if (ltimeout < -1) {
     642 [ +  - ][ +  - ]:          2 :                 LOG_ERROR(resolver_logger, RESOLVER_LOOKUP_TIME_SMALL)
                 [ +  - ]
     643 [ +  - ][ +  - ]:          1 :                           .arg(ltimeout);
     644 [ +  - ][ +  - ]:          2 :                 isc_throw(BadValue, "Lookup timeout too small");
     645                 :            :             }
     646                 :            :             set_timeouts = true;
     647                 :            :         }
     648         [ +  + ]:         33 :         if (retriesE) {
     649                 :            :             // Do the assignment from "retriesE->intValue()" to "retries"
     650                 :            :             // _after_ the comparison (as opposed to before it for the timeouts)
     651                 :            :             // because "retries" is unsigned.
     652 [ +  + ][ +  + ]:          3 :             if (retriesE->intValue() < 0) {
     653 [ +  - ][ +  - ]:          2 :                 LOG_ERROR(resolver_logger, RESOLVER_NEGATIVE_RETRIES)
                 [ +  - ]
     654 [ +  - ][ +  - ]:          1 :                           .arg(retriesE->intValue());
                 [ +  - ]
     655 [ +  - ][ +  - ]:          2 :                 isc_throw(BadValue, "Negative number of retries");
     656                 :            :             }
     657         [ +  - ]:          1 :             retries = retriesE->intValue();
     658                 :          1 :             set_timeouts = true;
     659                 :            :         }
     660                 :            :         // Everything OK, so commit the changes
     661                 :            :         // listenAddresses can fail to bind, so try them first
     662                 :         31 :         bool need_query_restart = false;
     663                 :            :         
     664 [ +  + ][ +  + ]:         61 :         if (!startup && listenAddressesE) {
                 [ +  + ]
     665         [ +  + ]:          5 :             setListenAddresses(listenAddresses);
     666                 :            :             need_query_restart = true;
     667                 :            :         }
     668         [ +  + ]:         28 :         if (forwardAddressesE) {
     669         [ +  - ]:          2 :             setForwardAddresses(forwardAddresses);
     670                 :            :             need_query_restart = true;
     671                 :            :         }
     672         [ +  + ]:         28 :         if (rootAddressesE) {
     673         [ +  - ]:          3 :             setRootAddresses(rootAddresses);
     674                 :            :             need_query_restart = true;
     675                 :            :         }
     676         [ +  + ]:         28 :         if (set_timeouts) {
     677         [ +  - ]:          1 :             setTimeouts(qtimeout, ctimeout, ltimeout, retries);
     678                 :            :             need_query_restart = true;
     679                 :            :         }
     680         [ +  + ]:         28 :         if (query_acl) {
     681         [ +  - ]:         20 :             setQueryACL(query_acl);
     682                 :            :         }
     683 [ +  + ][ -  + ]:         29 :         if (startup && listenAddressesE) {
                 [ +  + ]
     684         [ -  + ]:          1 :             setListenAddresses(listenAddresses);
     685                 :            :             need_query_restart = true;
     686                 :            :         }
     687                 :            : 
     688         [ +  + ]:         27 :         if (need_query_restart) {
     689         [ +  - ]:          7 :             impl_->queryShutdown();
     690                 :          7 :             impl_->querySetup(*dnss_, *nsas_, *cache_);
     691                 :            :         }
     692         [ +  - ]:         27 :         return (isc::config::createAnswer());
     693                 :            : 
     694         [ -  + ]:         58 :     } catch (const isc::Exception& error) {
     695                 :            : 
     696                 :            :         // Configuration error
     697 [ -  + ][ +  - ]:         29 :         LOG_ERROR(resolver_logger, RESOLVER_CONFIG_ERROR).arg(error.what());
         [ -  + ][ -  + ]
                 [ -  + ]
     698 [ -  + ][ -  + ]:         29 :         return (isc::config::createAnswer(1, error.what()));
     699                 :            :     }
     700                 :            : }
     701                 :            : 
     702                 :            : void
     703                 :          4 : Resolver::setForwardAddresses(const AddressList& addresses)
     704                 :            : {
     705                 :          4 :     impl_->setForwardAddresses(addresses, dnss_);
     706                 :          4 : }
     707                 :            : 
     708                 :            : void
     709                 :          3 : Resolver::setRootAddresses(const AddressList& addresses)
     710                 :            : {
     711                 :          3 :     impl_->setRootAddresses(addresses, dnss_);
     712                 :          3 : }
     713                 :            : 
     714                 :            : bool
     715                 :          5 : Resolver::isForwarding() const {
     716                 :          5 :     return (!impl_->upstream_.empty());
     717                 :            : }
     718                 :            : 
     719                 :            : AddressList
     720                 :          9 : Resolver::getForwardAddresses() const {
     721                 :          9 :     return (impl_->upstream_);
     722                 :            : }
     723                 :            : 
     724                 :            : AddressList
     725                 :          6 : Resolver::getRootAddresses() const {
     726                 :          6 :     return (impl_->upstream_root_);
     727                 :            : }
     728                 :            : 
     729                 :            : void
     730                 :          8 : Resolver::setListenAddresses(const AddressList& addresses) {
     731                 :          8 :     installListenAddresses(addresses, impl_->listen_, *dnss_);
     732                 :          4 : }
     733                 :            : 
     734                 :            : void
     735                 :          3 : Resolver::setTimeouts(int query_timeout, int client_timeout,
     736                 :            :                       int lookup_timeout, unsigned retries) {
     737         [ +  - ]:          6 :     LOG_DEBUG(resolver_logger, RESOLVER_DBG_CONFIG, RESOLVER_SET_PARAMS)
     738 [ +  - ][ +  - ]:          3 :               .arg(query_timeout).arg(client_timeout).arg(lookup_timeout)
                 [ +  - ]
     739         [ +  - ]:          3 :               .arg(retries);
     740                 :            : 
     741                 :          3 :     impl_->query_timeout_ = query_timeout;
     742                 :          3 :     impl_->client_timeout_ = client_timeout;
     743                 :          3 :     impl_->lookup_timeout_ = lookup_timeout;
     744                 :          3 :     impl_->retries_ = retries;
     745                 :          3 : }
     746                 :            : 
     747                 :            : int
     748                 :          3 : Resolver::getQueryTimeout() const {
     749                 :          3 :     return impl_->query_timeout_;
     750                 :            : }
     751                 :            : 
     752                 :            : int
     753                 :          3 : Resolver::getClientTimeout() const {
     754                 :          3 :     return impl_->client_timeout_;
     755                 :            : }
     756                 :            : 
     757                 :            : int
     758                 :          3 : Resolver::getLookupTimeout() const {
     759                 :          3 :     return impl_->lookup_timeout_;
     760                 :            : }
     761                 :            : 
     762                 :            : int
     763                 :          3 : Resolver::getRetries() const {
     764                 :          3 :     return impl_->retries_;
     765                 :            : }
     766                 :            : 
     767                 :            : AddressList
     768                 :         11 : Resolver::getListenAddresses() const {
     769                 :         11 :     return (impl_->listen_);
     770                 :            : }
     771                 :            : 
     772                 :            : const RequestACL&
     773                 :         16 : Resolver::getQueryACL() const {
     774                 :         16 :     return (impl_->getQueryACL());
     775                 :            : }
     776                 :            : 
     777                 :            : void
     778                 :         21 : Resolver::setQueryACL(boost::shared_ptr<const RequestACL> new_acl) {
     779         [ +  + ]:         21 :     if (!new_acl) {
     780         [ +  - ]:          2 :         isc_throw(InvalidParameter, "NULL pointer is passed to setQueryACL");
     781                 :            :     }
     782                 :            : 
     783         [ +  - ]:         20 :     LOG_INFO(resolver_logger, RESOLVER_SET_QUERY_ACL);
     784                 :         20 :     impl_->setQueryACL(new_acl);
     785                 :         21 : }

Generated by: LCOV version 1.9