{ "addDynBlockSMT", true, "names, message[, seconds [, action]]", "block the set of names with message `msg`, for `seconds` seconds (10 by default), applying `action` (default to the one set with `setDynBlocksAction()`)" },
{ "addLocal", true, "addr [, {doTCP=true, reusePort=false, tcpFastOpenQueueSize=0, interface=\"\", cpus={}}]", "add `addr` to the list of addresses we listen on" },
{ "addCacheHitResponseAction", true, "DNS rule, DNS response action [, {uuid=\"UUID\", name=\"name\"}}]", "add a cache hit response rule" },
+ { "AddProxyProtocolValueAction", true, "type, value", "Add a Proxy Protocol TLV value of this type" },
{ "addResponseAction", true, "DNS rule, DNS response action [, {uuid=\"UUID\", name=\"name\"}}]", "add a response rule" },
{ "addSelfAnsweredResponseAction", true, "DNS rule, DNS response action [, {uuid=\"UUID\", name=\"name\"}}]", "add a self-answered response rule" },
{ "addTLSLocal", true, "addr, certFile(s), keyFile(s) [,params]", "listen to incoming DNS over TLS queries on the specified address using the specified certificate (or list of) and key (or list of). The last parameter is a table" },
{ "PoolAvailableRule", true, "poolname", "Check whether a pool has any servers available to handle queries" },
{ "printDNSCryptProviderFingerprint", true, "\"/path/to/providerPublic.key\"", "display the fingerprint of the provided resolver public key" },
{ "ProbaRule", true, "probability", "Matches queries with a given probability. 1.0 means always" },
+ { "ProxyProtocolValueRule", true, "type [, value]", "matches queries with a specified Proxy Protocol TLV value of that type, optionnally matching the content of the option as well" },
{ "QClassRule", true, "qclass", "Matches queries with the specified qclass. class can be specified as an integer or as one of the built-in DNSClass" },
{ "QNameLabelsCountRule", true, "min, max", "matches if the qname has less than `min` or more than `max` labels" },
{ "QNameRule", true, "qname", "matches queries with the specified qname" },
{ "setPoolServerPolicyLua", true, "name, function, pool", "set the server selection policy for this pool to one named 'name' and provided by 'function'" },
{ "setPoolServerPolicyLuaFFI", true, "name, function, pool", "set the server selection policy for this pool to one named 'name' and provided by 'function'" },
{ "setPoolServerPolicyLuaFFIPerThread", true, "name, code", "set server selection policy for this pool to one named 'name' and returned by the Lua FFI code passed in 'code'" },
- { "setPreserveTrailingData", true, "bool", "set whether trailing data should be preserved while adding ECS or XPF records to incoming queries" },
+ { "setProxyProtocolACL", true, "{netmask, netmask}", "Set the netmasks who are allowed to send Proxy Protocol headers in front of queries/connections" },
+ { "setProxyProtocolApplyACLToProxiedClients", true, "apply", "Whether the general ACL should be applied to the source IP address gathered from a Proxy Protocol header, in addition to being first applied to the source address seen by dnsdist" },
+ { "setProxyProtocolMaximumPayloadSize", true, "max", "Set the maximum size of a Proxy Protocol payload, in bytes" },
{ "setQueryCount", true, "bool", "set whether queries should be counted" },
{ "setQueryCountFilter", true, "func", "filter queries that would be counted, where `func` is a function with parameter `dq` which decides whether a query should and how it should be counted" },
{ "setRingBuffersLockRetries", true, "n", "set the number of attempts to get a non-blocking lock to a ringbuffer shard before blocking" },
+ static_assert(s_udpIncomingBufferSize <= s_initialUDPPacketBufferSize, "The incoming buffer size should not be larger than s_initialUDPPacketBufferSize");
- vinfolog("Got query for %s|%s from %s, relayed to %s", ids->qname.toLogString(), QType(ids->qtype).getName(), remote.toStringWithPort(), ss->getName());
+ vinfolog("Got query for %s|%s from %s, relayed to %s", ids->qname.toLogString(), QType(ids->qtype).getName(), proxiedRemote.toStringWithPort(), ss->getName());
}
catch(const std::exception& e){
- vinfolog("Got an error in UDP question thread while parsing a query from %s, id %d: %s", remote.toStringWithPort(), queryId, e.what());
+ vinfolog("Got an error in UDP question thread while parsing a query from %s, id %d: %s", proxiedRemote.toStringWithPort(), queryId, e.what());
}
}
@@ -1393,22+1423,24 @@ static void MultipleMessagesUDPClientThread(ClientState* cs, LocalHolders& holde
cmsgbuf_aligned cbuf;
};
const size_t vectSize = g_udpVectorSize;
+
+ auto recvData = std::unique_ptr<MMReceiver[]>(new MMReceiver[vectSize]);
+ auto msgVec = std::unique_ptr<struct mmsghdr[]>(new struct mmsghdr[vectSize]);
+ auto outMsgVec = std::unique_ptr<struct mmsghdr[]>(new struct mmsghdr[vectSize]);
+
/* the actual buffer is larger because:
- we may have to add EDNS and/or ECS
- we use it for self-generated responses (from rule or cache)
but we only accept incoming payloads up to that size
*/
- static_assert(s_udpIncomingBufferSize <= s_initialUDPPacketBufferSize, "the incoming buffer size should not be larger than s_initialUDPPacketBufferSize");
-
- auto recvData = std::unique_ptr<MMReceiver[]>(new MMReceiver[vectSize]);
- auto msgVec = std::unique_ptr<struct mmsghdr[]>(new struct mmsghdr[vectSize]);
- auto outMsgVec = std::unique_ptr<struct mmsghdr[]>(new struct mmsghdr[vectSize]);
- - we use it for self-generated responses (from rule or cache)
- but we only accept incoming payloads up to that size
- */
- static_assert(s_udpIncomingBufferSize <= s_initialUDPPacketBufferSize, "the incoming buffer size should not be larger than sizeof(MMReceiver::packet)");
- struct msghdr msgh;
- struct iovec iov;
- /* used by HarvestDestinationAddress */
- cmsgbuf_aligned cbuf;
+ {
+ /* the actual buffer is larger because:
+ - we may have to add EDNS and/or ECS
+ - we use it for self-generated responses (from rule or cache)
+ but we only accept incoming payloads up to that size
- enum class State { doingHandshake, readingQuerySize, readingQuery, sendingResponse, idle /* in case of XFR, we stop processing queries */ };
+ enum class State { doingHandshake, readingProxyProtocolHeader, readingQuerySize, readingQuery, sendingResponse, idle /* in case of XFR, we stop processing queries */ };
@@ -15,4+15,4 @@ In addition to the global settings, rules and Lua bindings can alter this behavi
In effect this means that for the EDNS Client Subnet option to be added to the request, ``useClientSubnet`` should be set to ``true`` for the backend used (default to ``false``) and ECS should not have been disabled by calling :func:`DisableECSAction` or setting ``dq.useECS`` to ``false`` (default to true).
-Note that any trailing data present in the incoming query is removed by default when an OPT (or XPF) record has to be inserted. This behaviour can be modified using :func:`setPreserveTrailingData()`.
+Note that any trailing data present in the incoming query is removed when an OPT (or XPF) record has to be inserted.
In order to provide the downstream server with the address of the real client, or at least the one talking to dnsdist, the ``useProxyProtocol`` parameter can be used when creating a :func:`new server <newServer>`.
This parameter indicates whether a Proxy Protocol version 2 (binary) header should be prepended to the query before forwarding it to the backend, over UDP or TCP. This header contains the initial source and destination addresses and ports, and can also contain several custom values in a Type-Length-Value format. More information about the Proxy Protocol can be found at https://www.haproxy.org/download/2.2/doc/proxy-protocol.txt
+Such a Proxy Protocol header can also be passed from the client to dnsdist, using :func:`setProxyProtocolACL` to specify which clients to accept it from.
+If :func:`setProxyProtocolApplyACLToProxiedClients` is set (default is false), the general ACL will be applied to the source IP address as seen by dnsdist first, but also to the source IP address provided in the Proxy Protocol header.
-Custom values can be added to the header via :meth:`DNSQuestion:setProxyProtocolValues` and :func:`SetProxyProtocolValuesAction`.
+Custom values can be added to the header via :meth:`DNSQuestion:addProxyProtocolValue`, :meth:`DNSQuestion:setProxyProtocolValues`, :func:`AddProxyProtocolValueAction` and :func:`SetProxyProtocolValuesAction`.
+Be careful that Proxy Protocol values are sent once at the beginning of the TCP connection for TCP and DoT queries.
+That means that values received on an incoming TCP connection will be inherited by subsequent queries received over the same incoming TCP connection, if any, but values set to a query will not be inherited by subsequent queries.
+Please also note that the maximum size of a Proxy Protocol header dnsdist is willing to accept is 512 bytes by default, although it can be set via :func:`setProxyProtocolMaximumPayloadSize`.
-As of 1.5.0 only outgoing Proxy Protocol support has been implemented, although support for parsing incoming Proxy Protocol headers will likely be implemented in the future.
+dnsdist 1.5.0 only supports outgoing Proxy Protocol. Support for parsing incoming Proxy Protocol headers has been implemented in 1.6.0, except for DoH where it does not make sense anyway, since HTTP headers already provide a mechanism for that.
:param str fname: The path to a file containing a list of netmasks. Empty lines or lines starting with "#" are ignored.
+.. function:: setProxyProtocolACL(netmasks)
+
+ .. versionadded:: 1.6.0
+
+ Set the list of netmasks from which a Proxy Protocol header will be accepted, over UDP, TCP and DNS over TLS. The default is empty. Note that, if :func:`setProxyProtocolApplyACLToProxiedClients` is set (default is false), the general ACL will be applied to the source IP address as seen by dnsdist first, but also to the source IP address provided in the Proxy Protocol header.
+
+ :param {str} netmasks: A table of CIDR netmask, e.g. ``{"192.0.2.0/24", "2001:DB8:14::/56"}``. Without a subnetmask, only the specific address is allowed.
+
+.. function:: setProxyProtocolApplyACL(apply)
+
+ .. versionadded:: 1.6.0
+
+ Whether the general ACL should be applied to the source IP address provided in the Proxy Protocol header, in addition to being applied to the source IP address as seen by dnsdist first.
+
+ :param bool apply: Whether it should be applied or not (default is false).
+
.. function:: showACL()
Print a list of all netmasks allowed to send queries over UDP, TCP, DNS over TLS and DNS over HTTPS. See :ref:`ACL` for more information.
Set to true (defaults to false) to allow empty responses (qdcount=0) with a NoError or NXDomain rcode (default) from backends. dnsdist drops these responses by default because it can't match them against the initial query since they don't contain the qname, qtype and qclass, and therefore the risk of collision is much higher than with regular responses.
+ Set the maximum size of a Proxy Protocol payload that dnsdist is willing to accept, in bytes. The default is 512, which is more than enough except for very large TLV data. This setting can't be set to a value lower than 16 since it would deny of Proxy Protocol headers.
+
+ :param int size: The maximum size in bytes (default is 512)