Bind 9 and Samba 4 – In-addr.arpa Zone Delegation

active-directoryddnsdhcp-serverreverse-dnssamba4

Environment and goals

In my testing KVM lab I have a virtual network 172.16.50/24, in this network I have got 2 Centos 7 VMs running Bind 9 and ISC DHCP servers:

  • Мастер DNS : controller.wsvirt.home (172.16.50.2)
  • Slave DNS: controller2.wsvirt.home (172.16.50.3)

All clients in the network are Linux VMs and all of the them get network configuration from the DHCP server. This server dynamically updates DNS zones.

Bind 9 is an authoritative server for wsvirt.home zone.

In the lab environment I test a scenario which I have to implement in our business office network. In the business environment I should create an AD domain to serve Windows clients and for this purpose we have decided to utilize Samba 4 as a DC. I have built a Samba server for Centos 7 with Heimdal Kerberos support from the sources.

For the AD I allocated subnetwork 172.16.50.192/26 and assigned ad.wsvirt.home domain.

AD DC is a Centos 7 VM running Samba 4, Bind 9 and ISC DHCP servers. Samba makes use of BIND_DLZ as a DNS backend. AD controller has addc1.ad.wsvirt.home domain name and IP 172.16.50.193.

All Windows AD clients get IP from the DHCP server running on the AD DC which dynamically updates Bind DLZ zones.

In the real working physical environment all client PCs from the both networks should be connected to one broadcast domain.

To satisfy the requirements I delegated authority for the forward ad.wsvirt.home and reverse 172.16.50.192/26 DNS zones from the Bind on the controller.wsvirt.home server to the AD controller addc1.ad.wsvirt.home accordingly to [RFC 2317][1].

# Problem #

Everything works perfectly except one thing. When I test revers lookup for delegated reverse zone over AD DC then result looks OK, thus Windows AD client could resolve all reverse domain name in both domains. :

$ dig -x 172.16.50.193 @addc1.ad.wsvirt.home

; <<>> DiG 9.11.4-P2-RedHat-9.11.4-9.P2.el7 <<>> -x 172.16.50.193 @addc1.ad.wsvirt.home
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 43507
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;193.50.16.172.in-addr.arpa.    IN      PTR

;; ANSWER SECTION:
193.50.16.172.in-addr.arpa. 86400 IN    CNAME   193.50.16.172.ddns.
193.50.16.172.ddns.     900     IN      PTR     addc1.ad.wsvirt.home.

;; Query time: 7 msec
;; SERVER: 172.16.50.193#53(172.16.50.193)
;; WHEN: Mon Mar 30 21:05:12 IDT 2020
;; MSG SIZE  rcvd: 121

But when I route my requests to the DNS server “`controller.wsvirt.home“` it does not resolve any reverse name from the “`ad.wsvirt.home“` domain, consequently the Linux clients could not lookup any reverse name as well:

$ dig -x 172.16.50.193 @controller.wsvirt.home

; <<>> DiG 9.11.4-P2-RedHat-9.11.4-9.P2.el7 <<>> -x 172.16.50.193 @controller.wsvirt.home
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 48825
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;193.50.16.172.in-addr.arpa.    IN      PTR

;; ANSWER SECTION:
193.50.16.172.in-addr.arpa. 86400 IN    CNAME   193.50.16.172.ddns.

;; AUTHORITY SECTION:
.                       8133    IN      SOA     a.root-servers.net. nstld.verisign-grs.com. 2020033001 1800 900 604800 86400

;; Query time: 0 msec
;; SERVER: 172.16.50.2#53(172.16.50.2)
;; WHEN: Mon Mar 30 21:49:41 IDT 2020
;; MSG SIZE  rcvd: 162

**I need** Linux clients from the “`wsvirt.home“` domain to be able to resolve reverse domain names in the “`ad.wsvirt.home“` domain. Is it possible at all?

# Configurations #

To be more precise I put here my configuration files for both servers

Server controller.wsvirt.home

/etc/named.conf

acl local { 172.16.50.0/24; 127.0.0.1; };

include "/etc/named.rfc1912.zones";
include "/etc/named.root.key";
include "/etc/rndc.key";

server 172.16.50.3 {
        keys { "rndc-key"; };
};

...

options {
        listen-on port 53 { local; };
        listen-on-v6 port 53 { ::1; };
        directory       "/var/named";
        dump-file       "/var/named/data/cache_dump.db";
        statistics-file "/var/named/data/named_stats.txt";
        memstatistics-file "/var/named/data/named_mem_stats.txt";
        recursing-file  "/var/named/data/named.recursing";
        secroots-file   "/var/named/data/named.secroots";
        allow-query     { local; };
        allow-transfer { none; };
        notify no; 
        forwarders { 8.8.8.8; 8.8.4.4; };
        forward only;
        recursion yes;
        dnssec-enable yes;
        dnssec-validation yes;
        bindkeys-file "/etc/named.iscdlv.key";
        managed-keys-directory "/var/named/dynamic";
        pid-file "/run/named/named.pid";
        session-keyfile "/run/named/session.key";
};


