From 8e2273afceeda02bcc301494880600bc9984bf95 Mon Sep 17 00:00:00 2001 From: Aram Sargsyan Date: Wed, 23 Aug 2023 10:46:44 +0000 Subject: [PATCH] Expose the SOA query transport type used before/during XFR Add a new field in the incoming zone transfers section of the statistics channel to show the transport used for the SOA request. When the transfer is started beginning from the XFRST_SOAQUERY state, it means that the SOA query will be performed by xfrin itself, using the same transport. Otherwise, it means that the SOA query was already performed by other means (e.g. by zone.c:soa_query()), and, in that case, we use the SOA query transport type information passed by the 'soa_transport_type' argument, when the xfrin object was created. --- bin/named/bind9.xsl | 2 + bin/named/statschannel.c | 76 ++++++++++++++++++++++++++++--------- doc/arm/reference.rst | 4 ++ lib/dns/include/dns/xfrin.h | 27 +++++++++++-- lib/dns/xfrin.c | 43 ++++++++++++++++++--- lib/dns/zone.c | 29 ++++++++++++-- 6 files changed, 153 insertions(+), 28 deletions(-) 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);