)
;;
lmdb)
+ needlmdb=yes
PDNS_CHECK_LMDB
BOOST_SERIALIZATION
;;
PDNS_CHECK_SQLITE3
AM_CONDITIONAL([SQLITE3], [test "x$needsqlite3" = "xyes"])
+AM_CONDITIONAL([LMDB], [test "x$needlmdb" != "x"])
+AM_CONDITIONAL([HAVE_LMDB], [test "x$LMDB_LIBS" != "x"])
+
+AS_IF([test "x$needlmdb" = "xyes"], [
+ AS_IF([test "$with_lmdb" = "no"], [
+ AC_MSG_ERROR([--with-lmdb is set to 'no', but lmdb support is required])
+ ])
+ AS_IF([test "x$HAVE_LMDB" != "x1"], [
+ AC_MSG_ERROR([lmdb not found via pkg-config, please install lmdb or set --with-lmdb to your lmdb installation directory])
+ ])
+])
+
for a in $modules; do
AC_MSG_CHECKING([whether we can build module "${a}"])
if [[ -d "$srcdir/modules/${a}backend" ]]; then
AS_IF([test "$with_lmdb" != "no"], [
AS_IF([test "x$with_lmdb" = "xyes" -o "x$with_lmdb" = "xauto"], [
- PKG_CHECK_MODULES([LMDB], [lmdb], [ : ], [
- AC_MSG_ERROR([lmdb not found via pkg-config, please install lmdb or set --with-lmdb to your lmdb installation directory])
- ])
+ PKG_CHECK_MODULES([LMDB], [lmdb], [
+ AC_DEFINE([HAVE_LMDB], [1], [Define to 1 if you have LMDB])
+ [HAVE_LMDB=1]
+ ], [ : ]
+ )
], [
save_CPPFLAGS=$CPPFLAGS
save_LIBS=$LIBS
AC_CHECK_HEADERS([lmdb.h], [
dnl ac_cv_search_mdb_env_open contains '-llmdb'
LMDB_LIBS="$LMDB_LIBS $ac_cv_search_mdb_env_open"
+ AC_DEFINE([HAVE_LMDB], [1], [Define to 1 if you have LMDB])
+ [HAVE_LMDB=1]
], [
AC_MSG_ERROR([lmdb headers not found in $with_lmdb])
])
AC_SUBST([LMDB_LIBS])
])
])
- ], [
- AC_MSG_ERROR([--with-lmdb is set to 'no', but lmdb support is required])
])
+ AM_CONDITIONAL([HAVE_LMDB], [test "x$LMDB_LIBS" != "x"])
])
EXTRA_DIST = OBJECTFILES OBJECTLIBS
-liblmdbbackend_la_SOURCES = lmdbbackend.cc lmdbbackend.hh lmdb-safe.hh lmdb-safe.cc lmdb-typed.hh lmdb-typed.cc
+liblmdbbackend_la_SOURCES = lmdbbackend.cc lmdbbackend.hh lmdb-typed.hh lmdb-typed.cc \
+ ../../pdns/lmdb-safe.hh ../../pdns/lmdb-safe.cc
liblmdbbackend_la_LDFLAGS = -module -avoid-version
-liblmdbbackend_la_LIBADD = $(LMDB_LIBS) $(BOOST_SERIALIZATION_LIBS)
\ No newline at end of file
+liblmdbbackend_la_LIBADD = $(LMDB_LIBS) $(BOOST_SERIALIZATION_LIBS)
#pragma once
#include <iostream>
-#include "lmdb-safe.hh"
+#include "pdns/lmdb-safe.hh"
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/vector.hpp>
AM_CPPFLAGS +=$(LIBSODIUM_CFLAGS)
endif
+if LMDB
+AM_CPPFLAGS +=$(LMDB_CFLAGS)
+endif
+
EXTRA_DIST = \
dnslabeltext.rl \
dnslabeltext.cc \
pdns_server_LDADD += $(LIBDECAF_LIBS)
endif
+if LMDB
+pdns_server_LDADD += $(LMDB_LIBS)
+endif
+
if SQLITE3
pdns_server_SOURCES += ssqlite3.cc ssqlite3.hh
pdns_server_LDADD += $(SQLITE3_LIBS)
#include "dnsdist-ecs.hh"
#include "dnsdist-lua.hh"
#include "dnsdist-protobuf.hh"
+#include "dnsdist-kvs.hh"
#include "dolog.hh"
#include "dnstap.hh"
std::shared_ptr<DNSAction> d_action;
};
-
#ifdef HAVE_DNS_OVER_HTTPS
class HTTPStatusAction: public DNSAction
{
};
#endif /* HAVE_DNS_OVER_HTTPS */
+class KeyValueStoreLookupAction : public DNSAction
+{
+public:
+ KeyValueStoreLookupAction(std::shared_ptr<KeyValueStore>& kvs, std::shared_ptr<KeyValueLookupKey>& lookupKey, const std::string& destinationTag): d_kvs(kvs), d_key(lookupKey), d_tag(destinationTag)
+ {
+ }
+
+ DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
+ {
+ std::string key = d_key->getKey(*dq);
+ std::string result = d_kvs->getValue(key);
+
+ if (!dq->qTag) {
+ dq->qTag = std::make_shared<QTag>();
+ }
+
+ dq->qTag->insert({d_tag, std::move(result)});
+
+ return Action::None;
+ }
+
+ std::string toString() const override
+ {
+ return "lookup key-value store based on '" + d_key->toString() + "' and set the result in tag '" + d_tag + "'";
+ }
+
+private:
+ std::shared_ptr<KeyValueStore> d_kvs;
+ std::shared_ptr<KeyValueLookupKey> d_key;
+ std::string d_tag;
+};
+
template<typename T, typename ActionT>
static void addAction(GlobalStateHolder<vector<T> > *someRulActions, luadnsrule_t var, std::shared_ptr<ActionT> action, boost::optional<luaruleparams_t> params) {
setLuaSideEffect();
return std::shared_ptr<DNSAction>(new HTTPStatusAction(status, body, contentType ? *contentType : ""));
});
#endif /* HAVE_DNS_OVER_HTTPS */
+
+ g_lua.writeFunction("KeyValueStoreLookupAction", [](std::shared_ptr<KeyValueStore>& kvs, std::shared_ptr<KeyValueLookupKey>& lookupKey, const std::string& destinationTag) {
+ return std::shared_ptr<DNSAction>(new KeyValueStoreLookupAction(kvs, lookupKey, destinationTag));
+ });
}
#include "config.h"
#include "dnsdist.hh"
+#include "dnsdist-kvs.hh"
#include "dnsdist-lua.hh"
#include "dnsdist-protobuf.hh"
}
return values;
});
+
+ /* Key Value Store objects */
+ g_lua.writeFunction("KeyValueLookupKeySourceIP", []() {
+ return std::shared_ptr<KeyValueLookupKey>(new KeyValueLookupKeySourceIP());
+ });
+ g_lua.writeFunction("KeyValueLookupKeyQName", []() {
+ return std::shared_ptr<KeyValueLookupKey>(new KeyValueLookupKeyQName());
+ });
+ g_lua.writeFunction("KeyValueLookupKeyTag", [](const std::string& tag) {
+ return std::shared_ptr<KeyValueLookupKey>(new KeyValueLookupKeyTag(tag));
+ });
+
+#ifdef HAVE_LMDB
+ g_lua.writeFunction("newLMDBKVStore", [client](const std::string& fname, const std::string& dbName) {
+ if (client) {
+ return std::shared_ptr<KeyValueStore>(nullptr);
+ }
+ return std::shared_ptr<KeyValueStore>(new LMDBKVStore(fname, dbName));
+ });
+#endif /* HAVE_LMDB */
+
}
#ifdef HAVE_LIBSODIUM
cout<<"libsodium ";
#endif
+#ifdef HAVE_LMDB
+ cout<<"lmdb ";
+#endif
#ifdef HAVE_PROTOBUF
cout<<"protobuf ";
#endif
AM_CPPFLAGS += $(LIBCRYPTO_INCLUDES)
endif
+if HAVE_LMDB
+AM_CPPFLAGS += $(LMDB_CFLAGS)
+endif
+
if HAVE_DNS_OVER_HTTPS
if HAVE_LIBSSL
AM_CPPFLAGS += $(LIBSSL_CFLAGS)
dnsdist-dynblocks.hh \
dnsdist-ecs.cc dnsdist-ecs.hh \
dnsdist-idstate.cc \
+ dnsdist-kvs.hh dnsdist-kvs.cc \
dnsdist-lua.hh dnsdist-lua.cc \
dnsdist-lua-actions.cc \
dnsdist-lua-bindings.cc \
ext/incbin/incbin.h \
ext/libbpf/libbpf.h
+testrunner_SOURCES = \
+ base64.hh \
+ dns.hh \
+ test-base64_cc.cc \
+ test-delaypipe_hh.cc \
+ test-dnscrypt_cc.cc \
+ test-dnsdist_cc.cc \
+ test-dnsdistdynblocks_hh.cc \
+ test-dnsdistkvs_cc.cc \
+ test-dnsdistpacketcache_cc.cc \
+ test-dnsdistrings_cc.cc \
+ test-dnsdistrules_cc.cc \
+ test-dnsparser_cc.cc \
+ test-iputils_hh.cc \
+ test-mplexer.cc \
+ cachecleaner.hh \
+ circular_buffer.hh \
+ dnsdist.hh \
+ dnsdist-cache.cc dnsdist-cache.hh \
+ dnsdist-ecs.cc dnsdist-ecs.hh \
+ dnsdist-kvs.cc dnsdist-kvs.hh \
+ dnsdist-rings.hh \
+ dnsdist-xpf.cc dnsdist-xpf.hh \
+ dnscrypt.cc dnscrypt.hh \
+ dnslabeltext.cc \
+ dnsname.cc dnsname.hh \
+ dnsparser.hh dnsparser.cc \
+ dnswriter.cc dnswriter.hh \
+ dolog.hh \
+ ednsoptions.cc ednsoptions.hh \
+ ednscookies.cc ednscookies.hh \
+ ednssubnet.cc ednssubnet.hh \
+ gettime.cc gettime.hh \
+ iputils.cc iputils.hh \
+ misc.cc misc.hh \
+ namespaces.hh \
+ pdnsexception.hh \
+ pollmplexer.cc \
+ qtype.cc qtype.hh \
+ sholder.hh \
+ sodcrypto.cc \
+ sstuff.hh \
+ statnode.cc statnode.hh \
+ threadname.hh threadname.cc \
+ testrunner.cc \
+ xpf.cc xpf.hh
+
dnsdist_LDFLAGS = \
$(AM_LDFLAGS) \
$(PROGRAM_LDFLAGS) \
$(LIBCAP_LIBS) \
$(IPCRYPT_LIBS)
+testrunner_LDFLAGS = \
+ $(AM_LDFLAGS) \
+ $(PROGRAM_LDFLAGS) \
+ $(BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS) \
+ -pthread
+
+testrunner_LDADD = \
+ $(BOOST_UNIT_TEST_FRAMEWORK_LIBS) \
+ $(LIBSODIUM_LIBS) \
+ $(FSTRM_LIBS) \
+ $(RT_LIBS) \
+ $(SANITIZER_FLAGS) \
+ $(LIBCAP_LIBS)
+
if HAVE_RE2
dnsdist_LDADD += $(RE2_LIBS)
endif
dnsdist_SOURCES += ipcipher.cc ipcipher.hh
endif
+if HAVE_LMDB
+dnsdist_LDADD += $(LMDB_LDFLAGS) $(LMDB_LIBS)
+testrunner_LDADD += $(LMDB_LDFLAGS) $(LMDB_LIBS)
+dnsdist_SOURCES += lmdb-safe.cc lmdb-safe.hh
+testrunner_SOURCES += lmdb-safe.cc lmdb-safe.hh
+endif
+
if HAVE_DNS_OVER_TLS
if HAVE_GNUTLS
dnsdist_LDADD += -lgnutls
endif
endif
-testrunner_SOURCES = \
- base64.hh \
- dns.hh \
- test-base64_cc.cc \
- test-delaypipe_hh.cc \
- test-dnscrypt_cc.cc \
- test-dnsdist_cc.cc \
- test-dnsdistdynblocks_hh.cc \
- test-dnsdistpacketcache_cc.cc \
- test-dnsdistrings_cc.cc \
- test-dnsdistrules_cc.cc \
- test-dnsparser_cc.cc \
- test-iputils_hh.cc \
- test-mplexer.cc \
- cachecleaner.hh \
- circular_buffer.hh \
- dnsdist.hh \
- dnsdist-cache.cc dnsdist-cache.hh \
- dnsdist-ecs.cc dnsdist-ecs.hh \
- dnsdist-rings.hh \
- dnsdist-xpf.cc dnsdist-xpf.hh \
- dnscrypt.cc dnscrypt.hh \
- dnslabeltext.cc \
- dnsname.cc dnsname.hh \
- dnsparser.hh dnsparser.cc \
- dnswriter.cc dnswriter.hh \
- dolog.hh \
- ednsoptions.cc ednsoptions.hh \
- ednscookies.cc ednscookies.hh \
- ednssubnet.cc ednssubnet.hh \
- gettime.cc gettime.hh \
- iputils.cc iputils.hh \
- misc.cc misc.hh \
- namespaces.hh \
- pdnsexception.hh \
- pollmplexer.cc \
- qtype.cc qtype.hh \
- sholder.hh \
- sodcrypto.cc \
- sstuff.hh \
- statnode.cc statnode.hh \
- threadname.hh threadname.cc \
- testrunner.cc \
- xpf.cc xpf.hh
-
if HAVE_FREEBSD
dnsdist_SOURCES += kqueuemplexer.cc
testrunner_SOURCES += kqueuemplexer.cc
portsmplexer.cc
endif
-testrunner_LDFLAGS = \
- $(AM_LDFLAGS) \
- $(PROGRAM_LDFLAGS) \
- $(BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS) \
- -pthread
-
-testrunner_LDADD = \
- $(BOOST_UNIT_TEST_FRAMEWORK_LIBS) \
- $(LIBSODIUM_LIBS) \
- $(FSTRM_LIBS) \
- $(RT_LIBS) \
- $(SANITIZER_FLAGS) \
- $(LIBCAP_LIBS)
-
MANPAGES=dnsdist.1
dist_man_MANS=$(MANPAGES)
AM_CONDITIONAL([HAVE_GNUTLS], [false])
AM_CONDITIONAL([HAVE_LIBSSL], [false])
+AM_CONDITIONAL([HAVE_LMDB], [false])
PDNS_CHECK_LIBCRYPTO
])
])
+PDNS_CHECK_LMDB
+
AX_CXX_COMPILE_STDCXX_11([ext], [mandatory])
AC_MSG_CHECKING([whether we will enable compiler security checks])
[AC_MSG_NOTICE([OpenSSL: no])]
)]
)
+AS_IF([test "x$LMDB_LIBS" != "x"],
+ [AC_MSG_NOTICE([lmdb: yes])],
+ [AC_MSG_NOTICE([lmdb: no])]
+)
AC_MSG_NOTICE([])
--- /dev/null
+/*
+ * 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.
+ */
+
+#include "dnsdist-kvs.hh"
+#include "dolog.hh"
+
+#ifdef HAVE_LMDB
+
+#include "lmdb-safe.hh"
+
+std::string LMDBKVStore::getValue(const std::string& key)
+{
+ string_view result;
+ try {
+ auto transaction = d_env.getROTransaction();
+ auto dbi = transaction.openDB(d_dbName, 0);
+ int rc = transaction.get(dbi, MDBInVal(key), result);
+ if (rc == 0) {
+ return result.to_string();
+ }
+ else if (rc == MDB_NOTFOUND) {
+ return std::string();
+ }
+ }
+ catch(const std::exception& e) {
+ warnlog("Error while looking up key '%s' from LMDB file '%s', database '%s': %s", key, d_fname, d_dbName);
+ }
+ return std::string();
+}
+
+#endif /* HAVE_LMDB */
--- /dev/null
+/*
+ * 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::string getKey(const DNSQuestion&) = 0;
+ virtual std::string toString() const = 0;
+};
+
+class KeyValueLookupKeySourceIP: public KeyValueLookupKey
+{
+public:
+ std::string getKey(const DNSQuestion& dq) override
+ {
+ std::string key;
+ if (dq.remote->sin4.sin_family == AF_INET) {
+ key = std::string(reinterpret_cast<const char*>(&dq.remote->sin4.sin_addr.s_addr), sizeof(dq.remote->sin4.sin_addr.s_addr));
+ }
+ else if (dq.remote->sin4.sin_family == AF_INET6) {
+ key = std::string(reinterpret_cast<const char*>(&dq.remote->sin6.sin6_addr.s6_addr), sizeof(dq.remote->sin6.sin6_addr.s6_addr));
+ }
+ return key;
+ }
+
+ std::string toString() const override
+ {
+ return "source IP";
+ }
+};
+
+class KeyValueLookupKeyQName: public KeyValueLookupKey
+{
+public:
+ std::string getKey(const DNSQuestion& dq) override
+ {
+ return dq.qname->toDNSStringLC();
+ }
+
+ std::string toString() const override
+ {
+ return "qname";
+ }
+};
+
+class KeyValueLookupKeyTag: public KeyValueLookupKey
+{
+public:
+ KeyValueLookupKeyTag(const std::string& tag): d_tag(tag)
+ {
+ }
+
+ std::string getKey(const DNSQuestion& dq) override
+ {
+ std::string key;
+ if (dq.qTag) {
+ const auto& it = dq.qTag->find(d_tag);
+ if (it != dq.qTag->end()) {
+ key = it->second;
+ }
+ }
+ return key;
+ }
+
+ std::string toString() const override
+ {
+ return " value of the tag named '" + d_tag + '"';
+ }
+
+private:
+ std::string d_tag;
+};
+
+class KeyValueStore
+{
+public:
+ virtual ~KeyValueStore()
+ {
+ }
+
+ virtual std::string getValue(const std::string& key) = 0;
+};
+
+#ifdef HAVE_LMDB
+
+#include "lmdb-safe.hh"
+
+class LMDBKVStore: public KeyValueStore
+{
+public:
+ LMDBKVStore(const std::string& fname, const std::string& dbName): d_env(fname.c_str(), MDB_NOSUBDIR, 0600), d_fname(fname), d_dbName(dbName)
+ {
+ }
+
+ std::string getValue(const std::string& key) override;
+
+private:
+ MDBEnv d_env;
+ std::string d_fname;
+ std::string d_dbName;
+};
+
+#endif /* HAVE_LMDB */
--- /dev/null
+../lmdb-safe.cc
\ No newline at end of file
--- /dev/null
+../lmdb-safe.hh
\ No newline at end of file
--- /dev/null
+../../../m4/pdns_check_lmdb.m4
\ No newline at end of file
--- /dev/null
+
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_NO_MAIN
+
+#include <boost/test/unit_test.hpp>
+
+#include "dnsdist-kvs.hh"
+
+BOOST_AUTO_TEST_SUITE(dnsdistkvs_cc)
+
+#ifdef HAVE_LMDB
+BOOST_AUTO_TEST_CASE(test_LMDB) {
+
+ auto lmdb = make_unique<LMDBKVStore>("/data/Dumps/lmdb", "db-name");
+ auto key = make_unique<KeyValueLookupKeySourceIP>();
+
+ DNSName qname("powerdns.com.");
+ uint16_t qtype = QType::A;
+ uint16_t qclass = QClass::IN;
+ ComboAddress lc("127.0.0.1:53");
+ ComboAddress rem("127.0.0.1:42");
+ struct dnsheader dh;
+ memset(&dh, 0, sizeof(dh));
+ size_t bufferSize = 0;
+ size_t queryLen = 0;
+ bool isTcp = false;
+ struct timespec queryRealTime;
+ gettime(&queryRealTime, true);
+ struct timespec expiredTime;
+ /* the internal QPS limiter does not use the real time */
+ gettime(&expiredTime);
+
+ DNSQuestion dq(&qname, qtype, qclass, qname.wirelength(), &lc, &rem, &dh, bufferSize, queryLen, isTcp, &queryRealTime);
+
+ DTime dt;
+ dt.set();
+ for (size_t idx = 0; idx < 10000000; idx++) {
+ std::string value = lmdb->getValue(key->getKey(dq));
+ BOOST_CHECK_EQUAL(value, "this is the value of the tag");
+ }
+ cerr<<dt.udiff()/1000/1000<<endl;
+}
+#endif /* HAVE_LMDB */
+
+BOOST_AUTO_TEST_SUITE_END()