Content-Disposition: inline Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: binary Content-Length: 6980 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.