zone "." IN {
        type hint; 
        file "named.ca";
};

zone "wsvirt.home" IN {
        type master;
        file "wsvirt.home.db";
        allow-update { key "rndc-key"; };
        allow-transfer { key "rndc-key"; };
        notify yes;
        forwarders {};
};

zone "50.16.172.in-addr.arpa" IN {
        type master;
        file "50.16.172.db";
        allow-update { key "rndc-key"; };
        allow-transfer { key "rndc-key"; };
        notify yes;
};

### /var/named/50.16.172.db ###
“`
$ORIGIN .
$TTL 86400 ; 1 day
50.16.172.in-addr.arpa IN SOA controller.wsvirt.home. root.wsvirt.home. (
153 ; serial
3600 ; refresh (1 hour)
1800 ; retry (30 minutes)
604800 ; expire (1 week)
86400 ; minimum (1 day)
)
NS controller.wsvirt.home.
NS controller2.wsvirt.home.
$ORIGIN 50.16.172.in-addr.arpa.
2 PTR controller.wsvirt.home.
$TTL 86400 ; 1 day
3 PTR controller2.wsvirt.home.

;
50.16.172.ddns. IN NS addc1.ad.wsvirt.home.
$GENERATE 193-254 $ IN CNAME $.50.16.172.ddns.
“`

