]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Merge pull request #11010 from omoerbeek/rec-zero-scope-negcache
authorOtto Moerbeek <otto.moerbeek@open-xchange.com>
Tue, 23 Nov 2021 10:25:23 +0000 (11:25 +0100)
committerGitHub <noreply@github.com>
Tue, 23 Nov 2021 10:25:23 +0000 (11:25 +0100)
rec: Do negcache negative results, even when wasVariable() is true

23 files changed:
.github/actions/spell-check/expect.txt
docs/conf.py
docs/requirements.txt
pdns/calidns.cc
pdns/dnsdist-console.cc
pdns/dnsdist-lua.cc
pdns/dnsdist.cc
pdns/dnsdist.hh
pdns/dnsdistdist/docs/conf.py
pdns/dnsdistdist/docs/reference/tuning.rst
pdns/dnsdistdist/docs/requirements.txt
pdns/dnsreplay.cc
pdns/iputils.cc
pdns/iputils.hh
pdns/pdns_recursor.cc
pdns/recursordist/docs/conf.py
pdns/recursordist/docs/requirements.txt
pdns/recursordist/docs/settings.rst
pdns/recursordist/rec-taskqueue.cc
pdns/recursordist/taskqueue.hh
regression-tests.recursor-dnssec/runtests
regression-tests.recursor-dnssec/test_Notify.py [new file with mode: 0644]
tasks.py

index 3f057dae289454a6ad04345a8d83ef6964644ca1..a5aad5cb2b8405944c375633d5649ef3212e0770 100644 (file)
@@ -1413,6 +1413,7 @@ rightsidebar
 Rijsdijk
 ringbuffer
 rkey
+rmem
 rname
 rng
 rocommunity
@@ -1905,6 +1906,7 @@ yubikey
 YYYYMMD
 YYYYMMDD
 YYYYMMDDSS
+wmem
 Zealey
 zeha
 Zengers
index d4da03df3c098387b734cc3e79131e3827f799a4..73df1b2a4d34d5591465131116e38bb99f65f728 100644 (file)
@@ -97,7 +97,7 @@ changelog_render_changeset = "https://github.com/PowerDNS/pdns/commit/%s"
 changelog_sections = ['New Features', 'Removed Features', 'Improvements', 'Bug Fixes']
 changelog_inner_tag_sort = ['Internals', 'API', 'Tools', 'ALIAS', 'DNSUpdate', 'BIND', 'MySQL', 'Postgresql', 'LDAP', 'GeoIP', 'Remote']
 
-changelog_render_tags = False
+changelog_hide_tags_in_entry = True
 
 # -- Options for HTML output ----------------------------------------------
 
index 669c19b98508ed026818628efb4e7d805ccf932d..4f057729fa34cf21483013feeb2b7e0169db315b 100644 (file)
@@ -1,7 +1,7 @@
 Sphinx>=1.5.0,!=1.8.0,<2.0
 git+https://github.com/pieterlexis/sphinxcontrib-openapi@use-jsondomain-pdns
 git+https://github.com/pieterlexis/sphinx-jsondomain@no-type-links
-git+https://github.com/pieterlexis/sphinx-changelog@render-tags
+changelog>=0.5.6,<0.6
 sphinxcontrib-fulltoc
 guzzle_sphinx_theme
 docutils!=0.15,<0.18
index 973e5309538ef27c5245da88b91b5ba0f5c655eb..89886e3a704929968e6b5687dc165e4bde2bb4f2 100644 (file)
@@ -117,36 +117,6 @@ static void* recvThread(const vector<std::unique_ptr<Socket>>* sockets)
   return 0;
 }
 
-static void setSocketBuffer(int fd, int optname, uint32_t size)
-{
-  uint32_t psize=0;
-  socklen_t len=sizeof(psize);
-  
-  if(!getsockopt(fd, SOL_SOCKET, optname, (char*)&psize, &len) && psize > size) {
-    if (!g_quiet) {
-      cerr<<"Not decreasing socket buffer size from "<<psize<<" to "<<size<<endl;
-    }
-    return; 
-  }
-
-  if (setsockopt(fd, SOL_SOCKET, optname, (char*)&size, sizeof(size)) < 0 ) {
-    if (!g_quiet) {
-      cerr<<"Warning: unable to raise socket buffer size to "<<size<<": "<<stringerror()<<endl;
-    }
-  }
-}
-
-
-static void setSocketReceiveBuffer(int fd, uint32_t size)
-{
-  setSocketBuffer(fd, SO_RCVBUF, size);
-}
-
-static void setSocketSendBuffer(int fd, uint32_t size)
-{
-  setSocketBuffer(fd, SO_SNDBUF, size);
-}
-
 static ComboAddress getRandomAddressFromRange(const Netmask& ecsRange)
 {
   ComboAddress result = ecsRange.getMaskedNetwork();
@@ -426,8 +396,23 @@ try
   for(int i=0; i < 24; ++i) {
     auto sock = make_unique<Socket>(dest.sin4.sin_family, SOCK_DGRAM);
     //    sock->connect(dest);
-    setSocketSendBuffer(sock->getHandle(), 2000000);
-    setSocketReceiveBuffer(sock->getHandle(), 2000000);
+    try {
+      setSocketSendBuffer(sock->getHandle(), 2000000);
+    }
+    catch (const std::exception& e) {
+      if (!g_quiet) {
+        cerr<<e.what()<<endl;
+      }
+    }
+    try {
+      setSocketReceiveBuffer(sock->getHandle(), 2000000);
+    }
+    catch (const std::exception& e) {
+      if (!g_quiet) {
+        cerr<<e.what()<<endl;
+      }
+    }
+
     sockets.push_back(std::move(sock));
   }
   new thread(recvThread, &sockets);
index 44e33cc027dc6ad5996f8ad01992c78f415ef39d..bcf605844a621fdbc19153e791aac0edb942d596 100644 (file)
@@ -633,6 +633,7 @@ const std::vector<ConsoleKeyword> g_consoleKeywords{
   { "setTCPRecvTimeout", true, "n", "set the read timeout on TCP connections from the client, in seconds" },
   { "setTCPSendTimeout", true, "n", "set the write timeout on TCP connections from the client, in seconds" },
   { "setUDPMultipleMessagesVectorSize", true, "n", "set the size of the vector passed to recvmmsg() to receive UDP messages. Default to 1 which means that the feature is disabled and recvmsg() is used instead" },
+  { "setUDPSocketBufferSizes", true, "recv, send", "Set the size of the receive (SO_RCVBUF) and send (SO_SNDBUF) buffers for incoming UDP sockets" },
   { "setUDPTimeout", true, "n", "set the maximum time dnsdist will wait for a response from a backend over UDP, in seconds" },
   { "setVerboseHealthChecks", true, "bool", "set whether health check errors will be logged" },
   { "setWebserverConfig", true, "[{password=string, apiKey=string, customHeaders, statsRequireAuthentication}]", "Updates webserver configuration" },
index fde21a9fccb47b5f95b6d308d060f91e487e40bb..07f7545c09b9686d4f133da89f2908715f9dd106 100644 (file)
@@ -242,8 +242,8 @@ static void parseTLSConfig(TLSConfig& config, const std::string& context, boost:
 
 static void checkParameterBound(const std::string& parameter, uint64_t value, size_t max = std::numeric_limits<uint16_t>::max())
 {
-  if (value > std::numeric_limits<uint16_t>::max()) {
-    throw std::runtime_error("The value passed to " + parameter + " is too large, the maximum is " + std::to_string(max));
+  if (value > max) {
+    throw std::runtime_error("The value (" + std::to_string(value) + ") passed to " + parameter + " is too large, the maximum is " + std::to_string(max));
   }
 }
 
@@ -2780,6 +2780,23 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
       }
     }
   });
+
+  luaCtx.writeFunction("setUDPSocketBufferSizes", [client](uint64_t recv, uint64_t snd) {
+    if (client) {
+      return;
+    }
+    checkParameterBound("setUDPSocketBufferSizes", recv, std::numeric_limits<uint32_t>::max());
+    checkParameterBound("setUDPSocketBufferSizes", snd, std::numeric_limits<uint32_t>::max());
+    setLuaSideEffect();
+
+    if (g_configurationDone) {
+      g_outputBuffer = "setUDPSocketBufferSizes cannot be used at runtime!\n";
+      return;
+    }
+
+    g_socketUDPSendBuffer = snd;
+    g_socketUDPRecvBuffer = recv;
+  });
 }
 
 vector<std::function<void(void)>> setupLua(LuaContext& luaCtx, bool client, bool configCheck, const std::string& config)
index 4d43eadec2868f88e1c12b04525606fefd2fbf3a..4a18e7e7ad0b1129e0a48c0e1e6b6c106632b844 100644 (file)
@@ -141,6 +141,8 @@ bool g_servFailOnNoPolicy{false};
 bool g_truncateTC{false};
 bool g_fixupCase{false};
 bool g_dropEmptyQueries{false};
+uint32_t g_socketUDPSendBuffer{0};
+uint32_t g_socketUDPRecvBuffer{0};
 
 std::set<std::string> g_capabilitiesToRetain;
 
@@ -2073,6 +2075,26 @@ static void setUpLocalBind(std::unique_ptr<ClientState>& cs)
     }
   }
 
+  if (!cs->tcp) {
+    if (g_socketUDPSendBuffer > 0) {
+      try {
+        setSocketSendBuffer(cs->udpFD, g_socketUDPSendBuffer);
+      }
+      catch (const std::exception& e) {
+        warnlog(e.what());
+      }
+    }
+
+    if (g_socketUDPRecvBuffer > 0) {
+      try {
+        setSocketReceiveBuffer(cs->udpFD, g_socketUDPRecvBuffer);
+      }
+      catch (const std::exception& e) {
+        warnlog(e.what());
+      }
+    }
+  }
+
   const std::string& itf = cs->interface;
   if (!itf.empty()) {
 #ifdef SO_BINDTODEVICE
index 4576f843593ad541ca34ca73f7c8ec256808f2ba..6ee0b3382861f43e02a6a04eca3489f7bfdb4d7e 100644 (file)
@@ -1016,6 +1016,8 @@ extern std::string g_apiConfigDirectory;
 extern bool g_servFailOnNoPolicy;
 extern size_t g_udpVectorSize;
 extern bool g_allowEmptyResponse;
+extern uint32_t g_socketUDPSendBuffer;
+extern uint32_t g_socketUDPRecvBuffer;
 
 extern shared_ptr<BPFFilter> g_defaultBPFFilter;
 extern std::vector<std::shared_ptr<DynBPFFilter> > g_dynBPFFilters;
index 70e26fa64e149e2f74b245dcdc854c6d727ad880..93f501c3d8498e235cbafc893f846c2be70e0bd9 100644 (file)
@@ -94,7 +94,7 @@ changelog_render_changeset = "https://github.com/PowerDNS/pdns/commit/%s"
 changelog_sections = ['New Features', 'Improvements', 'Bug Fixes', 'Removals']
 changelog_inner_tag_sort = ['Security', 'DNS over HTTPS', 'DNS over TLS', 'DNSCrypt', 'DNSTAP', 'Protobuf', 'Performance', 'Webserver', 'Metrics']
 
-changelog_render_tags = False
+changelog_hide_tags_in_entry = True
 
 # -- Options for HTML output ----------------------------------------------
 
index 90442f5b80c1bd3d6456cb2bbacf7d51c011332c..741540a39812cee93b3e37ca068e01101b861b44 100644 (file)
@@ -160,6 +160,17 @@ Tuning related functions
 
   :param int num: maximum number of UDP queries to accept
 
+.. function:: setUDPSocketBufferSize(recv, send)
+
+  .. versionadded:: 1.7.0
+
+  Set the size of the receive (``SO_RCVBUF``) and send (``SO_SNDBUF``) buffers for incoming UDP sockets. On Linux the default
+  values correspond to ``net.core.rmem_default`` and ``net.core.wmem_default`` , and the maximum values are restricted
+  by ``net.core.rmem_max`` and ``net.core.wmem_max``.
+
+  :param int recv: ``SO_RCVBUF`` value. Default is 0, meaning the system value will be kept.
+  :param int send: ``SO_SNDBUF`` value. Default is 0, meaning the system value will be kept.
+
 .. function:: setUDPTimeout(num)
 
   Set the maximum time dnsdist will wait for a response from a backend over UDP, in seconds. Defaults to 2
index c9a188e66396713797f2c504290bcad67f7a56dd..cc6fc587f1fdcb6e342819721afd1d2e8031043b 100644 (file)
@@ -1,7 +1,7 @@
 Sphinx>=1.5.0,!=1.8.0,<2.0
 git+https://github.com/pieterlexis/sphinx-lua@pdns
 git+https://github.com/pieterlexis/sphinx-jsondomain@no-type-links
-git+https://github.com/pieterlexis/sphinx-changelog@render-tags
+changelog>=0.5.6,<0.6
 sphinxcontrib-httpdomain
 sphinxcontrib-fulltoc
 docutils!=0.15,<0.18
index 78226d919bd96e17d7e29924996ed769855c2b4c..0d4b8d10014f7bb6bb05ac8c33002057d289e5e4 100644 (file)
@@ -163,32 +163,6 @@ private:
   
 } s_idmanager;
 
