Allow-notify SUBNET and request-xfr inconsistency

Hi list,
We are observing strange behavior of nsd v3.2.9 acting as slave DNS server.

The environment is set up as follows:
0. We are using 172.16.0.0/16 subnet;
1. Primary Master server at 172.16.100.114;
2. Slave server at 172.16.100.115. The config file is
in /etc/nsd-dns-slave.conf;
3. There may be also other Master servers im the given subnet.

Now I want to permit DNS NOTIFY messages to come from 172.16/16 subnet.
To do this, I use allow-notify in the slave config file:

zone:
        name: "black"
        zonefile: "/var/nsd/zones/black.zone"
        allow-notify: 172.16.0.0/24 NOKEY

Then I receive error message from nsd-checkconf:
/etc/nsd-dns-slave.conf: zone black has allow-notify but no request-xfr items.
Where can it get a zone transfer when a notify is received?
/etc/nsd-dns-slave.conf: 1 semantic errors in 1 zones, 0 keys.

Hm, ok, I need request-xfr. But request-xfr does not allow to use subnets!
When I use:
zone:
        name: "black"
        zonefile: "/var/nsd/zones/black.zone"
        allow-notify: 172.16.0.0/24 NOKEY
        request-xfr: 172.16.0.0/24 NOKEY

I get:
/etc/nsd-dns-slave.conf:33: error: address range used for request-xfr
read /etc/nsd-dns-slave.conf failed: 1 errors in configuration file

OK. So I can use only host address here. Here I thought that I can put some
random address from my /16 network just to make nsd-checkconf shut up :slight_smile:
So:

zone:
        name: "black"
        zonefile: "/var/nsd/zones/black.zone"
        allow-notify: 172.16.0.0/16 NOKEY
        request-xfr: 172.16.100.199 NOKEY

The host 172.16.100.199 does not exist at all :slight_smile:

Now nsd-checkconf doesn't complain.
What I expect now is that any server from /16 network can send me a NOTIFY
message and it should be accepted. Furthermore, RFC-1996, Section 3.11 says:

Because a deep server dependency graph may have multiple paths
      from the primary master to any given slave, it is possible that
      a slave will receive a NOTIFY from one of its known masters even
      though the rest of its known masters have not yet updated their
      copies of the zone. Therefore, when issuing a QUERY for the
      zone's SOA, the query should be directed at the known master who
      was the source of the NOTIFY event, and not at any of the other
      known masters

therefore I expect that upon receiving NOTIFY from 172.16.100.114, my slave
server will send AXFR to it.
But this doesn't happen, I see the following in the logs:
[1342626791] nsd[12538]: info: Notify received and accepted, forward to xfrd
[1342626791] nsd[7729]: info: Handle incoming notify for zone black
[1342626791] nsd[7729]: error: xfrd: connect 172.16.100.199 failed: Host is
down
[1342626791] nsd[7729]: error: xfrd: connect 172.16.100.199 failed: Host is
down
[1342626791] nsd[7729]: error: xfrd: connect 172.16.100.199 failed: Host is
down

So, the question is: why did nsd try to connect to 172.16.100.199, if it
received DNS NOTIFY from 172.16.100.114?
Or 172.16.100.114 is not considered a "known master" despite being allowed to
send DNS NOTIFY by allow-notify ACL? What's the meaning of allow-notify ACL
in this case if nsd sends AXFR only to hosts from request-xfr list?

Thanks!

Hi Ilya,

When the notifying host is listed in the request-xfr's, it will be tried
first.

Having allow-notify and request-xfr separated is convenient in many
cases. For example you could add allow-notify: 127.0.0.0/8 to trigger a
transfer from a master server from the localhost with nsd-notify. Or
perhaps the master has multiple interfaces and will send out from one,
but only serve on another interface.

Op 18-07-12 18:00, Ilya Bakulin schreef:

Hi Willem,
thank you for your reply.
OK, I understand the purpose of allow-notify better now.

I have updated to nsd 3.2.11 and tried to test the case where nsd as slave has
multiple master servers (which are all listed in allow-notify and request-xfr
lists) and receives DNS NOTIFY from one of them. If I read your email
properly, in this case nsd should send AXFR to the server that has sent him
DNS NOTIFY.
Unfortunately, this is not the case.

My config:

