]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Merge pull request #9202 from omoerbeek/rec-cname-loop
authorOtto Moerbeek <otto.moerbeek@open-xchange.com>
Tue, 9 Jun 2020 10:07:45 +0000 (12:07 +0200)
committerGitHub <noreply@github.com>
Tue, 9 Jun 2020 10:07:45 +0000 (12:07 +0200)
rec: more sophisticated cname loop detection.

23 files changed:
README.md
build-scripts/docker/generate-repo-files.sh
docs/changelog/4.2.rst
docs/http-api/index.rst
docs/settings.rst
docs/tsig.rst
ext/lmdb-safe/lmdb-safe.hh
modules/remotebackend/httpconnector.cc
modules/remotebackend/remotebackend.cc
modules/remotebackend/remotebackend.hh
pdns/auth-packetcache.cc
pdns/auth-querycache.cc
pdns/common_startup.cc
pdns/dnsdistdist/views.hh
pdns/recursordist/docs/lua-scripting/hooks.rst
pdns/recursordist/docs/manpages/pdns_recursor.1.rst
pdns/recursordist/docs/settings.rst
pdns/recursordist/test-syncres_cc6.cc
pdns/statbag.cc
pdns/statbag.hh
pdns/syncres.cc
pdns/tcpreceiver.cc
pdns/ws-auth.cc

index ffc7603b768543328e422f9567103f3d81f06dc3..7fedb7a197ae370b3c6fd29fb1325d7b736f3c8f 100644 (file)
--- a/README.md
+++ b/README.md
@@ -5,10 +5,10 @@ exact license and exception used).
 All documentation can be found on https://doc.powerdns.com/
 
 This file may lag behind at times. For most recent updates, always check
-https://doc.powerdns.com/md/changelog/.
+https://doc.powerdns.com/authoritative/changelog/
 
 Another good place to look for information is:
-https://doc.powerdns.com/md/appendix/compiling-powerdns/
+https://doc.powerdns.com/authoritative/appendices/compiling.html
 
 To file bugs, head towards:
 https://github.com/PowerDNS/pdns/issues
@@ -42,7 +42,7 @@ This will bring up a USAGE-page which will explain how to build the different re
 
 COMPILING Authoritative Server
 ------------------------------
-The PowerDNS Authoritative Server depends on Boost, OpenSSL and requires a
+The PowerDNS Authoritative Server depends on Boost, OpenSSL and Lua, and requires a
 compiler with C++-2011 support.
 
 On Debian 9, the following is useful:
