]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Merge pull request #7753 from jpmens/patch-11
authorPieter Lexis <pieterlexis@users.noreply.github.com>
Thu, 2 May 2019 11:38:08 +0000 (13:38 +0200)
committerGitHub <noreply@github.com>
Thu, 2 May 2019 11:38:08 +0000 (13:38 +0200)
pdns_control reopens geoip databases on reload

108 files changed:
builder-support/debian/authoritative/debian-buster/config/dnsdomain2.schema [deleted file]
builder-support/debian/authoritative/debian-buster/pdns-backend-ldap.install
builder-support/debian/authoritative/debian-jessie/config/dnsdomain2.schema [deleted file]
builder-support/debian/authoritative/debian-jessie/pdns-backend-ldap.install
builder-support/debian/authoritative/debian-stretch/config/dnsdomain2.schema [deleted file]
builder-support/debian/authoritative/debian-stretch/pdns-backend-ldap.install
builder-support/debian/authoritative/ubuntu-trusty/config/dnsdomain2.schema [deleted file]
builder-support/debian/authoritative/ubuntu-trusty/pdns-backend-ldap.install
docs/appendices/backend-writers-guide.rst
docs/appendices/compiling.rst
docs/backends/bind.rst
docs/backends/generic-mysql.rst
docs/backends/generic-odbc.rst
docs/backends/generic-oracle.rst
docs/backends/generic-postgresql.rst
docs/backends/generic-sql.rst
docs/backends/generic-sqlite3.rst
docs/backends/index.rst
docs/backends/ldap.rst
docs/backends/lua.rst
docs/backends/lua2.rst
docs/backends/opendbx.rst
docs/backends/oracle.rst
docs/backends/remote.rst
docs/changelog/4.0.rst
docs/changelog/4.1.rst
docs/changelog/4.2.rst
docs/changelog/pre-4.0.rst
docs/common/security-policy.rst
docs/dnssec/index.rst
docs/dnssec/intro.rst
docs/dnssec/migration.rst
docs/dnssec/modes-of-operation.rst
docs/dnssec/operational.rst
docs/dnssec/pdnsutil.rst
docs/dnssec/pkcs11.rst
docs/dnsupdate.rst
docs/domainmetadata.rst
docs/guides/addingrecords.rst
docs/guides/alias.rst
docs/guides/basic-database.rst
docs/guides/kskroll.rst
docs/guides/recursion.rst
docs/guides/virtual-instances.rst
docs/guides/zskroll.rst
docs/http-api/tsigkey.rst
docs/index.rst
docs/installation.rst
docs/lua-records/functions.rst
docs/lua-records/index.rst
docs/lua-records/reference/comboaddress.rst
docs/lua-records/reference/index.rst
docs/lua-records/reference/misc.rst
docs/manpages/dumresp.1.rst
docs/manpages/ixfrdist.yml.5.rst
docs/manpages/pdns_control.1.rst
docs/manpages/pdnsutil.1.rst
docs/manpages/zone2json.1.rst
docs/manpages/zone2ldap.1.rst
docs/manpages/zone2sql.1.rst
docs/migration.rst
docs/modes-of-operation.rst
docs/running.rst
docs/secpoll.zone
docs/security-advisories/powerdns-advisory-2012-01.rst
docs/settings.rst
docs/tsig.rst
docs/upgrading.rst
modules/gmysqlbackend/enable-foreign-keys.mysql.sql
pdns/cachecleaner.hh
pdns/common_startup.cc
pdns/communicator.hh
pdns/dbdnsseckeeper.cc
pdns/dnsdistdist/docs/changelog.rst
pdns/dnsdistdist/docs/reference/constants.rst
pdns/dnsdistdist/docs/reference/index.rst
pdns/dnsdistdist/docs/rules-actions.rst
pdns/dnsname.hh
pdns/dnsrecords.hh
pdns/dnswasher.cc
pdns/dumresp.cc
pdns/mastercommunicator.cc
pdns/misc.cc
pdns/misc.hh
pdns/packethandler.cc
pdns/pdns_recursor.cc
pdns/rec_channel.hh
pdns/rec_channel_rec.cc
pdns/recursordist/docs/http-api/endpoint-jsonstat.rst [new file with mode: 0644]
pdns/recursordist/docs/http-api/index.rst
pdns/recursordist/docs/manpages/rec_control.1.rst
pdns/recursordist/docs/settings.rst
pdns/recursordist/negcache.cc
pdns/recursordist/test-negcache_cc.cc
pdns/recursordist/test-syncres_cc.cc
pdns/sholder.hh
pdns/syncres.cc
pdns/syncres.hh
pdns/tcpreceiver.cc
pdns/test-dnsname_cc.cc
pdns/validate.cc
pdns/validate.hh
regression-tests.dnsdist/README
regression-tests.dnsdist/runtests
regression-tests.nobackend/supermaster-signed/command
regression-tests.nobackend/supermaster-unsigned/command
regression-tests.recursor-dnssec/basicDNSSEC.py
regression-tests.recursor-dnssec/recursortests.py

