From 3cd01b932e1c85394272ae64fae67ebeda92fb00 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 13 Apr 2024 23:11:59 +0200 Subject: Adding upstream version 1.8.3. Signed-off-by: Daniel Baumann --- dnsdist-kvs.hh | 221 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 221 insertions(+) create mode 100644 dnsdist-kvs.hh (limited to 'dnsdist-kvs.hh') diff --git a/dnsdist-kvs.hh b/dnsdist-kvs.hh new file mode 100644 index 0000000..764a45c --- /dev/null +++ b/dnsdist-kvs.hh @@ -0,0 +1,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 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 getKeys(const ComboAddress& addr); + + std::vector 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 getKeys(const DNSName& qname) + { + if (d_wireFormat) { + return {qname.toDNSStringLC()}; + } + return {qname.makeLowerCase().toStringRootDot()}; + } + + std::vector 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 getKeys(const DNSName& qname); + + std::vector 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 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> 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 */ -- cgit v1.2.3