]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
dnsdist: Add TLV support
authorRemi Gacogne <remi.gacogne@powerdns.com>
Thu, 27 Feb 2020 13:40:23 +0000 (14:40 +0100)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Tue, 17 Mar 2020 13:12:54 +0000 (14:12 +0100)
pdns/dnsdist-lua-bindings-dnsquestion.cc
pdns/dnsdistdist/docs/reference/dq.rst
pdns/proxy-protocol.cc

index 71840e7f36481f79cc40cd4353102e3304c6d898..9c87d129c8f9b65c2893f8aed69493b6820810e4 100644 (file)
@@ -118,6 +118,18 @@ void setupLuaBindingsDNSQuestion()
       return *dq.qTag;
     });
 
+  g_lua.registerFunction<void(DNSQuestion::*)(std::vector<std::pair<uint8_t, std::string>>)>("setProxyProtocolValues", [](DNSQuestion& dq, const std::vector<std::pair<uint8_t, std::string>>& values) {
+      if (!dq.proxyProtocolValues) {
+        dq.proxyProtocolValues = make_unique<std::vector<ProxyProtocolValue>>();
+      }
+
+      dq.proxyProtocolValues->clear();
+      dq.proxyProtocolValues->reserve(values.size());
+      for (const auto& value : values) {
+        dq.proxyProtocolValues->push_back({value.second, value.first});
+      }
+    });
+
   /* LuaWrapper doesn't support inheritance */
   g_lua.registerMember<const ComboAddress (DNSResponse::*)>("localaddr", [](const DNSResponse& dq) -> const ComboAddress { return *dq.local; }, [](DNSResponse& dq, const ComboAddress newLocal) { (void) newLocal; });
   g_lua.registerMember<const DNSName (DNSResponse::*)>("qname", [](const DNSResponse& dq) -> const DNSName { return *dq.qname; }, [](DNSResponse& dq, const DNSName newName) { (void) newName; });
index da2672f7534ca04c8a94ba5054a1b96f54e33830..4259a260f8fe88562cff0b975a0dbd19cadc38c7 100644 (file)
@@ -204,6 +204,14 @@ This state can be modified from the various hooks.
     :param int expire: The value of the expire field in the SOA record
     :param int minimum: The value of the minimum field in the SOA record
 
+  .. method:: DNSQuestion:setProxyProtocolValues(values)
+
+    .. versionadded:: 1.5.0
+
+    Set the Type-Length Values to send to the backend using the Proxy Protocol.
+
+    :param table values: A table of types and values to send, for example: ``{ ["0"] = foo", ["42"] = "bar" }``
+
   .. method:: DNSQuestion:setTag(key, value)
 
     .. versionadded:: 1.2.0
index f9500bcf6e2a6aee7ea955ed6fa963374f10e998..73b7066741592f0e1f37934d4e0388212b31ea80 100644 (file)
@@ -22,7 +22,6 @@
 
 #include "proxy-protocol.hh"
 
-// TODO: handle TLV after address struct
 // TODO: maybe use structs instead of explicitly working byte by byte, like https://github.com/dovecot/core/blob/master/src/lib-master/master-service-haproxy.c
 
 #define PROXYMAGIC "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A"
@@ -42,7 +41,16 @@ std::string makeProxyHeader(bool tcp, const ComboAddress& source, const ComboAdd
   const size_t addrSize = source.isIPv4() ? sizeof(source.sin4.sin_addr.s_addr) : sizeof(source.sin6.sin6_addr.s6_addr);
   const uint16_t sourcePort = source.sin4.sin_port;
   const uint16_t destinationPort = destination.sin4.sin_port;
-  const uint16_t contentlen = htons((addrSize * 2) + sizeof(sourcePort) + sizeof(destinationPort));
+
+  size_t valuesSize = 0;
+  for (const auto& value : values) {
+    if (value.content.size() > std::numeric_limits<uint16_t>::max()) {
+      throw std::runtime_error("The size of proxy protocol values is limited to " + std::to_string(std::numeric_limits<uint16_t>::max()) + ", trying to add a value of size " + std::to_string(value.content.size()));
+    }
+    valuesSize += sizeof(uint8_t) + sizeof(uint8_t) * 2 + value.content.size();
+  }
+
+  const uint16_t contentlen = htons((addrSize * 2) + sizeof(sourcePort) + sizeof(destinationPort) + valuesSize);
 
   ret.reserve(proxymagic.size() + sizeof(versioncommand) + sizeof(protocol) + sizeof(contentlen) + contentlen);
 
@@ -70,6 +78,13 @@ std::string makeProxyHeader(bool tcp, const ComboAddress& source, const ComboAdd
   ret.append(reinterpret_cast<const char*>(&sourcePort), sizeof(sourcePort));
   ret.append(reinterpret_cast<const char*>(&destinationPort), sizeof(destinationPort));
 
+  for (const auto& value : values) {
+    uint16_t contentSize = htons(static_cast<uint16_t>(value.content.size()));
+    ret.append(reinterpret_cast<const char*>(&value.type), sizeof(value.type));
+    ret.append(reinterpret_cast<const char*>(&contentSize), sizeof(contentSize));
+    ret.append(reinterpret_cast<const char*>(value.content.data()), value.content.size());
+  }
+
   return ret;
 }
 
@@ -171,5 +186,28 @@ ssize_t parseProxyHeader(const std::string& header, ComboAddress& source, ComboA
   destination.setPort((header.at(pos) << 8) + header.at(pos+1));
   pos = pos + sizeof(uint16_t);
 
+  size_t remaining = got - pos;
+  while (remaining >= (sizeof(uint8_t) + sizeof(uint16_t))) {
+    /* we still have TLV values to parse */
+    uint8_t type = static_cast<uint8_t>(header.at(pos));
+    pos += sizeof(uint8_t);
+    uint16_t len = (header.at(pos) << 8) + header.at(pos + 1);
+    pos += sizeof(uint16_t);
+
+    if (len > 0) {
+      if (len > (got - pos)) {
+        return 0;
+      }
+
+      values.push_back({ std::string(&header.at(pos), len), type });
+      pos += len;
+    }
+    else {
+      values.push_back({ std::string(), type });
+    }
+
+    remaining = got - pos;
+  }
+
   return pos;
 }