]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Add the "Refresh SOA" state for the incoming zone transfers
authorAram Sargsyan <aram@isc.org>
Fri, 15 Sep 2023 08:57:21 +0000 (08:57 +0000)
committerAram Sargsyan <aram@isc.org>
Fri, 22 Sep 2023 11:05:52 +0000 (11:05 +0000)
With adding this state to the statistics channel, it can now show
the zone transfer in this state instead of as "Pending" when the
zone.c module is performing a refresh SOA request, before actually
starting the transfer process. This will help to understand
whether the process is waiting because of the rate limiter (i.e.
"Pending"), or the rate limiter is passed and it is now waiting for
the refresh SOA query to complete or time out.

bin/named/statschannel.c
doc/arm/reference.rst
lib/dns/include/dns/zone.h
lib/dns/zone.c

index 36fbe9cde81cff04edabd05346c89001fd00b9c3..fdf39dd8492a58a76651da742680beeff36d4dab 100644 (file)
@@ -1466,7 +1466,7 @@ xfrin_xmlrender(dns_zone_t *zone, void *arg) {
        dns_zonestat_level_t statlevel;
        int xmlrc;
        dns_xfrin_t *xfr = NULL;
-       bool is_running, is_deferred, is_pending;
+       bool is_running, is_deferred, is_presoa, is_pending;
        bool needs_refresh;
        bool is_first_data_received, is_ixfr;
        unsigned int nmsg = 0;
@@ -1479,13 +1479,15 @@ xfrin_xmlrender(dns_zone_t *zone, void *arg) {
        }
 
        result = dns_zone_getxfr(zone, &xfr, &is_running, &is_deferred,
-                                &is_pending, &needs_refresh);
+                                &is_presoa, &is_pending, &needs_refresh);
        if (result != ISC_R_SUCCESS) {
                result = ISC_R_SUCCESS;
                goto cleanup;
        }
 
-       if (!is_running && !is_deferred && !is_pending && !needs_refresh) {
+       if (!is_running && !is_deferred && !is_presoa && !is_pending &&
+           !needs_refresh)
+       {
                /* No ongoing/queued transfer. */
                goto cleanup;
        }
@@ -1546,6 +1548,9 @@ xfrin_xmlrender(dns_zone_t *zone, void *arg) {
                TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR xfr_state));
        } else if (is_deferred) {
                TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "Deferred"));
+       } else if (is_presoa) {
+               TRY0(xmlTextWriterWriteString(writer,
+                                             ISC_XMLCHAR "Refresh SOA"));
        } else if (is_pending) {
                TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR "Pending"));
        } else if (needs_refresh) {
@@ -1582,8 +1587,12 @@ xfrin_xmlrender(dns_zone_t *zone, void *arg) {
        TRY0(xmlTextWriterEndElement(writer));
 
        TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "soatransport"));
