5

I just switched to bind 9.9.5 dynamic DNS feature with semi-automatic management of DNSSEC entries, the whole process went good and my zone files were updated well, but now I can't update or add entries via nsupdate tool.

The /etc/bind/named.conf.local:

// 1
view "localhost_view" {
    
    allow-query-on { 127.0.0.1; };
    allow-query { localhost_acl; };
    match-clients { localhost_acl; };

    zone "somehost.tld" {
            type master;
            file "/etc/bind/db.somehost.tld_10";
    };

    zone "168.192.in-addr.arpa" {
            type master;
            notify no;
            file "/etc/bind/db.192.168.10";
    };

    // formerly named.conf.default-zones

        zone "." {
                type hint;
                file "/etc/bind/db.root";
        };

        zone "localhost" {
                type master;
                file "/etc/bind/db.local";
        };

        zone "127.in-addr.arpa" {
                type master;
                file "/etc/bind/db.127";
        };

        zone "0.in-addr.arpa" {
                type master;
                file "/etc/bind/db.0";
        };

        zone "255.in-addr.arpa" {
                type master;
                file "/etc/bind/db.255";
        };

    // formerly zones.rfc1918

        zone "10.in-addr.arpa"      { type master; file "/etc/bind/db.empty"; };
        zone "16.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "17.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "18.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "19.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "20.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "21.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "22.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "23.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "24.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "25.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "26.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "27.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "28.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "29.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "30.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "31.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };

};

// 2
view "internal_10_view" {
    
    allow-query-on { 192.168.10.1; };
    allow-query { internal_10_acl; };
    match-clients { internal_10_acl; };

    zone "somehost.tld" {
            type master;
            file "/etc/bind/db.somehost.tld_10";
    };

    zone "168.192.in-addr.arpa" {
            type master;
            notify no;
            file "/etc/bind/db.192.168.10";
    };

    // formerly named.conf.default-zones

        zone "." {
                type hint;
                file "/etc/bind/db.root";
        };

        zone "localhost" {
                type master;
                file "/etc/bind/db.local";
        };

        zone "127.in-addr.arpa" {
                type master;
                file "/etc/bind/db.127";
        };

        zone "0.in-addr.arpa" {
                type master;
                file "/etc/bind/db.0";
        };

        zone "255.in-addr.arpa" {
                type master;
                file "/etc/bind/db.255";
        };

    // formerly zones.rfc1918

        zone "10.in-addr.arpa"      { type master; file "/etc/bind/db.empty"; };
        zone "16.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "17.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "18.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "19.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "20.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "21.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "22.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "23.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "24.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "25.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "26.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "27.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "28.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "29.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "30.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "31.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };

};

// 3
view "internal_150_view" {

        allow-query-on { 192.168.150.1; };
        allow-query { internal_150_acl; };
    match-clients { internal_150_acl; };

    zone "somehost.tld" {
            type master;
            file "/etc/bind/db.somehost.tld_150";
    };

    zone "168.192.in-addr.arpa" {
            type master;
            notify no;
            file "/etc/bind/db.192.168.150";
    };

    // formerly named.conf.default-zones

        zone "." {
                type hint;
                file "/etc/bind/db.root";
        };

        zone "localhost" {
                type master;
                file "/etc/bind/db.local";
        };

        zone "127.in-addr.arpa" {
                type master;
                file "/etc/bind/db.127";
        };

        zone "0.in-addr.arpa" {
                type master;
                file "/etc/bind/db.0";
        };

        zone "255.in-addr.arpa" {
                type master;
                file "/etc/bind/db.255";
        };

    // formerly zones.rfc1918

        zone "10.in-addr.arpa"      { type master; file "/etc/bind/db.empty"; };
        zone "16.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "17.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "18.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "19.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "20.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "21.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "22.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "23.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "24.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "25.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "26.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "27.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "28.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "29.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "30.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "31.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };

};

// 4
view "vpn_view" {
    
    allow-query-on { 192.168.200.1; };
    allow-query { vpn_acl; };
    match-clients { vpn_acl; };
        
    zone "somehost.tld" {
        type master;
        file "/etc/bind/db.somehost.tld_vpn";
    };

    // formerly named.conf.default-zones

        zone "." {
                type hint;
                file "/etc/bind/db.root";
        };

        zone "localhost" {
                type master;
                file "/etc/bind/db.local";
        };

        zone "127.in-addr.arpa" {
                type master;
                file "/etc/bind/db.127";
        };

        zone "0.in-addr.arpa" {
                type master;
                file "/etc/bind/db.0";
        };

        zone "255.in-addr.arpa" {
                type master;
                file "/etc/bind/db.255";
        };

    // formerly zones.rfc1918

        zone "10.in-addr.arpa"      { type master; file "/etc/bind/db.empty"; };
        zone "16.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "17.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "18.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "19.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "20.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "21.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "22.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "23.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "24.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "25.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "26.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "27.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "28.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "29.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "30.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "32.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };

};

