]> granicus.if.org Git - pdns/commitdiff
Make the XPF code point configurable in dnsdist and the rec
authorRemi Gacogne <remi.gacogne@powerdns.com>
Thu, 2 Nov 2017 15:12:36 +0000 (16:12 +0100)
committerPieter Lexis <pieter.lexis@powerdns.com>
Mon, 22 Jan 2018 22:03:56 +0000 (23:03 +0100)
It's a bit trickier for sdig, though.

pdns/dnsdist-lua.cc
pdns/dnsdist-tcp.cc
pdns/dnsdist.cc
pdns/dnsdist.hh
pdns/dnsdistdist/docs/reference/config.rst
pdns/dnsparser.cc
pdns/pdns_recursor.cc
pdns/recursordist/docs/settings.rst
regression-tests.dnsdist/test_XPF.py

index 866ae4050ee1d6f7691b8c762d749f35fa90e5e6..0be2c3e84fd3f5274c28891539293a94b47fd67e 100644 (file)
@@ -307,10 +307,10 @@ void setupLuaConfig(bool client)
 
                        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")) {
index 54586a4375747292dd761ea349c920a932ebb484..13be397e9406a60d32c8f609ca4bc2401deae3a3 100644 (file)
@@ -440,8 +440,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;
index 293f4616ce83b2d1b6c81e36d1572dbbb4e7a98a..74924d3ec9ea825db37ef8d04c742816f88ce9a5 100644 (file)
@@ -1101,12 +1101,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());
@@ -1389,8 +1389,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++;
@@ -1542,7 +1542,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
index 06973257ba5d58e9bdd05c5b7b91130bd05959c0..6352f205f7948473ea71d800e69c6af60dca0f46 100644 (file)
@@ -624,6 +624,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;
@@ -632,7 +633,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};
@@ -869,7 +869,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"
 
index b83f05b3618f71a3531151baa40931beba3156fa..401437563c80aaf5acf83a2a3ef588aee8811e67 100644 (file)
@@ -245,8 +245,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
@@ -265,11 +263,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.
index bfe15ed93693349d85d8a708220ecf3c1b12f975..ba44b61e8da961174abffb112f784c5d5a159650 100644 (file)
@@ -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.toLogString()+"|#"+std::to_string(d_qtype)+") has a TSIG record in an invalid position.");
         }
         seenTSIG = true;
index ff3ec5ca55444ab30cef12f3504dbe83067232bb..a6f9f99db1b78425e6e827ea6e387fd5f66f7e92 100644 (file)
@@ -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;
@@ -1384,7 +1385,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();
@@ -1439,7 +1440,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;
       }
@@ -3064,6 +3065,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");
 
   g_networkTimeoutMsec = ::arg().asNum("network-timeout");
 
@@ -3498,6 +3500,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");
index 13a1e6b44b3c73834793d73867ee1f279e1a6ec3..67eb4d311e590526493393970feae5266b16247f 100644 (file)
@@ -1176,3 +1176,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.
index 261c5172b326dfba8746067de0cb6a82dc779cf2..1ee86526273ab536a426592187c576ee0e19f446 100644 (file)
@@ -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)