How to set macOS Server to prevent DNS zone transfer?

macOS Server 10.12.6 documentation says that we should prevent arbitrary zone transfers out of our DNS server, and that the way to do this is to firewall port 53 for anyone not on our LAN, with specific exceptions for our secondary DNS servers.

What they don't mention is that port 53 is where all DNS traffic goes, so firewalling that port also shuts off our DNS services for anyone on the road. Yes, we have VPN connections; no, they're not enforced and we don't want to start.

So the question then becomes: 1) how do we instruct the server to make a distinction between transfers and plain old DNS requests; 2) if that were simple, why doesn't the Apple documentation say to do that? I poked around and found the instructions to do this with plain old BIND anywhere but a Mac—and it's the same file the documentation told me to edit two weeks ago to fix a different security issue.

/Applications/Server.app/Contents/ServerRoot/private/etc/named.conf

My next step is to edit the file, try to attack my own server, and if it fails, mark this as done. In which case I can come back and answer my own question. But this requires figuring out how to do a zone transfer attack—and it leaves me back at square one if I follow the vanilla BIND instructions and it doesn't work. Anyone have any ideas?


Solution 1:

Preface: the file /Applications/Server.app/Contents/ServerRoot/private/etc/named.conf mentioned in your question is not the config file used by the macOS server. Instead the file is located at /Library/Server/named/named.conf.

The file in ServerRoot is the more or less empty default named.conf file. At the initial configuration while launching Server.app for the first time the ServerRoot named.conf is copied to /Library/Server/named/.


Access permissions to various features of the DNS server is determined by ACLs. The pre-connfigured acl in macOS server is com.apple.ServerAdmin.DNS.public.

Depending on your settings in the main panel of DNS the ACL com.apple.ServerAdmin.DNS.public is populated with networks:

  • If lookups are preformed for all clients:

    enter image description here

    the respective ACL in named.conf looks like this:

    acl "com.apple.ServerAdmin.DNS.public" {
        any;
    };
    
  • If lookups are preformed for some clients (example only):

    enter image description here

    the respective ACL in named.conf looks like this:

    acl "com.apple.ServerAdmin.DNS.public" {
        172.16.0.0/16;
        localhost;
        localnets;
    };
    

    The only ACL available in named.conf after the initial set-up is com.apple.ServerAdmin.DNS.public.

This ACL by default allows lookups in the view section for all member networks:

view "com.apple.ServerAdmin.DNS.public" { ⬅︎
    zone "localhost" IN {
        type master;
        file "localhost.zone";
        allow-update {
            none;
        };
    };

and also allows zone transfers in the view > zone [zone_name⁣] > allow-transfers section for all member networks.

...
    zone "test.home" IN {
        type master;
        file "db.test.home";
        allow-transfer {                      ⬅︎
            com.apple.ServerAdmin.DNS.public; ⬅︎
        };
        allow-update {
        none;
        };
...

To separate lookup clients from zone-transfers clients (AKA slaves) simply create a new ACL "slaves" (example):

acl "com.apple.ServerAdmin.DNS.public" {
    172.16.0.0/16;
    localhost;
    localnets;
};
acl "slaves" {
    172.16.1.8/32;  #first DNS slave
    172.16.1.18/32; #second DNS slave
};

To restrict a zone-transfer for a particular zone to slaves only, modify the allow-transfer directive ACL to slaves:

...
    zone "test.home" IN {
        type master;
        file "db.test.home";
        allow-transfer {       ⬅︎
            slaves;            ⬅︎
        };
        allow-update {
        none;
        };
...

Don't include the arrows accidentally and relaunch the DNS service afterwards!


A more advanced & secure approach is to use shared secrets/keys which is explained here: Using TSIG to enable secure Zone Transfers between Bind 9.x servers. I didn't get this to work in Sierra though.


To check whether zone transfers are possible to arbitrary hosts use on the (attacking) client:

dig @dns_server_ip example.org axfr