-
-static void setSocketBuffer(int fd, int optname, uint32_t size)
-{
-  uint32_t psize=0;
-  socklen_t len=sizeof(psize);
-  
-  if(!getsockopt(fd, SOL_SOCKET, optname, (char*)&psize, &len) && psize > size) {
-    cerr<<"Not decreasing socket buffer size from "<<psize<<" to "<<size<<endl;
-    return; 
-  }
-
-  if (setsockopt(fd, SOL_SOCKET, optname, (char*)&size, sizeof(size)) < 0 )
-    cerr<<"Warning: unable to raise socket buffer size to "<<size<<": "<<stringerror()<<endl;
-}
-
-static void setSocketReceiveBuffer(int fd, uint32_t size)
-{
-  setSocketBuffer(fd, SO_RCVBUF, size);
-}
-
-static void setSocketSendBuffer(int fd, uint32_t size)
-{
-  setSocketBuffer(fd, SO_SNDBUF, size);
-}
-
-
 struct AssignedIDTag{};
 struct QuestionTag{};
 
@@ -779,8 +753,18 @@ try
   if(g_vm.count("source-ip") && !g_vm["source-ip"].as<string>().empty())
     s_socket->bind(ComboAddress(g_vm["source-ip"].as<string>(), g_vm["source-port"].as<uint16_t>()));
 
-  setSocketReceiveBuffer(s_socket->getHandle(), 2000000);
-  setSocketSendBuffer(s_socket->getHandle(), 2000000);
+  try {
+    setSocketReceiveBuffer(s_socket->getHandle(), 2000000);
+  }
+  catch (const std::exception& e) {
+    cerr<<e.what()<<endl;
+  }
+  try {
+    setSocketSendBuffer(s_socket->getHandle(), 2000000);
+  }
+  catch (const std::exception& e) {
+    cerr<<e.what()<<endl;
+  }
 
   ComboAddress remote(g_vm["target-ip"].as<string>(), 
                     g_vm["target-port"].as<uint16_t>());
index 05eed1245ba48ab19be26e08391d8f5cbe637c21..1c042289a9e909c4ed7e95ef752ff33e015b1769 100644 (file)
@@ -519,3 +519,27 @@ ComboAddress parseIPAndPort(const std::string& input, uint16_t port)
     return ComboAddress(input, port);
   }
 }