diff --git a/builder-support/debian/authoritative/debian-buster/config/dnsdomain2.schema b/builder-support/debian/authoritative/debian-buster/config/dnsdomain2.schema
deleted file mode 100644 (file)
index a89aeaf..0000000
+++ /dev/null
@@ -1,195 +0,0 @@
-# A schema for storing DNS zones in LDAP
-#
-# ORDERING is not necessary, and some servers don't support
-# integerOrderingMatch. Omit or change if you like
-
-attributetype ( 1.3.6.1.4.1.2428.20.0.0  NAME 'dNSTTL'
-       DESC 'An integer denoting time to live'
-       EQUALITY integerMatch
-       ORDERING integerOrderingMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.0.1 NAME 'dNSClass'
-       DESC 'The class of a resource record'
-       EQUALITY caseIgnoreIA5Match
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.11 NAME 'wKSRecord'
-       DESC 'a well known service description, RFC 1035'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.12 NAME 'pTRRecord'
-       DESC 'domain name pointer, RFC 1035'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.13 NAME 'hInfoRecord'
-       DESC 'host information, RFC 1035'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.14 NAME 'mInfoRecord'
-       DESC 'mailbox or mail list information, RFC 1035'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.16 NAME 'tXTRecord'
-       DESC 'text string, RFC 1035'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.17 NAME 'rPRecord'
-       DESC 'for Responsible Person, RFC 1183'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.18 NAME 'aFSDBRecord'
-       DESC 'for AFS Data Base location, RFC 1183'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.24 NAME 'SigRecord'
-       DESC 'Signature, RFC 2535'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.25 NAME 'KeyRecord'
-       DESC 'Key, RFC 2535'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.27 NAME 'gPosRecord'
-       DESC 'Geographical Position, RFC 1712'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.28 NAME 'aAAARecord'
-       DESC 'IPv6 address, RFC 1886'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.29 NAME 'LocRecord'
-       DESC 'Location, RFC 1876'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.30 NAME 'nXTRecord'
-       DESC 'non-existant, RFC 2535'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.33 NAME 'sRVRecord'
-       DESC 'service location, RFC 2782'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.35 NAME 'nAPTRRecord'
-       DESC 'Naming Authority Pointer, RFC 2915'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.36 NAME 'kXRecord'
-       DESC 'Key Exchange Delegation, RFC 2230'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.37 NAME 'certRecord'
-       DESC 'certificate, RFC 2538'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.38 NAME 'a6Record'
-       DESC 'A6 Record Type, RFC 2874'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.39 NAME 'dNameRecord'
-       DESC 'Non-Terminal DNS Name Redirection, RFC 2672'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.42 NAME 'aPLRecord'
-       DESC 'Lists of Address Prefixes, RFC 3123'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.43 NAME 'dSRecord'
-       DESC 'Delegation Signer, RFC 3658'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.44 NAME 'sSHFPRecord'
-       DESC 'SSH Key Fingerprint, RFC 4255'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.45 NAME 'iPSecKeyRecord'
-       DESC 'SSH Key Fingerprint, RFC 4025'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.46 NAME 'rRSIGRecord'
-       DESC 'RRSIG, RFC 3755'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.47 NAME 'nSECRecord'
-       DESC 'NSEC, RFC 3755'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.48 NAME 'dNSKeyRecord'
-       DESC 'DNSKEY, RFC 3755'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.49 NAME 'dHCIDRecord'
-       DESC 'DHCID, RFC 4701'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.99 NAME 'sPFRecord'
-       DESC 'Sender Policy Framework, RFC 4408'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-objectclass ( 1.3.6.1.4.1.2428.20.2 NAME 'dNSDomain2'
-       SUP 'dNSDomain' STRUCTURAL
-       MAY ( DNSTTL $ DNSClass $ WKSRecord $ PTRRecord $
-               HINFORecord $ MINFORecord $ TXTRecord $ RPRecord $
-               AFSDBRecord $ SIGRecord $ KEYRecord $ GPOSRecord $
-               AAAARecord $ LOCRecord $ NXTRecord $ SRVRecord $
-               NAPTRRecord $ KXRecord $ CERTRecord $ A6Record $
-               DNAMERecord $ APLRecord $ DSRecord $ SSHFPRecord $
-               IPSECKEYRecord $ RRSIGRecord $ NSECRecord $
-               DNSKEYRecord $ DHCIDRecord $ SPFRecord
-       ) )
index 6375d07009e6560f266e47f61b260cca1f5b9d07..b16c18224522dffc4a8a1e4ba405a48d2089d27d 100644 (file)
@@ -1,3 +1,3 @@
-debian/config/dnsdomain2.schema etc/ldap/schema/
+modules/ldapbackend/dnsdomain2.schema etc/ldap/schema/
 usr/bin/zone2ldap usr/bin/
 usr/lib/*/pdns/libldapbackend.so*
diff --git a/builder-support/debian/authoritative/debian-jessie/config/dnsdomain2.schema b/builder-support/debian/authoritative/debian-jessie/config/dnsdomain2.schema
deleted file mode 100644 (file)
index a89aeaf..0000000
+++ /dev/null
@@ -1,195 +0,0 @@
-# A schema for storing DNS zones in LDAP
-#
-# ORDERING is not necessary, and some servers don't support
-# integerOrderingMatch. Omit or change if you like
-
-attributetype ( 1.3.6.1.4.1.2428.20.0.0  NAME 'dNSTTL'
-       DESC 'An integer denoting time to live'
-       EQUALITY integerMatch
-       ORDERING integerOrderingMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.0.1 NAME 'dNSClass'
-       DESC 'The class of a resource record'
-       EQUALITY caseIgnoreIA5Match
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.11 NAME 'wKSRecord'
-       DESC 'a well known service description, RFC 1035'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.12 NAME 'pTRRecord'
-       DESC 'domain name pointer, RFC 1035'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.13 NAME 'hInfoRecord'
-       DESC 'host information, RFC 1035'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.14 NAME 'mInfoRecord'
-       DESC 'mailbox or mail list information, RFC 1035'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.16 NAME 'tXTRecord'
-       DESC 'text string, RFC 1035'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.17 NAME 'rPRecord'
-       DESC 'for Responsible Person, RFC 1183'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.18 NAME 'aFSDBRecord'
-       DESC 'for AFS Data Base location, RFC 1183'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.24 NAME 'SigRecord'
-       DESC 'Signature, RFC 2535'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.25 NAME 'KeyRecord'
-       DESC 'Key, RFC 2535'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.27 NAME 'gPosRecord'
-       DESC 'Geographical Position, RFC 1712'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.28 NAME 'aAAARecord'
-       DESC 'IPv6 address, RFC 1886'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.29 NAME 'LocRecord'
-       DESC 'Location, RFC 1876'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.30 NAME 'nXTRecord'
-       DESC 'non-existant, RFC 2535'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.33 NAME 'sRVRecord'
-       DESC 'service location, RFC 2782'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.35 NAME 'nAPTRRecord'
-       DESC 'Naming Authority Pointer, RFC 2915'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.36 NAME 'kXRecord'
-       DESC 'Key Exchange Delegation, RFC 2230'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.37 NAME 'certRecord'
-       DESC 'certificate, RFC 2538'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.38 NAME 'a6Record'
-       DESC 'A6 Record Type, RFC 2874'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.39 NAME 'dNameRecord'
-       DESC 'Non-Terminal DNS Name Redirection, RFC 2672'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.42 NAME 'aPLRecord'
-       DESC 'Lists of Address Prefixes, RFC 3123'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.43 NAME 'dSRecord'
-       DESC 'Delegation Signer, RFC 3658'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.44 NAME 'sSHFPRecord'
-       DESC 'SSH Key Fingerprint, RFC 4255'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.45 NAME 'iPSecKeyRecord'
-       DESC 'SSH Key Fingerprint, RFC 4025'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.46 NAME 'rRSIGRecord'
-       DESC 'RRSIG, RFC 3755'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.47 NAME 'nSECRecord'
-       DESC 'NSEC, RFC 3755'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.48 NAME 'dNSKeyRecord'
-       DESC 'DNSKEY, RFC 3755'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.49 NAME 'dHCIDRecord'
-       DESC 'DHCID, RFC 4701'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.99 NAME 'sPFRecord'
-       DESC 'Sender Policy Framework, RFC 4408'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-objectclass ( 1.3.6.1.4.1.2428.20.2 NAME 'dNSDomain2'
-       SUP 'dNSDomain' STRUCTURAL
-       MAY ( DNSTTL $ DNSClass $ WKSRecord $ PTRRecord $
-               HINFORecord $ MINFORecord $ TXTRecord $ RPRecord $
-               AFSDBRecord $ SIGRecord $ KEYRecord $ GPOSRecord $
-               AAAARecord $ LOCRecord $ NXTRecord $ SRVRecord $
-               NAPTRRecord $ KXRecord $ CERTRecord $ A6Record $
-               DNAMERecord $ APLRecord $ DSRecord $ SSHFPRecord $
-               IPSECKEYRecord $ RRSIGRecord $ NSECRecord $
-               DNSKEYRecord $ DHCIDRecord $ SPFRecord
-       ) )
index 6375d07009e6560f266e47f61b260cca1f5b9d07..b16c18224522dffc4a8a1e4ba405a48d2089d27d 100644 (file)
@@ -1,3 +1,3 @@
-debian/config/dnsdomain2.schema etc/ldap/schema/
+modules/ldapbackend/dnsdomain2.schema etc/ldap/schema/
 usr/bin/zone2ldap usr/bin/
 usr/lib/*/pdns/libldapbackend.so*
diff --git a/builder-support/debian/authoritative/debian-stretch/config/dnsdomain2.schema b/builder-support/debian/authoritative/debian-stretch/config/dnsdomain2.schema
deleted file mode 100644 (file)
index a89aeaf..0000000
+++ /dev/null
@@ -1,195 +0,0 @@
-# A schema for storing DNS zones in LDAP
-#
-# ORDERING is not necessary, and some servers don't support
-# integerOrderingMatch. Omit or change if you like
-
-attributetype ( 1.3.6.1.4.1.2428.20.0.0  NAME 'dNSTTL'
-       DESC 'An integer denoting time to live'
-       EQUALITY integerMatch
-       ORDERING integerOrderingMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.0.1 NAME 'dNSClass'
-       DESC 'The class of a resource record'
-       EQUALITY caseIgnoreIA5Match
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.11 NAME 'wKSRecord'
-       DESC 'a well known service description, RFC 1035'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.12 NAME 'pTRRecord'
-       DESC 'domain name pointer, RFC 1035'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.13 NAME 'hInfoRecord'
-       DESC 'host information, RFC 1035'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.14 NAME 'mInfoRecord'
-       DESC 'mailbox or mail list information, RFC 1035'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.16 NAME 'tXTRecord'
-       DESC 'text string, RFC 1035'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.17 NAME 'rPRecord'
-       DESC 'for Responsible Person, RFC 1183'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.18 NAME 'aFSDBRecord'
-       DESC 'for AFS Data Base location, RFC 1183'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.24 NAME 'SigRecord'
-       DESC 'Signature, RFC 2535'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.25 NAME 'KeyRecord'
-       DESC 'Key, RFC 2535'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.27 NAME 'gPosRecord'
-       DESC 'Geographical Position, RFC 1712'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.28 NAME 'aAAARecord'
-       DESC 'IPv6 address, RFC 1886'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.29 NAME 'LocRecord'
-       DESC 'Location, RFC 1876'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.30 NAME 'nXTRecord'
-       DESC 'non-existant, RFC 2535'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.33 NAME 'sRVRecord'
-       DESC 'service location, RFC 2782'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.35 NAME 'nAPTRRecord'
-       DESC 'Naming Authority Pointer, RFC 2915'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.36 NAME 'kXRecord'
-       DESC 'Key Exchange Delegation, RFC 2230'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.37 NAME 'certRecord'
-       DESC 'certificate, RFC 2538'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.38 NAME 'a6Record'
-       DESC 'A6 Record Type, RFC 2874'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.39 NAME 'dNameRecord'
-       DESC 'Non-Terminal DNS Name Redirection, RFC 2672'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.42 NAME 'aPLRecord'
-       DESC 'Lists of Address Prefixes, RFC 3123'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.43 NAME 'dSRecord'
-       DESC 'Delegation Signer, RFC 3658'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.44 NAME 'sSHFPRecord'
-       DESC 'SSH Key Fingerprint, RFC 4255'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.45 NAME 'iPSecKeyRecord'
-       DESC 'SSH Key Fingerprint, RFC 4025'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.46 NAME 'rRSIGRecord'
-       DESC 'RRSIG, RFC 3755'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.47 NAME 'nSECRecord'
-       DESC 'NSEC, RFC 3755'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.48 NAME 'dNSKeyRecord'
-       DESC 'DNSKEY, RFC 3755'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.49 NAME 'dHCIDRecord'
-       DESC 'DHCID, RFC 4701'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.99 NAME 'sPFRecord'
-       DESC 'Sender Policy Framework, RFC 4408'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-objectclass ( 1.3.6.1.4.1.2428.20.2 NAME 'dNSDomain2'
-       SUP 'dNSDomain' STRUCTURAL
-       MAY ( DNSTTL $ DNSClass $ WKSRecord $ PTRRecord $
-               HINFORecord $ MINFORecord $ TXTRecord $ RPRecord $
-               AFSDBRecord $ SIGRecord $ KEYRecord $ GPOSRecord $
-               AAAARecord $ LOCRecord $ NXTRecord $ SRVRecord $
-               NAPTRRecord $ KXRecord $ CERTRecord $ A6Record $
-               DNAMERecord $ APLRecord $ DSRecord $ SSHFPRecord $
-               IPSECKEYRecord $ RRSIGRecord $ NSECRecord $
-               DNSKEYRecord $ DHCIDRecord $ SPFRecord
-       ) )
index 6375d07009e6560f266e47f61b260cca1f5b9d07..b16c18224522dffc4a8a1e4ba405a48d2089d27d 100644 (file)
@@ -1,3 +1,3 @@
-debian/config/dnsdomain2.schema etc/ldap/schema/
+modules/ldapbackend/dnsdomain2.schema etc/ldap/schema/
 usr/bin/zone2ldap usr/bin/
 usr/lib/*/pdns/libldapbackend.so*
diff --git a/builder-support/debian/authoritative/ubuntu-trusty/config/dnsdomain2.schema b/builder-support/debian/authoritative/ubuntu-trusty/config/dnsdomain2.schema
deleted file mode 100644 (file)
index a89aeaf..0000000
+++ /dev/null
@@ -1,195 +0,0 @@
-# A schema for storing DNS zones in LDAP
-#
-# ORDERING is not necessary, and some servers don't support
-# integerOrderingMatch. Omit or change if you like
-
-attributetype ( 1.3.6.1.4.1.2428.20.0.0  NAME 'dNSTTL'
-       DESC 'An integer denoting time to live'
-       EQUALITY integerMatch
-       ORDERING integerOrderingMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.0.1 NAME 'dNSClass'
-       DESC 'The class of a resource record'
-       EQUALITY caseIgnoreIA5Match
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.11 NAME 'wKSRecord'
-       DESC 'a well known service description, RFC 1035'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.12 NAME 'pTRRecord'
-       DESC 'domain name pointer, RFC 1035'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.13 NAME 'hInfoRecord'
-       DESC 'host information, RFC 1035'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.14 NAME 'mInfoRecord'
-       DESC 'mailbox or mail list information, RFC 1035'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.16 NAME 'tXTRecord'
-       DESC 'text string, RFC 1035'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.17 NAME 'rPRecord'
-       DESC 'for Responsible Person, RFC 1183'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.18 NAME 'aFSDBRecord'
-       DESC 'for AFS Data Base location, RFC 1183'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.24 NAME 'SigRecord'
-       DESC 'Signature, RFC 2535'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.25 NAME 'KeyRecord'
-       DESC 'Key, RFC 2535'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.27 NAME 'gPosRecord'
-       DESC 'Geographical Position, RFC 1712'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.28 NAME 'aAAARecord'
-       DESC 'IPv6 address, RFC 1886'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.29 NAME 'LocRecord'
-       DESC 'Location, RFC 1876'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.30 NAME 'nXTRecord'
-       DESC 'non-existant, RFC 2535'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.33 NAME 'sRVRecord'
-       DESC 'service location, RFC 2782'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.35 NAME 'nAPTRRecord'
-       DESC 'Naming Authority Pointer, RFC 2915'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.36 NAME 'kXRecord'
-       DESC 'Key Exchange Delegation, RFC 2230'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.37 NAME 'certRecord'
-       DESC 'certificate, RFC 2538'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.38 NAME 'a6Record'
-       DESC 'A6 Record Type, RFC 2874'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.39 NAME 'dNameRecord'
-       DESC 'Non-Terminal DNS Name Redirection, RFC 2672'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.42 NAME 'aPLRecord'
-       DESC 'Lists of Address Prefixes, RFC 3123'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.43 NAME 'dSRecord'
-       DESC 'Delegation Signer, RFC 3658'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.44 NAME 'sSHFPRecord'
-       DESC 'SSH Key Fingerprint, RFC 4255'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.45 NAME 'iPSecKeyRecord'
-       DESC 'SSH Key Fingerprint, RFC 4025'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.46 NAME 'rRSIGRecord'
-       DESC 'RRSIG, RFC 3755'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.47 NAME 'nSECRecord'
-       DESC 'NSEC, RFC 3755'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.48 NAME 'dNSKeyRecord'
-       DESC 'DNSKEY, RFC 3755'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.49 NAME 'dHCIDRecord'
-       DESC 'DHCID, RFC 4701'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-attributetype ( 1.3.6.1.4.1.2428.20.1.99 NAME 'sPFRecord'
-       DESC 'Sender Policy Framework, RFC 4408'
-       EQUALITY caseIgnoreIA5Match
-       SUBSTR caseIgnoreIA5SubstringsMatch
-       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-
-objectclass ( 1.3.6.1.4.1.2428.20.2 NAME 'dNSDomain2'
-       SUP 'dNSDomain' STRUCTURAL
-       MAY ( DNSTTL $ DNSClass $ WKSRecord $ PTRRecord $
-               HINFORecord $ MINFORecord $ TXTRecord $ RPRecord $
-               AFSDBRecord $ SIGRecord $ KEYRecord $ GPOSRecord $
-               AAAARecord $ LOCRecord $ NXTRecord $ SRVRecord $
-               NAPTRRecord $ KXRecord $ CERTRecord $ A6Record $
-               DNAMERecord $ APLRecord $ DSRecord $ SSHFPRecord $
-               IPSECKEYRecord $ RRSIGRecord $ NSECRecord $
-               DNSKEYRecord $ DHCIDRecord $ SPFRecord
-       ) )
index 6375d07009e6560f266e47f61b260cca1f5b9d07..b16c18224522dffc4a8a1e4ba405a48d2089d27d 100644 (file)
@@ -1,3 +1,3 @@
-debian/config/dnsdomain2.schema etc/ldap/schema/
+modules/ldapbackend/dnsdomain2.schema etc/ldap/schema/
 usr/bin/zone2ldap usr/bin/
 usr/lib/*/pdns/libldapbackend.so*
index 4766771f77d6955444f2dc7e320dcd6816e1d87d..9a8d9b8f6edab4937f1642d5963e0f3fb2155c38 100644 (file)
@@ -462,7 +462,7 @@ available. The exact definitions:
 
   Returns the numerical value of a parameter. Uses ``atoi()`` internally
 
-  Sample usage from the BindBackend: getting the 'check-interval' setting:
+  Sample usage from the BIND backend: getting the 'check-interval' setting:
 
   .. code-block:: cpp
 
@@ -643,9 +643,9 @@ Supermaster/Superslave capability
 A backend that wants to act as a 'superslave' for a master should
 implement the following method:
 
-::
+.. code-block:: cpp
 
-                class DNSBackend 
+                class DNSBackend
                 {
                    virtual bool superMasterBackend(const string &ip, const string &domain, const vector<DNSResourceRecord>&nsset, string *account, DNSBackend **db)
                 };
index 8972ecf6f2eeed271e645303f6392055dcc11116..a29d768bd7cef5b91c8291422e0d1b909dceaf8c 100644 (file)
@@ -17,7 +17,7 @@ Each backend has a module name that you look up in this table.
 To compile a module for inclusion at runtime, which is great if you are a unix vendor, use ``--with-dynmodules='mod1 mod2 mod3'``.
 These modules then end up as .so files in the compiled ``libdir``.
 
-By default, the :doc:`bind <../../backends/bind>`, :doc:`mysql <../../backends/generic-mysql>` and :doc:`random <../../backends/random>` are compiled into the binary. The :doc:`pipe <../../backends/pipe>` is, by default, compiled as a runtime loadable module.
+By default, the :doc:`bind <../../backends/bind>`, :doc:`mysql <../../backends/generic-mysql>` and :doc:`random <../../backends/random>` modules are compiled into the binary. The :doc:`pipe <../../backends/pipe>` is, by default, compiled as a runtime loadable module.
 
 Getting the sources
 -------------------
index 0dc1bf9efb00512da3641dd07fd40d407273d0ec..5434f3ec58fd8aa9f8e95eaf252f292ab4de225b 100644 (file)
@@ -1,4 +1,4 @@
-Bind zone file backend
+BIND zone file backend
 ======================
 
 * Native: Yes
@@ -13,16 +13,25 @@ Bind zone file backend
 * Module name: bind
 * Launch: ``bind``
 
-The BindBackend started life as a demonstration of the versatility of
+The BIND backend started life as a demonstration of the versatility of
 PowerDNS but quickly gained in importance when there appeared to be
-demand for a Bind 'work-alike'.
+demand for a BIND 'work-alike'.
 
-The BindBackend parses a Bind-style ``named.conf`` and extracts
+The BIND backend parses a BIND-style ``named.conf`` and extracts
 information about zones from it. It makes no attempt to honour other
 configuration flags, which you should configure (when available) using
 the PowerDNS native configuration.
 
-**note**: Because this backend retrieves its configuration from a text file and not a database, the HTTP API is unable to process changes for this backend. This effectively makes the API read-only for zones hosted by the BIND backend.  
+Unique to this PowerDNS backend is that it serves from plain zone files,
+which allows for hand-crafting zone files, only takes a tiny footprint
+in terms of server resource usage while being
+:ref:`performant efficiently <bind_performance>`.
+
+.. note::
+  Because this backend retrieves its configuration from plain files and
+  not a database, the HTTP API is unable to process changes for this
+  backend. This effectively makes the API read-only for zones hosted by
+  the BIND backend.
 
 Configuration Parameters
 ------------------------
@@ -32,9 +41,9 @@ Configuration Parameters
 ``bind-config``
 ~~~~~~~~~~~~~~~
 
-Location of the Bind configuration file to parse.
+Location of the BIND configuration file to parse.
 
-PowerDNS does not support every directive supported by Bind.
+PowerDNS does not support every directive supported by BIND.
 It supports the following blocks and directives:
 
 * ``options``
@@ -51,7 +60,9 @@ It supports the following blocks and directives:
 ``bind-check-interval``
 ~~~~~~~~~~~~~~~~~~~~~~~
 
-How often to check for zone changes. See :ref:`bind-operation` section.
+Interval in seconds to check for zone file changes. Default is 0 (disabled).
+
+See :ref:`bind-operation` section for more information.
 
 .. _setting-bind-dnssec-db:
 
@@ -64,6 +75,11 @@ slave DNSSEC-enabled domains (where the RRSIGS are in the AXFR), a
 :ref:`metadata-presigned` domain metadata is set
 during the zonetransfer.
 
+.. warning::
+   If this is left empty on slaves and a presigned zone is transferred,
+   it will (silently) serve it without DNSSEC. This in turn results in
+   serving the domain as bogus.
+
 .. _setting-bind-hybrid:
 
 ``bind-hybrid``
@@ -85,15 +101,15 @@ when loading zone files.
 Operation
 ---------
 
-On launch, the BindBackend first parses the ``named.conf`` to determine
+On launch, the BIND backend first parses the ``named.conf`` to determine
 which zones need to be loaded. These will then be parsed and made
 available for serving, as they are parsed. So a ``named.conf`` with
 100.000 zones may take 20 seconds to load, but after 10 seconds, 50.000
 zones will already be available. While a domain is being loaded, it is
 not yet available, to prevent incomplete answers.
 
-Reloading is currently done only when a request for a zone comes in, and
-then only after :ref:`setting-bind-check-interval`.
+Reloading is currently done only when a request (or zone transfer) for a
+zone comes in, and then only after :ref:`setting-bind-check-interval`
 seconds have passed after the last check. If a change occurred, access
 to the zone is disabled, the file is reloaded, access is restored, and
 the question is answered. For regular zones, reloading is fast enough to
@@ -103,13 +119,19 @@ If :ref:`setting-bind-check-interval` is specified as
 zero, no checks will be performed until the ``pdns_control reload`` is
 given.
 
+Please note that also the :ref:`setting-slave-cycle-interval` setting
+controls how often a master would notify a slave about changes.
+Especially in 'hidden master' configurations, where servers usually
+don't receive regular queries, you may want to lower that setting to a
+value as low as :ref:`setting-bind-check-interval`.
+
 pdns\_control commands
 ----------------------
 
 ``bind-add-zone <domain> <filename>``
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-Add zone ``domain`` from ``filename`` to PowerDNS's bind backend. Zone
+Add zone ``domain`` from ``filename`` to PowerDNS's BIND backend. Zone
 will be loaded at first request.
 
 .. note::
@@ -118,9 +140,11 @@ will be loaded at first request.
 ``bind-domain-status <domain> [domain]``
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-Output status of domain or domains. Can be one of
-``seen in named.conf, not parsed``, ``parsed successfully at <time>`` or
-``error parsing at line ... at <time>``.
+Output status of domain or domains. Can be one of:
+
+* ``seen in named.conf, not parsed``,
+* ``parsed successfully at <time>`` or
+* ``error parsing at line ... at <time>``.
 
 ``bind-list-rejects``
 ~~~~~~~~~~~~~~~~~~~~~
@@ -135,7 +159,7 @@ Reloads a zone from disk NOW, reporting back results.
 ``rediscover``
 ~~~~~~~~~~~~~~
 
-Reread the bind configuration file (``named.conf``). If parsing fails,
+Reread the BIND configuration file (``named.conf``). If parsing fails,
 the old configuration remains in force and ``pdns_control`` reports the
 error. Any newly discovered domains are read, discarded domains are
 removed from memory.
@@ -146,10 +170,12 @@ removed from memory.
 All zones with a changed timestamp are reloaded at the next incoming
 query for them.
 
+.. _bind_performance:
+
 Performance
 -----------
 
-The BindBackend does not benefit from the packet cache as it is fast
+The BIND backend does not benefit from the packet cache as it is fast
 enough on its own. Furthermore, on most systems, there will be no
 benefit in using multiple CPUs for the packetcache, so a noticeable
 speedup can be attained by specifying
@@ -162,7 +188,7 @@ Master
 ~~~~~~
 
 Works as expected. At startup, no notification storm is performed as
-this is generally not useful. Perhaps in the future the Bind Backend
+this is generally not useful. Perhaps in the future the BIND backend
 will attempt to store zone metadata in the zone, allowing it to
 determine if a zone has changed its serial since the last time
 notifications were sent out.
@@ -173,7 +199,7 @@ notifications however.
 Slave
 ~~~~~
 
-Also works as expected. The Bind backend expects to be able to write to
+Also works as expected. The BIND backend expects to be able to write to
 a directory where a slave domain lives. The incoming zone is stored as
 'zonename.RANDOM' and atomically renamed if it is retrieved
 successfully, and parsed only then.
@@ -195,5 +221,5 @@ are picked up in the same way as master and slave zones, see
 Native zones in the BIND backend are supported since version 4.1.0 of
 the PowerDNS Authoritative Server.
 
-**note**: Any zone with no ``type`` set (an error in BIND) is assumed to
-be native.
+.. note::
+  Any zone with no ``type`` set (an error in BIND) is assumed to be native.
index 02d39fe999daab71f491c8aafaa3dab87584db54..5cbf04418f4eb44fb79b4ea50a621e486b853f62 100644 (file)
@@ -33,6 +33,7 @@ material, and other information upon deletion of a domain from the
 domains table. The following SQL does the job:
 
 .. literalinclude:: ../../modules/gmysqlbackend/enable-foreign-keys.mysql.sql
+   :language: SQL
 
 Using MySQL replication
 -----------------------
index 69fa1b5f43a82485954e7306250ca069a8054a19..6c6b3997a773c98bde55f3dadd21146625b89878 100644 (file)
@@ -114,6 +114,7 @@ This schema can also be found in the PowerDNS source as
 This is the schema for 4.2. For 4.1, please find `the 4.1 schema on GitHub <https://github.com/PowerDNS/pdns/blob/rel/auth-4.1.x/modules/godbcbackend/schema.mssql.sql>`_.
 
 .. literalinclude:: ../../modules/godbcbackend/schema.mssql.sql
+   :language: SQL
 
 Load this into the database as follows:
 
@@ -133,7 +134,7 @@ Configuring PowerDNS
 
 Add the options required to your ``pdns.conf``:
 
-::
+.. code-block:: ini
 
     launch=godbc
     godbc-datasource=pdns1
index 31f08c2e2fd443e79e3e22cd3f7309cf29b0da3c..59fa2e74cadf68dff49a395d8d99e72d2cd342ee 100644 (file)
@@ -27,6 +27,7 @@ need or want to add ``namespace`` statements.
 Below, you will find the schema for 4.2. If you are using 4.1 or earlier, please find `the 4.1 schema on GitHub <https://github.com/PowerDNS/pdns/blob/rel/auth-4.1.x/modules/goraclebackend/schema.goracle.sql>`_.
 
 .. literalinclude:: ../../modules/goraclebackend/schema.goracle.sql
+   :language: SQL
 
 This schema contains all elements needed for master, slave and
 superslave operation.
index 824233413d129067b2bfdd0804f3f5f801df305b..c771876834136dce31f870f09a054cc66974ebe4 100644 (file)
@@ -82,7 +82,7 @@ Enable DNSSEC processing for this backend. Default: no.
 .. _setting-gpgsql-extra-connection-parameters:
 
 ``gpgsql-extra-connection-parameters``
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Extra connection parameters to forward to postgres. If you want to pin a
 specific certificate for the connection you should set this to
@@ -97,3 +97,4 @@ Default schema
 This is the 4.2 schema. Please find `the 4.1 schema on GitHub <https://github.com/PowerDNS/pdns/blob/rel/auth-4.1.x/modules/gpgsqlbackend/schema.pgsql.sql>`_.
 
 .. literalinclude:: ../../modules/gpgsqlbackend/schema.pgsql.sql
+   :language: SQL
index b1e2027f117924351c5b0549b7e42c3d45b4165a..b98eb04bb08d60477fdfe29714a3e8df32b9e91b 100644 (file)
@@ -48,17 +48,15 @@ And wait a while for PowerDNS to pick up the addition - which happens
 within one minute (this is determined by the
 :ref:`setting-slave-cycle-interval`
 setting). There is no need to inform PowerDNS that a new domain was
-added. Typical output is:
-
-.. code-block:: SQL
-
-    Apr 09 13:34:29 All slave domains are fresh
-    Apr 09 13:35:29 1 slave domain needs checking
-    Apr 09 13:35:29 Domain example.com is stale, master serial 1, our serial 0
-    Apr 09 13:35:30 [gPgSQLBackend] Connected to database
-    Apr 09 13:35:30 AXFR started for 'example.com'
-    Apr 09 13:35:30 AXFR done for 'example.com'
-    Apr 09 13:35:30 [gPgSQLBackend] Closing connection
+added. Typical output is::
+
+  Apr 09 13:34:29 All slave domains are fresh
+  Apr 09 13:35:29 1 slave domain needs checking
+  Apr 09 13:35:29 Domain example.com is stale, master serial 1, our serial 0
+  Apr 09 13:35:30 [gPgSQLBackend] Connected to database
+  Apr 09 13:35:30 AXFR started for 'example.com'
+  Apr 09 13:35:30 AXFR done for 'example.com'
+  Apr 09 13:35:30 [gPgSQLBackend] Closing connection
 
 From now on, PowerDNS is authoritative for the 'example.com' zone and
 will respond accordingly for queries within that zone.
index 31066a92135d81fab865802919b04ead54578a84..b0e723aceea839688aed483f15a8f70a868d132c 100644 (file)
@@ -93,11 +93,10 @@ Using the SQLite backend
 ------------------------
 
 The last thing you need to do is telling PowerDNS to use the SQLite
-backend.
+backend in pdns.conf:
 
-::
+.. code-block:: ini
 
-    # in pdns.conf
     launch=gsqlite3
     gsqlite3-database=<path to your SQLite database>
 
@@ -105,7 +104,7 @@ Then you can start PowerDNS and it should notify you that a connection
 to the database was made.
 
 Compiling the SQLite backend
------------------------------
+----------------------------
 
 Before you can begin compiling PowerDNS with the SQLite backend you need
 to have the SQLite utility and library installed on your system. You can
index caa25276aa2a8b244221c49ad090318c7d16056d..b71c933cd1ea3250aeacacf9057fa80df42d8f26 100644 (file)
@@ -22,6 +22,8 @@ The following table describes the supported backends and some of their capabilit
 +------------------------------------------------+--------+--------+-------+--------------+-------------+---------------------------------+--------------+
 | :doc:`LDAP <ldap>`                             | Yes    | No     | No    | No           | No          | No                              | ``ldap``     |
 +------------------------------------------------+--------+--------+-------+--------------+-------------+---------------------------------+--------------+
+| :doc:`Lua <lua>`                               | Yes    | Yes    | No    | No           | Yes         | Yes                             | ``lua``      |
++------------------------------------------------+--------+--------+-------+--------------+-------------+---------------------------------+--------------+
 | :doc:`Lua2 <lua2>`                             | Yes    | Yes    | No    | No           | Yes         | Yes                             | ``lua2``     |
 +------------------------------------------------+--------+--------+-------+--------------+-------------+---------------------------------+--------------+
 | :doc:`MyDNS <mydns>`                           | Yes    | No     | No    | No           | No          | No                              | ``mydns``    |
@@ -44,6 +46,7 @@ These backends have :doc:`features unique <generic-sql>` to the generic SQL back
 
 .. toctree::
   :maxdepth: 1
+  :hidden:
 
   bind
   generic-sql
index b2f58c9bb9bb4aa5de494ee0c8a4cdb747c1d556..dfc43d7a5d563e97d2aaa3dcdab3329a03d0a115 100644 (file)
@@ -65,7 +65,7 @@ Add them to the ``pdns.conf`` file.
 
 To launch the ldap backend:
 
-::
+.. code-block:: ini
 
     launch=ldap
 
@@ -74,7 +74,7 @@ To launch the ldap backend:
 ``ldap-host``
 ^^^^^^^^^^^^^
 
-(default "ldap://127.0.0.1:389/") : The values assigned to this
+(default "``ldap://127.0.0.1:389/``") : The values assigned to this
 parameter can be LDAP URIs (e.g. ``ldap://127.0.0.1/`` or
 ``ldaps://127.0.0.1/``) describing the connection to the LDAP server.
 There can be multiple LDAP URIs specified for load balancing and high
@@ -89,7 +89,7 @@ followed by a colon and the port).
 ^^^^^^^^^^^^^^^^^
 
 (default "no") : Use TLS encrypted connections to the LDAP server. This
-is only allowed if ldap-host is a ldap:// URI or a host name / IP
+is only allowed if ldap-host is an ``ldap://`` URI or a host name / IP
 address.
 
 .. _setting-ldap-timeout:
@@ -310,7 +310,7 @@ Wildcards
 ^^^^^^^^^
 
 Wild-card domains are possible by using the asterisk in the
-``associatedDomain`` value like it is used in the bind zone files. The
+``associatedDomain`` value like it is used in the BIND zone files. The
 "dc" attribute can be set to any value in simple or strict mode - this
 doesn't matter.
 
@@ -450,7 +450,7 @@ standard compliant LDAP server. ``zone2ldap`` needs the BIND
 ``named.conf`` (usually located in /etc) as input and writes the dns
 record entries in ldif format to stdout:
 
-::
+.. code-block:: shell
 
     zone2ldap
        --basedn=YOUR_BASE_DN \
@@ -460,7 +460,7 @@ record entries in ldif format to stdout:
 Alternatively zone2ldap can be used to convert only single zone files
 instead all zones:
 
-::
+.. code-block:: shell
 
     zone2ldap
        --basedn=YOUR_BASE_DN \
@@ -471,15 +471,15 @@ instead all zones:
 See :doc:`its manpage <../manpages/zone2ldap.1>` for a complete list of
 options.
 
-Bind LDAP backend
+BIND LDAP backend
 ^^^^^^^^^^^^^^^^^
 
-When coming from the `Bind LDAP sdb
+When coming from the `BIND LDAP sdb
 backend <http://bind9-ldap.bayour.com/>`__, the records can be kept in
 the LDAP tree also for the PowerDNS LDAP backend. The schemas both
 backends utilize is almost the same except for one important thing:
 Domains for PowerDNS are stored in the attribute "associatedDomain"
-whereas Bind stores them split in "relativeDomainName" and "zoneName".
+whereas BIND stores them split in "relativeDomainName" and "zoneName".
 
 There is a `migration
 script <http://www.linuxnetworks.de/pdnsldap/bind2pdns-ldap>`__ which
@@ -487,7 +487,7 @@ creates a file in LDIF format with the necessary LDAP updates including
 the "associatedDomain" and "dc" attributes. The utility is executed on
 the command line by:
 
-::
+.. code-block:: shell
 
     ./bind2pdns-ldap
        --host=HOSTNAME_OR_IP \
@@ -519,13 +519,13 @@ Other name server
 ^^^^^^^^^^^^^^^^^
 
 The easiest way for migrating DNS records is to use the output of a zone
-transfer (AXFR). Save the output of the ``dig`` program provided by bind
+transfer (AXFR). Save the output of the ``dig`` program provided by BIND
 into a file and call ``zone2ldap`` with the file name as option to the
 ``--zone-file`` parameter. This will generate the appropriate ldif file,
 which can be imported into the LDAP tree. The bash script except below
 automates this:
 
-::
+.. code-block:: shell
 
     DNSSERVER=127.0.0.1
     DOMAINS="example.com 10.10.in-addr.arpa"
@@ -629,4 +629,4 @@ SASL support
 ^^^^^^^^^^^^
 
 Support for more authentication methods would be handy. Anyone
-interested may `contribute <https://github.com/PowerDNS/pdns>`__.?
+interested may `contribute <https://github.com/PowerDNS/pdns>`__.
index aef67350c5ed4f5b90cef568cfa97b71374905b6..c95702114bea23b10f5f0b7d15d64583d4a2e5f7 100644 (file)
@@ -47,16 +47,16 @@ There is a couple of new functions for you to use in Lua:
 
 All these ``log_facilities`` is available: 
 
- * ``log_all`` 
- * ``log_ntlog`` 
- * ``log_alert`` 
- * ``log_critical`` 
- * ``log_error`` 
- * ``log_warning`` 
- * ``log_notice,`` 
- * ``log_info`` 
- * ``log_debug`` 
- * ``log_none``
+* ``log_all``
+* ``log_ntlog``
+* ``log_alert``
+* ``log_critical``
+* ``log_error``
+* ``log_warning``
+* ``log_notice,``
+* ``log_info``
+* ``log_debug``
+* ``log_none``
 
 ``dnspacket()``
 ~~~~~~~~~~~~~~~
@@ -66,6 +66,8 @@ This will give you back three parameters with ``remote_ip``,
 
 Can only be used in the functions ``list()`` and ``getsoa()``.
 
+.. _backends_lua_fun_getarg:
+
 ``getarg("PARAMETER")``
 ~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -75,8 +77,8 @@ pdns.conf file.
 ``mustdo("PARAMETER")``
 ~~~~~~~~~~~~~~~~~~~~~~~
 
-This is the same as ```getarg()`` <#getarg>`__ but return a boolean
-instead of a string.
+This is the same as :ref:`getarg() <backends_lua_fun_getarg>`, but returns
+a boolean instead of a string.
 
 You also have all the different QTypes in a table called 'QTypes'.
 
@@ -102,9 +104,9 @@ The following script can be used to test the server:
 
 This will yield the following result:
 
-::
+.. code-block:: shell
 
-    $dig any www.test.com @127.0.0.1 -p5300 +multiline
+    $ dig any www.test.com @127.0.0.1 -p5300 +multiline
     ; <<>> DiG 9.7.3 <<>> any www.test.com @127.0.0.1 -p5300 +multiline
     ;; global options: +cmd
     ;; Got answer:
@@ -152,7 +154,9 @@ luafunctions if you want. For example:
 
 .. _setting-lua-f_lookup:
 
-``lua-f_lookup = mynewfunction``
+.. code-block:: ini
+
+  lua-f_lookup = mynewfunction
 
 will call the function ``mynewfunction`` for the lookup-routine.
 
@@ -168,7 +172,9 @@ You can have an error function in Lua when Lua gives back a error.
 
 First make your error function then you put this in ``pdns.conf``:
 
-``lua-f_exec_error = YOUR_METHOD``
+.. code-block:: ini
+
+  lua-f_exec_error = YOUR_METHOD
 
 DNSSEC
 ------
index 7b079a0d4e684414a476339401fcff7e1b81ec17..f08815de2f363e9c6d439e98b2a063ee0cdd9585 100644 (file)
@@ -46,6 +46,7 @@ INPUT:
 
 OUTPUT:
  Expects a array which has tables with following keys:
+
  - DNSName name - resource record name (can also be string)
  - string type - type of resource record (can also be QType or valid integer)
  - string content - resource record content
@@ -75,6 +76,8 @@ OUTPUT:
 
 NOTES:
  This function is **optional**.
+
+.. _backends_lua2_dns_get_domaininfo:
  
 ``dns_get_domaininfo(domain)``
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -85,6 +88,7 @@ INPUT:
 
 OUTPUT:
  Return false if not supported or found, otherwise expects a table with keys:
+
  - string account - Associated account of this domain (default: <empty>)
  - string kind - Domain kind (NATIVE,MASTER,SLAVE) (default: NATIVE)
  - int id - Associated domain ID (default: -1)
@@ -106,7 +110,8 @@ NOTES:
 Get domain information for all domains.
 
 OUTPUT:
- Return false if not supported or found, otherwise return a table of string, domaininfo. See ``dns_get_domaininfo```.
+ Return false if not supported or found, otherwise return a table of string,
+ domaininfo. See :ref:`dns_get_domaininfo() <backends_lua2_dns_get_domaininfo>`.
 
 NOTES:
  This function is **optional**, except if you need master functionality.
@@ -147,6 +152,7 @@ INPUT:
 
 OUTPUT:
  Return false if not found or supported, otherwise expects array of tables with keys:
+
  - int id - Key ID
  - int flags - Key flags
  - bool active - Is key active
@@ -165,6 +171,7 @@ INPUT:
 
 OUTPUT:
  Table with keys:
+
  - unhashed - DNSName of the unhashed relative to domain
  - before - (hashed) name of previous record relative to domain
  - after - (hashed) name of next record relative to domain
index 81a19fc8e0cda67b71e0ad3bb53671ffa6d6f37d..768bc2836714cfd9d66aee2bc38e8882243458e8 100644 (file)
@@ -293,7 +293,7 @@ Supported without changes since OpenDBX 1.0.0 but requires to set
 (including the trailing slash or backslash, depending on your operating
 system) and opendbx-database to the name of the file.
 
-.. code-block:: SQL
+.. code-block:: ini
 
     opendbx-host-read = /path/to/file/
     opendbx-host-write = /path/to/file/
@@ -302,7 +302,7 @@ system) and opendbx-database to the name of the file.
 SQLite Schema
 ~~~~~~~~~~~~~
 
-::
+.. code-block:: SQL
 
     CREATE TABLE "domains" (
         "id" INTEGER NOT NULL PRIMARY KEY,
@@ -370,7 +370,7 @@ SQLite Schema
 SQLite3 Schema
 ~~~~~~~~~~~~~~
 
-::
+.. code-block:: SQL
 
     CREATE TABLE "domains" (
         "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
@@ -442,7 +442,7 @@ Requires :ref:`setting-opendbx-database` set to the path of
 the database file and doesn't support the default statement for starting
 transactions. Please add the following lines to your pdns.conf:
 
-::
+.. code-block:: ini
 
     opendbx-database = /var/lib/firebird2/data/powerdns.gdb
     opendbx-sql-transactbegin = SET TRANSACTION
@@ -452,7 +452,7 @@ tool with the parameter ``-page 4096``. Otherwise, you will get an error
 (key size exceeds implementation restriction for index
 "pdns\_unq\_domains\_name") when creating the tables.
 
-::
+.. code-block:: SQL
 
     CREATE TABLE "domains" (
         "id" INTEGER NOT NULL,
@@ -560,13 +560,13 @@ configuration file of the dblib client library) and doesn't support the
 default statement for starting transactions. Please add the following
 lines to your pdns.conf:
 
-::
+.. code-block:: ini
 
     opendbx-host-read = MSSQL2k
     opendbx-host-write = MSSQL2k
     opendbx-sql-transactbegin = BEGIN TRANSACTION
 
-::
+.. code-block:: SQL
 
     SET quoted_identifier ON;
 
@@ -650,13 +650,13 @@ section in the configuration file of the ctlib client library) and
 doesn't support the default statement for starting transactions. Please
 add the following lines to your pdns.conf:
 
-::
+.. code-block:: ini
 
     opendbx-host-read = SYBASE
     opendbx-host-write = SYBASE
     opendbx-sql-transactbegin = BEGIN TRANSACTION
 
-::
+.. code-block:: SQL
 
     SET quoted_identifier ON;
 
@@ -736,11 +736,11 @@ Oracle
 Uses a different syntax for transactions and requires the following
 additional line in your pdns.conf:
 
-::
+.. code-block:: ini
 
     opendbx-sql-transactbegin = SET TRANSACTION NAME 'AXFR'
 
-::
+.. code-block:: SQL
 
     CREATE TABLE "domains" (
         "id" INTEGER NOT NULL,
index 8445e694ec1e2e857a7e103defe214511179087d..ba9b7c34bd70bd061b56c6d661bb149aec61081a 100644 (file)
@@ -352,7 +352,7 @@ oracle-basic-query
 
 Looking for records based on owner name and type. Default:
 
-::
+.. code-block:: SQL
 
     SELECT fqdn, ttl, type, content, zone_id, last_change, auth
     FROM Records
@@ -363,7 +363,7 @@ oracle-basic-id-query
 
 Looking for records from one zone based on owner name and type. Default:
 
-::
+.. code-block:: SQL
 
     SELECT fqdn, ttl, type, content, zone_id, last_change, auth
     FROM Records
@@ -374,7 +374,7 @@ oracle-any-query
 
 Looking for records based on owner name. Default:
 
-::
+.. code-block:: SQL
 
     SELECT fqdn, ttl, type, content, zone_id, last_change, auth
     FROM Records
@@ -387,7 +387,7 @@ oracle-any-id-query
 
 Looking for records from one zone based on owner name. Default:
 
-::
+.. code-block:: SQL
 
     SELECT fqdn, ttl, type, content, zone_id, last_change, auth
     FROM Records
@@ -401,7 +401,7 @@ oracle-list-query
 
 Looking for all records from one zone. Default:
 
-::
+.. code-block:: SQL
 
     SELECT fqdn, ttl, type, content, zone_id, last_change, auth
     FROM Records
@@ -418,7 +418,7 @@ oracle-get-zone-metadata-query
 Fetch the content of the metadata entries of type ':kind' for the zone
 called ':name', in their original order. Default:
 
-::
+.. code-block:: SQL
 
     SELECT md.meta_content
     FROM Zones z JOIN ZoneMetadata md ON z.id = md.zone_id
@@ -432,7 +432,7 @@ Delete all metadata entries of type ':kind' for the zone called ':name'.
 You can skip this if you do not plan to manage zones with the
 ``pdnsutil`` tool. Default:
 
-::
+.. code-block:: SQL
 
     DELETE FROM ZoneMetadata md
     WHERE zone_id = (SELECT id FROM Zones z WHERE z.name = lower(:name))
@@ -444,7 +444,7 @@ oracle-set-zone-metadata-query
 Create a metadata entry. You can skip this if you do not plan to manage
 zones with the ``pdnsutil`` tool. Default:
 
-::
+.. code-block:: SQL
 
     INSERT INTO ZoneMetadata (zone_id, meta_type, meta_ind, meta_content)
     VALUES (
@@ -457,7 +457,7 @@ oracle-get-tsig-key-query
 
 Retrieved the TSIG key specified by ':name'. Default:
 
-::
+.. code-block:: SQL
 
     SELECT algorithm, secret
     FROM TSIGKeys
@@ -471,7 +471,7 @@ oracle-get-zone-keys-query
 
 Retrieve the DNSSEC signing keys for a zone. Default:
 
-::
+.. code-block:: SQL
 
     SELECT k.id, k.flags, k.active, k.keydata
     FROM ZoneDNSKeys k JOIN Zones z ON z.id = k.zone_id
@@ -483,7 +483,7 @@ oracle-del-zone-key-query
 Delete a DNSSEC signing key. You can skip this if you do not plan to
 manage zones with the ``pdnsutil`` tool. Default:
 
-::
+.. code-block:: SQL
 
     DELETE FROM ZoneDNSKeys WHERE id = :keyid
 
@@ -493,9 +493,9 @@ oracle-add-zone-key-query
 Add a DNSSEC signing key. You can skip this if you do not plan to manage
 zones with the ``pdnsutil`` tool. Default:
 
-::
+.. code-block:: SQL
 
-    INSERT INTO ZoneDNSKeys (id, zone_id, flags, active, keydata) "
+    INSERT INTO ZoneDNSKeys (id, zone_id, flags, active, keydata)
     VALUES (
       zonednskeys_id_seq.NEXTVAL,
       (SELECT id FROM Zones WHERE name = lower(:name)),
@@ -510,7 +510,7 @@ oracle-set-zone-key-state-query
 Enable or disable a DNSSEC signing key. You can skip this if you do not
 plan to manage zones with the **pdnsutil** tool. Default:
 
-::
+.. code-block:: SQL
 
     UPDATE ZoneDNSKeys SET active = :active WHERE id = :keyid
 
@@ -526,7 +526,7 @@ variables, not a query.
 
 Default:
 
-::
+.. code-block:: SQL
 
     BEGIN
       get_canonical_prev_next(:zoneid, :name, :prev, :next);
@@ -539,7 +539,7 @@ Given an NSEC3 hash, this call needs to return its predecessor and
 successor in NSEC3 zone ordering into ``:prev`` and ``:next``, and the
 FQDN of the predecessor into ``:unhashed``. Default:
 
-::
+.. code-block:: SQL
 
     BEGIN
       get_hashed_prev_next(:zoneid, :hash, :unhashed, :prev, :next);
@@ -554,7 +554,7 @@ oracle-zone-info-query
 Get some basic information about the named zone before doing
 master/slave things. Default:
 
-::
+.. code-block:: SQL
 
     SELECT id, name, type, last_check, serial, notified_serial
     FROM Zones
@@ -567,7 +567,7 @@ Delete all records for a zone in preparation for an incoming zone
 transfer. This happens inside a transaction, so if the transfer fails,
 the old zone content will still be there. Default:
 
-::
+.. code-block:: SQL
 
     DELETE FROM Records WHERE zone_id = :zoneid
 
@@ -578,7 +578,7 @@ Insert a record into the zone during an incoming zone transfer. This
 happens inside the same transaction as delete-zone, so we will not end
 up with a partially transferred zone. Default:
 
-::
+.. code-block:: SQL
 
     INSERT INTO Records (id, fqdn, zone_id, ttl, type, content)
     VALUES (records_id_seq.NEXTVAL, lower(:name), :zoneid, :ttl, :type, :content)
@@ -592,7 +592,7 @@ empty non-terminals, set the ``auth`` bit and NSEC3 hashes, and
 generally do any post-processing your schema requires. The do-nothing
 default:
 
-::
+.. code-block:: SQL
 
     DECLARE
       zone_id INTEGER := :zoneid;
@@ -610,7 +610,7 @@ Return a list of zones that need to be checked and their master servers.
 Return multiple rows, identical except for the master address, for zones
 with more than one master. Default:
 
-::
+.. code-block:: SQL
 
     SELECT z.id, z.name, z.last_check, z.serial, zm.master
     FROM Zones z JOIN Zonemasters zm ON z.id = zm.zone_id
@@ -623,7 +623,7 @@ oracle-zone-set-last-check-query
 
 Set the last check timestamp after a successful check. Default:
 
-::
+.. code-block:: SQL
 
     UPDATE Zones SET last_check = :lastcheck WHERE id = :zoneid
 
@@ -633,7 +633,7 @@ oracle-updated-masters-query
 Return a list of zones that need to have ``NOTIFY`` packets sent out.
 Default:
 
-::
+.. code-block:: SQL
 
     SELECT id, name, serial, notified_serial
     FROM Zones
@@ -645,7 +645,7 @@ oracle-zone-set-notified-serial-query
 
 Set the last notified serial after packets have been sent. Default:
 
-::
+.. code-block:: SQL
 
     UPDATE Zones SET notified_serial = :serial WHERE id = :zoneid
 
@@ -656,7 +656,7 @@ Return a list of hosts that should be notified, in addition to any
 nameservers in the NS records, when sending ``NOTIFY`` packets for the
 named zone. Default:
 
-::
+.. code-block:: SQL
 
     SELECT an.hostaddr
     FROM Zones z JOIN ZoneAlsoNotify an ON z.id = an.zone_id
@@ -667,7 +667,7 @@ oracle-zone-masters-query
 
 Return a list of masters for the zone specified by id. Default:
 
-::
+.. code-block:: SQL
 
     SELECT master
     FROM Zonemasters
@@ -679,7 +679,7 @@ oracle-is-zone-master-query
 Return a row if the specified host is a registered master for the named
 zone. Default:
 
-::
+.. code-block:: SQL
 
     SELECT zm.master
     FROM Zones z JOIN Zonemasters zm ON z.id = zm.zone_id
@@ -694,7 +694,7 @@ oracle-accept-supernotification-query
 If a supernotification should be accepted from ':ip', for the master
 nameserver ':ns', return a label for this supermaster. Default:
 
-::
+.. code-block:: SQL
 
     SELECT name
     FROM Supermasters
@@ -706,7 +706,7 @@ oracle-insert-slave-query
 A supernotification has just been accepted, and we need to create an
 entry for the new zone. Default:
 
-::
+.. code-block:: SQL
 
     INSERT INTO Zones (id, name, type)
     VALUES (zones_id_seq.NEXTVAL, lower(:zone), 'SLAVE')
@@ -718,7 +718,7 @@ oracle-insert-master-query
 We need to register the first master server for the newly created zone.
 Default:
 
-::
+.. code-block:: SQL
 
     INSERT INTO Zonemasters (zone_id, master)
     VALUES (:zoneid, :ip)
index 61d794ca3403ddd27212682b00290c64348c0ec1..49e74b4afc048a5bcb024812d9ca8e0e4d5966fc 100644 (file)
@@ -50,7 +50,7 @@ Usage
 The only configuration options for backend are remote-connection-string
 and remote-dnssec.
 
-::
+.. code-block:: ini
 
     remote-connection-string=<type>:<param>=<value>,<param>=<value>...
 
@@ -63,7 +63,7 @@ Unix connector
 
 parameters: path, timeout (default 2000ms)
 
-::
+.. code-block:: ini
 
     remote-connection-string=unix:path=/path/to/socket
 
@@ -72,7 +72,7 @@ Pipe connector
 
 parameters: command,timeout (default 2000ms)
 
-::
+.. code-block:: ini
 
     remote-connection-string=pipe:command=/path/to/executable,timeout=2000
 
@@ -81,7 +81,7 @@ HTTP connector
 
 parameters: url, url-suffix, post, post_json, timeout (default 2000ms)
 
-::
+.. code-block:: ini
 
     remote-connection-string=http:url=http://localhost:63636/dns,url-suffix=.php
 
@@ -107,7 +107,7 @@ ZeroMQ connector
 
 parameters: endpoint, timeout (default 2000ms)
 
-::
+.. code-block:: ini
 
     remote-connection-string=zeromq:endpoint=ipc:///tmp/tmp.sock
 
@@ -159,13 +159,13 @@ Example JSON/RPC
 
 Query:
 
-::
+.. code-block:: json
 
     {"method":"initialize", "parameters":{"command":"/path/to/something", "timeout":"2000", "something":"else"}}
 
 Response:
 
-::
+.. code-block:: json
 
     {"result":true}
 
@@ -191,13 +191,13 @@ Example JSON/RPC
 
 Query:
 
-::
+.. code-block:: json
 
     {"method":"lookup", "parameters":{"qtype":"ANY", "qname":"www.example.com.", "remote":"192.0.2.24", "local":"192.0.2.1", "real-remote":"192.0.2.24", "zone-id":-1}}
 
 Response:
 
-::
+.. code-block:: json
 
     {"result":[{"qtype":"A", "qname":"www.example.com", "content":"203.0.113.2", "ttl": 60}]}
 
@@ -241,13 +241,13 @@ Example JSON/RPC
 
 Query:
 
-::
+.. code-block:: json
 
     {"method":"list", "parameters":{"zonename":"example.com.","domain_id":-1}}
 
 Response (split into lines for ease of reading)
 
-::
+.. code-block:: json
 
     {"result":[
       {"qtype":"SOA", "qname":"example.com", "content":"dns1.icann.org. hostmaster.icann.org. 2012081600 7200 3600 1209600 3600", "ttl": 3600},
@@ -294,15 +294,15 @@ Example JSON/RPC
 
 Query:
 
-::
+.. code-block:: json
 
     {"method":"getbeforeandafternamesabsolute", "params":{"id":0,"qname":"www.example.com"}}
 
 Response:
 
-::
+.. code-block:: json
 
-    {result":{"before":"ns1","after":""}}
+    {"result":{"before":"ns1","after":""}}
 
 Example HTTP/RPC
 ''''''''''''''''
@@ -315,9 +315,9 @@ Query:
 
 Response:
 
-::
+.. code-block:: json
 
-    {result":{"before":"ns1","after":""}}
+    {"result":{"before":"ns1","after":""}}
 
 ``getAllDomainMetadata``
 ~~~~~~~~~~~~~~~~~~~~~~~~
@@ -326,22 +326,22 @@ Returns the value(s) for variable kind for zone name. You **must**
 always return something, if there are no values, you shall return empty
 set or false.
 
- *  Mandatory: No
- *  Parameters: name
- *  Reply: hash of key to array of strings
+*  Mandatory: No
+*  Parameters: name
+*  Reply: hash of key to array of strings
 
 Example JSON/RPC
 ''''''''''''''''
 
 Query:
 
-::
+.. code-block:: json
 
     {"method":"getalldomainmetadata", "parameters":{"name":"example.com"}}
 
 Response:
 
-::
+.. code-block:: json
 
     {"result":{"PRESIGNED":["0"]}}
 
@@ -380,13 +380,13 @@ Example JSON/RPC
 
 Query:
 
-::
+.. code-block:: json
 
     {"method":"getdomainmetadata", "parameters":{"name":"example.com.","kind":"PRESIGNED"}}
 
 Response:
 
-::
+.. code-block:: json
 
     {"result":["0"]}
 
@@ -424,13 +424,13 @@ Example JSON/RPC
 
 Query:
 
-::
+.. code-block:: json
 
     {"method":"setdomainmetadata","parameters":{"name":"example.com","kind":"PRESIGNED","value":["YES"]}}
 
 Response:
 
-::
+.. code-block:: json
 
     {"result":true}
 
@@ -476,13 +476,13 @@ Example JSON/RPC
 
 Query:
 
-::
+.. code-block:: json
 
     {"method":"getdomainkeys","parameters":{"name":"example.com."}}
 
 Response:
 
-::
+.. code-block:: json
 
     {"result":[{"id":1,"flags":256,"active":true,"content":"Private-key-format: v1.2
     Algorithm: 8 (RSASHA256)
@@ -538,7 +538,7 @@ Example JSON/RPC
 
 Query:
 
-::
+.. code-block:: json
 
     {"method":"adddomainkey", "parameters":{"key":{"id":1,"flags":256,"active":true,"content":"Private-key-format: v1.2
     Algorithm: 8 (RSASHA256)
@@ -553,7 +553,7 @@ Query:
 
 Response:
 
-::
+.. code-block:: json
 
     {"result":true}
 
@@ -602,13 +602,13 @@ Example JSON/RPC
 
 Query:
 
-::
+.. code-block:: json
 
-    {"method":"removedomainkey","parameters":"{"name":"example.com","id":1}}
+    {"method":"removedomainkey","parameters":{"name":"example.com","id":1}}
 
 Response:
 
-::
+.. code-block:: json
 
     {"result":true}
 
@@ -644,13 +644,13 @@ Example JSON/RPC
 
 Query:
 
-::
+.. code-block:: json
 
     {"method":"activatedomainkey","parameters":{"name":"example.com","id":1}}
 
 Response:
 
-::
+.. code-block:: json
 
     {"result":true}
 
@@ -686,13 +686,13 @@ Example JSON/RPC
 
 Query:
 
-::
+.. code-block:: json
 
     {"method":"deactivatedomainkey","parameters":{"name":"example.com","id":1}}
 
 Response:
 
-::
+.. code-block:: json
 
     {"result": true}
 
@@ -728,15 +728,15 @@ Example JSON/RPC
 
 Query:
 
-::
+.. code-block:: json
 
     {"method":"gettsigkey","parameters":{"name":"example.com."}}
 
 Response:
 
-::
+.. code-block:: json
 
-    {"result":{"algorithm":"hmac-md5","content:"kp4/24gyYsEzbuTVJRUMoqGFmN3LYgVDzJ/3oRSP7ys="}}
+    {"result":{"algorithm":"hmac-md5","content":"kp4/24gyYsEzbuTVJRUMoqGFmN3LYgVDzJ/3oRSP7ys="}}
 
 Example HTTP/RPC
 ''''''''''''''''
@@ -776,15 +776,15 @@ Example JSON/RPC
 
 Query:
 
-::
+.. code-block:: json
 
     {"method":"getdomaininfo","parameters":{"name":"example.com"}}
 
 Response:
 
-::
+.. code-block:: json
 
-    {"result":{id:1,"zone":"example.com","kind":"NATIVE","serial":2002010100}}
+    {"result":{"id":1,"zone":"example.com","kind":"NATIVE","serial":2002010100}}
 
 Example HTTP/RPC
 ''''''''''''''''
@@ -818,13 +818,13 @@ Example JSON/RPC
 
 Query:
 
-::
+.. code-block:: json
 
     {"method":"setnotified","parameters":{"id":1,"serial":2002010100}}
 
 Response:
 
-::
+.. code-block:: json
 
     {"result":true}
 
@@ -864,13 +864,13 @@ Example JSON/RPC
 
 Query:
 
-::
+.. code-block:: json
 
     {"method":"isMaster","parameters":{"name":"example.com","ip":"198.51.100.0.1"}}
 
 Response:
 
-::
+.. code-block:: json
 
     {"result":true}
 
@@ -909,19 +909,19 @@ Example JSON/RPC
 
 Query:
 
-::
+.. code-block:: json
 
     {"method":"superMasterBackend","parameters":{"ip":"198.51.100.0.1","domain":"example.com","nsset":[{"qtype":"NS","qname":"example.com","qclass":1,"content":"ns1.example.com","ttl":300,"auth":true},{"qtype":"NS","qname":"example.com","qclass":1,"content":"ns2.example.com","ttl":300,"auth":true}]}}
 
 Response:
 
-::
+.. code-block:: json
 
     {"result":true}
 
 Alternative response:
 
-::
+.. code-block:: json
 
     {"result":{"account":"my account","nameserver":"ns2.example.com"}}
 
@@ -970,13 +970,13 @@ Example JSON/RPC
 
 Query:
 
-::
+.. code-block:: json
 
     {"method":"createSlaveDomain","parameters":{"ip":"198.51.100.0.1","domain":"pirate.example.net"}}
 
 Response:
 
-::
+.. code-block:: json
 
     {"result":true}
 
@@ -1015,13 +1015,13 @@ Example JSON/RPC
 
 Query:
 
-::
+.. code-block:: json
 
     {"method":"replaceRRSet","parameters":{"domain_id":2,"qname":"replace.example.com","qtype":"A","trxid":1370416133,"rrset":[{"qtype":"A","qname":"replace.example.com","qclass":1,"content":"1.1.1.1","ttl":300,"auth":true}]}}
 
 Response:
 
-::
+.. code-block:: json
 
     {"result":true}
 
@@ -1062,13 +1062,13 @@ Example JSON/RPC
 
 Query:
 
-::
+.. code-block:: json
 
     {"method":"feedRecord","parameters":{"rr":{"qtype":"A","qname":"replace.example.com","qclass":1,"content":"127.0.0.1","ttl":300,"auth":true},"trxid":1370416133}}
 
 Response:
 
-::
+.. code-block:: json
 
     {"result":true}
 
@@ -1114,13 +1114,13 @@ Example JSON/RPC
 
 Query:
 
-::
+.. code-block:: json
 
     {"method":"feedEnts","parameters":{"domain_id":2,"trxid":1370416133,"nonterm":["_sip._udp","_udp"]}}
 
 Response:
 
-::
+.. code-block:: json
 
     {"result":true}
 
@@ -1161,13 +1161,13 @@ Example JSON/RPC
 
 Query:
 
-::
+.. code-block:: json
 
     {"method":"feedEnts3","parameters":{"domain_id":2,"domain":"example.com","times":1,"salt":"9642","narrow":false,"trxid":1370416356,"nonterm":["_sip._udp","_udp"]}}
 
 Response:
 
-::
+.. code-block:: json
 
     {"result":true}
 
@@ -1208,13 +1208,13 @@ Example JSON/RPC
 
 Query:
 
-::
+.. code-block:: json
 
     {"method":"startTransaction","parameters":{"trxid":1234,"domain_id":1,"domain":"example.com"}}
 
 Response:
 
-::
+.. code-block:: json
 
     {"result":true}
 
@@ -1255,13 +1255,13 @@ Example JSON/RPC
 
 Query:
 
-::
+.. code-block:: json
 
     {"method":"commitTransaction","parameters":{"trxid":1234}}
 
 Response:
 
-::
+.. code-block:: json
 
     {"result":true}
 
@@ -1299,13 +1299,13 @@ Example JSON/RPC
 
 Query:
 
-::
+.. code-block:: json
 
     {"method":"abortTransaction","parameters":{"trxid":1234}}
 
 Response:
 
-::
+.. code-block:: json
 
     {"result":true}
 
@@ -1344,13 +1344,13 @@ Example JSON/RPC
 
 Query:
 
-::
+.. code-block:: json
 
     {"method":"calculateSOASerial","parameters":{"domain":"unit.test","sd":{"qname":"unit.test","nameserver":"ns.unit.test","hostmaster":"hostmaster.unit.test","ttl":300,"serial":1,"refresh":2,"retry":3,"expire":4,"default_ttl":5,"domain_id":-1,"scopeMask":0}}}
 
 Response:
 
-::
+.. code-block:: json
 
     {"result":2013060501}
 
@@ -1391,13 +1391,13 @@ Example JSON/RPC
 
 Query:
 
-::
+.. code-block:: json
 
     {"method":"directBackendCmd","parameters":{"query":"PING"}}
 
 Response:
 
-::
+.. code-block:: json
 
     {"result":"PONG"}
 
@@ -1437,13 +1437,13 @@ Example JSON/RPC
 
 Query:
 
-::
+.. code-block:: json
 
     {"method": "getAllDomains", "parameters": {"include_disabled": true}}
 
 Response:
 
-::
+.. code-block:: json
 
     {"result":[{"id":1,"zone":"unit.test.","masters":["10.0.0.1"],"notified_serial":2,"serial":2,"last_check":1464693331,"kind":"native"}]}
 
@@ -1480,13 +1480,13 @@ Example JSON/RPC
 
 Query:
 
-::
+.. code-block:: json
 
     {"method":"searchRecords","parameters":{"pattern":"www.example*","maxResults":100}}
 
 Response:
 
-::
+.. code-block:: json
 
     {"result":[{"qtype":"A", "qname":"www.example.com", "content":"203.0.113.2", "ttl": 60}]}
 
@@ -1523,13 +1523,13 @@ Example JSON/RPC
 
 Query:
 
-::
+.. code-block:: json
 
     {"method": "getUpdatedMasters", "parameters": {}}
 
 Response:
 
-::
+.. code-block:: json
 
     {"result":[{"id":1,"zone":"unit.test.","masters":["10.0.0.1"],"notified_serial":2,"serial":2,"last_check":1464693331,"kind":"master"}]}
 
@@ -1561,7 +1561,7 @@ Scenario: SOA lookup via pipe, unix or zeromq connector
 
 Query:
 
-::
+.. code-block:: json
 
     { 
       "method": "lookup",
@@ -1574,7 +1574,7 @@ Query:
 
 Reply:
 
-::
+.. code-block:: json
 
     {
       "result": 
@@ -1599,7 +1599,7 @@ Query:
 
 Reply:
 
-::
+.. code-block:: json
 
     {
       "result":
index d230886809144e06510f521fa956adec3c954fc7..58783145701356b4ee6ad34dcac4a2c3f58ebac4 100644 (file)
@@ -442,9 +442,10 @@ PowerDNS Authoritative Server 4.0.0-rc2
 
 Released June 29th 2016
 
-**note**: rc1 was tagged in git but never officially released. Kees
-Monshouwer discovered an issue in the gmysql backend that would
-terminate the daemon on a connection error, this fixed in rc2.
+.. note::
+  rc1 was tagged in git but never officially released. Kees
+  Monshouwer discovered an issue in the gmysql backend that would
+  terminate the daemon on a connection error, this fixed in rc2.
 
 This Release Candidate adds IXFR consumption and fixes some issues with
 prepared statements:
index 0b37c2614c98c5384efa2e7d28fca77e756f1ea4..94cfe8f649bb429f1abff6d26014b7a489aa5f42 100644 (file)
@@ -922,7 +922,7 @@ Changelogs for 4.1.x
     :tags: Tools, Improvements
     :pullreq: 4584
 
-     Allow setting the account of a zone via pdnsutil (Tuxis Internet Engineering).
+    Allow setting the account of a zone via pdnsutil (Tuxis Internet Engineering).
 
   .. change::
     :tags: Internals, New Features
index 859a0c111cf61bdde8f3232804dd079777f9132a..84dba47bee9a6d7c186b10040e85bfd9044e8e59 100644 (file)
@@ -1159,3 +1159,13 @@ Changelogs for 4.2.x
     :tickets: 7357
 
     API: Add response-by-qtype and response-by-rcode on /statistics endpoint
+
+  .. change::
+    :tags: Improvements
+    :pullreq: 6021
+
+    Several improvements to processing of notifies.
+
+    * Turn off supermaster support by default (adds new setting).
+    * PowerDNS was wasting a lot of queries while processing notifies.
+    * Use comboaddress for IPs (was strings)
index a6246ea2db434dffffe360d57def4a11780fa9e8..2c16c085a46ecf396adcee00fd48abfb0568e562 100644 (file)
@@ -5042,7 +5042,7 @@ After the SOA of example.org was raised
 If however our slaves would ignore us, as some are prone to do, we can
 send some additional notifications
 
-::
+.. code-block:: shell
 
     $ sudo pdns_control notify example.org
     Added to queue
@@ -5055,7 +5055,7 @@ send some additional notifications
 Conversely, if PowerDNS needs to be reminded to retrieve a zone from a
 master, a command is provided
 
-::
+.. code-block:: shell
 
     $ sudo pdns_control retrieve forfun.net
     Added retrieval request for 'forfun.net' from master 212.187.98.67
index 4c2b36460940a83e256a83b15d1c872e0f8fafb3..6114a365608079ceb910d3520e80ef7638b3d5b4 100644 (file)
@@ -19,7 +19,6 @@ Do note that only the PowerDNS software is in scope for the HackerOne program, n
 
 Disclosure Policy
 ^^^^^^^^^^^^^^^^^
- - Let us know as soon as possible upon discovery of a potential security issue, and we'll make every effort to quickly resolve the issue.
- - Provide us a reasonable amount of time to resolve the issue before any disclosure to the public or a third-party.
- - We will always credit researchers in our :doc:`../security-advisories/index`.
-
+- Let us know as soon as possible upon discovery of a potential security issue, and we'll make every effort to quickly resolve the issue.
+- Provide us a reasonable amount of time to resolve the issue before any disclosure to the public or a third-party.
+- We will always credit researchers in our :doc:`../security-advisories/index`.
index dad7dcd01a1b3858b7b173c512f80349b9f15c36..85fa195e60fffd58baecc7c50d0cef0e3a67ae01 100644 (file)
@@ -19,7 +19,7 @@ automatically.
 
 As an example, securing an existing zone can be as simple as:
 
-::
+.. code-block:: shell
 
     $ pdnsutil secure-zone powerdnssec.org
 
index 09517b6439dc90b9b27aab8aa8ca38e1b0df9c81..239b67460a8f5d02c3ce92fac7b8c9454e02ee4f 100644 (file)
@@ -14,7 +14,7 @@ is used for verification. The private part is used for signing and is
 never published.
 
 To make sure that the internet knows that the key that is used for
-signing is the authentic key, confirmation can be gotten from the parent
+signing is the authentic key, confirmation can be obtained from the parent
 zone. This means that to become operational, a zone operator will have
 to publish a representation of the signing key to the parent zone, often
 a ccTLD or a gTLD. This representation is called a DS record, and is a
index 53d6a412e56c4fafdc10da6104a3b933504eff2b..0ba6656c8716b648e688017d39b35877374f5de2 100644 (file)
@@ -24,21 +24,21 @@ all the changes in database schemas as shown in the :doc:`upgrade documentation
 
 To deliver a correctly signed zone with the :ref:`dnssec-pdnsutil-dnssec-defaults`, invoke:
 
-::
+.. code-block:: shell
 
     pdnsutil secure-zone ZONE
 
 To view the DS records for this zone (to transfer to the parent zone),
 run
 
-::
+.. code-block:: shell
 
     pdnsutil show-zone ZONE
 
 For a more traditional setup with a KSK and a ZSK, use the following
 sequence of commands:
 
-::
+.. code-block:: shell
 
     pdnsutil add-zone-key ZONE ksk 2048 active rsasha256
     pdnsutil add-zone-key ZONE zsk 1024 active rsasha256
@@ -85,7 +85,7 @@ The ``pdnsutil`` tool features the option to import zone keys in the
 industry standard private key format, version 1.2. To import an existing
 KSK, use
 
-::
+.. code-block:: shell
 
     pdnsutil import-zone-key ZONE FILENAME ksk
 
index f6679dafbd3fe8ebe5f10dfb8603b34823f7bc91..c03759263eba10d35c389d2b86acd618a516dbe3 100644 (file)
@@ -32,6 +32,9 @@ DNSSEC data using the original keys.
 Such a single replicated database requires no further attention beyond
 monitoring already required during non-DNSSEC operations.
 
+Please note that the ALIAS record type is
+:ref:`not supported <alias_and_dnssec>` in this mode.
+
 Records, Keys, signatures, hashes within PowerDNS in online signing mode
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -52,13 +55,16 @@ As described above, there are several ways in which DNSSEC can deny the
 existence of a record, and this setting, which is also stored away from zone
 records, lives with the DNSSEC keying material.
 
+.. _dnssec-nsec-modes:
+
 (Hashed) Denial of Existence
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 PowerDNS supports unhashed secure denial-of-existence using NSEC
 records. These are generated with the help of the (database) backend,
 which needs to be able to supply the 'previous' and 'next' records in
-canonical ordering.
+canonical ordering. NSEC is the default mode for secured zones in
+PowerDNS.
 
 The Generic SQL Backends have fields that allow them to supply these
 relative record names.
@@ -69,11 +75,15 @@ the help of some additional calculations.
 
 NSEC3 in 'broad' or 'inclusive' mode works with the aid of the backend,
 where the backend should be able to supply the previous and next domain
-names in hashed order.
+names in hashed order. This is the default mode for NSEC3 in PowerDNS.
 
 NSEC3 in 'narrow' mode uses additional hashing calculations to provide
-hashed secure denial-of-existence 'on the fly', without further
-involving the database.
+hashed secure denial-of-existence 'on the fly' per
+`RFC 7129 <https://tools.ietf.org/html/rfc7129>`__, without further
+involving the database. This mode will make PowerDNS to send out "white
+lies" and prevents zone enumeration, but these responses require online
+signing capabilities by all nameservers and therefore denies incoming
+AXFRs for zones in this mode.
 
 .. _dnssec-signatures:
 
@@ -122,12 +132,15 @@ PowerDNS also serves the DNSKEY records in live-signing mode. Their TTL
 is derived from the SOA records *minimum* field. When using NSEC3, the
 TTL of the NSEC3PARAM record is also derived from that field.
 
+.. _dnssec_presigned_records:
+
 Pre-signed records
 ------------------
 
 In this mode, PowerDNS serves zones that already contain DNSSEC records.
-Such zones can either be slaved from a remote master, or can be signed
-using tools like OpenDNSSEC, ldns-signzone, and dnssec-signzone.
+Such zones can either be slaved from a remote master in online signing
+mode, or can be pre-signed using tools like OpenDNSSEC, ldns-signzone,
+and dnssec-signzone.
 
 Even in this mode, PowerDNS will synthesize NSEC(3) records itself
 because of its architecture. RRSIGs of these NSEC(3) will still need to
@@ -162,13 +175,14 @@ The signing and hashing algorithms are described in :ref:`dnssec-online-signing`
 BIND-mode operation
 -------------------
 
-The :doc:`bindbackend <../backends/bind>` can manage keys in an
-SQLite3 database without launching a separate gsqlite3 backend.
+The :doc:`BIND backend <../backends/bind>` can manage keys and other
+DNSSEC-related :doc:`domain metadata <../domainmetadata>` in an SQLite3
+database without launching a separate gsqlite3 backend.
 
-To use this mode, add
-``bind-dnssec-db=/var/db/bind-dnssec-db.sqlite3`` to pdns.conf, and run
-``pdnsutil create-bind-db /var/db/bind-dnssec-db.sqlite3``. Then,
-restart PowerDNS.
+To use this mode, run
+``pdnsutil create-bind-db /var/db/bind-dnssec-db.sqlite3`` and set
+:ref:`setting-bind-dnssec-db` in pdns.conf to the path of the created
+database. Then, restart PowerDNS.
 
 .. note::
   This SQLite database is different from the database used for the regular :doc:`SQLite 3 backend <../backends/generic-sqlite3>`.
@@ -182,14 +196,14 @@ Hybrid BIND-mode operation
 --------------------------
 
 PowerDNS can also operate based on 'BIND'-style zone & configuration
-files. This 'bindbackend' has full knowledge of DNSSEC but has no
+files. This 'BIND backend' has full knowledge of DNSSEC but has no
 native way of storing keying material.
 
 However, since PowerDNS supports operation with multiple simultaneous
 backends, this is not a problem.
 
 In hybrid mode, keying material and zone records are stored in different
-backends. This allows for 'bindbackend' operation in full DNSSEC mode.
+backends. This allows for 'BIND backend' operation in full DNSSEC mode.
 
 To benefit from this mode, include at least one database-based backend
 in the :ref:`setting-launch` statement. See the :doc:`backend specific documentation <../backends/index>`
index a0687bcfc6461ac18aa90826e8373b16b70573b5..c5e4b328ca2077362615649498b45cc47c819dda 100644 (file)
@@ -19,7 +19,7 @@ zone.
 Going insecure
 --------------
 
-::
+.. code-block:: shell
 
     pdnsutil disable-dnssec ZONE
 
@@ -28,19 +28,21 @@ Going insecure
   parent zone will make the zone BOGUS. Make sure the parent zone removes
   the DS record *before* going insecure.
 
+.. _dnssec-operational-nsec-modes-params:
+
 Setting the NSEC modes and parameters
 -------------------------------------
 
 As stated earlier, PowerDNS uses NSEC by default. If you want to use
 NSEC3 instead, issue:
 
-::
+.. code-block:: shell
 
-    pdnsutil set-nsec3 ZONE [PARAMETERS]
+    pdnsutil set-nsec3 ZONE [PARAMETERS] ['narrow']
 
 e.g.
 
-::
+.. code-block:: shell
 
     pdnsutil set-nsec3 example.net '1 0 1 ab'
 
@@ -51,12 +53,16 @@ The quoted part is the content of the NSEC3PARAM records, as defined in
 -  Flags, set to ``1`` for :rfc:`NSEC3 Opt-out <5155#section-6>`, this best
    set as ``0``
 -  Number of iterations of the hash function, read :rfc:`RFC 5155, Section
-   10.3 <5155#section-10.3>` for recommendations
+   10.3 <5155#section-10.3>` for recommendations. Limited by the
+   :ref:`setting-max-nsec3-iterations` setting.
 -  Salt to apply during hashing, in hexadecimal, or ``-`` to use no salt
 
+Optionally, NSEC3 can be set to 'narrow' mode. For more information refer
+to :ref:`dnssec-nsec-modes`.
+
 To convert a zone from NSEC3 to NSEC operations, run:
 
-::
+.. code-block:: shell
 
     pdnsutil unset-nsec3 ZONE
 
@@ -203,6 +209,16 @@ In some settings, having such (private) keying material available online
 is considered undesirable. In this case, consider running in pre-signed
 mode.
 
+A slightly more complex approach is running a *hidden* master in simple
+online signing mode, but on a highly secured system unreachable for the
+public. Internet-connected slaves can then transfer the zones pre-signed
+from this master over a secure private network. This topology offers
+substantial security benefits with regards to key material while
+maintaining ease of daily operation by PowerDNS's features in online
+mode.
+
+See also :ref:`dnssec_presigned_records`.
+
 Performance
 -----------
 
index b2836a1570bec72a8f3f0cf6dd0698a7e188d055..9c35f65eaacd43f739397eb4b2fc45859c3c99fb 100644 (file)
@@ -16,7 +16,7 @@ DNSSEC Defaults
 
 Since version 4.0, when securing a zone using ``pdnsutil secure-zone``,
 a single ECDSA (algorithm 13, ECDSAP256SHA256) key is generated that is
-used as ZSK. Before 4.0, 3 RSA (algorithm 8) keys were generated, one as
+used as CSK. Before 4.0, 3 RSA (algorithm 8) keys were generated, one as
 the KSK and two ZSKs. As all keys are online in the database, it made no
 sense to have this split-key setup.
 
index 89f77246bc02679f7dccb3402e16cb56876b04f7..2325d0955377aafc142943a48b6a42de681edfc3 100644 (file)
@@ -27,38 +27,32 @@ To test this feature, a software HSM can be used. It is **not
 recommended** to use this in production.
 
 Instructions on how to setup SoftHSM to work with the feature after
-compilation on ubuntu/debian (tested with Ubuntu 12 and 14). -
-``apt-get install softhsm p11-kit opensc`` - create directory
-/etc/pkcs11/modules - Add file called 'softhsm' there with (on newer
-versions, use softhsm.module)
-``module: /home/cmouse/softhsm/lib/softhsm/libsofthsm.so     managed: yes``
-- Verify it works: ``p11-kit -l`` - Create at least two tokens (ksk and
-zsk) with (slot-number starts from 0)
+compilation on Ubuntu/Debian (tested with Ubuntu 12.04 and 14.04).
 
-::
+- ``apt-get install softhsm p11-kit opensc``
+- create directory ``/etc/pkcs11/modules``
+- create a file ``softhsm`` (``softhsm.module`` on newer versions),
+  with contents:::
 
-    ```
-    sudo softhsm --init-token --slot slot-number --label zone-ksk|zone-zsk --pin some-pin --so-pin another-pin
-    ```
-
--  Using pkcs11-tool, initialize your new keys.
+    module: /home/cmouse/softhsm/lib/softhsm/libsofthsm.so     managed: yes
 
-   ::
+- Verify that it works: ``p11-kit -l``
+- Create at least two tokens (ksk and zsk) with (slot-number starts from 0)::
 
-       sudo pkcs11-tool --module=/home/cmouse/softhsm/lib/softhsm/libsofthsm.so -l -p some-pin -k --key-type RSA:2048 -a zone-ksk|zone-zsk --slot-index slot-number
+    sudo softhsm --init-token --slot slot-number --label zone-ksk|zone-zsk --pin some-pin --so-pin another-pin
 
--  Assign the keys using (note that token label is not necessarily same
-   as object label, see p11-kit -l)
+-  Using pkcs11-tool, initialize your new keys.::
 
-   ::
+    sudo pkcs11-tool --module=/home/cmouse/softhsm/lib/softhsm/libsofthsm.so -l -p some-pin -k --key-type RSA:2048 -a zone-ksk|zone-zsk --slot-index slot-number
 
-       pdnsutil hsm assign zone rsasha256 ksk|zsk softhsm token-label pin zone-ksk|zsk
+-  Assign the keys using (note that token label is not necessarily same
+   as object label, see p11-kit -l)::
 
--  Verify that everything worked, you should see valid data there
+    pdnsutil hsm assign zone rsasha256 ksk|zsk softhsm token-label pin zone-ksk|zsk
 
-   ::
+-  Verify that everything worked, you should see valid data there::
 
-       pdnsutil show-zone zone
+    pdnsutil show-zone zone
 
 -  SoftHSM signatures are fast enough to be used in live environment.
 
@@ -66,84 +60,69 @@ Using CryptAS
 -------------
 
 Instructions on how to use CryptAS
-```Athena IDProtect Key USB Token V2J`` <http://www.cryptoshop.com/products/smartcards/idprotect-key-j-laser.html>`__
-Smart Card token on Ubuntu 14. - install the manufacturer\`s support
-software on your system and initialize the Smart Card token as per
-instructions (do not use PIV). - apt-get install p11-kit opensc - create
-directory /etc/pkcs11/modules - Add file called 'athena.module' with
-content
+`Athena IDProtect Key USB Token V2J <http://www.cryptoshop.com/products/smartcards/idprotect-key-j-laser.html>`_
+Smart Card token on Ubuntu 14.04.
 
-::
+- Install the manufacturer's support software on your system and initialize
+  the Smart Card token as per instructions (do not use PIV).
+- ``apt-get install p11-kit opensc``
+- Create directory ``/etc/pkcs11/modules``.
+- Create file named ``athena.module`` with contents::
 
-    ```
     module: /lib64/libASEP11.so
     managed: yes
-    ```
-
--  Verify it worked, it should resemble output below. do not continue if
-   this does not show up.
-
-   ::
-
-       $ p11-kit -l
-       athena: /lib64/libASEP11.so
-           library-description: ASE Cryptoki
-           library-manufacturer: Athena Smartcard Solutions
-           library-version: 3.1
-           token: IDProtect#0A50123456789
-               manufacturer: Athena Smartcard Solutions
-               model: IDProtect
-               serial-number: 0A50123456789
-               hardware-version: 1.0
-               firmware-version: 1.0
-               flags:
-                      rng
-                      login-required
-                      user-pin-initialized
-                      token-initialized
-
--  Using pkcs11-tool, initialize your new keys. After this IDProtect
-   Manager no longer can show your token certificates and keys, at least
-   on version v6.23.04.
-
-   ::
-
-       pkcs11-tool --module=/home/cmouse/softhsm/lib/softhsm/libsofthsm.so -l -p some-pin -k --key-type RSA:2048 -a zone-ksk
-       pkcs11-tool --module=/home/cmouse/softhsm/lib/softhsm/libsofthsm.so -l -p some-pin -k --key-type RSA:2048 -a zone-zsk
-
--  Verify that keys are there.
-
-   ::
-
-       $ pkcs11-tool --module=/lib64/libASEP11.so -l -p some-pin -O
-       Using slot 0 with a present token (0x0)
-       Public Key Object; RSA 2048 bits
-         label:      zone-ksk
-         Usage:      encrypt, verify, wrap
-       Public Key Object; RSA 2048 bits
-         label:      zone-zsk
-         Usage:      encrypt, verify, wrap
-       Private Key Object; RSA
-         label:      zone-ksk
-         Usage:      decrypt, sign, unwrap
-       Private Key Object; RSA
-         label:      zone-zsk
-         Usage:      decrypt, sign, unwrap
-
--  Assign the keys using
-
-   ::
-
-       pdnsutil hsm assign zone rsasha256 ksk|zsk athena IDProtect#0A50123456789 pin zone-ksk|zsk
-
--  Verify that everything worked, you should see valid data there.
-
-   ::
-
-       pdnsutil show-zone zone
-
--  Note that the physical token is pretty slow, so you have to use it as
-   hidden master. It has been observed to produce about
-   1.5signatures/second.
-
 
+- Verify it worked, it should resemble output below. Do not continue if
+  this does not show up. ::
+
+    $ p11-kit -l
+    athena: /lib64/libASEP11.so
+        library-description: ASE Cryptoki
+        library-manufacturer: Athena Smartcard Solutions
+        library-version: 3.1
+        token: IDProtect#0A50123456789
+            manufacturer: Athena Smartcard Solutions
+            model: IDProtect
+            serial-number: 0A50123456789
+            hardware-version: 1.0
+            firmware-version: 1.0
+            flags:
+                  rng
+                  login-required
+                  user-pin-initialized
+                  token-initialized
+
+- Using pkcs11-tool, initialize your new keys. After this IDProtect
+  Manager no longer can show your token certificates and keys, at least
+  on version v6.23.04. ::
+
+    pkcs11-tool --module=/home/cmouse/softhsm/lib/softhsm/libsofthsm.so -l -p some-pin -k --key-type RSA:2048 -a zone-ksk
+    pkcs11-tool --module=/home/cmouse/softhsm/lib/softhsm/libsofthsm.so -l -p some-pin -k --key-type RSA:2048 -a zone-zsk
+
+- Verify that keys are there::
+
+    $ pkcs11-tool --module=/lib64/libASEP11.so -l -p some-pin -O
+    Using slot 0 with a present token (0x0)
+    Public Key Object; RSA 2048 bits
+      label:      zone-ksk
+      Usage:      encrypt, verify, wrap
+    Public Key Object; RSA 2048 bits
+      label:      zone-zsk
+      Usage:      encrypt, verify, wrap
+    Private Key Object; RSA
+      label:      zone-ksk
+      Usage:      decrypt, sign, unwrap
+    Private Key Object; RSA
+      label:      zone-zsk
+      Usage:      decrypt, sign, unwrap
+
+- Assign the keys using::
+
+    pdnsutil hsm assign zone rsasha256 ksk|zsk athena IDProtect#0A50123456789 pin zone-ksk|zsk
+
+- Verify that everything worked, you should see valid data there. ::
+
+    pdnsutil show-zone zone
+
+- Note that the physical token is pretty slow, so you have to use it as
+  hidden master. It has been observed to produce about 1.5 signatures/second.
index 94ed0b0fc06ff02c37012f68252e9c77aceb4c24..301358fe20b7999b5da4a9eeb007e7c76eaa642d 100644 (file)
@@ -90,7 +90,7 @@ Per zone settings
 -----------------
 
 For permissions, a number of per zone settings are available via the
-:doc:`domain metadata `<domainmetadata>`.
+:doc:`domain metadata <domainmetadata>`.
 
 .. _metadata-allow-dnsupdate-from:
 
@@ -98,7 +98,7 @@ ALLOW-DNSUPDATE-FROM
 ~~~~~~~~~~~~~~~~~~~~
 
 This setting has the same function as described in the configuration
-options (See ref:`above <dnsupdate-configuration-options>`). Only one item is
+options (See :ref:`above <dnsupdate-configuration-options>`). Only one item is
 allowed per row, but multiple rows can be added. An example:
 
 ::
@@ -120,19 +120,19 @@ This setting allows you to set the TSIG key required to do an DNS
 update. If you have GSS-TSIG enabled, you can use Kerberos principals
 here. An example, using :program:`pdnsutil` to create the key:
 
-::
+.. code-block:: shell
 
-    pdnsutil generate-tsig-key test hmac-md5
+    pdnsutil generate-tsig-key test hmac-md5
     Create new TSIG key test hmac-md5 kp4/24gyYsEzbuTVJRUMoqGFmN3LYgVDzJ/3oRSP7ys=
-    
+
+::
+
     sql> insert into tsigkeys (name, algorithm, secret) values ('test', 'hmac-md5', 'kp4/24gyYsEzbuTVJRUMoqGFmN3LYgVDzJ/3oRSP7ys=');
     sql> select id from domains where name='example.org';
     5
     sql> insert into domainmetadata (domain_id, kind, content) values (5, 'TSIG-ALLOW-DNSUPDATE', 'test');
 
-An example of how to use a TSIG key with the :program:`nsupdate` command:
-
-::
+An example of how to use a TSIG key with the :program:`nsupdate` command::
 
     nsupdate <<!
     server <ip> <port>
@@ -152,7 +152,7 @@ the IP(-range) of the updater still needs to be allowed via ``ALLOW-DNSUPDATE-FR
 FORWARD-DNSUPDATE
 ~~~~~~~~~~~~~~~~~
 
-See `Configuration options <dnsupdate-configuration-options>` for what it does,
+See :ref:`Configuration options <dnsupdate-configuration-options>` for what it does,
 but per domain.
 
 ::
@@ -252,14 +252,14 @@ Setting up dhcpd
 We're going to use a TSIG key for security. We're going to generate a
 key using the following command:
 
-::
+.. code-block:: shell
 
     dnssec-keygen -a hmac-md5 -b 128 -n USER dhcpdupdate
 
 This generates two files (Kdhcpdupdate.*.key and
 Kdhcpdupdate.*.private). You're interested in the .key file:
 
-::
+.. code-block:: shell
 
     # ls -l Kdhcp*
     -rw------- 1 root root  53 Aug 26 19:29 Kdhcpdupdate.+157+20493.key
@@ -338,7 +338,7 @@ dynamic updates from **dhcpd**.
 Enabled DNS update (:rfc:`2136`) support functionality in PowerDNS by adding
 the following to the PowerDNS configuration file (pdns.conf).
 
-::
+.. code-block:: ini
 
     dnsupdate=yes
     allow-dnsupdate-from=
@@ -454,20 +454,21 @@ each record at a time and you can approve or reject any or all.
 
 The object has following methods available:
 
-- DNSName getQName() - name to update
-- DNSName getZonename() - zone name
-- int getQType() - record type, it can be 255(ANY) for delete.
-- ComboAddress getLocal() - local socket address
-- ComboAddress getRemote() - remote socket address
-- Netmask getRealRemote() - real remote address (or netmask if EDNS Subnet is used)
-- DNSName getTsigName() - TSIG **key** name (you can assume it is validated here)
-- string getPeerPrincipal() - Return peer principal name (user@DOMAIN, service/machine.name@DOMAIN, host/MACHINE$@DOMAIN)
+- ``DNSName getQName()`` - name to update
+- ``DNSName getZonename()`` - zone name
+- ``int getQType()`` - record type, it can be 255(ANY) for delete.
+- ``ComboAddress getLocal()`` - local socket address
+- ``ComboAddress getRemote()`` - remote socket address
+- ``Netmask getRealRemote()`` - real remote address (or netmask if EDNS Subnet is used)
+- ``DNSName getTsigName()`` - TSIG **key** name (you can assume it is validated here)
+- ``string getPeerPrincipal()`` - Return peer principal name (``user@DOMAIN``,
+  ``service/machine.name@DOMAIN``, ``host/MACHINE$@DOMAIN``)
 
 There are many same things available as in recursor Lua scripts, but
-there is also resolve(qname, qtype) which returns array of records.
+there is also ``resolve(qname, qtype)`` which returns array of records.
 Example:
 
-::
+.. code-block:: lua
 
     resolve("www.google.com", pdns.A)
 
@@ -477,7 +478,7 @@ resolve does not perform local lookup.
 
 Simple example script:
 
-.. code:: lua
+.. code-block:: lua
 
     --- This script is not suitable for production use
 
index c3c6ece7fc2afd99310b328210826844be0c14fb..926628037ff7ca33a8c6efeda30433bce4eb096c 100644 (file)
@@ -30,7 +30,7 @@ that tries to allow all potential slaves in.
 
 Example:
 
-::
+.. code-block:: shell
 
     pdnsutil set-meta powerdns.org ALLOW-AXFR-FROM AUTO-NS 2001:db8::/48
 
@@ -38,10 +38,10 @@ Each ACL has its own row in the database:
 
 ::
 
-    select id from domains where name='example.com';
+    sql> select id from domains where name='example.com';
     7
-    insert into domainmetadata (domain_id, kind, content) values (7,'ALLOW-AXFR-FROM','AUTO-NS');
-    insert into domainmetadata (domain_id, kind, content) values (7,'ALLOW-AXFR-FROM','2001:db8::/48');
+    sql> insert into domainmetadata (domain_id, kind, content) values (7,'ALLOW-AXFR-FROM','AUTO-NS');
+    sql> insert into domainmetadata (domain_id, kind, content) values (7,'ALLOW-AXFR-FROM','2001:db8::/48');
 
 To disallow all IP's, except those explicitly allowed by domainmetadata
 records, add ``allow-axfr-ips=`` to ``pdns.conf``.
@@ -82,14 +82,14 @@ When notifying this domain, also notify this nameserver (can occur
 multiple times). The nameserver may have contain an optional port
 number. e.g.:
 
-::
+.. code-block:: shell
 
     pdnsutil set-meta powerdns.org ALSO-NOTIFY 192.0.2.1:5300
     pdnsutil set-meta powerdns.org ALLOW-AXFR-FROM 2001:db8:53::1
 
 Or in SQL:
 
-::
+.. code-block:: SQL
 
     insert into domainmetadata (domain_id, kind, content) values (7,'ALSO-NOTIFY','192.0.2.1:5300');
     insert into domainmetadata (domain_id, kind, content) values (7,'ALLOW-AXFR-FROM','2001:db8:53::1');
index de3f630674fd5788cb0dfb70bed727afe9748ec8..37a3c1c36d77e941ca32cc5805e0751335ec5591 100644 (file)
@@ -47,10 +47,10 @@ Next, it defines that the rest of the record is the actual certificate
 methods are supplied for all DNS data types in use.
 
 Now add ``TLSARecordContent::report()`` to
-```reportOtherTypes()`` <https://github.com/PowerDNS/pdns/blob/5a3409cbb4314b84f1171a69c7337386568fa886/pdns/dnsrecords.cc#L594>`__.
+`reportOtherTypes() <https://github.com/PowerDNS/pdns/blob/5a3409cbb4314b84f1171a69c7337386568fa886/pdns/dnsrecords.cc#L594>`__.
 
 And that's it. For completeness, add TLSA and 52 to the QType enum in
-```qtype.hh`` <https://github.com/PowerDNS/pdns/blob/5a3409cbb4314b84f1171a69c7337386568fa886/pdns/qtype.hh#L116>`__,
+`qtype.hh <https://github.com/PowerDNS/pdns/blob/5a3409cbb4314b84f1171a69c7337386568fa886/pdns/qtype.hh#L116>`__,
 which makes it easier to refer to the TLSA record in code if so
 required.
 
index 19e2e7946d66300f0f6afcdfa47fbcfca83c3e56..2efb6b63bacdbf6c201da0a5a4967dfef6e139fb 100644 (file)
@@ -9,7 +9,7 @@ Server 4.1.0 or higher, set the :ref:`setting-resolver`
 setting to an existing resolver and enable
 :ref:`setting-expand-alias`:
 
-::
+.. code-block:: ini
 
     resolver=[::1]:5300
     expand-alias=yes
@@ -53,6 +53,8 @@ records unless you AXFR regularly.
   Authoritative Server 4.0.x. Hence, ALIAS records are always expanded on
   a direct A or AAAA query.
 
+.. _alias_and_dnssec:
+
 ALIAS and DNSSEC
 ----------------
 
index 2c663a3f3451e92f9f8b12d352189e5c574f459b..bca3a9cee1f5b25dc1e3ab9320bb6f5b2e9f83da 100644 (file)
@@ -6,7 +6,7 @@ is called 'gmysql', and needs to be configured in ``pdns.conf``. Add the
 following lines, adjusted for your local setup (specifically, you may
 not want to use the 'root' user):
 
-::
+.. code-block:: ini
 
     launch=gmysql
     gmysql-host=127.0.0.1
@@ -46,9 +46,24 @@ Example: configuring MySQL
 --------------------------
 
 Connect to MySQL as a user with sufficient privileges and issue the
-following commands:
+following commands below if you are running the 4.2 or master version of PowerDNS:
+
+Please find `the 4.1 schema on GitHub <https://github.com/PowerDNS/pdns/blob/rel/auth-4.1.x/modules/gmysqlbackend/schema.mysql.sql>`_.
+
 
 .. literalinclude:: ../../modules/gmysqlbackend/schema.mysql.sql
+   :language: SQL
+
+We recommend you add the following MySQL statements as well. These will add
+foreign key constraints to the tables in order to automate deletion of records, key
+material, and other information upon deletion of a domain from the
+domains table. These will only work on the InnoDB storage engine, but if you
+followed our guide so far, that's exactly the engine we are using.
+
+The following SQL does the job:
+
+.. literalinclude:: ../../modules/gmysqlbackend/enable-foreign-keys.mysql.sql
+
 
 Now we have a database and an empty table. PowerDNS should now be able
 to launch in monitor mode and display no errors:
@@ -64,12 +79,11 @@ to launch in monitor mode and display no errors:
     15:39:55 [gMySQLbackend] MySQL connection succeeded
 
 In a different shell, a sample query sent to the server should now
-return quickly without data:
+return quickly *without* data:
 
-::
+.. code-block:: shell
 
-    $ dig +short www.example.com @127.0.0.1
-    $
+    $ dig +short www.example.com @127.0.0.1  # should print nothing
 
 .. warning::
   When debugging DNS problems, don't use ``host``. Please use
@@ -110,7 +124,7 @@ Now we need to add some records to our database (in a separate shell):
 
 If we now requery our database, ``www.example.com`` should be present:
 
-::
+.. code-block:: shell
 
     $ dig +short www.example.com @127.0.0.1
     192.0.2.10
@@ -223,7 +237,11 @@ test your nameserver as clients expect the nameserver to live on port
 Unable to launch, no backends configured for querying
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-PowerDNS did not find the ``launch=gmysql`` instruction in pdns.conf.
+You currently don't have a backend configured in the configuration file.
+Add a :ref:`setting-launch` statement for the backend you want to use.
+
+If you are following this guide and using a MySQL database as a backend,
+please add the ``launch=gmysql`` instruction to pdns.conf.
 
 Multiple IP addresses on your server, PowerDNS sending out answers on the wrong one, Massive amounts of 'recvfrom gave error, ignoring: Connection refused'
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
index f50ccc0728b393090ca9640ed4195dd6ef8bb04d..ee48f23549a477680eaf340f406d7a2ee2f8bcb8 100644 (file)
@@ -13,7 +13,7 @@ both a KSK and a CSK.
 To start the rollover, add an **active** new KSK to the zone
 (example.net in this case):
 
-::
+.. code-block:: shell
 
     pdnsutil add-zone-key example.net ksk active
 
@@ -24,7 +24,7 @@ If this zone is of the type 'MASTER', increase the SOA serial. The
 rollover is now in the "New KSK" stage. Retrieve the DS record(s) for
 the new KSK:
 
-::
+.. code-block:: shell
 
     pdnsutil show-zone example.net
 
@@ -38,7 +38,7 @@ rollover is now in the "DS Change" state and can continue to the
   The key-id for the old KSK is shown in the output of
   ``pdnsutil show-zone example.net``.
 
-::
+.. code-block:: shell
 
     pdnsutil remove-zone-key example.net KEY-ID
 
index c43536add733b7f85ace86af184f4bce96d4e67d..bca561d6aeb019c1bf92b899ad9722baf42bec5f 100644 (file)
@@ -50,7 +50,7 @@ should be removed:
 To make the authoritative server listen on the local loopback address
 and port 5300 change the following in ``pdns.conf``:
 
-::
+.. code-block:: ini
 
     local-ipv6=
     local-address=127.0.0.1
@@ -87,7 +87,7 @@ Authoritative Server. This is done using the
 ``recursor.conf``. The domains should be forwarded to 127.0.0.1:5300
 (the new address and port of the Authoritative Server):
 
-::
+.. code-block:: ini
 
     forward-zones=private.example.com=127.0.0.1:5300
     forward-zones+=another.example.com=127.0.0.1:5300
@@ -133,7 +133,7 @@ should be removed:
 To make the authoritative server listen on the local loopback address
 and port 5300 change the following in ``pdns.conf``:
 
-::
+.. code-block:: ini
 
     local-ipv6=
     local-address=127.0.0.1
@@ -153,7 +153,7 @@ Configure the recursor to listen on the local loopback interface on a
 different port than the Authoritative Server. Set the following in
 ``recursor.conf``:
 
-::
+.. code-block:: ini
 
     local-address=127.0.0.1
     local-port=5301
@@ -164,7 +164,7 @@ Authoritative Server. This is done using the
 ``recursor.conf``. The domains should be forwarded to 127.0.0.1:5300
 (the new address and port of the Authoritative Server):
 
-::
+.. code-block:: ini
 
     forward-zones=private.example.com=127.0.0.1:5300
     forward-zones+=another.example.com=127.0.0.1:5300
index 7794a77f58d19bbc0e96f498b09e1504efedbda6..87251ceefca03929b29a74a85ecdd7e338d35ac2 100644 (file)
@@ -40,13 +40,13 @@ Assuming your instance is called ``myinstance`` and
 ``pdns-myinstance.conf`` exists in the configuration directory, the
 following command will start the service:
 
-::
+.. code-block:: shell
 
     systemctl start pdns@myinstance.service
 
 Similarly you can enable it at boot:
 
-::
+.. code-block:: shell
 
     systemctl enable pdns@myinstance.service
 
index a139bd3196290fa7f8f56c6952416cb9e05277f5..aa7631a07ccffbe110f15a96f7b7ced6879336f3 100644 (file)
@@ -12,7 +12,7 @@ First, create a new inactive ZSK for the zone (if one already exists,
 you can skip this step), we add an ECDSA 256 bit key (algorithm 13)
 here:
 
-::
+.. code-block:: shell
 
     pdnsutil add-zone-key example.net zsk inactive ecdsa256
 
@@ -23,7 +23,7 @@ database and wait for the slaves to pickup the zone change.
 To change the RRSIGs on your records, the new key must be made active.
 Note: you can get the key-ids with ``pdnsutil show-zone example.net``:
 
-::
+.. code-block:: shell
 
     pdnsutil activate-zone-key example.net new-key-id
     pdnsutil deactivate-zone-key example.net previous-key-id
@@ -33,7 +33,7 @@ the "new RRSIGs" stage of the roll over.
 
 The last step is to remove the old key from the completely:
 
-::
+.. code-block:: shell
 
     pdnsutil remove-zone-key example.net previous-key-id
 
index 83b3db55f195b03462bdcc636109920aee176aeb..5509e21d569ea16d8a5abe698db03589a6df5a98 100644 (file)
@@ -36,7 +36,7 @@ Modifying the key material
   X-Api-Key: secret
   Content-Type: application/json
 
-  {"key": "mytsigkey, "key": "GQNyFy1QagMUarHmiSgsIJajghdTGJGVcN5TRVwgbclzxGyhQR1uYLCOyJ/uj9uj12jyeLwzJuW12wCI9PYv7Q=="}
+  {"name": "mytsigkey", "key": "GQNyFy1QagMUarHmiSgsIJajghdTGJGVcN5TRVwgbclzxGyhQR1uYLCOyJ/uj9uj12jyeLwzJuW12wCI9PYv7Q=="}
 
 .. code-block:: http
 
index f288312e4911c0ccc9d769244e7884ff23f38821..f20a956684f5927a0df8bec5bb83443652f79a79 100644 (file)
@@ -6,9 +6,9 @@ supports a large number of backends. These backends can either be plain
 zone files or be more dynamic in nature.
 
 PowerDNS has the concepts of 'backends'. A backend is a datastore that
-the server will consult that contains DNS records (and some meta-data).
+the server will consult that contains DNS records (and some metadata).
 The backends range from database backends (:doc:`MySQL <backends/generic-mysql>`, :doc:`PostgreSQL <backends/generic-postgresql>`, :doc:`Oracle <backends/oracle>`)
-and :doc:`Bind-zonefiles <backends/bind>` to :doc:`co-processes <backends/pipe>` and :doc:`JSON API's <backends/remote>`.
+and :doc:`BIND zone files <backends/bind>` to :doc:`co-processes <backends/pipe>` and :doc:`JSON API's <backends/remote>`.
 
 Multiple backends can be enabled in the configuration by using the
 :ref:`setting-launch` option. Each backend can be configured separately.
@@ -20,9 +20,9 @@ This documentation is also available as a `PDF document <PowerDNS-Authoritative.
 Getting Started
 ---------------
 
- * :doc:`Install the Authoritative Server <installation>`
- * :doc:`Configure the Server <settings>`
- * :doc:`Configure the backend(s) <backends/index>`
+* :doc:`Install the Authoritative Server <installation>`
+* :doc:`Configure the Server <settings>`
+* :doc:`Configure the backend(s) <backends/index>`
 
 Getting Support
 ---------------
@@ -31,9 +31,9 @@ You may also help others (please do).
 
 Public support is available via several different channels:
 
-  * This documentation
-  * `The mailing list <https://www.powerdns.com/mailing-lists.html>`_
-  * ``#powerdns`` on `irc.oftc.net <irc://irc.oftc.net/#powerdns>`_
+* This documentation
+* `The mailing list <https://www.powerdns.com/mailing-lists.html>`_
+* ``#powerdns`` on `irc.oftc.net <irc://irc.oftc.net/#powerdns>`_
 
 The PowerDNS company can provide help or support you in private as well.
 For first class and rapid support, please contact powerdns.support@powerdns.com, or see the `.com website <https://www.powerdns.com/support-services-consulting.html>`__.
index 6e1753d8eca4ee6083c011a78eb770e47206de0b..2b25b06f492a374fd2829d004d382e6a84eeb03e 100644 (file)
@@ -17,17 +17,17 @@ Debian-based Systems
 PowerDNS Authoritative Server is available through the
 `apt <https://packages.debian.org/pdns-server>`__ system.
 
-::
+.. code-block:: shell
 
-    # apt-get install pdns-server
+    $ sudo apt-get install pdns-server
 
 Debian splits the backends into `several different
 packages <https://packages.debian.org/pdns-backend>`__, install the
 required backend as follows:
 
-::
+.. code-block:: shell
 
-    # apt-get install pdns-backend-$backend
+    $ sudo apt-get install pdns-backend-$backend
 
 Redhat-based Systems
 ~~~~~~~~~~~~~~~~~~~~
@@ -39,15 +39,15 @@ or from `the PowerDNS repositories <https://repo.powerdns.com>`__:
 
 Add either to your list of repositories and install PowerDNS by issuing:
 
-::
+.. code-block:: shell
 
-    # yum install pdns
+    $ sudo yum install pdns
 
 The different backends can be installed using
 
-::
+.. code-block:: shell
 
-    # yum install pdns-backend-$backend
+    $ sudo yum install pdns-backend-$backend
 
 FreeBSD
 ~~~~~~~
@@ -57,13 +57,13 @@ PowerDNS Authoritative Server is available through the
 
 For the package:
 
-::
+.. code-block:: shell
 
-    # pkg install dns/powerdns
+    $ sudo pkg install dns/powerdns
 
 To have your system build the port:
 
-::
+.. code-block:: shell
 
     cd /usr/ports/dns/powerdns/ && make install clean
 
@@ -72,7 +72,7 @@ Mac OS X
 
 PowerDNS Authoritative Server is available through Homebrew:
 
-::
+.. code-block:: shell
 
     $ brew install pdns
 
index d180c76b5230121c603884c8c24baad117ede1e6..3b30327dab42ed0a7d821cbd03c99cdfe3af5158 100644 (file)
@@ -188,17 +188,17 @@ Reverse DNS functions
   
   **Formatting options:**
 
-    - ``%1%`` to ``%4%`` are individual octets
-        - Example record query: ``1.0.0.127.in-addr.arpa`` 
-        - ``%1%`` = 127
-        - ``%2%`` = 0
-        - ``%3%`` = 0
-        - ``%4%`` = 1
-    - ``%5%`` joins the four decimal octets together with dashes
-        - Example: ``%5%.static.example.com`` is equivalent to ``%1%-%2%-%3%-%4%.static.example.com``
-    - ``%6%`` converts each octet from decimal to hexadecimal and joins them together
-        - Example: A query for ``15.0.0.127.in-addr.arpa`` 
-        - ``%6`` would be ``7f00000f`` (127 is 7f, and 15 is 0f in hexadecimal)
+  - ``%1%`` to ``%4%`` are individual octets
+      - Example record query: ``1.0.0.127.in-addr.arpa``
+      - ``%1%`` = 127
+      - ``%2%`` = 0
+      - ``%3%`` = 0
+      - ``%4%`` = 1
+  - ``%5%`` joins the four decimal octets together with dashes
+      - Example: ``%5%.static.example.com`` is equivalent to ``%1%-%2%-%3%-%4%.static.example.com``
+  - ``%6%`` converts each octet from decimal to hexadecimal and joins them together
+      - Example: A query for ``15.0.0.127.in-addr.arpa``
+      - ``%6`` would be ``7f00000f`` (127 is 7f, and 15 is 0f in hexadecimal)
 
   **NOTE:** At the current time, only forward dotted format works with :func:`createForward` (i.e. ``127.0.0.1.static.example.com``)
   
@@ -255,18 +255,18 @@ Reverse DNS functions
   
   Formatting options:
    
-    - ``%1%`` to ``%32%`` are individual characters (nibbles)
-        - **Example PTR record query:** ``a.0.0.0.1.0.0.2.ip6.arpa``
-        - ``%1%`` = 2
-        - ``%2%`` = 0
-        - ``%3%`` = 0
-        - ``%4%`` = 1
-    - ``%33%`` converts the compressed address format into a dashed format, e.g. ``2001:a::1`` to ``2001-a--1``
-    - ``%34%`` to ``%41%`` represent the 8 uncompressed 2-byte chunks
-        - **Example:** PTR query for ``2001:a:b::123``
-        - ``%34%`` - returns ``2001`` (chunk 1)
-        - ``%35%`` - returns ``000a`` (chunk 2)
-        - ``%41%`` - returns ``0123`` (chunk 8)
+  - ``%1%`` to ``%32%`` are individual characters (nibbles)
+      - **Example PTR record query:** ``a.0.0.0.1.0.0.2.ip6.arpa``
+      - ``%1%`` = 2
+      - ``%2%`` = 0
+      - ``%3%`` = 0
+      - ``%4%`` = 1
+  - ``%33%`` converts the compressed address format into a dashed format, e.g. ``2001:a::1`` to ``2001-a--1``
+  - ``%34%`` to ``%41%`` represent the 8 uncompressed 2-byte chunks
+      - **Example:** PTR query for ``2001:a:b::123``
+      - ``%34%`` - returns ``2001`` (chunk 1)
+      - ``%35%`` - returns ``000a`` (chunk 2)
+      - ``%41%`` - returns ``0123`` (chunk 8)
   
   **NOTE:** At the current time, only dashed compressed format works for this function (i.e. ``2001-a-b--1.static6.example.com``)
   
index 3c2a9b0864ac0bcfea0ac550d4086cd461910c3f..d44dbe1a0b03bd8043b921acd45b4db39d114be2 100644 (file)
@@ -200,7 +200,7 @@ explicitly, either globally (``enable-lua-records``) or per zone
 Reference
 ---------
 
- .. toctree::
+.. toctree::
   :maxdepth: 2
 
   functions
index 56156e269769e87f8802d1399c9646498ab54c26..7d79eeec03a2896ce3bc06b7a029c8633386a0f6 100644 (file)
@@ -73,14 +73,14 @@ ComboAddressSet objects
 We provide a convenient object class that can store unique ComboAddresses in no particular
 order and allows fast retrieval of individual elements based on their values
 
-  .. code-block:: lua
-
-    addr = newCA("1.2.3.4")
-    myset = newCAS()
-    myset:add(addr)
-    if myset:check(addr) then -- prints "found!"
-      print('found!')
-    end
+.. code-block:: lua
+
+  addr = newCA("1.2.3.4")
+  myset = newCAS()
+  myset:add(addr)
+  if myset:check(addr) then -- prints "found!"
+    print('found!')
+  end
 
 Functions and methods of a ``ComboAddressSet``
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
index dbf23422a453b2e3fa55c21a8206b70c71a7d6fb..2ab827e1d879835415d261803a91bb6e82c3edda 100644 (file)
@@ -1,7 +1,7 @@
 LUA Reference
 -------------
 
- .. toctree::
+.. toctree::
   :maxdepth: 2
 
   comboaddress
index 89e1f0f6ec52c76278f0a1f6957728eabc24b8d3..c9f28d7f5b369d96bcbf13a091facecb7c2715f0 100644 (file)
@@ -10,16 +10,16 @@ Other functions
   :param string message: The message to log
   :param int loglevel: The urgency level of the message. Defaults to `pdns.loglevels.Warning`
 
- You can use the following constants as log levels :
-
-   - `pdns.loglevels.Alert`
-   - `pdns.loglevels.Critical`
-   - `pdns.loglevels.Debug`
-   - `pdns.loglevels.Emergency`
-   - `pdns.loglevels.Info`
-   - `pdns.loglevels.Notice`
-   - `pdns.loglevels.Warning`
-   - `pdns.loglevels.Error`
 You can use the following constants as log levels :
+
+  - `pdns.loglevels.Alert`
+  - `pdns.loglevels.Critical`
+  - `pdns.loglevels.Debug`
+  - `pdns.loglevels.Emergency`
+  - `pdns.loglevels.Info`
+  - `pdns.loglevels.Notice`
+  - `pdns.loglevels.Warning`
+  - `pdns.loglevels.Error`
 
 .. function:: pdnsrandom([maximum])
 
index 510d33828331db9d164ca2488b03a9ccf4591f5a..8a836a404086242c2a3a61cb4c322c1c9cf99113 100644 (file)
@@ -4,7 +4,7 @@ dumresp
 Synopsis
 --------
 
-**dumresp** *LOCAL-ADDRESS* *LOCAL-PORT* *NUMBER-OF-PROCESSES*
+**dumresp** *LOCAL-ADDRESS* *LOCAL-PORT* *NUMBER-OF-PROCESSES* [tcp]
 
 Description
 -----------
@@ -18,7 +18,8 @@ the port.
 Options
 -------
 
-None
+tcp: Whether to listen and accept TCP connections in addition to
+UDP packets. Defaults to false.
 
 See also
 --------
index 121a696ef2cd73b2a6af3db2b5a22849a983922a..5feca55ce42af9d5ebf62f74365b24735c6ff1ed 100644 (file)
@@ -118,7 +118,9 @@ Options
   When logging, each log-line contains the UUID of the request, this allows finding errors caused by certain requests.
   With 'none', nothing is logged except for errors.
   With 'normal' (the default), one line per request is logged in the style of the common log format::
+
     [NOTICE] [webserver] 46326eef-b3ba-4455-8e76-15ec73879aa3 127.0.0.1:57566 "GET /metrics HTTP/1.1" 200 1846
+
   with 'detailed', the full requests and responses (including headers) are logged along with the regular log-line from 'normal'.
 
 See also
index 0bac0c9492b7ecd7b27bb2d3c35c6b7798d73ca4..737c663fabfd36b681f8f82f614d686f0f7eafd0 100644 (file)
@@ -30,25 +30,25 @@ Commands
 bind-add-zone *DOMAIN* *FILENAME*
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-When using the bindbackend, add a zone. This zone is added in-memory
+When using the BIND backend, add a zone. This zone is added in-memory
 and served immediately. Note that this does not add the zone to the
 bind-config file. *FILENAME* must be an absolute path.
 
 bind-domain-status [*DOMAIN*...]
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-When using the bindbackend, list status of all domains. Optionally,
+When using the BIND backend, list status of all domains. Optionally,
 append *DOMAIN*\ s to get the status of specific zones.
 
 bind-list-rejects
 ^^^^^^^^^^^^^^^^^
 
-When using the bindbackend, get a list of all rejected domains.
+When using the BIND backend, get a list of all rejected domains.
 
 bind-reload-now *DOMAIN* [*DOMAIN*...]
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-When using the bindbackend, immediately reload *DOMAIN* from disk.
+When using the BIND backend, immediately reload *DOMAIN* from disk.
 
 ccounts
 ^^^^^^^
@@ -124,7 +124,7 @@ rediscover
 ^^^^^^^^^^
 
 Instructs backends that new domains may have appeared in the
-database, or, in the case of the Bind backend, in named.conf.
+database, or, in the case of the BIND backend, in named.conf.
 
 reload
 ^^^^^^
index 3b02ccfbc75d3e3011c41bb237477b4bc35cbe84..dbff966cf0840e2d5ca96942ef4342c359eaa8ee 100644 (file)
@@ -62,6 +62,8 @@ disable-dnssec *ZONE*
 export-zone-dnskey *ZONE* *KEY-ID*
     Export to standard output DNSKEY and DS of key with key id *KEY-ID*
     within zone called *ZONE*.
+export-zone-ds *ZONE*
+    Export to standard output all KSK DS records for *ZONE*.
 export-zone-key *ZONE* *KEY-ID*
     Export to standard output full (private) key with key id *KEY-ID*
     within zone called *ZONE*. The format used is compatible with BIND
@@ -80,7 +82,7 @@ import-zone-key *ZONE* *FILE* {**KSK**,\ **ZSK**}
     the added key.
 remove-zone-key *ZONE* *KEY-ID*
     Remove a key with id *KEY-ID* from a zone called *ZONE*.
-set-nsec3 *ZONE* '*HASH-ALGORITHM* *FLAGS* *ITERATIONS* *SALT*' [**narrow**]
+set-nsec3 *ZONE* ['*HASH-ALGORITHM* *FLAGS* *ITERATIONS* *SALT*'] [**narrow**]
     Sets NSEC3 parameters for this zone. The quoted parameters are 4
     values that are used for the the NSEC3PARAM record and decide how
     NSEC3 records are created. The NSEC3 parameters must be quoted on
@@ -88,14 +90,18 @@ set-nsec3 *ZONE* '*HASH-ALGORITHM* *FLAGS* *ITERATIONS* *SALT*' [**narrow**]
     *FLAGS* to 1 enables NSEC3 opt-out operation. Only do this if you
     know you need it. For *ITERATIONS*, please consult RFC 5155, section
     10.3. And be aware that a high number might overload validating
-    resolvers. The *SALT* is a hexadecimal string encoding the bits for
-    the salt, or - to use no salt. Setting **narrow** will make PowerDNS
-    send out "white lies" about the next secure record. Instead of
-    looking it up in the database, it will send out the hash + 1 as the
-    next secure record. A sample commandline is: "pdnsutil set-nsec3
-    powerdnssec.org '1 1 1 ab' narrow". **WARNING**: If running in
-    RSASHA1 mode (algorithm 5 or 7), switching from NSEC to NSEC3 will
-    require a DS update in the parent zone.
+    resolvers and that a limit can be set with ``max-nsec3-iterations``
+    in ``pdns.conf``. The *SALT* is a hexadecimal string encoding the bits
+    for the salt, or - to use no salt. Setting **narrow** will make PowerDNS
+    send out "white lies" (RFC 7129) about the next secure record to
+    prevent zone enumeration. Instead of looking it up in the database,
+    it will send out the hash + 1 as the next secure record. Narrow mode
+    requires online signing capabilities by the nameserver and therefore
+    zone transfers are denied. If only the zone is provided as argument,
+    the 4-parameter quoted string defaults to ``'1 0 1 ab'``. A sample
+    commandline is: ``pdnsutil set-nsec3 powerdnssec.org '1 1 1 ab' narrow``.
+    **WARNING**: If running in RSASHA1 mode (algorithm 5 or 7), switching
+    from NSEC to NSEC3 will require a DS update in the parent zone.
 unset-nsec3 *ZONE*
     Converts *ZONE* to NSEC operations. **WARNING**: If running in
     RSASHA1 mode (algorithm 5 or 7), switching from NSEC to NSEC3 will
index 8748435a187bc0f2a28f5935cb5cc0543dfaff98..b9c9d3ff1dae8d9308c749a1a206968bef295721 100644 (file)
@@ -9,10 +9,10 @@ Synopsis
 Description
 -----------
 
-:program:`zone2json` parses Bind named.conf files and zonefiles and outputs
+:program:`zone2json` parses BIND named.conf files and zonefiles and outputs
 JSON on standard out, which can then be fed to the PowerDNS API.
 
-:program:`zone2json` understands the Bind master file extension ``$GENERATE``
+:program:`zone2json` understands the BIND master file extension ``$GENERATE``
 and will also honour ``$ORIGIN`` and ``$TTL``.
 
 Options
@@ -21,7 +21,7 @@ Options
 INPUT Options
 -------------
 
---named-conf=<PATH>        Read *PATH* to get the bind configuration
+--named-conf=<PATH>        Read *PATH* to get the BIND configuration
 --zone=<PATH>              Parse only the zone file at *PATH* Conflicts with ``--named-conf`` parameter.
 --zone-name=<NAME>         When parsing a single zone without $ORIGIN statement, set *ZONE* as the zone name.
 
index 369ab8da8ab18e0a7cce3adfb5ed500e6e824175..d827dd0e087d513519ab14de19ef0ff4512a773e 100644 (file)
@@ -9,7 +9,7 @@ Synopsis
 Description
 -----------
 
-:program:`zone2ldap` is a program that converts bind zonefiles to ldif format
+:program:`zone2ldap` is a program that converts BIND zonefiles to ldif format
 which can inserted to an LDAP server.
 
 Options
@@ -19,7 +19,7 @@ Options
 --basedn=<DN>                   Base DN to store objects below
 --dnsttl                        Add dnsttl attribute to every entry
 --layout=<layout>               How to arrange entries in the directory ("simple" or "tree")
---named-conf=<PATH>             Path to a Bind named.conf to parse
+--named-conf=<PATH>             Path to a BIND named.conf to parse
 --resume                        Continue after errors
 --verbose                       Verbose comments on operation
 --zone-file=<PATH>              Zone file to parse
index cdd8cf06bfa6badcdd525fac8321b0573d18a2af..0cb19727848560b12cd478741b02e280d50d6406 100644 (file)
@@ -9,10 +9,10 @@ Synopsis
 Description
 -----------
 
-:program:`zone2sql` parses Bind named.conf files and zonefiles and outputs SQL
+:program:`zone2sql` parses BIND named.conf files and zonefiles and outputs SQL
 on standard out, which can then be fed to your database.
 
-:program:`zone2sql` understands the Bind master file extension ``$GENERATE``
+:program:`zone2sql` understands the BIND master file extension ``$GENERATE``
 and will also honour ``$ORIGIN`` and ``$TTL``.
 
 For backends supporting slave operation there is also an option to keep
@@ -27,7 +27,7 @@ Options
 INPUT Options
 -------------
 
---named-conf=<PATH>         Read *PATH* to get the bind configuration
+--named-conf=<PATH>         Read *PATH* to get the BIND configuration
 --zone=<PATH>               Parse only the zone file at *PATH* Conflicts with **--named-conf** parameter.
 --zone-name=<NAME>          When parsing a single zone without $ORIGIN statement, set *ZONE* as
                             the zone name.
index bfcab43a164feaed5987f6251332d79327e1acda..6c6dec24eb4e4a031c1f125a47e84cd6eab047f1 100644 (file)
@@ -28,7 +28,7 @@ In order to migrate to a Generic SQL backend, add all your domains to
 the 'domains' table with the IP of your current master. On your current
 master, make sure that this master allows AXFRs to this new slave.
 
-::
+.. code-block:: SQL
 
     INSERT INTO domains (name,type,master) VALUES ('example.net', 'SLAVE', '198.51.100.101');
 
@@ -36,7 +36,7 @@ Then start PowerDNS and wait for all the zones to be transferred. If
 this server is the new :ref:`master <master-operation>`, change the type of
 domain in the database:
 
-::
+.. code-block:: SQL
 
     UPDATE domains set type='MASTER' where type='SLAVE';
 
@@ -45,7 +45,7 @@ and restart PowerDNS.
 
 Or, if you want to use :ref:`native <native-operation>`:
 
-::
+.. code-block:: SQL
 
     UPDATE domains set type='NATIVE' where type='SLAVE';
 
@@ -86,10 +86,10 @@ From zonefiles to PowerDNS
 Using the BIND backend
 ~~~~~~~~~~~~~~~~~~~~~~
 
-To use the bind backend, set ``launch=bind`` and
+To use the BIND backend, set ``launch=bind`` and
 ``bind-config=/path/to/named.conf`` in your ``pdns.conf``. Note that
 PowerDNS will not honor any options from named.conf, it will only use
-the ``zone`` statements. See the :doc:`Bind backend <backends/bind>`
+the ``zone`` statements. See the :doc:`BIND backend <backends/bind>`
 documentation for more information.
 
 To a Generic SQL backend
@@ -104,7 +104,7 @@ Using ``zone2sql``
 
 To migrate, the ``zone2sql`` tool is provided. This tool parses a BIND
 ``named.conf`` file and zone files and outputs SQL on standard out,
-which can then be fed to your database. It understands the Bind master
+which can then be fed to your database. It understands the BIND master
 file extension ``$GENERATE`` and will also honour ``$ORIGIN`` and
 ``$TTL``.
 
@@ -116,7 +116,7 @@ See `its manpage <manpages/zone2sql.1>` for more information.
 
 An example call to ``zone2sql`` could be:
 
-::
+.. code-block:: shell
 
     zone2sql --named-conf=/path/to/named.conf --gmysql | mysql -u pdns -p pdns-db
 
@@ -148,7 +148,7 @@ Syntax: ``pdnsutil b2b-migrate OLD NEW``
 
 This tool lets you migrate data from one backend to another, it moves
 all data, including zones, metadata and crypto keys (if present). Some
-example use cases are moving from Bind style zonefiles to SQL based, or
+example use cases are moving from BIND-style zonefiles to SQL based, or
 other way around, or moving from MyDNS to gMySQL.
 
 Prerequisites
index bf76cf28e970bf44bc9448f7210daf0247cbf6e2..9eafb750f4e6d196737e2438d7274aff6a34e98c 100644 (file)
@@ -132,7 +132,7 @@ updated and if so, retransfering it.
 All backends which implement this feature must make sure that they can
 handle transactions so as to not leave the zone in a half updated state.
 MySQL configured with either BerkeleyDB or InnoDB meets this
-requirement, as do PostgreSQL and Oracle. The Bindbackend implements
+requirement, as do PostgreSQL and Oracle. The BIND backend implements
 transaction semantics by renaming files if and only if they have been
 retrieved completely and parsed correctly.
 
@@ -187,6 +187,10 @@ can not serve IXFR updates.
 Supermaster: automatic provisioning of slaves
 ---------------------------------------------
 
+.. versionchanged:: 4.2.0
+  Supermaster support needs to be explicitly enabled with the
+  :ref:`setting-supermaster` setting.
+
 PowerDNS can recognize so called 'supermasters'. A supermaster is a host
 which is master for domains and for which we are to be a slave. When a
 master (re)loads a domain, it sends out a notification to its slaves.
@@ -201,12 +205,13 @@ itself as a slave for that zone.
 Before a supermaster notification succeeds, the following conditions
 must be met:
 
- - :ref:`setting-supermaster` support must be enabled
- - The supermaster must carry a SOA record for the notified domain
- - The supermaster IP must be present in the 'supermaster' table
- - The set of NS records for the domain, as retrieved by the slave from the supermaster, must include the name that goes with the IP address in the supermaster table
- - If your master sends signed NOTIFY it will mark that TSIG key as the TSIG key used for retrieval as well
- - If you turn off :ref:`setting-allow-unsigned-supermaster`, then your supermaster(s) are required to sign their notifications.
+
+- :ref:`setting-superslave` support must be enabled
+- The supermaster must carry a SOA record for the notified domain
+- The supermaster IP must be present in the 'supermaster' table
+- The set of NS records for the domain, as retrieved by the slave from the supermaster, must include the name that goes with the IP address in the supermaster table
+- If your master sends signed NOTIFY it will mark that TSIG key as the TSIG key used for retrieval as well
+- If you turn off :ref:`setting-allow-unsigned-supermaster`, then your supermaster(s) are required to sign their notifications.
 
 .. warning::
   If you use another PowerDNS server as master and have
@@ -246,7 +251,7 @@ the ``domainmetadata`` table for the domain. Supposing the domain we
 want has an ``id`` of 3, the following SQL statement will enable the Lua
 script ``my.lua`` for that domain:
 
-::
+.. code-block:: SQL
 
     INSERT INTO domainmetadata (domain_id, kind, content) VALUES (3, "LUA-AXFR-SCRIPT", "/lua/my.lua");
 
@@ -270,7 +275,7 @@ incoming record as normal.
 
 Consider the following simple example:
 
-::
+.. code-block:: lua
 
         function axfrfilter(remoteip, zone, record)
 
index 42b1ed8322a54bde5e676e69709d4ef7c1556f0a..9900b9673662794e5ad7a93c2a86f0d863c5f172 100644 (file)
@@ -138,7 +138,7 @@ commands:
 -  ``mrtg``: Dump statistics in mrtg format. See the performance
    :ref:`counters` documentation.
 
- .. note::
+.. note::
   Packages provided by Operating System vendors might support
   different or less commands.
 
index 21c25746b9623d971bfb9ac5e44616ae2d37d3a9..f72b334decce38915156e8c95a1a23663599d6d3 100644 (file)
@@ -1,4 +1,4 @@
-@       86400   IN  SOA pdns-public-ns1.powerdns.com. pieter\.lexis.powerdns.com. 2019041201 10800 3600 604800 10800
+@       86400   IN  SOA pdns-public-ns1.powerdns.com. pieter\.lexis.powerdns.com. 2019042601 10800 3600 604800 10800
 @       3600    IN  NS  pdns-public-ns1.powerdns.com.
 @       3600    IN  NS  pdns-public-ns2.powerdns.com.
 ; Auth
@@ -301,3 +301,4 @@ recursor-4.0.0_beta1-1pdns.jessie.raspbian.security-status 60 IN TXT "3 Upgrade
 ; dnsdist
 dnsdist-1.3.3.security-status                              60 IN TXT "1 OK"
 dnsdist-1.4.0-alpha1.security-status                       60 IN TXT "1 OK"
+dnsdist-1.4.0-alpha2.security-status                       60 IN TXT "1 OK"
index 0c82fd2349be062112539689c93d448ca22106ec..cd4165284919ca1a1be7408f0664673623bff8a7 100644 (file)
@@ -37,7 +37,7 @@ Alternatively, on Linux systems with a working iptables setup,
 'responses' sent to the PowerDNS Authoritative Server 'question' address
 can be blocked by issuing:
 
-::
+.. code-block:: shell
 
           iptables -I INPUT -p udp --dst $AUTHIP --dport 53 \! -f -m u32 --u32 "0>>22&0x3C@8>>15&0x01=1" -j DROP 
         
@@ -57,7 +57,7 @@ announcement.
 For those running custom PowerDNS versions, just applying this patch may
 be easier:
 
-::
+.. code-block:: diff
 
     --- pdns/common_startup.cc   (revision 2326)
     +++ pdns/common_startup.cc   (working copy)
index eab1244d270046cbe771b179dcf3c2b2f772292c..5d35c0ddea625c82c687f7bd819291b43b2acd55 100644 (file)
@@ -19,7 +19,7 @@ means ``yes``.
 ``8bit-dns``
 ------------
 
--  Allow 8 bit dns queries
+-  Boolean
 -  Default: no
 
 .. versionadded:: 4.0.0
@@ -58,6 +58,21 @@ Allow DNS updates from these IP ranges. Set to empty string to honour ``ALLOW-DN
 Allow AXFR NOTIFY from these IP ranges. Setting this to an empty string
 will drop all incoming notifies.
 
+.. _setting-allow-recursion:
+
+``allow-recursion``
+-------------------
+
+-  IP ranges, separated by commas
+-  Default: 0.0.0.0/0
+
+.. deprecated:: 4.1.0
+  Recursion has been removed, see :doc:`guides/recursion`
+
+By specifying ``allow-recursion``, recursion can be restricted to
+netmasks specified. The default is to allow recursion from everywhere.
+Example: ``allow-recursion=198.51.100.0/24, 10.0.0.0/8, 192.0.2.4``.
+
 .. _setting-allow-unsigned-notify:
 
 ``allow-unsigned-notify``
@@ -84,21 +99,6 @@ signed by valid TSIG signature for the zone.
 Turning this off requires all supermaster notifications to be signed by
 valid TSIG signature. It will accept any existing key on slave.
 
-.. _setting-allow-recursion:
-
-``allow-recursion``
--------------------
-
--  IP ranges, separated by commas
--  Default: 0.0.0.0/0
-
-.. deprecated:: 4.1.0
-  Recursion has been removed, see :doc:`guides/recursion`
-
-By specifying ``allow-recursion``, recursion can be restricted to
-netmasks specified. The default is to allow recursion from everywhere.
-Example: ``allow-recursion=198.51.100.0/24, 10.0.0.0/8, 192.0.2.4``.
-
 .. _setting-also-notify:
 
 ``also-notify``
@@ -119,7 +119,8 @@ the list in :ref:`setting-only-notify`.
 -  Boolean
 -  Default: yes
 
-.. versionchanged:: 4.0.1, was 'no' before.
+.. versionchanged:: 4.0.1
+  was 'no' before.
 
 Answer questions for the ANY on UDP with a truncated packet that refers
 the remote server to TCP. Useful for mitigating reflection attacks.
@@ -155,7 +156,7 @@ Static pre-shared authentication key for access to the REST API.
 
 .. versionadded:: 4.0.0
 .. versionchanged:: 4.2.0
-This setting has been removed in 4.2.0.
+  This setting has been removed in 4.2.0.
 
 Disallow data modification through the REST API when set.
 
@@ -181,6 +182,31 @@ Also AXFR a zone from a master with a lower serial.
 
 Seconds to store packets in the :ref:`packet-cache`.
 
+.. _setting-carbon-instance:
+
+``carbon-instance``
+-------------------
+
+-  String
+-  Default: auth
+
+.. versionadded:: 4.2.0
+
+Set the instance or third string of the metric key. Be careful not to include
+any dots in this setting, unless you know what you are doing.
+See :ref:`metricscarbon`
+
+.. _setting-carbon-interval:
+
+``carbon-interval``
+-------------------
+
+-  Integer
+-  Default: 30
+
+If sending carbon updates, this is the interval between them in seconds.
+See :ref:`metricscarbon`.
+
 .. _setting-carbon-namespace:
 
 ``carbon-namespace``
@@ -207,20 +233,6 @@ If sending carbon updates, if set, this will override our hostname. Be
 careful not to include any dots in this setting, unless you know what
 you are doing. See :ref:`metricscarbon`
 
-.. _setting-carbon-instance:
-
-``carbon-instance``
--------------------
-
--  String
--  Default: auth
-
-.. versionadded:: 4.2.0
-
-Set the instance or third string of the metric key. Be careful not to include
-any dots in this setting, unless you know what you are doing.
-See :ref:`metricscarbon`
-
 .. _setting-carbon-server:
 
 ``carbon-server``
@@ -235,17 +247,6 @@ carbon-server=10.10.10.10,10.10.10.20.
 You may specify an alternate port by appending :port, ex:
 127.0.0.1:2004. See :ref:`metricscarbon`.
 
-.. _setting-carbon-interval:
-
-``carbon-interval``
--------------------
-
--  Integer
--  Default: 30
-
-If sending carbon updates, this is the interval between them in seconds.
-See :ref:`metricscarbon`.
-
 .. _setting-chroot:
 
 ``chroot``
@@ -324,7 +325,7 @@ The value of :ref:`metadata-api-rectify` if it is not set on the zone.
 .. _setting-default-ksk-algorithm:
 
 ``default-ksk-algorithm``
---------------------------
+-------------------------
 
 -  String
 -  Default: ecdsa256
@@ -360,16 +361,6 @@ to enable DNSSEC. Must be one of:
 The default keysize for the KSK generated with :doc:`pdnsutil secure-zone <dnssec/pdnsutil>`.
 Only relevant for algorithms with non-fixed keysizes (like RSA).
 
-.. _setting-default-soa-name:
-
-``default-soa-name``
---------------------
-
--  String
--  Default: a.misconfigured.powerdns.server
-
-Name to insert in the SOA record if none set in the backend.
-
 .. _setting-default-soa-edit:
 
 ``default-soa-edit``
@@ -402,6 +393,16 @@ Overrides :ref:`setting-default-soa-edit`
 
 Mail address to insert in the SOA record if none set in the backend.
 
+.. _setting-default-soa-name:
+
+``default-soa-name``
+--------------------
+
+-  String
+-  Default: a.misconfigured.powerdns.server
+
+Name to insert in the SOA record if none set in the backend.
+
 .. _setting-default-ttl:
 
 ``default-ttl``
@@ -617,14 +618,15 @@ Entropy source file to use.
 If this is enabled, ALIAS records are expanded (synthesised to their
 A/AAAA).
 
-If this is disabled (the default), ALIAS records will not expanded and
+If this is disabled (the default), ALIAS records will not be expanded and
 the server will will return NODATA for A/AAAA queries for such names.
 
-**note**: :ref:`setting-resolver` must also be set for ALIAS
-expansion to work!
+.. note::
+  :ref:`setting-resolver` must also be set for ALIAS expansion to work!
 
-**note**: In PowerDNS Authoritative Server 4.0.x, this setting did not
-exist and ALIAS was always expanded.
+.. note::
+  In PowerDNS Authoritative Server 4.0.x, this setting did not exist and
+  ALIAS was always expanded.
 
 .. _setting-forward-dnsupdate:
 
@@ -682,7 +684,7 @@ Which backends to launch and order to query them in. Launches backends.
 In its most simple form, supply all backends that need to be launched.
 e.g.
 
-::
+.. code-block:: ini
 
     launch=bind,gmysql,remote
 
@@ -690,7 +692,7 @@ If you find that you need to query a backend multiple times with
 different configuration, you can specify a name for later
 instantiations. e.g.:
 
-::
+.. code-block:: ini
 
     launch=gmysql,gmysql:server2
 
@@ -700,7 +702,7 @@ configuration item names change: e.g. ``gmysql-host`` is available to
 configure the ``host`` setting of the first or main instance, and
 ``gmysql-server2-host`` for the second one.
 
-Running multiple instances of the bind backend is not allowed.
+Running multiple instances of the BIND backend is not allowed.
 
 .. _setting-load-modules:
 
@@ -727,60 +729,6 @@ 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.
 
-.. _setting-log-timestamp:
-
-``log-timestamp``
------------------
-
-.. versionadded:: 4.1.0
-
-- Bool
-- Default: yes
-
-When printing log lines to stdout, prefix them with timestamps.
-Disable this if the process supervisor timestamps these lines already.
-
-.. note::
-  The systemd unit file supplied with the source code already disables timestamp printing
-
-.. _setting-lua-records-exec-limit:
-
-``lua-records-exec-limit``
------------------------------
-
--  Integer
--  Default: 1000
-
-Limit LUA records scripts to ``lua-records-exec-limit`` instructions.
-Setting this to any value less than or equal to 0 will set no limit.
-
-.. _setting-non-local-bind:
-
-``non-local-bind``
-------------------
-
--  Boolean
--  Default: no
-
-Bind to addresses even if one or more of the
-:ref:`setting-local-address`'s do not exist on this server.
-Setting this option will enable the needed socket options to allow
-binding to non-local addresses. This feature is intended to facilitate
-ip-failover setups, but it may also mask configuration issues and for
-this reason it is disabled by default.
-
-.. _setting-lua-axfr-script:
-
-``lua-axfr-script``
--------------------
-
--  String
--  Default: empty
-
-.. versionadded:: 4.1.0
-
-Script to be used to edit incoming AXFRs, see :ref:`modes-of-operation-axfrfilter`
-
 .. _setting-local-address-nonexist-fail:
 
 ``local-address-nonexist-fail``
@@ -836,6 +784,34 @@ The port on which we listen. Only one port possible.
 If set to 'no', informative-only DNS details will not even be sent to
 syslog, improving performance.
 
+.. _setting-log-dns-queries:
+
+``log-dns-queries``
+-------------------
+
+-  Boolean
+-  Default: no
+
+Tell PowerDNS to log all incoming DNS queries. This will lead to a lot
+of logging! Only enable for debugging! Set :ref:`setting-loglevel`
+to at least 5 to see the logs.
+
+.. _setting-log-timestamp:
+
+``log-timestamp``
+-----------------
+
+- Bool
+- Default: yes
+
+.. versionadded:: 4.1.0
+
+When printing log lines to stdout, prefix them with timestamps.
+Disable this if the process supervisor timestamps these lines already.
+
+.. note::
+  The systemd unit file supplied with the source code already disables timestamp printing
+
 .. _setting-logging-facility:
 
 ``logging-facility``
@@ -855,17 +831,17 @@ Do not pass names like 'local0'!
 Amount of logging. Higher is more. Do not set below 3. Corresponds to "syslog" level values,
 e.g. error = 3, warning = 4, notice = 5, info = 6
 
-.. _setting-log-dns-queries:
+.. _setting-lua-axfr-script:
 
-``log-dns-queries``
+``lua-axfr-script``
 -------------------
 
--  Boolean
--  Default: no
+-  String
+-  Default: empty
 
-Tell PowerDNS to log all incoming DNS queries. This will lead to a lot
-of logging! Only enable for debugging! Set :ref:`setting-loglevel`
-to at least 5 to see the logs.
+.. versionadded:: 4.1.0
+
+Script to be used to edit incoming AXFRs, see :ref:`modes-of-operation-axfrfilter`
 
 .. _setting-lua-prequery-script:
 
@@ -878,6 +854,17 @@ Lua script to run before answering a query. This is a feature used
 internally for regression testing. The API of this functionality is not
 guaranteed to be stable, and is in fact likely to change.
 
+.. _setting-lua-records-exec-limit:
+
+``lua-records-exec-limit``
+-----------------------------
+
+-  Integer
+-  Default: 1000
+
+Limit LUA records scripts to ``lua-records-exec-limit`` instructions.
+Setting this to any value less than or equal to 0 will set no limit.
+
 .. _setting-master:
 
 ``master``
@@ -898,7 +885,7 @@ Turn on master support. See :ref:`master-operation`.
 
 .. versionchanged:: 4.1.0
   The packet and query caches are distinct. Previously, this setting was used for
-  both the packet and query caches. See ref:`setting-max-packet-cache-entries` for
+  both the packet and query caches. See :ref:`setting-max-packet-cache-entries` for
   the packet-cache setting.
 
 Maximum number of entries in the query cache. 1 million (the default)
@@ -923,7 +910,8 @@ protection measure to avoid database explosion due to long names.
 -  Integer
 -  Default: 500
 
-Limit the number of NSEC3 hash iterations
+Limit the number of NSEC3 hash iterations for zone configurations.
+For more information see :ref:`dnssec-operational-nsec-modes-params`.
 
 .. _setting-max-packet-cache-entries:
 
@@ -1022,7 +1010,7 @@ compile-time.
 -  Integer
 -  Default: 60
 
-Seconds to store queries with no answer in the Query Cache. See ref:`query-cache`.
+Seconds to store queries with no answer in the Query Cache. See :ref:`query-cache`.
 
 .. _setting-no-config:
 
@@ -1032,7 +1020,8 @@ Seconds to store queries with no answer in the Query Cache. See ref:`query-cache
 -  Boolean
 -  Default: no
 
-Do not attempt to read the configuration file.
+Do not attempt to read the configuration file. Useful for configuration
+by parameters from the command line only.
 
 .. _setting-no-shuffle:
 
@@ -1044,75 +1033,20 @@ Do not attempt to read the configuration file.
 
 Do not attempt to shuffle query results, used for regression testing.
 
-.. _setting-overload-queue-length:
-
-``overload-queue-length``
--------------------------
-
--  Integer
--  Default: 0 (disabled)
-
-If this many packets are waiting for database attention, answer any new
-questions strictly from the packet cache.
-
-.. _setting-reuseport:
+.. _setting-non-local-bind:
 
-``reuseport``
--------------
+``non-local-bind``
+------------------
 
 -  Boolean
--  Default: No
-
-On Linux 3.9 and some BSD kernels the ``SO_REUSEPORT`` option allows
-each receiver-thread to open a new socket on the same port which allows
-for much higher performance on multi-core boxes. Setting this option
-will enable use of ``SO_REUSEPORT`` when available and seamlessly fall
-back to a single socket when it is not available. A side-effect is that
-you can start multiple servers on the same IP/port combination which may
-or may not be a good idea. You could use this to enable transparent
-restarts, but it may also mask configuration issues and for this reason
-it is disabled by default.
-
-.. _setting-rng:
-
-``rng``
--------
-
-- String
-- Default: auto
-
-Specify which random number generator to use. Permissible choises are
- - auto - choose automatically
- - sodium - Use libsodium ``randombytes_uniform``
- - openssl - Use libcrypto ``RAND_bytes``
- - getrandom - Use libc getrandom, falls back to urandom if it does not really work
- - arc4random - Use BSD ``arc4random_uniform``
- - urandom - Use ``/dev/urandom``
- - kiss - Use simple settable deterministic RNG. **FOR TESTING PURPOSES ONLY!**
-
-.. note::
-  Not all choises are available on all systems.
-
-.. _setting-security-poll-suffix:
-
-``security-poll-suffix``
-------------------------
-
--  String
--  Default: secpoll.powerdns.com.
-
-Domain name from which to query security update notifications. Setting
-this to an empty string disables secpoll.
-
-.. _setting-server-id:
-
-``server-id``
--------------
-
--  String
--  Default: The hostname of the server
+-  Default: no
 
-This is the server ID that will be returned on an EDNS NSID query.
+Bind to addresses even if one or more of the
+:ref:`setting-local-address`'s do not exist on this server.
+Setting this option will enable the needed socket options to allow
+binding to non-local addresses. This feature is intended to facilitate
+ip-failover setups, but it may also mask configuration issues and for
+this reason it is disabled by default.
 
 .. _setting-only-notify:
 
@@ -1148,12 +1082,14 @@ To notify all IP addresses apart from the 192.168.0.0/24 subnet use the followin
   :ref:`metadata-also-notify` domain metadata to avoid this potential bottleneck.
 
 .. note::
-  If your slaves support Internet Protocol version, which your master does not,
+  If your slaves support an Internet Protocol version, which your master does not,
   then set ``only-notify`` to include only supported protocol version.
   Otherwise there will be error trying to resolve address.
 
   For example, slaves support both IPv4 and IPv6, but PowerDNS master have only IPv4,
-  so allow only IPv4 with ``only-notify``::
+  so allow only IPv4 with ``only-notify``:
+
+  .. code-block:: ini
 
     only-notify=0.0.0.0/0
 
@@ -1162,12 +1098,12 @@ To notify all IP addresses apart from the 192.168.0.0/24 subnet use the followin
 ``out-of-zone-additional-processing``
 -------------------------------------
 
-.. deprecated:: 4.2.0
-  This setting has been removed.
-
 -  Boolean
 -  Default: yes
 
+.. deprecated:: 4.2.0
+  This setting has been removed.
+
 Do out of zone additional processing. This means that if a malicious
 user adds a '.com' zone to your server, it is not used for other domains
 and will not contaminate answers. Do not enable this setting if you run
@@ -1192,6 +1128,17 @@ If this is disabled (the default), ALIAS records are sent verbatim
 during outgoing AXFR. Note that if your slaves do not support ALIAS,
 they will return NODATA for A/AAAA queries for such names.
 
+.. _setting-overload-queue-length:
+
+``overload-queue-length``
+-------------------------
+
+-  Integer
+-  Default: 0 (disabled)
+
+If this many packets are waiting for database attention, answer any new
+questions strictly from the packet cache.
+
 .. _setting-prevent-self-notification:
 
 ``prevent-self-notification``
@@ -1316,6 +1263,56 @@ resolvers.
 
 Number of AXFR slave threads to start.
 
+.. _setting-reuseport:
+
+``reuseport``
+-------------
+
+-  Boolean
+-  Default: No
+
+On Linux 3.9 and some BSD kernels the ``SO_REUSEPORT`` option allows
+each receiver-thread to open a new socket on the same port which allows
+for much higher performance on multi-core boxes. Setting this option
+will enable use of ``SO_REUSEPORT`` when available and seamlessly fall
+back to a single socket when it is not available. A side-effect is that
+you can start multiple servers on the same IP/port combination which may
+or may not be a good idea. You could use this to enable transparent
+restarts, but it may also mask configuration issues and for this reason
+it is disabled by default.
+
+.. _setting-rng:
+
+``rng``
+-------
+
+- String
+- Default: auto
+
+Specify which random number generator to use. Permissible choises are:
+
+- auto - choose automatically
+- sodium - Use libsodium ``randombytes_uniform``
+- openssl - Use libcrypto ``RAND_bytes``
+- getrandom - Use libc getrandom, falls back to urandom if it does not really work
+- arc4random - Use BSD ``arc4random_uniform``
+- urandom - Use ``/dev/urandom``
+- kiss - Use simple settable deterministic RNG. **FOR TESTING PURPOSES ONLY!**
+
+.. note::
+  Not all choises are available on all systems.
+
+.. _setting-security-poll-suffix:
+
+``security-poll-suffix``
+------------------------
+
+-  String
+-  Default: secpoll.powerdns.com.
+
+Domain name from which to query security update notifications. Setting
+this to an empty string disables secpoll.
+
 .. _setting-send-signed-notify:
 
 ``send-signed-notify``
@@ -1330,6 +1327,16 @@ first one retrieved from the backend, which may not be the correct one for the
 respective slave. Hence, in setups with multiple slaves with different TSIG keys
 it may be required to send NOTIFYs unsigned.
 
+.. _setting-server-id:
+
+``server-id``
+-------------
+
+-  String
+-  Default: The hostname of the server
+
+This is the server ID that will be returned on an EDNS NSID query.
+
 .. _setting-setgid:
 
 ``setgid``
@@ -1348,6 +1355,17 @@ If set, change group id to this gid for more security. See :doc:`security`.
 
 If set, change user id to this uid for more security. See :doc:`security`.
 
+.. _setting-signing-threads:
+
+``signing-threads``
+-------------------
+
+-  Integer
+-  Default: 3
+
+Tell PowerDNS how many threads to use for signing. It might help improve
+signing speed by changing this number.
+
 .. _setting-slave:
 
 ``slave``
@@ -1364,9 +1382,9 @@ Turn on slave support. See :ref:`slave-operation`.
 ------------------------
 
 -  Integer
--  60
+-  Default: 60
 
-On a master, this is the amounts of seconds between the master checking
+On a master, this is the amount of seconds between the master checking
 the SOA serials in its database to determine to send out NOTIFYs to the
 slaves. On slaves, this is the number of seconds between the slave
 checking for updates to zones.
@@ -1383,17 +1401,6 @@ This setting will make PowerDNS renotify the slaves after an AXFR is
 *received* from a master. This is useful when using when running a
 signing-slave.
 
-.. _setting-signing-threads:
-
-``signing-threads``
--------------------
-
--  Integer
--  Default: 3
-
-Tell PowerDNS how many threads to use for signing. It might help improve
-signing speed by changing this number.
-
 .. _setting-soa-expire-default:
 
 ``soa-expire-default``
@@ -1449,15 +1456,17 @@ This path will also contain the pidfile for this instance of PowerDNS
 called ``pdns.pid`` by default. See :ref:`setting-config-name`
 and :doc:`Virtual Hosting <guides/virtual-instances>` how this can differ.
 
-.. _setting-supermaster:
+.. _setting-superslave:
 
-``supermaster``
+``superslave``
 ---------------
 
 -  Boolean
 -  Default: no
 
 .. versionadded:: 4.2.0
+  In versions before 4.2.x, this setting did not exist and supermaster support
+  was enabled by default.
 
 Turn on supermaster support. See :ref:`supermaster-operation`.
 
@@ -1654,7 +1663,7 @@ When set to "detailed", all information about the request and response are logge
 The value between the hooks is a UUID that is generated for each request. This can be used to find all lines related to a single request.
 
 .. note::
-  The webserver logs these line on the NOTICE level. The :ref:`settings-loglevel` seting must be 5 or higher for these lines to end up in the log.
+  The webserver logs these line on the NOTICE level. The :ref:`setting-loglevel` seting must be 5 or higher for these lines to end up in the log.
 
 .. _setting-webserver-password:
 
index f4074b2596f4718d6f1c66f68d1af107dd919a31..df97df2e74eba1e8d6aacfa6db1cfb2830badd35 100644 (file)
@@ -34,7 +34,9 @@ with the key name in the content field. For example::
     $ dig -t axfr powerdnssec.org @127.0.0.1 -y 'test:kp4/24gyYsEzbuTVJRUMoqGFmN3LYgVDzJ/3oRSP7ys='
 
 Another of importing and activating TSIG keys into the database is using
-:doc:`pdnsutil <manpages/pdnsutil.1>`::
+:doc:`pdnsutil <manpages/pdnsutil.1>`:
+
+.. code-block:: shell
 
     pdnsutil import-tsig-key test hmac-md5 'kp4/24gyYsEzbuTVJRUMoqGFmN3LYgVDzJ/3oRSP7ys='
     pdnsutil activate-tsig-key powerdnssec.org test master
@@ -70,9 +72,7 @@ The actual TSIG key must also be provisioned, as outlined in the
 previous section.
 
 For the Generic SQL backends, configuring the use of TSIG for AXFR
-requests could be achieved as follows:
-
-::
+requests could be achieved as follows::
 
     insert into tsigkeys (name, algorithm, secret) values ('test', 'hmac-md5', 'kp4/24gyYsEzbuTVJRUMoqGFmN3LYgVDzJ/3oRSP7ys=');
     select id from domains where name='powerdnssec.org';
@@ -82,7 +82,7 @@ requests could be achieved as follows:
 This can also be done using
 :doc:`/manpages/pdnsutil.1`:
 
-::
+.. code-block:: shell
 
     pdnsutil import-tsig-key test hmac-md5 'kp4/24gyYsEzbuTVJRUMoqGFmN3LYgVDzJ/3oRSP7ys='
     pdnsutil activate-tsig-key powerdnssec.org test slave
@@ -91,9 +91,7 @@ This setup corresponds to the ``TSIG-ALLOW-AXFR`` access rule defined in
 the previous section.
 
 In the interest of interoperability, the configuration above is (not
-quite) similar to the following BIND statements:
-
-::
+quite) similar to the following BIND statements::
 
     key test. {
             algorithm hmac-md5;
index 82ca98075471b424a7b6d0996229c76852abeb67..b0b7ba64ff2e77b39c756fd8cf53e2c89caaad5f 100644 (file)
@@ -8,6 +8,11 @@ Please upgrade to the PowerDNS Authoritative Server 4.0.0 from 3.4.2+.
 See the `3.X <https://doc.powerdns.com/3/authoritative/upgrading/>`__
 upgrade notes if your version is older than 3.4.2.
 
+4.1.X to 4.2.0
+--------------
+
+- Superslave operation is no longer enabled by default, use :ref:`setting-superslave` to enable. This setting was called ``supermaster`` in some 4.2.0 prereleases.
+
 4.1.0 to 4.1.1
 --------------
 
index 391936c0062fd3e9be3783cfc08309db5c7edd5f..8f746f8dc8703431fb31cdb32b5f229576ca9378 100644 (file)
@@ -3,7 +3,7 @@ Using this SQL causes Mysql to create foreign keys on your database. This will
 make sure that no records, comments or keys exists for domains that you already
 removed. This is not enabled by default, because we're not sure what the
 consequences are from a performance point of view. If you do have feedback,
-please let us know how this effects your setup.
+please let us know how this affects your setup.
 
 Please note that it's not possible to apply this, before you cleaned up your
 database, as the foreign keys do not exist.
index 1d80b1740cbf0e0003a198a25298aab8d99ba7a5..884029858e1af8108b2eac2ad40fe609b4f15e45 100644 (file)
@@ -201,3 +201,15 @@ template <typename T> uint64_t purgeExactLockedCollection(T& mc, const DNSName&
 
   return delcount;
 }
+
+template<typename Index>
+std::pair<typename Index::iterator,bool>
+lruReplacingInsert(Index& i,const typename Index::value_type& x)
+{
+  std::pair<typename Index::iterator,bool> res = i.insert(x);
+  if (!res.second) {
+    moveCacheItemToBack(i, res.first);
+    res.second = i.replace(res.first, x);
+  }
+  return res;
+}
index e7f6f5ab95255b3ebe17a214c2420ae131aa0634..bd57fc54235208771682b01da17d0c3a1d5e146d 100644 (file)
@@ -137,7 +137,7 @@ void declareArguments()
   
   ::arg().setSwitch("slave","Act as a slave")="no";
   ::arg().setSwitch("master","Act as a master")="no";
-  ::arg().setSwitch("supermaster", "Act as a supermaster")="no";
+  ::arg().setSwitch("superslave", "Act as a superslave")="no";
   ::arg().setSwitch("disable-axfr-rectify","Disable the rectify step during an outgoing AXFR. Only required for regression testing.")="no";
   ::arg().setSwitch("guardian","Run within a guardian process")="no";
   ::arg().setSwitch("prevent-self-notification","Don't send notifications to what we think is ourself")="yes";
index 5413e4dacf2335f9a5af69276536204d776719ae..c63534dc232b5fa709eba136905c9bfcde208645 100644 (file)
@@ -251,18 +251,32 @@ private:
 class FindNS
 {
 public:
-  vector<string> lookup(const DNSName &name, UeberBackend *b)
+  vector<string> lookup(const DNSName &name, UeberBackend *b, const DNSName& zone)
   {
     vector<string> addresses;
 
     this->resolve_name(&addresses, name);
     
     if(b) {
-        b->lookup(QType(QType::ANY),name);
-        DNSZoneRecord rr;
-        while(b->get(rr))
-          if(rr.dr.d_type == QType::A || rr.dr.d_type==QType::AAAA)
+      b->lookup(QType(QType::ANY),name);
+      while (true) {
+        try {
+          DNSZoneRecord rr;
+          if (!b->get(rr))
+            break;
+          if (rr.dr.d_type == QType::A || rr.dr.d_type == QType::AAAA)
             addresses.push_back(rr.dr.d_content->getZoneRepresentation());   // SOL if you have a CNAME for an NS
+        }
+        // After an exception, b can be inconsistent so break
+        catch (PDNSException &ae) {
+          g_log << Logger::Error << "Could not lookup address for nameserver " << name << " in zone " << zone << ", cannot notify: " << ae.reason << endl;
+          break;
+        }
+        catch (std::exception &e) {
+          g_log << Logger::Error << "Could not lookup address for nameserver " << name << " in zone " << zone << ", cannot notify: " << e.what() << endl;
+          break;
+        }
+      }
     }
     return addresses;
   }
index e4aa0b52821217f6dc738ce08c1de4206e2bafb8..4af74100310a540c1b5c669f6b4dcc17f452b825 100644 (file)
@@ -224,7 +224,7 @@ void DNSSECKeeper::getFromMeta(const DNSName& zname, const std::string& key, std
     nce.d_value = value;
     {
       WriteLock l(&s_metacachelock);
-      replacing_insert(s_metacache, nce);
+      lruReplacingInsert(s_metacache, nce);
     }
   }
 }
@@ -514,7 +514,7 @@ DNSSECKeeper::keyset_t DNSSECKeeper::getKeys(const DNSName& zone, bool useCache)
     kce.d_ttd = now + ttl;
     {
       WriteLock l(&s_keycachelock);
-      replacing_insert(s_keycache, kce);
+      lruReplacingInsert(s_keycache, kce);
     }
   }
 
index 3fea22211767cf0d592f6ec2d3191eee424cdb67..884a5ad2217c1fa1579fd42429b3a1992f0a0195 100644 (file)
@@ -1,10 +1,45 @@
 Changelog
 =========
 
+.. changelog::
+  :version: 1.4.0-alpha2
+  :released: 26th of April 2019
+
+  .. change::
+    :tags: Improvements
+    :pullreq: 7410
+
+    Ignore Path MTU discovery on UDP server socket
+
+  .. change::
+    :tags: Improvements
+    :pullreq: 7708
+
+    Alternative solution to the unaligned accesses.
+
+  .. change::
+    :tags: Bug Fixes
+    :pullreq: 7718
+
+    Exit when setting ciphers fails (GnuTLS)
+
+  .. change::
+    :tags: New Features
+    :pullreq: 7726
+    :tickets: 6911, 7526
+
+    Add DNS over HTTPS support based on libh2o
+
 .. changelog::
   :version: 1.4.0-alpha1
   :released: 12th of April 2019
 
+ .. change::
+    :tags: New Features
+    :pullreq: 7209
+
+    Make recursor & dnsdist communicate (ECS) 'variable' status
+
  .. change::
     :tags: Improvements
     :pullreq: 7167
index 03793cfa2cb6a59eea53c15d92979a074295f1f2..4df9586a49b4128e2449f169a88e6bd51c4fa241 100644 (file)
@@ -21,7 +21,7 @@ Reference: https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#
 .. _DNSClass:
 
 DNSClass
-------
+--------
 
 These constants represent the `CLASS <https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-2>`__ of a DNS record.
 
index 1df3ce56b13b1add475b2e0ef92045dd23726602..7f7f3ece426537c89332357f241bdca76d4a33b9 100644 (file)
@@ -11,6 +11,7 @@ These chapters contain extensive information on all functions and object availab
   comboaddress
   netmaskgroup
   dnsname
+  dnsnameset
   dq
   ebpf
   dnscrypt
index f2ad20a6d30e33652c1b39ed4f4d478f73a4a498..a0d1e38b51b67ef98b284022763db2243d3c8108 100644 (file)
@@ -720,7 +720,7 @@ These ``DNSRule``\ s be one of the following items:
 .. function:: RecordsTypeCountRule(section, qtype, minCount, maxCount)
 
   Matches if there is at least ``minCount`` and at most ``maxCount`` records of type ``type`` in the section ``section``.
-  ``section`` can be specified as an integer or as a ref:`DNSSection`.
+  ``section`` can be specified as an integer or as a :ref:`DNSSection`.
   ``qtype`` may be specified as an integer or as one of the :ref:`built-in QTypes <DNSQType>`, for instance ``DNSQType.A`` or ``DNSQType.TXT``.
 
   :param int section: The section to match on
index a8ea1a92281416210d3b3d84f4e1bb9e416e832b..e5f6b11dbbaa639f51910068aa47ee3dca260c84 100644 (file)
@@ -289,6 +289,40 @@ struct SuffixMatchTree
     }
   }
 
