Starting with the PowerDNS Authoritative Server 3.4.0, DNS update support is available. There are a number of items NOT supported:
The implementation requires the backend to support a number of new operations. Currently, the following backends have been modified to support DNS update:
There are two configuration parameters that can be used within the powerdns configuration file.
dnsupdate
¶A setting to enable/disable DNS update support completely. The default
is no, which means that DNS updates are ignored by PowerDNS (no message
is logged about this!). Change the setting to dnsupdate=yes
to
enable DNS update support. Default is no
.
allow-dnsupdate-from
¶A list of IP ranges that are allowed to perform updates on any domain.
The default is 127.0.0.0/8
, which means that all loopback addresses are accepted.
Multiple entries can be used on this line
(allow-dnsupdate-from=198.51.100.0/8 203.0.113.2/32
). The option can
be left empty to disallow everything, this then should be used in
combination with the ALLOW-DNSUPDATE-FROM
domain metadata setting per
zone. Setting a range here and in ALLOW-DNSUPDATE-FROM
enables updates
from either address range.
dnsupdate-require-tsig
¶New in version 5.0.0.
A setting to require DNS updates to be signed by a valid TSIG signature. The default is no, which means zones without TSIG keys can be updated by unauthenticated agents operating from an allowed address range.
forward-dnsupdate
¶Tell PowerDNS to forward to the master server if the zone is configured
as slave. Masters are determined by the masters field in the domains
table. The default behaviour is enabled (yes), which means that it will
try to forward. In the processing of the update packet, the
allow-dnsupdate-from
and TSIG-ALLOW-DNSUPDATE
are processed
first, so those permissions apply before the forward-dnsupdate
is
used. It will try all masters that you have configured until one is
successful.
lua-dnsupdate-policy-script
¶Use this Lua script containing function updatepolicy
to validate
each update. This will TURN OFF
all other
authorization methods, and you are expected to take care of everything
yourself. See Update policy for details and
examples.
The semantics are that first a dynamic update has to be allowed either
by the global allow-dnsupdate-from setting, or by a per-zone
ALLOW-DNSUPDATE-FROM
metadata setting.
Secondly, if a zone has a TSIG-ALLOW-DNSUPDATE
metadata setting, that
must match too.
So to only allow dynamic DNS updates to a zone based on TSIG key, and
regardless of IP address, set allow-dnsupdate-from to empty, set
ALLOW-DNSUPDATE-FROM
to “0.0.0.0/0” and “::/0” and set the
TSIG-ALLOW-DNSUPDATE
to the proper key name.
Further information can be found below.
For permissions, a number of per zone settings are available via the domain metadata.
This setting has the same function as described in the configuration options (See above). This will allow 198.51.100.0/8 and 203.0.113.2/32 to send DNS update messages for the example.org domain:
pdnsutil set-meta example.org ALLOW-DNSUPDATE-FROM 198.51.100.0/8 203.0.113.2/32
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. Here is an example using pdnsutil to create a key named test:
$ pdnsutil generate-tsig-key test hmac-sha512
Create new TSIG key test hmac-sha512 [base64-encoded key]
$ pdnsutil list-tsig-keys | grep test
test. hmac-sha512. [base64-encoded key]
This adds the key with the name test to the zone’s metadata. Note, the keys need to be added separately with add-meta, not as a comma or space-separated list:
$ pdnsutil add-meta example.org TSIG-ALLOW-DNSUPDATE test
Set 'example.org' meta TSIG-ALLOW-DNSUPDATE = test
$ pdnsutil get-meta example.org TSIG-ALLOW-DNSUPDATE
TSIG-ALLOW-DNSUPDATE = test
This is an example of using the new test TSIG key with the nsupdate command (see the manpage for nsupdate for full details):
$ nsupdate <<!
server 127.0.0.1 53
zone example.org
update add test1.example.org 3600 A 1.2.3.4
update add test1.example.org 3600 TXT "this is a test"
key hmac-sha512:test [base64-encoded key]
send
!
$ dig +noall +answer -t any test1.example.org @127.0.0.1
test1.example.org. 3600 IN A 1.2.3.4
test1.example.org. 3600 IN TXT "this is a test"
If any TSIG keys are listed in a zone’s TSIG-ALLOW-DNSUPDATE
metadata, one
of them is required for updates. If ALLOW-DNSUPDATE-FROM
is also set,
both requirements need to be satisfied before an update will be accepted.
By default, an update can add, update or delete any resource records in the zone. See Update policy for finer-grained control of what an update is allowed to do. Use dnsupdate-require-tsig to disallow unsigned updates.
See Configuration options for what it does, but per domain:
pdnsutil set-meta example.org FORWARD-DNSUPDATE 'yes'
The existence of the entry (even with an empty value) enables the forwarding. This domain-specific setting is only useful when the configuration option forward-dnsupdate is set to ‘no’, as that will disable it globally. Using the domainmetadata setting than allows you to enable it per domain.
Send a notification to all slave servers after every update. This will speed up the propagation of changes and is very useful for acme verification:
pdnsutil set-meta example.org NOTIFY-DNSUPDATE 1
After every update, the soa serial is updated as this is required by
section 3.7 of RFC 2136. The behaviour is configurable via domainmetadata
with the SOA-EDIT-DNSUPDATE
option. It has a number of options listed
below. If no behaviour is specified, DEFAULT is used.
2136, Section 3.6 defines some specific behaviour for updates of SOA records. Whenever the SOA record is updated via the update message, the logic to change the SOA is not executed.
Note
Powerdns will always use SOA-EDIT when serving SOA records, thus a query for the SOA record of the recently updated domain, might have an unexpected result due to a SOA-EDIT setting.
An example:
pdnsutil set-meta example.org SOA-EDIT-DNSUPDATE INCREASE
This will make the SOA Serial increase by one, for every successful update.
These are the settings available for SOA-EDIT-DNSUPDATE.
DNS update is often used with DHCP to automatically provide a hostname whenever a new IP-address is assigned by the DHCP server. This section describes how you can setup PowerDNS to receive DNS updates from ISC’s dhcpd (version 4.1.1-P1).
We’re going to use a TSIG key for security. We’re going to generate a key using the following command:
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:
# ls -l Kdhcp*
-rw------- 1 root root 53 Aug 26 19:29 Kdhcpdupdate.+157+20493.key
-rw------- 1 root root 165 Aug 26 19:29 Kdhcpdupdate.+157+20493.private
# cat Kdhcpdupdate.+157+20493.key
dhcpdupdate. IN KEY 0 3 157 FYhvwsW1ZtFZqWzsMpqhbg==
The important bits are the name of the key (dhcpdupdate) and the hash of the key (FYhvwsW1ZtFZqWzsMpqhbg==)
Using the details from the freshly generated key, add the following to your dhcpd.conf:
key "dhcpdupdate" {
algorithm hmac-md5;
secret "FYhvwsW1ZtFZqWzsMpqhbg==";
};
You must also tell dhcpd that you want dynamic dns to work, add the following section:
ddns-updates on;
ddns-update-style interim;
update-static-leases on;
This tells dhcpd to:
For more information on this, consult the dhcpd.conf manual.
Per subnet, you also have to tell dhcpd which (reverse-)domain it should update and on which master domain server it is running.
ddns-domainname "example.org";
ddns-rev-domainname "in-addr.arpa.";
zone example.org {
primary 127.0.0.1;
key dhcpdupdate;
}
zone 1.168.192.in-addr.arpa. {
primary 127.0.0.1;
key dhcpdupdate;
}
This tells dhcpd a number of things:
This concludes the changes that are needed to the dhcpd configuration file.
A number of small changes are needed to PowerDNS to make it accept dynamic updates from dhcpd.
Enable DNS update (RFC 2136) support functionality in PowerDNS by adding the following to the PowerDNS configuration file (pdns.conf).
dnsupdate=yes
allow-dnsupdate-from=
This tells PowerDNS to:
We just told PowerDNS (via the configuration file) that we accept updates from nobody via the allow-dnsupdate-from parameter. That’s not very useful, so we’re going to give permissions per zone (including the appropriate reverse zone), via the domainmetadata table.
pdnsutil set-meta example.org ALLOW-DNSUPDATE-FROM 127.0.0.1
pdnsutil set-meta 1.168.192.in-addr.arpa ALLOW-DNSUPDATE-FROM 127.0.0.1
This gives the ip ‘127.0.0.1’ access to send update messages. Make sure you use the ip address of the machine that runs dhcpd.
Another thing we want to do, is add TSIG security. This can only be done via the domainmetadata table:
pdnsutil import-tsig-key dhcpdupdate hmac-md5 FYhvwsW1ZtFZqWzsMpqhbg==
pdnsutil set-meta example.org TSIG-ALLOW-DNSUPDATE dhcpdupdate
pdnsutil set-meta 1.168.192.in-addr.arpa TSIG-ALLOW-DNSUPDATE dhcpdupdate
This will:
Restart PowerDNS and you should be ready to go!
This is a short description of how DNS update messages are processed by PowerDNS.
You can define a Lua script to handle DNS UPDATE message
authorization. The Lua script is to contain at least function called
updatepolicy
which accepts one parameter. This parameter is an
object, containing all the information for the request. To permit
change, return true, otherwise return false. The script is called for
each record at a time and you can approve or reject any or all.
The object has following methods available:
DNSName getQName()
- name to updateDNSName getZoneName()
- zone nameint getQType()
- record type, it can be 255(ANY) for delete.ComboAddress getLocal()
- local socket addressComboAddress getRemote()
- remote socket addressNetmask 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.
Example:
resolve("www.google.com", pdns.A)
You can use this to perform DNS lookups. If your resolver cannot find your local records, then this will not find them either. In other words, resolve does not perform local lookup.
Simple example script:
--- This script is not suitable for production use
function strpos (haystack, needle, offset)
local pattern = string.format("(%s)", needle)
local i = string.find (haystack, pattern, (offset or 0))
return (i ~= nil and i or false)
end
function updatepolicy(input)
princ = input:getPeerPrincipal()
if princ == ""
then
return false
end
if princ == "admin@DOMAIN" or input:getRemote():toString() == "192.168.1.1"
then
return true
end
if (input:getQType() == pdns.A or input:getQType() == pdns.AAAA) and princ:sub(5,5) == '/' and strpos(princ, "@", 0) ~= false
then
i = strpos(princ, "@", 0)
if princ:sub(i) ~= "@DOMAIN"
then
return false
end
hostname = princ:sub(6, i-1)
if input:getQName():toString() == hostname .. "." or input:getQName():toString() == hostname .. "." .. input:getZoneName():toString()
then
return true
end
end
return false
end
Additional updatepolicy example scripts can be found in our Wiki.