// 5
view "global_view" {
    
    allow-query-on { 1.2.3.4; };
//  match-clients { any; !localhost_acl; !internal_10_acl; !internal_150_acl; !vpn_acl; };
    recursion no;
        
    zone "somehost.tld" {

        type master;

        update-policy local;
        auto-dnssec maintain;

        file "/etc/bind/db.somehost.tld_global";

        key-directory "/etc/bind/keys";

    };

    zone "26/4.3.2.1.in-addr.arpa" IN {
        type master;
        file "/etc/bind/db.rev";
    };

    // formerly named.conf.default-zones

        zone "." {
                type hint;
                file "/etc/bind/db.root";
        };

        zone "localhost" {
                type master;
                file "/etc/bind/db.local";
        };

        zone "127.in-addr.arpa" {
                type master;
                file "/etc/bind/db.127";
        };

        zone "0.in-addr.arpa" {
                type master;
                file "/etc/bind/db.0";
        };

        zone "255.in-addr.arpa" {
                type master;
                file "/etc/bind/db.255";
        };

    // formerly zones.rfc1918

        zone "10.in-addr.arpa"      { type master; file "/etc/bind/db.empty"; };
        zone "16.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "17.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "18.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "19.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "20.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "21.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "22.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "23.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "24.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "25.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "26.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "27.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "28.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "29.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "30.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };
        zone "32.172.in-addr.arpa"  { type master; file "/etc/bind/db.empty"; };

};

ACLs:

acl localhost_acl {
        127.0.0.0/8;
};

acl internal_10_acl {
        192.168.10.0/24;
};

acl internal_150_acl {
        192.168.150.0/24;
};

acl vpn_acl {
        192.168.200.2;
        192.168.200.5;
};

So the update-policy local; is here, /var/run/named/session.key is successfully generated and user bind readable, but when I perform the add command via nsupdate -l (as root), I always get the update failed: REFUSED error (here with debug messages):

root@somehost:/etc/bind# nsupdate -l -v -D
setup_system()
Creating key...
namefromtext
keycreate
reset_system()
user_interaction()
> ttl 46000
do_next_command()
> zone somehost.tld.
do_next_command()
> update add whatever.somehost.tld. A 1.1.1.1
do_next_command()
evaluate_update()
update_addordelete()
> send
do_next_command()
start_update()
send_update()
Sending update to 127.0.0.1#53
show_message()
Outgoing update query:
;; ->>HEADER<<- opcode: UPDATE, status: NOERROR, id:  15363
;; flags:; ZONE: 1, PREREQ: 0, UPDATE: 1, ADDITIONAL: 1
;; ZONE SECTION:
;somehost.tld.                      IN      SOA

;; UPDATE SECTION:
whatever.somehost.tld.  46000   IN      A       1.1.1.1

;; TSIG PSEUDOSECTION:
local-ddns.             0       ANY     TSIG    hmac-sha256. 1446539060 300 32 r2lt18dGihGnJepoUjvIKx8l5BPMohNJvsLoO+WQiBE                                                                         = 15363 NOERROR 0

update_completed()
tsig verification successful
show_message()

Reply from update query:
;; ->>HEADER<<- opcode: UPDATE, status: REFUSED, id:  15363
;; flags: qr ra; ZONE: 1, PREREQ: 0, UPDATE: 0, ADDITIONAL: 1
;; ZONE SECTION:
;somehost.tld.                      IN      SOA

;; TSIG PSEUDOSECTION:
local-ddns.             0       ANY     TSIG    hmac-sha256. 1446539060 300 32 Cnh9Tgg5vhKngPRk2J8n0wiRzdBLlQrp0F0qmfUotN8                                                                         = 15363 NOERROR 0

done_update()
reset_system()
user_interaction()
> quit

It is some kind of permission issue? What's wrong?

8
  • Does your update hit the correct view? I noted that match-clients starts with any, so I guess all elements after that are essentially pointless. If there are similar mistakes for other views that's one thing that could explain hitting the wrong view. Nov 3, 2015 at 9:16
  • I've commented the match-clients string in the global_view view and added one more view (localhost_view) to the question for your reference. The error persists. Nov 3, 2015 at 9:50
  • Could anything ever hit the second view? (Based on what I noted about the first view) Nov 3, 2015 at 9:52
  • The second (localhost_view) view is hit only by localhost_acl IPs which are belong to the 127.0.0.0/8 subnet. And they actually hit it. Nov 3, 2015 at 9:54
  • Are the views actually in this order? Or the other way around? Nov 3, 2015 at 9:54

2 Answers 2

7

Finally figured it out. Thanks to @Håkan Lindqvist for inspiration.

These solutions are probably Debian/Ubuntu-specific and weren't tested in other distros.

1. FIRST SOLUTION

(Using update-policy local;).

You may actually use update-policy local; directive in /etc/bind/named.conf.local in each zone declaration you want, which restricts update requests from the internet or LAN for better security. In this case the key is generated automatically and nsupdate will use it if run with -l option.

Instead of server X.X.X.X command one should use local X.X.X.X. It accepts even public IP as argument if it is local to the system!