+  void remove(const DNSName &name) const
+  {
+    remove(name.getRawLabels());
+  }
+
+  /* Removes the node at `labels`, also make sure that no empty
+   * children will be left behind in memory
+   */
+  void remove(std::vector<std::string> labels) const
+  {
+    SuffixMatchTree smt(*labels.rbegin());
+    auto child = children.find(smt);
+    if (child == children.end()) {
+      // No subnode found, we're done
+      return;
+    }
+
+    // We have found a child
+    labels.pop_back();
+    if (labels.empty()) {
+      // The child is no longer an endnode
+      child->endNode = false;
+
+      // If the child has no further children, just remove it from the set.
+      if (child->children.empty()) {
+        children.erase(child);
+      }
+      return;
+    }
+
+    // We are not at the end, let the child figure out what to do
+    child->remove(labels);
+  }
+
   T* lookup(const DNSName& name)  const
   {
     if(children.empty()) { // speed up empty set
@@ -318,41 +352,86 @@ struct SuffixMatchTree
     return child->lookup(labels);
   }
 
+  // Returns all end-nodes, fully qualified (not as separate labels)
+  std::vector<DNSName> getNodes() const {
+    std::vector<DNSName> ret;
+    if (endNode) {
+      ret.push_back(DNSName(d_name));
+    }
+    for (const auto& child : children) {
+      auto nodes = child.getNodes();
+      for (const auto &node: nodes) {
+        ret.push_back(node + DNSName(d_name));
+      }
+    }
+    return ret;
+  }
 };
 
 /* Quest in life: serve as a rapid block list. If you add a DNSName to a root SuffixMatchNode,
    anything part of that domain will return 'true' in check */
 struct SuffixMatchNode
 {
-  SuffixMatchNode()
-  {}
-  std::string d_human;
-  SuffixMatchTree<bool> d_tree;
+  public:
+    SuffixMatchNode()
+    {}
+    SuffixMatchTree<bool> d_tree;
+
+    void add(const DNSName& dnsname)
+    {
+      d_tree.add(dnsname, true);
+      d_nodes.insert(dnsname);
+    }
 
-  void add(const DNSName& dnsname)
-  {
-    if(!d_human.empty())
-      d_human.append(", ");
-    d_human += dnsname.toString();
+    void add(std::vector<std::string> labels)
+    {
+      d_tree.add(labels, true);
+      DNSName tmp;
+      while (!labels.empty()) {
+        tmp.appendRawLabel(labels.back());
+        labels.pop_back(); // This is safe because we have a copy of labels
+      }
+      d_nodes.insert(tmp);
+    }
 
-    d_tree.add(dnsname, true);
-  }
+    void remove(const DNSName& name)
+    {
+      d_tree.remove(name);
+      d_nodes.erase(name);
+    }
 
-  void add(std::vector<std::string> labels)
-  {
-    d_tree.add(labels, true);
-  }
+    void remove(std::vector<std::string> labels)
+    {
+      d_tree.remove(labels);
+      DNSName tmp;
+      while (!labels.empty()) {
+        tmp.appendRawLabel(labels.back());
+        labels.pop_back(); // This is safe because we have a copy of labels
+      }
+      d_nodes.erase(tmp);
+    }
 
-  bool check(const DNSName& dnsname) const
-  {
-    return d_tree.lookup(dnsname) != nullptr;
-  }
+    bool check(const DNSName& dnsname) const
+    {
+      return d_tree.lookup(dnsname) != nullptr;
+    }
 
-  std::string toString() const
-  {
-    return d_human;
-  }
+    std::string toString() const
+    {
+      std::string ret;
+      bool first = true;
+      for (const auto& n : d_nodes) {
+        if (!first) {
+          ret += ", ";
+        }
+        first = false;
+        ret += n.toString();
+      }
+      return ret;
+    }
 
+  private:
+    mutable std::set<DNSName> d_nodes; // Only used for string generation
 };
 
 std::ostream & operator<<(std::ostream &os, const DNSName& d);
