Coverage Report

Created: 2026-10-03 06:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pdns/pdns/dnsdistdist/dnsdist-kvs.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 <memory>
25
#include "dnsdist.hh"
26
#include "logr.hh"
27
#include "dnsdist-lua-types.hh"
28
#include "ext/json11/json11.hpp"
29
#include "iputils.hh"
30
31
class KeyValueLookupKey
32
{
33
public:
34
  virtual ~KeyValueLookupKey()
35
0
  {
36
0
  }
37
  virtual std::vector<std::string> getKeys(const DNSQuestion&) = 0;
38
  virtual std::string toString() const = 0;
39
};
40
41
class KeyValueLookupKeySourceIP : public KeyValueLookupKey
42
{
43
public:
44
  KeyValueLookupKeySourceIP(uint8_t v4Mask, uint8_t v6Mask, bool includePort) :
45
    d_v4Mask(v4Mask), d_v6Mask(v6Mask), d_includePort(includePort)
46
0
  {
47
0
  }
48
49
  std::vector<std::string> getKeys(const ComboAddress& addr);
50
51
  std::vector<std::string> getKeys(const DNSQuestion& dq) override
52
0
  {
53
0
    return getKeys(dq.ids.origRemote);
54
0
  }
55
56
  std::string toString() const override
57
0
  {
58
0
    return "source IP (masked to " + std::to_string(d_v4Mask) + " (v4) / " + std::to_string(d_v6Mask) + " (v6) bits)" + (d_includePort ? " including the port" : "");
59
0
  }
60
61
private:
62
  uint8_t d_v4Mask;
63
  uint8_t d_v6Mask;
64
  bool d_includePort;
65
};
66
67
class KeyValueLookupKeyQName : public KeyValueLookupKey
68
{
69
public:
70
  KeyValueLookupKeyQName(bool wireFormat) :
71
    d_wireFormat(wireFormat)
72
0
  {
73
0
  }
74
75
  std::vector<std::string> getKeys(const DNSName& qname)
76
0
  {
77
0
    if (d_wireFormat) {
78
0
      return {qname.toDNSStringLC()};
79
0
    }
80
0
    return {qname.makeLowerCase().toStringRootDot()};
81
0
  }
82
83
  std::vector<std::string> getKeys(const DNSQuestion& dq) override
84
0
  {
85
0
    return getKeys(dq.ids.qname);
86
0
  }
87
88
  std::string toString() const override
89
0
  {
90
0
    if (d_wireFormat) {
91
0
      return "qname in wire format";
92
0
    }
93
0
    return "qname";
94
0
  }
95
96
private:
97
  bool d_wireFormat;
98
};
99
100
class KeyValueLookupKeySuffix : public KeyValueLookupKey
101
{
102
public:
103
  KeyValueLookupKeySuffix(size_t minLabels, bool wireFormat) :
104
    d_minLabels(minLabels), d_wireFormat(wireFormat)
105
0
  {
106
0
  }
107
108
  std::vector<std::string> getKeys(const DNSName& qname);
109
110
  std::vector<std::string> getKeys(const DNSQuestion& dq) override
111
0
  {
112
0
    return getKeys(dq.ids.qname);
113
0
  }
114
115
  std::string toString() const override
116
0
  {
117
0
    if (d_minLabels > 0) {
118
0
      return "suffix " + std::string(d_wireFormat ? "in wire format " : "") + "with at least " + std::to_string(d_minLabels) + " label(s)";
119
0
    }
120
0
    return "suffix" + std::string(d_wireFormat ? " in wire format" : "");
121
0
  }
122
123
private:
124
  size_t d_minLabels;
125
  bool d_wireFormat;
126
};
127
128
class KeyValueLookupKeyTag : public KeyValueLookupKey
129
{
130
public:
131
  KeyValueLookupKeyTag(const std::string& tag) :
132
    d_tag(tag)
133
0
  {
134
0
  }
135
136
  std::vector<std::string> getKeys(const DNSQuestion& dq) override
137
0
  {
138
0
    if (dq.ids.qTag) {
139
0
      const auto& it = dq.ids.qTag->find(d_tag);
140
0
      if (it != dq.ids.qTag->end()) {
141
0
        return {it->second};
142
0
      }
143
0
    }
144
0
    return {};
145
0
  }
146
147
  std::string toString() const override
148
0
  {
149
0
    return "value of the tag named '" + d_tag + "'";
150
0
  }
151
152
private:
153
  std::string d_tag;
154
};
155
156
class KeyValueStore
157
{
158
public:
159
  virtual ~KeyValueStore()
160
0
  {
161
0
  }
162
163
  virtual bool keyExists(const std::string& key) = 0;
164
  virtual bool getValue(const std::string& key, std::string& value) = 0;
165
  // do a range-based lookup (mostly useful for IP addresses), assuming that:
166
  // there is a key for the last element of the range (2001:0db8:ffff:ffff:ffff:ffff:ffff:ffff, in network byte order, for 2001:db8::/32)
167
  // which contains the first element of the range (2001:0db8:0000:0000:0000:0000:0000:0000, in network bytes order) followed by any data in the value
168
  // AND there is no overlapping ranges in the database !!
169
  // This requires that the underlying store supports ordered keys, which is true for LMDB but not for CDB, for example.
170
  virtual bool getRangeValue(const std::string& key, std::string& value)
171
0
  {
172
0
    (void)key;
173
0
    (void)value;
174
0
    throw std::runtime_error("range-based lookups are not implemented for this Key-Value Store");
175
0
  }
176
  virtual bool reload()
177
0
  {
178
0
    return false;
179
0
  }
180
};
181
182
#ifdef HAVE_LMDB
183
184
#include "ext/lmdb-safe/lmdb-safe.hh"
185
186
class LMDBKVStore : public KeyValueStore
187
{
188
public:
189
  LMDBKVStore(const std::string& fname, const std::string& dbName, bool noLock = false) :
190
    d_env(getMDBEnv(fname.c_str(), noLock ? MDB_NOSUBDIR | MDB_RDONLY | MDB_NOLOCK : MDB_NOSUBDIR | MDB_RDONLY, 0600, 0, 0)), d_dbi(d_env->openDB(dbName, 0)), d_fname(fname), d_dbName(dbName)
191
  {
192
  }
193
194
  bool keyExists(const std::string& key) override;
195
  bool getValue(const std::string& key, std::string& value) override;
196
  bool getRangeValue(const std::string& key, std::string& value) override;
197
198
private:
199
  std::shared_ptr<const Logr::Logger> getLogger() const;
200
201
  std::shared_ptr<MDBEnv> d_env;
202
  MDBDbi d_dbi;
203
  std::string d_fname;
204
  std::string d_dbName;
205
};
206
207
#endif /* HAVE_LMDB */
208
209
#ifdef HAVE_CDB
210
211
#include "cdb.hh"
212
213
class CDBKVStore : public KeyValueStore
214
{
215
public:
216
  CDBKVStore(const std::string& fname, time_t refreshDelay);
217
  ~CDBKVStore();
218
219
  bool keyExists(const std::string& key) override;
220
  bool getValue(const std::string& key, std::string& value) override;
221
  bool reload() override;
222
223
private:
224
  std::shared_ptr<const Logr::Logger> getLogger() const;
225
  void refreshDBIfNeeded(time_t now);
226
  bool reload(const struct stat& st);
227
228
  LockGuarded<std::unique_ptr<CDB>> d_cdb{nullptr};
229
  std::string d_fname;
230
  time_t d_mtime{0};
231
  time_t d_nextCheck{0};
232
  time_t d_refreshDelay{0};
233
  std::atomic_flag d_refreshing;
234
};
235
236
#endif /* HAVE_LMDB */
237
238
#ifdef HAVE_MMDB
239
240
#include <boost/variant.hpp>
241
#include "mmdb.hh"
242
243
class MMDBKVStore : public KeyValueStore
244
{
245
public:
246
  MMDBKVStore(const std::shared_ptr<MMDB>& mmdb, const LuaTypeOrArrayOf<std::string>& queryParams) :
247
    d_mmdb(mmdb), d_originalParams(queryParams), d_queryParams(MMDBQueryParams(d_originalParams)) {};
248
249
  bool keyExists(const std::string& key) override;
250
  bool getValue(const std::string& key, std::string& value) override;
251
  bool reload() override
252
  {
253
    return true;
254
  }
255
256
private:
257
  [[nodiscard]] std::shared_ptr<const Logr::Logger> getLogger() const;
258
  json11::Json parseAny(const LuaAny& any);
259
260
  std::shared_ptr<MMDB> d_mmdb;
261
  const LuaTypeOrArrayOf<std::string> d_originalParams;
262
  const MMDBQueryParams d_queryParams;
263
};
264
#endif // HAVE_MMDB