zone:
        name: "black"
        zonefile: "/var/nsd/zones/black.zone"
        allow-notify: 172.16.0.1/32 NOKEY
        request-xfr: 172.16.0.1 NOKEY
        allow-notify: 192.168.254.1/32 NOKEY
        request-xfr: 192.168.254.1 NOKEY
        allow-notify: 172.16.100.114/32 NOKEY
        request-xfr: 172.16.100.114 NOKEY

172.16.0.1 is just some host in the test network.
192.168.254.1 is a DNS server that serves the test network, but it doesn't
know anything about "black.zone".
172.16.100.114 is the master server for "black.zone".

Now I update the zone contents on 100.114.

I see the following in the logfile of slave nsd:
Jul 19 13:45:39 ggd115 <nsd> nsd[27117]: Notify received and accepted, forward
to xfrd
Jul 19 13:45:39 ggd115 <nsd> nsd[15476]: Handle incoming notify for zone black
Jul 19 13:45:49 ggd115 <nsd> nsd[15476]: xfrd: zone black received error code
SERVER NOT AUTHORITATIVE FOR ZONE from 192.168.254.1
Jul 19 13:45:49 ggd115 <nsd> nsd[15476]: xfrd: zone black written received XFR
from 172.16.100.114 with serial 1342698338 to disk
Jul 19 13:45:49 ggd115 <nsd> nsd[15476]: xfrd: zone black committed "xfrd:
zone black received update to serial 1342698338 at time 1342698349 from
172.16.100.114 in 1 parts"
Jul 19 13:45:49 ggd115 <nsd> nsd[16641]: signal received, reloading...
Jul 19 13:45:49 ggd115 <nsd> nsd[17632]: memory recyclebin holds 0 bytes
Jul 19 13:45:49 ggd115 <nsd> nsd[27117]: NSTATS 1342698349 1342698318 SOA=1
Jul 19 13:45:49 ggd115 <nsd> nsd[27117]: XSTATS 1342698349 1342698318 RR=0
RNXD=0 RFwdR=0 RDupR=0 RFail=0 RFErr=0 RErr=0 RAXFR=0 RLame=0 ROpts=0 SSysQ=0
SAns=1 SFwdQ=0 SDupQ=0 SErr=0 RQ=0 RIQ=0 RFwdQ=0 RDupQ=0 RTCP=0 SFwdR=0
SFail=0 SFErr=0 SNaAns=0 SNXD=0 RUQ=0 RURQ=0 RUXFR=0 RUUpd=0
Jul 19 13:45:49 ggd115 <nsd> nsd[15476]: Zone black serial 1342698298 is
updated to 1342698338.

So, what's strange is "error code SERVER NOT AUTHORITATIVE FOR ZONE from
192.168.254.1" -- that means that nsd tried to contact 192.168.254.1 despite
that he received NOTIFY from 172.16.100.114. When I run tcpdump on ggd115, I
see that nsd also tried to contact 172.16.0.1, but received nothing because
that host doesn't provide DNS at all.
And yes, first it tries 172.16.0.1, then 192.168.254.1, and only after that
172.16.100.114...

What am I doing wrong here?

Hi Ilya,

When the notifying host is listed in the request-xfr's, it will be tried
first.

Having allow-notify and request-xfr separated is convenient in many
cases. For example you could add allow-notify: 127.0.0.0/8 to trigger a
transfer from a master server from the localhost with nsd-notify. Or
perhaps the master has multiple interfaces and will send out from one,
but only serve on another interface.