index d9f5a18ec4740107e7865e93903d19cc8fee8c47..1031ddf59dd771fd857b7a0b83ee5be987a019fa 100644 (file)
@@ -272,6 +272,9 @@ class DNAMERecordContent : public DNSRecordContent
 {
 public:
   includeboilerplate(DNAME)
+  DNAMERecordContent(const DNSName& content) : d_content(content){}
+  const DNSName& getTarget() const { return d_content; }
+private:
   DNSName d_content;
 };
 
index 3ae3ea7ee3886043f7fdf6c37509ea630cd09bb7..c3da28c2d595845a749e49d34922b9b72779ce00 100644 (file)
@@ -54,6 +54,9 @@ po::variables_map g_vm;
 class IPObfuscator
 {
 public:
+  virtual ~IPObfuscator()
+  {
+  }
   virtual uint32_t obf4(uint32_t orig)=0;
   virtual struct in6_addr obf6(const struct in6_addr& orig)=0;
 };
index 8d12c5121f2567203d7a0ff09b9ada5f11e3a3bc..354eba7461bb2172d0f6d587e8ea1d2108c8429c 100644 (file)
@@ -30,9 +30,9 @@
 #include <thread>
 StatBag S;
 
-std::atomic<uint64_t>* g_counter;
+static std::atomic<uint64_t>* g_counter;
 
