]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Merge pull request #7904 from rgacogne/rec-filterpo-optims
authorRemi Gacogne <rgacogne@users.noreply.github.com>
Fri, 14 Jun 2019 08:39:30 +0000 (10:39 +0200)
committerGitHub <noreply@github.com>
Fri, 14 Jun 2019 08:39:30 +0000 (10:39 +0200)
 rec: Optimize for large number of filtering policies, empty sections

30 files changed:
.circleci/config.yml
builder
builder-support/gen-version
docs/secpoll.zone
modules/lmdbbackend/lmdbbackend.cc
pdns/backends/gsql/gsqlbackend.cc
pdns/dnsdist-console.cc
pdns/dnsdist-lua-bindings.cc
pdns/dnsdist-lua.cc
pdns/dnsdistdist/.gitignore
pdns/dnsdistdist/docs/changelog.rst
pdns/dnsdistdist/docs/reference/config.rst
pdns/dnsdistdist/docs/reference/dnscrypt.rst
pdns/dnsdistdist/docs/reference/dq.rst
pdns/dnsdistdist/docs/rules-actions.rst
pdns/dynhandler.cc
pdns/lua-record.cc
pdns/lwres.cc
pdns/pdnsutil.cc
pdns/protobuf.cc
pdns/protobuf.hh
pdns/receiver.cc
pdns/recursordist/docs/changelog/4.1.rst
pdns/recursordist/test-syncres_cc9.cc
pdns/ssqlite3.cc
pdns/statbag.cc
pdns/statbag.hh
pdns/syncres.cc
pdns/ueberbackend.cc
pdns/ws-auth.cc

index 24e4874a4abd069bbb2717798767018627b88c40..b2ff9ba8355035adb35902d84c6ee3b405cbe5d6 100644 (file)
@@ -33,6 +33,15 @@ commands:
           name: Install Coverity tools
           command: curl -s https://scan.coverity.com/download/linux64 --data "token=${COVERITY_TOKEN}&project=${COVERITY_PROJECT}" |  gunzip | tar xvf /dev/stdin --strip-components=2 --no-same-owner -C /usr/local
 
+  add-docs-upload-ssh:
+    description: Add ssh known_hosts fingerprints
+    steps:
+      - run:
+          command: mkdir -p $HOME/.ssh && echo "${DOCS_HOST} ${DOCS_FINGERPRINT}" > $HOME/.ssh/known_hosts
+      - add_ssh_keys:
+          fingerprints:
+            - "3e:0a:aa:2c:30:69:89:f3:eb:17:c1:3f:3b:78:40:7a"
+
   auth-regress-setup:
     description: Prepare the environment for auth regression tests
     steps:
@@ -274,6 +283,140 @@ commands:
             - ccache-cache-{{ arch }}-<< parameters.product >>-{{ .Branch }}
             - ccache-cache-{{ arch }}-<< parameters.product >>-
 
+  install-doc-deps:
+    description: Install dependencies needed to build the documentation
+    steps:
+      - run:
+          name: Install dependencies
+          command: |
+            apt-get update && apt-get -qq -y install \
+            autoconf \
+            automake \
+            bison \
+            curl \
+            flex \
+            g++ \
+            git \
+            latexmk \
+            libboost-all-dev \
+            libedit-dev \
+            libluajit-5.1-dev \
+            libssl-dev \
+            make \
+            pkg-config \
+            ragel \
+            virtualenv
+            if [ "${CIRCLE_PROJECT_USERNAME}" = "PowerDNS" -a "${CIRCLE_PROJECT_REPONAME}" = "pdns" -a "${CIRCLE_BRANCH}" = "master" ]; then
+              apt-get update && apt-get -qq -y install \
+                texlive-full
+            fi
+
+  build-auth-docs:
+    description: Build documentation
+    steps:
+      - run:
+          name: autoconf
+          command: |
+            BUILDER_VERSION=0.0.0-git1 autoreconf -vfi
+      - run:
+          name: configure
+          command: |
+            ./configure \
+            --disable-lua-records \
+            --disable-unit-tests \
+            --without-dynmodules \
+            --without-modules
+      - run:
+          name: build docs
+          command: |
+              make -C docs html-docs
+              if [ "${CIRCLE_PROJECT_USERNAME}" = "PowerDNS" -a "${CIRCLE_PROJECT_REPONAME}" = "pdns" -a "${CIRCLE_BRANCH}" = "master" ]; then
+                make -C docs all-docs
+              fi
+
+  upload-auth-docs:
+    steps:
+      - run:
+          name: Upload documents
+          command: |
+            if [ "${CIRCLE_PROJECT_USERNAME}" = "PowerDNS" -a "${CIRCLE_PROJECT_REPONAME}" = "pdns" -a "${CIRCLE_BRANCH}" = "master" ]; then
+              rsync -crv --delete --no-p --chmod=g=rwX --exclude '*~' ./docs/html-docs/ docs_powerdns_com@${DOCS_HOST}:/authoritative/
+              rsync -crv --no-p --chmod=g=rwX --exclude '*~' ./docs/html-docs.tar.bz2 docs_powerdns_com@${DOCS_HOST}:/authoritative/
+              rsync -crv --no-p --chmod=g=rwX --exclude '*~' ./docs/PowerDNS-Authoritative.pdf docs_powerdns_com@${DOCS_HOST}:/authoritative/
+            fi
+
+  build-recursor-docs:
+    description: Build Recursor documentation
+    steps:
+      - run:
+          name: autoconf
+          command: |
+            BUILDER_VERSION=0.0.0-git1 autoreconf -vfi
+          working_directory: ~/project/pdns/recursordist
+      - run:
+          name: configure
+          command: |
+            ./configure \
+              --disable-unit-tests \
+              --disable-protobuf
+          working_directory: ~/project/pdns/recursordist
+      - run:
+          name: build docs
+          command: |
+            make html-docs
+            if [ "${CIRCLE_PROJECT_USERNAME}" = "PowerDNS" -a "${CIRCLE_PROJECT_REPONAME}" = "pdns" -a "${CIRCLE_BRANCH}" = "master" ]; then
+              make all-docs
+            fi
+          working_directory: ~/project/pdns/recursordist
+
+  upload-recursor-docs:
+    steps:
+      - run:
+          name: Upload documents
+          working_directory: ~/project/pdns/recursordist
+          command: |
+            if [ "${CIRCLE_PROJECT_USERNAME}" = "PowerDNS" -a "${CIRCLE_PROJECT_REPONAME}" = "pdns" -a "${CIRCLE_BRANCH}" = "master" ]; then
+              rsync -crv --delete --no-p --chmod=g=rwX --exclude '*~' html-docs/ docs_powerdns_com@${DOCS_HOST}:/recursor/
+              rsync -crv --no-p --chmod=g=rwX --exclude '*~' html-docs.tar.bz2 docs_powerdns_com@${DOCS_HOST}:/recursor/
+              rsync -crv --no-p --chmod=g=rwX --exclude '*~' PowerDNS-Recursor.pdf docs_powerdns_com@${DOCS_HOST}:/recursor/
+            fi
+
+  build-dnsdist-docs:
+    description: Build dnsdist documentation
+    steps:
+      - run:
+          name: autoconf
+          command: |
+            BUILDER_VERSION=0.0.0-git1 autoreconf -vfi
+          working_directory: ~/project/pdns/dnsdistdist
+      - run:
+          name: configure
+          command: |
+            ./configure \
+              --disable-unit-tests \
+              --disable-protobuf
+          working_directory: ~/project/pdns/dnsdistdist
+      - run:
+          name: build docs
+          command: |
+            make html-docs
+            if [ "${CIRCLE_PROJECT_USERNAME}" = "PowerDNS" -a "${CIRCLE_PROJECT_REPONAME}" = "pdns" -a "${CIRCLE_BRANCH}" = "master" ]; then
+              make all-docs
+            fi
+          working_directory: ~/project/pdns/dnsdistdist
+
+  upload-dnsdist-docs:
+    steps:
+      - run:
+          name: Upload documents
+          working_directory: ~/project/pdns/dnsdistdist
+          command: |
+            if [ "${CIRCLE_PROJECT_USERNAME}" = "PowerDNS" -a "${CIRCLE_PROJECT_REPONAME}" = "pdns" -a "${CIRCLE_BRANCH}" = "master" ]; then
+              rsync -crv --delete --no-p --chmod=g=rwX --exclude '*~' html-docs/ dnsdist_org@${DOCS_HOST}:
+              rsync -crv --no-p --chmod=g=rwX --exclude '*~' html-docs.tar.bz2 dnsdist_org@${DOCS_HOST}:
+              rsync -crv --no-p --chmod=g=rwX --exclude '*~' dnsdist.pdf dnsdist_org@${DOCS_HOST}:
+            fi
+
 jobs:
   build-auth:
     docker:
@@ -346,7 +489,7 @@ jobs:
   test-auth-regress-odbc-mssql:
     docker:
       - image: debian:stretch
-      - image: mcr.microsoft.com/mssql/server:2019-CTP2.2-ubuntu
+      - image: mcr.microsoft.com/mssql/server:2017-GA-ubuntu
         environment:
           - ACCEPT_EULA: Y
           - SA_PASSWORD: 'SAsa12%%'
@@ -733,6 +876,60 @@ jobs:
             PDNSRECURSOR="/opt/pdns-recursor/sbin/pdns_recursor" \
             ./runtests recursor
 
+  build-auth-docs:
+    docker:
+      - image: debian:stretch
+    steps:
+      - checkout-shallow
+      - install-doc-deps
+      - build-auth-docs
+
+  deploy-auth-docs:
+    docker:
+      - image: debian:stretch
+    steps:
+      - checkout-shallow
+      - install-doc-deps
+      - build-auth-docs
+      - add-docs-upload-ssh
+      - upload-auth-docs
+
+  build-recursor-docs:
+    docker:
+      - image: debian:stretch
+    steps:
+      - checkout-shallow
+      - install-doc-deps
+      - build-recursor-docs
+
+  deploy-recursor-docs:
+    docker:
+      - image: debian:stretch
+    steps:
+      - checkout-shallow
+      - install-doc-deps
+      - build-recursor-docs
+      - add-docs-upload-ssh
+      - upload-recursor-docs
+
+  build-dnsdist-docs:
+    docker:
+      - image: debian:stretch
+    steps:
+      - checkout-shallow
+      - install-doc-deps
+      - build-dnsdist-docs
+
+  deploy-dnsdist-docs:
+    docker:
+      - image: debian:stretch
+    steps:
+      - checkout-shallow
+      - install-doc-deps
+      - build-dnsdist-docs
+      - add-docs-upload-ssh
+      - upload-dnsdist-docs
+
   coverity-auth:
     docker:
       - image: debian:stretch
@@ -982,3 +1179,35 @@ workflows:
       - test-recursor-api:
           requires:
             - build-recursor
+
+  build-docs:
+    jobs:
+      - build-auth-docs:
+          filters:
+            branches:
+              ignore: master
+      - build-recursor-docs:
+          filters:
+            branches:
+              ignore: master
+      - build-dnsdist-docs:
+          filters:
+            branches:
+              ignore: master
+
+      # These actually deploy
+      - deploy-auth-docs:
+          context: docs
+          filters:
+            branches:
+              only: master
+      - deploy-recursor-docs:
+          context: docs
+          filters:
+            branches:
+              only: master
+      - deploy-dnsdist-docs:
+          context: docs
+          filters:
+            branches:
+              only: master
diff --git a/builder b/builder
index 4f5ab935098ebacd6b55e89b405bd69e80ab2baf..6176c5f68354ca82814ef20a4c87327785157ff3 160000 (submodule)
--- a/builder
+++ b/builder
@@ -1 +1 @@
-Subproject commit 4f5ab935098ebacd6b55e89b405bd69e80ab2baf
+Subproject commit 6176c5f68354ca82814ef20a4c87327785157ff3
index a3eb581319eb1b4ad14b071ca3743dbd4273e6bb..4411794d7244775ea3ff958d686fabe49db21d1a 100755 (executable)
@@ -10,7 +10,7 @@ DIRTY=""
 git status | grep -q clean || DIRTY='.dirty'
 
 # Special environment variable to signal that we are building a release, as this
-# has condequenses for the version number.
+# has consequenses for the version number.
 if [ "${IS_RELEASE}" = "YES" ]; then
   TAG="$(git describe --tags --exact-match 2> /dev/null | cut -d- -f 2-)"
   if [ -n "${TAG}" ]; then
@@ -27,17 +27,26 @@ fi
 # Generate the version number based on the branch
 #
 if [ ! -z "$(git rev-parse --abbrev-ref HEAD 2> /dev/null)" ]; then
-  GIT_VERSION=""
-  if $(git rev-parse --abbrev-ref HEAD | grep -q 'rel/'); then
-    REL_TYPE="$(git rev-parse --abbrev-ref HEAD | cut -d/ -f 2 | cut -d- -f 1)"
-    GIT_VERSION="$(git describe --match=${REL_TYPE}-* --tags | cut -d- -f2-)"
+  if [ -n "${BUILDER_MODULES}" ]; then
+    match=${BUILDER_MODULES}
+    [ $match = "authoritative" ] && match='auth'
+    [ $match = "recursor" ] && match='rec'
+    GIT_VERSION="$(git describe --match=${match}-* --tags | cut -d- -f2-)"
+    if [ $(echo ${GIT_VERSION} | awk -F"-" '{print NF-1}') = '3' ]; then
+      # A prerelease happened before
+      LAST_TAG="$(echo ${GIT_VERSION} | cut -d- -f1-2)"
+      COMMITS_SINCE_TAG="$(echo ${GIT_VERSION} | cut -d- -f3)"
+      GIT_HASH="$(echo ${GIT_VERSION} | cut -d- -f4)"
+    else
+      LAST_TAG="$(echo ${GIT_VERSION} | cut -d- -f1)"
+      COMMITS_SINCE_TAG="$(echo ${GIT_VERSION} | cut -d- -f2)"
+      GIT_HASH="$(echo ${GIT_VERSION} | cut -d- -f3)"
+    fi
   fi
 
-  LAST_TAG="$(echo ${GIT_VERSION} | cut -d- -f1)"
-  COMMITS_SINCE_TAG="$(echo ${GIT_VERSION} | cut -d- -f2)"
-  GIT_HASH="$(echo ${GIT_VERSION} | cut -d- -f3)"
-
   if [ -z "${GIT_VERSION}" ]; then
+    # BUILDER_SUPPORT has more than one product listed, fall back to the 0.0.0 logic
+
     # We used 0.0.XXXXgHASH for master in the previous incarnation of our build pipeline.
     # This now becomes 0.0.XXXX.0.gHASH, as 0.0.0.XXXX.gHASH (which is more correct)
     # would break upgrades for those running master
@@ -45,11 +54,10 @@ if [ ! -z "$(git rev-parse --abbrev-ref HEAD 2> /dev/null)" ]; then
     LAST_TAG=0.0
     COMMITS_SINCE_TAG="$(git rev-list --count 12c868770afc20b6cc0da439d881105151d557dd..HEAD 2> /dev/null).0"
     [ "${COMMITS_SINCE_TAG}" = ".0" ] && COMMITS_SINCE_TAG=0.0
-    GIT_HASH="$(git rev-parse HEAD | cut -c1-10 2> /dev/null)"
+    GIT_HASH="g$(git rev-parse HEAD | cut -c1-10 2> /dev/null)"
   fi
 
   BRANCH=".$(git rev-parse --abbrev-ref HEAD | perl -p -e 's/[^[:alnum:]]//g;')"
-  [ "${BRANCH}" = ".master" ] && BRANCH=''
 
   TAG="$(git describe --tags --exact-match 2> /dev/null | cut -d- -f 2-)"
   if [ -n "${TAG}" ]; then # We're exactly on a tag
@@ -60,7 +68,7 @@ if [ ! -z "$(git rev-parse --abbrev-ref HEAD 2> /dev/null)" ]; then
     fi
   fi
 
-  VERSION="${LAST_TAG}.${COMMITS_SINCE_TAG}${BRANCH}.g${GIT_HASH}${DIRTY}"
+  VERSION="${LAST_TAG}.${COMMITS_SINCE_TAG}${BRANCH}.${GIT_HASH}${DIRTY}"
 fi
 
 printf $VERSION
index ec04ba4f92ae50e5aae4214507f314610ec958db..c557941294cba50f749f58009ddc8b88e8d905b2 100644 (file)
@@ -1,4 +1,4 @@
-@       86400   IN  SOA pdns-public-ns1.powerdns.com. pieter\.lexis.powerdns.com. 2019060601 10800 3600 604800 10800
+@       86400   IN  SOA pdns-public-ns1.powerdns.com. pieter\.lexis.powerdns.com. 2019061301 10800 3600 604800 10800
 @       3600    IN  NS  pdns-public-ns1.powerdns.com.
 @       3600    IN  NS  pdns-public-ns2.powerdns.com.
 ; Auth
@@ -182,6 +182,7 @@ recursor-4.1.10.security-status                         60 IN TXT "1 OK"
 recursor-4.1.11.security-status                         60 IN TXT "1 OK"
 recursor-4.1.12.security-status                         60 IN TXT "1 OK"
 recursor-4.1.13.security-status                         60 IN TXT "1 OK"
+recursor-4.1.14.security-status                         60 IN TXT "1 OK"
 recursor-4.2.0-alpha1.security-status                   60 IN TXT "1 OK"
 recursor-4.2.0-beta1.security-status                    60 IN TXT "1 OK"
 recursor-4.2.0-rc1.security-status                      60 IN TXT "1 OK"
index 165dcf01e3c2b681b8c48f8378c247e5b141e838..e78744a937b0664422da0f29177005c8b497cf9c 100644 (file)
@@ -58,7 +58,7 @@ LMDBBackend::LMDBBackend(const std::string& suffix)
     d_asyncFlag = MDB_NOMETASYNC;
   else if(syncMode == "mapasync")
     d_asyncFlag = MDB_MAPASYNC;
-  else if(syncMode.empty())
+  else if(syncMode.empty() || syncMode == "sync")
     d_asyncFlag = 0;
   else
     throw std::runtime_error("Unknown sync mode "+syncMode+" requested for LMDB backend");
@@ -1594,7 +1594,7 @@ public:
   void declareArguments(const string &suffix="")
   {
     declare(suffix,"filename","Filename for lmdb","./pdns.lmdb");
-    declare(suffix,"sync-mode","Synchronisation mode: nosync, nometasync, mapasync","mapasync");
+    declare(suffix,"sync-mode","Synchronisation mode: nosync, nometasync, mapasync, sync","mapasync");
     // there just is no room for more on 32 bit
     declare(suffix,"shards","Records database will be split into this number of shards", (sizeof(long) == 4) ? "2" : "64"); 
   }
index 7dc46b588bc5c2841bf7a5e4afe32f528810ea80..0f13175cbde8ddc75f21805d8748dcfcc268f136 100644 (file)
@@ -1349,6 +1349,10 @@ bool GSQLBackend::replaceRRSet(uint32_t domain_id, const DNSName& qname, const Q
   try {
     reconnectIfNeeded();
 
+    if (!d_inTransaction) {
+      throw PDNSException("replaceRRSet called outside of transaction");
+    }
+
     if (qt != QType::ANY) {
       d_DeleteRRSetQuery_stmt->
         bind("domain_id", domain_id)->
@@ -1495,6 +1499,9 @@ bool GSQLBackend::startTransaction(const DNSName &domain, int domain_id)
   try {
     reconnectIfNeeded();
 
+    if (inTransaction()) {
+      throw PDNSException("Attempted to start transaction while one was already active (domain '" + domain.toLogString() + "')");
+    }
     d_db->startTransaction();
     d_inTransaction = true;
     if(domain_id >= 0) {
@@ -1611,6 +1618,10 @@ bool GSQLBackend::replaceComments(const uint32_t domain_id, const DNSName& qname
   try {
     reconnectIfNeeded();
 
+    if (!d_inTransaction) {
+      throw PDNSException("replaceComments called outside of transaction");
+    }
+
     d_DeleteCommentRRsetQuery_stmt->
       bind("domain_id",domain_id)->
       bind("qname", qname)->
index 65fcf8ab8814850ed85d1eb06a97a3d179905bdb..98813b5cb1a5454b44297fde5a82a1dd705864fe 100644 (file)
@@ -345,11 +345,11 @@ const std::vector<ConsoleKeyword> g_consoleKeywords{
   { "addAction", true, "DNS rule, DNS action [, {uuid=\"UUID\"}]", "add a rule" },
   { "addBPFFilterDynBlocks", true, "addresses, dynbpf[[, seconds=10], msg]", "This is the eBPF equivalent of addDynBlocks(), blocking a set of addresses for (optionally) a number of seconds, using an eBPF dynamic filter" },
   { "addConsoleACL", true, "netmask", "add a netmask to the console ACL" },
-  { "addDNSCryptBind", true, "\"127.0.0.1:8443\", \"provider name\", \"/path/to/resolver.cert\", \"/path/to/resolver.key\", {reusePort=false, tcpFastOpenSize=0, interface=\"\", cpus={}}", "listen to incoming DNSCrypt queries on 127.0.0.1 port 8443, with a provider name of `provider name`, using a resolver certificate and associated key stored respectively in the `resolver.cert` and `resolver.key` files. The fifth optional parameter is a table of parameters" },
+  { "addDNSCryptBind", true, "\"127.0.0.1:8443\", \"provider name\", \"/path/to/resolver.cert\", \"/path/to/resolver.key\", {reusePort=false, tcpFastOpenQueueSize=0, interface=\"\", cpus={}}", "listen to incoming DNSCrypt queries on 127.0.0.1 port 8443, with a provider name of `provider name`, using a resolver certificate and associated key stored respectively in the `resolver.cert` and `resolver.key` files. The fifth optional parameter is a table of parameters" },
   { "addDOHLocal", true, "addr, certFile, keyFile [, urls [, vars]]", "listen to incoming DNS over HTTPS queries on the specified address using the specified certificate and key. The last two parameters are tables" },
   { "addDynBlocks", true, "addresses, message[, seconds[, action]]", "block the set of addresses with message `msg`, for `seconds` seconds (10 by default), applying `action` (default to the one set with `setDynBlocksAction()`)" },
   { "addDynBlockSMT", true, "names, msessage[, 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, tcpFastOpenSize=0, interface=\"\", cpus={}}]", "add `addr` to the list of addresses we listen on" },
+  { "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\"}]", "add a cache hit response rule" },
   { "addResponseAction", true, "DNS rule, DNS response action [, {uuid=\"UUID\"}]", "add a response rule" },
   { "addSelfAnsweredResponseAction", true, "DNS rule, DNS response action [, {uuid=\"UUID\"}]", "add a self-answered response rule" },
@@ -491,7 +491,7 @@ const std::vector<ConsoleKeyword> g_consoleKeywords{
   { "setECSSourcePrefixV4", true, "prefix-length", "the EDNS Client Subnet prefix-length used for IPv4 queries" },
   { "setECSSourcePrefixV6", true, "prefix-length", "the EDNS Client Subnet prefix-length used for IPv6 queries" },
   { "setKey", true, "key", "set access key to that key" },
-  { "setLocal", true, "addr [, {doTCP=true, reusePort=false, tcpFastOpenSize=0, interface=\"\", cpus={}}]", "reset the list of addresses we listen on to this address" },
+  { "setLocal", true, "addr [, {doTCP=true, reusePort=false, tcpFastOpenQueueSize=0, interface=\"\", cpus={}}]", "reset the list of addresses we listen on to this address" },
   { "setMaxTCPClientThreads", true, "n", "set the maximum of TCP client threads, handling TCP connections" },
   { "setMaxTCPConnectionDuration", true, "n", "set the maximum duration of an incoming TCP connection, in seconds. 0 means unlimited" },
   { "setMaxTCPConnectionsPerClient", true, "n", "set the maximum number of TCP connections per client. 0 means unlimited" },
index 64b48b6c5833044076a90db2bc5753de54081229..d29081e100603277f9e85f57d2a0a9f2d1a8a4fd 100644 (file)
@@ -320,7 +320,7 @@ void setupLuaBindings(bool client)
               boost::optional<uint16_t> qtype,
               boost::optional<bool> suffixMatch) {
                 if (cache) {
-                  cache->expungeByName(dname, qtype ? *qtype : QType(QType::ANY).getCode(), suffixMatch ? *suffixMatch : false);
+                  g_outputBuffer="Expunged " + std::to_string(cache->expungeByName(dname, qtype ? *qtype : QType(QType::ANY).getCode(), suffixMatch ? *suffixMatch : false)) + " records\n";
                 }
     });
   g_lua.registerFunction<void(std::shared_ptr<DNSDistPacketCache>::*)()>("printStats", [](const std::shared_ptr<DNSDistPacketCache> cache) {
index 71421a1862b447503abeab1c4287fb88842a33aa..aab963cf6675544865fb5d86c8f1dd9f4a836bcd 100644 (file)
@@ -89,12 +89,9 @@ void resetLuaSideEffect()
 
 typedef std::unordered_map<std::string, boost::variant<bool, int, std::string, std::vector<std::pair<int,int> > > > localbind_t;
 
-static void parseLocalBindVars(boost::optional<localbind_t> vars, bool& doTCP, bool& reusePort, int& tcpFastOpenQueueSize, std::string& interface, std::set<int>& cpus)
+static void parseLocalBindVars(boost::optional<localbind_t> vars, bool& reusePort, int& tcpFastOpenQueueSize, std::string& interface, std::set<int>& cpus)
 {
   if (vars) {
-    if (vars->count("doTCP")) {
-      doTCP = boost::get<bool>((*vars)["doTCP"]);
-    }
     if (vars->count("reusePort")) {
       reusePort = boost::get<bool>((*vars)["reusePort"]);
     }
@@ -485,13 +482,12 @@ void setupLuaConfig(bool client)
         g_outputBuffer="setLocal cannot be used at runtime!\n";
         return;
       }
-      bool doTCP = true;
       bool reusePort = false;
       int tcpFastOpenQueueSize = 0;
       std::string interface;
       std::set<int> cpus;
 
-      parseLocalBindVars(vars, doTCP, reusePort, tcpFastOpenQueueSize, interface, cpus);
+      parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus);
 
       try {
        ComboAddress loc(addr, 53);
@@ -507,9 +503,7 @@ void setupLuaConfig(bool client)
 
         // only works pre-startup, so no sync necessary
         g_frontends.push_back(std::unique_ptr<ClientState>(new ClientState(loc, false, reusePort, tcpFastOpenQueueSize, interface, cpus)));
-        if (doTCP) {
-          g_frontends.push_back(std::unique_ptr<ClientState>(new ClientState(loc, true, reusePort, tcpFastOpenQueueSize, interface, cpus)));
-        }
+        g_frontends.push_back(std::unique_ptr<ClientState>(new ClientState(loc, true, reusePort, tcpFastOpenQueueSize, interface, cpus)));
       }
       catch(const std::exception& e) {
        g_outputBuffer="Error: "+string(e.what())+"\n";
@@ -524,24 +518,22 @@ void setupLuaConfig(bool client)
         g_outputBuffer="addLocal cannot be used at runtime!\n";
         return;
       }
-      bool doTCP = true;
       bool reusePort = false;
       int tcpFastOpenQueueSize = 0;
       std::string interface;
       std::set<int> cpus;
 
-      parseLocalBindVars(vars, doTCP, reusePort, tcpFastOpenQueueSize, interface, cpus);
+      parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus);
 
       try {
        ComboAddress loc(addr, 53);
         // only works pre-startup, so no sync necessary
         g_frontends.push_back(std::unique_ptr<ClientState>(new ClientState(loc, false, reusePort, tcpFastOpenQueueSize, interface, cpus)));
-        if (doTCP) {
-          g_frontends.push_back(std::unique_ptr<ClientState>(new ClientState(loc, true, reusePort, tcpFastOpenQueueSize, interface, cpus)));
-        }
+        g_frontends.push_back(std::unique_ptr<ClientState>(new ClientState(loc, true, reusePort, tcpFastOpenQueueSize, interface, cpus)));
       }
       catch(std::exception& e) {
-       g_outputBuffer="Error: "+string(e.what())+"\n";
+        g_outputBuffer="Error: "+string(e.what())+"\n";
+        errlog("Error while trying to listen on %s: %s\n", addr, string(e.what()));
       }
     });
 
@@ -1100,13 +1092,12 @@ void setupLuaConfig(bool client)
         return;
       }
 #ifdef HAVE_DNSCRYPT
-      bool doTCP = true;
       bool reusePort = false;
       int tcpFastOpenQueueSize = 0;
       std::string interface;
       std::set<int> cpus;
 
-      parseLocalBindVars(vars, doTCP, reusePort, tcpFastOpenQueueSize, interface, cpus);
+      parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus);
 
       try {
         auto ctx = std::make_shared<DNSCryptContext>(providerName, certFile, keyFile);
@@ -1649,10 +1640,10 @@ void setupLuaConfig(bool client)
   });
 
   g_lua.writeFunction("addDOHLocal", [client](const std::string& addr, boost::variant<std::string, std::vector<std::pair<int,std::string>>> certFiles, boost::variant<std::string, std::vector<std::pair<int,std::string>>> keyFiles, boost::optional<boost::variant<std::string, vector<pair<int, std::string> > > > urls, boost::optional<localbind_t> vars) {
+#ifdef HAVE_DNS_OVER_HTTPS
     if (client) {
       return;
     }
-#ifdef HAVE_DNS_OVER_HTTPS
     setLuaSideEffect();
     if (g_configurationDone) {
       g_outputBuffer="addDOHLocal cannot be used at runtime!\n";
@@ -1680,15 +1671,13 @@ void setupLuaConfig(bool client)
       frontend->d_urls = {"/"};
     }
 
-    bool doTCP = true;
     bool reusePort = false;
     int tcpFastOpenQueueSize = 0;
     std::string interface;
     std::set<int> cpus;
-    (void) doTCP;
 
     if(vars) {
-      parseLocalBindVars(vars, doTCP, reusePort, tcpFastOpenQueueSize, interface, cpus);
+      parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus);
 
       if (vars->count("idleTimeout")) {
         frontend->d_idleTimeout = boost::get<int>((*vars)["idleTimeout"]);
@@ -1708,7 +1697,7 @@ void setupLuaConfig(bool client)
     cs->dohFrontend = frontend;
     g_frontends.push_back(std::move(cs));
 #else
-    g_outputBuffer="DNS over HTTPS support is not present!\n";
+    throw std::runtime_error("addDOHLocal() called but DNS over HTTPS support is not present!");
 #endif
   });
 
@@ -1750,7 +1739,7 @@ void setupLuaConfig(bool client)
         }
         catch(const std::exception& e) {
           g_outputBuffer="Error while trying to get DOH frontend with index " + std::to_string(index) + ": "+string(e.what())+"\n";
-          errlog("Error while trying to get get DOH frontend with index %zu: %s\n", index, string(e.what()));
+          errlog("Error while trying to get DOH frontend with index %zu: %s\n", index, string(e.what()));
         }
 #else
         g_outputBuffer="DNS over HTTPS support is not present!\n";
@@ -1765,9 +1754,9 @@ void setupLuaConfig(bool client)
       });
 
   g_lua.writeFunction("addTLSLocal", [client](const std::string& addr, boost::variant<std::string, std::vector<std::pair<int,std::string>>> certFiles, boost::variant<std::string, std::vector<std::pair<int,std::string>>> keyFiles, boost::optional<localbind_t> vars) {
+#ifdef HAVE_DNS_OVER_TLS
         if (client)
           return;
-#ifdef HAVE_DNS_OVER_TLS
         setLuaSideEffect();
         if (g_configurationDone) {
           g_outputBuffer="addTLSLocal cannot be used at runtime!\n";
@@ -1779,15 +1768,13 @@ void setupLuaConfig(bool client)
           return;
         }
 
-        bool doTCP = true;
         bool reusePort = false;
         int tcpFastOpenQueueSize = 0;
         std::string interface;
         std::set<int> cpus;
-        (void) doTCP;
 
         if (vars) {
-          parseLocalBindVars(vars, doTCP, reusePort, tcpFastOpenQueueSize, interface, cpus);
+          parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus);
 
           if (vars->count("provider")) {
             frontend->d_provider = boost::get<const string>((*vars)["provider"]);
@@ -1841,7 +1828,7 @@ void setupLuaConfig(bool client)
           g_outputBuffer="Error: "+string(e.what())+"\n";
         }
 #else
-        g_outputBuffer="DNS over TLS support is not present!\n";
+        throw std::runtime_error("addTLSLocal() called but DNS over TLS support is not present!");
 #endif
       });
 
index af0a51f259e5103a78c99b73152bab058062f4e6..5cec6c5e8f509f43c772c05c100016761b72ad24 100644 (file)
@@ -19,6 +19,8 @@
 /depcomp
 /dnsdist.1
 /dnslabeltext.cc
+/ext/ipcrypt/Makefile
+/ext/ipcrypt/Makefile.in
 /ext/yahttp/Makefile
 /ext/yahttp/Makefile.in
 /ext/yahttp/yahttp/Makefile
index c07abb5be0b03da8f2ca88601d899d9d5018c540..128a0b3f4816e45d9ae769df5549fac2dd03c81c 100644 (file)
@@ -5,7 +5,7 @@ Changelog
   :version: 1.4.0-beta1
   :released: 6th of June 2019
 
-    .. change::
+  .. change::
     :tags: Bug Fixes, DoH
     :pullreq: 7814
     :tickets: 7810
index 623ef6c2d4ac4ea223344a0138c0e08406841ef8..00b2293f8f58990fabd85dc7c05870a011bccd0d 100644 (file)
@@ -66,6 +66,9 @@ Listen Sockets
   .. versionchanged:: 1.3.0
     Added ``cpus`` to the options.
 
+  .. versionchanged:: 1.4.0
+    Removed ``doTCP`` from the options. A listen socket on TCP is always created.
+
   Add to the list of listen addresses.
 
   :param str address: The IP Address with an optional port to listen on.
@@ -74,15 +77,15 @@ Listen Sockets
 
   Options:
 
-  * ``doTCP=true``: bool - Also bind on TCP on ``address``.
+  * ``doTCP=true``: bool - Also bind on TCP on ``address``. Removed in 1.4.0.
   * ``reusePort=false``: bool - Set the ``SO_REUSEPORT`` socket option.
-  * ``tcpFastOpenSize=0``: int - Set the TCP Fast Open queue size, enabling TCP Fast Open when available and the value is larger than 0.
+  * ``tcpFastOpenQueueSize=0``: int - Set the TCP Fast Open queue size, enabling TCP Fast Open when available and the value is larger than 0.
   * ``interface=""``: str - Set the network interface to use.
   * ``cpus={}``: table - Set the CPU affinity for this listener thread, asking the scheduler to run it on a single CPU id, or a set of CPU ids. This parameter is only available if the OS provides the pthread_setaffinity_np() function.
 
   .. code-block:: lua
 
-    addLocal('0.0.0.0:5300', { doTCP=true, reusePort=true })
+    addLocal('0.0.0.0:5300', { reusePort=true })
 
   This will bind to both UDP and TCP on port 5300 with SO_REUSEPORT enabled.
 
@@ -110,13 +113,13 @@ Listen Sockets
                       The default port is 443.
   :param str certFile(s): The path to a X.509 certificate file in PEM format, or a list of paths to such files.
   :param str keyFile(s): The path to the private key file corresponding to the certificate, or a list of paths to such files, whose order should match the certFile(s) ones.
-  :param str or list urls: A base URL, or a list of base URLs, to accept queries on. Any query with a path under one of these will be treated as a DoH query. The default is /.
+  :param str-or-list urls: A base URL, or a list of base URLs, to accept queries on. Any query with a path under one of these will be treated as a DoH query. The default is /.
   :param table options: A table with key: value pairs with listen options.
 
   Options:
 
   * ``reusePort=false``: bool - Set the ``SO_REUSEPORT`` socket option.
-  * ``tcpFastOpenSize=0``: int - Set the TCP Fast Open queue size, enabling TCP Fast Open when available and the value is larger than 0.
+  * ``tcpFastOpenQueueSize=0``: int - Set the TCP Fast Open queue size, enabling TCP Fast Open when available and the value is larger than 0.
   * ``interface=""``: str - Set the network interface to use.
   * ``cpus={}``: table - Set the CPU affinity for this listener thread, asking the scheduler to run it on a single CPU id, or a set of CPU ids. This parameter is only available if the OS provides the pthread_setaffinity_np() function.
   * ``idleTimeout=30``: int - Set the idle timeout, in seconds.
@@ -146,7 +149,7 @@ Listen Sockets
   Options:
 
   * ``reusePort=false``: bool - Set the ``SO_REUSEPORT`` socket option.
-  * ``tcpFastOpenSize=0``: int - Set the TCP Fast Open queue size, enabling TCP Fast Open when available and the value is larger than 0.
+  * ``tcpFastOpenQueueSize=0``: int - Set the TCP Fast Open queue size, enabling TCP Fast Open when available and the value is larger than 0.
   * ``interface=""``: str - Set the network interface to use.
   * ``cpus={}``: table - Set the CPU affinity for this listener thread, asking the scheduler to run it on a single CPU id, or a set of CPU ids. This parameter is only available if the OS provides the pthread_setaffinity_np() function.
   * ``provider``: str - The TLS library to use between GnuTLS and OpenSSL, if they were available and enabled at compilation time.
@@ -1088,12 +1091,18 @@ Other functions
   If this function exists, it is called every second to so regular tasks.
   This can be used for e.g. :doc:`Dynamic Blocks <../guides/dynblocks>`.
 
-.. function: setAllowEmptyResponse()
+.. function:: setAllowEmptyResponse()
 
   .. versionadded:: 1.4.0
 
   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.
 
+.. function:: makeIPCipherKey(password) -> string
+
+  .. versionadded:: 1.4.0
+
+  Hashes the password to generate a 16-byte key that can be used to pseudonymize IP addresses with IP cipher.
+
 DOHFrontend
 ~~~~~~~~~~~
 
index 3e689a452f3499316b1e697bcc5309922b6e7d03..d25c6cfce888d57acf0b9727a807e88648b1560d 100644 (file)
@@ -6,6 +6,9 @@ DNSCrypt objects and functions
   .. versionchanged:: 1.3.0
     ``cpus`` option added.
 
+  .. versionchanged:: 1.4.0
+    Removed ``doTCP`` from the options. A listen socket on TCP is always created.
+
   Adds a DNSCrypt listen socket on ``address``.
 
   :param string address: The address and port to listen on
@@ -16,9 +19,9 @@ DNSCrypt objects and functions
 
   Options:
 
-  * ``doTCP=true``: bool - Also bind on TCP on ``address``.
+  * ``doTCP=true``: bool - Also bind on TCP on ``address``, removed in 1.4.0.
   * ``reusePort=false``: bool - Set the ``SO_REUSEPORT`` socket option.
-  * ``tcpFastOpenSize=0``: int - Set the TCP Fast Open queue size, enabling TCP Fast Open when available and the value is larger than 0
+  * ``tcpFastOpenQueueSize=0``: int - Set the TCP Fast Open queue size, enabling TCP Fast Open when available and the value is larger than 0
   * ``interface=""``: str - Sets the network interface to use
   * ``cpus={}``: table - Set the CPU affinity for this listener thread, asking the scheduler to run it on a single CPU id, or a set of CPU ids. This parameter is only available if the OS provides the pthread_setaffinity_np() function.
 
index c19d6dad9bfbbbb0d46e3eec1a2aa5e6367a2ee5..a02c9d2da36b76e8081e64ad7c927c953b5897c5 100644 (file)
@@ -38,7 +38,7 @@ This state can be modified from the various hooks.
   .. attribute:: DNSQuestion.qclass
 
     QClass (as an unsigned integer) of this question.
-    Can be compared against :ref:`DNSQClass`.
+    Can be compared against :ref:`DNSClass`.
 
   .. attribute:: DNSQuestion.qname
 
@@ -178,7 +178,7 @@ DNSResponse object
     All parameters to ``func`` are integers:
 
     - ``section`` is the section in the packet and can be compared to :ref:`DNSSection`
-    - ``qclass`` is the QClass of the record. Can be compared to :ref:`DNSQClass`
+    - ``qclass`` is the QClass of the record. Can be compared to :ref:`DNSClass`
     - ``qtype`` is the QType of the record. Can be e.g. compared to ``DNSQType.A``, ``DNSQType.AAAA`` :ref:`constants <DNSQType>` and the like.
     - ``ttl`` is the current TTL
 
index 73398baa673a4c7818ef44ab2f06e1736e654227..58eff1c9c18ef27c23493df6a8ee4f36cc773631 100644 (file)
@@ -1019,7 +1019,7 @@ The following actions exist.
   Options:
 
   * ``serverID=""``: str - Set the Server Identity field.
-  * ``ipEncryptKey=""``: str - A key, that can be generated via the :ref:`makeIPCipherKey` function, to encrypt the IP address of the requestor for anonymization purposes. The encryption is done using ipcrypt for IPv4 and a 128-bit AES ECB operation for IPv6.
+  * ``ipEncryptKey=""``: str - A key, that can be generated via the :func:`makeIPCipherKey` function, to encrypt the IP address of the requestor for anonymization purposes. The encryption is done using ipcrypt for IPv4 and a 128-bit AES ECB operation for IPv6.
 
 .. function:: RemoteLogResponseAction(remoteLogger[, alterFunction[, includeCNAME [, options]]])
 
@@ -1042,7 +1042,7 @@ The following actions exist.
   Options:
 
   * ``serverID=""``: str - Set the Server Identity field.
-  * ``ipEncryptKey=""``: str - A key, that can be generated via the :ref:`makeIPCipherKey` function, to encrypt the IP address of the requestor for anonymization purposes. The encryption is done using ipcrypt for IPv4 and a 128-bit AES ECB operation for IPv6.
+  * ``ipEncryptKey=""``: str - A key, that can be generated via the :func:`makeIPCipherKey` function, to encrypt the IP address of the requestor for anonymization purposes. The encryption is done using ipcrypt for IPv4 and a 128-bit AES ECB operation for IPv6.
 
 .. function:: SetECSAction(v4 [, v6])
 
index e1ea81f82a5afeca3618150e5341a01ea7aab5d6..bef847764b4ee1c795d84978c33bff89276055ab 100644 (file)
@@ -83,23 +83,22 @@ string DLPingHandler(const vector<string>&parts, Utility::pid_t ppid)
   return "PONG";
 }
 
