diff --git a/bin/named/bind9.xsl b/bin/named/bind9.xsl index badb3a1e9a..2c5f2eb1e0 100644 --- a/bin/named/bind9.xsl +++ b/bin/named/bind9.xsl @@ -923,6 +923,7 @@ Additional Refresh Queued Local Address Remote Address + SOA Transport Transport TSIG Key Name Duration (s) @@ -949,6 +950,7 @@ + diff --git a/bin/named/statschannel.c b/bin/named/statschannel.c index 191006ede0..36fbe9cde8 100644 --- a/bin/named/statschannel.c +++ b/bin/named/statschannel.c @@ -1461,7 +1461,7 @@ xfrin_xmlrender(dns_zone_t *zone, void *arg) { uint32_t serial; const isc_sockaddr_t *addrp = NULL; char addr_buf[ISC_SOCKADDR_FORMATSIZE]; - const dns_transport_t *transport = NULL; + dns_transport_type_t transport_type; xmlTextWriterPtr writer = arg; dns_zonestat_level_t statlevel; int xmlrc; @@ -1581,20 +1581,41 @@ xfrin_xmlrender(dns_zone_t *zone, void *arg) { } TRY0(xmlTextWriterEndElement(writer)); - TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "transport")); + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "soatransport")); if (is_running) { - transport = dns_xfrin_gettransport(xfr); - if (transport == NULL || - dns_transport_get_type(transport) == DNS_TRANSPORT_TCP) - { + transport_type = dns_xfrin_getsoatransporttype(xfr); + if (transport_type == DNS_TRANSPORT_UDP) { + TRY0(xmlTextWriterWriteString(writer, + ISC_XMLCHAR "UDP")); + } else if (transport_type == DNS_TRANSPORT_TCP) { TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "TCP")); - } else if (dns_transport_get_type(transport) == - DNS_TRANSPORT_TLS) - { + } else if (transport_type == DNS_TRANSPORT_TLS) { + TRY0(xmlTextWriterWriteString(writer, + ISC_XMLCHAR "TLS")); + } else if (transport_type == DNS_TRANSPORT_NONE) { + TRY0(xmlTextWriterWriteString(writer, + ISC_XMLCHAR "None")); + } else { + /* We don't expect any other SOA transport type. */ + TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "-")); + } + } else { + TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "-")); + } + TRY0(xmlTextWriterEndElement(writer)); + + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "transport")); + if (is_running) { + transport_type = dns_xfrin_gettransporttype(xfr); + if (transport_type == DNS_TRANSPORT_TCP) { + TRY0(xmlTextWriterWriteString(writer, + ISC_XMLCHAR "TCP")); + } else if (transport_type == DNS_TRANSPORT_TLS) { TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "TLS")); } else { + /* We don't expect any other transport type. */ TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "-")); } } else { @@ -2477,7 +2498,7 @@ xfrin_jsonrender(dns_zone_t *zone, void *arg) { json_object *xfrinobj = NULL; const isc_sockaddr_t *addrp = NULL; char addr_buf[ISC_SOCKADDR_FORMATSIZE]; - const dns_transport_t *transport = NULL; + dns_transport_type_t transport_type; dns_zonestat_level_t statlevel; dns_xfrin_t *xfr = NULL; bool is_running, is_deferred, is_pending; @@ -2582,18 +2603,39 @@ xfrin_jsonrender(dns_zone_t *zone, void *arg) { } if (is_running) { - transport = dns_xfrin_gettransport(xfr); - if (transport == NULL || - dns_transport_get_type(transport) == DNS_TRANSPORT_TCP) - { + transport_type = dns_xfrin_getsoatransporttype(xfr); + if (transport_type == DNS_TRANSPORT_UDP) { + json_object_object_add(xfrinobj, "soatransport", + json_object_new_string("UDP")); + } else if (transport_type == DNS_TRANSPORT_TCP) { + json_object_object_add(xfrinobj, "soatransport", + json_object_new_string("TCP")); + } else if (transport_type == DNS_TRANSPORT_TLS) { + json_object_object_add(xfrinobj, "soatransport", + json_object_new_string("TLS")); + } else if (transport_type == DNS_TRANSPORT_NONE) { + json_object_object_add(xfrinobj, "soatransport", + json_object_new_string("None")); + } else { + /* We don't expect any other SOA transport type. */ + json_object_object_add(xfrinobj, "soatransport", + json_object_new_string("-")); + } + } else { + json_object_object_add(xfrinobj, "soatransport", + json_object_new_string("-")); + } + + if (is_running) { + transport_type = dns_xfrin_gettransporttype(xfr); + if (transport_type == DNS_TRANSPORT_TCP) { json_object_object_add(xfrinobj, "transport", json_object_new_string("TCP")); - } else if (dns_transport_get_type(transport) == - DNS_TRANSPORT_TLS) - { + } else if (transport_type == DNS_TRANSPORT_TLS) { json_object_object_add(xfrinobj, "transport", json_object_new_string("TLS")); } else { + /* We don't expect any other transport type. */ json_object_object_add(xfrinobj, "transport", json_object_new_string("-")); } diff --git a/doc/arm/reference.rst b/doc/arm/reference.rst index 332c189bb6..29467716fa 100644 --- a/doc/arm/reference.rst +++ b/doc/arm/reference.rst @@ -7639,6 +7639,10 @@ Incoming Zone Transfers This shows the destination address used to establish the connection for the transfer. + ``SOA Transport`` (``soatransport``) + Text string. This is the transport protocol in use for the + SOA request. Possible values are: ``UDP``, ``TCP``, ``TLS``, ``None``. + ``Transport`` (``transport``) Text string. This is the transport protocol in use for the transfer. Possible values are: ``TCP``, ``TLS``. diff --git a/lib/dns/include/dns/xfrin.h b/lib/dns/include/dns/xfrin.h index 3d10bb42fe..7fa72f42ed 100644 --- a/lib/dns/include/dns/xfrin.h +++ b/lib/dns/include/dns/xfrin.h @@ -56,6 +56,7 @@ isc_result_t dns_xfrin_create(dns_zone_t *zone, dns_rdatatype_t xfrtype, const isc_sockaddr_t *primaryaddr, const isc_sockaddr_t *sourceaddr, dns_tsigkey_t *tsigkey, + dns_transport_type_t soa_transport_type, dns_transport_t *transport, isc_tlsctx_cache_t *tlsctx_cache, isc_mem_t *mctx, dns_xfrindone_t done, dns_xfrin_t **xfrp); /*%< @@ -81,6 +82,13 @@ dns_xfrin_create(dns_zone_t *zone, dns_rdatatype_t xfrtype, * *\li If 'xfrtype' is dns_rdatatype_ixfr or dns_rdatatype_soa, * the zone has a database. + * + *\li 'soa_transport_type' is DNS_TRANSPORT_NONE if 'xfrtype' + * is dns_rdatatype_soa (because in that case the SOA request + * will use the same transport as the XFR), or when there is no + * preceding SOA request. Otherwise, it should indicate the + * transport type used for the SOA request performed by the + * caller itself. */ isc_time_t @@ -160,10 +168,23 @@ dns_xfrin_getprimaryaddr(const dns_xfrin_t *xfr); *\li const pointer to the zone transfer's primary server's socket address */ -const dns_transport_t * -dns_xfrin_gettransport(const dns_xfrin_t *xfr); +dns_transport_type_t +dns_xfrin_gettransporttype(const dns_xfrin_t *xfr); /*%< - * Get the trnasport of the xfrin object. + * Get the zone transfer's trnasport type of the xfrin object. + * + * Requires: + *\li 'xfr' is a valid dns_xfrin_t. + * + * Returns: + *\li const pointer to the zone transfer's transport + * + */ + +dns_transport_type_t +dns_xfrin_getsoatransporttype(const dns_xfrin_t *xfr); +/*%< + * Get the SOA request's trnasport type of the xfrin object. * * Requires: *\li 'xfr' is a valid dns_xfrin_t. diff --git a/lib/dns/xfrin.c b/lib/dns/xfrin.c index c830533a27..7dd634eb12 100644 --- a/lib/dns/xfrin.c +++ b/lib/dns/xfrin.c @@ -164,6 +164,7 @@ struct dns_xfrin { dst_context_t *tsigctx; /*%< TSIG verification context */ unsigned int sincetsig; /*%< recvd since the last TSIG */ + dns_transport_type_t soa_transport_type; dns_transport_t *transport; dns_xfrindone_t done; @@ -206,6 +207,7 @@ xfrin_create(isc_mem_t *mctx, dns_zone_t *zone, dns_db_t *db, dns_name_t *zonename, dns_rdataclass_t rdclass, dns_rdatatype_t reqtype, const isc_sockaddr_t *primaryaddr, const isc_sockaddr_t *sourceaddr, dns_tsigkey_t *tsigkey, + dns_transport_type_t soa_transport_type, dns_transport_t *transport, isc_tlsctx_cache_t *tlsctx_cache, dns_xfrin_t **xfrp); @@ -700,6 +702,7 @@ isc_result_t dns_xfrin_create(dns_zone_t *zone, dns_rdatatype_t xfrtype, const isc_sockaddr_t *primaryaddr, const isc_sockaddr_t *sourceaddr, dns_tsigkey_t *tsigkey, + dns_transport_type_t soa_transport_type, dns_transport_t *transport, isc_tlsctx_cache_t *tlsctx_cache, isc_mem_t *mctx, dns_xfrindone_t done, dns_xfrin_t **xfrp) { dns_name_t *zonename = dns_zone_getorigin(zone); @@ -721,8 +724,8 @@ dns_xfrin_create(dns_zone_t *zone, dns_rdatatype_t xfrtype, } xfrin_create(mctx, zone, db, zonename, dns_zone_getclass(zone), xfrtype, - primaryaddr, sourceaddr, tsigkey, transport, tlsctx_cache, - &xfr); + primaryaddr, sourceaddr, tsigkey, soa_transport_type, + transport, tlsctx_cache, &xfr); if (db != NULL) { xfr->zone_had_db = true; @@ -854,11 +857,22 @@ dns_xfrin_getprimaryaddr(const dns_xfrin_t *xfr) { return (&xfr->primaryaddr); } -const dns_transport_t * -dns_xfrin_gettransport(const dns_xfrin_t *xfr) { +dns_transport_type_t +dns_xfrin_gettransporttype(const dns_xfrin_t *xfr) { REQUIRE(VALID_XFRIN(xfr)); - return (xfr->transport); + if (xfr->transport != NULL) { + return (dns_transport_get_type(xfr->transport)); + } + + return (DNS_TRANSPORT_TCP); +} + +dns_transport_type_t +dns_xfrin_getsoatransporttype(const dns_xfrin_t *xfr) { + REQUIRE(VALID_XFRIN(xfr)); + + return (xfr->soa_transport_type); } const dns_name_t * @@ -965,6 +979,7 @@ xfrin_create(isc_mem_t *mctx, dns_zone_t *zone, dns_db_t *db, dns_name_t *zonename, dns_rdataclass_t rdclass, dns_rdatatype_t reqtype, const isc_sockaddr_t *primaryaddr, const isc_sockaddr_t *sourceaddr, dns_tsigkey_t *tsigkey, + dns_transport_type_t soa_transport_type, dns_transport_t *transport, isc_tlsctx_cache_t *tlsctx_cache, dns_xfrin_t **xfrp) { dns_xfrin_t *xfr = NULL; @@ -977,6 +992,7 @@ xfrin_create(isc_mem_t *mctx, dns_zone_t *zone, dns_db_t *db, .maxrecords = dns_zone_getmaxrecords(zone), .primaryaddr = *primaryaddr, .sourceaddr = *sourceaddr, + .soa_transport_type = soa_transport_type, .firstsoa = DNS_RDATA_INIT, .edns = true, .magic = XFRIN_MAGIC, @@ -1082,6 +1098,23 @@ xfrin_start(dns_xfrin_t *xfr) { LIBDNS_XFRIN_START(xfr, xfr->info); + /* + * If the transfer is started when the 'state' is XFRST_SOAQUERY, it + * means the SOA query will be performed by xfrin. A transfer could also + * be initiated starting from the XFRST_INITIALSOA state, which means + * that the SOA query was already performed by other means (e.g. by + * zone.c:soa_query()), or that it's a transfer without a preceding + * SOA request, and 'soa_transport_type' is already correctly + * set by the creator of the xfrin. + */ + if (atomic_load(&xfr->state) == XFRST_SOAQUERY) { + /* + * The "SOA before" mode is used, where the SOA request is + * using the same transport as the XFR. + */ + xfr->soa_transport_type = dns_xfrin_gettransporttype(xfr); + } + /* Set the maximum timer */ isc_interval_set(&interval, dns_zone_getmaxxfrin(xfr->zone), 0); isc_timer_start(xfr->max_time_timer, isc_timertype_once, &interval); diff --git a/lib/dns/zone.c b/lib/dns/zone.c index 8e9c4ca5d6..1847f4ee99 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -17616,6 +17616,7 @@ got_transfer_quota(void *arg) { isc_sockaddr_t primaryaddr; isc_sockaddr_t sourceaddr; isc_time_t now; + dns_transport_type_t soa_transport_type = DNS_TRANSPORT_NONE; const char *soa_before = ""; bool loaded; isc_tlsctx_cache_t *zmgr_tlsctx_cache = NULL; @@ -17742,11 +17743,33 @@ got_transfer_quota(void *arg) { "zone transfer: %s", isc_result_totext(result)); } + + if (result == ISC_R_SUCCESS && xfrtype != dns_rdatatype_soa) { + soa_transport_type = DNS_TRANSPORT_TLS; + } } LOCK_ZONE(zone); + if (soa_transport_type == DNS_TRANSPORT_NONE && + xfrtype != dns_rdatatype_soa) + { + soa_transport_type = (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_USEVC)) + ? DNS_TRANSPORT_TCP + : DNS_TRANSPORT_UDP; + + /* Check if the peer is forced to always use TCP. */ + if (soa_transport_type != DNS_TRANSPORT_TCP && peer != NULL) { + bool usetcp; + result = dns_peer_getforcetcp(peer, &usetcp); + if (result == ISC_R_SUCCESS && usetcp) { + soa_transport_type = DNS_TRANSPORT_TCP; + } + } + } + sourceaddr = zone->sourceaddr; UNLOCK_ZONE(zone); + INSIST(isc_sockaddr_pf(&primaryaddr) == isc_sockaddr_pf(&sourceaddr)); if (zone->xfr != NULL) { @@ -17756,9 +17779,9 @@ got_transfer_quota(void *arg) { zmgr_tlsctx_attach(zone->zmgr, &zmgr_tlsctx_cache); result = dns_xfrin_create(zone, xfrtype, &primaryaddr, &sourceaddr, - zone->tsigkey, zone->transport, - zmgr_tlsctx_cache, zone->mctx, zone_xfrdone, - &zone->xfr); + zone->tsigkey, soa_transport_type, + zone->transport, zmgr_tlsctx_cache, + zone->mctx, zone_xfrdone, &zone->xfr); isc_tlsctx_cache_detach(&zmgr_tlsctx_cache);