I am running a “central DNS server”, powered by PowerDNS 3.1, which contains a number of domains natively in MySQL. The ‘type’ value for these domains is set to ‘MASTER’. Whenever I make an update to the domains (and update the SOA), PowerDNS sees this and sends a notify packet to two slave DNS servers, which are the ones that are actually defined in the zone and handle all queries for these domains.
On this same server, I also have a number of domains which actually have their master on a separate DNS server. This server retrieves the zone from them through AXFR (DNS Zone Transfer), so the ‘type’ value for these domains is set to ‘SLAVE’. The DNS servers defined for these zones are also the 2 ‘downstream’ DNS servers which I talked about above. When the zone changes on the respective master server, the server receives a notify packet from that server, and transfers the zone into its local database.
However, because the ‘type’ of these domains is set to ‘SLAVE’, PowerDNS is not sending a notify packet to those servers, as it (somewhat correctly) thinks it is a slave server, and notify packets are a job for the master server.
One could argue I could just let the 2 ‘lowest’ servers AXFR the zone from the source DNS servers and the issues would go away, but I want to keep configuration as simple as possible, upstream DNS servers only need to allow one single IP to notify and allow AXFR from.
Three solutions were proposed on the #powerdns IRC channel, the first two by Frank Louwers of Openminds fame, the last one by Jan-Piet Mens as a backup solution in case the former 2 had not worked:
- Run native MySQL replication between the intermediate server and the 2 downstream ones. These are actually also PowerDNS servers using a local MySQL database, so it would be an option.
- Change one or more queries PowerDNS uses to check the database for domains and spoof slave domains as masters.
- Run a BIND server in between, which is very flexible and actually also notifies when it is acting as a slave.
Update 18/11: None of these are the answer, see below for the built-in functionality.
The last option was the least attractive one, as I would not be replacing PowerDNS – it still contains a number of native MySQL zones – I would be installing another DNS server next to it for this sole purpose.
MySQL replication is also not my personal favourite, I used to do this but regularly ran into issues; it would be a more favourable option than adding another DNS server however.
Luckily, “spoofing” the MySQL query to check for master domains worked wonders.
The default value is:
gmysql-info-all-master-query=select id,name,master,last_check,notified_serial,type from domains where type='MASTER'
This is what I’m using right now:
gmysql-info-all-master-query=select id,name,master,last_check,notified_serial,type from domains where type='MASTER' or type='SLAVE'
Note: I didn’t remove the “where” part, as there are other types available in PowerDNS (‘NATIVE’ for example) and I didn’t want to inadvertently include these in the query result. The result of this change is that PowerDNS, when checking for its MASTER zones which may need a notify to downstream servers, will also see the slave domains, and check its notified_serial column to see if action is required, and if it is, sends a notify packet to the downstream servers and updates the notified_serial column.
I’m not (yet) aware of any other side-effects which might occur, but as far as I can see this is exactly what I needed!
Update 18/11: Peter van Dijk pointed me a bit after writing this at a feature that is unfortunately only documented in the PowerDNS 3.0 Release Notes:
Add 'slave-renotify' to retransmit notifies for slaved zones, which is helpful when acting as a 'signing slave' for a hidden master. Code in commit 1950.
Removing the above SQL query modification and simply adding slave-renotify=yes to the configuration file has the intended effect. Perfect!
I also noticed it is notifying the upstream server it received the notify from if (in case of some domains) it is also listed in the zone – which obviously sends a ‘REFUSED’ rcode back, but this is unrelated to whatever solution you’re using.