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; });
: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
#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"
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);
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;
}
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;
}