$(NET_SNMP_CFLAGS) \
$(NGHTTP2_CFLAGS) \
$(LIBCAP_CFLAGS) \
+ $(IPCRYPT2_CFLAGS) \
-I$(top_srcdir)/ext/protozero/include \
-I$(top_srcdir)/dnsdist-rust-lib \
-I$(top_builddir)/dnsdist-rust-lib \
dnsdist-rust-lib/rust \
ext/arc4random \
ext/ipcrypt \
+ ext/ipcrypt2 \
ext/yahttp
CLEANFILES = \
dnsdist-healthchecks.cc dnsdist-healthchecks.hh \
dnsdist-idstate.cc dnsdist-idstate.hh \
dnsdist-internal-queries.cc dnsdist-internal-queries.hh \
+ dnsdist-ipcrypt2.cc dnsdist-ipcrypt2.hh \
dnsdist-kvs.hh dnsdist-kvs.cc \
dnsdist-lbpolicies.cc dnsdist-lbpolicies.hh \
dnsdist-lua-actions.cc \
$(NET_SNMP_LIBS) \
$(LIBCAP_LIBS) \
$(IPCRYPT_LIBS) \
+ $(IPCRYPT2_LIBS) \
$(ARC4RANDOM_LIBS)
testrunner_LDFLAGS = \
AC_SUBST([YAHTTP_LIBS], ['$(top_builddir)/ext/yahttp/yahttp/libyahttp.la'])
AC_SUBST([IPCRYPT_CFLAGS], ['-I$(top_srcdir)/ext/ipcrypt'])
AC_SUBST([IPCRYPT_LIBS], ['$(top_builddir)/ext/ipcrypt/libipcrypt.la'])
+AC_SUBST([IPCRYPT2_CFLAGS], ['-I$(top_srcdir)/ext/ipcrypt2/include'])
+AC_SUBST([IPCRYPT2_LIBS], ['$(top_builddir)/ext/ipcrypt2/libipcrypt2.la'])
AC_SUBST([ARC4RANDOM_LIBS], ['$(top_builddir)/ext/arc4random/libarc4random.la'])
AC_CHECK_HEADERS([sys/random.h])
ext/arc4random/Makefile
ext/yahttp/Makefile
ext/yahttp/yahttp/Makefile
- ext/ipcrypt/Makefile])
+ ext/ipcrypt/Makefile
+ ext/ipcrypt2/Makefile])
AC_OUTPUT
- name: "ip_encrypt_key"
type: "String"
default: ""
- description: "A key, that can be generated via the :func:`makeIPCipherKey` function, to encrypt the IP address of the requestor for anonymization purposes. The encryption is done using ipcrypt for IPv4 and a 128-bit AES ECB operation for IPv6"
+ description: "A key to encrypt the IP address of the requestor for anonymization purposes. For the \"legacy\" method, it can be generated via the :func:`makeIPCipherKey` function. The encryption method can be set using ``ip_encrypt_method``"
+ - name: "ip_encrypt_method"
+ type: "String"
+ default: "legacy"
+ description: "
+ The method to encrypt the IP addresses with.
+ * legacy: The encryption is done using ipcrypt for IPv4 and a 128-bit AES ECB operation for IPv6. This is the default.
+ * ipcrypt-pfx: IPCrypt2, using prefix-preserving encryption. See `the ipcrypt website <https://ipcrypt-std.github.io/>__`. ``ip_encrypt_key`` must be 32 bytes."
- name: "export_tags"
type: "Vec<String>"
default: ""
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#include <optional>
#include <unordered_map>
#include "dnsdist-actions-factory.hh"
#include "ednsoptions.hh"
#include "fstrm_logger.hh"
#include "ipcipher.hh"
+#include "dnsdist-ipcrypt2.hh"
+#include "iputils.hh"
#include "remote_logger.hh"
#include "svc-records.hh"
#include "threadname.hh"
public:
// this action does not stop the processing
RemoteLogAction(RemoteLogActionConfiguration& config) :
- d_tagsToExport(std::move(config.tagsToExport)), d_metas(std::move(config.metas)), d_logger(config.logger), d_alterFunc(std::move(config.alterQueryFunc)), d_serverID(config.serverID), d_ipEncryptKey(config.ipEncryptKey)
+ d_tagsToExport(std::move(config.tagsToExport)), d_metas(std::move(config.metas)), d_logger(config.logger), d_alterFunc(std::move(config.alterQueryFunc)), d_serverID(config.serverID), d_ipEncryptKey(config.ipEncryptKey), d_ipEncryptMethod(config.ipEncryptMethod)
{
+ if (!d_ipEncryptKey.empty() && d_ipEncryptMethod == "ipcrypt-pfx") {
+ d_ipcrypt2 = pdns::ipcrypt2::IPCrypt2(pdns::ipcrypt2::IPCryptMethod::pfx, d_ipEncryptKey);
+ }
}
DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override
}
#ifdef HAVE_IPCIPHER
- if (!d_ipEncryptKey.empty()) {
+ if (!d_ipEncryptKey.empty() && d_ipEncryptMethod == "legacy") {
message.setRequestor(encryptCA(dnsquestion->ids.origRemote, d_ipEncryptKey));
}
#endif /* HAVE_IPCIPHER */
+ if (d_ipcrypt2) {
+ auto encryptedAddress = d_ipcrypt2->encrypt(dnsquestion->ids.origRemote);
+ encryptedAddress.setPort(dnsquestion->ids.origRemote.getPort());
+ message.setRequestor(encryptedAddress);
+ }
if (d_tagsToExport) {
addTagsToProtobuf(message, *dnsquestion, *d_tagsToExport);
std::optional<std::function<void(DNSQuestion*, DNSDistProtoBufMessage*)>> d_alterFunc;
std::string d_serverID;
std::string d_ipEncryptKey;
+ std::string d_ipEncryptMethod;
+ std::optional<pdns::ipcrypt2::IPCrypt2> d_ipcrypt2{std::nullopt};
};
#endif /* DISABLE_PROTOBUF */
std::shared_ptr<RemoteLoggerInterface> logger;
std::string serverID;
std::string ipEncryptKey;
+ std::string ipEncryptMethod{"legacy"};
std::optional<std::string> exportExtendedErrorsToMeta{std::nullopt};
bool includeCNAME{false};
};
actionConfig.logger = std::move(logger);
actionConfig.serverID = std::string(config.server_id);
actionConfig.ipEncryptKey = std::string(config.ip_encrypt_key);
+ actionConfig.ipEncryptMethod = std::string(config.ip_encrypt_method);
for (const auto& meta : config.metas) {
actionConfig.metas.emplace_back(std::string(meta.key), ProtoBufMetaKey(std::string(meta.value)));
}
--- /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 <memory>
+#include <stdexcept>
+#include <string>
+
+#include "dnsdist-ipcrypt2.hh"
+#include "ipcrypt2.h"
+#include "iputils.hh"
+
+// ipcrypt2 namespace does not have to be dnsdist-specific
+namespace pdns::ipcrypt2
+{
+IPCrypt2::IPCrypt2(const IPCryptMethod& method, const std::string& key) :
+ d_method(method)
+{
+ switch (method) {
+ case IPCryptMethod::pfx: {
+ if (key.size() != IPCRYPT_PFX_KEYBYTES) {
+ throw std::runtime_error("Key for IPCrypt PFX method is not " + std::to_string(IPCRYPT_PFX_KEYBYTES) + " bytes");
+ }
+ d_ipcryptCtxPfx = std::make_unique<IPCryptPFX>();
+ auto ret = ipcrypt_pfx_init(d_ipcryptCtxPfx.get(), reinterpret_cast<const uint8_t*>(key.data()));
+ if (ret != 0) {
+ throw std::runtime_error("Could not initialize IPCrypt2 PFX context");
+ }
+ } break;
+ default:
+ throw std::runtime_error("Unsupported IPCrypt2 method");
+ break;
+ }
+}
+
+IPCrypt2::~IPCrypt2()
+{
+ switch (d_method) {
+ case IPCryptMethod::pfx:
+ if (d_ipcryptCtxPfx != nullptr) {
+ ipcrypt_pfx_deinit(d_ipcryptCtxPfx.get());
+ }
+ break;
+ default:
+ return;
+ }
+};
+
+ComboAddress IPCrypt2::encrypt(const ComboAddress& address) const
+{
+ switch (d_method) {
+ case IPCryptMethod::pfx: {
+ std::string encryptedIP;
+ encryptedIP.resize(IPCRYPT_MAX_IP_STR_BYTES);
+ auto ret = ipcrypt_pfx_encrypt_ip_str(d_ipcryptCtxPfx.get(), encryptedIP.data(), address.toString().c_str());
+ // XXX: Do we *need* to resize?
+ encryptedIP.resize(ret);
+ return ComboAddress(encryptedIP);
+ } break;
+ default:
+ throw std::runtime_error("Unsupported method");
+ break;
+ }
+}
+}
--- /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 <memory>
+#include <string>
+
+#include "iputils.hh"
+#include "ipcrypt2.h"
+
+namespace pdns::ipcrypt2
+{
+
+enum IPCryptMethod : uint8_t
+{
+ deterministic,
+ pfx,
+ nd,
+ ndx
+};
+
+class IPCrypt2
+{
+public:
+ IPCrypt2(const IPCryptMethod& method, const std::string& key);
+
+ IPCrypt2(IPCrypt2&& rhs) = default;
+ IPCrypt2& operator=(IPCrypt2&& rhs) = default;
+
+ IPCrypt2(const IPCrypt2& orig) = delete;
+ IPCrypt2& operator=(const IPCrypt2& orig) = delete;
+
+ ~IPCrypt2();
+
+ [[nodiscard]] ComboAddress encrypt(const ComboAddress& address) const;
+
+private:
+ std::unique_ptr<struct IPCryptPFX> d_ipcryptCtxPfx;
+ IPCryptMethod d_method;
+};
+}
#include "dnsdist-rule-chains.hh"
#include "dnstap.hh"
#include "remote_logger.hh"
+#include <stdexcept>
template <typename ActionT, typename IdentifierT>
static void addAction(IdentifierT identifier, const luadnsrule_t& var, const std::shared_ptr<ActionT>& action, boost::optional<luaruleparams_t>& params)
});
#ifndef DISABLE_PROTOBUF
+ // Used for both RemoteLogAction and RemoteLogResponseAction
+ static const std::array<std::string, 2> s_validIpEncryptMethods = {"legacy", "ipcrypt-pfx"};
+
luaCtx.writeFunction("RemoteLogAction", [](std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<dnsdist::actions::ProtobufAlterFunction> alterFunc, boost::optional<LuaAssociativeTable<std::string>> vars, boost::optional<LuaAssociativeTable<std::string>> metas) {
if (logger) {
// avoids potentially-evaluated-expression warning with clang.
}
getOptionalValue<std::string>(vars, "serverID", config.serverID);
getOptionalValue<std::string>(vars, "ipEncryptKey", config.ipEncryptKey);
+ getOptionalValue<std::string>(vars, "ipEncryptMethod", config.ipEncryptMethod);
getOptionalValue<std::string>(vars, "exportTags", tags);
if (metas) {
}
}
+ if (std::find(s_validIpEncryptMethods.begin(), s_validIpEncryptMethods.end(), config.ipEncryptMethod) == s_validIpEncryptMethods.end()) {
+ throw std::runtime_error("Invalid IP Encryption method in RemoteLogAction");
+ }
+
if (!tags.empty()) {
config.tagsToExport = std::unordered_set<std::string>();
if (tags != "*") {
# Ext
subdir('ext' / 'arc4random')
subdir('ext' / 'ipcrypt')
+subdir('ext' / 'ipcrypt2')
subdir('ext' / 'json11')
subdir('ext' / 'luawrapper')
subdir('ext' / 'protozero')
src_dir / 'dnsdist-healthchecks.cc',
src_dir / 'dnsdist-idstate.cc',
src_dir / 'dnsdist-internal-queries.cc',
+ src_dir / 'dnsdist-ipcrypt2.cc',
src_dir / 'dnsdist-kvs.cc',
src_dir / 'dnsdist-lbpolicies.cc',
src_dir / 'dnsdist-lua-actions.cc',
dep_dnstap,
dep_htmlfiles,
dep_ipcrypt,
+ dep_ipcrypt2,
dep_libcap,
dep_libcrypto,
dep_gnutls,