Note: the key is not world-readable, so use sudo.

Example:

me@somehost:~$ sudo nsupdate -l
> local 1.2.3.4
> zone somehost.tld
> update add something.somehost.tld. 86400 A 1.1.1.1
> send
> quit

2. SECOND SOLUTION

(Using ddns-confgen).

I have plenty of views (localhost_view, global_view etc.), some of which have common zones (somehost.tld in my example). If I want to dynamically update them, I should use server X.X.X.X command when do nsupdate. Therefore nsupdate will send an update request to the appropriate interface and the appropriate view will handle it.

update-policy local; is not suitable in this configuration because it forbids use of the server command in nsupdate. So it is needed to generate a DDNS key and specify it in all of the zones declarations, which should be dynamically updated by nsupdate. In the Debian universe there is a ddns-confgen command which simplifies this task a lot:

me@somehost:~$ ddns-confgen
# To activate this key, place the following in named.conf, and
# in a separate keyfile on the system or systems from which nsupdate
# will be run:
key "ddns-key" {
        algorithm hmac-sha256;
        secret "pXohPnPR7dyri9ADfDLtSz+lHw/QliISyiEe0wg0a14=";
};

# Then, in the "zone" statement for each zone you wish to dynamically
# update, place an "update-policy" statement granting update permission
# to this key.  For example, the following statement grants this key
# permission to update any name within the zone:
update-policy {
        grant ddns-key zonesub ANY;
};

# After the keyfile has been placed, the following command will
# execute nsupdate using this key:
nsupdate -k <keyfile>

The output of this command is quite self-descriptive. It is needed to add key... snippet to the /etc/bind/named.conf and separate file with any name, and update-policy... snippet into each zone declaration, which will be managed by nsupdate.

To properly use nsupdate tool in multi-view BIND environment, it is needed to explicitly specify a server directive before executing any other command. So, for updating localhost_view's somehost.tld zone (considering key... snippet was saved to the /etc/bind/ddns-key.key) the commands are as follows (note the server 127.0.0.1):

me@somehost:~$ nsupdate -k /etc/bind/ddns-key.key
> server 127.0.0.1
> zone somehost.tld
> update add something.somehost.tld. 86400 A 1.1.1.1
> send
> quit

whereas to manipulate global_view's somehost.tld zone the commands are essentially the same, but with different server. In this case it is needed to use public IP (1.2.3.4 in my example):

me@somehost:~$ nsupdate -k /etc/bind/ddns-key.key
> server 1.2.3.4
> zone somehost.tld
> update add something.somehost.tld. 86400 A 1.1.1.1
> send
> quit

Therefore nsupdate sends a request to a proper interface (which may or may not be the local one) and a specific view works.

2

You're using nsupdate -l which sends the update message to localhost (the verbose output confirms that it used the loopback address, as expected, Sending update to 127.0.0.1#53).

However, the zone you are attempting to update is not in the view that this update message will hit. Your first view (localhost_view) has match-clients { localhost_acl; };.

acl localhost_acl {
        127.0.0.0/8;
};

The zone you are trying to update is in the view global_view defined later in your config.

If you check your logs, I would think that the failure is logged and the log message will likely include information about which view it hit (should be localhost_view, based on your config).

It's important to note that views are ordered and the first matching view will receive any given message.

From the section on views in the manual:

Each view statement defines a view of the DNS namespace that will be seen by a subset of clients. A client matches a view if its source IP address matches the address_match_list of the view's match-clients clause and its destination IP address matches the address_match_list of the view's match-destinations clause. If not specified, both match-clients and match-destinations default to matching all addresses. In addition to checking IP addresses match-clients and match-destinations can also take keys which provide an mechanism for the client to select the view. A view can also be specified as match-recursive-only, which means that only recursive requests from matching clients will match that view. The order of the view statements is significant — a client request will be resolved in the context of the first view that it matches.

As is mentioned in the quoted explanation, you could match by TSIG key instead of IP if that helps (by adjusting match-client).

It's worth noting that address_match_list (the type of argument for eg match-client) accepts both IP addresses and keys. Also it is, much like the views, ordered as and the first matching element decides the outcome. Putting any first renders any other elements in the list pointless.

7
  • Okay, so how do I update global_view's somehost.tld zone via nsupdate? There is nothing interesting in the logs, by the way. Nov 3, 2015 at 10:17
  • @TranslucentCloud By either changing match-client of your views or changing how the message is sent so that the update message will hit the desired view. (The latter would mean abandoning the convenience of -l.) Nov 3, 2015 at 10:34
  • @TranslucentCloud Matching on key rather than client IP is generally easier to deal with. Nov 3, 2015 at 10:35
  • Okay, am I understood it right, that I should generate a special key for this? Nov 3, 2015 at 10:43
  • @TranslucentCloud Either match based on the key you currently use implicitly by using the -l option (local-ddns.) if that doesn't conflict with your other requirements or generate and add additional keys to your configuration and specify those keys as necessary to nsupdate instead of using -l. Nov 3, 2015 at 10:48

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .