From 905305fe1d1f814dbc144b10f44b97e7a9eebeeb Mon Sep 17 00:00:00 2001 From: Pieter Lexis Date: Mon, 15 Sep 2025 11:41:55 +0200 Subject: [PATCH] feat(dnsdist): Add IPCrypt2 PFX mode to RemoteResponseLogAction Signed-off-by: Pieter Lexis --- pdns/dnsdistdist/dnsdist-actions-factory.cc | 14 ++++++++++++-- pdns/dnsdistdist/dnsdist-configuration-yaml.cc | 1 + pdns/dnsdistdist/dnsdist-lua-actions.cc | 4 ++++ .../dnsdist-response-actions-definitions.yml | 9 ++++++++- 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/pdns/dnsdistdist/dnsdist-actions-factory.cc b/pdns/dnsdistdist/dnsdist-actions-factory.cc index 694d733b28..deb8110e16 100644 --- a/pdns/dnsdistdist/dnsdist-actions-factory.cc +++ b/pdns/dnsdistdist/dnsdist-actions-factory.cc @@ -1772,8 +1772,11 @@ class RemoteLogResponseAction : public DNSResponseAction, public boost::noncopya public: // this action does not stop the processing RemoteLogResponseAction(RemoteLogActionConfiguration& config) : - d_tagsToExport(std::move(config.tagsToExport)), d_metas(std::move(config.metas)), d_logger(config.logger), d_alterFunc(std::move(config.alterResponseFunc)), d_serverID(config.serverID), d_ipEncryptKey(config.ipEncryptKey), d_exportExtendedErrorsToMeta(std::move(config.exportExtendedErrorsToMeta)), d_includeCNAME(config.includeCNAME) + d_tagsToExport(std::move(config.tagsToExport)), d_metas(std::move(config.metas)), d_logger(config.logger), d_alterFunc(std::move(config.alterResponseFunc)), d_serverID(config.serverID), d_ipEncryptKey(config.ipEncryptKey), d_ipEncryptMethod(config.ipEncryptMethod), d_exportExtendedErrorsToMeta(std::move(config.exportExtendedErrorsToMeta)), d_includeCNAME(config.includeCNAME) { + if (!d_ipEncryptKey.empty() && d_ipEncryptMethod == "ipcrypt-pfx") { + d_ipcrypt2 = pdns::ipcrypt2::IPCrypt2(pdns::ipcrypt2::IPCryptMethod::pfx, d_ipEncryptKey); + } } DNSResponseAction::Action operator()(DNSResponse* response, std::string* ruleresult) const override { @@ -1791,10 +1794,15 @@ public: } #ifdef HAVE_IPCIPHER - if (!d_ipEncryptKey.empty()) { + if (!d_ipEncryptKey.empty() && d_ipEncryptMethod == "legacy") { message.setRequestor(encryptCA(response->ids.origRemote, d_ipEncryptKey)); } #endif /* HAVE_IPCIPHER */ + if (d_ipcrypt2) { + auto encryptedAddress = d_ipcrypt2->encrypt(response->ids.origRemote); + encryptedAddress.setPort(response->ids.origRemote.getPort()); + message.setRequestor(encryptedAddress); + } if (d_tagsToExport) { addTagsToProtobuf(message, *response, *d_tagsToExport); @@ -1833,6 +1841,8 @@ private: std::optional> d_alterFunc; std::string d_serverID; std::string d_ipEncryptKey; + std::string d_ipEncryptMethod; + std::optional d_ipcrypt2{std::nullopt}; std::optional d_exportExtendedErrorsToMeta{std::nullopt}; bool d_includeCNAME; }; diff --git a/pdns/dnsdistdist/dnsdist-configuration-yaml.cc b/pdns/dnsdistdist/dnsdist-configuration-yaml.cc index a84c4f8ead..a3e6acbf0f 100644 --- a/pdns/dnsdistdist/dnsdist-configuration-yaml.cc +++ b/pdns/dnsdistdist/dnsdist-configuration-yaml.cc @@ -1698,6 +1698,7 @@ std::shared_ptr getRemoteLogResponseAction(const Remot 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); actionConfig.includeCNAME = config.include_cname; for (const auto& meta : config.metas) { actionConfig.metas.emplace_back(std::string(meta.key), ProtoBufMetaKey(std::string(meta.value))); diff --git a/pdns/dnsdistdist/dnsdist-lua-actions.cc b/pdns/dnsdistdist/dnsdist-lua-actions.cc index 3d10df0753..30bfd068a4 100644 --- a/pdns/dnsdistdist/dnsdist-lua-actions.cc +++ b/pdns/dnsdistdist/dnsdist-lua-actions.cc @@ -354,6 +354,7 @@ void setupLuaActions(LuaContext& luaCtx) config.includeCNAME = includeCNAME ? *includeCNAME : false; getOptionalValue(vars, "serverID", config.serverID); getOptionalValue(vars, "ipEncryptKey", config.ipEncryptKey); + getOptionalValue(vars, "ipEncryptMethod", config.ipEncryptMethod); getOptionalValue(vars, "exportTags", tags); getOptionalValue(vars, "exportExtendedErrorsToMeta", config.exportExtendedErrorsToMeta); @@ -373,6 +374,9 @@ void setupLuaActions(LuaContext& luaCtx) } } } + if (std::find(s_validIpEncryptMethods.begin(), s_validIpEncryptMethods.end(), config.ipEncryptMethod) == s_validIpEncryptMethods.end()) { + throw std::runtime_error("Invalid IP Encryption method in RemoteLogResponseAction"); + } checkAllParametersConsumed("RemoteLogResponseAction", vars); diff --git a/pdns/dnsdistdist/dnsdist-response-actions-definitions.yml b/pdns/dnsdistdist/dnsdist-response-actions-definitions.yml index d04f2c7036..6b2aa60e18 100644 --- a/pdns/dnsdistdist/dnsdist-response-actions-definitions.yml +++ b/pdns/dnsdistdist/dnsdist-response-actions-definitions.yml @@ -155,7 +155,14 @@ The function will be invoked in a per-thread Lua state, without access to the gl - 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 __`. ``ip_encrypt_key`` must be 32 bytes." - name: "include_cname" type: "bool" default: "false" -- 2.47.3