-void printStatus()
+static void printStatus()
 {
   auto prev= g_counter->load();
   for(;;) {
@@ -42,47 +42,151 @@ void printStatus()
   }
 }
 
-void usage() {
-  cerr<<"Syntax: dumresp LOCAL-ADDRESS LOCAL-PORT NUMBER-OF-PROCESSES"<<endl;
+static void usage() {
+  cerr<<"Syntax: dumresp LOCAL-ADDRESS LOCAL-PORT NUMBER-OF-PROCESSES [tcp]"<<endl;
+}
+
+static void turnQueryIntoResponse(dnsheader* dh)
+{
+  (*g_counter)++;
+
+  dh->qr=1;
+  dh->ad=0;
+}
+
+static void tcpConnectionHandler(int sock)
+try
+{
+  char buffer[1500];
+  auto dh = reinterpret_cast<struct dnsheader*>(buffer);
+
+  for (;;) {
+    uint16_t len = 0;
+    ssize_t got = read(sock, &len, sizeof(len));
+
+    if (got == 0) {
+      break;
+    }
+
+    if (got != sizeof(len))
+      unixDie("read 1");
+
+    len = ntohs(len);
+
+    if (len < sizeof(dnsheader))
+      unixDie("too small");
+
+    if (len > sizeof(buffer))
+      unixDie("too large");
+
+    got = read(sock, buffer, len);
+    if (got != len)
+      unixDie("read 2: " + std::to_string(got) + " / " + std::to_string(len));
+
+    if (dh->qr)
+      continue;
+
+    turnQueryIntoResponse(dh);
+
+    uint16_t wirelen = htons(len);
+    if (write(sock, &wirelen, sizeof(wirelen)) != sizeof(wirelen))
+      unixDie("send 1");
+
+    if (write(sock, buffer, len) < 0)
+      unixDie("send 2");
+  }
+
+  close(sock);
+}
+catch(const std::exception& e) {
+  cerr<<"TCP connection handler got an exception: "<<e.what()<<endl;
+}
+
+static void tcpAcceptor(const ComboAddress local)
+{
+  Socket tcpSocket(local.sin4.sin_family, SOCK_STREAM);
+#ifdef SO_REUSEPORT
+  int one=1;
+  if(setsockopt(tcpSocket.getHandle(), SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) < 0)
+    unixDie("setsockopt for REUSEPORT");
+#endif
+
+  tcpSocket.bind(local);
+  tcpSocket.listen(1024);
+
+  ComboAddress rem("::1");
+  auto socklen = rem.getSocklen();
+
+  for (;;) {
+    int sock = accept(tcpSocket.getHandle(), reinterpret_cast<struct sockaddr*>(&rem), &socklen);
+    if (sock == -1) {
+        continue;
+    }
+
+    std::thread connectionHandler(tcpConnectionHandler, sock);
+    connectionHandler.detach();
+  }
 }
 
 int main(int argc, char** argv)
 try
 {
+  bool tcp = false;
+
   for(int i = 1; i < argc; i++) {
-    if((string) argv[i] == "--help"){
+    if(std::string(argv[i]) == "--help"){
       usage();
       return(EXIT_SUCCESS);
     }
 
-    if((string) argv[i] == "--version"){
+    if(std::string(argv[i]) == "--version"){
       cerr<<"dumresp "<<VERSION<<endl;
       return(EXIT_SUCCESS);
     }
   }
 
-  if(argc != 4) {
+  if(argc == 5) {
+    if (std::string(argv[4]) == "tcp") {
+      tcp = true;
+    }
+    else {
+      usage();
+      exit(EXIT_FAILURE);
+    }
+  }
+  else if(argc != 4) {
     usage();
     exit(EXIT_FAILURE);
   }
 
-  auto ptr = mmap(NULL, sizeof(std::atomic<uint64_t>), PROT_READ | PROT_WRITE,
+  auto ptr = mmap(nullptr, sizeof(std::atomic<uint64_t>), PROT_READ | PROT_WRITE,
                  MAP_SHARED | MAP_ANONYMOUS, -1, 0);
 
   g_counter = new(ptr) std::atomic<uint64_t>();
-  
+
+  int numberOfListeners = atoi(argv[3]);
+  ComboAddress local(argv[1], atoi(argv[2]));
+
   int i=1;
-  for(; i < atoi(argv[3]); ++i) {
+  for(; i < numberOfListeners; ++i) {
     if(!fork())
       break;
   }
-  if(i==1) {
+
+  if (i==1) {
     std::thread t(printStatus);
     t.detach();
+
+    if (tcp) {
+      for (int j = 0; j < numberOfListeners; j++) {
+        cout<<"Listening to TCP "<<local.toStringWithPort()<<endl;
+        std::thread tcpAcceptorThread(tcpAcceptor, local);
+        tcpAcceptorThread.detach();
+      }
+    }
   }
-  
-  ComboAddress local(argv[1], atoi(argv[2]));
-  Socket s(local.sin4.sin_family, SOCK_DGRAM);  
+
+  Socket s(local.sin4.sin_family, SOCK_DGRAM);
 #ifdef SO_REUSEPORT
   int one=1;
   if(setsockopt(s.getHandle(), SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) < 0)
@@ -90,28 +194,32 @@ try
 #endif
 
   s.bind(local);
-  cout<<"Bound to "<<local.toStringWithPort()<<endl;
-  char buffer[1500];
-  struct dnsheader* dh = (struct dnsheader*)buffer;
-  int len;
-  ComboAddress rem=local;
+  cout<<"Bound to UDP "<<local.toStringWithPort()<<endl;
+
+  ComboAddress rem = local;
   socklen_t socklen = rem.getSocklen();
+  char buffer[1500];
+  auto dh = reinterpret_cast<struct dnsheader*>(buffer);
+
   for(;;) {
-    len=recvfrom(s.getHandle(), buffer, sizeof(buffer), 0, (struct sockaddr*)&rem, &socklen);
-    (*g_counter)++;
+    uint16_t len = recvfrom(s.getHandle(), buffer, sizeof(buffer), 0, reinterpret_cast<struct sockaddr*>(&rem), &socklen);
+
     if(len < 0)
       unixDie("recvfrom");
 
+    if (len < sizeof(dnsheader))
+      unixDie("too small " + std::to_string(len));
+
     if(dh->qr)
       continue;
-    dh->qr=1;
-    dh->ad=0;
-    if(sendto(s.getHandle(), buffer, len, 0,  (struct sockaddr*)&rem, socklen) < 0)
-      unixDie("sendto");
 
+    turnQueryIntoResponse(dh);
+
+    if(sendto(s.getHandle(), buffer, len, 0,  reinterpret_cast<const struct sockaddr*>(&rem), socklen) < 0)
+      unixDie("sendto");
   }
 }
-catch(std::exception& e)
+catch(const std::exception& e)
 {
   cerr<<"Fatal error: "<<e.what()<<endl;
   exit(EXIT_FAILURE);
index b5841132cfad6121768edc75bbd0b92acd50f5a8..04803474994a64e63d7294265b30260d6ed0a768 100644 (file)
@@ -56,7 +56,7 @@ void CommunicatorClass::queueNotifyDomain(const DomainInfo& di, UeberBackend* B)
       nsset.insert(getRR<NSRecordContent>(rr.dr)->getNS().toString());
 
     for(set<string>::const_iterator j=nsset.begin();j!=nsset.end();++j) {
-      vector<string> nsips=fns.lookup(DNSName(*j), B);
+      vector<string> nsips=fns.lookup(DNSName(*j), B, di.zone);
       if(nsips.empty())
         g_log<<Logger::Warning<<"Unable to queue notification of domain '"<<di.zone<<"': nameservers do not resolve!"<<endl;
       else
index 9b6eea36d56b2668367ed46974fb98a7b58805e5..1f90bbcbd14c4ff8bf98c9d7d8729f712ed73bc7 100644 (file)
@@ -1485,3 +1485,36 @@ std::vector<ComboAddress> getResolvers(const std::string& resolvConfPath)
 
   return results;
 }
+
+size_t getPipeBufferSize(int fd)
+{
+#ifdef F_GETPIPE_SZ
+  int res = fcntl(fd, F_GETPIPE_SZ);
+  if (res == -1) {
+    return 0;
+  }
+  return res;
+#else
+  errno = ENOSYS;
+  return 0;
+#endif /* F_GETPIPE_SZ */
+}
+
+bool setPipeBufferSize(int fd, size_t size)
+{
+#ifdef F_SETPIPE_SZ
+  if (size > std::numeric_limits<int>::max()) {
+    errno = EINVAL;
+    return false;
+  }
+  int newSize = static_cast<int>(size);
+  int res = fcntl(fd, F_SETPIPE_SZ, newSize);
+  if (res == -1) {
+    return false;
+  }
+  return true;
+#else
+  errno = ENOSYS;
+  return false;
+#endif /* F_SETPIPE_SZ */
+}
index 9adfe35dc410e43730910ee72ae64436fac2a830..ee255e9b90930a0d7972e1527529a805929386a4 100644 (file)
@@ -537,8 +537,11 @@ bool isNonBlocking(int sock);
 bool setReceiveSocketErrors(int sock, int af);
 int closesocket(int fd);
 bool setCloseOnExec(int sock);
-uint64_t udpErrorStats(const std::string& str);
 
+size_t getPipeBufferSize(int fd);
+bool setPipeBufferSize(int fd, size_t size);
+
+uint64_t udpErrorStats(const std::string& str);
 uint64_t getRealMemoryUsage(const std::string&);
 uint64_t getSpecialMemoryUsage(const std::string&);
 uint64_t getOpenFileDescriptors(const std::string&);
index e7189ece004c6515c115c929d42838ab004db1eb..8499c1dd0fd7c44162c884d59fe23f0693807501 100644 (file)
@@ -331,7 +331,7 @@ vector<DNSZoneRecord> PacketHandler::getBestDNAMESynth(DNSPacket *p, SOAData& sd
       ret.push_back(rr);  // put in the original
       rr.dr.d_type = QType::CNAME;
       rr.dr.d_name = prefix + rr.dr.d_name;
-      rr.dr.d_content = std::make_shared<CNAMERecordContent>(CNAMERecordContent(prefix + getRR<DNAMERecordContent>(rr.dr)->d_content));
+      rr.dr.d_content = std::make_shared<CNAMERecordContent>(CNAMERecordContent(prefix + getRR<DNAMERecordContent>(rr.dr)->getTarget()));
       rr.auth = 0; // don't sign CNAME
       target= getRR<CNAMERecordContent>(rr.dr)->getTarget();
       ret.push_back(rr); 
@@ -887,7 +887,7 @@ int PacketHandler::processNotify(DNSPacket *p)
   //
   DomainInfo di;
   if(!B.getDomainInfo(p->qdomain, di, false) || !di.backend) {
-    if(::arg().mustDo("supermaster")) {
+    if(::arg().mustDo("superslave")) {
       g_log<<Logger::Warning<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" for which we are not authoritative, trying supermaster"<<endl;
       return trySuperMaster(p, p->getTSIGKeyname());
     }
index 722464af33542484a876389b6b51052dc195f8ea..1e171080c00231e789afb398fb6302df39b12c0c 100644 (file)
@@ -241,6 +241,10 @@ unsigned int g_numThreads;
 uint16_t g_outgoingEDNSBufsize;
 bool g_logRPZChanges{false};
 
+// Used in the Syncres to not throttle certain servers
+GlobalStateHolder<SuffixMatchNode> g_dontThrottleNames;
+GlobalStateHolder<NetmaskGroup> g_dontThrottleNetmasks;
+
 #define LOCAL_NETS "127.0.0.0/8, 10.0.0.0/8, 100.64.0.0/10, 169.254.0.0/16, 192.168.0.0/16, 172.16.0.0/12, ::1/128, fc00::/7, fe80::/10"
 #define LOCAL_NETS_INVERSE "!127.0.0.0/8, !10.0.0.0/8, !100.64.0.0/10, !169.254.0.0/16, !192.168.0.0/16, !172.16.0.0/12, !::1/128, !fc00::/7, !fe80::/10"
 // Bad Nets taken from both:
@@ -2777,6 +2781,11 @@ static void houseKeeping(void *)
 
 static void makeThreadPipes()
 {
+  auto pipeBufferSize = ::arg().asNum("distribution-pipe-buffer-size");
+  if (pipeBufferSize > 0) {
+    g_log<<Logger::Info<<"Resizing the buffer of the distribution pipe to "<<pipeBufferSize<<endl;
+  }
+
   /* thread 0 is the handler / SNMP, we start at 1 */
   for(unsigned int n = 1; n <= (g_numWorkerThreads + g_numDistributorThreads); ++n) {
     auto& threadInfos = s_threadInfos.at(n);
@@ -2800,6 +2809,16 @@ static void makeThreadPipes()
     threadInfos.pipes.readQueriesToThread = fd[0];
     threadInfos.pipes.writeQueriesToThread = fd[1];
 
+    if (pipeBufferSize > 0) {
+      if (!setPipeBufferSize(threadInfos.pipes.writeQueriesToThread, pipeBufferSize)) {
+        g_log<<Logger::Warning<<"Error resizing the buffer of the distribution pipe for thread "<<n<<" to "<<pipeBufferSize<<": "<<strerror(errno)<<endl;
+        auto existingSize = getPipeBufferSize(threadInfos.pipes.writeQueriesToThread);
+        if (existingSize > 0) {
+          g_log<<Logger::Warning<<"The current size of the distribution pipe's buffer for thread "<<n<<" is "<<existingSize<<endl;
+        }
+      }
+    }
+
     if (!setNonBlocking(threadInfos.pipes.writeQueriesToThread)) {
       unixDie("Making pipe for inter-thread communications non-blocking");
     }
@@ -3803,6 +3822,23 @@ static int serviceMain(int argc, char*argv[])
 
   g_statisticsInterval = ::arg().asNum("statistics-interval");
 
+  {
+    SuffixMatchNode dontThrottleNames;
+    vector<string> parts;
+    stringtok(parts, ::arg()["dont-throttle-names"]);
+    for (const auto &p : parts) {
+      dontThrottleNames.add(DNSName(p));
+    }
+    g_dontThrottleNames.setState(dontThrottleNames);
+
+    NetmaskGroup dontThrottleNetmasks;
+    stringtok(parts, ::arg()["dont-throttle-netmasks"]);
+    for (const auto &p : parts) {
+      dontThrottleNetmasks.addMask(Netmask(p));
+    }
+    g_dontThrottleNetmasks.setState(dontThrottleNetmasks);
+  }
+
   s_balancingFactor = ::arg().asDouble("distribution-load-factor");
   if (s_balancingFactor != 0.0 && s_balancingFactor < 1.0) {
     s_balancingFactor = 0.0;
@@ -4323,6 +4359,8 @@ int main(int argc, char **argv)
     ::arg().set("max-tcp-clients","Maximum number of simultaneous TCP clients")="128";
     ::arg().set("server-down-max-fails","Maximum number of consecutive timeouts (and unreachables) to mark a server as down ( 0 => disabled )")="64";
     ::arg().set("server-down-throttle-time","Number of seconds to throttle all queries to a server after being marked as down")="60";
+    ::arg().set("dont-throttle-names", "Do not throttle nameservers with this name or suffix")="";
+    ::arg().set("dont-throttle-netmasks", "Do not throttle nameservers with this IP netmask")="";
     ::arg().set("hint-file", "If set, load root hints from this file")="";
     ::arg().set("max-cache-entries", "If set, maximum number of entries in the main cache")="1000000";
     ::arg().set("max-negative-ttl", "maximum number of seconds to keep a negative cached entry in memory")="3600";
@@ -4379,6 +4417,7 @@ int main(int argc, char **argv)
     ::arg().set("max-recursion-depth", "Maximum number of internal recursion calls per query, 0 for unlimited")="40";
     ::arg().set("max-udp-queries-per-round", "Maximum number of UDP queries processed per recvmsg() round, before returning back to normal processing")="10000";
     ::arg().set("protobuf-use-kernel-timestamp", "Compute the latency of queries in protobuf messages by using the timestamp set by the kernel when the query was received (when available)")="";
+    ::arg().set("distribution-pipe-buffer-size", "Size in bytes of the internal buffer of the pipe used by the distributor to pass incoming queries to a worker thread")="0";
 
     ::arg().set("include-dir","Include *.conf files from this directory")="";
     ::arg().set("security-poll-suffix","Domain name from which to query security update notifications")="secpoll.powerdns.com.";
index 2eb6fb8fd6cd5bf0cbf84dd6aa2ea8521ab236d7..041c2ca2aa27dde102f537beb9568ce3388e727f 100644 (file)
 #include <pthread.h>
 #include "iputils.hh"
 #include "dnsname.hh"
+#include "sholder.hh"
 #include <atomic>
 
+extern GlobalStateHolder<SuffixMatchNode> g_dontThrottleNames;
+extern GlobalStateHolder<NetmaskGroup> g_dontThrottleNetmasks;
+
 /** this class is used both to send and answer channel commands to the PowerDNS Recursor */
 class RecursorControlChannel
 {
index 77bbd872e83c431d7425ef4a1157f8f4cd27d660..c2f0139ca2b3adc1e880f833a183def7cf831eac 100644 (file)
@@ -1398,6 +1398,190 @@ static string* nopFunction()
   return new string("pong\n");
 }
 
+static string getDontThrottleNames() {
+  auto dtn = g_dontThrottleNames.getLocal();
+  return dtn->toString() + "\n";
+}
+
+static string getDontThrottleNetmasks() {
+  auto dtn = g_dontThrottleNetmasks.getLocal();
+  return dtn->toString() + "\n";
+}
+
+template<typename T>
+static string addDontThrottleNames(T begin, T end) {
+  if (begin == end) {
+    return "No names specified, keeping existing list\n";
+  }
+  vector<DNSName> toAdd;
+  while (begin != end) {
+    try {
+      auto d = DNSName(*begin);
+      toAdd.push_back(d);
+    }
+    catch(const std::exception &e) {
+      return "Problem parsing '" + *begin + "': "+ e.what() + ", nothing added\n";
+    }
+    begin++;
+  }
+
+  string ret = "Added";
+  auto dnt = g_dontThrottleNames.getCopy();
+  bool first = true;
+  for (auto const &d : toAdd) {
+    if (!first) {
+      ret += ",";
+    }
+    first = false;
+    ret += " " + d.toLogString();
+    dnt.add(d);
+  }
+
+  g_dontThrottleNames.setState(dnt);
+
+  ret += " to the list of nameservers that may not be throttled";
+  g_log<<Logger::Info<<ret<<", requested via control channel"<<endl;
+  return ret + "\n";
+}
+
+template<typename T>
+static string addDontThrottleNetmasks(T begin, T end) {
+  if (begin == end) {
+    return "No netmasks specified, keeping existing list\n";
+  }
+  vector<Netmask> toAdd;
+  while (begin != end) {
+    try {
+      auto n = Netmask(*begin);
+      toAdd.push_back(n);
+    }
+    catch(const std::exception &e) {
+      return "Problem parsing '" + *begin + "': "+ e.what() + ", nothing added\n";
+    }
+    catch(const PDNSException &e) {
+      return "Problem parsing '" + *begin + "': "+ e.reason + ", nothing added\n";
+    }
+    begin++;
+  }
+
+  string ret = "Added";
+  auto dnt = g_dontThrottleNetmasks.getCopy();
+  bool first = true;
+  for (auto const &t : toAdd) {
+    if (!first) {
+      ret += ",";
+    }
+    first = false;
+    ret += " " + t.toString();
+    dnt.addMask(t);
+  }
+
+  g_dontThrottleNetmasks.setState(dnt);
+
+  ret += " to the list of nameserver netmasks that may not be throttled";
+  g_log<<Logger::Info<<ret<<", requested via control channel"<<endl;
+  return ret + "\n";
+}
+
+template<typename T>
+static string clearDontThrottleNames(T begin, T end) {
+  if(begin == end)
+    return "No names specified, doing nothing.\n";
+
+  if (begin + 1 == end && *begin == "*"){
+    SuffixMatchNode smn;
+    g_dontThrottleNames.setState(smn);
+    string ret = "Cleared list of nameserver names that may not be throttled";
+    g_log<<Logger::Warning<<ret<<", requested via control channel"<<endl;
+    return ret + "\n";
+  }
+
+  vector<DNSName> toRemove;
+  while (begin != end) {
+    try {
+      if (*begin == "*") {
+        return "Please don't mix '*' with other names, nothing removed\n";
+      }
+      toRemove.push_back(DNSName(*begin));
+    }
+    catch (const std::exception &e) {
+      return "Problem parsing '" + *begin + "': "+ e.what() + ", nothing removed\n";
+    }
+    begin++;
+  }
+
+  string ret = "Removed";
+  bool first = true;
+  auto dnt = g_dontThrottleNames.getCopy();
+  for (const auto &name : toRemove) {
+    if (!first) {
+      ret += ",";
+    }
+    first = false;
+    ret += " " + name.toLogString();
+    dnt.remove(name);
+  }
+
+  g_dontThrottleNames.setState(dnt);
+
+  ret += " from the list of nameservers that may not be throttled";
+  g_log<<Logger::Info<<ret<<", requested via control channel"<<endl;
+  return ret + "\n";
+}
+
+template<typename T>
+static string clearDontThrottleNetmasks(T begin, T end) {
+  if(begin == end)
+    return "No netmasks specified, doing nothing.\n";
+
+  if (begin + 1 == end && *begin == "*"){
+    auto nmg = g_dontThrottleNetmasks.getCopy();
+    nmg.clear();
+    g_dontThrottleNetmasks.setState(nmg);
+
+    string ret = "Cleared list of nameserver addresses that may not be throttled";
+    g_log<<Logger::Warning<<ret<<", requested via control channel"<<endl;
+    return ret + "\n";
+  }
+
+  std::vector<Netmask> toRemove;
+  while (begin != end) {
+    try {
+      if (*begin == "*") {
+        return "Please don't mix '*' with other netmasks, nothing removed\n";
+      }
+      auto n = Netmask(*begin);
+      toRemove.push_back(n);
+    }
+    catch(const std::exception &e) {
+      return "Problem parsing '" + *begin + "': "+ e.what() + ", nothing added\n";
+    }
+    catch(const PDNSException &e) {
+      return "Problem parsing '" + *begin + "': "+ e.reason + ", nothing added\n";
+    }
+    begin++;
+  }
+
+  string ret = "Removed";
+  bool first = true;
+  auto dnt = g_dontThrottleNetmasks.getCopy();
+  for (const auto &mask : toRemove) {
+    if (!first) {
+      ret += ",";
+    }
+    first = false;
+    ret += " " + mask.toString();
+    dnt.deleteMask(mask);
+  }
+
+  g_dontThrottleNetmasks.setState(dnt);
+
+  ret += " from the list of nameservers that may not be throttled";
+  g_log<<Logger::Info<<ret<<", requested via control channel"<<endl;
+  return ret + "\n";
+}
+
+
 string RecursorControlParser::getAnswer(const string& question, RecursorControlParser::func_t** command)
 {
   *command=nop;
@@ -1413,9 +1597,15 @@ string RecursorControlParser::getAnswer(const string& question, RecursorControlP
   // should probably have a smart dispatcher here, like auth has
   if(cmd=="help")
     return
+"add-dont-throttle-names [N...]   add names that are not allowed to be throttled\n"
+"add-dont-throttle-netmasks [N...]\n"
+"                                 add netmasks that are not allowed to be throttled\n"
 "add-nta DOMAIN [REASON]          add a Negative Trust Anchor for DOMAIN with the comment REASON\n"
 "add-ta DOMAIN DSRECORD           add a Trust Anchor for DOMAIN with data DSRECORD\n"
 "current-queries                  show currently active queries\n"
+"clear-dont-throttle-names [N...] remove names that are not allowed to be throttled. If N is '*', remove all\n"
+"clear-dont-throttle-netmasks [N...]\n"
+"                                 remove netmasks that are not allowed to be throttled. If N is '*', remove all\n"
 "clear-nta [DOMAIN]...            Clear the Negative Trust Anchor for DOMAINs, if no DOMAIN is specified, remove all\n"
 "clear-ta [DOMAIN]...             Clear the Trust Anchor for DOMAINs\n"
 "dump-cache <filename>            dump cache contents to the named file\n"
@@ -1425,6 +1615,8 @@ string RecursorControlParser::getAnswer(const string& question, RecursorControlP
 "dump-throttlemap <filename>      dump the contents of the throttle to the named file\n"
 "get [key1] [key2] ..             get specific statistics\n"
 "get-all                          get all statistics\n"
+"get-dont-throttle-names          get the list of names that are not allowed to be throttled\n"
+"get-dont-throttle-netmasks       get the list of netmasks that are not allowed to be throttled\n"
 "get-ntas                         get all configured Negative Trust Anchors\n"
 "get-tas                          get all configured Trust Anchors\n"
 "get-parameter [key1] [key2] ..   get configuration parameters\n"
@@ -1655,5 +1847,29 @@ string RecursorControlParser::getAnswer(const string& question, RecursorControlP
   if (cmd=="set-dnssec-log-bogus")
     return doSetDnssecLogBogus(begin, end);
 
+  if (cmd == "get-dont-throttle-names") {
+    return getDontThrottleNames();
+  }
+
+  if (cmd == "get-dont-throttle-netmasks") {
+    return getDontThrottleNetmasks();
+  }
+
+  if (cmd == "add-dont-throttle-names") {
+    return addDontThrottleNames(begin, end);
+  }
+
+  if (cmd == "add-dont-throttle-netmasks") {
+    return addDontThrottleNetmasks(begin, end);
+  }
+
+  if (cmd == "clear-dont-throttle-names") {
+    return clearDontThrottleNames(begin, end);
+  }
+
+  if (cmd == "clear-dont-throttle-netmasks") {
+    return clearDontThrottleNetmasks(begin, end);
+  }
+
   return "Unknown command '"+cmd+"', try 'help'\n";
 }
diff --git a/pdns/recursordist/docs/http-api/endpoint-jsonstat.rst b/pdns/recursordist/docs/http-api/endpoint-jsonstat.rst
new file mode 100644 (file)
index 0000000..768368c
--- /dev/null
@@ -0,0 +1,245 @@
+jsonstat endpoint
+=================
+
+.. http:get:: /jsonstat
+
+  Get statistics from recursor in JSON format.
+  The ``Accept`` request header is ignored.
+  This endpoint accepts a ``command`` and ``name`` query for different statistics:
+
+  * ``get-query-ring``: Retrieve statistics from the query subsection. ``name`` can be ``servfail-queries`` or ``queries``. Supports optional argument ``public-filtered`` which if set to any value will group queries by the public suffix list.
+  * ``get-remote-ring``: Retrieve statistics from the remotes subsection. ``name`` can be ``remotes``, ``servfail-remotes``, ``bogus-remotes`` (added in 4.2.0), ``large-answer-remotes``, or ``timeouts`` (added in 4.2.0).
+
+  **Example request**:
+
+   .. sourcecode:: http
+
+      GET /jsonstat?command=get-query-ring&name=servfail-queries HTTP/1.1
+      Host: example.com
+      Accept: application/json, text/javascript
+      X-API-Key: examplekey
+
+  **Example response**:
+
+   .. sourcecode:: http
+
+      HTTP/1.1 200 OK
+      Access-Control-Allow-Origin: *
+      Connection: close
+      Content-Length: 94
+      Content-Security-Policy: default-src 'self'; style-src 'self' 'unsafe-inline'
+      Content-Type: application/json
+      Server: PowerDNS/4.1.11
+      X-Content-Type-Options: nosniff
+      X-Frame-Options: deny
+      X-Permitted-Cross-Domain-Policies: none
+      X-Xss-Protection: 1; mode=block
+
+      {"entries": [[2, "wpad.americas.hpecorp.net", "A"], [1, "wpad.americas.hpecorp.net", "AAAA"]]}
+
+  **Example request**:
+
+   .. sourcecode:: http
+
+      GET /jsonstat?command=get-query-ring&name=queries HTTP/1.1
+      Host: example.com
+      Accept: application/json, text/javascript
+      X-API-Key: examplekey
+
+  **Example response**:
+
+   .. sourcecode:: http
+
+      HTTP/1.1 200 OK
+      Access-Control-Allow-Origin: *
+      Connection: close
+      Content-Length: 69
+      Content-Security-Policy: default-src 'self'; style-src 'self' 'unsafe-inline'
+      Content-Type: application/json
+      Server: PowerDNS/4.1.11
+      X-Content-Type-Options: nosniff
+      X-Frame-Options: deny
+      X-Permitted-Cross-Domain-Policies: none
+      X-Xss-Protection: 1; mode=block
+
+      {"entries": [[1, "a.powerdns.com", "A"], [1, "b.powerdns.com", "A"]]}
+
+  **Example request**:
+
+   .. sourcecode:: http
+
+      GET /jsonstat?command=get-query-ring&name=queries&public-filtered=true HTTP/1.1
+      Host: example.com
+      Accept: application/json, text/javascript
+      X-API-Key: examplekey
+
+  **Example response**:
+
+   .. sourcecode:: http
+
+      HTTP/1.1 200 OK
+      Access-Control-Allow-Origin: *
+      Connection: close
+      Content-Length: 39
+      Content-Security-Policy: default-src 'self'; style-src 'self' 'unsafe-inline'
+      Content-Type: application/json
+      Server: PowerDNS/4.1.11
+      X-Content-Type-Options: nosniff
+      X-Frame-Options: deny
+      X-Permitted-Cross-Domain-Policies: none
+      X-Xss-Protection: 1; mode=block
+
+      {"entries": [[2, "powerdns.com", "A"]]}
+
+  **Example request**:
+
+   .. sourcecode:: http
+
+      GET /jsonstat?command=get-remote-ring&name=remotes HTTP/1.1
+      Host: example.com
+      Accept: application/json, text/javascript
+      X-API-Key: examplekey
+
+  **Example response**:
+
+   .. sourcecode:: http
+
+      HTTP/1.1 200 OK
+      Access-Control-Allow-Origin: *
+      Connection: close
+      Content-Length: 62
+      Content-Security-Policy: default-src 'self'; style-src 'self' 'unsafe-inline'
+      Content-Type: application/json
+      Server: PowerDNS/4.1.11
+      X-Content-Type-Options: nosniff
+      X-Frame-Options: deny
+      X-Permitted-Cross-Domain-Policies: none
+      X-Xss-Protection: 1; mode=block
+
+      {"entries": [[11, "10.0.2.15"], [7, "::1"], [4, "127.0.0.1"]]}
+
+  **Example response**:
+
+   .. sourcecode:: http
+
+      HTTP/1.1 200 OK
+      Access-Control-Allow-Origin: *
+      Connection: close
+      Content-Length: 43
+      Content-Security-Policy: default-src 'self'; style-src 'self' 'unsafe-inline'
+      Content-Type: application/json
+      Server: PowerDNS/4.1.11
+      X-Content-Type-Options: nosniff
+      X-Frame-Options: deny
+      X-Permitted-Cross-Domain-Policies: none
+      X-Xss-Protection: 1; mode=block
+
+      {"entries": [[2, "::1"], [1, "127.0.0.1"]]}
+
+  **Example request**:
+
+   .. sourcecode:: http
+
+      GET /jsonstat?command=get-remote-ring&name=bogus-remotes HTTP/1.1
+      Host: example.com
+      Accept: application/json, text/javascript
+      X-API-Key: examplekey
+
+  **Example response**:
+
+   .. sourcecode:: http
+
+      HTTP/1.1 200 OK
+      Access-Control-Allow-Origin: *
+      Connection: close
+      Content-Length: 32
+      Content-Security-Policy: default-src 'self'; style-src 'self' 'unsafe-inline'
+      Content-Type: application/json
+      Server: PowerDNS/4.2.0-alpha1
+      X-Content-Type-Options: nosniff
+      X-Frame-Options: deny
+      X-Permitted-Cross-Domain-Policies: none
+      X-Xss-Protection: 1; mode=block
+
+      {"entries": [[20, "127.0.0.1"]]}
+
+  **Example request**:
+
+   .. sourcecode:: http
+
+      GET /jsonstat?command=get-remote-ring&name=servfail-remotes HTTP/1.1
+      Host: example.com
+      Accept: application/json, text/javascript
+      X-API-Key: examplekey
+
+  **Example response**:
+
+   .. sourcecode:: http
+
+      HTTP/1.1 200 OK
+      Access-Control-Allow-Origin: *
+      Connection: close
+      Content-Length: 31
+      Content-Security-Policy: default-src 'self'; style-src 'self' 'unsafe-inline'
+      Content-Type: application/json
+      Server: PowerDNS/4.1.11
+      X-Content-Type-Options: nosniff
+      X-Frame-Options: deny
+      X-Permitted-Cross-Domain-Policies: none
+      X-Xss-Protection: 1; mode=block
+
+      {"entries": [[4, "127.0.0.1"]]}
+
+  **Example request**:
+
+   .. sourcecode:: http
+
+      GET /jsonstat?command=get-remote-ring&name=large-answer-remotes HTTP/1.1
+      Host: example.com
+      Accept: application/json, text/javascript
+      X-API-Key: examplekey
+
+  **Example response**:
+
+   .. sourcecode:: http
+
+      HTTP/1.1 200 OK
+      Access-Control-Allow-Origin: *
+      Connection: close
+      Content-Length: 43
+      Content-Security-Policy: default-src 'self'; style-src 'self' 'unsafe-inline'
+      Content-Type: application/json
+      Server: PowerDNS/4.1.11
+      X-Content-Type-Options: nosniff
+      X-Frame-Options: deny
+      X-Permitted-Cross-Domain-Policies: none
+      X-Xss-Protection: 1; mode=block
+
+      {"entries": [[2, "127.0.0.1"], [1, "::1"]]}
+
+  **Example request**:
+
+   .. sourcecode:: http
+
+      GET /jsonstat?command=get-remote-ring&name=timeouts HTTP/1.1
+      Host: example.com
+      Accept: application/json, text/javascript
+      X-API-Key: examplekey
+
+  **Example response**:
+
+   .. sourcecode:: http
+
+      HTTP/1.1 200 OK
+      Access-Control-Allow-Origin: *
+      Connection: close
+      Content-Length: 189
+      Content-Security-Policy: default-src 'self'; style-src 'self' 'unsafe-inline'
+      Content-Type: application/json
+      Server: PowerDNS/4.2.0-alpha1
+      X-Content-Type-Options: nosniff
+      X-Frame-Options: deny
+      X-Permitted-Cross-Domain-Policies: none
+      X-Xss-Protection: 1; mode=block
+
+      {"entries": [[3, "15.219.145.20"], [3, "15.211.192.20"], [2, "15.219.160.20"], [2, "15.203.224.20"], [2, "15.219.145.21"], [2, "15.219.160.21"], [2, "15.211.192.21"], [2, "15.203.224.21"]]}
index 41e6f6bce1214a9a5861a14d42aeb0f6aa71b0fd..9fd799638717236d8a452f0e65595b2767500a48 100644 (file)
@@ -64,3 +64,4 @@ All API endpoints for the PowerDNS Recursor are documented here:
   endpoint-cache
   endpoint-failure
   endpoint-rpz-stats
+  endpoint-jsonstat
index 8fa4b018cdaba19ce3a1752361ba157cc67c16ed..8dbb587bfab97f4253214a86740228c08f1ba804 100644 (file)
@@ -45,6 +45,12 @@ Options
 
 Commands
 --------
+add-dont-throttle-names NAME [NAME...]
+    Add names for nameserver domains that may not be throttled.
+
+add-dont-throttle-netmasks NETMASK [NETMASK...]
+    Add netmasks for nameservers that may not be throttled.
+
 add-nta *DOMAIN* [*REASON*]
     Add a Negative Trust Anchor for *DOMAIN*, suffixed optionally with
     *REASON*.
@@ -56,6 +62,12 @@ add-ta *DOMAIN* *DSRECORD*
 current-queries
     Shows the currently active queries.
 
+clear-dont-throttle-names NAME [NAME...]
+    Remove names that are not allowed to be throttled. If *NAME* is '*', remove all
+
+clear-dont-throttle-netmasks NETMASK [NETMASK...]
+    Remove netmasks that are not allowed to be throttled. If *NETMASK* is '*', remove all
+
 clear-nta *DOMAIN*...
     Remove Negative Trust Anchor for one or more *DOMAIN*\ s. Set domain to
     '*' to remove all NTA's.
@@ -144,6 +156,12 @@ get *STATISTIC* [*STATISTIC*]...
 get-all
     Retrieve all known statistics.
 
+get-dont-throttle-names
+    Get the list of names that are not allowed to be throttled.
+
+get-dont-throttle-netmasks
+    Get the list of netmasks that are not allowed to be throttled.
+
 get-ntas
     Get a list of the currently configured Negative Trust Anchors.
 
index 18627082c2e1f20565d721a4829a3a9a6ddf2640..a867200c42503031e563404f35141b8dcb27045a 100644 (file)
@@ -257,6 +257,40 @@ Operate in the background.
 
 Which domains we only accept delegations from (a Verisign special).
 
+.. _setting-dont-throttle-names:
+
+``dont-throttle-names``
+----------------------------
+.. versionadded:: 4.2.0
+
+-  Comma separated list of domain-names
+-  Default: (empty)
+
+When an authoritative server does not answer a query or sends a reply the recursor does not like, it is throttled.
+Any servers' name suffix-matching the supplied names will never be throttled.
+
+.. warning::
+  Most servers on the internet do not respond for a good reason (overloaded or unreachable), ``dont-throttle-names`` could make this load on the upstream server even higher, resulting in further service degradation.
+
+.. _setting-dont-throttle-netmasks:
+
+``dont-throttle-netmasks``
+----------------------------
+.. versionadded:: 4.2.0
+
+-  Comma separated list of netmasks
+-  Default: (empty)
+
+When an authoritative server does not answer a query or sends a reply the recursor does not like, it is throttled.
+Any servers matching the supplied netmasks will never be throttled.
+
+This can come in handy on lossy networks when forwarding, where the same server is configured multiple times (e.g. with ``forward-zones-recurse=example.com=192.0.2.1;192.0.2.1``).
+By default, the PowerDNS Recursor would throttle the "first" server on a timeout and hence not retry the "second" one.
+In this case, ``dont-throttle-netmasks`` could be set to ``192.0.2.1``.
+
+.. warning::
+  Most servers on the internet do not respond for a good reason (overloaded or unreachable), ``dont-throttle-netmasks`` could make this load on the upstream server even higher, resulting in further service degradation.
+
 .. _setting-disable-packetcache:
 
 ``disable-packetcache``
@@ -297,6 +331,21 @@ average load. This helps making sure that all the workers have roughly the same
 share of queries, even if the incoming traffic is very skewed, with a larger
 number of requests asking for the same qname.
 
+.. _setting-distribution-pipe-buffer-size:
+
+``distribution-pipe-buffer-size``
+---------------------------------
+.. versionadded:: 4.2.0
+
+-  Integer
+-  Default: 0
+
+Size in bytes of the internal buffer of the pipe used by the distributor to pass incoming queries to a worker thread.
+Requires support for `F_SETPIPE_SZ` which is present in Linux since 2.6.35. The actual size might be rounded up to
+a multiple of a page size. 0 means that the OS default size is used.
+A large buffer might allow the recursor to deal with very short-lived load spikes during which a worker thread gets
+overloaded, but it will be at the cost of an increased latency.
+
 .. _setting-distributor-threads:
 
 ``distributor-threads``
@@ -1718,7 +1767,7 @@ If a PID file should be written to `socket-dir`_
 The server will trust XPF records found in queries sent from those netmasks (both IPv4 and IPv6),
 and will adjust queries' source and destination accordingly. This is especially useful when the recursor
 is placed behind a proxy like `dnsdist <https://dnsdist.org>`_.
-Note that the ref:`setting-allow-from` setting is still applied to the original source address, and thus access restriction
+Note that the :ref:`setting-allow-from` setting is still applied to the original source address, and thus access restriction
 should be done on the proxy.
 
 .. _setting-xpf-rr-code:
index 0f5325c33a4f0fe51f51226267b7d299562313ca..f7f5646f45d345f95e6ee50d469b1d4d264ade34 100644 (file)
@@ -101,7 +101,7 @@ bool NegCache::get(const DNSName& qname, const QType& qtype, const struct timeva
  * \param ne The NegCacheEntry to add to the cache
  */
 void NegCache::add(const NegCacheEntry& ne) {
-  replacing_insert(d_negcache, ne);
+  lruReplacingInsert(d_negcache, ne);
 }
 
 /*!
index f5ddec76b9a8e5256ffafdb39d9db1001fe1e26a..b67874c2ee1ff357e620e167e881423d851dfaee 100644 (file)
@@ -264,6 +264,59 @@ BOOST_AUTO_TEST_CASE(test_prune) {
   BOOST_CHECK_EQUAL(cache.size(), 100);
 }
 
+BOOST_AUTO_TEST_CASE(test_prune_valid_entries) {
+  DNSName power1("powerdns.com.");
+  DNSName power2("powerdns-1.com.");
+  DNSName auth("com.");
+
+  struct timeval now;
+  Utility::gettimeofday(&now, 0);
+
+  NegCache cache;
+  NegCache::NegCacheEntry ne;
+
+  /* insert power1 then power2 */
+  ne = genNegCacheEntry(power1, auth, now);
+  cache.add(ne);
+  ne = genNegCacheEntry(power2, auth, now);
+  cache.add(ne);
+
+  BOOST_CHECK_EQUAL(cache.size(), 2);
+
+  /* power2 has been inserted more recently, so it should be
+     removed last */
+  cache.prune(1);
+  BOOST_CHECK_EQUAL(cache.size(), 1);
+
+  const NegCache::NegCacheEntry* got = nullptr;
+  bool ret = cache.get(power2, QType(1), now, &got);
+  BOOST_REQUIRE(ret);
+  BOOST_CHECK_EQUAL(got->d_name, power2);
+  BOOST_CHECK_EQUAL(got->d_auth, auth);
+
+  /* insert power1 back */
+  ne = genNegCacheEntry(power1, auth, now);
+  cache.add(ne);
+  BOOST_CHECK_EQUAL(cache.size(), 2);
+
+  /* replace the entry for power2 */
+  ne = genNegCacheEntry(power2, auth, now);
+  cache.add(ne);
+
+  BOOST_CHECK_EQUAL(cache.size(), 2);
+
+  /* power2 has been updated more recently, so it should be
+     removed last */
+  cache.prune(1);
+
+  BOOST_CHECK_EQUAL(cache.size(), 1);
+  got = nullptr;
+  ret = cache.get(power2, QType(1), now, &got);
+  BOOST_REQUIRE(ret);
+  BOOST_CHECK_EQUAL(got->d_name, power2);
+  BOOST_CHECK_EQUAL(got->d_auth, auth);
+}
+
 BOOST_AUTO_TEST_CASE(test_wipe_single) {
   string qname(".powerdns.com");
   DNSName auth("powerdns.com");
index f31f115e721658bfe8bc689fd76acb1118693c86..9634dcfe916bec168bcec490bb0354ec2e336db7 100644 (file)
@@ -17,6 +17,8 @@
 
 RecursorStats g_stats;
 GlobalStateHolder<LuaConfigItems> g_luaconfs;
+GlobalStateHolder<SuffixMatchNode> g_dontThrottleNames;
+GlobalStateHolder<NetmaskGroup> g_dontThrottleNetmasks;
 thread_local std::unique_ptr<MemRecursorCache> t_RC{nullptr};
 unsigned int g_numThreads = 1;
 bool g_lowercaseOutgoing = false;
@@ -6608,6 +6610,123 @@ BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec_wildcard_missing) {
   BOOST_CHECK_EQUAL(queriesCount, 9);
 }
 
+BOOST_AUTO_TEST_CASE(test_dnssec_validation_wildcard_expanded_onto_itself) {
+  std::unique_ptr<SyncRes> sr;
+  initSR(sr, true);
+
+  setDNSSECValidation(sr, DNSSECMode::ValidateAll);
+
+  primeHints();
+  const DNSName target("*.powerdns.com.");
+  testkeysset_t keys;
+
+  auto luaconfsCopy = g_luaconfs.getCopy();
+  luaconfsCopy.dsAnchors.clear();
+  generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
+  generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
+  generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
+
+  g_luaconfs.setState(luaconfsCopy);
+
+  sr->setAsyncCallback([target,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) {
+
+      if (type == QType::DS || type == QType::DNSKEY) {
+        if (domain == target) {
+          const auto auth = DNSName("powerdns.com.");
+          /* we don't want a cut there */
+          setLWResult(res, 0, true, false, true);
+          addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
+          addRRSIG(keys, res->d_records, auth, 300);
+          /* add a NSEC denying the DS */
+          std::set<uint16_t> types = { QType::NSEC };
+          addNSECRecordToLW(domain, DNSName("z") + domain, types, 600, res->d_records);
+          addRRSIG(keys, res->d_records, auth, 300);
+          return 1;
+        }
+        return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
+      }
+      else {
+        setLWResult(res, 0, true, false, true);
+        addRecordToLW(res, domain, QType::A, "192.0.2.42");
+        addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300, false, boost::none, DNSName("*.powerdns.com"));
+        /* we don't _really_ need to add the proof that the exact name does not exist because it does,
+           it's the wildcard itself, but let's do it so other validators don't choke on it */
+        addNSECRecordToLW(DNSName("*.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
+        addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
+        return 1;
+      }
+    });
+
+  vector<DNSRecord> ret;
+  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
+  BOOST_CHECK_EQUAL(res, RCode::NoError);
+  BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
+  /* A + RRSIG, NSEC + RRSIG */
+  BOOST_REQUIRE_EQUAL(ret.size(), 4);
+}
+
+BOOST_AUTO_TEST_CASE(test_dnssec_validation_wildcard_like_expanded_from_wildcard) {
+  std::unique_ptr<SyncRes> sr;
+  initSR(sr, true);
+
+  setDNSSECValidation(sr, DNSSECMode::ValidateAll);
+
+  primeHints();
+  const DNSName target("*.sub.powerdns.com.");
+  testkeysset_t keys;
+
+  auto luaconfsCopy = g_luaconfs.getCopy();
+  luaconfsCopy.dsAnchors.clear();
+  generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
+  generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
+  generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
+
+  g_luaconfs.setState(luaconfsCopy);
+
+  sr->setAsyncCallback([target,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) {
+
+      if (type == QType::DS || type == QType::DNSKEY) {
+        if (domain == target) {
+          const auto auth = DNSName("powerdns.com.");
+          /* we don't want a cut there */
+          setLWResult(res, 0, true, false, true);
+          addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
+          addRRSIG(keys, res->d_records, auth, 300);
+          addNSECRecordToLW(DNSName("*.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
+          addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
+          return 1;
+        }
+        else if (domain == DNSName("sub.powerdns.com.")) {
+          const auto auth = DNSName("powerdns.com.");
+          /* we don't want a cut there */
+          setLWResult(res, 0, true, false, true);
+          addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
+          addRRSIG(keys, res->d_records, auth, 300);
+          /* add a NSEC denying the DS */
+          addNSECRecordToLW(DNSName("*.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
+          addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
+          return 1;
+        }
+        return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
+      }
+      else {
+        setLWResult(res, 0, true, false, true);
+        addRecordToLW(res, domain, QType::A, "192.0.2.42");
+        addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300, false, boost::none, DNSName("*.powerdns.com"));
+        addNSECRecordToLW(DNSName("*.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
+        addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
+        return 1;
+      }
+    });
+
+  vector<DNSRecord> ret;
+  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
+  BOOST_CHECK_EQUAL(res, RCode::NoError);
+  BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
+  /* A + RRSIG, NSEC + RRSIG */
+  BOOST_REQUIRE_EQUAL(ret.size(), 4);
+}
+
 BOOST_AUTO_TEST_CASE(test_dnssec_no_ds_on_referral_secure) {
   std::unique_ptr<SyncRes> sr;
   initSR(sr, true);
@@ -11109,6 +11228,516 @@ BOOST_AUTO_TEST_CASE(test_records_sanitization_scrubs_ns_nxd) {
   BOOST_CHECK_LT(t_RC->get(now, DNSName("spoofed.ns."), QType(QType::AAAA), false, &cached, who), 0);
 }
 
+BOOST_AUTO_TEST_CASE(test_dname_processing) {
+  std::unique_ptr<SyncRes> sr;
+  initSR(sr);
+
+  primeHints();
+
+  const DNSName dnameOwner("powerdns.com");
+  const DNSName dnameTarget("powerdns.net");
+
+  const DNSName target("dname.powerdns.com.");
+  const DNSName cnameTarget("dname.powerdns.net");
+
+  const DNSName uncachedTarget("dname-uncached.powerdns.com.");
+  const DNSName uncachedCNAMETarget("dname-uncached.powerdns.net.");
+
+  const DNSName synthCNAME("cname-uncached.powerdns.com.");
+  const DNSName synthCNAMETarget("cname-uncached.powerdns.net.");
+
+  size_t queries = 0;
+
+  sr->setAsyncCallback([dnameOwner, dnameTarget, target, cnameTarget, uncachedTarget, uncachedCNAMETarget, &queries](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) {
+      queries++;
+
+      if (isRootServer(ip)) {
+        if (domain.isPartOf(dnameOwner)) {
+          setLWResult(res, 0, false, false, true);
+          addRecordToLW(res, dnameOwner, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
+          addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
+          return 1;
+        }
+        if (domain.isPartOf(dnameTarget)) {
+          setLWResult(res, 0, false, false, true);
+          addRecordToLW(res, dnameTarget, QType::NS, "b.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
+          addRecordToLW(res, "b.gtld-servers.net.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
+          return 1;
+        }
+      } else if (ip == ComboAddress("192.0.2.1:53")) {
+        if (domain == target) {
+          setLWResult(res, 0, true, false, false);
+          addRecordToLW(res, dnameOwner, QType::DNAME, dnameTarget.toString());
+          addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
+          return 1;
+        }
+      } else if (ip == ComboAddress("192.0.2.2:53")) {
+        if (domain == cnameTarget) {
+          setLWResult(res, 0, true, false, false);
+          addRecordToLW(res, domain, QType::A, "192.0.2.2");
+        }
+        if (domain == uncachedCNAMETarget) {
+          setLWResult(res, 0, true, false, false);
+          addRecordToLW(res, domain, QType::A, "192.0.2.3");
+        }
+        return 1;
+      }
+      return 0;
+    });
+
+  vector<DNSRecord> ret;
+  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
+
+  BOOST_CHECK_EQUAL(res, RCode::NoError);
+  BOOST_REQUIRE_EQUAL(ret.size(), 3);
+
+  BOOST_CHECK_EQUAL(queries, 4);
+
+  BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
+  BOOST_CHECK(ret[0].d_name == dnameOwner);
+  BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
+
+  BOOST_CHECK(ret[1].d_type == QType::CNAME);
+  BOOST_CHECK_EQUAL(ret[1].d_name, target);
+
+  BOOST_CHECK(ret[2].d_type == QType::A);
+  BOOST_CHECK_EQUAL(ret[2].d_name, cnameTarget);
+
+  // Now check the cache
+  ret.clear();
+  res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
+
+  BOOST_CHECK_EQUAL(res, RCode::NoError);
+  BOOST_REQUIRE_EQUAL(ret.size(), 3);
+
+  BOOST_CHECK_EQUAL(queries, 4);
+
+  BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
+  BOOST_CHECK(ret[0].d_name == dnameOwner);
+  BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
+
+  BOOST_CHECK(ret[1].d_type == QType::CNAME);
+  BOOST_CHECK_EQUAL(ret[1].d_name, target);
+
+  BOOST_CHECK(ret[2].d_type == QType::A);
+  BOOST_CHECK_EQUAL(ret[2].d_name, cnameTarget);
+
+  // Check if we correctly return a synthesizd CNAME, should send out just 1 more query
+  ret.clear();
+  res = sr->beginResolve(uncachedTarget, QType(QType::A), QClass::IN, ret);
+
+  BOOST_CHECK_EQUAL(res, RCode::NoError);
+  BOOST_CHECK_EQUAL(queries, 5);
+
+  BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
+  BOOST_CHECK(ret[0].d_name == dnameOwner);
+  BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
+
+  BOOST_REQUIRE(ret[1].d_type == QType::CNAME);
+  BOOST_CHECK_EQUAL(ret[1].d_name, uncachedTarget);
+  BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[1])->getTarget(), uncachedCNAMETarget);
+
+  BOOST_CHECK(ret[2].d_type == QType::A);
+  BOOST_CHECK_EQUAL(ret[2].d_name, uncachedCNAMETarget);
+
+  // Check if we correctly return the DNAME from cache when asked
+  ret.clear();
+  res = sr->beginResolve(dnameOwner, QType(QType::DNAME), QClass::IN, ret);
+  BOOST_CHECK_EQUAL(res, RCode::NoError);
+  BOOST_CHECK_EQUAL(queries, 5);
+
+  BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
+  BOOST_CHECK(ret[0].d_name == dnameOwner);
+  BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
+
+  // Check if we correctly return the synthesized CNAME from cache when asked
+  ret.clear();
+  res = sr->beginResolve(synthCNAME, QType(QType::CNAME), QClass::IN, ret);
+  BOOST_CHECK_EQUAL(res, RCode::NoError);
+  BOOST_CHECK_EQUAL(queries, 5);
+
+  BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
+  BOOST_CHECK(ret[0].d_name == dnameOwner);
+  BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
+
+  BOOST_REQUIRE(ret[1].d_type == QType::CNAME);
+  BOOST_CHECK(ret[1].d_name == synthCNAME);
+  BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[1])->getTarget(), synthCNAMETarget);
+}
+
+BOOST_AUTO_TEST_CASE(test_dname_dnssec_secure) {
+  std::unique_ptr<SyncRes> sr;
+  initSR(sr, true);
+  setDNSSECValidation(sr, DNSSECMode::ValidateAll);
+
+  primeHints();
+
+  const DNSName dnameOwner("powerdns");
+  const DNSName dnameTarget("example");
+
+  const DNSName target("dname.powerdns");
+  const DNSName cnameTarget("dname.example");
+
+  testkeysset_t keys;
+
+  auto luaconfsCopy = g_luaconfs.getCopy();
+  luaconfsCopy.dsAnchors.clear();
+  generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
+  generateKeyMaterial(dnameOwner, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
+  generateKeyMaterial(dnameTarget, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
+  g_luaconfs.setState(luaconfsCopy);
+
+  size_t queries = 0;
+
+  sr->setAsyncCallback([dnameOwner, dnameTarget, target, cnameTarget, keys, &queries](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) {
+      queries++;
+      /* We don't use the genericDSAndDNSKEYHandler here, as it would deny names existing at the wrong level of the tree, due to the way computeZoneCuts works
+       * As such, we need to do some more work to make the answers correct.
+       */
+
+      if (isRootServer(ip)) {
+        if (domain.countLabels() == 0 && type == QType::DNSKEY) { // .|DNSKEY
+          setLWResult(res, 0, true, false, true);
+          addDNSKEY(keys, domain, 300, res->d_records);
+          addRRSIG(keys, res->d_records, DNSName("."), 300);
+          return 1;
+        }
+        if (domain.countLabels() == 1 && type == QType::DS) { // powerdns|DS or example|DS
+          setLWResult(res, 0, true, false, true);
+          addDS(domain, 300, res->d_records, keys);
+          addRRSIG(keys, res->d_records, DNSName("."), 300);
+          return 1;
+        }
+        // For the rest, delegate!
+        if (domain.isPartOf(dnameOwner)) {
+          setLWResult(res, 0, false, false, true);
+          addRecordToLW(res, dnameOwner, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
+          addDS(dnameOwner, 300, res->d_records, keys);
+          addRRSIG(keys, res->d_records, DNSName("."), 300);
+          addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
+          return 1;
+        }
+        if (domain.isPartOf(dnameTarget)) {
+          setLWResult(res, 0, false, false, true);
+          addRecordToLW(res, dnameTarget, QType::NS, "b.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
+          addDS(dnameTarget, 300, res->d_records, keys);
+          addRRSIG(keys, res->d_records, DNSName("."), 300);
+          addRecordToLW(res, "b.gtld-servers.net.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
+          return 1;
+        }
+      } else if (ip == ComboAddress("192.0.2.1:53")) {
+        if (domain.countLabels() == 1 && type == QType::DNSKEY) { // powerdns|DNSKEY
+          setLWResult(res, 0, true, false, true);
+          addDNSKEY(keys, domain, 300, res->d_records);
+          addRRSIG(keys, res->d_records, domain, 300);
+          return 1;
+        }
+        if (domain == target && type == QType::DS) { // dname.powerdns|DS
+          return genericDSAndDNSKEYHandler(res, domain, dnameOwner, type, keys);
+        }
+        if (domain == target) {
+          setLWResult(res, 0, true, false, false);
+          addRecordToLW(res, dnameOwner, QType::DNAME, dnameTarget.toString());
+          addRRSIG(keys, res->d_records, dnameOwner, 300);
+          addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString()); // CNAME from a DNAME is not signed
+          return 1;
+        }
+      } else if (ip == ComboAddress("192.0.2.2:53")) {
+        if (domain.countLabels() == 1 && type == QType::DNSKEY) { // example|DNSKEY
+          setLWResult(res, 0, true, false, true);
+          addDNSKEY(keys, domain, 300, res->d_records);
+          addRRSIG(keys, res->d_records, domain, 300);
+          return 1;
+        }
+        if (domain == target && type == QType::DS) { // dname.example|DS
+          return genericDSAndDNSKEYHandler(res, domain, dnameTarget, type, keys);
+        }
+        if (domain == cnameTarget) {
+          setLWResult(res, 0, true, false, false);
+          addRecordToLW(res, domain, QType::A, "192.0.2.2");
+          addRRSIG(keys, res->d_records, dnameTarget, 300);
+        }
+        return 1;
+      }
+      return 0;
+    });
+
+  vector<DNSRecord> ret;
+  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
+
+  BOOST_CHECK_EQUAL(res, RCode::NoError);
+  BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
+  BOOST_REQUIRE_EQUAL(ret.size(), 5); /* DNAME + RRSIG(DNAME) + CNAME + A + RRSIG(A) */
+
+  BOOST_CHECK_EQUAL(queries, 11);
+
+  BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
+  BOOST_CHECK(ret[0].d_name == dnameOwner);
+  BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
+
+  BOOST_REQUIRE(ret[1].d_type == QType::RRSIG);
+  BOOST_CHECK_EQUAL(ret[1].d_name, dnameOwner);
+
+  BOOST_CHECK(ret[2].d_type == QType::CNAME);
+  BOOST_CHECK_EQUAL(ret[2].d_name, target);
+
+  BOOST_CHECK(ret[3].d_type == QType::A);
+  BOOST_CHECK_EQUAL(ret[3].d_name, cnameTarget);
+
+  BOOST_CHECK(ret[4].d_type == QType::RRSIG);
+  BOOST_CHECK_EQUAL(ret[4].d_name, cnameTarget);
+
+  // And the cache
+  ret.clear();
+  res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
+
+  BOOST_CHECK_EQUAL(res, RCode::NoError);
+  BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
+  BOOST_REQUIRE_EQUAL(ret.size(), 5); /* DNAME + RRSIG(DNAME) + CNAME + A + RRSIG(A) */
+
+  BOOST_CHECK_EQUAL(queries, 11);
+
+  BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
+  BOOST_CHECK(ret[0].d_name == dnameOwner);
+  BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
+
+  BOOST_CHECK(ret[1].d_type == QType::RRSIG);
+  BOOST_CHECK_EQUAL(ret[1].d_name, dnameOwner);
+
+  BOOST_CHECK(ret[2].d_type == QType::CNAME);
+  BOOST_CHECK_EQUAL(ret[2].d_name, target);
+
+  BOOST_CHECK(ret[3].d_type == QType::A);
+  BOOST_CHECK_EQUAL(ret[3].d_name, cnameTarget);
+
+  BOOST_CHECK(ret[4].d_type == QType::RRSIG);
+  BOOST_CHECK_EQUAL(ret[4].d_name, cnameTarget);
+
+}
+
+BOOST_AUTO_TEST_CASE(test_dname_dnssec_insecure) {
+  /*
+   * The DNAME itself is signed, but the final A record is not
+   */
+  std::unique_ptr<SyncRes> sr;
+  initSR(sr, true);
+  setDNSSECValidation(sr, DNSSECMode::ValidateAll);
+
+  primeHints();
+
+  const DNSName dnameOwner("powerdns");
+  const DNSName dnameTarget("example");
+
+  const DNSName target("dname.powerdns");
+  const DNSName cnameTarget("dname.example");
+
+  testkeysset_t keys;
+
+  auto luaconfsCopy = g_luaconfs.getCopy();
+  luaconfsCopy.dsAnchors.clear();
+  generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
+  generateKeyMaterial(dnameOwner, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
+  g_luaconfs.setState(luaconfsCopy);
+
+  size_t queries = 0;
+
+  sr->setAsyncCallback([dnameOwner, dnameTarget, target, cnameTarget, keys, &queries](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) {
+      queries++;
+
+      if (isRootServer(ip)) {
+        if (domain.countLabels() == 0 && type == QType::DNSKEY) { // .|DNSKEY
+          setLWResult(res, 0, true, false, true);
+          addDNSKEY(keys, domain, 300, res->d_records);
+          addRRSIG(keys, res->d_records, DNSName("."), 300);
+          return 1;
+        }
+        if (domain == dnameOwner && type == QType::DS) { // powerdns|DS
+          setLWResult(res, 0, true, false, true);
+          addDS(domain, 300, res->d_records, keys);
+          addRRSIG(keys, res->d_records, DNSName("."), 300);
+          return 1;
+        }
+        if (domain == dnameTarget && type == QType::DS) { // example|DS
+          return genericDSAndDNSKEYHandler(res, domain, DNSName("."), type, keys);
+        }
+        // For the rest, delegate!
+        if (domain.isPartOf(dnameOwner)) {
+          setLWResult(res, 0, false, false, true);
+          addRecordToLW(res, dnameOwner, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
+          addDS(dnameOwner, 300, res->d_records, keys);
+          addRRSIG(keys, res->d_records, DNSName("."), 300);
+          addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
+          return 1;
+        }
+        if (domain.isPartOf(dnameTarget)) {
+          setLWResult(res, 0, false, false, true);
+          addRecordToLW(res, dnameTarget, QType::NS, "b.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
+          addDS(dnameTarget, 300, res->d_records, keys);
+          addRRSIG(keys, res->d_records, DNSName("."), 300);
+          addRecordToLW(res, "b.gtld-servers.net.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
+          return 1;
+        }
+      } else if (ip == ComboAddress("192.0.2.1:53")) {
+        if (domain.countLabels() == 1 && type == QType::DNSKEY) { // powerdns|DNSKEY
+          setLWResult(res, 0, true, false, true);
+          addDNSKEY(keys, domain, 300, res->d_records);
+          addRRSIG(keys, res->d_records, domain, 300);
+          return 1;
+        }
+        if (domain == target && type == QType::DS) { // dname.powerdns|DS
+          return genericDSAndDNSKEYHandler(res, domain, dnameOwner, type, keys);
+        }
+        if (domain == target) {
+          setLWResult(res, 0, true, false, false);
+          addRecordToLW(res, dnameOwner, QType::DNAME, dnameTarget.toString());
+          addRRSIG(keys, res->d_records, dnameOwner, 300);
+          addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString()); // CNAME from a DNAME is not signed
+          return 1;
+        }
+      } else if (ip == ComboAddress("192.0.2.2:53")) {
+        if (domain == target && type == QType::DS) { // dname.example|DS
+          return genericDSAndDNSKEYHandler(res, domain, dnameTarget, type, keys);
+        }
+        if (domain == cnameTarget) {
+          setLWResult(res, 0, true, false, false);
+          addRecordToLW(res, domain, QType::A, "192.0.2.2");
+        }
+        return 1;
+      }
+      return 0;
+    });
+
+  vector<DNSRecord> ret;
+  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
+
+  BOOST_CHECK_EQUAL(res, RCode::NoError);
+  BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
+  BOOST_REQUIRE_EQUAL(ret.size(), 4); /* DNAME + RRSIG(DNAME) + CNAME + A */
+
+  BOOST_CHECK_EQUAL(queries, 9);
+
+  BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
+  BOOST_CHECK(ret[0].d_name == dnameOwner);
+  BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
+
+  BOOST_CHECK(ret[1].d_type == QType::RRSIG);
+  BOOST_CHECK_EQUAL(ret[1].d_name, dnameOwner);
+
+  BOOST_CHECK(ret[2].d_type == QType::CNAME);
+  BOOST_CHECK_EQUAL(ret[2].d_name, target);
+
+  BOOST_CHECK(ret[3].d_type == QType::A);
+  BOOST_CHECK_EQUAL(ret[3].d_name, cnameTarget);
+
+  // And the cache
+  ret.clear();
+  res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
+
+  BOOST_CHECK_EQUAL(res, RCode::NoError);
+  BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
+  BOOST_REQUIRE_EQUAL(ret.size(), 4); /* DNAME + RRSIG(DNAME) + CNAME + A */
+
+  BOOST_CHECK_EQUAL(queries, 9);
+
+  BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
+  BOOST_CHECK(ret[0].d_name == dnameOwner);
+  BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
+
+  BOOST_CHECK(ret[1].d_type == QType::RRSIG);
+  BOOST_CHECK_EQUAL(ret[1].d_name, dnameOwner);
+
+  BOOST_CHECK(ret[2].d_type == QType::CNAME);
+  BOOST_CHECK_EQUAL(ret[2].d_name, target);
+
+  BOOST_CHECK(ret[3].d_type == QType::A);
+  BOOST_CHECK_EQUAL(ret[3].d_name, cnameTarget);
+}
+
+BOOST_AUTO_TEST_CASE(test_dname_processing_no_CNAME) {
+  std::unique_ptr<SyncRes> sr;
+  initSR(sr);
+
+  primeHints();
+
+  const DNSName dnameOwner("powerdns.com");
+  const DNSName dnameTarget("powerdns.net");
+
+  const DNSName target("dname.powerdns.com.");
+  const DNSName cnameTarget("dname.powerdns.net");
+
+  size_t queries = 0;
+
+  sr->setAsyncCallback([dnameOwner, dnameTarget, target, cnameTarget, &queries](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) {
+      queries++;
+
+      if (isRootServer(ip)) {
+        if (domain.isPartOf(dnameOwner)) {
+          setLWResult(res, 0, false, false, true);
+          addRecordToLW(res, dnameOwner, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
+          addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
+          return 1;
+        }
+        if (domain.isPartOf(dnameTarget)) {
+          setLWResult(res, 0, false, false, true);
+          addRecordToLW(res, dnameTarget, QType::NS, "b.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
+          addRecordToLW(res, "b.gtld-servers.net.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
+          return 1;
+        }
+      } else if (ip == ComboAddress("192.0.2.1:53")) {
+        if (domain == target) {
+          setLWResult(res, 0, true, false, false);
+          addRecordToLW(res, dnameOwner, QType::DNAME, dnameTarget.toString());
+          // No CNAME, recursor should synth
+          return 1;
+        }
+      } else if (ip == ComboAddress("192.0.2.2:53")) {
+        if (domain == cnameTarget) {
+          setLWResult(res, 0, true, false, false);
+          addRecordToLW(res, domain, QType::A, "192.0.2.2");
+        }
+        return 1;
+      }
+      return 0;
+    });
+
+  vector<DNSRecord> ret;
+  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
+
+  BOOST_CHECK_EQUAL(res, RCode::NoError);
+  BOOST_REQUIRE_EQUAL(ret.size(), 3);
+
+  BOOST_CHECK_EQUAL(queries, 4);
+
+  BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
+  BOOST_CHECK(ret[0].d_name == dnameOwner);
+  BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
+
+  BOOST_CHECK(ret[1].d_type == QType::CNAME);
+  BOOST_CHECK_EQUAL(ret[1].d_name, target);
+
+  BOOST_CHECK(ret[2].d_type == QType::A);
+  BOOST_CHECK_EQUAL(ret[2].d_name, cnameTarget);
+
+  // Now check the cache
+  ret.clear();
+  res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
+
+  BOOST_CHECK_EQUAL(res, RCode::NoError);
+  BOOST_REQUIRE_EQUAL(ret.size(), 3);
+
+  BOOST_CHECK_EQUAL(queries, 4);
+
+  BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
+  BOOST_CHECK(ret[0].d_name == dnameOwner);
+  BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
+
+  BOOST_CHECK(ret[1].d_type == QType::CNAME);
+  BOOST_CHECK_EQUAL(ret[1].d_name, target);
+
+  BOOST_CHECK(ret[2].d_type == QType::A);
+  BOOST_CHECK_EQUAL(ret[2].d_name, cnameTarget);
+}
+
 /*
 // cerr<<"asyncresolve called to ask "<<ip.toStringWithPort()<<" about "<<domain.toString()<<" / "<<QType(type).getName()<<" over "<<(doTCP ? "TCP" : "UDP")<<" (rd: "<<sendRDQuery<<", EDNS0 level: "<<EDNS0Level<<")"<<endl;
 
index 5a57ddc59c9e723eb7ba911a46bab71df5351bb2..75837c30f1461280db8544bc3e1662faf91116ca 100644 (file)
@@ -19,6 +19,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
+#pragma once
 #include <memory>
 #include <atomic>
 #include <mutex>
index 1b71d3c190b1ae2b27b3b308415aa292421e0dfe..5dd3c98a39fefc6d2d0baecf51328714b50a1d25 100644 (file)
@@ -47,6 +47,7 @@ SuffixMatchNode SyncRes::s_ednsdomains;
 EDNSSubnetOpts SyncRes::s_ecsScopeZero;
 string SyncRes::s_serverID;
 SyncRes::LogMode SyncRes::s_lm;
+const std::unordered_set<uint16_t> SyncRes::s_redirectionQTypes = {QType::CNAME, QType::DNAME};
 
 unsigned int SyncRes::s_maxnegttl;
 unsigned int SyncRes::s_maxbogusttl;
@@ -943,15 +944,42 @@ bool SyncRes::doCNAMECacheCheck(const DNSName &qname, const QType &qtype, vector
     return true;
   }
 
-  LOG(prefix<<qname<<": Looking for CNAME cache hit of '"<<qname<<"|CNAME"<<"'"<<endl);
   vector<DNSRecord> cset;
   vector<std::shared_ptr<RRSIGRecordContent>> signatures;
   vector<std::shared_ptr<DNSRecord>> authorityRecs;
   bool wasAuth;
   uint32_t capTTL = std::numeric_limits<uint32_t>::max();
+  DNSName foundName;
+  QType foundQT = QType(0); // 0 == QTYPE::ENT
+
+  LOG(prefix<<qname<<": Looking for CNAME cache hit of '"<<qname<<"|CNAME"<<"'"<<endl);
   /* we don't require auth data for forward-recurse lookups */
-  if(t_RC->get(d_now.tv_sec, qname, QType(QType::CNAME), !wasForwardRecurse && d_requireAuthData, &cset, d_cacheRemote, d_doDNSSEC ? &signatures : nullptr, d_doDNSSEC ? &authorityRecs : nullptr, &d_wasVariable, &state, &wasAuth) > 0) {
+  if (t_RC->get(d_now.tv_sec, qname, QType(QType::CNAME), !wasForwardRecurse && d_requireAuthData, &cset, d_cacheRemote, d_doDNSSEC ? &signatures : nullptr, d_doDNSSEC ? &authorityRecs : nullptr, &d_wasVariable, &state, &wasAuth) > 0) {
+    foundName = qname;
+    foundQT = QType(QType::CNAME);
+  }
+
+  if (foundName.empty() && qname != g_rootdnsname) {
+    // look for a DNAME cache hit
+    auto labels = qname.getRawLabels();
+    DNSName dnameName(g_rootdnsname);
+
+    do {
+      dnameName.prependRawLabel(labels.back());
+      labels.pop_back();
+      if (dnameName == qname && qtype != QType::DNAME) { // The client does not want a DNAME, but we've reached the QNAME already. So there is no match
+        break;
+      }
+      LOG(prefix<<qname<<": Looking for DNAME cache hit of '"<<dnameName<<"|DNAME"<<"'"<<endl);
+      if (t_RC->get(d_now.tv_sec, dnameName, QType(QType::DNAME), !wasForwardRecurse && d_requireAuthData, &cset, d_cacheRemote, d_doDNSSEC ? &signatures : nullptr, d_doDNSSEC ? &authorityRecs : nullptr, &d_wasVariable, &state, &wasAuth) > 0) {
+        foundName = dnameName;
+        foundQT = QType(QType::DNAME);
+        break;
+      }
+    } while(!labels.empty());
+  }
 
+  if(!foundName.empty()) {
     for(auto j=cset.cbegin() ; j != cset.cend() ; ++j) {
       if (j->d_class != QClass::IN) {
         continue;
@@ -963,40 +991,40 @@ bool SyncRes::doCNAMECacheCheck(const DNSName &qname, const QType &qtype, vector
           /* This means we couldn't figure out the state when this entry was cached,
              most likely because we hadn't computed the zone cuts yet. */
           /* make sure they are computed before validating */
-          DNSName subdomain(qname);
+          DNSName subdomain(foundName);
           /* if we are retrieving a DS, we only care about the state of the parent zone */
           if(qtype == QType::DS)
             subdomain.chopOff();
 
           computeZoneCuts(subdomain, g_rootdnsname, depth);
 
-          vState recordState = getValidationStatus(qname, false);
+          vState recordState = getValidationStatus(foundName, false);
           if (recordState == Secure) {
-            LOG(prefix<<qname<<": got Indeterminate state from the CNAME cache, validating.."<<endl);
-            state = SyncRes::validateRecordsWithSigs(depth, qname, QType(QType::CNAME), qname, cset, signatures);
+            LOG(prefix<<qname<<": got Indeterminate state from the "<<foundQT.getName()<<" cache, validating.."<<endl);
+            state = SyncRes::validateRecordsWithSigs(depth, foundName, foundQT, foundName, cset, signatures);
             if (state != Indeterminate) {
               LOG(prefix<<qname<<": got Indeterminate state from the CNAME cache, new validation result is "<<vStates[state]<<endl);
               if (state == Bogus) {
                 capTTL = s_maxbogusttl;
               }
-              updateValidationStatusInCache(qname, QType(QType::CNAME), wasAuth, state);
+              updateValidationStatusInCache(foundName, foundQT, wasAuth, state);
             }
           }
         }
 
-        LOG(prefix<<qname<<": Found cache CNAME hit for '"<< qname << "|CNAME" <<"' to '"<<j->d_content->getZoneRepresentation()<<"', validation state is "<<vStates[state]<<endl);
+        LOG(prefix<<qname<<": Found cache "<<foundQT.getName()<<" hit for '"<< foundName << "|"<<foundQT.getName()<<"' to '"<<j->d_content->getZoneRepresentation()<<"', validation state is "<<vStates[state]<<endl);
 
         DNSRecord dr=*j;
         dr.d_ttl -= d_now.tv_sec;
         dr.d_ttl = std::min(dr.d_ttl, capTTL);
         const uint32_t ttl = dr.d_ttl;
-        ret.reserve(ret.size() + 1 + signatures.size() + authorityRecs.size());
+        ret.reserve(ret.size() + 2 + signatures.size() + authorityRecs.size());
         ret.push_back(dr);
 
         for(const auto& signature : signatures) {
           DNSRecord sigdr;
           sigdr.d_type=QType::RRSIG;
-          sigdr.d_name=qname;
+          sigdr.d_name=foundName;
           sigdr.d_ttl=ttl;
           sigdr.d_content=signature;
           sigdr.d_place=DNSResourceRecord::ANSWER;
@@ -1010,25 +1038,63 @@ bool SyncRes::doCNAMECacheCheck(const DNSName &qname, const QType &qtype, vector
           ret.push_back(authDR);
         }
 
-        if(qtype != QType::CNAME) { // perhaps they really wanted a CNAME!
-          set<GetBestNSAnswer>beenthere;
+        DNSName newTarget;
+        if (foundQT == QType::DNAME) {
+          if (qtype == QType::DNAME && qname == foundName) { // client wanted the DNAME, no need to synthesize a CNAME
+            res = 0;
+            return true;
+          }
+          // Synthesize a CNAME
+          auto dnameRR = getRR<DNAMERecordContent>(*j);
+          if (dnameRR == nullptr) {
+            throw ImmediateServFailException("Unable to get record content for "+foundName.toLogString()+"|DNAME cache entry");
+          }
+          const auto& dnameSuffix = dnameRR->getTarget();
+          DNSName targetPrefix = qname.makeRelative(foundName);
+          try {
+            dr.d_type = QType::CNAME;
+            dr.d_name = targetPrefix + foundName;
+            newTarget = targetPrefix + dnameSuffix;
+            dr.d_content = std::make_shared<CNAMERecordContent>(CNAMERecordContent(newTarget));
+            ret.push_back(dr);
+          } catch (const std::exception &e) {
+            // We should probably catch an std::range_error here and set the rcode to YXDOMAIN (RFC 6672, section 2.2)
+            // But this is consistent with processRecords
+            throw ImmediateServFailException("Unable to perform DNAME substitution(DNAME owner: '" + foundName.toLogString() +
+                                             "', DNAME target: '" + dnameSuffix.toLogString() + "', substituted name: '" +
+                                             targetPrefix.toLogString() + "." + dnameSuffix.toLogString() +
+                                             "' : " + e.what());
+          }
 
-          vState cnameState = Indeterminate;
+          LOG(prefix<<qname<<": Synthesized "<<dr.d_name<<"|CNAME "<<newTarget<<endl);
+        }
+
+        if(qtype == QType::CNAME) { // perhaps they really wanted a CNAME!
+          res = 0;
+          return true;
+        }
+
+        // We have a DNAME _or_ CNAME cache hit and the client wants something else than those two.
+        // Let's find the answer!
+        if (foundQT == QType::CNAME) {
           const auto cnameContent = getRR<CNAMERecordContent>(*j);
-          if (cnameContent) {
-            res=doResolve(cnameContent->getTarget(), qtype, ret, depth+1, beenthere, cnameState);
-            LOG(prefix<<qname<<": updating validation state for response to "<<qname<<" from "<<vStates[state]<<" with the state from the CNAME quest: "<<vStates[cnameState]<<endl);
-            updateValidationState(state, cnameState);
+          if (cnameContent == nullptr) {
+            throw ImmediateServFailException("Unable to get record content for "+foundName.toLogString()+"|CNAME cache entry");
           }
+          newTarget = cnameContent->getTarget();
         }
-        else
-          res=0;
+
+        set<GetBestNSAnswer>beenthere;
+        vState cnameState = Indeterminate;
+        res = doResolve(newTarget, qtype, ret, depth+1, beenthere, cnameState);
+        LOG(prefix<<qname<<": updating validation state for response to "<<qname<<" from "<<vStates[state]<<" with the state from the DNAME/CNAME quest: "<<vStates[cnameState]<<endl);
+        updateValidationState(state, cnameState);
 
         return true;
       }
     }
   }
-  LOG(prefix<<qname<<": No CNAME cache hit of '"<< qname << "|CNAME" <<"' found"<<endl);
+  LOG(prefix<<qname<<": No CNAME or DNAME cache hit of '"<< qname <<"' found"<<endl);
   return false;
 }
 
@@ -2087,7 +2153,7 @@ void SyncRes::sanitizeRecords(const std::string& prefix, LWResult& lwr, const DN
       continue;
     }
 
-    if (rec->d_place == DNSResourceRecord::ANSWER && (qtype != QType::ANY && rec->d_type != qtype.getCode() && rec->d_type != QType::CNAME && rec->d_type != QType::SOA && rec->d_type != QType::RRSIG)) {
+    if (rec->d_place == DNSResourceRecord::ANSWER && (qtype != QType::ANY && rec->d_type != qtype.getCode() && s_redirectionQTypes.count(rec->d_type) == 0 && rec->d_type != QType::SOA && rec->d_type != QType::RRSIG)) {
       LOG(prefix<<"Removing irrelevant record '"<<rec->d_name<<"|"<<DNSRecordContent::NumberToType(rec->d_type)<<"|"<<rec->d_content->getZoneRepresentation()<<"' in the "<<(int)rec->d_place<<" section received from "<<auth<<endl);
       rec = lwr.d_records.erase(rec);
       continue;
@@ -2162,7 +2228,7 @@ void SyncRes::sanitizeRecords(const std::string& prefix, LWResult& lwr, const DN
   }
 }
 
-RCode::rcodes_ SyncRes::updateCacheFromRecords(unsigned int depth, LWResult& lwr, const DNSName& qname, const QType& qtype, const DNSName& auth, bool wasForwarded, const boost::optional<Netmask> ednsmask, vState& state, bool& needWildcardProof, unsigned int& wildcardLabelsCount, bool rdQuery)
+RCode::rcodes_ SyncRes::updateCacheFromRecords(unsigned int depth, LWResult& lwr, const DNSName& qname, const QType& qtype, const DNSName& auth, bool wasForwarded, const boost::optional<Netmask> ednsmask, vState& state, bool& needWildcardProof, bool& gatherWildcardProof, unsigned int& wildcardLabelsCount, bool rdQuery)
 {
   bool wasForwardRecurse = wasForwarded && rdQuery;
   tcache_t tcache;
@@ -2178,19 +2244,24 @@ RCode::rcodes_ SyncRes::updateCacheFromRecords(unsigned int depth, LWResult& lwr
   std::vector<std::shared_ptr<DNSRecord>> authorityRecs;
   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) {
       continue;
     }
 
-    if(!isCNAMEAnswer && rec.d_place == DNSResourceRecord::ANSWER && rec.d_type == QType::CNAME && (!(qtype==QType(QType::CNAME))) && rec.d_name == qname) {
+    if(!isCNAMEAnswer && rec.d_place == DNSResourceRecord::ANSWER && rec.d_type == QType::CNAME && (!(qtype==QType(QType::CNAME))) && rec.d_name == qname && !isDNAMEAnswer) {
       isCNAMEAnswer = true;
     }
+    if(!isDNAMEAnswer && rec.d_place == DNSResourceRecord::ANSWER && rec.d_type == QType::DNAME && qtype != QType(QType::DNAME) && qname.isPartOf(rec.d_name)) {
+      isDNAMEAnswer = true;
+      isCNAMEAnswer = false;
+    }
 
     /* if we have a positive answer synthetized from a wildcard,
        we need to store the corresponding NSEC/NSEC3 records proving
        that the exact name did not exist in the negative cache */
-    if(needWildcardProof) {
+    if(gatherWildcardProof) {
       if (nsecTypes.count(rec.d_type)) {
         authorityRecs.push_back(std::make_shared<DNSRecord>(rec));
       }
@@ -2208,9 +2279,20 @@ RCode::rcodes_ SyncRes::updateCacheFromRecords(unsigned int depth, LWResult& lwr
            count can be lower than the name's label count if it was
            synthetized from the wildcard. Note that the difference might
            be > 1. */
-        if (rec.d_name == qname && rrsig->d_labels < labelCount) {
-          LOG(prefix<<qname<<": RRSIG indicates the name was synthetized from a wildcard, we need a wildcard proof"<<endl);
-          needWildcardProof = true;
+        if (rec.d_name == qname && isWildcardExpanded(labelCount, rrsig)) {
+          gatherWildcardProof = true;
+          if (!isWildcardExpandedOntoItself(rec.d_name, labelCount, rrsig)) {
+            /* if we have a wildcard expanded onto itself, we don't need to prove
+               that the exact name doesn't exist because it actually does.
+               We still want to gather the corresponding NSEC/NSEC3 records
+               to pass them to our client in case it wants to validate by itself.
+            */
+            LOG(prefix<<qname<<": RRSIG indicates the name was synthetized from a wildcard, we need a wildcard proof"<<endl);
+            needWildcardProof = true;
+          }
+          else {
+            LOG(prefix<<qname<<": RRSIG indicates the name was synthetized from a wildcard expanded onto itself, we need to gather wildcard proof"<<endl);
+          }
           wildcardLabelsCount = rrsig->d_labels;
         }
 
@@ -2258,6 +2340,10 @@ RCode::rcodes_ SyncRes::updateCacheFromRecords(unsigned int depth, LWResult& lwr
       }
       else {
         bool haveLogged = false;
+        if (isDNAMEAnswer && rec.d_type == QType::CNAME) {
+          LOG("NO - we already have a DNAME answer for this domain");
+          continue;
+        }
         if (!t_sstorage.domainmap->empty()) {
           // Check if we are authoritative for a zone in this answer
           DNSName tmp_qname(rec.d_name);
@@ -2374,11 +2460,25 @@ RCode::rcodes_ SyncRes::updateCacheFromRecords(unsigned int depth, LWResult& lwr
             recordState = validateDNSKeys(i->first.name, i->second.records, i->second.signatures, depth);
           }
           else {
-            LOG(d_prefix<<"Validating non-additional record for "<<i->first.name<<endl);
-            recordState = validateRecordsWithSigs(depth, qname, qtype, i->first.name, i->second.records, i->second.signatures);
-            /* we might have missed a cut (zone cut within the same auth servers), causing the NS query for an Insecure zone to seem Bogus during zone cut determination */
-            if (qtype == QType::NS && i->second.signatures.empty() && recordState == Bogus && haveExactValidationStatus(i->first.name) && getValidationStatus(i->first.name) == Indeterminate) {
-              recordState = Indeterminate;
+            /*
+             * RFC 6672 section 5.3.1
+             *  In any response, a signed DNAME RR indicates a non-terminal
+             *  redirection of the query.  There might or might not be a server-
+             *  synthesized CNAME in the answer section; if there is, the CNAME will
+             *  never be signed.  For a DNSSEC validator, verification of the DNAME
+             *  RR and then that the CNAME was properly synthesized is sufficient
+             *  proof.
+             *
+             * We do the synthesis check in processRecords, here we make sure we
+             * don't validate the CNAME.
+             */
+            if (!(isDNAMEAnswer && i->first.type == QType::CNAME)) {
+              LOG(d_prefix<<"Validating non-additional record for "<<i->first.name<<endl);
+              recordState = validateRecordsWithSigs(depth, qname, qtype, i->first.name, i->second.records, i->second.signatures);
+              /* we might have missed a cut (zone cut within the same auth servers), causing the NS query for an Insecure zone to seem Bogus during zone cut determination */
+              if (qtype == QType::NS && i->second.signatures.empty() && recordState == Bogus && haveExactValidationStatus(i->first.name) && getValidationStatus(i->first.name) == Indeterminate) {
+                recordState = Indeterminate;
+              }
             }
           }
         }
@@ -2483,9 +2583,11 @@ dState SyncRes::getDenialValidationState(const NegCache::NegCacheEntry& ne, cons
   return getDenial(csp, ne.d_name, ne.d_qtype.getCode(), referralToUnsigned, expectedState == NXQTYPE);
 }
 
-bool SyncRes::processRecords(const std::string& prefix, const DNSName& qname, const QType& qtype, const DNSName& auth, LWResult& lwr, const bool sendRDQuery, vector<DNSRecord>& ret, set<DNSName>& nsset, DNSName& newtarget, DNSName& newauth, bool& realreferral, bool& negindic, vState& state, const bool needWildcardProof, const unsigned int wildcardLabelsCount)
+bool SyncRes::processRecords(const std::string& prefix, const DNSName& qname, const QType& qtype, const DNSName& auth, LWResult& lwr, const bool sendRDQuery, vector<DNSRecord>& ret, set<DNSName>& nsset, DNSName& newtarget, DNSName& newauth, bool& realreferral, bool& negindic, vState& state, const bool needWildcardProof, const bool gatherWildcardProof, const unsigned int wildcardLabelsCount)
 {
   bool done = false;
+  DNSName dnameTarget, dnameOwner;
+  uint32_t dnameTTL = 0;
 
   for(auto& rec : lwr.d_records) {
     if (rec.d_type!=QType::OPT && rec.d_class!=QClass::IN)
@@ -2545,16 +2647,48 @@ bool SyncRes::processRecords(const std::string& prefix, const DNSName& qname, co
 
       negindic=true;
     }
-    else if(rec.d_place==DNSResourceRecord::ANSWER && rec.d_type==QType::CNAME && (!(qtype==QType(QType::CNAME))) && rec.d_name == qname) {
-      ret.push_back(rec);
-      if (auto content = getRR<CNAMERecordContent>(rec)) {
-        newtarget=content->getTarget();
+    else if(rec.d_place==DNSResourceRecord::ANSWER && s_redirectionQTypes.count(rec.d_type) > 0 && // CNAME or DNAME answer
+        s_redirectionQTypes.count(qtype.getCode()) == 0) { // But not in response to a CNAME or DNAME query
+      if (rec.d_type == QType::CNAME && rec.d_name == qname) {
+        if (!dnameOwner.empty()) { // We synthesize ourselves
+          continue;
+        }
+        ret.push_back(rec);
+        if (auto content = getRR<CNAMERecordContent>(rec)) {
+          newtarget=content->getTarget();
+        }
+      } else if (rec.d_type == QType::DNAME && qname.isPartOf(rec.d_name)) { // DNAME
+        ret.push_back(rec);
+        if (auto content = getRR<DNAMERecordContent>(rec)) {
+          dnameOwner = rec.d_name;
+          dnameTarget = content->getTarget();
+          dnameTTL = rec.d_ttl;
+          if (!newtarget.empty()) { // We had a CNAME before, remove it from ret so we don't cache it
+            ret.erase(std::remove_if(
+                  ret.begin(),
+                  ret.end(),
+                  [&qname](DNSRecord& rr) {
+                    return (rr.d_place == DNSResourceRecord::ANSWER && rr.d_type == QType::CNAME && rr.d_name == qname);
+                  }),
+                  ret.end());
+          }
+          try {
+            newtarget = qname.makeRelative(dnameOwner) + dnameTarget;
+          } catch (const std::exception &e) {
+            // We should probably catch an std::range_error here and set the rcode to YXDOMAIN (RFC 6672, section 2.2)
+            // But there is no way to set the RCODE from this function
+            throw ImmediateServFailException("Unable to perform DNAME substitution(DNAME owner: '" + dnameOwner.toLogString() +
+                                             "', DNAME target: '" + dnameTarget.toLogString() + "', substituted name: '" +
+                                             qname.makeRelative(dnameOwner).toLogString() + "." + dnameTarget.toLogString() +
+                                             "' : " + e.what());
+          }
+        }
       }
     }
     /* if we have a positive answer synthetized from a wildcard, we need to
        return the corresponding NSEC/NSEC3 records from the AUTHORITY section
        proving that the exact name did not exist */
-    else if(needWildcardProof && (rec.d_type==QType::RRSIG || rec.d_type==QType::NSEC || rec.d_type==QType::NSEC3) && rec.d_place==DNSResourceRecord::AUTHORITY) {
+    else if(gatherWildcardProof && (rec.d_type==QType::RRSIG || rec.d_type==QType::NSEC || rec.d_type==QType::NSEC3) && rec.d_place==DNSResourceRecord::AUTHORITY) {
       ret.push_back(rec); // enjoy your DNSSEC
     }
     // for ANY answers we *must* have an authoritative answer, unless we are forwarding recursively
@@ -2603,8 +2737,14 @@ bool SyncRes::processRecords(const std::string& prefix, const DNSName& qname, co
       ret.push_back(rec);
     }
     else if((rec.d_type==QType::RRSIG || rec.d_type==QType::NSEC || rec.d_type==QType::NSEC3) && rec.d_place==DNSResourceRecord::ANSWER) {
-      if(rec.d_type != QType::RRSIG || rec.d_name == qname)
+      if(rec.d_type != QType::RRSIG || rec.d_name == qname) {
         ret.push_back(rec); // enjoy your DNSSEC
+      } else if(rec.d_type == QType::RRSIG && qname.isPartOf(rec.d_name)) {
+        auto rrsig = getRR<RRSIGRecordContent>(rec);
+        if (rrsig != nullptr && rrsig->d_type == QType::DNAME) {
+           ret.push_back(rec);
+        }
+      }
     }
     else if(rec.d_place==DNSResourceRecord::AUTHORITY && rec.d_type==QType::NS && qname.isPartOf(rec.d_name)) {
       if(moreSpecificThan(rec.d_name,auth)) {
@@ -2694,6 +2834,15 @@ bool SyncRes::processRecords(const std::string& prefix, const DNSName& qname, co
     }
   }
 
+  if (!dnameTarget.empty()) {
+    // Synthesize a CNAME
+    auto cnamerec = DNSRecord();
+    cnamerec.d_name = qname;
+    cnamerec.d_type = QType::CNAME;
+    cnamerec.d_ttl = dnameTTL;
+    cnamerec.d_content = std::make_shared<CNAMERecordContent>(CNAMERecordContent(newtarget));
+    ret.push_back(cnamerec);
+  }
   return done;
 }
 
@@ -2751,6 +2900,13 @@ bool SyncRes::doResolveAtThisIP(const std::string& prefix, const DNSName& qname,
   d_totUsec += lwr.d_usec;
   accountAuthLatency(lwr.d_usec, remoteIP.sin4.sin_family);
 
+  bool dontThrottle = false;
+  {
+    auto dontThrottleNames = g_dontThrottleNames.getLocal();
+    auto dontThrottleNetmasks = g_dontThrottleNetmasks.getLocal();
+    dontThrottle = dontThrottleNames->check(nsName) || dontThrottleNetmasks->match(remoteIP);
+  }
+
   if(resolveret != 1) {
     /* Error while resolving */
     if(resolveret == 0) {
@@ -2780,7 +2936,9 @@ bool SyncRes::doResolveAtThisIP(const std::string& prefix, const DNSName& qname,
       LOG(prefix<<qname<<": error resolving from "<<remoteIP.toString()<< (doTCP ? " over TCP" : "") <<", possible error: "<<strerror(errno)<< endl);
     }
 
-    if(resolveret != -2 && !chained) { // don't account for resource limits, they are our own fault
+    if(resolveret != -2 && !chained && !dontThrottle) {
+      // don't account for resource limits, they are our own fault
+      // And don't throttle when the IP address is on the dontThrottleNetmasks list or the name is part of dontThrottleNames
       t_sstorage.nsSpeeds[nsName.empty()? DNSName(remoteIP.toStringWithPort()) : nsName].submit(remoteIP, 1000000, &d_now); // 1 sec
 
       // code below makes sure we don't filter COM or the root
@@ -2794,7 +2952,7 @@ bool SyncRes::doResolveAtThisIP(const std::string& prefix, const DNSName& qname,
         t_sstorage.throttle.throttle(d_now.tv_sec, boost::make_tuple(remoteIP, qname, qtype.getCode()), 60, 100);
       }
       else {
-        // timeout
+        // timeout, 10 seconds or 5 queries
         t_sstorage.throttle.throttle(d_now.tv_sec, boost::make_tuple(remoteIP, qname, qtype.getCode()), 10, 5);
       }
     }
@@ -2805,7 +2963,7 @@ bool SyncRes::doResolveAtThisIP(const std::string& prefix, const DNSName& qname,
   /* we got an answer */
   if(lwr.d_rcode==RCode::ServFail || lwr.d_rcode==RCode::Refused) {
     LOG(prefix<<qname<<": "<<nsName<<" ("<<remoteIP.toString()<<") returned a "<< (lwr.d_rcode==RCode::ServFail ? "ServFail" : "Refused") << ", trying sibling IP or NS"<<endl);
-    if (!chained) {
+    if (!chained && !dontThrottle) {
       t_sstorage.throttle.throttle(d_now.tv_sec, boost::make_tuple(remoteIP, qname, qtype.getCode()), 60, 3);
     }
     return false;
@@ -2819,7 +2977,7 @@ bool SyncRes::doResolveAtThisIP(const std::string& prefix, const DNSName& qname,
   if(lwr.d_tcbit) {
     *truncated = true;
 
-    if (doTCP) {
+    if (doTCP && !dontThrottle) {
       LOG(prefix<<qname<<": truncated bit set, over TCP?"<<endl);
       /* let's treat that as a ServFail answer from this server */
       t_sstorage.throttle.throttle(d_now.tv_sec, boost::make_tuple(remoteIP, qname, qtype.getCode()), 60, 3);
@@ -2857,8 +3015,9 @@ bool SyncRes::processAnswer(unsigned int depth, LWResult& lwr, const DNSName& qn
   }
 
   bool needWildcardProof = false;
+  bool gatherWildcardProof = false;
   unsigned int wildcardLabelsCount;
-  *rcode = updateCacheFromRecords(depth, lwr, qname, qtype, auth, wasForwarded, ednsmask, state, needWildcardProof, wildcardLabelsCount, sendRDQuery);
+  *rcode = updateCacheFromRecords(depth, lwr, qname, qtype, auth, wasForwarded, ednsmask, state, needWildcardProof, gatherWildcardProof, wildcardLabelsCount, sendRDQuery);
   if (*rcode != RCode::NoError) {
     return true;
   }
@@ -2870,7 +3029,7 @@ bool SyncRes::processAnswer(unsigned int depth, LWResult& lwr, const DNSName& qn
   DNSName newauth;
   DNSName newtarget;
 
-  bool done = processRecords(prefix, qname, qtype, auth, lwr, sendRDQuery, ret, nsset, newtarget, newauth, realreferral, negindic, state, needWildcardProof, wildcardLabelsCount);
+  bool done = processRecords(prefix, qname, qtype, auth, lwr, sendRDQuery, ret, nsset, newtarget, newauth, realreferral, negindic, state, needWildcardProof, gatherWildcardProof, wildcardLabelsCount);
 
   if(done){
     LOG(prefix<<qname<<": status=got results, this level of recursion done"<<endl);
index a28ca22c57a34c0a35d5cc362cc07c11ed217551..b316c92d4bf4de8473cdfd87a4a40d7c1ddbb484 100644 (file)
@@ -49,6 +49,7 @@
 #include "ednssubnet.hh"
 #include "filterpo.hh"
 #include "negcache.hh"
+#include "sholder.hh"
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
@@ -58,6 +59,9 @@
 #include <boost/uuid/uuid.hpp>
 #endif
 
+extern GlobalStateHolder<SuffixMatchNode> g_dontThrottleNames;
+extern GlobalStateHolder<NetmaskGroup> g_dontThrottleNetmasks;
+
 class RecursorLua4;
 
 typedef map<
@@ -748,6 +752,7 @@ private:
   static EDNSSubnetOpts s_ecsScopeZero;
   static LogMode s_lm;
   static std::unique_ptr<NetmaskGroup> s_dontQuery;
+  const static std::unordered_set<uint16_t> s_redirectionQTypes;
 
   struct GetBestNSAnswer
   {
@@ -789,8 +794,8 @@ private:
   vector<ComboAddress> retrieveAddressesForNS(const std::string& prefix, const DNSName& qname, vector<DNSName >::const_iterator& tns, const unsigned int depth, set<GetBestNSAnswer>& beenthere, const vector<DNSName >& rnameservers, NsSet& nameservers, bool& sendRDQuery, bool& pierceDontQuery, bool& flawedNSSet, bool cacheOnly);
 
   void sanitizeRecords(const std::string& prefix, LWResult& lwr, const DNSName& qname, const QType& qtype, const DNSName& auth, bool wasForwarded, bool rdQuery);
-  RCode::rcodes_ updateCacheFromRecords(unsigned int depth, LWResult& lwr, const DNSName& qname, const QType& qtype, const DNSName& auth, bool wasForwarded, const boost::optional<Netmask>, vState& state, bool& needWildcardProof, unsigned int& wildcardLabelsCount, bool sendRDQuery);
-  bool processRecords(const std::string& prefix, const DNSName& qname, const QType& qtype, const DNSName& auth, LWResult& lwr, const bool sendRDQuery, vector<DNSRecord>& ret, set<DNSName>& nsset, DNSName& newtarget, DNSName& newauth, bool& realreferral, bool& negindic, vState& state, const bool needWildcardProof, const unsigned int wildcardLabelsCount);
+  RCode::rcodes_ updateCacheFromRecords(unsigned int depth, LWResult& lwr, const DNSName& qname, const QType& qtype, const DNSName& auth, bool wasForwarded, const boost::optional<Netmask>, vState& state, bool& needWildcardProof, bool& gatherWildcardProof, unsigned int& wildcardLabelsCount, bool sendRDQuery);
+  bool processRecords(const std::string& prefix, const DNSName& qname, const QType& qtype, const DNSName& auth, LWResult& lwr, const bool sendRDQuery, vector<DNSRecord>& ret, set<DNSName>& nsset, DNSName& newtarget, DNSName& newauth, bool& realreferral, bool& negindic, vState& state, const bool needWildcardProof, const bool gatherwildcardProof, const unsigned int wildcardLabelsCount);
 
   bool doSpecialNamesResolve(const DNSName &qname, const QType &qtype, const uint16_t qclass, vector<DNSRecord> &ret);
 
index 9c0a7b80c11256ca94fd0f56833d20e51f7b64b0..b9160c072d58a5628ec23b3649a14d9d73796970 100644 (file)
@@ -493,7 +493,7 @@ bool TCPNameserver::canDoAXFR(shared_ptr<DNSPacket> q)
         while(B->get(rr)) 
           nsset.insert(DNSName(rr.content));
         for(const auto & j: nsset) {
-          vector<string> nsips=fns.lookup(j, s_P->getBackend());
+          vector<string> nsips=fns.lookup(j, s_P->getBackend(),q->qdomain);
           for(vector<string>::const_iterator k=nsips.begin();k!=nsips.end();++k) {
             // cerr<<"got "<<*k<<" from AUTO-NS"<<endl;
             if(*k == q->getRemote().toString())
index d003b8ddcc0c901dbb3df0b6bcc219cf8dcb3247..833f2fc31e434015d6072e894969275d5220b663 100644 (file)
@@ -507,6 +507,11 @@ BOOST_AUTO_TEST_CASE(test_suffixmatch) {
   smn.add(net);
   BOOST_CHECK(smn.check(examplenet));
   BOOST_CHECK(smn.check(net));
+
+  // Remove .net and check that example.net still exists
+  smn.remove(net);
+  BOOST_CHECK_EQUAL(smn.check(net), false);
+  BOOST_CHECK(smn.check(examplenet));
 }
 
 BOOST_AUTO_TEST_CASE(test_suffixmatch_tree) {
@@ -558,6 +563,66 @@ BOOST_AUTO_TEST_CASE(test_suffixmatch_tree) {
   BOOST_CHECK_EQUAL(*smt.lookup(examplenet), examplenet);
   BOOST_REQUIRE(smt.lookup(net));
   BOOST_CHECK_EQUAL(*smt.lookup(net), net);
+
+  // Remove .net, and check that example.net remains
+  smt.remove(net);
+  BOOST_CHECK(smt.lookup(net) == nullptr);
+  BOOST_CHECK_EQUAL(*smt.lookup(examplenet), examplenet);
+
+  smt = SuffixMatchTree<DNSName>();
+  smt.add(examplenet, examplenet);
+  smt.add(net, net);
+  smt.add(DNSName("news.bbc.co.uk."), DNSName("news.bbc.co.uk."));
+  smt.add(apowerdnscom, apowerdnscom);
+
+  smt.remove(DNSName("not-such-entry.news.bbc.co.uk."));
+  BOOST_REQUIRE(smt.lookup(DNSName("news.bbc.co.uk.")));
+  smt.remove(DNSName("news.bbc.co.uk."));
+  BOOST_CHECK(smt.lookup(DNSName("news.bbc.co.uk.")) == nullptr);
+
+  smt.remove(net);
+  BOOST_REQUIRE(smt.lookup(examplenet));
+  BOOST_CHECK_EQUAL(*smt.lookup(examplenet), examplenet);
+  BOOST_CHECK(smt.lookup(net) == nullptr);
+
+  smt.remove(examplenet);
+  BOOST_CHECK(smt.lookup(net) == nullptr);
+  BOOST_CHECK(smt.lookup(examplenet) == nullptr);
+
+  smt.add(examplenet, examplenet);
+  smt.add(net, net);
+  BOOST_REQUIRE(smt.lookup(examplenet));
+  BOOST_CHECK_EQUAL(*smt.lookup(examplenet), examplenet);
+  BOOST_REQUIRE(smt.lookup(net));
+  BOOST_CHECK_EQUAL(*smt.lookup(net), net);
+
+  smt.remove(examplenet);
+  BOOST_CHECK_EQUAL(*smt.lookup(examplenet), net);
+  BOOST_CHECK_EQUAL(*smt.lookup(net), net);
+  smt.remove(examplenet);
+  BOOST_CHECK_EQUAL(*smt.lookup(examplenet), net);
+  BOOST_CHECK_EQUAL(*smt.lookup(net), net);
+  smt.remove(net);
+  BOOST_CHECK(smt.lookup(net) == nullptr);
+  BOOST_CHECK(smt.lookup(examplenet) == nullptr);
+  smt.remove(net);
+
+  size_t count = 0;
+  smt.visit([apowerdnscom, &count](const SuffixMatchTree<DNSName>& smt) {
+      count++;
+      BOOST_CHECK_EQUAL(smt.d_value, apowerdnscom);
+    });
+  BOOST_CHECK_EQUAL(count, 1);
+
+  BOOST_CHECK_EQUAL(*smt.lookup(apowerdnscom), apowerdnscom);
+  smt.remove(apowerdnscom);
+  BOOST_CHECK(smt.lookup(apowerdnscom) == nullptr);
+
+  count = 0;
+  smt.visit([&count](const SuffixMatchTree<DNSName>& smt) {
+      count++;
+    });
+  BOOST_CHECK_EQUAL(count, 0);
 }
 
 
index c9d17c86e204b4880e54c90700c8689a960a587d..ab7fa3d9e25d76286fd0f373d6400ef63ba13e43 100644 (file)
@@ -112,6 +112,15 @@ bool denialProvesNoDelegation(const DNSName& zone, const std::vector<DNSRecord>&
    Labels field of the covering RRSIG RR, then the RRset and its
    covering RRSIG RR were created as a result of wildcard expansion."
 */
+bool isWildcardExpanded(unsigned int labelCount, const std::shared_ptr<RRSIGRecordContent>& sign)
+{
+  if (sign && sign->d_labels < labelCount) {
+    return true;
+  }
+
+  return false;
+}
+
 static bool isWildcardExpanded(const DNSName& owner, const std::vector<std::shared_ptr<RRSIGRecordContent> >& signatures)
 {
   if (signatures.empty()) {
@@ -120,13 +129,29 @@ static bool isWildcardExpanded(const DNSName& owner, const std::vector<std::shar
 
   const auto& sign = signatures.at(0);
   unsigned int labelsCount = owner.countLabels();
-  if (sign && sign->d_labels < labelsCount) {
+  return isWildcardExpanded(labelsCount, sign);
+}
+
+bool isWildcardExpandedOntoItself(const DNSName& owner, unsigned int labelCount, const std::shared_ptr<RRSIGRecordContent>& sign)
+{
+  if (owner.isWildcard() && (labelCount - 1) == sign->d_labels) {
+    /* this is a wildcard alright, but it has not been expanded */
     return true;
   }
-
   return false;
 }
 
+static bool isWildcardExpandedOntoItself(const DNSName& owner, const std::vector<std::shared_ptr<RRSIGRecordContent> >& signatures)
+{
+  if (signatures.empty()) {
+    return false;
+  }
+
+  const auto& sign = signatures.at(0);
+  unsigned int labelsCount = owner.countLabels();
+  return isWildcardExpandedOntoItself(owner, labelsCount, sign);
+}
+
 /* if this is a wildcard NSEC, the owner name has been modified
    to match the name. Make sure we use the original '*' form. */
 static DNSName getNSECOwnerName(const DNSName& initialOwner, const std::vector<std::shared_ptr<RRSIGRecordContent> >& signatures)
@@ -381,7 +406,7 @@ dState getDenial(const cspmap_t &validrrsets, const DNSName& qname, const uint16
           /* we know that the name exists (but this qtype doesn't) so except
              if the answer was generated by a wildcard expansion, no wildcard
              could have matched (rfc4035 section 5.4 bullet 1) */
-          if (!isWildcardExpanded(owner, v.second.signatures)) {
+          if (!isWildcardExpanded(owner, v.second.signatures) || isWildcardExpandedOntoItself(owner, v.second.signatures)) {
             needWildcardProof = false;
           }
 
@@ -395,6 +420,7 @@ dState getDenial(const cspmap_t &validrrsets, const DNSName& qname, const uint16
 
         /* check if the whole NAME is denied existing */
         if(isCoveredByNSEC(qname, owner, nsec->d_next)) {
+          LOG(qname<<" is covered ");
           /* if the name is an ENT and we received a NODATA answer,
              we are fine with a NSEC proving that the name does not exist. */
           if (wantsNoDataProof && nsecProvesENT(qname, owner, nsec->d_next)) {
@@ -403,15 +429,19 @@ dState getDenial(const cspmap_t &validrrsets, const DNSName& qname, const uint16
           }
 
           if (!needWildcardProof) {
+            LOG("and we did not need a wildcard proof"<<endl);
             return NXDOMAIN;
           }
 
+          LOG("but we do need a wildcard proof so ");
           if (wantsNoDataProof) {
+            LOG("looking for NODATA proof"<<endl);
             if (provesNoDataWildCard(qname, qtype, validrrsets)) {
               return NXQTYPE;
             }
           }
           else {
+            LOG("looking for NO wildcard proof"<<endl);
             if (provesNoWildCard(qname, qtype, validrrsets)) {
               return NXDOMAIN;
             }
index d58b49206307c4cbac36eb9e2dec721fdc6ddfe8..b30fca1c6e79533b316c744f34ee116a418afcec 100644 (file)
@@ -77,3 +77,5 @@ bool isSupportedDS(const DSRecordContent& ds);
 DNSName getSigner(const std::vector<std::shared_ptr<RRSIGRecordContent> >& signatures);
 bool denialProvesNoDelegation(const DNSName& zone, const std::vector<DNSRecord>& dsrecords);
 bool isRRSIGNotExpired(const time_t now, const shared_ptr<RRSIGRecordContent> sig);
+bool isWildcardExpanded(unsigned int labelCount, const std::shared_ptr<RRSIGRecordContent>& sign);
+bool isWildcardExpandedOntoItself(const DNSName& owner, unsigned int labelCount, const std::shared_ptr<RRSIGRecordContent>& sign);
index 09780c58146d8031491cb92f2269084fd406b73b..bfa46bc6058b1dad4b7e5a27122dafed12c25ead 100644 (file)
@@ -9,10 +9,9 @@ DNSDISTBIN=../pdns/dnsdistdist/dnsdist ./runtests
 The tests are self-contained and require no further nameservers to be
 installed.
 
-However, do make sure to build a dnsdist with libsodium and dnscrypt support
-as otherwise some tests will fail.
+However, do make sure to build a dnsdist with libsodium, dnscrypt, DoT and DoH
+support as otherwise some tests will fail.
 
 To run a specific test, use something like:
 
 ./runtests test_Advanced.py:TestAdvancedSpoof.testSpoofActionMultiA
-
index e83d947c85d8148d71178a001d757e9b74b741c1..251e76a6a79d99f39591f580c8792adbb3268dd1 100755 (executable)
@@ -16,7 +16,21 @@ if [ ! -d .venv ]; then
 fi
 . .venv/bin/activate
 python -V
+
+if [ `uname -s` == Darwin ]
+then
+  if [ ! -e /usr/local/opt/curl-openssl ]
+  then
+    echo Please run: brew install curl-openssl, and try again
+    exit 1
+  else
+    export PYCURL_CURL_CONFIG=/usr/local/opt/curl-openssl/bin/curl-config
+    export LDFLAGS=-L/usr/local/opt/openssl/lib
+    export CPPFLAGS=-I/usr/local/opt/openssl/include
+  fi
+fi
 pip install -r requirements.txt
+
 protoc -I=../pdns/ --python_out=. ../pdns/dnsmessage.proto
 protoc -I=../pdns/ --python_out=. ../pdns/dnstap.proto
 
index 6eb46127f0852d39414a3db71afaba7fd024f570..ffb0da45c548e69b59b68852c46079a357307143 100755 (executable)
@@ -94,7 +94,7 @@ start_slave()
 
         $RUNWRAPPER $PDNS2 --daemon=no --local-port=$slaveport --config-dir=. --module-dir=../regression-tests/modules \
                 --config-name=gsqlite3-slave --socket-dir=./ --no-shuffle --local-address=127.0.0.2 --local-ipv6='' \
-                --slave --retrieval-threads=4 --slave=yes --supermaster=yes --query-local-address=127.0.0.2 \
+                --slave --retrieval-threads=4 --slave=yes --superslave=yes --query-local-address=127.0.0.2 \
                 --slave-cycle-interval=300 --allow-unsigned-notify=no --allow-unsigned-supermaster=no &
 }
 
index 86dde039276fabc4de0d2a65cef9e922ee7c79d0..6311fd2d01951f324dac2ce2ef2b03e290bbd0aa 100755 (executable)
@@ -85,7 +85,7 @@ start_slave()
 
         $RUNWRAPPER $PDNS2 --daemon=no --local-port=$slaveport --config-dir=. --module-dir=../regression-tests/modules \
                 --config-name=gsqlite3-slave --socket-dir=./ --no-shuffle --local-address=127.0.0.2 --local-ipv6= \
-                --slave --retrieval-threads=4 --slave=yes --supermaster=yes --query-local-address=127.0.0.2 \
+                --slave --retrieval-threads=4 --slave=yes --superslave=yes --query-local-address=127.0.0.2 \
                 --slave-cycle-interval=300 --dname-processing &
 }
 
index e754dffa8488eb312ad6533b4cedc5669797b95f..04fc82308914709df473c0df294e59f586d81f5d 100644 (file)
@@ -147,3 +147,127 @@ class BasicDNSSEC(RecursorTest):
         self.assertRRsetInAnswer(res, expectedA)
         self.assertMatchingRRSIGInAnswer(res, expectedCNAME)
 
+    def testSecureDNAMEToSecureAnswer(self):
+        res = self.sendQuery('host1.dname-secure.secure.example.', 'A')
+        expectedDNAME = dns.rrset.from_text('dname-secure.secure.example.', 0, dns.rdataclass.IN, 'DNAME', 'dname-secure.example.')
+        expectedCNAME = dns.rrset.from_text('host1.dname-secure.secure.example.', 0, dns.rdataclass.IN, 'CNAME', 'host1.dname-secure.example.')
+        expectedA = dns.rrset.from_text('host1.dname-secure.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.21')
+
+        self.assertRcodeEqual(res, dns.rcode.NOERROR)
+        self.assertMessageHasFlags(res, ['QR', 'RD', 'RA', 'AD'], ['DO'])
+        self.assertRRsetInAnswer(res, expectedA)
+        self.assertRRsetInAnswer(res, expectedCNAME)
+        self.assertRRsetInAnswer(res, expectedDNAME)
+        self.assertMatchingRRSIGInAnswer(res, expectedDNAME)
+        self.assertMatchingRRSIGInAnswer(res, expectedA)
+
+    def testSecureDNAMEToSecureNXDomain(self):
+        res = self.sendQuery('nxd.dname-secure.secure.example.', 'A')
+        expectedDNAME = dns.rrset.from_text('dname-secure.secure.example.', 0, dns.rdataclass.IN, 'DNAME', 'dname-secure.example.')
+        expectedCNAME = dns.rrset.from_text('nxd.dname-secure.secure.example.', 0, dns.rdataclass.IN, 'CNAME', 'nxd.dname-secure.example.')
+
+        self.assertRcodeEqual(res, dns.rcode.NXDOMAIN)
+        self.assertMessageHasFlags(res, ['QR', 'RD', 'RA', 'AD'], ['DO'])
+        self.assertRRsetInAnswer(res, expectedCNAME)
+        self.assertRRsetInAnswer(res, expectedDNAME)
+        self.assertMatchingRRSIGInAnswer(res, expectedDNAME)
+
+    def testSecureDNAMEToInsecureAnswer(self):
+        res = self.sendQuery('node1.dname-insecure.secure.example.', 'A')
+        expectedDNAME = dns.rrset.from_text('dname-insecure.secure.example.', 0, dns.rdataclass.IN, 'DNAME', 'insecure.example.')
+        expectedCNAME = dns.rrset.from_text('node1.dname-insecure.secure.example.', 0, dns.rdataclass.IN, 'CNAME', 'node1.insecure.example.')
+        expectedA = dns.rrset.from_text('node1.insecure.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.6')
+
+        self.assertRcodeEqual(res, dns.rcode.NOERROR)
+        self.assertMessageHasFlags(res, ['QR', 'RD', 'RA'], ['DO'])
+        self.assertRRsetInAnswer(res, expectedA)
+        self.assertRRsetInAnswer(res, expectedCNAME)
+        self.assertRRsetInAnswer(res, expectedDNAME)
+        self.assertMatchingRRSIGInAnswer(res, expectedDNAME)
+
+    def testSecureDNAMEToInsecureNXDomain(self):
+        res = self.sendQuery('nxd.dname-insecure.secure.example.', 'A')
+        expectedDNAME = dns.rrset.from_text('dname-insecure.secure.example.', 0, dns.rdataclass.IN, 'DNAME', 'insecure.example.')
+        expectedCNAME = dns.rrset.from_text('nxd.dname-insecure.secure.example.', 0, dns.rdataclass.IN, 'CNAME', 'nxd.insecure.example.')
+
+        self.assertRcodeEqual(res, dns.rcode.NXDOMAIN)
+        self.assertMessageHasFlags(res, ['QR', 'RD', 'RA'], ['DO'])
+        self.assertRRsetInAnswer(res, expectedCNAME)
+        self.assertRRsetInAnswer(res, expectedDNAME)
+        self.assertMatchingRRSIGInAnswer(res, expectedDNAME)
+
+    def testSecureDNAMEToBogusAnswer(self):
+        res = self.sendQuery('ted.dname-bogus.secure.example.', 'A')
+
+        self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
+        self.assertAnswerEmpty(res)
+
+    def testSecureDNAMEToBogusNXDomain(self):
+        res = self.sendQuery('nxd.dname-bogus.secure.example.', 'A')
+
+        self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
+        self.assertAnswerEmpty(res)
+
+    def testInsecureDNAMEtoSecureAnswer(self):
+        res = self.sendQuery('host1.dname-to-secure.insecure.example.', 'A')
+        expectedDNAME = dns.rrset.from_text('dname-to-secure.insecure.example.', 0, dns.rdataclass.IN, 'DNAME', 'dname-secure.example.')
+        expectedCNAME = dns.rrset.from_text('host1.dname-to-secure.insecure.example.', 0, dns.rdataclass.IN, 'CNAME', 'host1.dname-secure.example.')
+        expectedA = dns.rrset.from_text('host1.dname-secure.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.21')
+
+        self.assertRcodeEqual(res, dns.rcode.NOERROR)
+        self.assertMessageHasFlags(res, ['QR', 'RD', 'RA'], ['DO'])
+        self.assertRRsetInAnswer(res, expectedA)
+        self.assertRRsetInAnswer(res, expectedCNAME)
+        self.assertRRsetInAnswer(res, expectedDNAME)
+        self.assertMatchingRRSIGInAnswer(res, expectedA)
+
+    def testSecureDNAMEToSecureCNAMEAnswer(self):
+        res = self.sendQuery('cname-to-secure.dname-secure.secure.example.', 'A')
+
+        expectedDNAME = dns.rrset.from_text('dname-secure.secure.example.', 0, dns.rdataclass.IN, 'DNAME', 'dname-secure.example.')
+        expectedCNAME1 = dns.rrset.from_text('cname-to-secure.dname-secure.secure.example.', 0, dns.rdataclass.IN, 'CNAME', 'cname-to-secure.dname-secure.example.')
+        expectedCNAME2 = dns.rrset.from_text('cname-to-secure.dname-secure.example.', 0, dns.rdataclass.IN, 'CNAME', 'host1.secure.example.')
+        expectedA = dns.rrset.from_text('host1.secure.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.2')
+
+        self.assertRcodeEqual(res, dns.rcode.NOERROR)
+        self.assertMessageHasFlags(res, ['QR', 'RD', 'RA', 'AD'], ['DO'])
+        self.assertRRsetInAnswer(res, expectedA)
+        self.assertRRsetInAnswer(res, expectedCNAME1)
+        self.assertRRsetInAnswer(res, expectedCNAME2)
+        self.assertMatchingRRSIGInAnswer(res, expectedCNAME2)
+        self.assertRRsetInAnswer(res, expectedDNAME)
+        self.assertMatchingRRSIGInAnswer(res, expectedDNAME)
+        self.assertMatchingRRSIGInAnswer(res, expectedA)
+
+    def testSecureDNAMEToInsecureCNAMEAnswer(self):
+        res = self.sendQuery('cname-to-insecure.dname-secure.secure.example.', 'A')
+
+        expectedDNAME = dns.rrset.from_text('dname-secure.secure.example.', 0, dns.rdataclass.IN, 'DNAME', 'dname-secure.example.')
+        expectedCNAME1 = dns.rrset.from_text('cname-to-insecure.dname-secure.secure.example.', 0, dns.rdataclass.IN, 'CNAME', 'cname-to-insecure.dname-secure.example.')
+        expectedCNAME2 = dns.rrset.from_text('cname-to-insecure.dname-secure.example.', 0, dns.rdataclass.IN, 'CNAME', 'node1.insecure.example.')
+        expectedA = dns.rrset.from_text('node1.insecure.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.6')
+
+        self.assertRcodeEqual(res, dns.rcode.NOERROR)
+        self.assertMessageHasFlags(res, ['QR', 'RD', 'RA'], ['DO'])
+        self.assertRRsetInAnswer(res, expectedA)
+        self.assertRRsetInAnswer(res, expectedCNAME1)
+        self.assertRRsetInAnswer(res, expectedCNAME2)
+        self.assertMatchingRRSIGInAnswer(res, expectedCNAME2)
+        self.assertRRsetInAnswer(res, expectedDNAME)
+        self.assertMatchingRRSIGInAnswer(res, expectedDNAME)
+
+    def testSecureDNAMEToBogusCNAMEAnswer(self):
+        res = self.sendQuery('cname-to-bogus.dname-secure.secure.example.', 'A')
+
+        self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
+        self.assertAnswerEmpty(res)
+
+    def testInsecureDNAMEtoSecureNXDomain(self):
+        res = self.sendQuery('nxd.dname-to-secure.insecure.example.', 'A')
+        expectedDNAME = dns.rrset.from_text('dname-to-secure.insecure.example.', 0, dns.rdataclass.IN, 'DNAME', 'dname-secure.example.')
+        expectedCNAME = dns.rrset.from_text('nxd.dname-to-secure.insecure.example.', 0, dns.rdataclass.IN, 'CNAME', 'nxd.dname-secure.example.')
+
+        self.assertRcodeEqual(res, dns.rcode.NXDOMAIN)
+        self.assertMessageHasFlags(res, ['QR', 'RD', 'RA'], ['DO'])
+        self.assertRRsetInAnswer(res, expectedCNAME)
+        self.assertRRsetInAnswer(res, expectedDNAME)
index 46ca97c4677ba9b3d873d324d4f184d0f8e29f1d..cfbd87bad4a6c035e399f42404e9363d3a920434 100644 (file)
@@ -85,6 +85,10 @@ cname-secure.example.    3600 IN NS   ns.cname-secure.example.
 cname-secure.example.    3600 IN DS   49148 13 1 a10314452d5ec4d97fcc6d7e275d217261fe790f
 ns.cname-secure.example. 3600 IN A    {prefix}.15
 
+dname-secure.example. 3600 IN NS ns.dname-secure.example.
+dname-secure.example. 3600 IN DS 42043 13 2 11c67f46b7c4d5968bc5f6cc944d58377b762bda53ddb4f3a6dbe6faf7a9940f
+ns.dname-secure.example. 3600 IN A {prefix}.13
+
 bogus.example.           3600 IN NS   ns.bogus.example.
 bogus.example.           3600 IN DS   65034 13 1 6df3bb50ea538e90eacdd7ae5419730783abb0ee
 ns.bogus.example.        3600 IN A    {prefix}.12
@@ -137,7 +141,22 @@ insecure.sub2.secure.example. 3600 IN NS ns1.insecure.example.
 *.cnamewildcardnxdomain.secure.example. 3600 IN CNAME doesntexist.secure.example.
 
 cname-to-formerr.secure.example. 3600 IN CNAME host1.insecure-formerr.example.
+
+dname-secure.secure.example. 3600 IN DNAME dname-secure.example.
+dname-insecure.secure.example. 3600 IN DNAME insecure.example.
+dname-bogus.secure.example. 3600 IN DNAME bogus.example.
         """,
+        'dname-secure.example': """
+dname-secure.example. 3600 IN SOA {soa}
+dname-secure.example. 3600 IN NS ns.dname-secure.example.
+ns.dname-secure.example. 3600 IN A {prefix}.13
+
+host1.dname-secure.example. IN A 192.0.2.21
+
+cname-to-secure.dname-secure.example. 3600 IN CNAME host1.secure.example.
+cname-to-insecure.dname-secure.example. 3600 IN CNAME node1.insecure.example.
+cname-to-bogus.dname-secure.example.    3600 IN CNAME ted.bogus.example.
+""",
         'cname-secure.example': """
 cname-secure.example.          3600 IN SOA   {soa}
 cname-secure.example.          3600 IN NS    ns.cname-secure.example.
@@ -165,6 +184,8 @@ ns1.insecure.example.    3600 IN A    {prefix}.13
 node1.insecure.example.  3600 IN A    192.0.2.6
 
 cname-to-secure.insecure.example. 3600 IN CNAME host1.secure.example.
+
+dname-to-secure.insecure.example. 3600 IN DNAME dname-secure.example.
         """,
         'optout.example': """
 optout.example.        3600 IN SOA  {soa}
@@ -262,6 +283,12 @@ PrivateKey: o9F5iix8V68tnMcuOaM2Lt8XXhIIY//SgHIHEePk6cM=
 Private-key-format: v1.2
 Algorithm: 13 (ECDSAP256SHA256)
 PrivateKey: kvoV/g4IO/tefSro+FLJ5UC7H3BUf0IUtZQSUOfQGyA=
+""",
+
+        'dname-secure.example': """
+Private-key-format: v1.2
+Algorithm: 13 (ECDSAP256SHA256)
+PrivateKey: Ep9uo6+wwjb4MaOmqq7LHav2FLrjotVOeZg8JT1Qk04=
 """
     }
 
@@ -274,7 +301,7 @@ PrivateKey: kvoV/g4IO/tefSro+FLJ5UC7H3BUf0IUtZQSUOfQGyA=
         '10': ['example'],
         '11': ['example'],
         '12': ['bogus.example', 'undelegated.secure.example', 'undelegated.insecure.example'],
-        '13': ['insecure.example', 'insecure.sub2.secure.example'],
+        '13': ['insecure.example', 'insecure.sub2.secure.example', 'dname-secure.example'],
         '14': ['optout.example'],
         '15': ['insecure.optout.example', 'secure.optout.example', 'cname-secure.example']
     }
@@ -333,6 +360,7 @@ query-cache-ttl=0
 log-dns-queries=yes
 log-dns-details=yes
 loglevel=9
+dname-processing=yes
 distributor-threads=1""".format(confdir=confdir,
                                 bind_dnssec_db=bind_dnssec_db))