summaryrefslogtreecommitdiffstats
path: root/dnsdist-kvs.hh
blob: 764a45c35c07532d2cae06b68681b06e426b248e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
/*
 * This file is part of PowerDNS or dnsdist.
 * Copyright -- PowerDNS.COM B.V. and its contributors
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of version 2 of the GNU General Public License as
 * published by the Free Software Foundation.
 *
 * In addition, for the avoidance of any doubt, permission is granted to
 * link this program with OpenSSL and to (re)distribute the binaries
 * produced as the result of such linking.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
#pragma once

#include "dnsdist.hh"

class KeyValueLookupKey
{
public:
  virtual ~KeyValueLookupKey()
  {
  }
  virtual std::vector<std::string> getKeys(const DNSQuestion&) = 0;
  virtual std::string toString() const = 0;
};

class KeyValueLookupKeySourceIP: public KeyValueLookupKey
{
public:
  KeyValueLookupKeySourceIP(uint8_t v4Mask, uint8_t v6Mask, bool includePort): d_v4Mask(v4Mask), d_v6Mask(v6Mask), d_includePort(includePort)
  {
  }

  std::vector<std::string> getKeys(const ComboAddress& addr);

  std::vector<std::string> getKeys(const DNSQuestion& dq) override
  {
    return getKeys(dq.ids.origRemote);
  }

  std::string toString() const override
  {
    return "source IP (masked to " + std::to_string(d_v4Mask) + " (v4) / " + std::to_string(d_v6Mask) + " (v6) bits)" + (d_includePort ? " including the port" : "");
  }
private:
  uint8_t d_v4Mask;
  uint8_t d_v6Mask;
  bool d_includePort;
};

class KeyValueLookupKeyQName: public KeyValueLookupKey
{
public:

  KeyValueLookupKeyQName(bool wireFormat): d_wireFormat(wireFormat)
  {
  }

  std::vector<std::string> getKeys(const DNSName& qname)
  {
    if (d_wireFormat) {
      return {qname.toDNSStringLC()};
    }
    return {qname.makeLowerCase().toStringRootDot()};
  }

  std::vector<std::string> getKeys(const DNSQuestion& dq) override
  {
    return getKeys(dq.ids.qname);
  }

  std::string toString() const override
  {
    if (d_wireFormat) {
      return "qname in wire format";
    }
    return "qname";
  }

private:
  bool d_wireFormat;
};

class KeyValueLookupKeySuffix: public KeyValueLookupKey
{
public:
  KeyValueLookupKeySuffix(size_t minLabels, bool wireFormat): d_minLabels(minLabels), d_wireFormat(wireFormat)
  {
  }

  std::vector<std::string> getKeys(const DNSName& qname);

  std::vector<std::string> getKeys(const DNSQuestion& dq) override
  {
    return getKeys(dq.ids.qname);
  }

  std::string toString() const override
  {
    if (d_minLabels > 0) {
      return "suffix " + std::string(d_wireFormat ? "in wire format " : "") + "with at least " + std::to_string(d_minLabels) + " label(s)";
    }
    return "suffix" + std::string(d_wireFormat ? " in wire format" : "");
  }

private:
  size_t d_minLabels;
  bool d_wireFormat;
};

class KeyValueLookupKeyTag: public KeyValueLookupKey
{
public:
  KeyValueLookupKeyTag(const std::string& tag): d_tag(tag)
  {
  }

  std::vector<std::string> getKeys(const DNSQuestion& dq) override
  {
    if (dq.ids.qTag) {
      const auto& it = dq.ids.qTag->find(d_tag);
      if (it != dq.ids.qTag->end()) {
        return { it->second };
      }
    }
    return {};
  }

  std::string toString() const override
  {
    return "value of the tag named '" + d_tag + "'";
  }

private:
  std::string d_tag;
};

class KeyValueStore
{
public:
  virtual ~KeyValueStore()
  {
  }

  virtual bool keyExists(const std::string& key) = 0;
  virtual bool getValue(const std::string& key, std::string& value) = 0;
  // do a range-based lookup (mostly useful for IP addresses), assuming that:
  // 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)
  // 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
  // AND there is no overlapping ranges in the database !!
  // This requires that the underlying store supports ordered keys, which is true for LMDB but not for CDB, for example.
  virtual bool getRangeValue(const std::string& key, std::string& value)
  {
    throw std::runtime_error("range-based lookups are not implemented for this Key-Value Store");
  }
  virtual bool reload()
  {
    return false;
  }
};

#ifdef HAVE_LMDB

#include "ext/lmdb-safe/lmdb-safe.hh"

class LMDBKVStore: public KeyValueStore
{
public:
  LMDBKVStore(const std::string& fname, const std::string& dbName, bool noLock=false): d_env(fname.c_str(), noLock ? MDB_NOSUBDIR|MDB_RDONLY|MDB_NOLOCK : MDB_NOSUBDIR|MDB_RDONLY, 0600, 0), d_dbi(d_env.openDB(dbName, 0)), d_fname(fname), d_dbName(dbName)
  {
  }

  bool keyExists(const std::string& key) override;
  bool getValue(const std::string& key, std::string& value) override;
  bool getRangeValue(const std::string& key, std::string& value) override;

private:
  MDBEnv d_env;
  MDBDbi d_dbi;
  std::string d_fname;
  std::string d_dbName;
};

#endif /* HAVE_LMDB */

#ifdef HAVE_CDB

#include "cdb.hh"

class CDBKVStore: public KeyValueStore
{
public:
  CDBKVStore(const std::string& fname, time_t refreshDelay);
  ~CDBKVStore();

  bool keyExists(const std::string& key) override;
  bool getValue(const std::string& key, std::string& value) override;
  bool reload() override;

private:
  void refreshDBIfNeeded(time_t now);
  bool reload(const struct stat& st);

  SharedLockGuarded<std::unique_ptr<CDB>> d_cdb{nullptr};
  std::string d_fname;
  time_t d_mtime{0};
  time_t d_nextCheck{0};
  time_t d_refreshDelay{0};
  std::atomic_flag d_refreshing;
};

#endif /* HAVE_LMDB */