### /etc/dhcp/dhcpd.conf ###
“`
include "/etc/rndc.key";

default-lease-time 600;
max-lease-time 7200;
authoritative;
ddns-update-style interim;

class "windows" {
match if substring (option vendor-class-identifier, 0, 8) = "MSFT 5.0";
}

subnet 172.16.50.0 netmask 255.255.255.0 {
log (info, concat("Vendor Class ID (60): ", option vendor-class-identifier));
log (info, concat("DHCP Client ID (61): ", option dhcp-client-identifier));
log (info, concat("User Class ID (77): ", option user-class));
option domain-name-servers 172.16.50.2, 172.16.50.3;
option ntp-servers 172.16.50.2;
option routers 172.16.50.1;
option broadcast-address 172.16.50.255;
default-lease-time 600;
max-lease-time 7200;
option ip-forwarding off;
ignore client-updates;
option domain-name "wsvirt.home";
option domain-search "wsvirt.home";
option netbios-scope "";
option netbios-node-type 8;
option netbios-name-servers 172.16.50.2;
option netbios-dd-server 172.16.50.2;
ddns-updates on;
ddns-domainname "wsvirt.home.";
ddns-rev-domainname "in-addr.arpa.";

    pool {  
            range 172.16.50.21 172.16.50.190;
            deny members of "windows";
    }

    zone wsvirt.home {
            primary 172.16.50.2;
            key "rndc-key";
    }

    zone 50.16.172.in-addr.arpa {
            primary 172.16.50.2;
            key "rndc-key";
    }

}



<br />
## AD DC addc1.ad.wsvirt.home ##

### /etc/named.conf ###

options {
listen-on port 53 { any; };
listen-on-v6 port 53 { ::1; };
directory "/var/named";
dump-file "/var/named/data/cache_dump.db";
statistics-file "/var/named/data/named_stats.txt";
memstatistics-file "/var/named/data/named_mem_stats.txt";
recursing-file "/var/named/data/named.recursing";
secroots-file "/var/named/data/named.secroots";
allow-query { any; };
forwarders { 172.16.50.2; 172.16.50.3; };
forward only;
recursion yes;
dnssec-enable no;
dnssec-validation no;
bindkeys-file "/etc/named.root.key";
managed-keys-directory "/var/named/dynamic";
pid-file "/run/named/named.pid";
session-keyfile "/run/named/session.key";
tkey-gssapi-keytab "/var/lib/samba/private/dns.keytab";
minimal-responses yes;
};

zone "." IN {
type hint;
file "named.ca";
};

include "/etc/rndc.key";
include "/etc/named.rfc1912.zones";
include "/etc/named.root.key";
include "/var/lib/samba/bind-dns/named.conf";


<br />
### /etc/dhcp/dhcpd.conf ###

include "/etc/rndc.key";

default-lease-time 600;
max-lease-time 7200;
min-secs 5;
authoritative;
ddns-update-style none;

class "others" {
match if substring (option vendor-class-identifier, 0, 8) != "MSFT 5.0";
}

subnet 172.16.50.192 netmask 255.255.255.192 {
log (info, concat("Vendor Class ID (60): ", option vendor-class-identifier));
log (info, concat("DHCP Client ID (61): ", option dhcp-client-identifier));
log (info, concat("User Class ID (77): ", option user-class));
option routers 172.16.50.1;
option broadcast-address 172.16.50.255;
default-lease-time 600;
max-lease-time 7200;
option ip-forwarding off;
ignore client-updates;
option ntp-servers 172.16.50.193;
option domain-name-servers 172.16.50.193;
option domain-name "ad.wsvirt.home";
option domain-search "ad.wsvirt.home";
option netbios-name-servers 172.16.50.193;
option netbios-dd-server 172.16.50.193;
option netbios-scope "";
option netbios-node-type 8;
ddns-rev-domainname "ddns";

pool {
    range 172.16.50.210 172.16.50.254;
    deny members of "others";
}

}

on commit {
set noname = concat("dhcp-", binary-to-ascii(10, 8, "-", leased-address));
set ClientIP = binary-to-ascii(10, 8, ".", leased-address);
set ClientDHCID = concat (
suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,1,1))),2), ":",
suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,2,1))),2), ":",
suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,3,1))),2), ":",
suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,4,1))),2), ":",
suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,5,1))),2), ":",
suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,6,1))),2)
);
set ClientName = pick-first-value(option host-name, config-option-host-name, client-name, noname);
log(concat("Commit: IP: ", ClientIP, " DHCID: ", ClientDHCID, " Name: ", ClientName));
execute("/usr/local/sbin/dhcp-dyndns.sh", "add", ClientIP, ClientDHCID, ClientName);
}

on release {
set ClientIP = binary-to-ascii(10, 8, ".", leased-address);
set ClientDHCID = concat (
suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,1,1))),2), ":",
suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,2,1))),2), ":",
suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,3,1))),2), ":",
suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,4,1))),2), ":",
suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,5,1))),2), ":",
suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,6,1))),2)
);
log(concat("Release: IP: ", ClientIP));
execute("/usr/local/sbin/dhcp-dyndns.sh", "delete", ClientIP, ClientDHCID);
}

on expiry {
set ClientIP = binary-to-ascii(10, 8, ".", leased-address);
log(concat("Expired: IP: ", ClientIP));
execute("/usr/local/sbin/dhcp-dyndns.sh", "delete", ClientIP, "", "0");
}


<br />
### A DLZ revers zone 50.16.172.ddns on the AD DC ###

$ samba-tool dns query localhost 50.16.172.ddns @ ALL
Password for [administrator@AD.WSVIRT.HOME]:
Name=, Records=2, Children=0
SOA: serial=3, refresh=900, retry=600, expire=86400, minttl=3600, ns=addc1.ad.wsvirt.home., email=hostmaster.ad.wsvirt.home. (flags=600000f0, serial=3, ttl=3600)
NS: addc1.ad.wsvirt.home. (flags=600000f0, serial=1, ttl=3600)
Name=193, Records=1, Children=0
PTR: addc1.ad.wsvirt.home (flags=f0, serial=3, ttl=900)
Name=230, Records=1, Children=0
PTR: winxp-1.ad.wsvirt.home (flags=f0, serial=3, ttl=3600)



  [1]: https://www.rfc-editor.org/rfc/rfc2317

Best Answer

It's normal not to get the PTR on the same answer, as the controller.wsvirt.home. isn't an authoritative name server for both zones. The flags: aa states that this is an authoritative answer, but that wouldn't be true for 193.50.16.172.ddns. IN PTR. Therefore, it can't be sent on this authoritative answer.

This is not really a problem, because that only causes another query for 193.50.16.172.ddns. IN PTR, which could then be answered recursively. Clients should be aware of doing this automatically in case of a CNAME answer.

Regarding that, there's another problem, as only addc1.ad.wsvirt.home. has zone 50.16.172.ddns.; you would get an NXDOMAIN answer on:

dig 193.50.16.172.ddns. PTR @controller.wsvirt.home

The controller.wsvirt.home. is configured as recursive (recursion yes;), but it's not aware that these addresses could be found on addc1.ad.wsvirt.home.. Therefore, it tries to resolve them as everything else: from the forwarders { 8.8.8.8; 8.8.4.4; };... and fails.

You could add the addc1.ad.wsvirt.home. as a forwarder for 50.16.172.ddns. on the controller.wsvirt.home.:

zone "50.16.172.ddns." { 
    type forward; 
    forwarders { 172.16.50.193; }; 
};

Finally, the zone for $ORIGIN 50.16.172.in-addr.arpa. could only delegate control for its own subdomains – not for a completely unrelated 50.16.172.ddns..

If you really still want to send the PTR on the same response, you need to make this domain authoritative for 50.16.172.ddns. by adding a slave zone (instead of a forward zone), e.g.

zone "50.16.172.ddns." { 
    type slave;
    file "50.16.172.ddns.db";
    masters { 172.16.50.193; }; 
};

The primary server (addc1.ad.wsvirt.home.) needs to be aware of this and allow zone transfers from controller.wsvirt.home. (and controller2.wsvirt.home, if it should act similarly):

options {
    . . .
    allow-transfer { 172.16.50.2; 172.16.50.3; };
}
Related Topic