Op 18-07-12 18:00, Ilya Bakulin schreef:
> Hi list,
> We are observing strange behavior of nsd v3.2.9 acting as slave DNS
> server.
>
> The environment is set up as follows:
> 0. We are using 172.16.0.0/16 subnet;
> 1. Primary Master server at 172.16.100.114;
> 2. Slave server at 172.16.100.115. The config file is
> in /etc/nsd-dns-slave.conf;
> 3. There may be also other Master servers im the given subnet.
>
> Now I want to permit DNS NOTIFY messages to come from 172.16/16 subnet.
> To do this, I use allow-notify in the slave config file:
>
> zone:
> name: "black"
> zonefile: "/var/nsd/zones/black.zone"
> allow-notify: 172.16.0.0/24 NOKEY
>
> Then I receive error message from nsd-checkconf:
> /etc/nsd-dns-slave.conf: zone black has allow-notify but no request-xfr
> items. Where can it get a zone transfer when a notify is received?
> /etc/nsd-dns-slave.conf: 1 semantic errors in 1 zones, 0 keys.
>
> Hm, ok, I need request-xfr. But request-xfr does not allow to use
> subnets! When I use:
> zone:
> name: "black"
> zonefile: "/var/nsd/zones/black.zone"
> allow-notify: 172.16.0.0/24 NOKEY
> request-xfr: 172.16.0.0/24 NOKEY
>
> I get:
> /etc/nsd-dns-slave.conf:33: error: address range used for request-xfr
> read /etc/nsd-dns-slave.conf failed: 1 errors in configuration file
>
> OK. So I can use only host address here. Here I thought that I can put
> some random address from my /16 network just to make nsd-checkconf shut
> up :slight_smile: So:
>
> zone:
> name: "black"
> zonefile: "/var/nsd/zones/black.zone"
> allow-notify: 172.16.0.0/16 NOKEY
> request-xfr: 172.16.100.199 NOKEY
>
> The host 172.16.100.199 does not exist at all :slight_smile:
>
> Now nsd-checkconf doesn't complain.
> What I expect now is that any server from /16 network can send me a
> NOTIFY
>
> message and it should be accepted. Furthermore, RFC-1996, Section 3.11

says:

Hi Willem,
could you please comment on this? Sorry I haven't CCed you in my previous
email...

Hi Ilya,

message and it should be accepted. Furthermore, RFC-1996, Section 3.11

says:

Because a deep server dependency graph may have multiple paths
      from the primary master to any given slave, it is possible that
      a slave will receive a NOTIFY from one of its known masters even
      though the rest of its known masters have not yet updated their
      copies of the zone. Therefore, when issuing a QUERY for the
      zone's SOA, the query should be directed at the known master who
      was the source of the NOTIFY event, and not at any of the other
      known masters

This is in fact what NSD does. I took a look at it today and it seems
that there is a bug when allow-notify specifies a subnet. The notifier
is than not properly matched with the request-xfr entries.

Tomorrow I will spend some time fixing it. Untested, but as a work
around specify all hosts separately in allow-notify exactly like in
request-xfr.

Regards,
Yuri Schaeffer

Hi Yuri,

Hello Ilya,

I have tested suggested workaround and it works as expected.
We will now wait for your fix.

As of revision 3621 in the NSD_3_2 branch NSD should select the notifier
to XFR from as a first try. Even if allow-notify specifies a subnet.
I.e. IFF the notifying host matches a request-xfr entry exactly. This
also means you should use the same key for allow-notify and request-xfr
for that particular host (or both NOKEY).

Thank you for reporting your observations!

Regards,
Yuri

Hi Yuri,
thank you for your fix!
There is one small problem with it. The following code in xfrd.c:

                /* First, see if our notifier has a match in provide-xfr */
                xfr_acl = acl_find_num(
                        zone->zone_options->request_xfr, acl_num_xfr);

                if (xfr_acl) {
                        next = acl_num_xfr;
                } /* If not, find master that matches notifiers ACL entry
*/ else {
                        next = find_same_master_notify(zone, acl_num);
                        if(next != -1) {
                                zone->next_master = next;
                                DEBUG(DEBUG_XFRD,1, (LOG_INFO,
                                        "xfrd: notify set next master to
query %d", next));
                        }
                }

doesn't work correctly, because after assigning value of "acl_num_xfr"
to "next" variable it is never used. I have corrected this as follows:

                /* First, see if our notifier has a match in provide-xfr */
                xfr_acl = acl_find_num(
                        zone->zone_options->request_xfr, acl_num_xfr);

                if (xfr_acl) {
                        next = acl_num_xfr;
                } /* If not, find master that matches notifiers ACL entry
*/ else {
                        next = find_same_master_notify(zone, acl_num);
                }
                if(next != -1) {
                  zone->next_master = next;
                  DEBUG(DEBUG_XFRD,1, (LOG_INFO,
                                       "xfrd: notify set next master to
query %d", next));
                }

And now it works correctly.

Hi Ilya,

There is one small problem with it. The following code in xfrd.c:

[..]

doesn't work correctly, because after assigning value of
"acl_num_xfr" to "next" variable it is never used. I have
corrected this as follows:

You are absolutely right. I guess I cleaned up the code a bit too much
before committing. Your patch is applied in the repository.

Thank you for reviewing!
Regards,
Yuri