]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
feat(dnsdist): Add IPCrypt2 PFX mode to RemoteResponseLogAction
authorPieter Lexis <pieter.lexis@powerdns.com>
Mon, 15 Sep 2025 09:41:55 +0000 (11:41 +0200)
committerPieter Lexis <pieter.lexis@powerdns.com>
Thu, 2 Oct 2025 12:07:03 +0000 (14:07 +0200)
Signed-off-by: Pieter Lexis <pieter.lexis@powerdns.com>
pdns/dnsdistdist/dnsdist-actions-factory.cc
pdns/dnsdistdist/dnsdist-configuration-yaml.cc
pdns/dnsdistdist/dnsdist-lua-actions.cc
pdns/dnsdistdist/dnsdist-response-actions-definitions.yml

index 694d733b285de11abc3c61770780d3277451fed1..deb8110e167624a9820d730e0f1ba1f3ac2104f0 100644 (file)
@@ -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<std::function<void(DNSResponse*, DNSDistProtoBufMessage*)>> d_alterFunc;
   std::string d_serverID;
   std::string d_ipEncryptKey;
+  std::string d_ipEncryptMethod;
+  std::optional<pdns::ipcrypt2::IPCrypt2> d_ipcrypt2{std::nullopt};
   std::optional<std::string> d_exportExtendedErrorsToMeta{std::nullopt};
   bool d_includeCNAME;
 };
index a84c4f8ead7990f8335c1a0444114f220a47b617..a3e6acbf0f032e0959c7ac09571218e72ab2b200 100644 (file)
@@ -1698,6 +1698,7 @@ std::shared_ptr<DNSResponseActionWrapper> 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)));
index 3d10df07531994b5b6113960a5a34d034e3e42b8..30bfd068a484faba3eb086d906c569f403bd73eb 100644 (file)
@@ -354,6 +354,7 @@ void setupLuaActions(LuaContext& luaCtx)
     config.includeCNAME = includeCNAME ? *includeCNAME : false;
     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);
     getOptionalValue<std::string>(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);
 
index d04f2c7036f97039c9070fc6e60a1b166a310c71..6b2aa60e1817b0d814cc9b5df44a7f767541fb39 100644 (file)
@@ -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 <https://ipcrypt-std.github.io/>__`. ``ip_encrypt_key`` must be 32 bytes."
     - name: "include_cname"
       type: "bool"
       default: "false"