@@ -119,62 +119,6 @@ Building the HTML documentation
 
 The HTML documentation (as seen [on the PowerDNS docs site](https://doc.powerdns.com/authoritative/)) is built from ReStructured Text (rst) files located in `docs`. They are compiled into HTML files using [Sphinx](http://www.sphinx-doc.org/en/master/index.html), a documentation generator tool which is built in Python.
 
-**Using a normal Python installation**
-
-For those simply contributing to the documentation, this avoids needing to install the various build
-tools and other dependencies.
-
-Install Python 2.7 or Python 3 (preferable) if you don't yet have it installed. On some operating
-systems you may also have to install `python3-pip` or similarly named.
-
-Ubuntu 16.04 / 18.04
-
-```sh
-apt update
-apt install python3 python3-pip python3-venv
-```
-
-macOS (using homebrew)
-
-```sh
-brew install python3
-```
-
-Update your `pip` and install/update `virtualenv` to avoid problems:
-
-```sh
-# for python2, use "pip" instead of "pip3"
-pip3 install -U pip
-pip3 install -U virtualenv
-```
-
-Enter the repository's `docs` folder, set up the virtualenv, and install the requirements
-
-```sh
-cd docs
-# for python2, use "virtualenv .venv" instead
-python3 -m venv .venv
-source .venv/bin/activate
-# The virtualenv may use an older pip, so upgrade it again
-pip3 install -U pip setuptools setuptools-git
-# Now you can install the requirements
-pip3 install -r requirements.txt
-```
-
-Finally, you can build the documentation:
-
-```sh
-sphinx-build . html-docs
-```
-
-Note: If your shell has problems finding sphinx-build, try using `.venv/bin/sphinx-build` instead.
-
-The HTML documentation is now available in `html-docs`.
-
-**Using the build tools**
-
-This method is preferable for those who already have a working build environment for PowerDNS.
-
 Install the dependencies under "COMPILING", and run autoreconf if you haven't already:
 
 ```sh
@@ -190,12 +134,6 @@ make html-docs
 
 The HTML documentation will now be available in `html-docs`.
 
-Solaris Notes
--------------
-Use a recent gcc (and other build tools), possibly from Solaris 11 IPS.
-
-If you encounter problems with the Solaris make, gmake is advised.
-
 FreeBSD Notes
 -------------
 You need to compile using gmake - regular make only appears to work, but doesn't in fact. Use gmake, not make.
index 05da8b04552ae3c7113c04d7cc126deaf92a45c8..ef6f868f59d621912c95edaf18cf91843f251a03 100755 (executable)
@@ -24,9 +24,9 @@
 if [ "$1" = "" -o "$1" = "-?" -o "$1" = "-h" -o "$1" = "--help" ]; then
     echo "Usage: generate-repo-files.sh RELEASE"
     echo
-    echo "  • RELEASE: [ auth-40 | auth-41 | auth-42 | auth-43 |"
-    echo "               rec-40 | rec-41 | rec-42 | rec-43 | rec-44 |"
-    echo "               dnsdist-15 ]"
+    echo "  • RELEASE: [ auth-40 | auth-41 | auth-42 | auth-43 | auth-master |"
+    echo "               rec-40 | rec-41 | rec-42 | rec-43 | rec-44 | rec-master |"
+    echo "               dnsdist-15 | dnsdist-master ]"
     exit 1
 fi
 
@@ -113,6 +113,7 @@ COPY pdns.debian-and-ubuntu /etc/apt/preferences.d/pdns
 COPY pdns.list.$RELEASE.$OS-$VERSION /etc/apt/sources.list.d/pdns.list
 
 RUN curl https://repo.powerdns.com/FD380FBB-pub.asc | apt-key add -
+RUN curl https://repo.powerdns.com/CBC8B383-pub.asc | apt-key add -
 RUN apt-get update
 RUN apt-get install -y $PKG
 EOF
@@ -160,7 +161,7 @@ elif [ "$RELEASE" = "auth-41" ]; then
     write_ubuntu trusty pdns-server pdns_server
     write_ubuntu xenial pdns-server pdns_server
     write_ubuntu bionic pdns-server pdns_server
-elif [ "$RELEASE" = "auth-42" -o "$RELEASE" = "auth-43" ]; then
+elif [ "$RELEASE" = "auth-42" -o "$RELEASE" = "auth-43" -o "$RELEASE" = "auth-master" ]; then
     write_centos 6 pdns pdns_server
     write_centos 7 pdns pdns_server
     write_centos 8 pdns pdns_server
@@ -183,7 +184,7 @@ elif [ "$RELEASE" = "rec-41" ]; then
     write_ubuntu trusty pdns-recursor pdns_recursor
     write_ubuntu xenial pdns-recursor pdns_recursor
     write_ubuntu bionic pdns-recursor pdns_recursor
-elif [ "$RELEASE" = "rec-42" -o "$RELEASE" = "rec-43" -o "$RELEASE" = "rec-44" ]; then
+elif [ "$RELEASE" = "rec-42" -o "$RELEASE" = "rec-43" -o "$RELEASE" = "rec-44" -o "$RELEASE" = "rec-master" ]; then
     write_centos 6 pdns-recursor pdns_recursor
     write_centos 7 pdns-recursor pdns_recursor
     write_centos 8 pdns-recursor pdns_recursor
@@ -191,7 +192,7 @@ elif [ "$RELEASE" = "rec-42" -o "$RELEASE" = "rec-43" -o "$RELEASE" = "rec-44" ]
     write_debian buster pdns-recursor pdns_recursor
     write_ubuntu xenial pdns-recursor pdns_recursor
     write_ubuntu bionic pdns-recursor pdns_recursor
-elif [ "$RELEASE" = "dnsdist-15" ]; then
+elif [ "$RELEASE" = "dnsdist-15" -o "$RELEASE" = "dnsdist-master" ]; then
     write_centos 6 dnsdist dnsdist
     write_centos 7 dnsdist dnsdist
     write_centos 8 dnsdist dnsdist
index 4f0ebdb3c0cce96bcbb0c0fc95b17eb655bee077..7212a97ee7fc8c0abe122da63a54e0265f96eb39 100644 (file)
@@ -81,6 +81,14 @@ Changelogs for 4.2.x
 
     API: reduce number of database connections (Kees Monshouwer)
 
+  .. change::
+    :tags: Bug Fixes
+    :pullreq: 8497
+
+    Clear the caches for the entire zone after a patch operation (was apex only).
+    The default default-api-rectify setting was ignored in patchZone(), rectify only took place when the API-RECTIFY metadata was set to "1".
+    (Kees Monshouwer)
+
   .. change::
     :tags: Improvements
     :pullreq: 8546
index ae62df5c748c9468114822ecdc3d0595f8585506..45c83308f96e7e85727f79e7238d65af37894093 100644 (file)
@@ -21,6 +21,276 @@ The following webserver related configuration items are available:
 * :ref:`setting-webserver-allow-from`: Netmasks that are allowed to connect to the webserver
 * :ref:`setting-webserver-max-bodysize`: Maximum request/response body size in megabytes
 
+
+Metrics Endpoint
+----------------
+
+The webserver exposes a metrics-endpoint that follows the `prometheus exposition-format <https://github.com/prometheus/docs/blob/master/content/docs/instrumenting/exposition_formats.md>`_ on path ``/metrics``.
+
+The metrics listed are equivalent to the variables section on the index-page of the webserver (prefixed with ``pdns_auth_`` and replacing dashes with underscores).
+
+A simple ``GET`` request will return a response similar to the following:
+
+.. http:get:: /metrics
+
+  HTTP/1.1 200 OK
+  Connection: close
+  Content-Length: 12044
+  Content-Type: text/plain
+  Server: PowerDNS/0.0.19015.0.master.ge719aae4e8
+
+  # HELP pdns_auth_corrupt_packets Number of corrupt packets received
+  # TYPE pdns_auth_corrupt_packets counter
+  pdns_auth_corrupt_packets 0
+  # HELP pdns_auth_deferred_cache_inserts Amount of cache inserts that were deferred because of maintenance
+  # TYPE pdns_auth_deferred_cache_inserts counter
+  pdns_auth_deferred_cache_inserts 0
+  # HELP pdns_auth_deferred_cache_lookup Amount of cache lookups that were deferred because of maintenance
+  # TYPE pdns_auth_deferred_cache_lookup counter
+  pdns_auth_deferred_cache_lookup 0
+  # HELP pdns_auth_deferred_packetcache_inserts Amount of packet cache inserts that were deferred because of maintenance
+  # TYPE pdns_auth_deferred_packetcache_inserts counter
+  pdns_auth_deferred_packetcache_inserts 0
+  # HELP pdns_auth_deferred_packetcache_lookup Amount of packet cache lookups that were deferred because of maintenance
+  # TYPE pdns_auth_deferred_packetcache_lookup counter
+  pdns_auth_deferred_packetcache_lookup 0
+  # HELP pdns_auth_dnsupdate_answers DNS update packets successfully answered.
+  # TYPE pdns_auth_dnsupdate_answers counter
+  pdns_auth_dnsupdate_answers 0
+  # HELP pdns_auth_dnsupdate_changes DNS update changes to records in total.
+  # TYPE pdns_auth_dnsupdate_changes counter
+  pdns_auth_dnsupdate_changes 0
+  # HELP pdns_auth_dnsupdate_queries DNS update packets received.
+  # TYPE pdns_auth_dnsupdate_queries counter
+  pdns_auth_dnsupdate_queries 0
+  # HELP pdns_auth_dnsupdate_refused DNS update packets that are refused.
+  # TYPE pdns_auth_dnsupdate_refused counter
+  pdns_auth_dnsupdate_refused 0
+  # HELP pdns_auth_incoming_notifications NOTIFY packets received.
+  # TYPE pdns_auth_incoming_notifications counter
+  pdns_auth_incoming_notifications 0
+  # HELP pdns_auth_overload_drops Queries dropped because backends overloaded
+  # TYPE pdns_auth_overload_drops counter
+  pdns_auth_overload_drops 0
+  # HELP pdns_auth_packetcache_hit Number of hits on the packet cache
+  # TYPE pdns_auth_packetcache_hit counter
+  pdns_auth_packetcache_hit 0
+  # HELP pdns_auth_packetcache_miss Number of misses on the packet cache
+  # TYPE pdns_auth_packetcache_miss counter
+  pdns_auth_packetcache_miss 0
+  # HELP pdns_auth_packetcache_size Number of entries in the packet cache
+  # TYPE pdns_auth_packetcache_size gauge
+  pdns_auth_packetcache_size 0
+  # HELP pdns_auth_query_cache_hit Number of hits on the query cache
+  # TYPE pdns_auth_query_cache_hit counter
+  pdns_auth_query_cache_hit 0
+  # HELP pdns_auth_query_cache_miss Number of misses on the query cache
+  # TYPE pdns_auth_query_cache_miss counter
+  pdns_auth_query_cache_miss 0
+  # HELP pdns_auth_query_cache_size Number of entries in the query cache
+  # TYPE pdns_auth_query_cache_size gauge
+  pdns_auth_query_cache_size 0
+  # HELP pdns_auth_rd_queries Number of recursion desired questions
+  # TYPE pdns_auth_rd_queries counter
+  pdns_auth_rd_queries 0
+  # HELP pdns_auth_recursing_answers Number of recursive answers sent out
+  # TYPE pdns_auth_recursing_answers counter
+  pdns_auth_recursing_answers 0
+  # HELP pdns_auth_recursing_questions Number of questions sent to recursor
+  # TYPE pdns_auth_recursing_questions counter
+  pdns_auth_recursing_questions 0
+  # HELP pdns_auth_recursion_unanswered Number of packets unanswered by configured recursor
+  # TYPE pdns_auth_recursion_unanswered counter
+  pdns_auth_recursion_unanswered 0
+  # HELP pdns_auth_security_status Security status based on regular polling
+  # TYPE pdns_auth_security_status gauge
+  pdns_auth_security_status 0
+  # HELP pdns_auth_servfail_packets Number of times a server-failed packet was sent out
+  # TYPE pdns_auth_servfail_packets counter
+  pdns_auth_servfail_packets 0
+  # HELP pdns_auth_signatures Number of DNSSEC signatures made
+  # TYPE pdns_auth_signatures counter
+  pdns_auth_signatures 0
+  # HELP pdns_auth_tcp_answers Number of answers sent out over TCP
+  # TYPE pdns_auth_tcp_answers counter
+  pdns_auth_tcp_answers 0
+  # HELP pdns_auth_tcp_answers_bytes Total size of answers sent out over TCP
+  # TYPE pdns_auth_tcp_answers_bytes counter
+  pdns_auth_tcp_answers_bytes 0
+  # HELP pdns_auth_tcp_queries Number of TCP queries received
+  # TYPE pdns_auth_tcp_queries counter
+  pdns_auth_tcp_queries 0
+  # HELP pdns_auth_tcp4_answers Number of IPv4 answers sent out over TCP
+  # TYPE pdns_auth_tcp4_answers counter
+  pdns_auth_tcp4_answers 0
+  # HELP pdns_auth_tcp4_answers_bytes Total size of answers sent out over TCPv4
+  # TYPE pdns_auth_tcp4_answers_bytes counter
+  pdns_auth_tcp4_answers_bytes 0
+  # HELP pdns_auth_tcp4_queries Number of IPv4 TCP queries received
+  # TYPE pdns_auth_tcp4_queries counter
+  pdns_auth_tcp4_queries 0
+  # HELP pdns_auth_tcp6_answers Number of IPv6 answers sent out over TCP
+  # TYPE pdns_auth_tcp6_answers counter
+  pdns_auth_tcp6_answers 0
+  # HELP pdns_auth_tcp6_answers_bytes Total size of answers sent out over TCPv6
+  # TYPE pdns_auth_tcp6_answers_bytes counter
+  pdns_auth_tcp6_answers_bytes 0
+  # HELP pdns_auth_tcp6_queries Number of IPv6 TCP queries received
+  # TYPE pdns_auth_tcp6_queries counter
+  pdns_auth_tcp6_queries 0
+  # HELP pdns_auth_timedout_packets Number of packets which weren't answered within timeout set
+  # TYPE pdns_auth_timedout_packets counter
+  pdns_auth_timedout_packets 0
+  # HELP pdns_auth_udp_answers Number of answers sent out over UDP
+  # TYPE pdns_auth_udp_answers counter
+  pdns_auth_udp_answers 0
+  # HELP pdns_auth_udp_answers_bytes Total size of answers sent out over UDP
+  # TYPE pdns_auth_udp_answers_bytes counter
+  pdns_auth_udp_answers_bytes 0
+  # HELP pdns_auth_udp_do_queries Number of UDP queries received with DO bit
+  # TYPE pdns_auth_udp_do_queries counter
+  pdns_auth_udp_do_queries 0
+  # HELP pdns_auth_udp_queries Number of UDP queries received
+  # TYPE pdns_auth_udp_queries counter
+  pdns_auth_udp_queries 0
+  # HELP pdns_auth_udp4_answers Number of IPv4 answers sent out over UDP
+  # TYPE pdns_auth_udp4_answers counter
+  pdns_auth_udp4_answers 0
+  # HELP pdns_auth_udp4_answers_bytes Total size of answers sent out over UDPv4
+  # TYPE pdns_auth_udp4_answers_bytes counter
+  pdns_auth_udp4_answers_bytes 0
+  # HELP pdns_auth_udp4_queries Number of IPv4 UDP queries received
+  # TYPE pdns_auth_udp4_queries counter
+  pdns_auth_udp4_queries 0
+  # HELP pdns_auth_udp6_answers Number of IPv6 answers sent out over UDP
+  # TYPE pdns_auth_udp6_answers counter
+  pdns_auth_udp6_answers 0
+  # HELP pdns_auth_udp6_answers_bytes Total size of answers sent out over UDPv6
+  # TYPE pdns_auth_udp6_answers_bytes counter
+  pdns_auth_udp6_answers_bytes 0
+  # HELP pdns_auth_udp6_queries Number of IPv6 UDP queries received
+  # TYPE pdns_auth_udp6_queries counter
+  pdns_auth_udp6_queries 0
+  # HELP pdns_auth_cpu_iowait Time spent waiting for I/O to complete by the whole system, in units of USER_HZ
+  # TYPE pdns_auth_cpu_iowait counter
+  pdns_auth_cpu_iowait 2739
+  # HELP pdns_auth_cpu_steal Stolen time, which is the time spent by the whole system in other operating systems when running in a virtualized environment, in units of USER_HZ
+  # TYPE pdns_auth_cpu_steal counter
+  pdns_auth_cpu_steal 0
+  # HELP pdns_auth_fd_usage Number of open filedescriptors
+  # TYPE pdns_auth_fd_usage gauge
+  pdns_auth_fd_usage 26
+  # HELP pdns_auth_key_cache_size Number of entries in the key cache
+  # TYPE pdns_auth_key_cache_size gauge
+  pdns_auth_key_cache_size 0
+  # HELP pdns_auth_latency Average number of microseconds needed to answer a question
+  # TYPE pdns_auth_latency gauge
+  pdns_auth_latency 0
+  # HELP pdns_auth_meta_cache_size Number of entries in the metadata cache
+  # TYPE pdns_auth_meta_cache_size gauge
+  pdns_auth_meta_cache_size 0
+  # HELP pdns_auth_open_tcp_connections Number of currently open TCP connections
+  # TYPE pdns_auth_open_tcp_connections gauge
+  pdns_auth_open_tcp_connections 0
+  # HELP pdns_auth_qsize_q Number of questions waiting for database attention
+  # TYPE pdns_auth_qsize_q gauge
+  pdns_auth_qsize_q 0
+  # HELP pdns_auth_real_memory_usage Actual unique use of memory in bytes (approx)
+  # TYPE pdns_auth_real_memory_usage gauge
+  pdns_auth_real_memory_usage 133189632
+  # HELP pdns_auth_ring_logmessages_capacity Maximum number of entries in the logmessages ring
+  # TYPE pdns_auth_ring_logmessages_capacity gauge
+  pdns_auth_ring_logmessages_capacity 10000
+  # HELP pdns_auth_ring_logmessages_size Number of entries in the logmessages ring
+  # TYPE pdns_auth_ring_logmessages_size gauge
+  pdns_auth_ring_logmessages_size 7
+  # HELP pdns_auth_ring_noerror_queries_capacity Maximum number of entries in the noerror-queries ring
+  # TYPE pdns_auth_ring_noerror_queries_capacity gauge
+  pdns_auth_ring_noerror_queries_capacity 10000
+  # HELP pdns_auth_ring_noerror_queries_size Number of entries in the noerror-queries ring
+  # TYPE pdns_auth_ring_noerror_queries_size gauge
+  pdns_auth_ring_noerror_queries_size 0
+  # HELP pdns_auth_ring_nxdomain_queries_capacity Maximum number of entries in the nxdomain-queries ring
+  # TYPE pdns_auth_ring_nxdomain_queries_capacity gauge
+  pdns_auth_ring_nxdomain_queries_capacity 10000
+  # HELP pdns_auth_ring_nxdomain_queries_size Number of entries in the nxdomain-queries ring
+  # TYPE pdns_auth_ring_nxdomain_queries_size gauge
+  pdns_auth_ring_nxdomain_queries_size 0
+  # HELP pdns_auth_ring_queries_capacity Maximum number of entries in the queries ring
+  # TYPE pdns_auth_ring_queries_capacity gauge
+  pdns_auth_ring_queries_capacity 10000
+  # HELP pdns_auth_ring_queries_size Number of entries in the queries ring
+  # TYPE pdns_auth_ring_queries_size gauge
+  pdns_auth_ring_queries_size 0
+  # HELP pdns_auth_ring_remotes_capacity Maximum number of entries in the remotes ring
+  # TYPE pdns_auth_ring_remotes_capacity gauge
+  pdns_auth_ring_remotes_capacity 10000
+  # HELP pdns_auth_ring_remotes_corrupt_capacity Maximum number of entries in the remotes-corrupt ring
+  # TYPE pdns_auth_ring_remotes_corrupt_capacity gauge
+  pdns_auth_ring_remotes_corrupt_capacity 10000
+  # HELP pdns_auth_ring_remotes_corrupt_size Number of entries in the remotes-corrupt ring
+  # TYPE pdns_auth_ring_remotes_corrupt_size gauge
+  pdns_auth_ring_remotes_corrupt_size 0
+  # HELP pdns_auth_ring_remotes_size Number of entries in the remotes ring
+  # TYPE pdns_auth_ring_remotes_size gauge
+  pdns_auth_ring_remotes_size 0
+  # HELP pdns_auth_ring_remotes_unauth_capacity Maximum number of entries in the remotes-unauth ring
+  # TYPE pdns_auth_ring_remotes_unauth_capacity gauge
+  pdns_auth_ring_remotes_unauth_capacity 10000
+  # HELP pdns_auth_ring_remotes_unauth_size Number of entries in the remotes-unauth ring
+  # TYPE pdns_auth_ring_remotes_unauth_size gauge
+  pdns_auth_ring_remotes_unauth_size 0
+  # HELP pdns_auth_ring_servfail_queries_capacity Maximum number of entries in the servfail-queries ring
+  # TYPE pdns_auth_ring_servfail_queries_capacity gauge
+  pdns_auth_ring_servfail_queries_capacity 10000
+  # HELP pdns_auth_ring_servfail_queries_size Number of entries in the servfail-queries ring
+  # TYPE pdns_auth_ring_servfail_queries_size gauge
+  pdns_auth_ring_servfail_queries_size 0
+  # HELP pdns_auth_ring_unauth_queries_capacity Maximum number of entries in the unauth-queries ring
+  # TYPE pdns_auth_ring_unauth_queries_capacity gauge
+  pdns_auth_ring_unauth_queries_capacity 10000
+  # HELP pdns_auth_ring_unauth_queries_size Number of entries in the unauth-queries ring
+  # TYPE pdns_auth_ring_unauth_queries_size gauge
+  pdns_auth_ring_unauth_queries_size 0
+  # HELP pdns_auth_signature_cache_size Number of entries in the signature cache
+  # TYPE pdns_auth_signature_cache_size gauge
+  pdns_auth_signature_cache_size 0
+  # HELP pdns_auth_sys_msec Number of msec spent in system time
+  # TYPE pdns_auth_sys_msec counter
+  pdns_auth_sys_msec 56
+  # HELP pdns_auth_udp_in_errors UDP 'in' errors
+  # TYPE pdns_auth_udp_in_errors counter
+  pdns_auth_udp_in_errors 151
+  # HELP pdns_auth_udp_noport_errors UDP 'noport' errors
+  # TYPE pdns_auth_udp_noport_errors counter
+  pdns_auth_udp_noport_errors 9
+  # HELP pdns_auth_udp_recvbuf_errors UDP 'recvbuf' errors
+  # TYPE pdns_auth_udp_recvbuf_errors counter
+  pdns_auth_udp_recvbuf_errors 0
+  # HELP pdns_auth_udp_sndbuf_errors UDP 'sndbuf' errors
+  # TYPE pdns_auth_udp_sndbuf_errors counter
+  pdns_auth_udp_sndbuf_errors 9
+  # HELP pdns_auth_uptime Uptime of process in seconds
+  # TYPE pdns_auth_uptime counter
+  pdns_auth_uptime 672
+  # HELP pdns_auth_user_msec Number of msec spent in user time
+  # TYPE pdns_auth_user_msec counter
+  pdns_auth_user_msec 48
+
+
+Prometheus can then be configured to scrape metrics from this endpoint using a simple job description like the following:
+
+.. prometheus scrape-job::
+
+  scrape_configs:
+    - job_name: 'pdns_auth'
+      scrape_interval: 1m
+      static_configs:
+        - targets: ['pdns_auth_host:pdns_auth_ws_port'] 
+
+Further details can be gathered from the `prometheus docs <https://prometheus.io/docs/prometheus/latest/configuration/configuration/#scrape_config>`_.
+
+
 Enabling the API
 ----------------
 
index 8de9398fbc311e22e5a5bab4630c67eb732a7b9c..58f16aba4be9ed66b89683afa45086e00a5982a0 100644 (file)
@@ -35,7 +35,12 @@ Allow 8 bit DNS queries.
 -  Default: 127.0.0.0/8,::1
 
 If set, only these IP addresses or netmasks will be able to perform
-AXFR.
+AXFR without TSIG.
+
+.. warning::
+   This setting only applies to AXFR without TSIG keys. If you allow a TSIG key to perform an AXFR,
+   this setting will not be checked for that transfer, and the client will be able to perform the AXFR
+   from everywhere.
 
 .. _setting-allow-dnsupdate-from:
 
@@ -770,19 +775,27 @@ available in non-static distributions.
 ``local-address``
 -----------------
 .. versionchanged:: 4.3.0
-  now also takes your IPv6 addresses
+  now also accepts IPv6 addresses
 
 .. versionchanged:: 4.3.0
-  Before 4.3.0, this setting only supported IPv4.
+  Before 4.3.0, this setting only supported IPv4 addresses.
 
--  IPv4 Addresses, separated by commas or whitespace
+-  IPv4/IPv6 Addresses, with optional port numbers, separated by commas or whitespace
 -  Default: ``0.0.0.0, ::``
 
-Local IP addresses to which we bind. It is highly advised to bind to
-specific interfaces and not use the default 'bind to any'. This causes
-big problems if you have multiple IP addresses. Unix does not provide a
-way of figuring out what IP address a packet was sent to when binding to
-any.
+Local IP addresses to which we bind. Each address specified can
+include a port number; if no port is included then the
+:ref:`setting-local-port` port will be used for that address. If a
+port number is specified, it must be separated from the address with a
+':'; for an IPv6 address the address must be enclosed in square
+brackets.
+
+Examples::
+
+  local-address=127.0.0.1 ::1
+  local-address=0.0.0.0:5353
+  local-address=[::]:8053
+  local-address=127.0.0.1:53, [::1]:5353
 
 .. _setting-local-address-nonexist-fail:
 
@@ -834,7 +847,8 @@ addresses do not exist on this server.
 -  Integer
 -  Default: 53
 
-The port on which we listen. Only one port possible.
+Local port to bind to.
+If an address in :ref:`setting-local-address` does not have an explicit port, this port is used.
 
 .. _setting-log-dns-details:
 
index 0716c9487e0ffee0bd5db71b97e87d28d4b7a881..1f7941c89f59522768b8291613b8c9890e4831c5 100644 (file)
@@ -33,6 +33,10 @@ with the key name in the content field. For example::
 
     $ dig -t axfr powerdnssec.org @127.0.0.1 -y 'test:kp4/24gyYsEzbuTVJRUMoqGFmN3LYgVDzJ/3oRSP7ys='
 
+.. warning::
+  Any host with the correct TSIG key will be able to perform the AXFR, even
+  if the host is not within the defined ``allow-axfr-ips`` ranges.
+
 Another way of importing and activating TSIG keys into the database is using
 :doc:`pdnsutil <manpages/pdnsutil.1>`:
 
index 056a6cd823dfb208eab7dae21619e5f781e94e48..16d150fa7d6112e4f1d276f28da6a1d9acd8e4d3 100644 (file)
@@ -12,8 +12,9 @@
 #include <vector>
 #include <algorithm>
 
-// apple compiler somehow has string_view even in c++11!
-#if __cplusplus < 201703L && !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(__FreeBSD__)
+#ifdef __cpp_lib_string_view
+using std::string_view;
+#else
 #include <boost/version.hpp>
 #if BOOST_VERSION >= 106100
 #include <boost/utility/string_view.hpp>
@@ -22,8 +23,6 @@ using boost::string_view;
 #include <boost/utility/string_ref.hpp>
 using string_view = boost::string_ref;
 #endif
-#else // C++17
-using std::string_view;
 #endif
 
 
index ce42ca7932361013a9c7eb935ab0dd7c0ea4f590..6d5bc3ab0e1af2b39b4483a43f23bd52b70b1bb7 100644 (file)
@@ -384,7 +384,6 @@ int HTTPConnector::recv_message(Json& output) {
     if (d_socket == nullptr ) return -1; // cannot receive :(
     char buffer[4096];
     int rd = -1;
-    bool fail = false;
     time_t t0;
 
     arl.initialize(&resp);
@@ -403,24 +402,18 @@ int HTTPConnector::recv_message(Json& output) {
       if (arl.ready() == false)
         throw NetworkError("timeout");
     } catch (NetworkError &ne) {
-      g_log<<Logger::Error<<"While reading from HTTP endpoint "<<d_addr.toStringWithPort()<<": "<<ne.what()<<std::endl; 
       d_socket.reset();
-      fail = true;
+      throw PDNSException("While reading from HTTP endpoint " + d_addr.toStringWithPort() + ": " + ne.what());
     } catch (...) {
-      g_log<<Logger::Error<<"While reading from HTTP endpoint "<<d_addr.toStringWithPort()<<": exception caught"<<std::endl;
       d_socket.reset();
-      fail = true;
-    }
-
-    if (fail) {
-      return -1;
+      throw PDNSException("While reading from HTTP endpoint " + d_addr.toStringWithPort() + ": unknown error");
     }
 
     arl.finalize();
 
-    if (resp.status < 200 || resp.status >= 400) {
+    if ((resp.status < 200 || resp.status >= 400) && resp.status != 404) {
       // bad. 
-      return -1;
+      throw PDNSException("Received unacceptable HTTP status code " + std::to_string(resp.status) + " from HTTP endpoint " + d_addr.toStringWithPort());
     }
 
     int rv = -1;
index b5862edbc273adf6b5663441fc8691e756992524..77e74ab893330c093e21545a09055ef7e6975e6b 100644 (file)
@@ -42,18 +42,27 @@ bool Connector::send(Json& value) {
  * result. Logging is performed here, too.
  */
 bool Connector::recv(Json& value) {
-    if (recv_message(value)>0) {
-       bool rv = true;
-       // check for error
-       if (value["result"] == Json())
-         return false;
-       if (value["result"].is_bool() && boolFromJson(value, "result", false) == false)
-         rv = false;
-       for(const auto& message: value["log"].array_items())
-         g_log<<Logger::Info<<"[remotebackend]: "<< message.string_value() <<std::endl;
-       return rv;
+  if (recv_message(value) > 0) {
+    bool retval = true;
+    if (value["result"] == Json()) {
+      throw PDNSException("No 'result' field in response from remote process");
+    } else if (value["result"].is_bool() && boolFromJson(value, "result", false) == false) {
+      retval = false;
     }
-    return false;
+    for(const auto& message: value["log"].array_items()) {
+      g_log<<Logger::Info<<"[remotebackend]: "<< message.string_value() <<std::endl;
+    }
+    return retval;
+  }
+  throw PDNSException("Unknown error while receiving data");
+}
+
+void RemoteBackend::makeErrorAndThrow(Json &value) {
+  std::string msg = "Remote process indicated a failure";
+  for(const auto& message: value["log"].array_items()) {
+    msg += " '" + message.string_value() + "'";
+  }
+  throw PDNSException(msg);
 }
 
 /**
@@ -74,29 +83,31 @@ RemoteBackend::RemoteBackend(const std::string &suffix)
 RemoteBackend::~RemoteBackend() { }
 
 bool RemoteBackend::send(Json& value) {
-   try {
-     return connector->send(value);
-   } catch (PDNSException &ex) {
-     g_log<<Logger::Error<<"Exception caught when sending: "<<ex.reason<<std::endl;
-   }
-
-   this->connector.reset();
-   build();
-   return false;
+  try {
+    if (!connector->send(value)) {
+      // XXX does this work work even though we throw?
+      this->connector.reset();
+      build();
+      throw DBException("Could not send a message to remote process");
+    }
+  } catch (const PDNSException &ex) {
+    throw DBException("Exception caught when sending: " + ex.reason);
+  }
+  return true;
 }
 
 bool RemoteBackend::recv(Json& value) {
-   try {
-     return connector->recv(value);
-   } catch (PDNSException &ex) {
-     g_log<<Logger::Error<<"Exception caught when receiving: "<<ex.reason<<std::endl;
-   } catch (...) {
-     g_log<<Logger::Error<<"Exception caught when receiving"<<std::endl;;
-   }
-
-   this->connector.reset();
-   build();
-   return false;
+  try {
+    return connector->recv(value);
+  } catch (const PDNSException &ex) {
+    this->connector.reset();
+    build();
+    throw DBException("Exception caught when receiving: " + ex.reason);
+  } catch (const std::exception &e) {
+    this->connector.reset();
+    build();
+    throw DBException("Exception caught when receiving: " + std::string(e.what()));
+  }
 }
 
 
index 5f94d223bc4c0864a06768f3a3dde8ac24cedc5d..cadc8eed7e8e0742f9e0c0327c5d2b27b7ba9b97 100644 (file)
@@ -207,6 +207,7 @@ class RemoteBackend : public DNSBackend
 
     bool send(Json &value);
     bool recv(Json &value);
+    void makeErrorAndThrow(Json &value);
  
     string asString(const Json& value) {
       if (value.is_number()) return std::to_string(value.int_value());
index 759864e58888323b83981edccd7e210e9c004ad7..1cb554f44ed4e4513594ecd1527608ba0e9ecc6b 100644 (file)
@@ -34,7 +34,7 @@ AuthPacketCache::AuthPacketCache(size_t mapsCount): d_maps(mapsCount), d_lastcle
 {
   S.declare("packetcache-hit", "Number of hits on the packet cache");
   S.declare("packetcache-miss", "Number of misses on the packet cache");
-  S.declare("packetcache-size", "Number of entries in the packet cache");
+  S.declare("packetcache-size", "Number of entries in the packet cache", StatType::gauge);
   S.declare("deferred-packetcache-inserts","Amount of packet cache inserts that were deferred because of maintenance");
   S.declare("deferred-packetcache-lookup","Amount of packet cache lookups that were deferred because of maintenance");
 
index f98d9b133d875aa8d15222ac17c40d0831ae426a..82489e1e9214a4fafa33fdf1941d8221d1e3d491 100644 (file)
@@ -35,7 +35,7 @@ AuthQueryCache::AuthQueryCache(size_t mapsCount): d_maps(mapsCount), d_lastclean
 {
   S.declare("query-cache-hit","Number of hits on the query cache");
   S.declare("query-cache-miss","Number of misses on the query cache");
-  S.declare("query-cache-size", "Number of entries in the query cache");
+  S.declare("query-cache-size", "Number of entries in the query cache", StatType::gauge);
   S.declare("deferred-cache-inserts","Amount of cache inserts that were deferred because of maintenance");
   S.declare("deferred-cache-lookup","Amount of cache lookups that were deferred because of maintenance");
 
index f5a777c1435c59713b50dc6a80e280ba5982915f..fe4994cc1392e12ad86babd5a76d95682f7e0ba1 100644 (file)
@@ -333,9 +333,9 @@ void declareStats(void)
   S.declare("tcp6-queries","Number of IPv6 TCP queries received");
   S.declare("tcp6-answers","Number of IPv6 answers sent out over TCP");
 
-  S.declare("open-tcp-connections","Number of currently open TCP connections", getTCPConnectionCount);;
+  S.declare("open-tcp-connections","Number of currently open TCP connections", getTCPConnectionCount, StatType::gauge);
 
-  S.declare("qsize-q","Number of questions waiting for database attention", getQCount);
+  S.declare("qsize-q","Number of questions waiting for database attention", getQCount, StatType::gauge);
 
   S.declare("dnsupdate-queries", "DNS update packets received.");
   S.declare("dnsupdate-answers", "DNS update packets successfully answered.");
@@ -344,33 +344,33 @@ void declareStats(void)
 
   S.declare("incoming-notifications", "NOTIFY packets received.");
 
-  S.declare("uptime", "Uptime of process in seconds", uptimeOfProcess);
-  S.declare("real-memory-usage", "Actual unique use of memory in bytes (approx)", getRealMemoryUsage);
-  S.declare("special-memory-usage", "Actual unique use of memory in bytes (approx)", getSpecialMemoryUsage);
-  S.declare("fd-usage", "Number of open filedescriptors", getOpenFileDescriptors);
+  S.declare("uptime", "Uptime of process in seconds", uptimeOfProcess, StatType::counter);
+  S.declare("real-memory-usage", "Actual unique use of memory in bytes (approx)", getRealMemoryUsage, StatType::gauge);
+  S.declare("special-memory-usage", "Actual unique use of memory in bytes (approx)", getSpecialMemoryUsage, StatType::gauge);
+  S.declare("fd-usage", "Number of open filedescriptors", getOpenFileDescriptors, StatType::gauge);
 #ifdef __linux__
-  S.declare("udp-recvbuf-errors", "UDP 'recvbuf' errors", udpErrorStats);
-  S.declare("udp-sndbuf-errors", "UDP 'sndbuf' errors", udpErrorStats);
-  S.declare("udp-noport-errors", "UDP 'noport' errors", udpErrorStats);
-  S.declare("udp-in-errors", "UDP 'in' errors", udpErrorStats);
+  S.declare("udp-recvbuf-errors", "UDP 'recvbuf' errors", udpErrorStats, StatType::counter);
+  S.declare("udp-sndbuf-errors", "UDP 'sndbuf' errors", udpErrorStats, StatType::counter);
+  S.declare("udp-noport-errors", "UDP 'noport' errors", udpErrorStats, StatType::counter);
+  S.declare("udp-in-errors", "UDP 'in' errors", udpErrorStats, StatType::counter);
 #endif
 
-  S.declare("sys-msec", "Number of msec spent in system time", getSysUserTimeMsec);
-  S.declare("user-msec", "Number of msec spent in user time", getSysUserTimeMsec);
+  S.declare("sys-msec", "Number of msec spent in system time", getSysUserTimeMsec, StatType::counter);
+  S.declare("user-msec", "Number of msec spent in user time", getSysUserTimeMsec, StatType::counter);
 
 #ifdef __linux__
-  S.declare("cpu-iowait", "Time spent waiting for I/O to complete by the whole system, in units of USER_HZ", getCPUIOWait);
-  S.declare("cpu-steal", "Stolen time, which is the time spent by the whole system in other operating systems when running in a virtualized environment, in units of USER_HZ", getCPUSteal);
+  S.declare("cpu-iowait", "Time spent waiting for I/O to complete by the whole system, in units of USER_HZ", getCPUIOWait, StatType::counter);
+  S.declare("cpu-steal", "Stolen time, which is the time spent by the whole system in other operating systems when running in a virtualized environment, in units of USER_HZ", getCPUSteal, StatType::counter);
 #endif
 
-  S.declare("meta-cache-size", "Number of entries in the metadata cache", DNSSECKeeper::dbdnssecCacheSizes);
-  S.declare("key-cache-size", "Number of entries in the key cache", DNSSECKeeper::dbdnssecCacheSizes);
-  S.declare("signature-cache-size", "Number of entries in the signature cache", signatureCacheSize);
+  S.declare("meta-cache-size", "Number of entries in the metadata cache", DNSSECKeeper::dbdnssecCacheSizes, StatType::gauge);
+  S.declare("key-cache-size", "Number of entries in the key cache", DNSSECKeeper::dbdnssecCacheSizes, StatType::gauge);
+  S.declare("signature-cache-size", "Number of entries in the signature cache", signatureCacheSize, StatType::gauge);
 
   S.declare("servfail-packets","Number of times a server-failed packet was sent out");
-  S.declare("latency","Average number of microseconds needed to answer a question", getLatency);
+  S.declare("latency","Average number of microseconds needed to answer a question", getLatency, StatType::gauge);
   S.declare("timedout-packets","Number of packets which weren't answered within timeout set");
-  S.declare("security-status", "Security status based on regular polling");
+  S.declare("security-status", "Security status based on regular polling", StatType::gauge);
   S.declareDNSNameQTypeRing("queries","UDP Queries Received");
   S.declareDNSNameQTypeRing("nxdomain-queries","Queries for non-existent records within existent domains");
   S.declareDNSNameQTypeRing("noerror-queries","Queries for existing records, but for type we don't have");
index 1d3dfb4758d18d8fa505cbb586dde9923f99dd14..7e56c1590daa566f48f5f6f398417f6cfd060188 100644 (file)
@@ -22,8 +22,9 @@
 
 #pragma once
 
-// apple compiler somehow has string_view even in c++11!
-#if __cplusplus < 201703L && !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(__FreeBSD__)
+#ifdef __cpp_lib_string_view
+using std::string_view;
+#else
 #include <boost/version.hpp>
 #if BOOST_VERSION >= 106100
 #include <boost/utility/string_view.hpp>
@@ -32,6 +33,4 @@ using boost::string_view;
 #include <boost/utility/string_ref.hpp>
 using string_view = boost::string_ref;
 #endif
-#else // C++17
-using std::string_view;
 #endif
index 1e74044b468c40235e72e33492acfd88a681a194..ddd9c6664a75999837889784bac05c85d9a40b86 100644 (file)
@@ -6,6 +6,7 @@ Please find it `here <https://github.com/PowerDNS/pdns/blob/master/pdns/recursor
 Queries can be intercepted in many places:
 
 -  before any packet parsing begins (:func:`ipfilter`)
+-  before the packet cache has been looked up (:func:`gettag` and its FFI counterpart, :func:`gettag_ffi`)
 -  before any filtering policy have been applied (:func:`prerpz`)
 -  before the resolving logic starts to work (:func:`preresolve`)
 -  after the resolving process failed to find a correct answer for a domain (:func:`nodata`, :func:`nxdomain`)
@@ -100,6 +101,18 @@ Interception Functions
 
     :return: ``tag`` [``, policyTags`` [``, data`` [``, reqId`` [``, deviceId`` [``, deviceName`` [``, routingTag`` ]]]]]]
 
+.. function:: gettag_ffi(param) -> optional Lua object
+
+    .. versionadded:: 4.1.2
+
+    .. versionchanged:: 4.3.0
+
+      The ability to craft answers was added.
+
+    This function is the FFI counterpart of the :func:`gettag` function, and offers the same functionality.
+    It accepts a single, scalable parameter which can be accessed using FFI accessors.
+    Like the non-FFI version, it has the ability to set a tag for the packetcache, policy tags, a routing tag, the :attr:`DNSQuestion.requestorId` and :attr:`DNSQuestion.deviceId`values and to fill the :attr:`DNSQuestion.data` table. It also offers ways to mark the answer as variable so it's not inserted into the packetcache, to set a cap on the TTL of the returned records, and to generate a response by adding records and setting the RCode. It can also instruct the recursor to do a proper resolution in order to follow any `CNAME` records added in this step.
+
 .. function:: prerpz(dq)
 
   This hook is called before any filtering policy have been applied,  making it possible to completely disable filtering by setting  :attr:`dq.wantsRPZ <DNSQuestion.wantsRPZ>` to false.
index 689d09cc8e5ee4d2530f8b40407f0c7fc39c6014..4bd7d3de974c4c235746d10c4410d8e70770e92b 100644 (file)
@@ -76,6 +76,8 @@ at `<https://doc.powerdns.com/>`
     Load root hints from this *filename*
 --local-address=<address>
     Listen on *address*, separated by spaces or commas.
+    Addresses specified can include port numbers; any which do not
+    include port numbers will listen on *--local-port*.
 --local-port=<port>
     Listen on *port*.
 --log-common-errors
index a3425b96cd80fdb5fecf5b9a792224b41e47ee74..26cc9989a4f518ba688e692c30c4d31efc9dfd4e 100644 (file)
@@ -715,14 +715,22 @@ Indication of how many queries will be averaged to get the average latency repor
 
 ``local-address``
 -----------------
--  IP addresses, comma separated
--  Default: 127.0.0.1
-
-Local IPv4 or IPv6 addresses to bind to.
-Addresses can also contain port numbers, for IPv4 specify like this: ``192.0.2.4:5300``, for IPv6: ``[::1]:5300``.
-
-**Warning**: When binding to wildcard addresses, UNIX semantics mean that answers may not be sent from the address a query was received on.
-It is highly recommended to bind to explicit addresses.
+-  IPv4/IPv6 Addresses, with optional port numbers, separated by commas or whitespace
+-  Default: ``0.0.0.0, ::``
+
+Local IP addresses to which we bind. Each address specified can
+include a port number; if no port is included then the
+:ref:`setting-local-port` port will be used for that address. If a
+port number is specified, it must be separated from the address with a
+':'; for an IPv6 address the address must be enclosed in square
+brackets.
+
+Examples::
+
+  local-address=127.0.0.1 ::1
+  local-address=0.0.0.0:5353
+  local-address=[::]:8053
+  local-address=127.0.0.1:53, [::1]:5353
 
 .. _setting-local-port:
 
index ca0852f9c8720fcc66335e0cfa8f0e472d2522c8..96c71e67c9b52bf6ae638edd28ae77f812c63465 100644 (file)
@@ -238,6 +238,56 @@ BOOST_AUTO_TEST_CASE(test_dnssec_ds_sign_loop)
   BOOST_CHECK_EQUAL(queriesCount, 8U);
 }
 
+BOOST_AUTO_TEST_CASE(test_dnssec_ds_root)
+{
+  std::unique_ptr<SyncRes> sr;
+  initSR(sr, true);
+
+  setDNSSECValidation(sr, DNSSECMode::ValidateAll);
+
+  primeHints();
+  const DNSName target(".");
+  testkeysset_t keys;
+
+  auto luaconfsCopy = g_luaconfs.getCopy();
+  luaconfsCopy.dsAnchors.clear();
+  generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
+
+  g_luaconfs.setState(luaconfsCopy);
+
+  size_t queriesCount = 0;
+
+  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) {
+    queriesCount++;
+
+    if (type == QType::DS) {
+      setLWResult(res, 0, true, false, true);
+      addRecordToLW(res, ".", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
+      addRRSIG(keys, res->d_records, DNSName("."), 300);
+      addNSECRecordToLW(domain, DNSName("aaa."), {QType::DNSKEY, QType::SOA, QType::NS, QType::NSEC, QType::RRSIG}, 600, res->d_records);
+      addRRSIG(keys, res->d_records, DNSName("."), 300);
+      return 1;
+    }
+
+    return 0;
+  });
+
+  vector<DNSRecord> ret;
+  int res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
+  BOOST_CHECK_EQUAL(res, RCode::NoError);
+  BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
+  BOOST_REQUIRE_EQUAL(ret.size(), 4U);
+  BOOST_CHECK_EQUAL(queriesCount, 1U);
+
+  /* again, to test the cache */
+  ret.clear();
+  res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
+  BOOST_CHECK_EQUAL(res, RCode::NoError);
+  BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
+  BOOST_REQUIRE_EQUAL(ret.size(), 4U);
+  BOOST_CHECK_EQUAL(queriesCount, 1U);
+}
+
 BOOST_AUTO_TEST_CASE(test_dnssec_dnskey_signed_child)
 {
   /* check that we don't accept a signer below us */
index 9d89d15b774294904e8450527ac8a99bb35bb916..110287ae0831879ce9a2d3e805652d925bb27848 100644 (file)
@@ -97,18 +97,25 @@ string StatBag::getDescrip(const string &item)
   return d_keyDescrips[item];
 }
 
-void StatBag::declare(const string &key, const string &descrip)
+StatType StatBag::getStatType(const string &item)
+{
+  exists(item);
+  return d_statTypes[item];
+}
+
+void StatBag::declare(const string &key, const string &descrip, StatType statType)
 {
   auto i=make_unique<AtomicCounter>(0);
   d_stats[key]=std::move(i);
   d_keyDescrips[key]=descrip;
+  d_statTypes[key]=statType;
 }
 
-void StatBag::declare(const string &key, const string &descrip, StatBag::func_t func)
+void StatBag::declare(const string &key, const string &descrip, StatBag::func_t func, StatType statType)
 {
-
   d_funcstats[key]=func;
   d_keyDescrips[key]=descrip;
+  d_statTypes[key]=statType;
 }
 
           
@@ -237,8 +244,8 @@ vector<pair<T, unsigned int> >StatRing<T,Comp>::get() const
 
 void StatBag::registerRingStats(const string& name)
 {
-  declare("ring-" + name + "-size", "Number of entries in the " + name + " ring", [this,name](const std::string&) { return static_cast<uint64_t>(getRingEntriesCount(name)); });
-  declare("ring-" + name + "-capacity", "Maximum number of entries in the " + name + " ring", [this,name](const std::string&) { return static_cast<uint64_t>(getRingSize(name)); });
+  declare("ring-" + name + "-size", "Number of entries in the " + name + " ring", [this,name](const std::string&) { return static_cast<uint64_t>(getRingEntriesCount(name)); }, StatType::gauge);
+  declare("ring-" + name + "-capacity", "Maximum number of entries in the " + name + " ring", [this,name](const std::string&) { return static_cast<uint64_t>(getRingSize(name)); }, StatType::gauge);
 }
 
 void StatBag::declareRing(const string &name, const string &help, unsigned int size)
index 982f739dfbe43b5f0ac6554150486936eb6358df..1887b7833a4cc5c329b7f5599a7260a721fd6d21 100644 (file)
@@ -62,12 +62,17 @@ private:
   string d_help;
 };
 
+enum class StatType : uint8_t {
+  counter = 1,
+  gauge = 2,
+};
 
 //! use this to gather and query statistics
 class StatBag
 {
   map<string, std::unique_ptr<AtomicCounter>> d_stats;
   map<string, string> d_keyDescrips;
+  map<string, StatType> d_statTypes;
   map<string,StatRing<string, CIStringCompare> >d_rings;
   map<string,StatRing<SComboAddress> >d_comboRings;
   map<string,StatRing<std::tuple<DNSName, QType> > >d_dnsnameqtyperings;
@@ -82,8 +87,8 @@ class StatBag
 public:
   StatBag(); //!< Naked constructor. You need to declare keys before this class becomes useful
   ~StatBag();
-  void declare(const string &key, const string &descrip=""); //!< Before you can store or access a key, you need to declare it
-  void declare(const string &key, const string &descrip, func_t func); //!< Before you can store or access a key, you need to declare it
+  void declare(const string &key, const string &descrip="", StatType statType=StatType::counter); //!< Before you can store or access a key, you need to declare it
+  void declare(const string &key, const string &descrip, func_t func, StatType statType); //!< Before you can store or access a key, you need to declare it
 
   void declareRing(const string &name, const string &title, unsigned int size=10000);
   void declareComboRing(const string &name, const string &help, unsigned int size=10000);
@@ -131,6 +136,7 @@ public:
   string directory(); //!< Returns a list of all data stored
   vector<string> getEntries(); //!< returns a vector with datums (items)
   string getDescrip(const string &item); //!< Returns the description of this datum/item
+  StatType getStatType(const string &item); //!< Returns the stats type for the metrics endpoint
   void exists(const string &key); //!< call this function to throw an exception in case a key does not exist
   inline void deposit(const string &key, int value); //!< increment the statistics behind this key by value amount
   inline void inc(const string &key); //!< increase this key's value by one
index c01851dfe0cb2ad76e064fb50e036a4030569eef..27b78cd2883d03a06bd24770320307a1e2291f12 100644 (file)
@@ -2367,8 +2367,10 @@ vState SyncRes::validateRecordsWithSigs(unsigned int depth, const DNSName& qname
     if (!signer.empty() && name.isPartOf(signer)) {
       if ((qtype == QType::DNSKEY || qtype == QType::DS) && signer == qname) {
         /* we are already retrieving those keys, sorry */
-        if (qtype == QType::DS) {
-          /* something is very wrong */
+        if (qtype == QType::DS && !signer.isRoot()) {
+          /* Unless we are getting the DS of the root zone, we should never see a
+             DS (or a denial of a DS) signed by the DS itself, since we should be
+             requesting it from the parent zone. Something is very wrong */
           LOG(d_prefix<<"The DS for "<<qname<<" is signed by itself, going Bogus"<<endl);
           return Bogus;
         }
@@ -2572,11 +2574,13 @@ RCode::rcodes_ SyncRes::updateCacheFromRecords(unsigned int depth, LWResult& lwr
   const unsigned int labelCount = qname.countLabels();
   bool isCNAMEAnswer = false;
   bool isDNAMEAnswer = false;
-  for(const auto& rec : lwr.d_records) {
-    if (rec.d_class != QClass::IN) {
+  for (auto& rec : lwr.d_records) {
+    if (rec.d_type == QType::OPT || rec.d_class != QClass::IN) {
       continue;
     }
 
+    rec.d_ttl = min(s_maxcachettl, rec.d_ttl);
+
     if(!isCNAMEAnswer && rec.d_place == DNSResourceRecord::ANSWER && rec.d_type == QType::CNAME && (!(qtype==QType(QType::CNAME))) && rec.d_name == qname && !isDNAMEAnswer) {
       isCNAMEAnswer = true;
     }
@@ -2599,7 +2603,7 @@ RCode::rcodes_ SyncRes::updateCacheFromRecords(unsigned int depth, LWResult& lwr
         }
       }
     }
-    if(rec.d_type == QType::RRSIG) {
+    if (rec.d_type == QType::RRSIG) {
       auto rrsig = getRR<RRSIGRecordContent>(rec);
       if (rrsig) {
         /* As illustrated in rfc4035's Appendix B.6, the RRSIG label
index 7e93964e0c5b42e908c666a16e332cbb3b3c222b..6dea329261a4db8624204365e74ecf0d9754760d 100644 (file)
@@ -1057,8 +1057,10 @@ int TCPNameserver::doIXFR(std::unique_ptr<DNSPacket>& q, int outsock)
 
   g_log<<Logger::Error<<"IXFR of domain '"<<q->qdomain<<"' initiated by "<<q->getRemote()<<" with serial "<<serial<<endl;
 
-  // determine if zone exists and AXFR is allowed using existing backend before spawning a new backend.
+  // determine if zone exists, XFR is allowed, and if IXFR can proceed using existing backend before spawning a new backend.
   SOAData sd;
+  bool securedZone;
+  bool serialPermitsIXFR;
   {
     std::lock_guard<std::mutex> l(s_plock);
     DLOG(g_log<<"Looking for SOA"<<endl); // find domain_id via SOA and list complete domain. No SOA, no IXFR
@@ -1074,39 +1076,33 @@ int TCPNameserver::doIXFR(std::unique_ptr<DNSPacket>& q, int outsock)
       sendPacket(outpacket,outsock);
       return 0;
     }
-  }
-
-  DNSSECKeeper dk;
-  NSEC3PARAMRecordContent ns3pr;
-  bool narrow;
 
-  DNSSECKeeper::clearCaches(q->qdomain);
-  bool securedZone = dk.isSecuredZone(q->qdomain);
-  if(dk.getNSEC3PARAM(q->qdomain, &ns3pr, &narrow)) {
-    if(narrow) {
-      g_log<<Logger::Error<<"Not doing IXFR of an NSEC3 narrow zone."<<endl;
-      g_log<<Logger::Error<<"IXFR of domain '"<<q->qdomain<<"' denied to "<<q->getRemote()<<endl;
-      outpacket->setRcode(RCode::Refused);
-      sendPacket(outpacket,outsock);
-      return 0;
+    DNSSECKeeper dk(s_P->getBackend());
+    DNSSECKeeper::clearCaches(q->qdomain);
+    bool narrow;
+    securedZone = dk.isSecuredZone(q->qdomain);
+    if(dk.getNSEC3PARAM(q->qdomain, nullptr, &narrow)) {
+      if(narrow) {
+        g_log<<Logger::Error<<"Not doing IXFR of an NSEC3 narrow zone."<<endl;
+        g_log<<Logger::Error<<"IXFR of domain '"<<q->qdomain<<"' denied to "<<q->getRemote()<<endl;
+        outpacket->setRcode(RCode::Refused);
+        sendPacket(outpacket,outsock);
+        return 0;
+      }
     }
-  }
-
-  DNSName target = q->qdomain;
 
-  UeberBackend db;
-  if(!db.getSOAUncached(target, sd)) {
-    g_log<<Logger::Error<<"IXFR of domain '"<<target<<"' failed: not authoritative in second instance"<<endl;
-    outpacket->setRcode(RCode::NotAuth);
-    sendPacket(outpacket,outsock);
-    return 0;
+    serialPermitsIXFR = !rfc1982LessThan(serial, calculateEditSOA(sd.serial, dk, sd.qname));
   }
 
-  if (!rfc1982LessThan(serial, calculateEditSOA(sd.serial, dk, sd.qname))) {
+  if (serialPermitsIXFR) {
+    DNSName target = q->qdomain;
     TSIGRecordContent trc;
     DNSName tsigkeyname;
     string tsigsecret;
 
+    UeberBackend db;
+    DNSSECKeeper dk(&db);
+
     bool haveTSIGDetails = q->getTSIGDetails(&trc, &tsigkeyname);
 
     if(haveTSIGDetails && !tsigkeyname.empty()) {
@@ -1114,8 +1110,7 @@ int TCPNameserver::doIXFR(std::unique_ptr<DNSPacket>& q, int outsock)
       DNSName algorithm=trc.d_algoName; // FIXME400: was toLowerCanonic, compare output
       if (algorithm == DNSName("hmac-md5.sig-alg.reg.int"))
         algorithm = DNSName("hmac-md5");
-      std::lock_guard<std::mutex> l(s_plock);
-      if(!s_P->getBackend()->getTSIGKey(tsigkeyname, &algorithm, &tsig64)) {
+      if(!db.getTSIGKey(tsigkeyname, &algorithm, &tsig64)) {
         g_log<<Logger::Error<<"TSIG key '"<<tsigkeyname<<"' for domain '"<<target<<"' not found"<<endl;
         return 0;
       }
@@ -1125,8 +1120,6 @@ int TCPNameserver::doIXFR(std::unique_ptr<DNSPacket>& q, int outsock)
       }
     }
 
-    UeberBackend signatureDB;
-
     // SOA *must* go out first, our signing pipe might reorder
     DLOG(g_log<<"Sending out SOA"<<endl);
     DNSZoneRecord soa = makeEditedDNSZRFromSOAData(dk, sd);
@@ -1134,7 +1127,7 @@ int TCPNameserver::doIXFR(std::unique_ptr<DNSPacket>& q, int outsock)
     if(securedZone && outpacket->d_dnssecOk) {
       set<DNSName> authSet;
       authSet.insert(target);
-      addRRSigs(dk, signatureDB, authSet, outpacket->getRRS());
+      addRRSigs(dk, db, authSet, outpacket->getRRS());
     }
 
     if(haveTSIGDetails && !tsigkeyname.empty())
@@ -1147,7 +1140,7 @@ int TCPNameserver::doIXFR(std::unique_ptr<DNSPacket>& q, int outsock)
     return 1;
   }
 
-  g_log<<Logger::Error<<"IXFR fallback to AXFR for domain '"<<target<<"' our serial "<<sd.serial<<endl;
+  g_log<<Logger::Error<<"IXFR fallback to AXFR for domain '"<<q->qdomain<<"' our serial "<<sd.serial<<endl;
   return doAXFR(q->qdomain, q, outsock);
 }
 
index de5fa008405e1a019be87da67208bb0fec535081..864a1b586e34a23986f39a49185bfbc7f415de7b 100644 (file)
@@ -2253,6 +2253,35 @@ static void apiServerCacheFlush(HttpRequest* req, HttpResponse* resp) {
   });
 }
 
+static std::ostream& operator<<(std::ostream& os, StatType statType)
+{
+  switch (statType)
+  {
+    case StatType::counter: return os << "counter";
+    case StatType::gauge: return os << "gauge";
+  };
+  return os << static_cast<uint16_t>(statType);
+}
+
+static void prometheusMetrics(HttpRequest* req, HttpResponse* resp) {
+  if (req->method != "GET")
+    throw HttpMethodNotAllowedException();
+
+  std::ostringstream output;
+  for (const auto &metricName : S.getEntries()) {
+    // Prometheus suggest using '_' instead of '-'
+    std::string prometheusMetricName = "pdns_auth_" + boost::replace_all_copy(metricName, "-", "_");
+
+    output << "# HELP " << prometheusMetricName << " " << S.getDescrip(metricName) << "\n";
+    output << "# TYPE " << prometheusMetricName << " " << S.getStatType(metricName) << "\n";
+    output << prometheusMetricName << " " << S.read(metricName) << "\n";
+  }
+
+  resp->body = output.str();
+  resp->headers["Content-Type"] = "text/plain";
+  resp->status = 200;
+}
+
 void AuthWebServer::cssfunction(HttpRequest* req, HttpResponse* resp)
 {
   resp->headers["Cache-Control"] = "max-age=86400";
@@ -2317,6 +2346,7 @@ void AuthWebServer::webThread()
     if (::arg().mustDo("webserver")) {
       d_ws->registerWebHandler("/style.css", std::bind(&AuthWebServer::cssfunction, this, std::placeholders::_1, std::placeholders::_2));
       d_ws->registerWebHandler("/", std::bind(&AuthWebServer::indexfunction, this, std::placeholders::_1, std::placeholders::_2));
+      d_ws->registerWebHandler("/metrics", prometheusMetrics);
     }
     d_ws->go();
   }