-       if (is_running) {
-               transport_type = dns_xfrin_getsoatransporttype(xfr);
+       if (is_running || is_presoa) {
+               if (is_running) {
+                       transport_type = dns_xfrin_getsoatransporttype(xfr);
+               } else {
+                       transport_type = dns_zone_getrequesttransporttype(zone);
+               }
                if (transport_type == DNS_TRANSPORT_UDP) {
                        TRY0(xmlTextWriterWriteString(writer,
                                                      ISC_XMLCHAR "UDP"));
@@ -2501,7 +2510,7 @@ xfrin_jsonrender(dns_zone_t *zone, void *arg) {
        dns_transport_type_t transport_type;
        dns_zonestat_level_t statlevel;
        dns_xfrin_t *xfr = NULL;
-       bool is_running, is_deferred, is_pending;
+       bool is_running, is_deferred, is_presoa, is_pending;
        bool needs_refresh;
        bool is_first_data_received, is_ixfr;
        unsigned int nmsg = 0;
@@ -2534,13 +2543,15 @@ xfrin_jsonrender(dns_zone_t *zone, void *arg) {
        }
 
        result = dns_zone_getxfr(zone, &xfr, &is_running, &is_deferred,
-                                &is_pending, &needs_refresh);
+                                &is_presoa, &is_pending, &needs_refresh);
        if (result != ISC_R_SUCCESS) {
                result = ISC_R_SUCCESS;
                goto cleanup;
        }
 
-       if (!is_running && !is_deferred && !is_pending && !needs_refresh) {
+       if (!is_running && !is_deferred && !is_presoa && !is_pending &&
+           !needs_refresh)
+       {
                /* No ongoing/queued transfer. */
                goto cleanup;
        }
@@ -2568,6 +2579,9 @@ xfrin_jsonrender(dns_zone_t *zone, void *arg) {
        } else if (is_deferred) {
                json_object_object_add(xfrinobj, "state",
                                       json_object_new_string("Deferred"));
+       } else if (is_presoa) {
+               json_object_object_add(xfrinobj, "state",
+                                      json_object_new_string("Refresh SOA"));
        } else if (is_pending) {
                json_object_object_add(xfrinobj, "state",
                                       json_object_new_string("Pending"));
@@ -2602,8 +2616,13 @@ xfrin_jsonrender(dns_zone_t *zone, void *arg) {
                                       json_object_new_string("-"));
        }
 
-       if (is_running) {
-               transport_type = dns_xfrin_getsoatransporttype(xfr);
+       if (is_running || is_presoa) {
+               if (is_running) {
+                       transport_type = dns_xfrin_getsoatransporttype(xfr);
+               } else {
+                       transport_type = dns_zone_getrequesttransporttype(zone);
+               }
+
                if (transport_type == DNS_TRANSPORT_UDP) {
                        json_object_object_add(xfrinobj, "soatransport",
                                               json_object_new_string("UDP"));
index 29467716faddcb9543eead47dbabb46eacb3b2e3..ea4ae03c77ac93a30f887d5941bf04e0bf919903 100644 (file)
@@ -7580,9 +7580,17 @@ Incoming Zone Transfers
             hasn't started yet.
 
          ``Pending``
-            The zone is flagged for a refresh, but the process is
-            in waiting state because of rate-limiting, see
-            :any:`serial-query-rate`.
+            The zone is flagged for a refresh, but the process is currently
+            in the queue and will start shortly, or is in a waiting state
+            because of rate-limiting, see :any:`serial-query-rate`.
+
+         ``Refresh SOA``
+            Sending a refresh SOA query to get the zone serial number, then
+            initiate a zone transfer, if necessary. If this step is successful,
+            the ``SOA Query`` and ``Got SOA`` states will be skipped.
+            Otherwise, the zone transfer procedure can still be initiated,
+            and the SOA request will be attempted using the same transport as
+            the zone transfer.
 
          ``Deferred``
             The zone is going to be refreshed, but the process was
@@ -7641,7 +7649,14 @@ Incoming Zone Transfers
 
    ``SOA Transport`` (``soatransport``)
       Text string. This is the transport protocol in use for the
-      SOA request. Possible values are: ``UDP``, ``TCP``, ``TLS``, ``None``.
+      SOA query.  Note, that this value can potentially change during the
+      process. For example, when the transfer is in the ``Refresh SOA``
+      state, the ``SOA Transport`` of the ongoing query can be shown as ``UDP``.
+      If that query fails or times out, it then can be retried using another
+      transport, or the transfer process can be initiated in "SOA before" mode,
+      where the SOA query will be attempted using the same transport as the zone
+      transfer. See the description of the ``State`` field for more information.
+      Possible values are: ``UDP``, ``TCP``, ``TLS``, ``None``.
 
    ``Transport`` (``transport``)
       Text string. This is the transport protocol in use for the
index 233793cc2448c700f04fc75b2b3b21ac143b0fec..c2ce8a7a5e526ff9a00744809e3fbdec63867762 100644 (file)
@@ -1479,6 +1479,18 @@ dns_zone_getsigresigninginterval(dns_zone_t *zone);
  * \li 'zone' to be a valid zone.
  */
 
+dns_transport_type_t
+dns_zone_getrequesttransporttype(dns_zone_t *zone);
+/*%<
+ * Get the transport type used for the SOA query to the current primary server
+ * before an ongoing incoming zone transfer is lanunched. When the transfer is
+ * already running, this information should be retrieved from the xfrin object
+ * instead, using the dns_xfrin_gettransporttype() function.
+ *
+ * Requires:
+ * \li 'zone' to be a valid zone.
+ */
+
 void
 dns_zone_setnotifytype(dns_zone_t *zone, dns_notifytype_t notifytype);
 /*%<
@@ -1792,7 +1804,8 @@ dns_zonemgr_getcount(dns_zonemgr_t *zmgr, int state);
 
 isc_result_t
 dns_zone_getxfr(dns_zone_t *zone, dns_xfrin_t **xfrp, bool *is_running,
-               bool *is_deferred, bool *is_pending, bool *needs_refresh);
+               bool *is_deferred, bool *is_presoa, bool *is_pending,
+               bool *needs_refresh);
 /*%<
  *     Returns the xfrin associated with the zone (if any) with the current
  *     transfer states (as booleans). When no longer needed, the returned xfrin
@@ -1803,6 +1816,7 @@ dns_zone_getxfr(dns_zone_t *zone, dns_xfrin_t **xfrp, bool *is_running,
  *\li  'xfrp' to be non NULL and '*xfrp' to be NULL.
  *\li  'is_running' to be non NULL.
  *\li  'is_deferred' to be non NULL.
+ *\li  'is_presoa' to be non NULL.
  *\li  'is_pending' to be non NULL.
  *\li  'needs_refresh' to be non NULL.
  *
index 1847f4ee990f316667856b4fc1614d9c908bae8a..fd4ab0546a069116d2f40ac059387637dd197e39 100644 (file)
@@ -17599,6 +17599,61 @@ queue_xfrin(dns_zone_t *zone) {
        }
 }
 
+/*
+ * Get the transport type used for the SOA query to the current primary server
+ * before an ongoing incoming zone transfer.
+ *
+ * Requires:
+ *     The zone is locked by the caller.
+ */
+static dns_transport_type_t
+get_request_transport_type(dns_zone_t *zone) {
+       dns_transport_type_t transport_type = DNS_TRANSPORT_NONE;
+
+       if (zone->transport != NULL) {
+               transport_type = dns_transport_get_type(zone->transport);
+       } else {
+               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 (transport_type != DNS_TRANSPORT_TCP) {
+                       isc_result_t result;
+                       isc_sockaddr_t primaryaddr;
+                       isc_netaddr_t primaryip;
+                       dns_peer_t *peer = NULL;
+
+                       primaryaddr = dns_remote_curraddr(&zone->primaries);
+                       isc_netaddr_fromsockaddr(&primaryip, &primaryaddr);
+                       result = dns_peerlist_peerbyaddr(zone->view->peers,
+                                                        &primaryip, &peer);
+                       if (result == ISC_R_SUCCESS && peer != NULL) {
+                               bool usetcp;
+                               result = dns_peer_getforcetcp(peer, &usetcp);
+                               if (result == ISC_R_SUCCESS && usetcp) {
+                                       transport_type = DNS_TRANSPORT_TCP;
+                               }
+                       }
+               }
+       }
+
+       return (transport_type);
+}
+
+dns_transport_type_t
+dns_zone_getrequesttransporttype(dns_zone_t *zone) {
+       dns_transport_type_t transport_type;
+
+       REQUIRE(DNS_ZONE_VALID(zone));
+
+       LOCK_ZONE(zone);
+       transport_type = get_request_transport_type(zone);
+       UNLOCK_ZONE(zone);
+
+       return (transport_type);
+}
+
 /*
  * This event callback is called when a zone has received
  * any necessary zone transfer quota.  This is the time
@@ -17743,30 +17798,19 @@ 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;
-                       }
-               }
+       if (xfrtype != dns_rdatatype_soa) {
+               /*
+                * If 'xfrtype' is dns_rdatatype_soa, then the SOA query will be
+                * performed by xfrin, otherwise, the SOA request performed by
+                * soa_query() was successful and we should inform the xfrin
+                * about the transport type used for that query, so that the
+                * information can be presented in the statistics channel.
+                */
+               soa_transport_type = get_request_transport_type(zone);
        }
-
        sourceaddr = zone->sourceaddr;
        UNLOCK_ZONE(zone);
 
@@ -19189,7 +19233,8 @@ dns_zonemgr_getcount(dns_zonemgr_t *zmgr, int state) {
 
 isc_result_t
 dns_zone_getxfr(dns_zone_t *zone, dns_xfrin_t **xfrp, bool *is_running,
-               bool *is_deferred, bool *is_pending, bool *needs_refresh) {
+               bool *is_deferred, bool *is_presoa, bool *is_pending,
+               bool *needs_refresh) {
        REQUIRE(DNS_ZONE_VALID(zone));
        REQUIRE(xfrp != NULL && *xfrp == NULL);
 
@@ -19197,6 +19242,12 @@ dns_zone_getxfr(dns_zone_t *zone, dns_xfrin_t **xfrp, bool *is_running,
                return (ISC_R_NOTFOUND);
        }
 
+       /* Reset. */
+       *is_running = false;
+       *is_deferred = false;
+       *is_presoa = false;
+       *is_pending = false;
+
        RWLOCK(&zone->zmgr->rwlock, isc_rwlocktype_read);
        LOCK_ZONE(zone);
        if (zone->xfr != NULL) {
@@ -19204,20 +19255,14 @@ dns_zone_getxfr(dns_zone_t *zone, dns_xfrin_t **xfrp, bool *is_running,
        }
        if (zone->statelist == &zone->zmgr->xfrin_in_progress) {
                *is_running = true;
-               *is_deferred = false;
-               *is_pending = false;
        } else if (zone->statelist == &zone->zmgr->waiting_for_xfrin) {
-               *is_running = false;
                *is_deferred = true;
-               *is_pending = false;
        } else if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_REFRESH)) {
-               *is_running = false;
-               *is_deferred = false;
-               *is_pending = true;
-       } else {
-               *is_running = false;
-               *is_deferred = false;
-               *is_pending = false;
+               if (zone->request != NULL) {
+                       *is_presoa = true;
+               } else {
+                       *is_pending = true;
+               }
        }
        *needs_refresh = DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDREFRESH);
        UNLOCK_ZONE(zone);