Skip to content

Commit

Permalink
Make the XPF code point configurable in dnsdist and the rec
Browse files Browse the repository at this point in the history
It's a bit trickier for sdig, though.
  • Loading branch information
rgacogne committed Nov 2, 2017
1 parent 91ac726 commit f8dd365
Show file tree
Hide file tree
Showing 9 changed files with 35 additions and 19 deletions.
4 changes: 2 additions & 2 deletions pdns/dnsdist-lua.cc
Expand Up @@ -479,10 +479,10 @@ vector<std::function<void(void)>> setupLua(bool client, const std::string& confi

if(vars.count("ipBindAddrNoPort")) {
ret->ipBindAddrNoPort=boost::get<bool>(vars["ipBindAddrNoPort"]);
}
}

if(vars.count("addXPF")) {
ret->addXPF=boost::get<bool>(vars["addXPF"]);
ret->xpfOptionCode=std::stoi(boost::get<string>(vars["addXPF"]));
}

if(vars.count("maxCheckFailures")) {
Expand Down
4 changes: 2 additions & 2 deletions pdns/dnsdist-tcp.cc
Expand Up @@ -425,8 +425,8 @@ void* tcpClientThread(int pipefd)
break;
}

if (dq.addXPF && ds->addXPF) {
addXPF(dq);
if (dq.addXPF && ds->xpfOptionCode != 0) {
addXPF(dq, ds->xpfOptionCode);
}

int dsock = -1;
Expand Down
9 changes: 4 additions & 5 deletions pdns/dnsdist.cc
Expand Up @@ -1084,12 +1084,12 @@ static ssize_t udpClientSendRequestToBackend(DownstreamState* ss, const int sd,
return result;
}

bool addXPF(DNSQuestion& dq)
bool addXPF(DNSQuestion& dq, uint16_t optionCode)
{
std::string payload = generateXPFPayload(dq.tcp, *dq.remote, *dq.local);
uint8_t root = '\0';
dnsrecordheader drh;
drh.d_type = htons(QType::XPF);
drh.d_type = htons(optionCode);
drh.d_class = htons(QClass::IN);
drh.d_ttl = 0;
drh.d_clen = htons(payload.size());
Expand Down Expand Up @@ -1370,8 +1370,8 @@ static void processUDPQuery(ClientState& cs, LocalHolders& holders, const struct
return;
}

if (dq.addXPF && ss->addXPF) {
addXPF(dq);
if (dq.addXPF && ss->xpfOptionCode != 0) {
addXPF(dq, ss->xpfOptionCode);
}

ss->queries++;
Expand Down Expand Up @@ -1521,7 +1521,6 @@ static void MultipleMessagesUDPClientThread(ClientState* cs, LocalHolders& holde
}
#endif /* defined(HAVE_RECVMMSG) && defined(HAVE_SENDMMSG) && defined(MSG_WAITFORONE) */


// listens to incoming queries, sends out to downstream servers, noting the intended return path
static void* udpClientThread(ClientState* cs)
try
Expand Down
4 changes: 2 additions & 2 deletions pdns/dnsdist.hh
Expand Up @@ -621,6 +621,7 @@ struct DownstreamState
int tcpSendTimeout{30};
unsigned int sourceItf{0};
uint16_t retries{5};
uint16_t xpfOptionCode{0};
uint8_t currentCheckFailures{0};
uint8_t maxCheckFailures{1};
StopWatch sw;
Expand All @@ -629,7 +630,6 @@ struct DownstreamState
bool mustResolve{false};
bool upStatus{false};
bool useECS{false};
bool addXPF{false};
bool setCD{false};
std::atomic<bool> connected{false};
bool tcpFastOpen{false};
Expand Down Expand Up @@ -852,7 +852,7 @@ int handleDnsCryptQuery(DnsCryptContext* ctx, char* packet, uint16_t len, std::s
bool encryptResponse(char* response, uint16_t* responseLen, size_t responseSize, bool tcp, std::shared_ptr<DnsCryptQuery> dnsCryptQuery, dnsheader** dh, dnsheader* dhCopy);
#endif

bool addXPF(DNSQuestion& dq);
bool addXPF(DNSQuestion& dq, uint16_t optionCode);

#include "dnsdist-snmp.hh"

Expand Down
6 changes: 3 additions & 3 deletions pdns/dnsdistdist/docs/reference/config.rst
Expand Up @@ -215,8 +215,6 @@ Servers

newServer({
address="IP:PORT", -- IP and PORT of the backend server (mandatory)
addXPF=BOOL, -- Add the client's IP address and port to the query, along with the original destination address and port,
-- using the experimental XPF record from `draft-bellis-dnsop-xpf`. Default to false
qps=NUM, -- Limit the number of queries per second to NUM, when using the `firstAvailable` policy
order=NUM, -- The order of this server, used by the `leastOustanding` and `firstAvailable` policies
weight=NUM, -- The weight of this server, used by the `wrandom` and `whashed` policies
Expand All @@ -234,11 +232,13 @@ Servers
maxCheckFailures=NUM, -- Allow NUM check failures before declaring the backend down, default: false
mustResolve=BOOL, -- Set to true when the health check MUST return a NOERROR RCODE and an answer
useClientSubnet=BOOL, -- Add the client's IP address in the EDNS Client Subnet option when forwarding the query to this backend
source=STRING -- The source address or interface to use for queries to this backend, by default this is left to the kernel's address selection
source=STRING, -- The source address or interface to use for queries to this backend, by default this is left to the kernel's address selection
-- The following formats are supported:
-- "address", e.g. "192.0.2.2"
-- "interface name", e.g. "eth0"
-- "address@interface", e.g. "192.0.2.2@eth0"
addXPF=NUM -- Add the client's IP address and port to the query, along with the original destination address and port,
-- using the experimental XPF record from `draft-bellis-dnsop-xpf` and the specified option code. Default is disabled (0)
})

:param str server_string: A simple IP:PORT string.
Expand Down
7 changes: 5 additions & 2 deletions pdns/dnsparser.cc
Expand Up @@ -296,13 +296,16 @@ void MOADNSParser::init(bool query, const char *packet, unsigned int len)

d_answers.push_back(make_pair(dr, pr.d_pos));

if (dr.d_place == DNSResourceRecord::ADDITIONAL && seenTSIG && dr.d_type != QType::XPF) {
/* XXX: XPF records should be allowed after TSIG as soon as the actual XPF option code has been assigned:
if (dr.d_place == DNSResourceRecord::ADDITIONAL && seenTSIG && dr.d_type != QType::XPF)
*/
if (dr.d_place == DNSResourceRecord::ADDITIONAL && seenTSIG) {
/* only XPF records are allowed after a TSIG */
throw MOADNSException("Packet ("+d_qname.toString()+"|#"+std::to_string(d_qtype)+") has an unexpected record ("+std::to_string(dr.d_type)+") after a TSIG one.");
}

if(dr.d_type == QType::TSIG && dr.d_class == QClass::ANY) {
if(dr.d_place != DNSResourceRecord::ADDITIONAL) {
if(seenTSIG || dr.d_place != DNSResourceRecord::ADDITIONAL) {
throw MOADNSException("Packet ("+d_qname.toString()+"|#"+std::to_string(d_qtype)+") has a TSIG record in an invalid position.");
}
seenTSIG = true;
Expand Down
7 changes: 5 additions & 2 deletions pdns/pdns_recursor.cc
Expand Up @@ -148,6 +148,7 @@ static unsigned int g_maxMThreads;
static unsigned int g_numWorkerThreads;
static int g_tcpTimeout;
static uint16_t g_udpTruncationThreshold;
static uint16_t g_xpfOptionCode{0};
static std::atomic<bool> statsWanted;
static std::atomic<bool> g_quiet;
static bool g_logCommonErrors;
Expand Down Expand Up @@ -1365,7 +1366,7 @@ static void getQNameAndSubnet(const std::string& question, DNSName* dnsname, uin
bool& foundECS, EDNSSubnetOpts* ednssubnet, std::map<uint16_t, EDNSOptionView>* options,
bool& foundXPF, ComboAddress* xpfSource, ComboAddress* xpfDest)
{
const bool lookForXPF = xpfSource != nullptr;
const bool lookForXPF = xpfSource != nullptr && g_xpfOptionCode != 0;
const bool lookForECS = ednssubnet != nullptr;
const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(question.c_str());
size_t questionLen = question.length();
Expand Down Expand Up @@ -1420,7 +1421,7 @@ static void getQNameAndSubnet(const std::string& question, DNSName* dnsname, uin
}
}
}
else if (lookForXPF && ntohs(drh->d_type) == QType::XPF && ntohs(drh->d_class) == QClass::IN && drh->d_ttl == 0) {
else if (lookForXPF && ntohs(drh->d_type) == g_xpfOptionCode && ntohs(drh->d_class) == QClass::IN && drh->d_ttl == 0) {
if ((questionLen - pos) < ntohs(drh->d_clen)) {
return;
}
Expand Down Expand Up @@ -3063,6 +3064,7 @@ static int serviceMain(int argc, char*argv[])
g_useIncomingECS = ::arg().mustDo("use-incoming-edns-subnet");

g_XPFAcl.toMasks(::arg()["xpf-allow-from"]);
g_xpfOptionCode = ::arg().asNum("xpf-option-code");

int forks;
for(forks = 0; forks < ::arg().asNum("processes") - 1; ++forks) {
Expand Down Expand Up @@ -3451,6 +3453,7 @@ int main(int argc, char **argv)
::arg().setSwitch("log-rpz-changes", "Log additions and removals to RPZ zones at Info level")="no";

::arg().set("xpf-allow-from","XPF information is only processed from these subnets")="";
::arg().set("xpf-option-code","XPF option code to use")="0";

::arg().setCmd("help","Provide a helpful message");
::arg().setCmd("version","Print version string");
Expand Down
10 changes: 10 additions & 0 deletions pdns/recursordist/docs/settings.rst
Expand Up @@ -1158,3 +1158,13 @@ and will adjust queries' source and destination accordingly. This is especially
is placed behind a proxy like dnsdist.
Note that the `allow-from`_ setting is still applied to the original source address, and thus access restriction
should be done on the proxy.

``xpf-option-code``
-------------
.. versionadded:: 4.1.0

- Integer
- Default: 0

This is an experimental implementation of `draft-bellis-dnsop-xpf`.
The option code to use for XPF records, as long as an official code has not been assigned to it. 0 means disabled.
3 changes: 2 additions & 1 deletion regression-tests.dnsdist/test_XPF.py
Expand Up @@ -10,8 +10,9 @@ class XPFTest(DNSDistTest):

_xpfCode = 65422
_config_template = """
newServer{address="127.0.0.1:%s", addXPF=true}
newServer{address="127.0.0.1:%d", addXPF=%d}
"""
_config_params = ['_testServerPort', '_xpfCode']

def checkMessageHasXPF(self, msg, expectedValue):
self.assertGreaterEqual(len(msg.additional), 1)
Expand Down

0 comments on commit f8dd365

Please sign in to comment.