From: Remi Gacogne Date: Thu, 27 Feb 2020 13:40:23 +0000 (+0100) Subject: dnsdist: Add TLV support X-Git-Tag: dnsdist-1.5.0-alpha1~12^2~29 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8a79a6c49945837dacdec24130db8d83d16fe3e3;p=thirdparty%2Fpdns.git dnsdist: Add TLV support --- diff --git a/pdns/dnsdist-lua-bindings-dnsquestion.cc b/pdns/dnsdist-lua-bindings-dnsquestion.cc index 71840e7f36..9c87d129c8 100644 --- a/pdns/dnsdist-lua-bindings-dnsquestion.cc +++ b/pdns/dnsdist-lua-bindings-dnsquestion.cc @@ -118,6 +118,18 @@ void setupLuaBindingsDNSQuestion() return *dq.qTag; }); + g_lua.registerFunction>)>("setProxyProtocolValues", [](DNSQuestion& dq, const std::vector>& values) { + if (!dq.proxyProtocolValues) { + dq.proxyProtocolValues = make_unique>(); + } + + 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("localaddr", [](const DNSResponse& dq) -> const ComboAddress { return *dq.local; }, [](DNSResponse& dq, const ComboAddress newLocal) { (void) newLocal; }); g_lua.registerMember("qname", [](const DNSResponse& dq) -> const DNSName { return *dq.qname; }, [](DNSResponse& dq, const DNSName newName) { (void) newName; }); diff --git a/pdns/dnsdistdist/docs/reference/dq.rst b/pdns/dnsdistdist/docs/reference/dq.rst index da2672f753..4259a260f8 100644 --- a/pdns/dnsdistdist/docs/reference/dq.rst +++ b/pdns/dnsdistdist/docs/reference/dq.rst @@ -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 diff --git a/pdns/proxy-protocol.cc b/pdns/proxy-protocol.cc index f9500bcf6e..73b7066741 100644 --- a/pdns/proxy-protocol.cc +++ b/pdns/proxy-protocol.cc @@ -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::max()) { + throw std::runtime_error("The size of proxy protocol values is limited to " + std::to_string(std::numeric_limits::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(&sourcePort), sizeof(sourcePort)); ret.append(reinterpret_cast(&destinationPort), sizeof(destinationPort)); + for (const auto& value : values) { + uint16_t contentSize = htons(static_cast(value.content.size())); + ret.append(reinterpret_cast(&value.type), sizeof(value.type)); + ret.append(reinterpret_cast(&contentSize), sizeof(contentSize)); + ret.append(reinterpret_cast(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(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; }