Subject: | nsupdate: master address failover works incorrectly when GSSAPI is used |
When GSSAPI is used and TKEY retrieval fails for a given master address,
nsupdate resends the TKEY query to the next master address, if
available. However, recvgss() uses sendrequest() instead of
send_gssrequest() for sending the retried TKEY query to the next master
address, which causes recvsoa() to be called instead of recvgss() when
the retried TKEY query is completed.
AFAICT, this bug has been present in the code ever since GSS-TSIG was
first implemented in 289ae548d5.
The issue is pretty obscure, here is the simplest (sic!) environment in
which I was able to trigger it:
- a dual-stacked host,
- a local named instance running with the following configuration:
----------------------------------------------------------------
options {
listen-on { 127.0.0.1; };
listen-on-v6 { };
tkey-gssapi-keytab "keytab";
};
zone "example." {
type master;
file "example.db";
notify no;
update-policy {
grant user@REALM zonesub ANY;
};
};
----------------------------------------------------------------
- example.db contains:
----------------------------------------------------------------
$TTL 300 ; 5 minutes
example IN SOA localhost. michal.isc.org. (
1 ; serial
86400 ; refresh (1 day)
3600 ; retry (1 hour)
3600000 ; expire (5 weeks 6 days 16 hours)
300 ; minimum (5 minutes)
)
NS ns1.example.
NS ns2.example.
$ORIGIN example.
ns1 A 127.0.0.1
ns2 A 127.0.0.1
----------------------------------------------------------------
- nsupdate.txt contains:
----------------------------------------------------------------
update add ns3.example. 300 A 127.0.0.1
send
----------------------------------------------------------------
- /etc/resolv.conf contains "nameserver 127.0.0.1".
Kerberos setup is irrelevant, as long as it is working properly.
When run in the above environment, "nsupdate -g < nsupdate.txt" will
look for the master server to send UPDATE messages to by issuing a SOA
query to the resolver configured in /etc/resolv.conf (i.e. 127.0.0.1)
and checking the MNAME field in the response. As the MNAME is set to
"localhost.", nsupdate will then grab a list of master server addresses
using bind9_getaddresses(). Due to the host being dual-stacked,
"localhost" will be resolved to a list of two addresses: ::1 and
127.0.0.1. As the local named instance does not listen on ::1,
recvgss() will fail over to the next master address, i.e. 127.0.0.1.
Here is a debug log generated using nsupdate from current master:
--------------------------------------------------------------------
$ nsupdate -g -D < nsupdate.txt
setup_system()
reset_system()
user_interaction()
do_next_command()
evaluate_update()
update_addordelete()
do_next_command()
start_update()
recvsoa()
About to create rcvmsg
show_message()
Reply from SOA query:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 61922
;; flags: qr aa rd ra; QUESTION: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0
;; QUESTION SECTION:
;ns3.example. IN SOA
;; AUTHORITY SECTION:
example. 0 IN SOA localhost. michal.isc.org. 1 86400 3600 3600000 300
Found zone name: example
The master is: localhost
start_gssrequest
Found realm from ticket: REALM
send_gssrequest
show_message()
Outgoing update query:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 58268
;; flags:; QUESTION: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
;; QUESTION SECTION:
;519555431.sig-localhost. ANY TKEY
;; ADDITIONAL SECTION:
519555431.sig-localhost. 0 ANY TKEY gss-tsig. 1497444295 1497444295 3 NOERROR 647 YIICgwYGKwYBBQUCoIICdzCCAnOgDTALBgkqhkiG9xIBAgKiggJgBIIC XGCCAlgGCSqGSIb3EgECAgEAboICRzCCAkOgAwIBBaEDAgEOogcDBQAg AAAAo4IBV2GCAVMwggFPoAMCAQWhDxsNSFEuS0VNUE5JVS5QTKIbMBmg AwIBAaESMBAbA0ROUxsJbG9jYWxob3N0o4IBGDCCARSgAwIBEqEDAgEC ooIBBgSCAQJdNb6tzrm3W/YubKnziJWlzVG6YcBRZh2vRgxa+fOItHVR YlvanW+KoWmpbp4UmEK/6RybBEZzfZ2Guwz2MilFJD0XtdamDvnT1z+j Qn6jGwtS4q3M+raoIlcu3DPecCqgdzv+bRPaTQMpUmp5RILD8Y+6qa18 9j7TZiSW2TJTFSdOSIfLNRbfQ7l5XiPzTx9Wsc7y9cUegStpWa/DnysK r9MhjNuuUfA69ZZB57ODYoMmD6gL+N9GepqzJPYuSeb7XqJCBJtnyG6V UXDje4G+6w9JEIh/i8DSHFBPIfTnRRJXcBwSpR5AA6w8PwynyLpBFY1+ MbvbMhMgG1DJqZcc9GqkgdIwgc+gAwIBEqKBxwSBxPlrNBoqYvw4xFx3 DvqWViKA1/lfBqQ9odRb4xVN5c0X7hM3JTE6lUsRr76KZ1arzuyNLeF/ 4TxtSGKPCBz8h86ziV4hY1bCHQ0s7hsc/IjwYSIFikh9adFH/vcZJ5Eh vyB6Q2eFu2yEW3YIcDx+nppuPZjwIqCabZ85KDqRbB1ryvFzamoBlpHr LhbFAxh5qhPJWwz9EzMq9E5mRm+EYzmHYNFeQ4BoHrY+kM8mFNkmzIYy 6Qzb9Tyh+vbptvdtSEwyV1I= 0
Out of recvsoa
recvgss()
; Communication with ::1#53 failed: operation canceled
recvgss: trying next server
Destroying request [0x7f2526fef010]
recvsoa()
About to create rcvmsg
show_message()
Reply from SOA query:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 39068
;; flags: qr ra; QUESTION: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;519555431.sig-localhost. ANY TKEY
;; ANSWER SECTION:
519555431.sig-localhost. 0 ANY TKEY gss-tsig. 1497444295 1497447895 3 NOERROR 186 oYG3MIG0oAMKAQChCwYJKoZIhvcSAQICooGfBIGcYIGZBgkqhkiG9xIB AgICAG+BiTCBhqADAgEFoQMCAQ+iejB4oAMCARKicQRvJv80Y9UPwyJd MSxmo/yIgR9LgpY+BjqvuW2yPqc0hm+qxjdpdPFZVUVE7Xl43flI4VM6 vwSvD9Gi3S4x5UXAI2LOQl60p9CzQnrsMP8+NLEblNSRSSxtIsT6b8uK EjZ3OxCNyqdIva95wFl2l6AV 0
Out of recvsoa
recvsoa()
About to create rcvmsg
show_message()
Reply from SOA query:
;; ->>HEADER<<- opcode: QUERY, status: FORMERR, id: 54329
;; flags: qr ra; QUESTION: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;sig-localhost. ANY TKEY
response to SOA query was unsuccessful
--------------------------------------------------------------------
A PCAP captured during the above nsupdate session is also attached.
What happens here is that recvgss() resends the TKEY query to 127.0.0.1
using sendrequest(), which causes recvsoa() to be called when the resent
TKEY query is answered. recvsoa() is understandably baffled as it is
unable to find a SOA RR in either the ANSWER section or the AUTHORITY
section of the received answer, which causes it to evaluate the code
beneath the "droplabel" label, which in turn causes the TKEY query to be
resent once again, this time with one label cut off, soliciting a
FORMERR response.
Subject: | nsupdate-master-failover-error.pcap |
Message body not shown because it is not plain text.