Meerwald
Mekking
memlock
-MEMLOCK
Memusage
menuselection
metadatabase
tsigkey
tsigname
tsigsecret
+Tsinghua
tstamp
TSU
ttls
Xek
Xeon
XForwarded
+Xiang
xorbooter
xpf
XRecord
XXXXXX
yahttp
Yehuda
+yeswehack
Yiu
Ylitalo
yml
Yes We Hack
-----------
Security issues can also be reported on [our YesWeHack page](https://yeswehack.com/programs/powerdns) and might fetch a bounty.
-Do note that only the PowerDNS software (PowerDNS Authoritative Server, the PowerDNS Recursor and dnsdist) is in scope for the HackerOne program, not our websites or other infrastructure.
+Do note that only the PowerDNS software (PowerDNS Authoritative Server, the PowerDNS Recursor and dnsdist) is in scope for the YesWeHack program, not our websites or other infrastructure.
Disclosure Policy
-----------------
+++ /dev/null
-See /usr/share/doc/quilt/README.source
--- /dev/null
+#!/bin/bash
+
+if [ "$1" = "--cflags" ]; then
+ FLAGS=$(/usr/bin/net-snmp-config --cflags)
+ MYFLAGS=""
+ for flag in $FLAGS; do
+ if [[ "$flag" =~ -DNETSNMP* ]]; then
+ MYFLAGS="$MYFLAGS $flag"
+ fi
+ done
+ echo "$MYFLAGS"
+ exit 0
+
+elif [ "$1" = "--netsnmp-agent-libs" ]; then
+ /usr/bin/net-snmp-config "$@"
+ exit $?
+
+else
+ echo "E: debian/configure-helpers/net-snmp-config: unknown flag $1" >&2
+ exit 1
+fi
Source: pdns-recursor
Section: net
-Priority: extra
-Standards-Version: 4.1.2
-Maintainer: PowerDNS.COM BV <powerdns.support@powerdns.com>
+Maintainer: PowerDNS Autobuilder <powerdns.support@powerdns.com>
+Priority: optional
+Standards-Version: 4.5.1
+Build-Conflicts: libboost-context-dev [mips mipsel]
Build-Depends: debhelper (>= 10),
dh-autoreconf,
- libboost-all-dev,
+ libboost-context-dev [amd64 arm64 armel armhf i386 ppc64el],
+ libboost-dev,
+ libboost-program-options-dev,
+ libboost-system-dev,
+ libboost-test-dev,
+ libboost-thread-dev,
libcap-dev,
libcurl4-openssl-dev,
- libluajit-5.1-dev [!arm64 !s390x],
- liblua5.3-dev [arm64 s390x],
libfstrm-dev,
+ libluajit-5.1-dev (>= 2.1.0~beta3+dfsg-5.3) [amd64 arm64] | libluajit-5.1-dev [amd64] | liblua5.3-dev,
+ libprotobuf-dev,
libsnmp-dev,
libsodium-dev,
libssl-dev,
- libsystemd-dev [linux-any],
+ libsystemd-dev,
pkg-config,
+ protobuf-compiler,
ragel,
- systemd [linux-any]
-Vcs-Git: https://anonscm.debian.org/git/pkg-dns/pdns-recursor.git
-Vcs-Browser: https://anonscm.debian.org/cgit/pkg-dns/pdns-recursor.git
+ systemd
Homepage: https://www.powerdns.com/
+Rules-Requires-Root: no
Package: pdns-recursor
Architecture: any
+Pre-Depends: ${misc:Pre-Depends}
Depends: adduser,
dns-root-data,
${misc:Depends},
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: PowerDNS
Source: https://www.powerdns.com/downloads.html
+Upstream-Contact: https://mailman.powerdns.com/mailman/listinfo/pdns-users
Files: *
Copyright: 2002 - 2022 PowerDNS.COM BV and contributors
Copyright: 2002 - 2004 Wichert Akkermann <wichert@wiggy.net>
2004 - 2013 Matthijs Möhlmann <matthijs@cacholong.nl>
2012 - 2013 Marc Haber <mh+debian-packages@zugschlus.de>
- 2014 - 2016 Chris Hofstaedtler <zeha@debian.org>
- 2016 PowerDNS.COM BV and contributors
+ 2014 - 2018 Chris Hofstaedtler <zeha@debian.org>
+ 2016 - 2018 PowerDNS.COM BV and contributors
License: GPL-2
Files: ext/yahttp/*
+++ /dev/null
-# Variables for PowerDNS recursor init script.
-# Not honored when systemd is the running init.
-#
-# Set START to yes to start the pdns-recursor
-START=yes
-# Run resolvconf? (Deprecated feature.)
-RESOLVCONF=no
+++ /dev/null
-#!/bin/sh
-### BEGIN INIT INFO
-# Provides: pdns-recursor
-# Required-Start: $network $remote_fs $syslog
-# Required-Stop: $network $remote_fs $syslog
-# Default-Start: 2 3 4 5
-# Default-Stop: 0 1 6
-# Short-Description: PowerDNS Recursor - Recursive DNS Server
-# Description: PowerDNS Recursor - Recursive DNS Server
-### END INIT INFO
-
-#
-# Authors: Matthijs Möhlmann <matthijs@cacholong.nl>
-# Christoph Haas <haas@debian.org>
-#
-# Thanks to:
-# Thomas Hood <jdthood@aglu.demon.nl>
-#
-# initscript for PowerDNS recursor
-
-# Load lsb stuff for systemd redirection (if available).
-if [ -e /lib/lsb/init-functions ]; then
- . /lib/lsb/init-functions
-fi
-
-PATH=/sbin:/bin:/usr/sbin:/usr/bin
-DESC="PowerDNS Recursor"
-NAME=pdns_recursor
-DAEMON=/usr/sbin/$NAME
-# Derive the socket-dir setting from /etc/powerdns/recursor.conf
-# or fall back to the default /var/run if not specified there.
-PIDDIR=$(awk -F= '/^socket-dir=/ {print $2}' /etc/powerdns/recursor.conf)
-if [ -z "$PIDDIR" ]; then PIDDIR=/var/run/pdns-recursor; mkdir -p $PIDDIR; fi
-PIDFILE=$PIDDIR/$NAME.pid
-
-# Gracefully exit if the package has been removed.
-test -x $DAEMON || exit 0
-
-# Read config file if it is present.
-if [ -r /etc/default/pdns-recursor ]; then
- . /etc/default/pdns-recursor
-fi
-
-start() {
-# Return
-# 0 if daemon has been started / was already running
-# >0 if daemon could not be started
- start-stop-daemon --start --oknodo --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null || return 0
- start-stop-daemon --start --oknodo --quiet --pidfile $PIDFILE --exec $DAEMON -- --daemon=yes || return 2
-}
-
-start_resolvconf() {
- if [ "X$RESOLVCONF" = "Xyes" ] && [ -x /sbin/resolvconf ]; then
- echo "nameserver 127.0.0.1" | /sbin/resolvconf -a lo.pdns-recursor
- fi
- return 0
-}
-
-stop() {
-# Return
-# 0 if daemon has been stopped
-# 1 if daemon was already stopped
-# 2 if daemon could not be stopped
-# other if a failure occurred
- start-stop-daemon --stop --quiet --pidfile $PIDFILE --name $NAME
- RETVAL="$?"
- [ "$RETVAL" = 2 ] && return 2
- rm -f $PIDFILE
- return "$RETVAL"
-}
-
-stop_resolvconf() {
- if [ "X$RESOLVCONF" = "Xyes" ] && [ -x /sbin/resolvconf ]; then
- /sbin/resolvconf -d lo.pdns-recursor
- fi
- return 0
-}
-
-isrunning()
-{
- /usr/bin/rec_control ping > /dev/null
- return $?
-}
-
-case "$1" in
- start)
- if [ "$START" != "yes" ]; then
- echo "Not starting $DESC -- disabled."
- exit 0
- fi
- echo -n "Starting $DESC: $NAME ..."
- start
- case "$?" in
- 0)
- start_resolvconf
- echo done
- break
- ;;
- 1)
- echo "already running"
- break
- ;;
- *)
- echo "failed"
- exit 1
- ;;
- esac
- ;;
- stop)
- stop_resolvconf
- echo -n "Stopping $DESC: $NAME ..."
- stop
- case "$?" in
- 0)
- echo done
- break
- ;;
- 1)
- echo "not running"
- break
- ;;
- *)
- echo "failed"
- exit 1
- ;;
- esac
- ;;
- restart|force-reload)
- if [ "$START" != "yes" ]; then
- $0 stop
- exit 0
- fi
- echo -n "Restarting $DESC ..."
- stop
- case "$?" in
- 0|1)
- start
- case "$?" in
- 0)
- echo done
- exit 0
- ;;
- 1)
- echo "failed -- old process still running"
- exit 1
- ;;
- *)
- echo "failed to start"
- exit 1
- ;;
- esac
- ;;
- *)
- echo "failed to stop"
- exit 1
- ;;
- esac
- ;;
- status)
- if isrunning; then
- echo "$NAME is running"
- exit 0
- else
- echo "$NAME is not running or not responding"
- exit 3
- fi
- ;;
- *)
- echo "Usage: $0 {start|stop|restart|force-reload|status}" >&2
- exit 3
- ;;
-esac
-
-exit 0
-
# Source carries OpenSSL Exception
pdns-recursor: possible-gpl-code-linked-with-openssl
-# We load lsb-functions conditionally.
-pdns-recursor: init.d-script-needs-depends-on-lsb-base
case "$1" in
configure)
- if [ -z "`getent group pdns`" ]; then
- addgroup --system pdns
- fi
- if [ -z "`getent passwd pdns`" ]; then
- adduser --system --home /var/spool/powerdns --shell /bin/false --ingroup pdns --disabled-password --disabled-login --gecos "PowerDNS" pdns
- fi
- if [ "`stat -c '%U:%G' /etc/powerdns/recursor.conf`" = "root:root" ]; then
- chown root:pdns /etc/powerdns/recursor.conf
- # Make sure that pdns can read it; the default used to be 0600
- chmod g+r /etc/powerdns/recursor.conf
- fi
+ addgroup --system pdns
+ adduser --system --home /var/spool/powerdns --shell /bin/false --ingroup pdns --disabled-password --disabled-login --gecos "PowerDNS" pdns
;;
*)
;;
esac
-# Startup errors should never cause dpkg to fail.
-initscript_error() {
- return 0
-}
-
#DEBHELPER#
exit 0
--- /dev/null
+#!/bin/sh
+set -e
+
+delete_unchanged() {
+ if [ -e "$1" ] && echo "$2 $1" | md5sum --check --status; then
+ echo "Removing unchanged configuration file $1"
+ rm -f "$1"
+ fi
+}
+
+backup_conffile() {
+ if [ -e "$1" ]; then
+ echo "Moving configuration file $1 to $1.dpkg-bak"
+ mv -f "$1" "$1".dpkg-bak
+ fi
+}
+
+case "$1" in
+ install|upgrade)
+ # clean up files we no longer ship
+ delete_unchanged "/etc/default/pdns-recursor" a09916ceb17db9a49ac8cfa84790bf3b
+ delete_unchanged "/etc/default/pdns-recursor" 076b21b9b76d7ffecc918af47d2963c6
+ backup_conffile "/etc/default/pdns-recursor"
+ delete_unchanged "/etc/init.d/pdns-recursor" e2ea0586c3d99fdbafb76483a769b964
+ delete_unchanged "/etc/init.d/pdns-recursor" fb608ec5edc3d068213bac3480782355
+ backup_conffile "/etc/init.d/pdns-recursor"
+ ;;
+esac
+
+#DEBHELPER#
+++ /dev/null
-#!/bin/sh
-set -e
-
-# Startup errors should never cause dpkg to fail.
-initscript_error() {
- return 0
-}
-
-#DEBHELPER#
-
-exit 0
#!/usr/bin/make -f
-include /usr/share/dpkg/architecture.mk
-include /usr/share/dpkg/pkg-info.mk
-# Enable hardening features for daemons
+# Turn on all hardening flags, as we're a networked daemon.
# Note: blhc (build log hardening check) will find these false positives: CPPFLAGS 2 missing, LDFLAGS 1 missing
-export DEB_BUILD_MAINT_OPTIONS=hardening=+bindnow,+pie
+export DEB_BUILD_MAINT_OPTIONS = hardening=+all
+# see EXAMPLES in dpkg-buildflags(1) and read /usr/share/dpkg/*
DPKG_EXPORT_BUILDFLAGS = 1
-# Include buildflags.mk so we can append to the vars it sets.
-include /usr/share/dpkg/buildflags.mk
+include /usr/share/dpkg/default.mk
-# Only enable systemd integration on Linux operating systems
-ifeq ($(DEB_HOST_ARCH_OS),linux)
-CONFIGURE_ARGS += --enable-systemd --with-systemd=/lib/systemd/system
-DH_ARGS += --with systemd
-else
-CONFIGURE_ARGS += --disable-systemd
-endif
-
-# Only disable luajit on arm64
-ifneq ($(DEB_HOST_ARCH),arm64)
-CONFIGURE_ARGS += --with-lua=luajit
-else
-CONFIGURE_ARGS += --with-lua=lua5.3
-endif
-# Use new build system
%:
- dh $@ \
- --with autoreconf \
- $(DH_ARGS)
+ dh $@
+
+override_dh_auto_clean:
+ dh_auto_clean
+ rm -f dnslabeltext.cc
+ chmod +x mkpubsuffixcc || true
override_dh_auto_configure:
- dh_auto_configure -- \
+ PATH=debian/configure-helpers/:$$PATH dh_auto_configure -- \
--sysconfdir=/etc/powerdns \
+ --enable-systemd --with-systemd=/lib/systemd/system \
--enable-unit-tests \
- --with-libcap \
- --with-libsodium \
- --enable-dns-over-tls \
- --enable-dnstap \
- --with-net-snmp \
--disable-silent-rules \
--with-service-user=pdns \
--with-service-group=pdns \
- $(CONFIGURE_ARGS)
+ --with-libcap \
+ --with-libsodium \
+ --with-lua \
+ --with-net-snmp \
+ --enable-dns-over-tls \
+ --enable-dnstap
override_dh_auto_install:
dh_auto_install
install -d debian/pdns-recursor/usr/share/pdns-recursor/lua-config
install -m 644 -t debian/pdns-recursor/usr/share/pdns-recursor/lua-config debian/lua-config/rootkeys.lua
install -m 644 -t debian/pdns-recursor/etc/powerdns debian/recursor.lua
+ install -d debian/pdns-recursor/usr/share/pdns-recursor/snmp
+ install -m 644 -t debian/pdns-recursor/usr/share/pdns-recursor/snmp RECURSOR-MIB.txt
rm -f debian/pdns-recursor/etc/powerdns/recursor.conf-dist
- ./pdns_recursor --config=default | sed \
- -e 's!# config-dir=.*!config-dir=/etc/powerdns!' \
- -e 's!# include-dir=.*!&\ninclude-dir=/etc/powerdns/recursor.d!' \
- -e 's!# local-address=.*!local-address=127.0.0.1!' \
- -e 's!# lua-config-file=.*!lua-config-file=/etc/powerdns/recursor.lua!' \
- -e 's!# quiet=.*!quiet=yes!' \
- -e 's!# setgid=.*!setgid=pdns!' \
- -e 's!# setuid=.*!setuid=pdns!' \
- -e 's!# hint-file=.*!&\nhint-file=/usr/share/dns/root.hints!' \
+ ./pdns_recursor --no-config --config=default | sed \
+ -e 's!^# config-dir=.*!config-dir=/etc/powerdns!' \
+ -e 's!^# hint-file=.*!&\nhint-file=/usr/share/dns/root.hints!' \
+ -e 's!^# include-dir=.*!&\ninclude-dir=/etc/powerdns/recursor.d!' \
+ -e 's!^# local-address=.*!local-address=127.0.0.1!' \
+ -e 's!^# lua-config-file=.*!lua-config-file=/etc/powerdns/recursor.lua!' \
+ -e 's!^# quiet=.*!quiet=yes!' \
-e '/^# version-string=.*/d' \
> debian/pdns-recursor/etc/powerdns/recursor.conf
-override_dh_strip:
- dh_strip --ddeb-migration='pdns-recursor-dbg'
-
-override_dh_installinit:
- dh_installinit --error-handler=initscript_error
+override_dh_auto_test:
+ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS)))
+ dh_auto_test
+ -cat testrunner.log
+endif
override_dh_gencontrol:
dh_gencontrol -- $(SUBSTVARS)
-
-override_dh_fixperms:
- dh_fixperms
-# these files often contain passwords. 640 as it is chowned to root:pdns
- chmod 0640 debian/pdns-recursor/etc/powerdns/recursor.conf
-
-override_dh_builddeb:
- dh_builddeb -- -Zgzip
+++ /dev/null
-# Source is in html/js/d3.js
-pdns-recursor source: source-is-missing html/js/d3.v3.js line length is 32005 characters (>512)
Tests: smoke
-Depends: @, dnsutils
+Depends: dnsutils,
+ @
Restrictions: needs-root
exec 2>&1
set -ex
+restart_failed() {
+ echo E: service restart failed
+ journalctl -n200 --no-pager
+ exit 1
+}
+
cat <<EOF >>/etc/powerdns/recursor.conf
auth-zones=example.org=/etc/powerdns/example.org.zone
EOF
smoke.example.org. 172800 IN A 127.0.0.123
EOF
-service pdns-recursor restart
+service pdns-recursor restart || restart_failed
TMPFILE=$(mktemp)
cleanup() {
- rm -f "$TMPFILE"
+ rm -f "$TMPFILE"
}
trap cleanup EXIT
If you believe you have found a security vulnerability that applies to DNS implementations generally, and you want to report this responsibly to a number of implementers, you might consider also using the `Open Source DNS Vulnerability mailing list <https://www.dns-oarc.net/oarc/oss-dns-vulns/>`_, managed by `DNS-OARC <https://www.dns-oarc.net/>`_.
-HackerOne
+YesWeHack
^^^^^^^^^
-Security issues can also be reported on `our HackerOne page <https://hackerone.com/powerdns>`_ and might fetch a bounty.
-Do note that only the PowerDNS software is in scope for the HackerOne program, not our websites or other infrastructure.
+Security issues can also be reported on `our YesWeHack page <https://yeswehack.com/programs/powerdns>`_ and might fetch a bounty.
+Do note that only the PowerDNS software is in scope for the YesWeHack program, not our websites or other infrastructure.
Disclosure Policy
^^^^^^^^^^^^^^^^^
-@ 86400 IN SOA pdns-public-ns1.powerdns.com. peter\.van\.dijk.powerdns.com. 2023032101 10800 3600 604800 10800
+@ 86400 IN SOA pdns-public-ns1.powerdns.com. peter\.van\.dijk.powerdns.com. 2023033001 10800 3600 604800 10800
@ 3600 IN NS pdns-public-ns1.powerdns.com.
@ 3600 IN NS pdns-public-ns2.powerdns.com.
recursor-4.6.0.security-status 60 IN TXT "3 Upgrade now, see https://doc.powerdns.com/recursor/security-advisories/powerdns-advisory-2022-01.html"
recursor-4.6.1.security-status 60 IN TXT "3 Upgrade now, see https://doc.powerdns.com/recursor/security-advisories/powerdns-advisory-2022-02.html"
recursor-4.6.2.security-status 60 IN TXT "3 Upgrade now, see https://doc.powerdns.com/recursor/security-advisories/powerdns-advisory-2022-02.html"
-recursor-4.6.3.security-status 60 IN TXT "1 OK"
-recursor-4.6.4.security-status 60 IN TXT "1 OK"
-recursor-4.6.5.security-status 60 IN TXT "1 OK"
+recursor-4.6.3.security-status 60 IN TXT "3 Upgrade now, see https://doc.powerdns.com/recursor/security-advisories/powerdns-advisory-2023-02.html"
+recursor-4.6.4.security-status 60 IN TXT "3 Upgrade now, see https://doc.powerdns.com/recursor/security-advisories/powerdns-advisory-2023-02.html"
+recursor-4.6.5.security-status 60 IN TXT "3 Upgrade now, see https://doc.powerdns.com/recursor/security-advisories/powerdns-advisory-2023-02.html"
+recursor-4.6.6.security-status 60 IN TXT "1 OK"
recursor-4.7.0-alpha1.security-status 60 IN TXT "3 Unsupported pre-release (known vulnerabilities)"
recursor-4.7.0-beta1.security-status 60 IN TXT "3 Unsupported pre-release (known vulnerabilities)"
recursor-4.7.0-rc1.security-status 60 IN TXT "3 Unsupported pre-release (known vulnerabilities)"
recursor-4.7.0.security-status 60 IN TXT "3 Upgrade now, see https://doc.powerdns.com/recursor/security-advisories/powerdns-advisory-2022-02.html"
recursor-4.7.1.security-status 60 IN TXT "3 Upgrade now, see https://doc.powerdns.com/recursor/security-advisories/powerdns-advisory-2022-02.html"
-recursor-4.7.2.security-status 60 IN TXT "1 OK"
-recursor-4.7.3.security-status 60 IN TXT "1 OK"
-recursor-4.7.4.security-status 60 IN TXT "1 OK"
+recursor-4.7.2.security-status 60 IN TXT "3 Upgrade now, see https://doc.powerdns.com/recursor/security-advisories/powerdns-advisory-2023-02.html"
+recursor-4.7.3.security-status 60 IN TXT "3 Upgrade now, see https://doc.powerdns.com/recursor/security-advisories/powerdns-advisory-2023-02.html"
+recursor-4.7.4.security-status 60 IN TXT "3 Upgrade now, see https://doc.powerdns.com/recursor/security-advisories/powerdns-advisory-2023-02.html"
+recursor-4.7.5.security-status 60 IN TXT "1 OK"
recursor-4.8.0-alpha1.security-status 60 IN TXT "3 Unsupported pre-release (known vulnerabilities)"
recursor-4.8.0-beta1.security-status 60 IN TXT "3 Unsupported pre-release (known vulnerabilities)"
recursor-4.8.0-beta2.security-status 60 IN TXT "3 Unsupported pre-release (known vulnerabilities)"
recursor-4.8.0-rc1.security-status 60 IN TXT "3 Unsupported pre-release (known vulnerabilities)"
recursor-4.8.0.security-status 60 IN TXT "3 Upgrade now, see https://doc.powerdns.com/recursor/security-advisories/powerdns-advisory-2023-01.html"
-recursor-4.8.1.security-status 60 IN TXT "1 OK"
-recursor-4.8.2.security-status 60 IN TXT "1 OK"
-recursor-4.8.3.security-status 60 IN TXT "1 OK"
+recursor-4.8.1.security-status 60 IN TXT "3 Upgrade now, see https://doc.powerdns.com/recursor/security-advisories/powerdns-advisory-2023-02.html"
+recursor-4.8.2.security-status 60 IN TXT "3 Upgrade now, see https://doc.powerdns.com/recursor/security-advisories/powerdns-advisory-2023-02.html"
+recursor-4.8.3.security-status 60 IN TXT "3 Upgrade now, see https://doc.powerdns.com/recursor/security-advisories/powerdns-advisory-2023-02.html"
+recursor-4.8.4.security-status 60 IN TXT "1 OK"
; Recursor Debian
recursor-3.6.2-2.debian.security-status 60 IN TXT "3 Upgrade now, see https://doc.powerdns.com/3/security/powerdns-advisory-2015-01/ and https://doc.powerdns.com/3/security/powerdns-advisory-2016-02/"
dnsdist-1.7.3.security-status 60 IN TXT "1 OK"
dnsdist-1.8.0-rc1.security-status 60 IN TXT "2 Unsupported pre-release (no known vulnerabilities)"
dnsdist-1.8.0-rc2.security-status 60 IN TXT "2 Unsupported pre-release (no known vulnerabilities)"
-dnsdist-1.8.0-rc3.security-status 60 IN TXT "1 Unsupported pre-release"
+dnsdist-1.8.0-rc3.security-status 60 IN TXT "2 Unsupported pre-release (no known vulnerabilities)"
+dnsdist-1.8.0.security-status 60 IN TXT "1 OK"
}
if (d_dolog)
- g_log << Logger::Warning << "Query " << ((long)(void*)this) << ": " << d_dtime.udiffNoReset() << " usec to execute" << endl;
+ g_log << Logger::Warning << "Query " << ((long)(void*)this) << ": " << d_dtime.udiffNoReset() << " us to execute" << endl;
return this;
}
bool hasNextRow()
{
if (d_dolog && d_residx == d_resnum) {
- g_log << Logger::Warning << "Query " << ((long)(void*)this) << ": " << d_dtime.udiffNoReset() << " total usec to last row" << endl;
+ g_log << Logger::Warning << "Query " << ((long)(void*)this) << ": " << d_dtime.udiffNoReset() << " us total to last row" << endl;
}
return d_residx < d_resnum;
}
d_cur_set = 0;
if (d_dolog) {
auto diff = d_dtime.udiffNoReset();
- g_log << Logger::Warning << "Query " << ((long)(void*)this) << ": " << diff << " usec to execute" << endl;
+ g_log << Logger::Warning << "Query " << ((long)(void*)this) << ": " << diff << " us to execute" << endl;
}
nextResult();
bool hasNextRow()
{
if (d_dolog && d_residx == d_resnum) {
- g_log << Logger::Warning << "Query " << ((long)(void*)this) << ": " << d_dtime.udiff() << " total usec to last row" << endl;
+ g_log << Logger::Warning << "Query " << ((long)(void*)this) << ": " << d_dtime.udiff() << " us total to last row" << endl;
}
return d_residx < d_resnum;
if (d_getcursor->lower_bound(d_matchkey, key, val) || key.getNoStripHeader<StringView>().rfind(d_matchkey, 0) != 0) {
d_getcursor.reset();
if (d_dolog) {
- g_log << Logger::Warning << "Query " << ((long)(void*)this) << ": " << d_dtime.udiffNoReset() << " usec to execute (found nothing)" << endl;
+ g_log << Logger::Warning << "Query " << ((long)(void*)this) << ": " << d_dtime.udiffNoReset() << " us to execute (found nothing)" << endl;
}
return;
}
if (d_dolog) {
- g_log << Logger::Warning << "Query " << ((long)(void*)this) << ": " << d_dtime.udiffNoReset() << " usec to execute" << endl;
+ g_log << Logger::Warning << "Query " << ((long)(void*)this) << ": " << d_dtime.udiffNoReset() << " us to execute" << endl;
}
d_lookupdomain = hunt;
{
(*d_acc)(usec/1000.0);
// if(usec > 1000000)
- // cerr<<"Slow: "<<domain<<" ("<<usec/1000.0<<" msec)\n";
+ // cerr<<"Slow: "<<domain<<" ("<<usec/1000.0<<" ms)\n";
if(!g_quiet) {
- cout<<domain.name<<"|"<<DNSRecordContent::NumberToType(domain.type)<<": ("<<usec/1000.0<<"msec) rcode: "<<dr.rcode;
+ cout<<domain.name<<"|"<<DNSRecordContent::NumberToType(domain.type)<<": ("<<usec/1000.0<<" ms) rcode: "<<dr.rcode;
for(const ComboAddress& ca : dr.ips) {
cout<<", "<<ca.toString();
}
cerr<< datafmt % "Total " % (sr.d_oks + sr.d_errors + sr.d_nodatas + sr.d_nxdomains + sr.d_unknowns + inflighter.getTimeouts()) % "" % "";
cerr<<"\n";
- cerr<< "Mean response time: "<<mean(*sr.d_acc) << " msec"<<", median: "<<median(*sr.d_acc)<< " msec\n";
+ cerr<< "Mean response time: "<<mean(*sr.d_acc) << " ms"<<", median: "<<median(*sr.d_acc)<< " ms\n";
- boost::format statfmt("Time < %6.03f msec %|30t|%6.03f%% cumulative\n");
+ boost::format statfmt("Time < %6.03f ms %|30t|%6.03f%% cumulative\n");
for (unsigned int i = 0; i < sr.d_probs.size(); ++i) {
cerr << statfmt % extended_p_square(*sr.d_acc)[i] % (100*sr.d_probs[i]);
usleep(toSleepUSec);
}
else {
- vinfolog("Carbon export for %s took longer (%s usec) than the configured interval (%d usec)", endpoint.server.toStringWithPort(), elapsedUSec, intervalUSec);
+ vinfolog("Carbon export for %s took longer (%s us) than the configured interval (%d us)", endpoint.server.toStringWithPort(), elapsedUSec, intervalUSec);
}
consecutiveFailures = 0;
}
}
std::string toString() const override
{
- return "delay by "+std::to_string(d_msec)+ " msec";
+ return "delay by "+std::to_string(d_msec)+ " ms";
}
private:
int d_msec;
}
std::string toString() const override
{
- return "delay by "+std::to_string(d_msec)+ " msec";
+ return "delay by "+std::to_string(d_msec)+ " ms";
}
private:
int d_msec;
return;
}
- g_outputBuffer = (boost::format("Average response latency: %.02f msec\n") % (0.001*totlat/size)).str();
+ g_outputBuffer = (boost::format("Average response latency: %.02f ms\n") % (0.001*totlat/size)).str();
double highest=0;
for(auto iter = histo.cbegin(); iter != histo.cend(); ++iter) {
highest=std::max(highest, iter->second*1.0);
}
boost::format fmt("%7.2f\t%s\n");
- g_outputBuffer += (fmt % "msec" % "").str();
+ g_outputBuffer += (fmt % "ms" % "").str();
for(auto iter = histo.cbegin(); iter != histo.cend(); ++iter) {
int stars = (70.0 * iter->second/highest);
}
}
double udiff = sw.udiff();
- g_outputBuffer=(boost::format("Had %d matches out of %d, %.1f qps, in %.1f usec\n") % matches % times % (1000000*(1.0*times/udiff)) % udiff).str();
+ g_outputBuffer=(boost::format("Had %d matches out of %d, %.1f qps, in %.1f us\n") % matches % times % (1000000*(1.0*times/udiff)) % udiff).str();
});
if (currentResponse.d_idstate.selfGenerated == false && ds) {
const auto& ids = currentResponse.d_idstate;
double udiff = ids.queryRealTime.udiff();
- vinfolog("Got answer from %s, relayed to %s (%s, %d bytes), took %f usec", ds->d_config.remote.toStringWithPort(), ids.origRemote.toStringWithPort(), (state->d_handler.isTLS() ? "DoT" : "TCP"), currentResponse.d_buffer.size(), udiff);
+ vinfolog("Got answer from %s, relayed to %s (%s, %d bytes), took %f us", ds->d_config.remote.toStringWithPort(), ids.origRemote.toStringWithPort(), (state->d_handler.isTLS() ? "DoT" : "TCP"), currentResponse.d_buffer.size(), udiff);
auto backendProtocol = ds->getProtocol();
if (backendProtocol == dnsdist::Protocol::DoUDP) {
if (!selfGenerated) {
double udiff = ids.queryRealTime.udiff();
if (!muted) {
- vinfolog("Got answer from %s, relayed to %s (UDP), took %f usec", ds->d_config.remote.toStringWithPort(), ids.origRemote.toStringWithPort(), udiff);
+ vinfolog("Got answer from %s, relayed to %s (UDP), took %f us", ds->d_config.remote.toStringWithPort(), ids.origRemote.toStringWithPort(), udiff);
}
else {
- vinfolog("Got answer from %s, NOT relayed to %s (UDP) since that frontend is muted, took %f usec", ds->d_config.remote.toStringWithPort(), ids.origRemote.toStringWithPort(), udiff);
+ vinfolog("Got answer from %s, NOT relayed to %s (UDP) since that frontend is muted, took %f us", ds->d_config.remote.toStringWithPort(), ids.origRemote.toStringWithPort(), udiff);
}
handleResponseSent(ids, udiff, dr.ids.origRemote, ds->d_config.remote, response.size(), cleartextDH, ds->getProtocol(), true);
Changelog
=========
+.. changelog::
+ :version: 1.8.0
+ :released: 30th of March 2023
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 12687
+
+ Fix 'Unknown key' issue for actions and rules parameters
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 12672
+
+ Fix a dnsheader unaligned case
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 12654
+
+ secpoll: explicitly include necessary ctime header for time_t
+
.. changelog::
:version: 1.8.0-rc3
:released: 16th of March 2023
- Release date
- Security-Only updates
- End of Life
+ * - 1.8
+ - March 30 2023
+ -
+ -
* - 1.7
- January 17 2022
- -
+ - March 30 2023
-
* - 1.6
- May 11 2021
- -
+ - March 30 2023
-
* - 1.5
- July 30 2020
- January 17 2022
- -
+ - EOL (March 30 2023)
* - 1.4
- November 20 2019
- May 2021
if (!du->ids.selfGenerated) {
double udiff = du->ids.queryRealTime.udiff();
- vinfolog("Got answer from %s, relayed to %s (https), took %f usec", du->downstream->d_config.remote.toStringWithPort(), du->ids.origRemote.toStringWithPort(), udiff);
+ vinfolog("Got answer from %s, relayed to %s (https), took %f us", du->downstream->d_config.remote.toStringWithPort(), du->ids.origRemote.toStringWithPort(), udiff);
auto backendProtocol = du->downstream->getProtocol();
if (backendProtocol == dnsdist::Protocol::DoUDP && du->tcp) {
du = std::move(dr.ids.du);
double udiff = du->ids.queryRealTime.udiff();
- vinfolog("Got answer from %s, relayed to %s (https), took %f usec", du->downstream->d_config.remote.toStringWithPort(), du->ids.origRemote.toStringWithPort(), udiff);
+ vinfolog("Got answer from %s, relayed to %s (https), took %f us", du->downstream->d_config.remote.toStringWithPort(), du->ids.origRemote.toStringWithPort(), udiff);
handleResponseSent(du->ids, udiff, dr.ids.origRemote, du->downstream->d_config.remote, du->response.size(), cleartextDH, du->downstream->getProtocol(), true);
cout.precision(2);
for(unsigned int i =0 ; i < sizeof(limits)/sizeof(limits[0]); ++i) {
if(limits[i]!=flightTimes.size())
- cout<<"Within "<<limits[i]<<" msec: ";
+ cout<<"Within "<<limits[i]<<" ms: ";
else
- cout<<"Beyond "<<limits[i]-2<<" msec: ";
+ cout<<"Beyond "<<limits[i]-2<<" ms: ";
uint64_t here = countLessThan(limits[i]);
cout<<100.0*here/totals<<"% ("<<100.0*(here-sofar)/totals<<"%)"<<endl;
sofar=here;
perc=sum*100.0/totpairs;
if(j->first < 1024)
- cout<< perc <<"% of questions answered within " << j->first << " usec (";
+ cout<< perc <<"% of questions answered within " << j->first << " us (";
else
- cout<< perc <<"% of questions answered within " << j->first/1000.0 << " msec (";
+ cout<< perc <<"% of questions answered within " << j->first/1000.0 << " ms (";
cout<<perc-lastperc<<"%)\n";
lastperc=sum*100.0/totpairs;
if(!j->second) {
perc=sum*100.0/totpairs;
if(j->first < 1024)
- cout<< perc <<"% of questions answered within " << j->first << " usec (";
+ cout<< perc <<"% of questions answered within " << j->first << " us (";
else
- cout<< perc <<"% of questions answered within " << j->first/1000.0 << " msec (";
+ cout<< perc <<"% of questions answered within " << j->first/1000.0 << " ms (";
cout<<perc-lastperc<<"%)\n";
lastperc=sum*100.0/totpairs;
cout<< (totpairs-lastsum)<<" responses ("<<((totpairs-lastsum)*100.0/answers) <<"%) older than "<< (done.rbegin()->first/1000000.0) <<" seconds"<<endl;
if(totpairs)
- cout<<"Average non-late response time: "<<tottime/totpairs<<" usec"<<endl;
+ cout<<"Average non-late response time: "<<tottime/totpairs<<" us"<<endl;
if(!g_vm["load-stats"].as<string>().empty()) {
ofstream load(g_vm["load-stats"].as<string>().c_str());
if(verified) {
udiffVerify = dt.udiff() / 100;
- cout<<"Signature & verify ok, create "<<udiffCreate<<"usec, signature "<<udiffSign<<"usec, verify "<<udiffVerify<<"usec"<<endl;
+ cout<<"Signature & verify ok, create "<<udiffCreate<<"us, signature "<<udiffSign<<"us, verify "<<udiffVerify<<"us"<<endl;
}
else {
throw runtime_error("Verification of creator "+dckeCreate->getName()+" with signer "+dckeSign->getName()+" and verifier "+dckeVerify->getName()+" failed");
if(g_verbose) {
cout<<"Sending queries to: "<<g_dest.toStringWithPort()<<endl;
cout<<"Attempting UDP first: " << (g_onlyTCP ? "no" : "yes") <<endl;
- cout<<"Timeout: "<< g_timeoutMsec<<"msec"<<endl;
+ cout<<"Timeout: "<< g_timeoutMsec<<" ms"<<endl;
cout << "Using TCP_NODELAY: "<<g_tcpNoDelay<<endl;
}
}
cout<<"Average qps: "<<mean(qps)<<", median qps: "<<median(qps)<<endl;
- cout<<"Average UDP latency: "<<mean(udpspeeds)<<"usec, median: "<<median(udpspeeds)<<"usec"<<endl;
- cout<<"Average TCP latency: "<<mean(tcpspeeds)<<"usec, median: "<<median(tcpspeeds)<<"usec"<<endl;
+ cout<<"Average UDP latency: "<<mean(udpspeeds)<<" us, median: "<<median(udpspeeds)<<" us"<<endl;
+ cout<<"Average TCP latency: "<<mean(tcpspeeds)<<" us, median: "<<median(tcpspeeds)<<" us"<<endl;
cout<<"OK: "<<g_OK<<", network errors: "<<g_networkErrors<<", other errors: "<<g_otherErrors<<endl;
cout<<"Timeouts: "<<g_timeOuts<<endl;
}
else if (cmds.at(0) == "clear-zone") {
if(cmds.size() != 2) {
- cerr<<"Syntax: pdnsutil edit-zone ZONE"<<endl;
+ cerr<<"Syntax: pdnsutil clear-zone ZONE"<<endl;
return 0;
}
if (cmds.at(1) == ".")
Changelogs for 4.6.X
====================
+.. changelog::
+ :version: 4.6.6
+ :released: 29th of March 2023
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 12702
+
+ PowerDNS Security Advisory 2023-02: Deterred spoofing attempts can lead to authoritative servers being marked unavailable.
+
.. changelog::
:version: 4.6.5
:released: 25th of November 2022
Changelogs for 4.7.X
====================
+.. changelog::
+ :version: 4.7.5
+ :released: 29th of March 2023
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 12701
+
+ PowerDNS Security Advisory 2023-02: Deterred spoofing attempts can lead to authoritative servers being marked unavailable.
+
.. changelog::
:version: 4.7.4
:released: 25th of November 2022
Changelogs for 4.8.X
====================
+.. changelog::
+ :version: 4.8.4
+ :released: 29th of March 2023
+
+ .. change::
+ :tags: Bug Fixes
+ :pullreq: 12700
+
+ PowerDNS Security Advisory 2023-02: Deterred spoofing attempts can lead to authoritative servers being marked unavailable.
+
.. changelog::
:version: 4.8.3
:released: 7th of March 2023
Sample Linux command lines would be::
## IPv4
+ ## NOTRACK rules for 53/udp, keep in mind that you also need your regular rules for 53/tcp
iptables -t raw -I OUTPUT -p udp --dport 53 -j CT --notrack
iptables -t raw -I OUTPUT -p udp --sport 53 -j CT --notrack
iptables -t raw -I PREROUTING -p udp --dport 53 -j CT --notrack
iptables -I OUTPUT -p udp --sport 53 -j ACCEPT
## IPv6
+ ## NOTRACK rules for 53/udp, keep in mind that you also need your regular rules for 53/tcp
ip6tables -t raw -I OUTPUT -p udp --dport 53 -j CT --notrack
ip6tables -t raw -I OUTPUT -p udp --sport 53 -j CT --notrack
ip6tables -t raw -I PREROUTING -p udp --sport 53 -j CT --notrack
The settings can be made permanent by using the ``--permanent`` flag::
## IPv4
+ ## NOTRACK rules for 53/udp, keep in mind that you also need your regular rules for 53/tcp
firewall-cmd --direct --add-rule ipv4 raw OUTPUT 0 -p udp --dport 53 -j CT --notrack
firewall-cmd --direct --add-rule ipv4 raw OUTPUT 0 -p udp --sport 53 -j CT --notrack
firewall-cmd --direct --add-rule ipv4 raw PREROUTING 0 -p udp --dport 53 -j CT --notrack
firewall-cmd --direct --add-rule ipv4 filter OUTPUT 0 -p udp --sport 53 -j ACCEPT
## IPv6
+ ## NOTRACK rules for 53/udp, keep in mind that you also need your regular rules for 53/tcp
firewall-cmd --direct --add-rule ipv6 raw OUTPUT 0 -p udp --dport 53 -j CT --notrack
firewall-cmd --direct --add-rule ipv6 raw OUTPUT 0 -p udp --sport 53 -j CT --notrack
firewall-cmd --direct --add-rule ipv6 raw PREROUTING 0 -p udp --dport 53 -j CT --notrack
--- /dev/null
+PowerDNS Security Advisory 2023-02: Deterred spoofing attempts can lead to authoritative servers being marked unavailable
+=========================================================================================================================
+
+- CVE: CVE-2023-26437
+- Date: 29th of March 2023
+- Affects: PowerDNS Recursor up to and including 4.6.5, 4.7.4 and 4.8.3
+- Not affected: PowerDNS Recursor 4.6.6, 4.7.5 and 4.8.4
+- Severity: Low
+- Impact: Denial of service
+- Exploit: Successful spoofing may lead to authoritative servers being marked unavailable
+- Risk of system compromise: None
+- Solution: Upgrade to patched version
+
+When the recursor detects and deters a spoofing attempt or receives certain malformed DNS packets,
+it throttles the server that was the target of the impersonation attempt so that other authoritative
+servers for the same zone will be more likely to be used in the future, in case the attacker
+controls the path to one server only. Unfortunately this mechanism can be used by an attacker with
+the ability to send queries to the recursor, guess the correct source port of the corresponding
+outgoing query and inject packets with a spoofed IP address to force the recursor to mark specific
+authoritative servers as not available, leading a denial of service for the zones served by those
+servers.
+
+CVSS 3.0 score: 3.7 (Low)
+https://www.first.org/cvss/calculator/3.0#CVSS:3.0/AV:N/AC:H/PR:N/UI:R/S:C/C:N/I:N/A:L
+
+Thanks to Xiang Li from Network and Information Security Laboratory, Tsinghua University for reporting this issue.
+
+
static void handleUDPServerResponse(int fd, FDMultiplexer::funcparam_t& var)
{
std::shared_ptr<PacketID> pid = boost::any_cast<std::shared_ptr<PacketID>>(var);
- ssize_t len;
PacketBuffer packet;
packet.resize(g_outgoingEDNSBufsize);
ComboAddress fromaddr;
socklen_t addrlen = sizeof(fromaddr);
- len = recvfrom(fd, &packet.at(0), packet.size(), 0, (sockaddr*)&fromaddr, &addrlen);
+ ssize_t len = recvfrom(fd, &packet.at(0), packet.size(), 0, reinterpret_cast<sockaddr*>(&fromaddr), &addrlen);
- if (len < (ssize_t)sizeof(dnsheader)) {
- if (len < 0)
- ; // cerr<<"Error on fd "<<fd<<": "<<stringerror()<<"\n";
- else {
- t_Counters.at(rec::Counter::serverParseError)++;
- if (g_logCommonErrors)
- SLOG(g_log << Logger::Error << "Unable to parse packet from remote UDP server " << fromaddr.toString() << ": packet smaller than DNS header" << endl,
- g_slogout->info(Logr::Error, "Unable to parse packet from remote UDP server", "from", Logging::Loggable(fromaddr)));
- }
+ const ssize_t signed_sizeof_sdnsheader = sizeof(dnsheader);
+ if (len < 0) {
+ // len < 0: error on socket
t_udpclientsocks->returnSocket(fd);
- PacketBuffer empty;
+ PacketBuffer empty;
MT_t::waiters_t::iterator iter = MT->d_waiters.find(pid);
- if (iter != MT->d_waiters.end())
+ if (iter != MT->d_waiters.end()) {
doResends(iter, pid, empty);
+ }
+ MT->sendEvent(pid, &empty); // this denotes error (does retry lookup using other NS)
+ return;
+ }
- MT->sendEvent(pid, &empty); // this denotes error (does lookup again.. at least L1 will be hot)
+ if (len < signed_sizeof_sdnsheader) {
+ // We have received a packet that cannot be a valid DNS packet, as it has no complete header
+ // Drop it, but continue to wait for other packets
+ t_Counters.at(rec::Counter::serverParseError)++;
+ if (g_logCommonErrors) {
+ SLOG(g_log << Logger::Error << "Unable to parse too short packet from remote UDP server " << fromaddr.toString() << ": packet smaller than DNS header" << endl,
+ g_slogout->info(Logr::Error, "Unable to parse too short packet from remote UDP server", "from", Logging::Loggable(fromaddr)));
+ }
return;
}
+ // We have at least a full header
packet.resize(len);
dnsheader dh;
memcpy(&dh, &packet.at(0), sizeof(dh));
}
else {
try {
- if (len > 12)
- pident->domain = DNSName(reinterpret_cast<const char*>(packet.data()), len, 12, false, &pident->type); // don't copy this from above - we need to do the actual read
+ if (len > signed_sizeof_sdnsheader) {
+ pident->domain = DNSName(reinterpret_cast<const char*>(packet.data()), len, static_cast<int>(sizeof(dnsheader)), false, &pident->type); // don't copy this from above - we need to do the actual read
+ }
+ else {
+ // len == sizeof(dnsheader), only header case
+ // We will do a full scan search later to see if we can match this reply even without a domain
+ pident->domain.clear();
+ pident->type = 0;
+ }
}
catch (std::exception& e) {
+ // Parse error, continue waiting for other packets
t_Counters.at(rec::Counter::serverParseError)++; // won't be fed to lwres.cc, so we have to increment
SLOG(g_log << Logger::Warning << "Error in packet from remote nameserver " << fromaddr.toStringWithPort() << ": " << e.what() << endl,
g_slogudpin->error(Logr::Warning, e.what(), "Error in packet from remote nameserver", "from", Logging::Loggable(fromaddr)));
}
}
- MT_t::waiters_t::iterator iter = MT->d_waiters.find(pident);
- if (iter != MT->d_waiters.end()) {
- doResends(iter, pident, packet);
+ if (!pident->domain.empty()) {
+ MT_t::waiters_t::iterator iter = MT->d_waiters.find(pident);
+ if (iter != MT->d_waiters.end()) {
+ doResends(iter, pident, packet);
+ }
}
retryWithName:
- if (!MT->sendEvent(pident, &packet)) {
+ if (pident->domain.empty() || MT->sendEvent(pident, &packet) == 0) {
/* we did not find a match for this response, something is wrong */
// we do a full scan for outstanding queries on unexpected answers. not too bad since we only accept them on the right port number, which is hard enough to guess
#include "config.h"
#endif
+#include "arguments.hh"
#include "syncres.hh"
#include "reczones-helpers.hh"
+#include "root-addresses.hh"
+#include "zoneparser-tng.hh"
+
+static void putIntoCache(time_t now, QType qtype, vState state, const ComboAddress& from, const set<DNSName>& seen, const std::multimap<DNSName, DNSRecord>& allRecords)
+{
+ for (const auto& name : seen) {
+ auto records = allRecords.equal_range(name);
+ vector<DNSRecord> aset;
+ for (auto elem = records.first; elem != records.second; ++elem) {
+ aset.emplace_back(elem->second);
+ }
+ // Put non-default root hints into cache as authoritative. As argued below in
+ // putDefaultHintsIntoCache, this is actually wrong, but people might depend on it by having
+ // root-hints that refer to servers that aren't actually capable or willing to serve root data.
+ g_recCache->replace(now, name, qtype, aset, {}, {}, true, g_rootdnsname, boost::none, boost::none, state, from);
+ }
+}
+
+static void parseHintFile(time_t now, const std::string& hintfile, set<DNSName>& seenA, set<DNSName>& seenAAAA, set<DNSName>& seenNS, std::multimap<DNSName, DNSRecord>& aRecords, std::multimap<DNSName, DNSRecord>& aaaaRecords, vector<DNSRecord>& nsvec)
+{
+ ZoneParserTNG zpt(hintfile);
+ zpt.setMaxGenerateSteps(::arg().asNum("max-generate-steps"));
+ zpt.setMaxIncludes(::arg().asNum("max-include-depth"));
+ DNSResourceRecord rrecord;
+
+ while (zpt.get(rrecord)) {
+ rrecord.ttl += now;
+ switch (rrecord.qtype) {
+ case QType::A:
+ seenA.insert(rrecord.qname);
+ aRecords.emplace(rrecord.qname, DNSRecord(rrecord));
+ break;
+ case QType::AAAA:
+ seenAAAA.insert(rrecord.qname);
+ aaaaRecords.emplace(rrecord.qname, DNSRecord(rrecord));
+ break;
+ case QType::NS:
+ seenNS.emplace(rrecord.content);
+ rrecord.content = toLower(rrecord.content);
+ nsvec.emplace_back(rrecord);
+ break;
+ }
+ }
+}
+
+static bool determineReachable(const set<DNSName>& names, const set<DNSName>& nameservers)
+{
+ bool reachable = false;
+ for (auto const& record : names) {
+ if (nameservers.count(record) != 0) {
+ reachable = true;
+ break;
+ }
+ }
+ return reachable;
+}
+
+bool readHintsIntoCache(time_t now, const std::string& hintfile, std::vector<DNSRecord>& nsvec)
+{
+ const ComboAddress from("255.255.255.255");
+ set<DNSName> seenNS;
+ set<DNSName> seenA;
+ set<DNSName> seenAAAA;
+
+ std::multimap<DNSName, DNSRecord> aRecords;
+ std::multimap<DNSName, DNSRecord> aaaaRecords;
+
+ parseHintFile(now, hintfile, seenA, seenAAAA, seenNS, aRecords, aaaaRecords, nsvec);
+
+ putIntoCache(now, QType::A, vState::Insecure, from, seenA, aRecords);
+ putIntoCache(now, QType::AAAA, vState::Insecure, from, seenAAAA, aaaaRecords);
+
+ bool reachableA = determineReachable(seenA, seenNS);
+ bool reachableAAAA = determineReachable(seenAAAA, seenNS);
+
+ auto log = g_slog->withName("config");
+ if (SyncRes::s_doIPv4 && !SyncRes::s_doIPv6 && !reachableA) {
+ SLOG(g_log << Logger::Error << "Running IPv4 only but no IPv4 root hints" << endl,
+ log->info(Logr::Error, "Running IPv4 only but no IPv4 root hints"));
+ return false;
+ }
+ if (!SyncRes::s_doIPv4 && SyncRes::s_doIPv6 && !reachableAAAA) {
+ SLOG(g_log << Logger::Error << "Running IPv6 only but no IPv6 root hints" << endl,
+ log->info(Logr::Error, "Running IPv6 only but no IPv6 root hints"));
+ return false;
+ }
+ if (SyncRes::s_doIPv4 && SyncRes::s_doIPv6 && !reachableA && !reachableAAAA) {
+ SLOG(g_log << Logger::Error << "No valid root hints" << endl,
+ log->info(Logr::Error, "No valid root hints"));
+ return false;
+ }
+ return true;
+}
+
+void putDefaultHintsIntoCache(time_t now, std::vector<DNSRecord>& nsvec)
+{
+ const ComboAddress from("255.255.255.255");
+
+ DNSRecord arr;
+ DNSRecord aaaarr;
+ DNSRecord nsrr;
+
+ nsrr.d_name = g_rootdnsname;
+ arr.d_type = QType::A;
+ aaaarr.d_type = QType::AAAA;
+ nsrr.d_type = QType::NS;
+ arr.d_ttl = aaaarr.d_ttl = nsrr.d_ttl = now + 3600000;
+
+ string templ = "a.root-servers.net.";
+
+ static_assert(rootIps4.size() == rootIps6.size());
+
+ for (size_t letter = 0; letter < rootIps4.size(); ++letter) {
+ templ.at(0) = static_cast<char>(letter + 'a');
+ aaaarr.d_name = arr.d_name = DNSName(templ);
+ nsrr.setContent(std::make_shared<NSRecordContent>(DNSName(templ)));
+ nsvec.push_back(nsrr);
+
+ if (!rootIps4.at(letter).empty()) {
+ arr.setContent(std::make_shared<ARecordContent>(ComboAddress(rootIps4.at(letter))));
+ /*
+ * Originally the hint records were inserted with the auth flag set, with the consequence that
+ * data from AUTHORITY and ADDITIONAL sections (as seen in a . NS response) were not used. This
+ * (together with the long ttl) caused outdated hint to be kept in cache. So insert as non-auth,
+ * and the extra sections in the . NS refreshing cause the cached records to be updated with
+ * up-to-date information received from a real root server.
+ *
+ * Note that if a user query is done for one of the root-server.net names, it will be inserted
+ * into the cache with the auth bit set. Further NS refreshes will not update that entry. If all
+ * root names are queried at the same time by a user, all root-server.net names will be marked
+ * auth and will expire at the same time. A re-prime is then triggered, as before, when the
+ * records were inserted with the auth bit set and the TTD comes.
+ */
+ g_recCache->replace(now, DNSName(templ), QType::A, {arr}, {}, {}, false, g_rootdnsname, boost::none, boost::none, vState::Insecure, from);
+ }
+ if (!rootIps6.at(letter).empty()) {
+ aaaarr.setContent(std::make_shared<AAAARecordContent>(ComboAddress(rootIps6.at(letter))));
+ g_recCache->replace(now, DNSName(templ), QType::AAAA, {aaaarr}, {}, {}, false, g_rootdnsname, boost::none, boost::none, vState::Insecure, from);
+ }
+ }
+}
template <typename T>
static SyncRes::AuthDomain makeSOAAndNSNodes(DNSRecord& dr, T content)
#include "syncres.hh"
#include "logger.hh"
+bool readHintsIntoCache(time_t now, const std::string& hintfile, std::vector<DNSRecord>& nsvec);
+void putDefaultHintsIntoCache(time_t now, std::vector<DNSRecord>& nsvec);
+
void makeIPToNamesZone(const std::shared_ptr<SyncRes::domainmap_t>& newMap,
const vector<string>& parts,
Logr::log_t log);
#endif
#include "reczones-helpers.hh"
-#include "syncres.hh"
#include "arguments.hh"
-#include "zoneparser-tng.hh"
-#include "logger.hh"
#include "dnsrecords.hh"
-#include "root-addresses.hh"
+#include "logger.hh"
+#include "syncres.hh"
+#include "zoneparser-tng.hh"
extern int g_argc;
extern char** g_argv;
-bool primeHints(time_t ignored)
+bool primeHints(time_t now)
{
- // prime root cache
- const vState validationState = vState::Insecure;
- const ComboAddress from("255.255.255.255");
- vector<DNSRecord> nsset;
-
- time_t now = time(nullptr);
-
- auto log = g_slog->withName("config");
const string hintfile = ::arg()["hint-file"];
+ vector<DNSRecord> nsvec;
+ bool ret = true;
+
if (hintfile == "no") {
+ auto log = g_slog->withName("config");
SLOG(g_log << Logger::Debug << "Priming root disabled by hint-file=no" << endl,
log->info(Logr::Debug, "Priming root disabled by hint-file=no"));
- return true;
+ return ret;
}
- if (hintfile.empty()) {
- DNSRecord arr, aaaarr, nsrr;
- nsrr.d_name = g_rootdnsname;
- arr.d_type = QType::A;
- aaaarr.d_type = QType::AAAA;
- nsrr.d_type = QType::NS;
-
- arr.d_ttl = aaaarr.d_ttl = nsrr.d_ttl = now + 3600000;
-
- for (char c = 'a'; c <= 'm'; ++c) {
- char templ[40];
- strncpy(templ, "a.root-servers.net.", sizeof(templ) - 1);
- templ[sizeof(templ) - 1] = '\0';
- *templ = c;
- aaaarr.d_name = arr.d_name = DNSName(templ);
- nsrr.setContent(std::make_shared<NSRecordContent>(DNSName(templ)));
- arr.setContent(std::make_shared<ARecordContent>(ComboAddress(rootIps4[c - 'a'])));
- vector<DNSRecord> aset;
- aset.push_back(arr);
- /*
- * Originally the hint records were inserted with the auth flag set, with the consequence that data from AUTHORITY and
- * ADDITIONAL sections (as seen in a . NS response) were not used. This (together with the long ttl) caused outdated
- * hint to be kept in cache. So insert as non-auth, and the extra sections in the . NS refreshing cause the cached
- * records to be updated with up-to-date information received from a real root server.
- *
- * Note that if a user query is done for one of the root-server.net names, it will be inserted into the cache with the
- * auth bit set. Further NS refreshes will not update that entry. If all root names are queried at the same time by a user,
- * all root-server.net names will be marked auth and will expire at the same time. A re-prime is then triggered,
- * as before, when the records were inserted with the auth bit set and the TTD comes.
- */
- g_recCache->replace(now, DNSName(templ), QType(QType::A), aset, vector<std::shared_ptr<const RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), false, g_rootdnsname, boost::none, boost::none, validationState, from); // auth, nuke it all
- if (rootIps6[c - 'a'] != NULL) {
- aaaarr.setContent(std::make_shared<AAAARecordContent>(ComboAddress(rootIps6[c - 'a'])));
-
- vector<DNSRecord> aaaaset;
- aaaaset.push_back(aaaarr);
- g_recCache->replace(now, DNSName(templ), QType(QType::AAAA), aaaaset, vector<std::shared_ptr<const RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), false, g_rootdnsname, boost::none, boost::none, validationState, from);
- }
- nsset.push_back(nsrr);
- }
+ if (hintfile.empty()) {
+ putDefaultHintsIntoCache(now, nsvec);
}
else {
- ZoneParserTNG zpt(hintfile);
- zpt.setMaxGenerateSteps(::arg().asNum("max-generate-steps"));
- zpt.setMaxIncludes(::arg().asNum("max-include-depth"));
- DNSResourceRecord rr;
- set<DNSName> seenNS;
- set<DNSName> seenA;
- set<DNSName> seenAAAA;
-
- while (zpt.get(rr)) {
- rr.ttl += now;
- if (rr.qtype.getCode() == QType::A) {
- seenA.insert(rr.qname);
- vector<DNSRecord> aset;
- aset.push_back(DNSRecord(rr));
- g_recCache->replace(now, rr.qname, QType(QType::A), aset, vector<std::shared_ptr<const RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), true, g_rootdnsname, boost::none, boost::none, validationState, from); // auth, etc see above
- }
- else if (rr.qtype.getCode() == QType::AAAA) {
- seenAAAA.insert(rr.qname);
- vector<DNSRecord> aaaaset;
- aaaaset.push_back(DNSRecord(rr));
- g_recCache->replace(now, rr.qname, QType(QType::AAAA), aaaaset, vector<std::shared_ptr<const RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), true, g_rootdnsname, boost::none, boost::none, validationState, from);
- }
- else if (rr.qtype.getCode() == QType::NS) {
- seenNS.insert(DNSName(rr.content));
- rr.content = toLower(rr.content);
- nsset.push_back(DNSRecord(rr));
- }
- }
-
- // Check reachability of A and AAAA records
- bool reachableA = false, reachableAAAA = false;
- for (auto const& r : seenA) {
- if (seenNS.count(r)) {
- reachableA = true;
- break;
- }
- }
- for (auto const& r : seenAAAA) {
- if (seenNS.count(r)) {
- reachableAAAA = true;
- break;
- }
- }
- if (SyncRes::s_doIPv4 && !SyncRes::s_doIPv6 && !reachableA) {
- SLOG(g_log << Logger::Error << "Running IPv4 only but no IPv4 root hints" << endl,
- log->info(Logr::Error, "Running IPv4 only but no IPv4 root hints"));
- return false;
- }
- if (!SyncRes::s_doIPv4 && SyncRes::s_doIPv6 && !reachableAAAA) {
- SLOG(g_log << Logger::Error << "Running IPv6 only but no IPv6 root hints" << endl,
- log->info(Logr::Error, "Running IPv6 only but no IPv6 root hints"));
- return false;
- }
- if (SyncRes::s_doIPv4 && SyncRes::s_doIPv6 && !reachableA && !reachableAAAA) {
- SLOG(g_log << Logger::Error << "No valid root hints" << endl,
- log->info(Logr::Error, "No valid root hints"));
- return false;
- }
+ ret = readHintsIntoCache(now, hintfile, nsvec);
}
g_recCache->doWipeCache(g_rootdnsname, false, QType::NS);
- g_recCache->replace(now, g_rootdnsname, QType(QType::NS), nsset, vector<std::shared_ptr<const RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), false, g_rootdnsname, boost::none, boost::none, validationState, from); // and stuff in the cache
- return true;
+ g_recCache->replace(now, g_rootdnsname, QType::NS, nsvec, {}, {}, false, g_rootdnsname, boost::none, boost::none, vState::Insecure, ComboAddress("255.255.255.255")); // and stuff in the cache
+ return ret;
}
static void convertServersForAD(const std::string& zone, const std::string& input, SyncRes::AuthDomain& ad, const char* sepa, Logr::log_t log, bool verbose = true)
*/
#pragma once
-static const char* const rootIps4[] = {
+#include <array>
+#include <string>
+
+const std::array<const std::string, 13> rootIps4 = {
"198.41.0.4", // a.root-servers.net.
"199.9.14.201", // b.root-servers.net.
"192.33.4.12", // c.root-servers.net.
"199.7.83.42", // l.root-servers.net.
"202.12.27.33" // m.root-servers.net.
};
-static size_t const rootIps4Count = sizeof(rootIps4) / sizeof(*rootIps4);
-static const char* const rootIps6[] = {
+const std::array<const std::string, 13> rootIps6 = {
"2001:503:ba3e::2:30", // a.root-servers.net.
"2001:500:200::b", // b.root-servers.net.
"2001:500:2::c", // c.root-servers.net.
"2001:500:9f::42", // l.root-servers.net.
"2001:dc3::35" // m.root-servers.net.
};
-static size_t const rootIps6Count = sizeof(rootIps6) / sizeof(*rootIps6);
if (s_addExtendedResolutionDNSErrors) {
extendedError = EDNSExtendedError{static_cast<uint16_t>(EDNSExtendedError::code::NoReachableAuthority), "Timeout waiting for answer(s)"};
}
- throw ImmediateServFailException("Too much time waiting for " + qname.toLogString() + "|" + qtype.toString() + ", timeouts: " + std::to_string(d_timeouts) + ", throttles: " + std::to_string(d_throttledqueries) + ", queries: " + std::to_string(d_outqueries) + ", " + std::to_string(d_totUsec / 1000) + "msec");
+ throw ImmediateServFailException("Too much time waiting for " + qname.toLogString() + "|" + qtype.toString() + ", timeouts: " + std::to_string(d_timeouts) + ", throttles: " + std::to_string(d_throttledqueries) + ", queries: " + std::to_string(d_outqueries) + ", " + std::to_string(d_totUsec / 1000) + " ms");
}
if (doTCP) {
}
d_totUsec += lwr.d_usec;
+
+ if (resolveret == LWResult::Result::Spoofed) {
+ spoofed = true;
+ return false;
+ }
+
accountAuthLatency(lwr.d_usec, remoteIP.sin4.sin_family);
++t_Counters.at(rec::RCode::auth).rcodeCounters.at(static_cast<uint8_t>(lwr.d_rcode));
if (resolveret == LWResult::Result::Timeout) {
/* Time out */
- LOG(prefix << qname << ": Timeout resolving after " << lwr.d_usec / 1000.0 << "msec " << (doTCP ? "over TCP" : "") << endl);
+ LOG(prefix << qname << ": Timeout resolving after " << lwr.d_usec / 1000.0 << " ms " << (doTCP ? "over TCP" : "") << endl);
d_timeouts++;
t_Counters.at(rec::Counter::outgoingtimeouts)++;
LOG(prefix << qname << ": Hit a local resource limit resolving" << (doTCP ? " over TCP" : "") << ", probable error: " << stringerror() << endl);
t_Counters.at(rec::Counter::resourceLimits)++;
}
- else if (resolveret == LWResult::Result::Spoofed) {
- spoofed = true;
- }
else {
/* LWResult::Result::PermanentError */
t_Counters.at(rec::Counter::unreachables)++;
if(remoteIP->sin4.sin_family==AF_INET6)
lwr.d_usec/=3;
*/
- // cout<<"msec: "<<lwr.d_usec/1000.0<<", "<<g_avgLatency/1000.0<<'\n';
+ // cout<<"ms: "<<lwr.d_usec/1000.0<<", "<<g_avgLatency/1000.0<<'\n';
s_nsSpeeds.lock()->find_or_enter(tns->first.empty() ? DNSName(remoteIP->toStringWithPort()) : tns->first, d_now).submit(*remoteIP, lwr.d_usec, d_now);
BOOST_TEST_MESSAGE("-----------------------------------------------------");
}
+const std::string hints = ". 3600 IN NS ns.\n"
+ ". 3600 IN NS ns1.\n"
+ "ns. 3600 IN A 192.168.178.16\n"
+ "ns. 3600 IN A 192.168.178.17\n"
+ "ns. 3600 IN A 192.168.178.18\n"
+ "ns. 3600 IN AAAA 1::2\n"
+ "ns. 3600 IN AAAA 1::3\n"
+ "ns1. 3600 IN A 192.168.178.18\n";
+
+BOOST_AUTO_TEST_CASE(test_UserHints)
+{
+
+ g_recCache = make_unique<MemRecursorCache>();
+
+ ::arg().set("max-generate-steps") = "0";
+ ::arg().set("max-include-depth") = "0";
+ char temp[] = "/tmp/hintsXXXXXXXXXX";
+ int fd = mkstemp(temp);
+ BOOST_REQUIRE(fd > 0);
+ FILE* fp = fdopen(fd, "w");
+ BOOST_REQUIRE(fp != nullptr);
+ size_t written = fwrite(hints.data(), 1, hints.length(), fp);
+ BOOST_REQUIRE(written == hints.length());
+ BOOST_REQUIRE(fclose(fp) == 0);
+
+ time_t now = time(nullptr);
+ std::vector<DNSRecord> nsvec;
+
+ auto ok = readHintsIntoCache(now, std::string(temp), nsvec);
+ BOOST_CHECK(ok);
+ BOOST_CHECK_EQUAL(nsvec.size(), 2U);
+
+ const MemRecursorCache::Flags flags = 0;
+
+ BOOST_CHECK(g_recCache->get(now, DNSName("ns"), QType::A, flags, &nsvec, ComboAddress()) > 0);
+ BOOST_CHECK_EQUAL(nsvec.size(), 3U);
+
+ BOOST_CHECK(g_recCache->get(now, DNSName("ns"), QType::AAAA, flags, &nsvec, ComboAddress()) > 0);
+ BOOST_CHECK_EQUAL(nsvec.size(), 2U);
+
+ BOOST_CHECK(g_recCache->get(now, DNSName("ns1"), QType::A, flags, &nsvec, ComboAddress()) > 0);
+ BOOST_CHECK_EQUAL(nsvec.size(), 1U);
+}
+
BOOST_AUTO_TEST_SUITE_END()
vector<DNSRecord> aset;
aset.push_back(arr);
g_recCache->replace(now, DNSName(templ), QType(QType::A), aset, vector<std::shared_ptr<const RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), false, g_rootdnsname);
- if (rootIps6[c - 'a'] != NULL) {
+ if (!rootIps6[c - 'a'].empty()) {
aaaarr.setContent(std::make_shared<AAAARecordContent>(ComboAddress(rootIps6[c - 'a'])));
vector<DNSRecord> aaaaset;
bool isRootServer(const ComboAddress& ip)
{
if (ip.isIPv4()) {
- for (size_t idx = 0; idx < rootIps4Count; idx++) {
+ for (size_t idx = 0; idx < rootIps4.size(); idx++) {
if (ip.toString() == rootIps4[idx]) {
return true;
}
}
}
else {
- for (size_t idx = 0; idx < rootIps6Count; idx++) {
+ for (size_t idx = 0; idx < rootIps6.size(); idx++) {
if (ip.toString() == rootIps6[idx]) {
return true;
}
cmd();
}
double delta=dt.ndiff()/1000000000.0;
- boost::format fmt("'%s' %.02f seconds: %.1f runs/s, %.02f usec/run");
+ boost::format fmt("'%s' %.02f seconds: %.1f runs/s, %.02f us/run");
cerr<< (fmt % cmd.getName() % delta % (runs/delta) % (delta* 1000000.0/runs)) << endl;
g_totalRuns += runs;
throw SSqlException(string("Error while retrieving SQLite query results: ")+SSQLite3ErrorString(d_db->db()));
}
if(d_dolog)
- g_log<<Logger::Warning<< "Query "<<((long)(void*)this)<<": "<<d_dtime.udiffNoReset()<<" usec to execute"<<endl;
+ g_log<<Logger::Warning<< "Query "<<((long)(void*)this)<<": "<<d_dtime.udiffNoReset()<<" us to execute"<<endl;
return this;
}
bool hasNextRow() {
if(d_dolog && d_rc != SQLITE_ROW) {
- g_log<<Logger::Warning<< "Query "<<((long)(void*)this)<<": "<<d_dtime.udiffNoReset()<<" total usec to last row"<<endl;
+ g_log<<Logger::Warning<< "Query "<<((long)(void*)this)<<": "<<d_dtime.udiffNoReset()<<" us total to last row"<<endl;
}
return d_rc == SQLITE_ROW;
}
LINE1:alloutqueries#00ff00:"outqueries/s"
rrdtool graph $GRAPHOPTS --start -$1 $WWWPREFIX/qa-latency-$2.png -w $WSIZE -h $HSIZE -l 0 \
- -t "Questions/answer latency in milliseconds" \
- -v "msec" \
+ -t "Questions/answer latency in ms" \
+ -v "ms" \
DEF:qalatency=pdns_recursor.rrd:qa-latency:AVERAGE \
CDEF:mqalatency=qalatency,1000,/ \
LINE1:mqalatency#ff0000:"questions/s"