Coverage Report

Created: 2026-08-31 06:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pdns/pdns/dnsdistdist/dnsdist-cache.hh
Line
Count
Source
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 <atomic>
25
#include <unordered_map>
26
27
#include "iputils.hh"
28
#include "lock.hh"
29
#include "noinitvector.hh"
30
#include "stat_t.hh"
31
#include "ednsoptions.hh"
32
33
struct DNSQuestion;
34
35
class DNSDistPacketCache : boost::noncopyable
36
{
37
public:
38
  struct CacheSettings
39
  {
40
    std::unordered_set<uint16_t> d_optionsToSkip{EDNSOptionCode::COOKIE, EDNSOptionCode::PADDING};
41
    std::vector<uint16_t> d_payloadRanks{};
42
    size_t d_maxEntries{0};
43
    size_t d_maximumEntrySize{4096};
44
    uint32_t d_maxTTL{86400};
45
    uint32_t d_minTTL{0};
46
    uint32_t d_tempFailureTTL{60};
47
    uint32_t d_maxNegativeTTL{3600};
48
    uint32_t d_truncatedTTL{0};
49
    uint32_t d_staleTTL{60};
50
    uint32_t d_shardCount{1};
51
    bool d_dontAge{false};
52
    bool d_deferrableInsertLock{true};
53
    bool d_parseECS{false};
54
    bool d_keepStaleData{false};
55
    bool d_shuffle{false};
56
  };
57
58
  DNSDistPacketCache(CacheSettings settings);
59
60
  void insert(uint32_t key, const std::optional<Netmask>& subnet, uint16_t queryFlags, bool dnssecOK, const DNSName& qname, uint16_t qtype, uint16_t qclass, const PacketBuffer& response, bool receivedOverUDP, uint8_t rcode, std::optional<uint32_t> tempFailureTTL);
61
  bool get(DNSQuestion& dnsQuestion, uint16_t queryId, uint32_t* keyOut, std::optional<Netmask>& subnet, bool dnssecOK, bool receivedOverUDP, uint32_t allowExpired = 0, bool skipAging = false, bool truncatedOK = true, bool recordMiss = true);
62
  size_t purgeExpired(size_t upTo, time_t now);
63
  size_t expunge(size_t upTo = 0);
64
  size_t expungeByName(const DNSName& name, uint16_t qtype = QType::ANY, bool suffixMatch = false);
65
  size_t expungeByName(const std::vector<DNSName>& names, uint16_t qtype = QType::ANY, bool suffixMatch = false);
66
  [[nodiscard]] bool isFull();
67
  [[nodiscard]] string toString();
68
  [[nodiscard]] uint64_t getSize();
69
0
  [[nodiscard]] uint64_t getHits() const { return d_hits.load(); }
70
0
  [[nodiscard]] uint64_t getMisses() const { return d_misses.load(); }
71
0
  [[nodiscard]] uint64_t getDeferredLookups() const { return d_deferredLookups.load(); }
72
0
  [[nodiscard]] uint64_t getDeferredInserts() const { return d_deferredInserts.load(); }
73
0
  [[nodiscard]] uint64_t getLookupCollisions() const { return d_lookupCollisions.load(); }
74
0
  [[nodiscard]] uint64_t getInsertCollisions() const { return d_insertCollisions.load(); }
75
0
  [[nodiscard]] uint64_t getMaxEntries() const { return d_settings.d_maxEntries; }
76
0
  [[nodiscard]] uint64_t getTTLTooShorts() const { return d_ttlTooShorts.load(); }
77
0
  [[nodiscard]] uint64_t getCleanupCount() const { return d_cleanupCount.load(); }
78
  [[nodiscard]] uint64_t getEntriesCount();
79
  uint64_t dump(int fileDesc, bool rawResponse = false);
80
81
  /* get the list of domains (qnames) that contains the given address in an A or AAAA record */
82
  [[nodiscard]] std::set<DNSName> getDomainsContainingRecords(const ComboAddress& addr);
83
  /* get the list of IP addresses contained in A or AAAA for a given domains (qname) */
84
  [[nodiscard]] std::set<ComboAddress> getRecordsForDomain(const DNSName& domain);
85
86
0
  [[nodiscard]] bool isECSParsingEnabled() const { return d_settings.d_parseECS; }
87
88
  [[nodiscard]] bool keepStaleData() const
89
0
  {
90
0
    return d_settings.d_keepStaleData;
91
0
  }
92
93
0
  [[nodiscard]] size_t getMaximumEntrySize() const { return d_settings.d_maximumEntrySize; }
94
95
  uint32_t getKey(const DNSName::string_t& qname, size_t qnameWireLength, const PacketBuffer& packet, bool receivedOverUDP) const;
96
97
  static uint32_t getMinTTL(const char* packet, uint16_t length, bool* seenNoDataSOA);
98
  static bool getClientSubnet(const PacketBuffer& packet, size_t qnameWireLength, std::optional<Netmask>& subnet);
99
100
private:
101
  struct CacheValue
102
  {
103
0
    [[nodiscard]] time_t getTTD() const { return validity; }
104
    std::string value;
105
    DNSName qname;
106
    std::optional<Netmask> subnet;
107
    uint16_t qtype{0};
108
    uint16_t qclass{0};
109
    uint16_t queryFlags{0};
110
    time_t added{0};
111
    time_t validity{0};
112
    uint16_t len{0};
113
    bool receivedOverUDP{false};
114
    bool dnssecOK{false};
115
  };
116
117
  class CacheShard
118
  {
119
  public:
120
0
    CacheShard() = default;
121
    CacheShard(CacheShard&& /* old */) noexcept
122
0
    {
123
0
    }
124
    CacheShard(const CacheShard& /* old */)
125
0
    {
126
0
    }
127
    CacheShard& operator=(CacheShard&& /* old */) noexcept
128
0
    {
129
0
      return *this;
130
0
    }
131
    CacheShard& operator=(const CacheShard& /* old */)
132
0
    {
133
0
      return *this;
134
0
    }
135
0
    ~CacheShard() = default;
136
137
    void setSize(size_t maxSize)
138
0
    {
139
0
      d_map.write_lock()->reserve(maxSize);
140
0
    }
141
142
    SharedLockGuarded<std::unordered_map<uint32_t, CacheValue>> d_map{};
143
    std::atomic<uint64_t> d_entriesCount{0};
144
  };
145
146
  [[nodiscard]] bool cachedValueMatches(const CacheValue& cachedValue, uint16_t queryFlags, const DNSName& qname, uint16_t qtype, uint16_t qclass, bool receivedOverUDP, bool dnssecOK, const std::optional<Netmask>& subnet) const;
147
  [[nodiscard]] uint32_t getShardIndex(uint32_t key) const;
148
  bool insertLocked(std::unordered_map<uint32_t, CacheValue>& map, uint32_t key, CacheValue& newValue);
149
150
  std::vector<CacheShard> d_shards{};
151
152
  pdns::stat_t d_deferredLookups{0};
153
  pdns::stat_t d_deferredInserts{0};
154
  pdns::stat_t d_hits{0};
155
  pdns::stat_t d_misses{0};
156
  pdns::stat_t d_insertCollisions{0};
157
  pdns::stat_t d_lookupCollisions{0};
158
  pdns::stat_t d_ttlTooShorts{0};
159
  pdns::stat_t d_cleanupCount{0};
160
161
  CacheSettings d_settings;
162
};