+
+void setSocketBuffer(int fd, int optname, uint32_t size)
+{
+  uint32_t psize = 0;
+  socklen_t len = sizeof(psize);
+
+  if (!getsockopt(fd, SOL_SOCKET, optname, &psize, &len) && psize > size) {
+    throw std::runtime_error("Not decreasing socket buffer size from " + std::to_string(psize) + " to " + std::to_string(size));
+  }
+
+  if (setsockopt(fd, SOL_SOCKET, optname, &size, sizeof(size)) < 0) {
+    throw std::runtime_error("Unable to raise socket buffer size to " + std::to_string(size) + ": " + stringerror());
+  }
+}
+
+void setSocketReceiveBuffer(int fd, uint32_t size)
+{
+  setSocketBuffer(fd, SO_RCVBUF, size);
+}
+
+void setSocketSendBuffer(int fd, uint32_t size)
+{
+  setSocketBuffer(fd, SO_SNDBUF, size);
+}
index b36f0e27723607d1bd252f22da547fa8d0611b77..23b200b1a5375fa69f6f7f609d2614f155176190 100644 (file)
@@ -1649,3 +1649,9 @@ bool isTCPSocketUsable(int sock);
 
 extern template class NetmaskTree<bool>;
 ComboAddress parseIPAndPort(const std::string& input, uint16_t port);
+
+/* These functions throw if the value was already set to a higher value,
+   or on error */
+void setSocketBuffer(int fd, int optname, uint32_t size);
+void setSocketReceiveBuffer(int fd, uint32_t size);
+void setSocketSendBuffer(int fd, uint32_t size);
index f3ac0a08dc84491c69d44b327d21136b62dc1f3e..6e8678b19c48245d380fc8690c3d36a4b9914405 100644 (file)
@@ -597,34 +597,6 @@ PacketBuffer GenUDPQueryResponse(const ComboAddress& dest, const string& query)
 
 static void handleUDPServerResponse(int fd, FDMultiplexer::funcparam_t&);
 
-static void setSocketBuffer(int fd, int optname, uint32_t size)
-{
-  uint32_t psize=0;
-  socklen_t len=sizeof(psize);
-
-  if(!getsockopt(fd, SOL_SOCKET, optname, (char*)&psize, &len) && psize > size) {
-    g_log<<Logger::Error<<"Not decreasing socket buffer size from "<<psize<<" to "<<size<<endl;
-    return;
-  }
-
-  if (setsockopt(fd, SOL_SOCKET, optname, (char*)&size, sizeof(size)) < 0) {
-    int err = errno;
-    g_log << Logger::Error << "Unable to raise socket buffer size to " << size << ": " << stringerror(err) << endl;
-  }
-}
-
-
-static void setSocketReceiveBuffer(int fd, uint32_t size)
-{
-  setSocketBuffer(fd, SO_RCVBUF, size);
-}
-
-static void setSocketSendBuffer(int fd, uint32_t size)
-{
-  setSocketBuffer(fd, SO_SNDBUF, size);
-}
-
-
 // you can ask this class for a UDP socket to send a query from
 // this socket is not yours, don't even think about deleting it
 // but after you call 'returnSocket' on it, don't assume anything anymore
@@ -2412,11 +2384,13 @@ static void startDoResolve(void *p)
       g_log<<endl;
     }
 
-    if (sr.d_outqueries || sr.d_authzonequeries) {
-      g_recCache->cacheMisses++;
-    }
-    else {
-      g_recCache->cacheHits++;
+    if (dc->d_mdp.d_header.opcode == Opcode::Query) {
+      if (sr.d_outqueries || sr.d_authzonequeries) {
+        g_recCache->cacheMisses++;
+      }
+      else {
+        g_recCache->cacheHits++;
+      }
     }
 
     g_stats.answers(spentUsec);
@@ -2950,6 +2924,7 @@ static void handleRunningTCPQuestion(int fd, FDMultiplexer::funcparam_t& var)
             }
 
             g_stats.sourceDisallowedNotify++;
+            terminateTCPConnection(fd);
             return;
           }
 
@@ -2959,6 +2934,7 @@ static void handleRunningTCPQuestion(int fd, FDMultiplexer::funcparam_t& var)
             }
 
             g_stats.zoneDisallowedNotify++;
+            terminateTCPConnection(fd);
             return;
           }
         }
@@ -2995,6 +2971,7 @@ static void handleRunningTCPQuestion(int fd, FDMultiplexer::funcparam_t& var)
             if (dc->d_eventTrace.enabled() && SyncRes::s_event_trace_enabled & SyncRes::event_trace_to_log) {
               g_log << Logger::Info << dc->d_eventTrace.toString() << endl;
             }
+            return;
           } // cache hit
         } // query opcode
 
