query->lookup->rdtype == dns_rdatatype_axfr;
if (xfr &&
isc_nm_socket_type(query->handle) == isc_nm_streamdnssocket &&
- query->lookup->tls_mode && !isc_nm_xfr_allowed(query->handle))
+ query->lookup->tls_mode)
{
- dighost_error("zone transfers over the "
- "established TLS connection are not allowed");
- dighost_error("as the "
- "connection does not meet the requirements "
- "enforced by the RFC 9103");
- isc_refcount_decrement0(&recvcount);
- isc_nmhandle_detach(&query->readhandle);
- cancel_lookup(l);
- lookup_detach(&l);
- clear_current_lookup();
- return;
+ isc_result_t result = isc_nm_xfr_checkperm(query->handle);
+ if (result != ISC_R_SUCCESS) {
+ dighost_error("zone transfers over the established TLS "
+ "connection are not allowed: %s",
+ isc_result_totext(result));
+ isc_refcount_decrement0(&recvcount);
+ isc_nmhandle_detach(&query->readhandle);
+ cancel_lookup(l);
+ lookup_detach(&l);
+ clear_current_lookup();
+ return;
+ }
}
query_attach(query, &readquery);
CHECK(result);
- if (!isc_nm_xfr_allowed(handle)) {
- /* set the error code so that XFER will fail */
- result = ISC_R_NOPERM;
- goto failure;
- }
+ CHECK(isc_nm_xfr_checkperm(handle));
zmgr = dns_zone_getmgr(xfr->zone);
if (zmgr != NULL) {
* \li 'handle' is a valid netmgr handle object.
*/
-bool
-isc_nm_xfr_allowed(isc_nmhandle_t *handle);
+isc_result_t
+isc_nm_xfr_checkperm(isc_nmhandle_t *handle);
/*%<
- * Check if it is possible to do a zone transfer over the given handle.
+ * Check if it is permitted to do a zone transfer over the given handle.
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS Success, permission check passed successfully
+ * \li #ISC_R_DOTALPNERROR No permission because of ALPN tag mismatch
+ * \li #ISC_R_NOPERM No permission because of other restrictions
+ * \li any other result indicates failure (i.e. no permission)
*
* Requires:
* \li 'handle' is a valid connection handle.
ISC_R_TLSERROR, /*%< TLS error */
ISC_R_TLSBADPEERCERT, /*%< TLS peer certificate verification failed */
ISC_R_HTTP2ALPNERROR, /*%< ALPN for HTTP/2 failed */
+ ISC_R_DOTALPNERROR, /*%< ALPN for DoT failed */
DNS_R_LABELTOOLONG = 1 << 16,
DNS_R_BADESCAPE,
void
isc__nm_streamdns_set_tlsctx(isc_nmsocket_t *listener, isc_tlsctx_t *tlsctx);
-bool
-isc__nm_streamdns_xfr_allowed(isc_nmsocket_t *sock);
+isc_result_t
+isc__nm_streamdns_xfr_checkperm(isc_nmsocket_t *sock);
void
isc__nmsocket_streamdns_reset(isc_nmsocket_t *sock);
}
}
-bool
-isc_nm_xfr_allowed(isc_nmhandle_t *handle) {
+isc_result_t
+isc_nm_xfr_checkperm(isc_nmhandle_t *handle) {
isc_nmsocket_t *sock = NULL;
+ isc_result_t result = ISC_R_NOPERM;
REQUIRE(VALID_NMHANDLE(handle));
REQUIRE(VALID_NMSOCK(handle->sock));
switch (sock->type) {
case isc_nm_streamdnssocket:
- return (isc__nm_streamdns_xfr_allowed(sock));
+ result = isc__nm_streamdns_xfr_checkperm(sock);
+ break;
default:
- return (false);
+ break;
}
- UNREACHABLE();
-
- return (false);
+ return (result);
}
bool
}
}
-bool
-isc__nm_streamdns_xfr_allowed(isc_nmsocket_t *sock) {
+isc_result_t
+isc__nm_streamdns_xfr_checkperm(isc_nmsocket_t *sock) {
+ isc_result_t result = ISC_R_NOPERM;
+
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock->type == isc_nm_streamdnssocket);
- if (sock->outerhandle == NULL) {
- return (false);
- } else if (!isc_nm_has_encryption(sock->outerhandle)) {
- return (true);
+ if (sock->outerhandle != NULL) {
+ if (isc_nm_has_encryption(sock->outerhandle) &&
+ !sock->streamdns.dot_alpn_negotiated)
+ {
+ result = ISC_R_DOTALPNERROR;
+ } else {
+ result = ISC_R_SUCCESS;
+ }
}
- return (sock->streamdns.dot_alpn_negotiated);
+ return (result);
}
void
[ISC_R_TLSERROR] = "TLS error",
[ISC_R_TLSBADPEERCERT] = "TLS peer certificate verification failed",
[ISC_R_HTTP2ALPNERROR] = "ALPN for HTTP/2 failed",
+ [ISC_R_DOTALPNERROR] = "ALPN for DoT failed",
[DNS_R_LABELTOOLONG] = "label too long",
[DNS_R_BADESCAPE] = "bad escape",
[ISC_R_TLSERROR] = "ISC_R_TLSERROR",
[ISC_R_TLSBADPEERCERT] = "ISC_R_TLSBADPEERCERT",
[ISC_R_HTTP2ALPNERROR] = "ISC_R_HTTP2ALPNERROR",
+ [ISC_R_DOTALPNERROR] = "ISC_R_DOTALPNERROR",
[DNS_R_LABELTOOLONG] = "DNS_R_LABELTOOLONG",
[DNS_R_BADESCAPE] = "DNS_R_BADESCAPE",
[DNS_R_EMPTYLABEL] = "DNS_R_EMPTYLABEL",
return;
}
if (isc_nm_socket_type(handle) ==
- isc_nm_streamdnssocket &&
- isc_nm_has_encryption(handle) &&
- !isc_nm_xfr_allowed(handle))
+ isc_nm_streamdnssocket)
{
/*
* Currently this code is here for DoT, which
* transfers compared to other stream
* protocols. See RFC 9103 for details.
*/
- query_error(client, DNS_R_REFUSED, __LINE__);
- return;
+ switch (isc_nm_xfr_checkperm(handle)) {
+ case ISC_R_SUCCESS:
+ break;
+ case ISC_R_DOTALPNERROR:
+ query_error(client, DNS_R_NOALPN,
+ __LINE__);
+ return;
+ default:
+ query_error(client, DNS_R_REFUSED,
+ __LINE__);
+ return;
+ }
}
ns_xfr_start(client, rdataset->type);
return;