rec: more sophisticated cname loop detection.
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
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:
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
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.
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
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
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
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
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
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
* :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
----------------
- 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:
``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:
- 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:
$ 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>`:
#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>
#include <boost/utility/string_ref.hpp>
using string_view = boost::string_ref;
#endif
-#else // C++17
-using std::string_view;
#endif
if (d_socket == nullptr ) return -1; // cannot receive :(
char buffer[4096];
int rd = -1;
- bool fail = false;
time_t t0;
arl.initialize(&resp);
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;
* 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);
}
/**
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()));
+ }
}
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());
{
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");
{
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");
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.");
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");
#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>
#include <boost/utility/string_ref.hpp>
using string_view = boost::string_ref;
#endif
-#else // C++17
-using std::string_view;
#endif
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`)
: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.
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
``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:
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 */
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;
}
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)
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;
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);
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
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;
}
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;
}
}
}
}
- 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
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
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()) {
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;
}
}
}
- UeberBackend signatureDB;
-
// SOA *must* go out first, our signing pipe might reorder
DLOG(g_log<<"Sending out SOA"<<endl);
DNSZoneRecord soa = makeEditedDNSZRFromSOAData(dk, sd);
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())
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);
}
});
}
+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";
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();
}