@@ -3680,7 +3657,13 @@ static void makeTCPServerSockets(deferredAdd_t& deferredAdds, std::set<int>& tcp
       throw PDNSException("Binding TCP server socket for "+ st.host +": "+stringerror());
 
     setNonBlocking(fd);
-    setSocketSendBuffer(fd, 65000);
+    try {
+      setSocketSendBuffer(fd, 65000);
+    }
+    catch (const std::exception& e) {
+      g_log<<Logger::Error<<e.what()<<endl;
+    }
+
     listen(fd, 128);
     deferredAdds.emplace_back(fd, handleNewTCPQuestion);
     tcpSockets.insert(fd);
@@ -3744,7 +3727,12 @@ static void makeUDPServerSockets(deferredAdd_t& deferredAdds)
 
     setCloseOnExec(fd);
 
-    setSocketReceiveBuffer(fd, 250000);
+    try {
+      setSocketReceiveBuffer(fd, 250000);
+    }
+    catch (const std::exception& e) {
+      g_log<<Logger::Error<<e.what()<<endl;
+    }
     sin.sin4.sin_port = htons(st.port);
 
   
index 54c5c447d7b627abe12df0fa55bbdeab7315339b..9e3a31cbfaa980df7f01fee86904417c194a8edf 100644 (file)
@@ -97,7 +97,7 @@ changelog_render_changeset = "https://github.com/PowerDNS/pdns/commit/%s"
 changelog_sections = ['New Features', 'Improvements', 'Bug Fixes']
 changelog_inner_tag_sort = ['General', 'DNSSEC', 'Protobuf', 'RPZ']
 
-changelog_render_tags = False
+changelog_hide_tags_in_entry = True
 
 # -- Options for HTML output ----------------------------------------------
 
index 5d88e2afefc3204c02b4d3e3add57bffaddb5bc8..448fa8d4e697f91fa3cbf91c37bbd464083a6493 100644 (file)
@@ -1,7 +1,7 @@
 Sphinx>=1.5.0,!=1.8.0,<2.0
 git+https://github.com/pieterlexis/sphinx-jsondomain@no-type-links
 git+https://github.com/pieterlexis/sphinx-lua@pdns
-git+https://github.com/pieterlexis/sphinx-changelog@render-tags
+changelog>=0.5.6,<0.6
 guzzle_sphinx_theme
 sphinxcontrib.httpdomain
 sphinxcontrib-fulltoc
index 086bd7c1d43dc1c23cf371790012cebeb33723c7..61c8d01a08599c5049fdc281b25d283b833b79e2 100644 (file)
@@ -83,6 +83,8 @@ Like `allow-notify-for`_, except reading from file. To use this
 feature, supply one domain name per line, with optional comments
 preceded by a "#".
 
+NOTIFY-allowed zones can also be specified using `forward-zones-file`_.
+
 .. _setting-allow-notify-from:
 
 ``allow-notify-from``
index 2705c59b854dfa941d3b590f291da37fdea33776..000af77dd603c6ea2661ada389b6682295e1f9a3 100644 (file)
@@ -76,7 +76,8 @@ void runTaskOnce(bool logErrors)
 void pushAlmostExpiredTask(const DNSName& qname, uint16_t qtype, time_t deadline)
 {
   ++s_almost_expired_tasks_pushed;
-  t_taskQueue.push({qname, qtype, deadline, true, resolve});
+  pdns::ResolveTask task{qname, qtype, deadline, true, resolve};
+  t_taskQueue.push(std::move(task));
 }
 
 uint64_t getTaskPushes()
index ec0c91d08894a7897202e5a01262bdbe0c519cb6..5bd53029b99ba718bd0f416e748b7e815710aff4 100644 (file)
@@ -21,6 +21,7 @@
  */
 #pragma once
 
+#include <sys/time.h>
 #include <thread>
 
 #include <boost/multi_index_container.hpp>
index 600d681adf2351f37f9d6cb7949b6b7e4208febf..d570c5849729eb94c1ec96e36ebd46f37536d6d8 100755 (executable)
@@ -21,7 +21,7 @@ export PDNSUTIL=${PDNSUTIL:-${PWD}/../pdns/pdnsutil}
 export PDNSRECURSOR=${PDNSRECURSOR:-${PWD}/../pdns/recursordist/pdns_recursor}
 export RECCONTROL=${RECCONTROL:-${PWD}/../pdns/recursordist/rec_control}
 
-LIBFAKETIME_DEFAULT=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1 # ubuntu default
+LIBFAKETIME_DEFAULT=/usr/lib/x86_64-linux-gnu/faketime/libfaketimeMT.so.1 # ubuntu default
 LIBAUTHBIND_DEFAULT=/usr/lib/authbind/libauthbind.so.1
 if [ $(uname -s) = "Darwin" ]; then
   # macOS is not /really/ supported here; it works for some tests, and then you might need sudo.
@@ -55,14 +55,9 @@ if ! "$PDNSRECURSOR" --version 2>&1 | grep Features | grep -q dnstap-framestream
   export NODNSTAPTESTS=1
 fi
 
-# libfstrm has a bad interaction with libfaketime on at least Ubuntu Focal.
-# to run the test without LIBFAKETIME, we clear the var if it set to /bin/false
-if [ "$LIBFAKETIME" = "/bin/false" ]; then
-  LIBFAKETIME=""
-fi
-
-if [ "${LIBAUTHBIND}" != "" -o "${LIBFAKETIME}" != "" ]; then
-LD_PRELOAD="${LIBASAN} ${LIBAUTHBIND} ${LIBFAKETIME}" nosetests -I test_WellKnown.py --with-xunit $@
+# LIBFAKETIME is only added to LD_PRELOAD by the pyton code when needed
+if [ "${LIBASAN}" != "" -o "${LIBAUTHBIND}" != "" ]; then
+LD_PRELOAD="${LIBASAN} ${LIBAUTHBIND}" nosetests -I test_WellKnown.py --with-xunit $@
 else
 nosetests -I test_WellKnown.py --with-xunit $@
 fi
diff --git a/regression-tests.recursor-dnssec/test_Notify.py b/regression-tests.recursor-dnssec/test_Notify.py
new file mode 100644 (file)
index 0000000..6ff0ea3
--- /dev/null
@@ -0,0 +1,117 @@
+import clientsubnetoption
+import cookiesoption
+import dns
+import os
+import requests
+import subprocess
+
+from recursortests import RecursorTest
+
+class NotifyRecursorTest(RecursorTest):
+
+    _auth_zones = {
+        '8': {'threads': 1,
+              'zones': ['ROOT']}
+    }
+
+    _confdir = 'Notify'
+    _wsPort = 8042
+    _wsTimeout = 2
+    _wsPassword = 'secretpassword'
+    _apiKey = 'secretapikey'
+    _config_template = """
+    disable-packetcache=yes
+    auth-zones=example=configs/%s/example.zone
+    allow-notify-from=127.0.0.1
+    allow-notify-for=example
+    quiet=no
+    loglevel=9
+    webserver=yes
+    webserver-port=%d
+    webserver-address=127.0.0.1
+    webserver-password=%s
+    api-key=%s
+    """ % (_confdir, _wsPort, _wsPassword, _apiKey)
+
+    @classmethod
+    def generateRecursorConfig(cls, confdir):
+        authzonepath = os.path.join(confdir, 'example.zone')
+        with open(authzonepath, 'w') as authzone:
+            authzone.write("""$ORIGIN example.
+@ 3600 IN SOA {soa}
+a 3600 IN A 192.0.2.42
+b 3600 IN A 192.0.2.42
+c 3600 IN A 192.0.2.42
+d 3600 IN A 192.0.2.42
+e 3600 IN A 192.0.2.42
+f 3600 IN CNAME f            ; CNAME loop: dirty trick to get a ServFail in an authzone
+""".format(soa=cls._SOA))
+        super(NotifyRecursorTest, cls).generateRecursorConfig(confdir)
+
+    def checkRecordCacheMetrics(self, expectedHits, expectedMisses):
+        headers = {'x-api-key': self._apiKey}
+        url = 'http://127.0.0.1:' + str(self._wsPort) + '/api/v1/servers/localhost/statistics'
+        r = requests.get(url, headers=headers, timeout=self._wsTimeout)
+        self.assertTrue(r)
+        self.assertEqual(r.status_code, 200)
+        self.assertTrue(r.json())
+        content = r.json()
+        foundHits = False
+        foundMisses = True
+        for entry in content:
+            if entry['name'] == 'cache-hits':
+                foundHits = True
+                self.assertEqual(int(entry['value']), expectedHits)
+            elif entry['name'] == 'cache-misses':
+                foundMisses = True
+                self.assertEqual(int(entry['value']), expectedMisses)
+
+        self.assertTrue(foundHits)
+        self.assertTrue(foundMisses)
+
+    def testNotify(self):
+        # first query
+        qname = 'a.example.'
+        query = dns.message.make_query(qname, 'A', want_dnssec=True)
+        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, 'A', '192.0.2.42')
+
+        for method in ("sendUDPQuery", "sendTCPQuery"):
+            sender = getattr(self, method)
+            res = sender(query)
+            self.assertRcodeEqual(res, dns.rcode.NOERROR)
+            self.assertRRsetInAnswer(res, expected)
+
+        self.checkRecordCacheMetrics(1, 1)
+
+        # we should get a hit over UDP this time
+        res = self.sendUDPQuery(query)
+        self.assertRcodeEqual(res, dns.rcode.NOERROR)
+        self.assertRRsetInAnswer(res, expected)
+        self.checkRecordCacheMetrics(2, 1)
+
+        # we should get a hit over TCP this time
+        res = self.sendTCPQuery(query)
+        self.assertRcodeEqual(res, dns.rcode.NOERROR)
+        self.assertRRsetInAnswer(res, expected)
+        self.checkRecordCacheMetrics(3, 1)
+
+        notify = dns.message.make_query('example', 'SOA', want_dnssec=False)
+        notify.set_opcode(4) # notify
+        notifyexpected = dns.rrset.from_text('example.', 0, dns.rdataclass.IN, 'SOA')
+        for method in ("sendUDPQuery", "sendTCPQuery"):
+            sender = getattr(self, method)
+            res = sender(notify)
+            self.assertRcodeEqual(res, dns.rcode.NOERROR)
+            self.assertEquals(res.opcode(), 4)
+            print(res)
+            self.assertEquals(res.question[0].to_text(), 'example. IN SOA')
+
+        self.checkRecordCacheMetrics(3, 1)
+
+        for method in ("sendUDPQuery", "sendTCPQuery"):
+            sender = getattr(self, method)
+            res = sender(query)
+            self.assertRcodeEqual(res, dns.rcode.NOERROR)
+            self.assertRRsetInAnswer(res, expected)
+
+        self.checkRecordCacheMetrics(4, 2)
index 74f14b5dcb658cf2dda4c7f28c19278448d60f90..0edc6c3f01ac5018ec81b37e9cfa4101ef64a7fd 100644 (file)
--- a/tasks.py
+++ b/tasks.py
@@ -456,8 +456,7 @@ def test_dnsdist(c):
 @task
 def test_regression_recursor(c):
     c.run('/opt/pdns-recursor/sbin/pdns_recursor --version')
-    c.run('PDNSRECURSOR=/opt/pdns-recursor/sbin/pdns_recursor RECCONTROL=/opt/pdns-recursor/bin/rec_control SKIP_IPV6_TESTS=y LIBFAKETIME=/bin/false ./build-scripts/test-recursor test_RecDnstap.py')
-    c.run('PDNSRECURSOR=/opt/pdns-recursor/sbin/pdns_recursor RECCONTROL=/opt/pdns-recursor/bin/rec_control SKIP_IPV6_TESTS=y ./build-scripts/test-recursor -I test_RecDnstap.py')
+    c.run('PDNSRECURSOR=/opt/pdns-recursor/sbin/pdns_recursor RECCONTROL=/opt/pdns-recursor/bin/rec_control SKIP_IPV6_TESTS=y ./build-scripts/test-recursor')
 
 @task
 def test_bulk_recursor(c, threads, mthreads, shards):