• 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

89.55
/pdns/recursordist/recpacketcache.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
#include <string>
24
#include <cinttypes>
25
#include "dns.hh"
26
#include "namespaces.hh"
27
#include <iostream>
28
#include <boost/multi_index_container.hpp>
29
#include <boost/multi_index/ordered_index.hpp>
30
#include <boost/multi_index/hashed_index.hpp>
31
#include <boost/multi_index/sequenced_index.hpp>
32
#include <boost/multi_index/key_extractors.hpp>
33
#include <boost/optional.hpp>
34

35
#include "packetcache.hh"
36
#include "validate.hh"
37
#include "lock.hh"
38
#include "stat_t.hh"
39

40
#ifdef HAVE_CONFIG_H
41
#include "config.h"
42
#endif
43

44
using namespace ::boost::multi_index;
45

46
class RecursorPacketCache : public PacketCache
47
{
48
public:
49
  static unsigned int s_refresh_ttlperc;
50

51
  struct PBData
52
  {
53
    std::string d_message;
54
    std::string d_response;
55
    bool d_tagged;
56
  };
57
  using OptPBData = boost::optional<PBData>;
58

59
  RecursorPacketCache(size_t maxsize, size_t shards = 1024) :
60
    d_maps(shards)
61
  {
156✔
62
    setMaxSize(maxsize);
156✔
63
  }
156✔
64

65
  bool getResponsePacket(unsigned int tag, const std::string& queryPacket, time_t now,
66
                         std::string* responsePacket, uint32_t* age, uint32_t* qhash)
67
  {
32✔
68
    DNSName qname;
32✔
69
    uint16_t qtype{0};
32✔
70
    uint16_t qclass{0};
32✔
71
    vState valState{vState::Indeterminate};
32✔
72
    return getResponsePacket(tag, queryPacket, qname, &qtype, &qclass, now, responsePacket, age, &valState, qhash, nullptr, false);
32✔
73
  }
32✔
74

75
  bool getResponsePacket(unsigned int tag, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, time_t now,
76
                         std::string* responsePacket, uint32_t* age, uint32_t* qhash)
77
  {
36✔
78
    vState valState{vState::Indeterminate};
36✔
79
    return getResponsePacket(tag, queryPacket, qname, qtype, qclass, now, responsePacket, age, &valState, qhash, nullptr, false);
36✔
80
  }
36✔
81

82
  bool getResponsePacket(unsigned int tag, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, time_t now, std::string* responsePacket, uint32_t* age, vState* valState, uint32_t* qhash, OptPBData* pbdata, bool tcp);
83
  bool getResponsePacket(unsigned int tag, const std::string& queryPacket, DNSName& qname, uint16_t* qtype, uint16_t* qclass, time_t now, std::string* responsePacket, uint32_t* age, vState* valState, uint32_t* qhash, OptPBData* pbdata, bool tcp);
84

85
  void insertResponsePacket(unsigned int tag, uint32_t qhash, std::string&& query, const DNSName& qname, uint16_t qtype, uint16_t qclass, std::string&& responsePacket, time_t now, uint32_t ttl, const vState& valState, OptPBData&& pbdata, bool tcp);
86
  void doPruneTo(time_t now, size_t maxSize);
87
  uint64_t doDump(int file);
88
  uint64_t doWipePacketCache(const DNSName& name, uint16_t qtype = 0xffff, bool subtree = false);
89

90
  void setMaxSize(size_t size)
91
  {
156✔
92
    if (size < d_maps.size()) {
156✔
93
      size = d_maps.size();
10✔
94
    }
10✔
95
    setShardSizes(size / d_maps.size());
156✔
96
  }
156✔
97

98
  [[nodiscard]] uint64_t size() const;
99
  [[nodiscard]] uint64_t bytes();
100
  [[nodiscard]] uint64_t getHits();
101
  [[nodiscard]] uint64_t getMisses();
102
  [[nodiscard]] pair<uint64_t, uint64_t> stats();
103

104
private:
105
  struct Entry
106
  {
107
    Entry(DNSName&& qname, uint16_t qtype, uint16_t qclass, std::string&& packet, std::string&& query, bool tcp,
108
          // NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
109
          uint32_t qhash, time_t ttd, time_t now, uint32_t tag, vState vstate) :
110
      d_name(std::move(qname)),
111
      d_packet(std::move(packet)),
112
      d_query(std::move(query)),
113
      d_ttd(ttd),
114
      d_creation(now),
115
      d_qhash(qhash),
116
      d_tag(tag),
117
      d_type(qtype),
118
      d_class(qclass),
119
      d_vstate(vstate),
120
      d_tcp(tcp)
121
    {
1,841✔
122
    }
1,841✔
123

124
    DNSName d_name;
125
    mutable std::string d_packet;
126
    mutable std::string d_query;
127
    mutable OptPBData d_pbdata;
128
    mutable time_t d_ttd;
129
    mutable time_t d_creation; // so we can 'age' our packets
130
    uint32_t d_qhash;
131
    uint32_t d_tag;
132
    uint16_t d_type;
133
    uint16_t d_class;
134
    mutable vState d_vstate;
135
    mutable bool d_submitted{false}; // whether this entry has been queued for refetch
136
    bool d_tcp; // whether this entry was created from a TCP query
137
    inline bool operator<(const struct Entry& rhs) const;
138

139
    bool isStale(time_t now) const
140
    {
1,391✔
141
      return d_ttd < now;
1,391✔
142
    }
1,391✔
143

144
    uint32_t getOrigTTL() const
145
    {
2,183✔
146
      return d_ttd - d_creation;
2,183✔
147
    }
2,183✔
148
  };
149

150
  struct HashTag
151
  {
152
  };
153
  struct NameTag
154
  {
155
  };
156
  struct SequencedTag
157
  {
158
  };
159
  using packetCache_t = multi_index_container<Entry,
160
                                              indexed_by<hashed_non_unique<tag<HashTag>,
161
                                                                           composite_key<Entry,
162
                                                                                         member<Entry, uint32_t, &Entry::d_tag>,
163
                                                                                         member<Entry, uint32_t, &Entry::d_qhash>,
164
                                                                                         member<Entry, bool, &Entry::d_tcp>>>,
165
                                                         sequenced<tag<SequencedTag>>,
166
                                                         ordered_non_unique<tag<NameTag>, member<Entry, DNSName, &Entry::d_name>, CanonDNSNameCompare>>>;
167

168
  struct MapCombo
169
  {
170
    MapCombo() = default;
159,744✔
171
    ~MapCombo() = default;
10,240✔
172
    MapCombo(const MapCombo&) = delete;
173
    MapCombo(MapCombo&&) = delete;
174
    MapCombo& operator=(const MapCombo&) = delete;
175
    MapCombo& operator=(MapCombo&&) = delete;
176

177
    struct LockedContent
178
    {
179
      packetCache_t d_map;
180
      size_t d_shardSize{0};
181
      uint64_t d_hits{0};
182
      uint64_t d_misses{0};
183
      uint64_t d_contended_count{0};
184
      uint64_t d_acquired_count{0};
185
      void invalidate() {}
44,044✔
186
      void preRemoval(const Entry& /* entry */) {}
33✔
187
    };
188

189
    LockGuardedTryHolder<MapCombo::LockedContent> lock()
190
    {
1,720,021✔
191
      auto locked = d_content.try_lock();
1,720,021✔
192
      if (!locked.owns_lock()) {
1,720,021!
193
        locked.lock();
×
194
        ++locked->d_contended_count;
×
195
      }
×
196
      ++locked->d_acquired_count;
1,720,021✔
197
      return locked;
1,720,021✔
198
    }
1,720,021✔
199

200
    [[nodiscard]] auto getEntriesCount() const
201
    {
361,264✔
202
      return d_entriesCount.load();
361,264✔
203
    }
361,264✔
204

205
    void incEntriesCount()
206
    {
1,841✔
207
      ++d_entriesCount;
1,841✔
208
    }
1,841✔
209

210
    void decEntriesCount()
211
    {
215✔
212
      --d_entriesCount;
215✔
213
    }
215✔
214

215
  private:
216
    LockGuarded<LockedContent> d_content;
217
    pdns::stat_t d_entriesCount{0};
218
  };
219

220
  vector<MapCombo> d_maps;
221

222
  static size_t combine(unsigned int tag, uint32_t hash, bool tcp)
223
  {
6,771✔
224
    size_t ret = 0;
6,771✔
225
    boost::hash_combine(ret, tag);
6,771✔
226
    boost::hash_combine(ret, hash);
6,771✔
227
    boost::hash_combine(ret, tcp);
6,771✔
228
    return ret;
6,771✔
229
  }
6,771✔
230

231
  MapCombo& getMap(unsigned int tag, uint32_t hash, bool tcp)
232
  {
6,770✔
233
    return d_maps.at(combine(tag, hash, tcp) % d_maps.size());
6,770✔
234
  }
6,770✔
235

236
  [[nodiscard]] const MapCombo& getMap(unsigned int tag, uint32_t hash, bool tcp) const
237
  {
×
238
    return d_maps.at(combine(tag, hash, tcp) % d_maps.size());
×
239
  }
×
240

241
  static bool qrMatch(const packetCache_t::index<HashTag>::type::iterator& iter, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass);
242
  static bool checkResponseMatches(MapCombo::LockedContent& shard, std::pair<packetCache_t::index<HashTag>::type::iterator, packetCache_t::index<HashTag>::type::iterator> range, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, time_t now, std::string* responsePacket, uint32_t* age, vState* valState, OptPBData* pbdata);
243

244
  void setShardSizes(size_t shardSize);
245
};
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