• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

PowerDNS / pdns / 12595591960

03 Jan 2025 09:27AM UTC coverage: 62.774% (+2.5%) from 60.245%
12595591960

Pull #15008

github

web-flow
Merge c2a2749d3 into 788f396a7
Pull Request #15008: Do not follow CNAME records for ANY or CNAME queries

30393 of 78644 branches covered (38.65%)

Branch coverage included in aggregate %.

105822 of 138350 relevant lines covered (76.49%)

4613078.44 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.24
/pdns/recursordist/negcache.hh
1
/*
2
 * This file is part of PowerDNS or dnsdist.
3
 * Copyright -- PowerDNS.COM B.V. and its contributors
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of version 2 of the GNU General Public License as
7
 * published by the Free Software Foundation.
8
 *
9
 * In addition, for the avoidance of any doubt, permission is granted to
10
 * link this program with OpenSSL and to (re)distribute the binaries
11
 * produced as the result of such linking.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU General Public License
19
 * along with this program; if not, write to the Free Software
20
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21
 */
22
#pragma once
23

24
#include <vector>
25
#include <boost/multi_index_container.hpp>
26
#include <boost/multi_index/ordered_index.hpp>
27
#include <boost/multi_index/hashed_index.hpp>
28
#include <boost/multi_index/sequenced_index.hpp>
29
#include <boost/multi_index/key_extractors.hpp>
30
#include <boost/optional.hpp>
31
#include "dnsparser.hh"
32
#include "dnsname.hh"
33
#include "dns.hh"
34
#include "lock.hh"
35
#include "stat_t.hh"
36
#include "validate.hh"
37

38
using namespace ::boost::multi_index;
39

40
/* FIXME should become part of the normal cache (I think) and should become more like
41
 * struct {
42
 *   vector<DNSRecord> records;
43
 *   vector<DNSRecord> signatures;
44
 * } recsig_t;
45
 *
46
 * typedef vector<recsig_t> recordsAndSignatures;
47
 */
48
typedef struct
49
{
50
  vector<DNSRecord> records;
51
  vector<DNSRecord> signatures;
52
} recordsAndSignatures;
53

54
class NegCache : public boost::noncopyable
55
{
56
public:
57
  NegCache(size_t mapsCount = 128);
58

59
  // For a description on how ServeStale works, see recursor_cache.cc, the general structure is the same.
60
  // The number of times a stale cache entry is extended
61
  static uint16_t s_maxServedStaleExtensions;
62
  // The time a stale cache entry is extended
63
  static constexpr uint32_t s_serveStaleExtensionPeriod = 30;
64

65
  struct NegCacheEntry
66
  {
67
    recordsAndSignatures authoritySOA; // The upstream SOA record and RRSIGs
68
    recordsAndSignatures DNSSECRecords; // The upstream NSEC(3) and RRSIGs
69
    DNSName d_name; // The denied name
70
    DNSName d_auth; // The denying name (aka auth)
71
    mutable time_t d_ttd; // Timestamp when this entry should die
72
    uint32_t d_orig_ttl;
73
    mutable uint16_t d_servedStale{0};
74
    mutable vState d_validationState{vState::Indeterminate};
75
    QType d_qtype; // The denied type
76

77
    bool isStale(time_t now) const
78
    {
2,129✔
79
      // We like to keep things in cache when we (potentially) should serve stale
80
      if (s_maxServedStaleExtensions > 0) {
2,129!
81
        return d_ttd + static_cast<time_t>(s_maxServedStaleExtensions) * std::min(s_serveStaleExtensionPeriod, d_orig_ttl) < now;
×
82
      }
×
83
      else {
2,129✔
84
        return d_ttd < now;
2,129✔
85
      }
2,129✔
86
    };
2,129✔
87

88
    bool isEntryUsable(time_t now, bool serveStale) const
89
    {
2,739✔
90
      // When serving stale, we consider expired records
91
      return d_ttd > now || serveStale || d_servedStale != 0;
2,739✔
92
    }
2,739✔
93
  };
94

95
  void add(const NegCacheEntry& ne);
96
  void updateValidationStatus(const DNSName& qname, QType qtype, vState newState, boost::optional<time_t> capTTD);
97
  bool get(const DNSName& qname, QType qtype, const struct timeval& now, NegCacheEntry& ne, bool typeMustMatch = false, bool serverStale = false, bool refresh = false);
98
  bool getRootNXTrust(const DNSName& qname, const struct timeval& now, NegCacheEntry& negEntry, bool serveStale, bool refresh);
99
  size_t count(const DNSName& qname);
100
  size_t count(const DNSName& qname, QType qtype);
101
  void prune(time_t now, size_t maxEntries);
102
  void clear();
103
  size_t doDump(int fd, size_t maxCacheEntries, time_t now = time(nullptr));
104
  size_t wipe(const DNSName& name, bool subtree = false);
105
  size_t wipeTyped(const DNSName& name, QType qtype);
106
  size_t size() const;
107

108
private:
109
  struct CompositeKey
110
  {
111
  };
112
  struct SequenceTag
113
  {
114
  };
115
  typedef boost::multi_index_container<
116
    NegCacheEntry,
117
    indexed_by<
118
      ordered_unique<tag<CompositeKey>,
119
                     composite_key<
120
                       NegCacheEntry,
121
                       member<NegCacheEntry, DNSName, &NegCacheEntry::d_name>,
122
                       member<NegCacheEntry, QType, &NegCacheEntry::d_qtype>>,
123
                     composite_key_compare<
124
                       CanonDNSNameCompare, std::less<QType>>>,
125
      sequenced<tag<SequenceTag>>,
126
      hashed_non_unique<tag<NegCacheEntry>,
127
                        member<NegCacheEntry, DNSName, &NegCacheEntry::d_name>>>>
128
    negcache_t;
129

130
  void updateStaleEntry(time_t now, negcache_t::iterator& entry, QType qtype);
131

132
  struct MapCombo
133
  {
134
    MapCombo() {}
99,724✔
135
    MapCombo(const MapCombo&) = delete;
136
    MapCombo& operator=(const MapCombo&) = delete;
137
    struct LockedContent
138
    {
139
      negcache_t d_map;
140
      uint64_t d_contended_count{0};
141
      uint64_t d_acquired_count{0};
142
      void invalidate() {}
2,572✔
143
      void preRemoval(const NegCacheEntry& /* entry */) {}
1,204✔
144
    };
145

146
    LockGuardedTryHolder<MapCombo::LockedContent> lock()
147
    {
311,880✔
148
      auto locked = d_content.try_lock();
311,880✔
149
      if (!locked.owns_lock()) {
311,880✔
150
        locked.lock();
467✔
151
        ++locked->d_contended_count;
467✔
152
      }
467✔
153
      ++locked->d_acquired_count;
311,880✔
154
      return locked;
311,880✔
155
    }
311,880✔
156

157
    [[nodiscard]] auto getEntriesCount() const
158
    {
44,369✔
159
      return d_entriesCount.load();
44,369✔
160
    }
44,369✔
161

162
    void incEntriesCount()
163
    {
9,018✔
164
      ++d_entriesCount;
9,018✔
165
    }
9,018✔
166

167
    void decEntriesCount()
168
    {
2,118✔
169
      --d_entriesCount;
2,118✔
170
    }
2,118✔
171

172
    void clearEntriesCount()
173
    {
69,632✔
174
      d_entriesCount = 0;
69,632✔
175
    }
69,632✔
176

177
  private:
178
    LockGuarded<LockedContent> d_content;
179
    pdns::stat_t d_entriesCount{0};
180
  };
181

182
  vector<MapCombo> d_maps;
183

184
  MapCombo& getMap(const DNSName& qname)
185
  {
87,430✔
186
    return d_maps.at(qname.hash() % d_maps.size());
87,430✔
187
  }
87,430✔
188
  const MapCombo& getMap(const DNSName& qname) const
189
  {
×
190
    return d_maps.at(qname.hash() % d_maps.size());
×
191
  }
×
192
};
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc