LCOV - code coverage report
Current view: top level - cache - message_entry.cc (source / functions) Hit Total Coverage
Test: report.info Lines: 131 132 99.2 %
Date: 2012-05-15 Functions: 10 10 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 151 240 62.9 %

           Branch data     Line data    Source code
       1                 :            : // Copyright (C) 2010  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 <limits>
      18                 :            : #include <dns/message.h>
      19                 :            : #include <nsas/nsas_entry.h>
      20                 :            : #include "message_entry.h"
      21                 :            : #include "message_utility.h"
      22                 :            : #include "rrset_cache.h"
      23                 :            : #include "logger.h"
      24                 :            : 
      25                 :            : using namespace isc::dns;
      26                 :            : using namespace std;
      27                 :            : 
      28                 :            : // Put file scope functions in unnamed namespace.
      29                 :            : namespace {
      30                 :            : 
      31                 :            : // Get the shortest existing ancestor which is the owner name of
      32                 :            : // one DNAME record for the given query name.
      33                 :            : // Note: there may be multiple DNAME records(DNAME chain) in answer
      34                 :            : // section. In most cases they are in order, but the code can't depend
      35                 :            : // on that, it has to find the starter by iterating the DNAME chain.
      36                 :            : Name
      37                 :          9 : getDNAMEChainStarter(const Message& message, const Name& query_name) {
      38                 :          9 :     Name dname = query_name;
      39 [ +  - ][ +  - ]:         18 :     RRsetIterator rrset_iter = message.beginSection(Message::SECTION_ANSWER);
      40 [ +  - ][ +  - ]:         47 :     while(rrset_iter != message.endSection(Message::SECTION_ANSWER)) {
         [ +  - ][ +  + ]
      41 [ +  - ][ +  - ]:         38 :         if ((*rrset_iter)->getType() == RRType::DNAME()) {
                 [ +  + ]
      42 [ +  - ][ +  - ]:         16 :             const Name& rrname = (*rrset_iter)->getName();
      43         [ +  + ]:         16 :             if (NameComparisonResult::SUBDOMAIN ==
      44         [ +  - ]:         16 :                 dname.compare(rrname).getRelation()) {
      45         [ +  - ]:          5 :                 dname = rrname;
      46                 :            :             }
      47                 :            :         }
      48         [ +  - ]:         38 :         ++rrset_iter;
      49                 :            :     }
      50                 :            : 
      51                 :          9 :     return (dname);
      52                 :            : }
      53                 :            : 
      54                 :            : } // End of unnamed namespace
      55                 :            : 
      56                 :            : namespace isc {
      57                 :            : namespace cache {
      58                 :            : 
      59                 :          3 : static uint32_t MAX_UINT32 = numeric_limits<uint32_t>::max();
      60                 :            : 
      61                 :            : // As with caching positive responses it is sensible for a resolver to
      62                 :            : // limit for how long it will cache a negative response as the protocol
      63                 :            : // supports caching for up to 68 years.  Such a limit should not be
      64                 :            : // greater than that applied to positive answers and preferably be
      65                 :            : // tunable.  Values of one to three hours have been found to work well
      66                 :            : // and would make sensible a default.  Values exceeding one day have
      67                 :            : // been found to be problematic. (sec 5, RFC2308)
      68                 :            : // The default value is 3 hours (10800 seconds)
      69                 :            : // TODO:Give an option to let user configure
      70                 :            : static uint32_t MAX_NEGATIVE_CACHE_TTL = 10800;
      71                 :            : 
      72                 :            : // Sets the maximum time for which the server will cache ordinary (positive) answers. The
      73                 :            : // default is one week (7 days = 604800 seconds)
      74                 :            : // TODO:Give an option to let user configure
      75                 :            : static uint32_t MAX_NORMAL_CACHE_TTL = 604800;
      76                 :            : 
      77                 :         36 : MessageEntry::MessageEntry(const isc::dns::Message& msg,
      78                 :            :                            const RRsetCachePtr& rrset_cache,
      79                 :            :                            const RRsetCachePtr& negative_soa_cache):
      80                 :            :     rrset_cache_(rrset_cache),
      81                 :            :     negative_soa_cache_(negative_soa_cache),
      82                 :            :     headerflag_aa_(false),
      83                 :          0 :     headerflag_tc_(false)
      84                 :            : {
      85         [ +  - ]:         36 :     initMessageEntry(msg);
      86         [ +  - ]:         72 :     entry_name_ = genCacheEntryName(query_name_, query_type_);
      87         [ +  - ]:         36 :     hash_key_ptr_ = new HashKey(entry_name_, RRClass(query_class_));
      88                 :         36 : }
      89                 :            : 
      90                 :            : bool
      91                 :         20 : MessageEntry::getRRsetEntries(vector<RRsetEntryPtr>& rrset_entry_vec,
      92                 :            :                               const time_t time_now)
      93                 :            : {
      94                 :         20 :     uint16_t entry_count = answer_count_ + authority_count_ + additional_count_;
      95                 :         20 :     rrset_entry_vec.reserve(rrset_entry_vec.size() + entry_count);
      96         [ +  + ]:         85 :     for (int index = 0; index < entry_count; ++index) {
      97                 :        130 :         RRsetCache* rrset_cache = rrsets_[index].cache_;
      98                 :         65 :         RRsetEntryPtr rrset_entry = rrset_cache->lookup(rrsets_[index].name_,
      99                 :         65 :                                                         rrsets_[index].type_);
     100 [ +  + ][ +  - ]:         65 :         if (rrset_entry && time_now < rrset_entry->getExpireTime()) {
         [ +  + ][ +  + ]
     101                 :            :             rrset_entry_vec.push_back(rrset_entry);
     102                 :            :         } else {
     103                 :          2 :             return (false);
     104                 :            :         }
     105                 :            :     }
     106                 :            : 
     107                 :            :     return (true);
     108                 :            : }
     109                 :            : 
     110                 :            : void
     111                 :         54 : MessageEntry::addRRset(isc::dns::Message& message,
     112                 :            :                        const vector<RRsetEntryPtr>& rrset_entry_vec,
     113                 :            :                        const isc::dns::Message::Section& section,
     114                 :            :                        bool dnssec_need)
     115                 :            : {
     116                 :         54 :     uint16_t start_index = 0;
     117                 :         54 :     uint16_t end_index = answer_count_;
     118         [ -  + ]:         54 :     assert(section != Message::SECTION_QUESTION);
     119                 :            : 
     120         [ +  + ]:         54 :     if (section == Message::SECTION_AUTHORITY) {
     121                 :         18 :         start_index = answer_count_;
     122                 :         18 :         end_index = answer_count_ + authority_count_;
     123         [ +  + ]:         36 :     } else if (section == Message::SECTION_ADDITIONAL) {
     124                 :         18 :         start_index = answer_count_ + authority_count_;
     125                 :         18 :         end_index = start_index + additional_count_;
     126                 :            :     }
     127                 :            : 
     128         [ +  + ]:        114 :     for (uint16_t index = start_index; index < end_index; ++index) {
     129                 :         60 :         message.addRRset(section, rrset_entry_vec[index]->getRRset(),
     130         [ +  - ]:         60 :                          dnssec_need);
     131                 :            :     }
     132                 :         54 : }
     133                 :            : 
     134                 :            : bool
     135                 :         20 : MessageEntry::genMessage(const time_t& time_now,
     136                 :            :                          isc::dns::Message& msg)
     137                 :            : {
     138         [ +  + ]:         20 :     if (time_now >= expire_time_) {
     139                 :            :         // The message entry has expired.
     140                 :            :         return (false);
     141                 :            :     } else {
     142                 :            :         // Before do any generation, we should check if some rrset
     143                 :            :         // has expired, if it is, return false.
     144                 :         20 :         vector<RRsetEntryPtr> rrset_entry_vec;
     145 [ +  - ][ +  + ]:         19 :         if (false == getRRsetEntries(rrset_entry_vec, time_now)) {
     146 [ +  - ][ +  - ]:          2 :             LOG_DEBUG(logger, DBG_TRACE_DATA, CACHE_ENTRY_MISSING_RRSET).
                 [ +  - ]
     147         [ +  - ]:          1 :                 arg(entry_name_);
     148                 :            :             return (false);
     149                 :            :         }
     150                 :            : 
     151                 :            :         // Begin message generation. We don't need to add question
     152                 :            :         // section, since it has been included in the message.
     153                 :            :         // Set cached header flags.
     154                 :            :         // The AA flag bit should be cleared because this is a response from
     155                 :            :         // resolver cache
     156         [ +  - ]:         18 :         msg.setHeaderFlag(Message::HEADERFLAG_AA, false);
     157         [ +  - ]:         18 :         msg.setHeaderFlag(Message::HEADERFLAG_TC, headerflag_tc_);
     158                 :            : 
     159         [ +  - ]:         18 :         bool dnssec_need = msg.getEDNS().get();
     160         [ +  - ]:         18 :         addRRset(msg, rrset_entry_vec, Message::SECTION_ANSWER, dnssec_need);
     161         [ +  - ]:         18 :         addRRset(msg, rrset_entry_vec, Message::SECTION_AUTHORITY, dnssec_need);
     162         [ +  - ]:         18 :         addRRset(msg, rrset_entry_vec, Message::SECTION_ADDITIONAL, dnssec_need);
     163                 :            : 
     164                 :            :         return (true);
     165                 :            :     }
     166                 :            : }
     167                 :            : 
     168                 :            : RRsetTrustLevel
     169                 :        176 : MessageEntry::getRRsetTrustLevel(const Message& message,
     170                 :            :     const isc::dns::RRsetPtr& rrset,
     171                 :            :     const isc::dns::Message::Section& section)
     172                 :            : {
     173                 :        176 :     bool aa = message.getHeaderFlag(Message::HEADERFLAG_AA);
     174   [ +  +  +  - ]:        176 :     switch(section) {
     175                 :            :         case Message::SECTION_ANSWER: {
     176         [ +  + ]:         59 :             if (aa) {
     177                 :            :                 // According RFC2181 section 5.4.1, only the record
     178                 :            :                 // describing that ailas is necessarily authoritative.
     179                 :            :                 // If there are CNAME(Not synchronized from DNAME)
     180                 :            :                 // records in answer section, only the CNAME record
     181                 :            :                 // whose owner name is same with qname is assumed as
     182                 :            :                 // authoritative, all the left records are not authoritative.
     183                 :            :                 //
     184                 :            :                 // If there are DNAME records in answer section,
     185                 :            :                 // Only the start DNAME and the synchronized CNAME record
     186                 :            :                 // from it are authoritative, any other records in answer
     187                 :            :                 // section are non-authoritative.
     188                 :        104 :                 QuestionIterator quest_iter = message.beginQuestion();
     189                 :            :                 // Make sure question section is not empty.
     190 [ +  - ][ +  - ]:         52 :                 assert( quest_iter != message.endQuestion());
         [ -  + ][ +  - ]
     191                 :            : 
     192         [ +  - ]:         52 :                 const Name& query_name = (*quest_iter)->getName();
     193         [ +  - ]:         52 :                 const RRType& type = rrset->getType();
     194         [ +  - ]:         52 :                 const Name& name = rrset->getName();
     195         [ +  + ]:        172 :                 if ((type == RRType::CNAME() && name == query_name) ||
           [ +  +  +  + ]
         [ +  + ][ +  + ]
     196                 :         41 :                     (type == RRType::DNAME() &&
     197 [ +  - ][ +  + ]:         61 :                      name == getDNAMEChainStarter(message, query_name))) {
                 [ #  # ]
     198                 :            :                     return (RRSET_TRUST_ANSWER_AA);
     199                 :            :                 } else {
     200                 :            :                     // If there is a CNAME record whose ower name is the same as
     201                 :            :                     // the query name in answer section, the other records in answer
     202                 :            :                     // section are non-authoritative, except the starter of DNAME
     203                 :            :                     // chain (only checking CNAME is enough, because if the CNAME
     204                 :            :                     // record is synthesized from a DNAME record, that DNAME
     205                 :            :                     // record must be the starter of the DNAME chain).
     206 [ +  - ][ +  - ]:         74 :                     RRsetIterator iter = message.beginSection(Message::SECTION_ANSWER);
                 [ +  - ]
     207 [ +  - ][ +  - ]:         62 :                     while(iter != message.endSection(Message::SECTION_ANSWER)) {
         [ +  - ][ +  + ]
     208 [ +  - ][ +  - ]:         59 :                         if ((*iter)->getType() == RRType::CNAME() &&
         [ +  + ][ -  + ]
                 [ +  + ]
     209 [ +  - ][ +  - ]:         17 :                              (*iter)->getName() == query_name) {
     210                 :            :                             return (RRSET_TRUST_ANSWER_NONAA);
     211                 :            :                         }
     212         [ +  - ]:         25 :                         ++iter;
     213                 :            :                     }
     214                 :            :                 }
     215                 :            :                 return (RRSET_TRUST_ANSWER_AA);
     216                 :            :             } else {
     217                 :            :                 return (RRSET_TRUST_ANSWER_NONAA);
     218                 :            :             }
     219                 :            :             break;
     220                 :            :         }
     221                 :            : 
     222                 :            :         case Message::SECTION_AUTHORITY: {
     223         [ +  + ]:         31 :             if (aa) {
     224                 :            :                 return (RRSET_TRUST_AUTHORITY_AA);
     225                 :            :             } else {
     226                 :          6 :                 return (RRSET_TRUST_AUTHORITY_NONAA);
     227                 :            :             }
     228                 :            :             break;
     229                 :            :         }
     230                 :            : 
     231                 :            :         case Message::SECTION_ADDITIONAL: {
     232         [ +  + ]:         86 :             if (aa) {
     233                 :            :                 return (RRSET_TRUST_ADDITIONAL_AA);
     234                 :            :             } else {
     235                 :        176 :                 return (RRSET_TRUST_ADDITIONAL_NONAA);
     236                 :            :             }
     237                 :            :             break;
     238                 :            :         }
     239                 :            : 
     240                 :            :         default:
     241                 :            :             return (RRSET_TRUST_DEFAULT);
     242                 :            :     }
     243                 :            : }
     244                 :            : 
     245                 :            : void
     246                 :        107 : MessageEntry::parseSection(const isc::dns::Message& msg,
     247                 :            :                          const Message::Section& section,
     248                 :            :                          uint32_t& smaller_ttl,
     249                 :            :                          uint16_t& rrset_count)
     250                 :            : {
     251                 :        107 :     RRsetIterator iter;
     252                 :        107 :     int count = 0;
     253 [ +  - ][ +  - ]:        780 :     for (iter = msg.beginSection(section);
         [ +  - ][ +  - ]
         [ +  - ][ +  + ]
     254 [ +  - ][ +  - ]:        520 :          iter != msg.endSection(section);
     255                 :            :          ++iter) {
     256                 :            :         // Add the rrset entry to rrset_cache or update the existed
     257                 :            :         // rrset entry if the new one is more authoritative.
     258                 :            :         //TODO set proper rrset trust level.
     259         [ +  - ]:        153 :         RRsetPtr rrset_ptr = *iter;
     260         [ +  - ]:        153 :         RRsetTrustLevel level = getRRsetTrustLevel(msg, rrset_ptr, section);
     261         [ +  - ]:        306 :         RRsetEntryPtr rrset_entry = rrset_cache_->update(*rrset_ptr, level);
     262 [ +  - ][ +  - ]:        153 :         rrsets_.push_back(RRsetRef(rrset_ptr->getName(), rrset_ptr->getType(),
     263         [ +  - ]:        153 :                           rrset_cache_.get()));
     264                 :            : 
     265         [ +  - ]:        153 :         uint32_t rrset_ttl = rrset_entry->getTTL();
     266         [ +  + ]:        153 :         if (smaller_ttl > rrset_ttl) {
     267                 :         52 :             smaller_ttl = rrset_ttl;
     268                 :            :         }
     269                 :            : 
     270                 :        153 :         count++;
     271                 :            :     }
     272                 :            : 
     273                 :        107 :     rrset_count = count;
     274                 :        107 : }
     275                 :            : 
     276                 :            : void
     277                 :          4 : MessageEntry::parseNegativeResponseAuthoritySection(const isc::dns::Message& msg,
     278                 :            :         uint32_t& min_ttl,
     279                 :            :         uint16_t& rrset_count)
     280                 :            : {
     281                 :          4 :     uint16_t count = 0;
     282 [ +  - ][ +  - ]:         24 :     for (RRsetIterator iter = msg.beginSection(Message::SECTION_AUTHORITY);
                 [ +  + ]
     283 [ +  - ][ +  - ]:         16 :             iter != msg.endSection(Message::SECTION_AUTHORITY);
     284                 :            :             ++iter) {
     285         [ +  - ]:          4 :         RRsetPtr rrset_ptr = *iter;
     286                 :            :         RRsetTrustLevel level = getRRsetTrustLevel(msg, rrset_ptr,
     287         [ +  - ]:          4 :                                                    Message::SECTION_AUTHORITY);
     288                 :          4 :         boost::shared_ptr<RRsetCache> rrset_cache_ptr = rrset_cache_;
     289 [ +  - ][ +  - ]:          4 :         if (rrset_ptr->getType() == RRType::SOA()) {
     290                 :          4 :             rrset_cache_ptr = negative_soa_cache_;
     291                 :            :         }
     292                 :            : 
     293         [ +  - ]:          8 :         RRsetEntryPtr rrset_entry = rrset_cache_ptr->update(*rrset_ptr, level);
     294         [ +  - ]:          4 :         rrsets_.push_back(RRsetRef(rrset_ptr->getName(),
     295         [ +  - ]:          4 :                                    rrset_ptr->getType(),
     296         [ +  - ]:          4 :                                    rrset_cache_ptr.get()));
     297         [ +  - ]:          4 :         uint32_t rrset_ttl = rrset_entry->getTTL();
     298         [ +  - ]:          4 :         if (min_ttl > rrset_ttl) {
     299                 :          4 :             min_ttl = rrset_ttl;
     300                 :            :         }
     301                 :          4 :         ++count;
     302                 :            :     }
     303                 :            : 
     304                 :          4 :     rrset_count = count;
     305                 :          4 : }
     306                 :            : 
     307                 :            : void
     308                 :         36 : MessageEntry::initMessageEntry(const isc::dns::Message& msg) {
     309                 :            :     //TODO better way to cache the header flags?
     310                 :         36 :     headerflag_aa_ = msg.getHeaderFlag(Message::HEADERFLAG_AA);
     311                 :         36 :     headerflag_tc_ = msg.getHeaderFlag(Message::HEADERFLAG_TC);
     312                 :            : 
     313                 :            :     // We only cache the first question in question section.
     314                 :            :     // TODO, do we need to support muptiple questions?
     315                 :         36 :     query_count_ = 1;
     316                 :         72 :     QuestionIterator iter = msg.beginQuestion();
     317 [ +  - ][ +  - ]:         72 :     query_name_ = (*iter)->getName().toText();
     318         [ +  - ]:         36 :     query_type_ = (*iter)->getType().getCode();
     319         [ +  - ]:         36 :     query_class_ = (*iter)->getClass().getCode();
     320                 :            : 
     321                 :         36 :     uint32_t min_ttl = MAX_UINT32;
     322                 :            : 
     323         [ +  - ]:         36 :     bool isNegativeResponse = MessageUtility::isNegativeResponse(msg);
     324                 :            : 
     325         [ +  - ]:         36 :     parseSection(msg, Message::SECTION_ANSWER, min_ttl, answer_count_);
     326         [ +  + ]:         36 :     if (!isNegativeResponse) {
     327         [ +  - ]:         32 :         parseSection(msg, Message::SECTION_AUTHORITY, min_ttl, authority_count_);
     328                 :            :     } else {
     329         [ +  - ]:          4 :         parseNegativeResponseAuthoritySection(msg, min_ttl, authority_count_);
     330                 :            :     }
     331         [ +  - ]:         36 :     parseSection(msg, Message::SECTION_ADDITIONAL, min_ttl, additional_count_);
     332                 :            : 
     333                 :            :     // Limit the ttl to a prset max-value
     334         [ +  + ]:         36 :     if (!isNegativeResponse) {
     335         [ +  + ]:         32 :         if (min_ttl > MAX_NORMAL_CACHE_TTL) {
     336                 :          1 :             min_ttl = MAX_NORMAL_CACHE_TTL;
     337                 :            :         }
     338                 :            :     } else {
     339         [ +  + ]:          4 :         if (min_ttl > MAX_NEGATIVE_CACHE_TTL) {
     340                 :          3 :             min_ttl = MAX_NEGATIVE_CACHE_TTL;
     341                 :            :         }
     342                 :            :     }
     343                 :            : 
     344                 :         36 :     expire_time_ = time(NULL) + min_ttl;
     345                 :         36 : }
     346                 :            : 
     347                 :            : } // namespace cache
     348                 :         13 : } // namespace isc

Generated by: LCOV version 1.9