bind: "nsupdate -l" failed with status "update failed: REFUSED"
Solution 1
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.
Solution 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.
Neurotransmitter
Updated on September 18, 2022Comments
-
Neurotransmitter almost 2 years
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 viansupdate
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 userbind
readable, but when I perform the add command viansupdate -l
(as root), I always get theupdate 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?
-
Håkan Lindqvist over 8 yearsDoes your update hit the correct view? I noted that
match-clients
starts withany
, 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. -
Neurotransmitter over 8 yearsI've commented the
match-clients
string in theglobal_view
view and added one more view (localhost_view
) to the question for your reference. The error persists. -
Håkan Lindqvist over 8 yearsCould anything ever hit the second view? (Based on what I noted about the first view)
-
Neurotransmitter over 8 yearsThe second (
localhost_view
) view is hit only bylocalhost_acl
IPs which are belong to the127.0.0.0/8
subnet. And they actually hit it. -
Håkan Lindqvist over 8 yearsAre the views actually in this order? Or the other way around?
-
Neurotransmitter over 8 yearsOrder have meaning? Okay, I'll paste my whole
named.conf.local
now. Wait a minute. -
Håkan Lindqvist over 8 yearsYes, for any incoming message (query, update, ...) the first view that matches is the view it will hit. (And for address match lists, the first element that matches decides the result, hence why
any
at the beginning is a bad idea.) -
Neurotransmitter over 8 yearsHere you go, I updated the question. Take a look.
-
-
Neurotransmitter over 8 yearsOkay, so how do I update
global_view
'ssomehost.tld
zone viansupdate
? There is nothing interesting in the logs, by the way. -
Håkan Lindqvist over 8 years@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
.) -
Håkan Lindqvist over 8 years@TranslucentCloud Matching on key rather than client IP is generally easier to deal with.
-
Neurotransmitter over 8 yearsOkay, am I understood it right, that I should generate a special key for this?
-
Håkan Lindqvist over 8 years@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 tonsupdate
instead of using-l
. -
Neurotransmitter over 8 yearsAs far as I understood, I need to provide the
allow-update { key "somekey"; };
to my zone definition, however this option is mutually exclusive withupdate-policy local;
option I have got there. -
Håkan Lindqvist over 8 years@TranslucentCloud You do not need both. Use whichever best matches your requirements.
update-policy
is more flexible. ftp.isc.org/isc/bind9/cur/9.10/doc/arm/…