]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
dnsdist: Add an option to set the SSL proxy protocol TLV 13506/head
authorRemi Gacogne <remi.gacogne@powerdns.com>
Fri, 17 Nov 2023 11:14:19 +0000 (12:14 +0100)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Fri, 17 Nov 2023 11:49:05 +0000 (12:49 +0100)
When the new `proxyProtocolAdvertiseTLS` to `newServer` is set, and
the query has been received from the client over an encrypted channel,
the SSL proxy protocol TLV is set in the proxy protocol payload sent
to the backend.

pdns/dnsdist-lua.cc
pdns/dnsdist-protocols.cc
pdns/dnsdist-protocols.hh
pdns/dnsdist.cc
pdns/dnsdist.hh
pdns/dnsdistdist/docs/reference/config.rst
pdns/proxy-protocol.hh
regression-tests.dnsdist/test_ProxyProtocol.py

index 09d9c5a34431de79a202846f3d2a5588b0d37be6..1869ab0cf384820a57bd43bac964ad2c5241d64a 100644 (file)
@@ -496,6 +496,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
 
                          getOptionalValue<bool>(vars, "useClientSubnet", config.useECS);
                          getOptionalValue<bool>(vars, "useProxyProtocol", config.useProxyProtocol);
+                         getOptionalValue<bool>(vars, "proxyProtocolAdvertiseTLS", config.d_proxyProtocolAdvertiseTLS);
                          getOptionalValue<bool>(vars, "disableZeroScope", config.disableZeroScope);
                          getOptionalValue<bool>(vars, "ipBindAddrNoPort", config.ipBindAddrNoPort);
 
index e113925e069529de5a1de7b6ebfe420f1e37b3de..2347822153e6c5f4ce8bac3e329e9cbab4d110cb 100644 (file)
@@ -81,6 +81,11 @@ bool Protocol::isUDP() const
   return d_protocol == DoUDP || d_protocol == DNSCryptUDP;
 }
 
+bool Protocol::isEncrypted() const
+{
+  return d_protocol != DoUDP && d_protocol != DoTCP;
+}
+
 uint8_t Protocol::toNumber() const
 {
   return static_cast<uint8_t>(d_protocol);
index bece30095508847581a8edf8f4e39696157cfb69..00070a0d2141ad895bd870c909a461777f3a335b 100644 (file)
@@ -57,6 +57,7 @@ public:
   const std::string& toString() const;
   const std::string& toPrettyString() const;
   bool isUDP() const;
+  bool isEncrypted() const;
   uint8_t toNumber() const;
 
 private:
index b07713885097520160ce2728f51cc1e4695ab409..2d34cd1fbebfb329e222e4ff073561570a046abd 100644 (file)
@@ -1506,6 +1506,13 @@ ProcessQueryResult processQueryAfterRules(DNSQuestion& dq, LocalHolders& holders
       addXPF(dq, selectedBackend->d_config.xpfRRCode);
     }
 
+    if (selectedBackend->d_config.useProxyProtocol && dq.getProtocol().isEncrypted() && selectedBackend->d_config.d_proxyProtocolAdvertiseTLS) {
+      if (!dq.proxyProtocolValues) {
+        dq.proxyProtocolValues = std::make_unique<std::vector<ProxyProtocolValue>>();
+      }
+      dq.proxyProtocolValues->push_back(ProxyProtocolValue{"", static_cast<uint8_t>(ProxyProtocolValue::Types::PP_TLV_SSL)});
+    }
+
     selectedBackend->incQueriesCount();
     return ProcessQueryResult::PassToBackend;
   }
index acbc45102e49787944a6c255fe9ad8d413e7c979..2a8b22d9b1f9ebde40a645f1ad3d410b489b6269 100644 (file)
@@ -712,6 +712,7 @@ struct DownstreamState: public std::enable_shared_from_this<DownstreamState>
     bool mustResolve{false};
     bool useECS{false};
     bool useProxyProtocol{false};
+    bool d_proxyProtocolAdvertiseTLS{false};
     bool setCD{false};
     bool disableZeroScope{false};
     bool tcpFastOpen{false};
index 61888708ca9646b814847b6f73247c3acb71b489..06264ee28590cc47b11c6128510083ef4d9540fb 100644 (file)
@@ -598,6 +598,9 @@ Servers
   .. versionchanged:: 1.8.0
     Added ``autoUpgrade``, ``autoUpgradeDoHKey``, ``autoUpgradeInterval``, ``autoUpgradeKeep``, ``autoUpgradePool``, ``maxConcurrentTCPConnections``, ``subjectAddr``, ``lazyHealthCheckSampleSize``, ``lazyHealthCheckMinSampleCount``, ``lazyHealthCheckThreshold``, ``lazyHealthCheckFailedInterval``, ``lazyHealthCheckMode``, ``lazyHealthCheckUseExponentialBackOff``, ``lazyHealthCheckMaxBackOff``, ``lazyHealthCheckWhenUpgraded``, ``healthCheckMode`` and ``ktls`` to server_table.
 
+  .. versionchanged:: 1.9.0
+    Added ``proxyProtocolAdvertiseTLS`` to server_table.
+
   :param str server_string: A simple IP:PORT string.
   :param table server_table: A table with at least an ``address`` key
 
@@ -684,6 +687,7 @@ Servers
     ``lazyHealthCheckMaxBackOff``            ``number``            "This value, in seconds, caps the time between two health-check queries when ``lazyHealthCheckUseExponentialBackOff`` is set to true. The default is 3600 which means that at most one hour will pass between two health-check queries."
     ``lazyHealthCheckWhenUpgraded``          ``bool``              "Whether the auto-upgraded version of this backend (see ``autoUpgrade``) should use the lazy health-checking mode. Default is false, which means it will use the regular health-checking mode."
     ``ktls``                                 ``bool``              "Whether to enable the experimental kernel TLS support on Linux, if both the kernel and the OpenSSL library support it. Default is false. Currently both DoT and DoH backend support this option."
+    ``proxyProtocolAdvertiseTLS``            ``bool``              "Whether to set the SSL Proxy Protocol TLV in the proxy protocol payload sent to the backend if the query was received over an encrypted channel (DNSCrypt, DoQ, DoH or DoT). Requires ``useProxyProtocol=true``. Default is false."
 
 .. function:: getServer(index) -> Server
 
index 373a750e944a06e0ddc4ef6408b3e7300c775afa..a44c72110f5c74cfe79367de0f89d79d34155ece 100644 (file)
@@ -33,6 +33,8 @@ struct ProxyProtocolValue
   {
     return type == rhs.type && content == rhs.content;
   }
+
+  enum class Types : uint8_t { PP_TLV_ALPN = 0x01, PP_TLV_SSL = 0x20 };
 };
 
 static const size_t s_proxyProtocolMinimumHeaderSize = 16;
index dd4ca4fbefb9dc010d537ae3e1f6a53c33a3e889..8e9eab2c4143aa5476c4b6ff09545ceb8d555bce 100644 (file)
@@ -492,7 +492,7 @@ class TestProxyProtocolIncoming(ProxyProtocolTest):
     addDOHLocal("127.0.0.1:%d", "%s", "%s", {"/"}, {library='nghttp2', proxyProtocolOutsideTLS=true})
     addDOHLocal("127.0.0.1:%d", "%s", "%s", {"/"}, {library='nghttp2', proxyProtocolOutsideTLS=false})
     setProxyProtocolACL( { "127.0.0.1/32" } )
-    newServer{address="127.0.0.1:%d", useProxyProtocol=true}
+    newServer{address="127.0.0.1:%d", useProxyProtocol=true, proxyProtocolAdvertiseTLS=true}
 
     function addValues(dq)
       dq:addProxyProtocolValue(0, 'foo')
@@ -789,7 +789,7 @@ class TestProxyProtocolIncoming(ProxyProtocolTest):
         receivedResponse.id = response.id
         self.assertEqual(receivedQuery, query)
         self.assertEqual(receivedResponse, response)
-        self.checkMessageProxyProtocol(receivedProxyPayload, '127.0.0.1', '127.0.0.1', True, [ [0, b'foo'], [1, b'dnsdist'], [ 2, b'foo'], [3, b'proxy'], [ 42, b'bar'], [255, b'proxy-protocol'] ], v6=False, sourcePort=None, destinationPort=reverseProxyPort)
+        self.checkMessageProxyProtocol(receivedProxyPayload, '127.0.0.1', '127.0.0.1', True, [ [0, b'foo'], [1, b'dnsdist'], [ 2, b'foo'], [3, b'proxy'], [32, ''], [42, b'bar'], [255, b'proxy-protocol'] ], v6=False, sourcePort=None, destinationPort=reverseProxyPort)
 
         for idx in range(5):
           receivedResponse = None
@@ -805,7 +805,7 @@ class TestProxyProtocolIncoming(ProxyProtocolTest):
           receivedResponse.id = response.id
           self.assertEqual(receivedQuery, query)
           self.assertEqual(receivedResponse, response)
-          self.checkMessageProxyProtocol(receivedProxyPayload, '127.0.0.1', '127.0.0.1', True, [ [0, b'foo'], [1, b'dnsdist'], [ 2, b'foo'], [3, b'proxy'], [ 42, b'bar'], [255, b'proxy-protocol'] ], v6=False, sourcePort=None, destinationPort=reverseProxyPort)
+          self.checkMessageProxyProtocol(receivedProxyPayload, '127.0.0.1', '127.0.0.1', True, [ [0, b'foo'], [1, b'dnsdist'], [ 2, b'foo'], [3, b'proxy'], [32, ''], [42, b'bar'], [255, b'proxy-protocol'] ], v6=False, sourcePort=None, destinationPort=reverseProxyPort)
 
     def testProxyDoHSeveralQueriesOverConnectionPPInside(self):
         """
@@ -842,7 +842,7 @@ class TestProxyProtocolIncoming(ProxyProtocolTest):
         receivedResponse.id = response.id
         self.assertEqual(receivedQuery, query)
         self.assertEqual(receivedResponse, response)
-        self.checkMessageProxyProtocol(receivedProxyPayload, '127.0.0.1', '127.0.0.1', True, [ [0, b'foo'], [1, b'dnsdist'], [ 2, b'foo'], [3, b'proxy'], [ 42, b'bar'], [255, b'proxy-protocol'] ], v6=False, sourcePort=None, destinationPort=reverseProxyPort)
+        self.checkMessageProxyProtocol(receivedProxyPayload, '127.0.0.1', '127.0.0.1', True, [ [0, b'foo'], [1, b'dnsdist'], [ 2, b'foo'], [3, b'proxy'], [32, ''], [ 42, b'bar'], [255, b'proxy-protocol'] ], v6=False, sourcePort=None, destinationPort=reverseProxyPort)
 
         for idx in range(5):
           receivedResponse = None
@@ -858,7 +858,7 @@ class TestProxyProtocolIncoming(ProxyProtocolTest):
           receivedResponse.id = response.id
           self.assertEqual(receivedQuery, query)
           self.assertEqual(receivedResponse, response)
-          self.checkMessageProxyProtocol(receivedProxyPayload, '127.0.0.1', '127.0.0.1', True, [ [0, b'foo'], [1, b'dnsdist'], [ 2, b'foo'], [3, b'proxy'], [ 42, b'bar'], [255, b'proxy-protocol'] ], v6=False, sourcePort=None, destinationPort=reverseProxyPort)
+          self.checkMessageProxyProtocol(receivedProxyPayload, '127.0.0.1', '127.0.0.1', True, [ [0, b'foo'], [1, b'dnsdist'], [ 2, b'foo'], [3, b'proxy'], [32, ''], [ 42, b'bar'], [255, b'proxy-protocol'] ], v6=False, sourcePort=None, destinationPort=reverseProxyPort)
 
     @classmethod
     def tearDownClass(cls):