-string DLShowHandler(const vector<string>&parts, Utility::pid_t ppid)
-try
-{
-  extern StatBag S;
-  string ret("Wrong number of parameters");
-  if(parts.size()==2) {
-    if(parts[1]=="*")
-      ret=S.directory();
-    else
-      ret=S.getValueStr(parts[1]);
-  }
+string DLShowHandler(const vector<string>&parts, Utility::pid_t ppid) {
+  try {
+    extern StatBag S;
+    string ret("Wrong number of parameters");
+    if (parts.size() == 2) {
+      if (parts[1] == "*")
+        ret = S.directory();
+      else
+        ret = S.getValueStr(parts[1]);
+    }
 
-  return ret;
-}
-catch(...)
-{
-  return "Unknown";
+    return ret;
+  }
+  catch (...) {
+    return "Unknown";
+  }
 }
 
 void setStatus(const string &str)
index 0e2b9102b813e491bca4297308dd6cebed8dfd6e..12bbaa662105be7de225d2ff0805c09778f48a2b 100644 (file)
@@ -490,6 +490,7 @@ std::vector<shared_ptr<DNSRecordContent>> luaSynth(const std::string& code, cons
     bestwho=dnsp.getRealRemote().getNetwork();
   }
   else {
+    lua.writeVariable("ecswho", nullptr);
     bestwho=dnsp.getRemote();
   }
 
index 3d3aee1e053e685b9cb7544929341ff1b1f44558..d6ff02696c5176691dce04192b7351adc1601f12 100644 (file)
@@ -118,48 +118,46 @@ static void logFstreamResponse(const std::shared_ptr<std::vector<std::unique_ptr
 
 #endif // HAVE_FSTRM
 
-static void logOutgoingQuery(const std::shared_ptr<std::vector<std::unique_ptr<RemoteLogger>>>& outgoingLoggers, boost::optional<const boost::uuids::uuid&> initialRequestId, const boost::uuids::uuid& uuid, const ComboAddress& ip, const DNSName& domain, int type, uint16_t qid, bool doTCP, size_t bytes, boost::optional<Netmask>& srcmask)
+static void logOutgoingQuery(const std::shared_ptr<std::vector<std::unique_ptr<RemoteLogger>>>& outgoingLoggers, boost::optional<RecProtoBufMessage>& message, boost::optional<const boost::uuids::uuid&> initialRequestId, const boost::uuids::uuid& uuid, const ComboAddress& ip, const DNSName& domain, int type, uint16_t qid, bool doTCP, size_t bytes, boost::optional<Netmask>& srcmask)
 {
   if(!outgoingLoggers)
     return;
 
-  RecProtoBufMessage message(DNSProtoBufMessage::OutgoingQuery, uuid, nullptr, &ip, domain, type, QClass::IN, qid, doTCP, bytes);
-  message.setServerIdentity(SyncRes::s_serverID);
+  message = RecProtoBufMessage(DNSProtoBufMessage::OutgoingQuery, uuid, nullptr, &ip, domain, type, QClass::IN, qid, doTCP, bytes);
+  message->setServerIdentity(SyncRes::s_serverID);
 
   if (initialRequestId) {
-    message.setInitialRequestID(*initialRequestId);
+    message->setInitialRequestID(*initialRequestId);
   }
 
   if (srcmask) {
-    message.setEDNSSubnet(*srcmask);
+    message->setEDNSSubnet(*srcmask);
   }
 
 //  cerr <<message.toDebugString()<<endl;
   std::string str;
-  message.serialize(str);
+  message->serialize(str);
 
   for (auto& logger : *outgoingLoggers) {
     logger->queueData(str);
   }
 }
 
-static void logIncomingResponse(const std::shared_ptr<std::vector<std::unique_ptr<RemoteLogger>>>& outgoingLoggers, boost::optional<const boost::uuids::uuid&> initialRequestId, const boost::uuids::uuid& uuid, const ComboAddress& ip, const DNSName& domain, int type, uint16_t qid, bool doTCP, size_t bytes, int rcode, const std::vector<DNSRecord>& records, const struct timeval& queryTime, const std::set<uint16_t>& exportTypes)
+static void logIncomingResponse(const std::shared_ptr<std::vector<std::unique_ptr<RemoteLogger>>>& outgoingLoggers, boost::optional<RecProtoBufMessage>& message, size_t bytes, int rcode, const std::vector<DNSRecord>& records, const struct timeval& queryTime, const std::set<uint16_t>& exportTypes)
 {
-  if(!outgoingLoggers)
+  if(!outgoingLoggers || !message)
     return;
 
-  RecProtoBufMessage message(DNSProtoBufMessage::IncomingResponse, uuid, nullptr, &ip, domain, type, QClass::IN, qid, doTCP, bytes);
-  message.setServerIdentity(SyncRes::s_serverID);
-  if (initialRequestId) {
-    message.setInitialRequestID(*initialRequestId);
-  }
-  message.setQueryTime(queryTime.tv_sec, queryTime.tv_usec);
-  message.setResponseCode(rcode);
-  message.addRRs(records, exportTypes);
+  message->updateTime();
+  message->setType(DNSProtoBufMessage::IncomingResponse);
+  message->setBytes(bytes);
+  message->setQueryTime(queryTime.tv_sec, queryTime.tv_usec);
+  message->setResponseCode(rcode);
+  message->addRRs(records, exportTypes);
 
 //  cerr <<message.toDebugString()<<endl;
   std::string str;
-  message.serialize(str);
+  message->serialize(str);
 
   for (auto& logger : *outgoingLoggers) {
     logger->queueData(str);
@@ -226,10 +224,11 @@ int asyncresolve(const ComboAddress& ip, const DNSName& domain, int type, bool d
 #ifdef HAVE_PROTOBUF
   boost::uuids::uuid uuid;
   const struct timeval queryTime = *now;
+  boost::optional<RecProtoBufMessage> pbMessage = boost::none;
 
   if (outgoingLoggers) {
     uuid = getUniqueID();
-    logOutgoingQuery(outgoingLoggers, context ? context->d_initialRequestId : boost::none, uuid, ip, domain, type, qid, doTCP, vpacket.size(), srcmask);
+    logOutgoingQuery(outgoingLoggers, pbMessage, context ? context->d_initialRequestId : boost::none, uuid, ip, domain, type, qid, doTCP, vpacket.size(), srcmask);
   }
 #endif /* HAVE_PROTOBUF */
 #ifdef HAVE_FSTRM
@@ -327,7 +326,7 @@ int asyncresolve(const ComboAddress& ip, const DNSName& domain, int type, bool d
     if(mdp.d_header.rcode == RCode::FormErr && mdp.d_qname.empty() && mdp.d_qtype == 0 && mdp.d_qclass == 0) {
 #ifdef HAVE_PROTOBUF
       if(outgoingLoggers) {
-        logIncomingResponse(outgoingLoggers, context ? context->d_initialRequestId : boost::none, uuid, ip, domain, type, qid, doTCP, len, lwr->d_rcode, lwr->d_records, queryTime, exportTypes);
+        logIncomingResponse(outgoingLoggers, pbMessage, len, lwr->d_rcode, lwr->d_records, queryTime, exportTypes);
       }
 #endif
       lwr->d_validpacket=true;
@@ -373,7 +372,7 @@ int asyncresolve(const ComboAddress& ip, const DNSName& domain, int type, bool d
         
 #ifdef HAVE_PROTOBUF
     if(outgoingLoggers) {
-      logIncomingResponse(outgoingLoggers, context ? context->d_initialRequestId : boost::none, uuid, ip, domain, type, qid, doTCP, len, lwr->d_rcode, lwr->d_records, queryTime, exportTypes);
+      logIncomingResponse(outgoingLoggers, pbMessage, len, lwr->d_rcode, lwr->d_records, queryTime, exportTypes);
     }
 #endif
     lwr->d_validpacket=true;
@@ -386,7 +385,7 @@ int asyncresolve(const ComboAddress& ip, const DNSName& domain, int type, bool d
     g_stats.serverParseError++;
 #ifdef HAVE_PROTOBUF
     if(outgoingLoggers) {
-      logIncomingResponse(outgoingLoggers, context ? context->d_initialRequestId : boost::none, uuid, ip, domain, type, qid, doTCP, len, lwr->d_rcode, lwr->d_records, queryTime, exportTypes);
+      logIncomingResponse(outgoingLoggers, pbMessage, len, lwr->d_rcode, lwr->d_records, queryTime, exportTypes);
     }
 #endif
     lwr->d_validpacket=false;
index a1b0995a50796f8cf299e2313dd3b7389caa6e7c..b2045b9d43d8035cff1c1e449001731c61344971 100644 (file)
@@ -157,11 +157,11 @@ void loadMainConfig(const std::string& configdir)
   UeberBackend::go();
 }
 
-bool rectifyZone(DNSSECKeeper& dk, const DNSName& zone, bool quiet = false)
+bool rectifyZone(DNSSECKeeper& dk, const DNSName& zone, bool quiet = false, bool rectifyTransaction = true)
 {
   string output;
   string error;
-  bool ret = dk.rectifyZone(zone, error, output, true);
+  bool ret = dk.rectifyZone(zone, error, output, rectifyTransaction);
   if (!quiet || !ret) {
     // When quiet, only print output if there was an error
     if (!output.empty()) {
@@ -859,9 +859,10 @@ int clearZone(DNSSECKeeper& dk, const DNSName &zone) {
   return EXIT_SUCCESS;
 }
 
-int editZone(DNSSECKeeper& dk, const DNSName &zone) {
+int editZone(const DNSName &zone) {
   UeberBackend B;
   DomainInfo di;
+  DNSSECKeeper dk(&B);
 
   if (! B.getDomainInfo(zone, di)) {
     cerr<<"Domain '"<<zone<<"' not found!"<<endl;
@@ -1004,6 +1005,7 @@ int editZone(DNSSECKeeper& dk, const DNSName &zone) {
   else if(changed.empty() || c!='a')
     goto reAsk2;
 
+  di.backend->startTransaction(zone, -1);
   for(const auto& change : changed) {
     vector<DNSResourceRecord> vrr;
     for(const DNSRecord& rr : grouped[change.first]) {
@@ -1013,7 +1015,8 @@ int editZone(DNSSECKeeper& dk, const DNSName &zone) {
     }
     di.backend->replaceRRSet(di.id, change.first.first, QType(change.first.second), vrr);
   }
-  rectifyZone(dk, zone);
+  rectifyZone(dk, zone, false, false);
+  di.backend->commitTransaction();
   return EXIT_SUCCESS;
 }
 
@@ -1190,6 +1193,9 @@ int addOrReplaceRecord(bool addOrReplace, const vector<string>& cmds) {
   rr.domain_id = di.id;
   rr.qname = name;
   DNSResourceRecord oldrr;
+
+  di.backend->startTransaction(zone, -1);
+
   if(addOrReplace) { // the 'add' case
     di.backend->lookup(rr.qtype, rr.qname, 0, di.id);
 
@@ -1245,6 +1251,7 @@ int addOrReplaceRecord(bool addOrReplace, const vector<string>& cmds) {
   di.backend->replaceRRSet(di.id, name, rr.qtype, newrrs);
   // need to be explicit to bypass the ueberbackend cache!
   di.backend->lookup(rr.qtype, name, 0, di.id);
+  di.backend->commitTransaction();
   cout<<"New rrset:"<<endl;
   while(di.backend->get(rr)) {
     cout<<rr.qname.toString()<<" "<<rr.ttl<<" IN "<<rr.qtype.getName()<<" "<<rr.content<<endl;
@@ -1270,7 +1277,9 @@ int deleteRRSet(const std::string& zone_, const std::string& name_, const std::s
     name=DNSName(name_)+zone;
 
   QType qt(QType::chartocode(type_.c_str()));
+  di.backend->startTransaction(zone, -1);
   di.backend->replaceRRSet(di.id, name, qt, vector<DNSResourceRecord>());
+  di.backend->commitTransaction();
   return EXIT_SUCCESS;
 }
 
@@ -2388,7 +2397,7 @@ try
     if(cmds[1]==".")
       cmds[1].clear();
 
-    exit(editZone(dk, DNSName(cmds[1])));
+    exit(editZone(DNSName(cmds[1])));
   }
   else if(cmds[0] == "clear-zone") {
     if(cmds.size() != 2) {
index 37fb01e8b143b518b2908433c7de6eb375199016..fd491ac669f629cb407f3bd3d73c71aac75b0510 100644 (file)
@@ -300,12 +300,16 @@ void DNSProtoBufMessage::setInitialRequestID(const boost::uuids::uuid& uuid)
   std::copy(uuid.begin(), uuid.end(), messageId->begin());
 }
 
-void DNSProtoBufMessage::update(const boost::uuids::uuid& uuid, const ComboAddress* requestor, const ComboAddress* responder, bool isTCP, uint16_t id)
+void DNSProtoBufMessage::updateTime()
 {
   struct timespec ts;
   gettime(&ts, true);
   setTime(ts.tv_sec, ts.tv_nsec / 1000);
+}
 
+void DNSProtoBufMessage::update(const boost::uuids::uuid& uuid, const ComboAddress* requestor, const ComboAddress* responder, bool isTCP, uint16_t id)
+{
+  updateTime();
   setUUID(uuid);
   d_message.set_id(ntohs(id));
 
index c52af41621b97019c0bdd11eb7ab3522a583cab2..f87dd5f08cc6a57b10f128a7946573363b40c4a1 100644 (file)
@@ -59,6 +59,7 @@ public:
   void setEDNSSubnet(const Netmask& subnet, uint8_t mask=128);
   void setBytes(size_t bytes);
   void setTime(time_t sec, uint32_t usec);
+  void updateTime();
   void setQueryTime(time_t sec, uint32_t usec);
   void setResponseCode(uint8_t rcode);
   void addRRsFromPacket(const char* packet, const size_t len, bool includeCNAME=false);
index bd0f7cf9b11d58a6511eac5a6b7a4d866312f3c8..e6686787b38ef9c19a265df5d66759525cf3e38c 100644 (file)
@@ -606,6 +606,8 @@ int main(int argc, char **argv)
   }
   
   declareStats();
+  S.blacklist("special-memory-usage");
+
   DLOG(g_log<<Logger::Warning<<"Verbose logging in effect"<<endl);
 
   showProductVersion();
index 87fd7aea2438a1f732261799e7a0a4627b420701..2d0b61c8216fad20e224527d67d440cd1aa49010 100644 (file)
@@ -2,6 +2,20 @@ Changelogs for 4.1.x
 ====================
 
 .. changelog::
+  :version: 4.1.14
+  :released: 13th of June 2019
+
+  .. change::
+    :tags: Improvements
+    :pullreq: 7906
+
+    Add statistics counters for AD and CD queries.
+
+    :tags: Bug Fixes
+    :pullreq: 7912
+
+    Add missing getregisteredname Lua function
+
   :version: 4.1.13
   :released: 21st of May 2019
 
index 61afa24e806dea5b861bece7e4905e00f351cc27..77707d5f2977af49840d589b75f7f943a62ad154 100644 (file)
@@ -349,8 +349,9 @@ BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_negcache_secure) {
   g_luaconfs.setState(luaconfsCopy);
 
   size_t queriesCount = 0;
+  const time_t fixedNow = sr->getNow().tv_sec;
 
-  sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, LWResult* res, bool* chained) {
+  sr->setAsyncCallback([target,&queriesCount,keys,fixedNow](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, LWResult* res, bool* chained) {
       queriesCount++;
 
       DNSName auth = domain;
@@ -364,7 +365,7 @@ BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_negcache_secure) {
         addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
         addRRSIG(keys, res->d_records, domain, 300);
         addNSECRecordToLW(domain, DNSName("z."), { QType::NSEC, QType::RRSIG }, 600, res->d_records);
-        addRRSIG(keys, res->d_records, domain, 1);
+        addRRSIG(keys, res->d_records, domain, 1, false, boost::none, boost::none, fixedNow);
         return 1;
       }
 
@@ -379,7 +380,7 @@ BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_negcache_secure) {
   BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
   BOOST_REQUIRE_EQUAL(ret.size(), 4);
   BOOST_CHECK_EQUAL(queriesCount, 1);
-  /* check that the entry has not been negatively cached */
+  /* check that the entry has been negatively cached */
   const NegCache::NegCacheEntry* ne = nullptr;
   BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
   BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), &ne), true);
index eb7075388d1af4f7a925f61d8460b6bdc731455b..752c72950b18779e5bbfc5c6ab4e00e8fdc7097d 100644 (file)
@@ -46,6 +46,11 @@ int pdns_sqlite3_clear_bindings(sqlite3_stmt *pStmt){
   return rc;
 }
 
+static string SSQLite3ErrorString(sqlite3 *db)
+{
+  return string(sqlite3_errmsg(db)+string(" (")+std::to_string(sqlite3_extended_errcode(db))+string(")"));
+}
+
 class SSQLite3Statement: public SSqlStatement
 {
 public:
@@ -86,8 +91,8 @@ public:
       // failed.
       releaseStatement();
       if (d_rc == SQLITE_CANTOPEN)
-        throw SSqlException(string("CANTOPEN error in sqlite3, often caused by unwritable sqlite3 db *directory*: ")+string(sqlite3_errmsg(d_db->db())));
-      throw SSqlException(string("Error while retrieving SQLite query results: ")+string(sqlite3_errmsg(d_db->db())));
+        throw SSqlException(string("CANTOPEN error in sqlite3, often caused by unwritable sqlite3 db *directory*: ")+SSQLite3ErrorString(d_db->db()));
+      throw SSqlException(string("Error while retrieving SQLite query results: ")+SSQLite3ErrorString(d_db->db()));
     }
     if(d_dolog) 
       g_log<<Logger::Warning<< "Query "<<((long)(void*)this)<<": "<<d_dtime.udiffNoReset()<<" usec to execute"<<endl;
@@ -164,7 +169,7 @@ private:
 #endif
     {
       releaseStatement();
-      throw SSqlException(string("Unable to compile SQLite statement : '")+d_query+"': "+sqlite3_errmsg(d_db->db()));
+      throw SSqlException(string("Unable to compile SQLite statement : '")+d_query+"': "+SSQLite3ErrorString(d_db->db()));
     }
     if (pTail && strlen(pTail)>0)
       g_log<<Logger::Warning<<"Sqlite3 command partially processed. Unprocessed part: "<<pTail<<endl;
index c4f46a5b1f8fc70a62cb183f2d7fa7097c34c86d..83af32c7517887cc8496b071c9f8b6ddadbfa689 100644 (file)
@@ -54,11 +54,15 @@ string StatBag::directory()
   ostringstream o;
 
   for(const auto& i: d_stats) {
+    if (d_blacklist.find(i.first) != d_blacklist.end())
+      continue;
     o<<i.first<<"="<<*(i.second)<<",";
   }
 
 
   for(const funcstats_t::value_type& val :  d_funcstats) {
+    if (d_blacklist.find(val.first) != d_blacklist.end())
+      continue;
     o << val.first<<"="<<val.second(val.first)<<",";
   }
   dir=o.str();
@@ -71,10 +75,14 @@ vector<string>StatBag::getEntries()
   vector<string> ret;
 
   for(const auto& i: d_stats) {
-      ret.push_back(i.first);
+    if (d_blacklist.find(i.first) != d_blacklist.end())
+      continue;
+    ret.push_back(i.first);
   }
 
   for(const funcstats_t::value_type& val :  d_funcstats) {
+    if (d_blacklist.find(val.first) != d_blacklist.end())
+      continue;
     ret.push_back(val.first);
   }
 
@@ -325,6 +333,10 @@ bool StatBag::ringExists(const string &name)
   return d_rings.count(name) || d_comborings.count(name) || d_dnsnameqtyperings.count(name);
 }
 
+void StatBag::blacklist(const string& str) {
+  d_blacklist.insert(str);
+}
+
 template class StatRing<std::string, CIStringCompare>;
 template class StatRing<SComboAddress>;
 template class StatRing<std::tuple<DNSName, QType> >;
index 2c8ca2850dfd4d7ed7caa23cda8ac7fc8b3aa385..f36c211f636f886096f9a779a662c908c2f2cc6e 100644 (file)
@@ -71,6 +71,7 @@ class StatBag
   typedef map<string, func_t> funcstats_t;
   funcstats_t d_funcstats;
   bool d_doRings;
+  std::set<string> d_blacklist;
 
 public:
   StatBag(); //!< Naked constructor. You need to declare keys before this class becomes useful
@@ -132,6 +133,7 @@ public:
   AtomicCounter *getPointer(const string &key); //!< get a direct pointer to the value behind a key. Use this for high performance increments
   string getValueStr(const string &key); //!< read a value behind a key, and return it as a string
   string getValueStrZero(const string &key); //!< read a value behind a key, and return it as a string, and zero afterwards
+  void blacklist(const string &str);
 };
 
 inline void StatBag::deposit(const string &key, int value)
index dcdcc1ce0ba9ac811186099f3d2ddbff4c7080fc..baca8d53dd24ec08aae9873cd6d125e841994b59 100644 (file)
@@ -1106,7 +1106,7 @@ struct CacheKey
   uint16_t type;
   DNSResourceRecord::Place place;
   bool operator<(const CacheKey& rhs) const {
-    return tie(name, type, place) < tie(rhs.name, rhs.type, rhs.place);
+    return tie(type, place, name) < tie(rhs.type, rhs.place, rhs.name);
   }
 };
 typedef map<CacheKey, CacheEntry> tcache_t;
index 6c3aecae1276ab01373b225405efda980b13dc8c..2c3dd363b04d4ef65a7d74c325c0c494ede9d86e 100644 (file)
@@ -282,7 +282,7 @@ bool UeberBackend::getAuth(const DNSName &target, const QType& qtype, SOAData* s
   // com. We then store that and keep querying the other backends in case one
   // of them has a more specific zone but don't bother asking this specific
   // backend again for b.c.example.com., c.example.com. and example.com.
-  // If a backend has no match it may respond with an enmpty qname.
+  // If a backend has no match it may respond with an empty qname.
 
   bool found = false;
   int cstat;
@@ -330,6 +330,9 @@ bool UeberBackend::getAuth(const DNSName &target, const QType& qtype, SOAData* s
           DLOG(g_log<<Logger::Error<<"lookup: "<<shorter<<endl);
           if((*i)->getAuth(shorter, sd)) {
             DLOG(g_log<<Logger::Error<<"got: "<<sd->qname<<endl);
+            if(!shorter.isPartOf(sd->qname) && !sd->qname.empty()) {
+              throw PDNSException("getAuth() returned an SOA for the wrong zone. Zone '"+sd->qname.toLogString()+"' is not part of '"+shorter.toLogString()+"'");
+            }
             j->first = sd->qname.wirelength();
             j->second = *sd;
             if(sd->qname == shorter) {
@@ -409,6 +412,9 @@ bool UeberBackend::getSOAUncached(const DNSName &domain, SOAData &sd)
 
   for(vector<DNSBackend *>::const_iterator i=backends.begin();i!=backends.end();++i)
     if((*i)->getSOA(domain, sd)) {
+      if(domain != sd.qname) {
+        throw PDNSException("getSOA() returned an SOA for the wrong zone. Question: '"+domain.toLogString()+"', answer: '"+sd.qname.toLogString()+"'");
+      }
       if(d_cache_ttl) {
         DNSZoneRecord rr;
         rr.dr.d_name = sd.qname;
index 349876b74ea8bef7c752d6d28e0de7ad75096675..61d9cb5380135d50472c9a18410b4e30626e51d3 100644 (file)
@@ -618,7 +618,7 @@ static void throwUnableToSecure(const DNSName& zonename) {
       + "capable backends are loaded, or because the backends have DNSSEC disabled. Check your configuration.");
 }
 
-static void updateDomainSettingsFromDocument(UeberBackend& B, const DomainInfo& di, const DNSName& zonename, const Json document) {
+static void updateDomainSettingsFromDocument(UeberBackend& B, const DomainInfo& di, const DNSName& zonename, const Json document, bool rectifyTransaction=true) {
   vector<string> zonemaster;
   bool shouldRectify = false;
   for(auto value : document["masters"].array_items()) {
@@ -743,7 +743,7 @@ static void updateDomainSettingsFromDocument(UeberBackend& B, const DomainInfo&
     if (api_rectify == "1") {
       string info;
       string error_msg;
-      if (!dk.rectifyZone(zonename, error_msg, info, true)) {
+      if (!dk.rectifyZone(zonename, error_msg, info, rectifyTransaction)) {
         throw ApiException("Failed to rectify '" + zonename.toString() + "' " + error_msg);
       }
     }
@@ -1642,13 +1642,13 @@ static void apiServerZones(HttpRequest* req, HttpResponse* resp) {
     if(!B.getDomainInfo(zonename, di))
       throw ApiException("Creating domain '"+zonename.toString()+"' failed: lookup of domain ID failed");
 
+    di.backend->startTransaction(zonename, di.id);
+
     // updateDomainSettingsFromDocument does NOT fill out the default we've established above.
     if (!soa_edit_api_kind.empty()) {
       di.backend->setDomainMetadataOne(zonename, "SOA-EDIT-API", soa_edit_api_kind);
     }
 
-    di.backend->startTransaction(zonename, di.id);
-
     for(auto rr : new_records) {
       rr.domain_id = di.id;
       di.backend->feedRecord(rr, DNSName());
@@ -1658,7 +1658,7 @@ static void apiServerZones(HttpRequest* req, HttpResponse* resp) {
       di.backend->feedComment(c);
     }
 
-    updateDomainSettingsFromDocument(B, di, zonename, document);
+    updateDomainSettingsFromDocument(B, di, zonename, document, false);
 
     di.backend->commitTransaction();
 
@@ -1714,7 +1714,9 @@ static void apiServerZoneDetail(HttpRequest* req, HttpResponse* resp) {
   if(req->method == "PUT") {
     // update domain settings
 
-    updateDomainSettingsFromDocument(B, di, zonename, req->json());
+    di.backend->startTransaction(zonename, -1);
+    updateDomainSettingsFromDocument(B, di, zonename, req->json(), false);
+    di.backend->commitTransaction();
 
     resp->body = "";
     resp->status = 204; // No Content, but indicate success