1999-08-20 05:35:16 +00:00
|
|
|
/*
|
2016-05-26 12:36:17 -07:00
|
|
|
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
1999-08-20 05:35:16 +00:00
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: MPL-2.0
|
2021-06-03 08:37:05 +02:00
|
|
|
*
|
1999-08-20 05:35:16 +00:00
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
2018-02-23 09:53:12 +01:00
|
|
|
*
|
1999-08-20 05:35:16 +00:00
|
|
|
* See the COPYRIGHT file distributed with this work for additional
|
|
|
|
* information regarding copyright ownership.
|
|
|
|
*/
|
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*! \file */
|
1999-08-20 05:35:16 +00:00
|
|
|
|
2018-03-28 14:56:40 +02:00
|
|
|
#include <inttypes.h>
|
2018-04-17 08:29:14 -07:00
|
|
|
#include <stdbool.h>
|
2018-03-28 14:56:40 +02:00
|
|
|
|
2024-06-11 10:57:15 +00:00
|
|
|
#include <isc/async.h>
|
2023-07-06 14:00:48 +10:00
|
|
|
#include <isc/atomic.h>
|
2024-08-14 13:25:50 +02:00
|
|
|
#include <isc/log.h>
|
1999-08-20 05:35:16 +00:00
|
|
|
#include <isc/mem.h>
|
2000-10-16 04:26:08 +00:00
|
|
|
#include <isc/random.h>
|
2021-10-04 17:14:53 +02:00
|
|
|
#include <isc/result.h>
|
2022-04-11 15:53:34 +01:00
|
|
|
#include <isc/string.h>
|
2000-02-25 00:52:11 +00:00
|
|
|
#include <isc/util.h>
|
2023-10-13 14:41:22 +02:00
|
|
|
#include <isc/work.h>
|
1999-08-20 05:35:16 +00:00
|
|
|
|
2012-06-20 14:13:12 -05:00
|
|
|
#include <dns/callbacks.h>
|
2016-05-26 21:23:19 +02:00
|
|
|
#include <dns/catz.h>
|
1999-10-29 22:42:44 +00:00
|
|
|
#include <dns/db.h>
|
2000-12-09 02:17:12 +00:00
|
|
|
#include <dns/diff.h>
|
2023-02-21 20:14:30 -08:00
|
|
|
#include <dns/dispatch.h>
|
1999-10-29 22:42:44 +00:00
|
|
|
#include <dns/journal.h>
|
|
|
|
#include <dns/message.h>
|
2023-06-29 17:25:15 +10:00
|
|
|
#include <dns/peer.h>
|
2000-12-30 13:03:48 +00:00
|
|
|
#include <dns/rdataclass.h>
|
1999-08-20 05:35:16 +00:00
|
|
|
#include <dns/rdatalist.h>
|
|
|
|
#include <dns/rdataset.h>
|
1999-10-29 22:42:44 +00:00
|
|
|
#include <dns/result.h>
|
2001-05-31 10:38:01 +00:00
|
|
|
#include <dns/soa.h>
|
2023-01-31 10:14:21 +01:00
|
|
|
#include <dns/trace.h>
|
2021-01-14 12:51:25 +01:00
|
|
|
#include <dns/transport.h>
|
1999-09-10 15:01:04 +00:00
|
|
|
#include <dns/tsig.h>
|
2025-02-18 08:34:41 +00:00
|
|
|
#include <dns/unreachcache.h>
|
1999-10-29 22:42:44 +00:00
|
|
|
#include <dns/view.h>
|
1999-10-29 02:12:01 +00:00
|
|
|
#include <dns/xfrin.h>
|
1999-10-14 01:37:00 +00:00
|
|
|
#include <dns/zone.h>
|
1999-08-20 05:35:16 +00:00
|
|
|
|
2000-06-02 18:59:33 +00:00
|
|
|
#include <dst/dst.h>
|
|
|
|
|
2023-01-31 10:14:21 +01:00
|
|
|
#include "probes.h"
|
|
|
|
|
1999-08-20 05:35:16 +00:00
|
|
|
/*
|
|
|
|
* Incoming AXFR and IXFR.
|
|
|
|
*/
|
|
|
|
|
2023-10-12 17:44:51 +02:00
|
|
|
#define CHECK(op) \
|
|
|
|
{ \
|
|
|
|
result = (op); \
|
|
|
|
if (result != ISC_R_SUCCESS) { \
|
|
|
|
goto failure; \
|
|
|
|
} \
|
|
|
|
}
|
1999-08-20 05:35:16 +00:00
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*%
|
1999-08-20 05:35:16 +00:00
|
|
|
* The states of the *XFR state machine. We handle both IXFR and AXFR
|
2024-08-14 13:25:50 +02:00
|
|
|
* with a single integrated state machine because they cannot be
|
|
|
|
* distinguished immediately - an AXFR response to an IXFR request can
|
|
|
|
* only be detected when the first two (2) response RRs have already
|
|
|
|
* been received.
|
1999-08-20 05:35:16 +00:00
|
|
|
*/
|
|
|
|
typedef enum {
|
2006-07-19 00:53:42 +00:00
|
|
|
XFRST_SOAQUERY,
|
|
|
|
XFRST_GOTSOA,
|
2023-09-19 09:35:20 +00:00
|
|
|
XFRST_ZONEXFRREQUEST,
|
1999-08-20 05:35:16 +00:00
|
|
|
XFRST_FIRSTDATA,
|
|
|
|
XFRST_IXFR_DELSOA,
|
|
|
|
XFRST_IXFR_DEL,
|
|
|
|
XFRST_IXFR_ADDSOA,
|
|
|
|
XFRST_IXFR_ADD,
|
2011-02-19 01:24:46 +00:00
|
|
|
XFRST_IXFR_END,
|
1999-08-20 05:35:16 +00:00
|
|
|
XFRST_AXFR,
|
2011-02-19 01:24:46 +00:00
|
|
|
XFRST_AXFR_END
|
1999-08-20 05:35:16 +00:00
|
|
|
} xfrin_state_t;
|
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*%
|
1999-08-20 05:35:16 +00:00
|
|
|
* Incoming zone transfer context.
|
|
|
|
*/
|
|
|
|
|
2023-02-23 10:29:33 -08:00
|
|
|
struct dns_xfrin {
|
2000-03-29 05:03:07 +00:00
|
|
|
unsigned int magic;
|
1999-08-20 05:35:16 +00:00
|
|
|
isc_mem_t *mctx;
|
1999-10-14 00:05:02 +00:00
|
|
|
dns_zone_t *zone;
|
2023-02-21 20:14:30 -08:00
|
|
|
dns_view_t *view;
|
1999-08-20 05:35:16 +00:00
|
|
|
|
2020-11-09 11:32:55 +01:00
|
|
|
isc_refcount_t references;
|
2000-01-28 23:48:58 +00:00
|
|
|
|
2021-04-16 11:08:05 +02:00
|
|
|
atomic_bool shuttingdown;
|
2020-09-06 00:38:50 -07:00
|
|
|
|
2015-04-14 12:13:06 +05:30
|
|
|
isc_result_t shutdown_result;
|
2000-08-01 01:33:37 +00:00
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
dns_name_t name; /*%< Name of zone to transfer */
|
1999-08-20 05:35:16 +00:00
|
|
|
dns_rdataclass_t rdclass;
|
|
|
|
|
2000-10-16 04:26:08 +00:00
|
|
|
dns_messageid_t id;
|
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*%
|
1999-08-20 05:35:16 +00:00
|
|
|
* Requested transfer type (dns_rdatatype_axfr or
|
|
|
|
* dns_rdatatype_ixfr). The actual transfer type
|
|
|
|
* may differ due to IXFR->AXFR fallback.
|
|
|
|
*/
|
1999-08-27 18:30:59 +00:00
|
|
|
dns_rdatatype_t reqtype;
|
1999-08-20 05:35:16 +00:00
|
|
|
|
2021-10-05 11:28:24 +02:00
|
|
|
isc_sockaddr_t primaryaddr;
|
2000-01-28 01:12:01 +00:00
|
|
|
isc_sockaddr_t sourceaddr;
|
2020-09-06 00:38:50 -07:00
|
|
|
|
2023-02-21 20:14:30 -08:00
|
|
|
dns_dispatch_t *disp;
|
|
|
|
dns_dispentry_t *dispentry;
|
1999-08-20 05:35:16 +00:00
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*% Buffer for IXFR/AXFR request message */
|
1999-08-27 18:30:59 +00:00
|
|
|
isc_buffer_t qbuffer;
|
1999-08-20 05:35:16 +00:00
|
|
|
unsigned char qbuffer_data[512];
|
|
|
|
|
Log a message when a transferred mirror zone comes into effect
Log a message when a mirror zone is successfully transferred and
verified, but only if no database for that zone was yet loaded at the
time the transfer was initiated.
This could have been implemented in a simpler manner, e.g. by modifying
zone_replacedb(), but (due to the calling order of the functions
involved in finalizing a zone transfer) that would cause the resulting
logs to suggest that a mirror zone comes into effect before its transfer
is finished, which would be confusing given the nature of mirror zones
and the fact that no message is logged upon successful mirror zone
verification.
Once the dns_zone_replacedb() call in axfr_finalize() is made, it
becomes impossible to determine whether the transferred zone had a
database attached before the transfer was started. Thus, that check is
instead performed when the transfer context is first created and the
result of this check is passed around in a field of the transfer context
structure. If it turns out to be desired, the relevant log message is
then emitted just before the transfer context is freed.
Taking this approach means that the log message added by this commit is
not timed precisely, i.e. mirror zone data may be used before this
message is logged. However, that can only be fixed by logging the
message inside zone_replacedb(), which causes arguably more dire issues
discussed above.
dns_zone_isloaded() is not used to double-check that transferred zone
data was correctly loaded since the 'shutdown_result' field of the zone
transfer context will not be set to ISC_R_SUCCESS unless axfr_finalize()
succeeds (and that in turn will not happen unless dns_zone_replacedb()
succeeds).
2019-01-16 15:31:48 +01:00
|
|
|
/*%
|
|
|
|
* Whether the zone originally had a database attached at the time this
|
2020-11-09 11:32:55 +01:00
|
|
|
* transfer context was created. Used by xfrin_destroy() when making
|
Log a message when a transferred mirror zone comes into effect
Log a message when a mirror zone is successfully transferred and
verified, but only if no database for that zone was yet loaded at the
time the transfer was initiated.
This could have been implemented in a simpler manner, e.g. by modifying
zone_replacedb(), but (due to the calling order of the functions
involved in finalizing a zone transfer) that would cause the resulting
logs to suggest that a mirror zone comes into effect before its transfer
is finished, which would be confusing given the nature of mirror zones
and the fact that no message is logged upon successful mirror zone
verification.
Once the dns_zone_replacedb() call in axfr_finalize() is made, it
becomes impossible to determine whether the transferred zone had a
database attached before the transfer was started. Thus, that check is
instead performed when the transfer context is first created and the
result of this check is passed around in a field of the transfer context
structure. If it turns out to be desired, the relevant log message is
then emitted just before the transfer context is freed.
Taking this approach means that the log message added by this commit is
not timed precisely, i.e. mirror zone data may be used before this
message is logged. However, that can only be fixed by logging the
message inside zone_replacedb(), which causes arguably more dire issues
discussed above.
dns_zone_isloaded() is not used to double-check that transferred zone
data was correctly loaded since the 'shutdown_result' field of the zone
transfer context will not be set to ISC_R_SUCCESS unless axfr_finalize()
succeeds (and that in turn will not happen unless dns_zone_replacedb()
succeeds).
2019-01-16 15:31:48 +01:00
|
|
|
* logging decisions.
|
|
|
|
*/
|
|
|
|
bool zone_had_db;
|
|
|
|
|
1999-08-20 05:35:16 +00:00
|
|
|
dns_db_t *db;
|
|
|
|
dns_dbversion_t *ver;
|
2005-04-27 04:57:32 +00:00
|
|
|
dns_diff_t diff; /*%< Pending database changes */
|
2000-08-01 01:33:37 +00:00
|
|
|
|
2023-10-13 14:41:22 +02:00
|
|
|
/* Diff queue */
|
|
|
|
bool diff_running;
|
|
|
|
struct __cds_wfcq_head diff_head;
|
|
|
|
struct cds_wfcq_tail diff_tail;
|
|
|
|
|
2023-07-06 14:00:48 +10:00
|
|
|
_Atomic xfrin_state_t state;
|
2023-06-29 17:59:24 +10:00
|
|
|
uint32_t expireopt;
|
2023-07-06 14:00:48 +10:00
|
|
|
bool edns, expireoptset;
|
|
|
|
atomic_bool is_ixfr;
|
1999-08-20 05:35:16 +00:00
|
|
|
|
2023-10-13 12:16:37 +02:00
|
|
|
/*
|
|
|
|
* Following variable were made atomic only for loading the values for
|
2023-10-13 14:41:22 +02:00
|
|
|
* the statistics channel, thus all accesses can be **relaxed** because
|
2023-10-13 12:16:37 +02:00
|
|
|
* all store and load operations that affect XFR are done on the same
|
|
|
|
* thread and only the statistics channel thread could perform a load
|
|
|
|
* operation from a different thread and it's ok to not be precise in
|
|
|
|
* the statistics.
|
|
|
|
*/
|
|
|
|
atomic_uint nmsg; /*%< Number of messages recvd */
|
|
|
|
atomic_uint nrecs; /*%< Number of records recvd */
|
|
|
|
atomic_uint_fast64_t nbytes; /*%< Number of bytes received */
|
|
|
|
_Atomic(isc_time_t) start; /*%< Start time of the transfer */
|
2024-11-27 10:34:40 +00:00
|
|
|
atomic_uint_fast64_t rate_bytes_per_second;
|
2023-10-13 12:16:37 +02:00
|
|
|
_Atomic(dns_transport_type_t) soa_transport_type;
|
|
|
|
atomic_uint_fast32_t end_serial;
|
2007-12-02 23:21:19 +00:00
|
|
|
|
2016-11-02 17:31:27 +11:00
|
|
|
unsigned int maxrecords; /*%< The maximum number of
|
|
|
|
* records set for the zone */
|
2024-06-10 16:48:26 +00:00
|
|
|
uint64_t nbytes_saved; /*%< For enforcing the minimum transfer rate */
|
2016-11-02 17:31:27 +11:00
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
dns_tsigkey_t *tsigkey; /*%< Key used to create TSIG */
|
|
|
|
isc_buffer_t *lasttsig; /*%< The last TSIG */
|
|
|
|
dst_context_t *tsigctx; /*%< TSIG verification context */
|
|
|
|
unsigned int sincetsig; /*%< recvd since the last TSIG */
|
2021-01-14 12:51:25 +01:00
|
|
|
|
|
|
|
dns_transport_t *transport;
|
|
|
|
|
1999-12-13 03:01:53 +00:00
|
|
|
dns_xfrindone_t done;
|
1999-09-10 15:01:04 +00:00
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*%
|
1999-08-20 05:35:16 +00:00
|
|
|
* AXFR- and IXFR-specific data. Only one is used at a time
|
|
|
|
* according to the is_ixfr flag, so this could be a union,
|
|
|
|
* but keeping them separate makes it a bit simpler to clean
|
|
|
|
* things up when destroying the context.
|
|
|
|
*/
|
2012-06-20 14:13:12 -05:00
|
|
|
dns_rdatacallbacks_t axfr;
|
2000-08-01 01:33:37 +00:00
|
|
|
|
1999-08-20 05:35:16 +00:00
|
|
|
struct {
|
2024-06-07 14:47:55 +00:00
|
|
|
uint32_t diffs;
|
|
|
|
uint32_t maxdiffs;
|
2018-03-28 14:19:37 +02:00
|
|
|
uint32_t request_serial;
|
|
|
|
uint32_t current_serial;
|
2000-09-19 01:44:15 +00:00
|
|
|
dns_journal_t *journal;
|
1999-08-20 05:35:16 +00:00
|
|
|
} ixfr;
|
2021-03-15 15:43:26 +11:00
|
|
|
|
|
|
|
dns_rdata_t firstsoa;
|
|
|
|
unsigned char *firstsoa_data;
|
2021-12-23 16:08:41 +02:00
|
|
|
|
|
|
|
isc_tlsctx_cache_t *tlsctx_cache;
|
2023-04-05 22:35:00 +02:00
|
|
|
|
2024-03-04 13:21:35 +01:00
|
|
|
isc_loop_t *loop;
|
|
|
|
|
2024-06-10 16:48:26 +00:00
|
|
|
isc_timer_t *min_rate_timer;
|
2023-04-05 22:35:00 +02:00
|
|
|
isc_timer_t *max_time_timer;
|
|
|
|
isc_timer_t *max_idle_timer;
|
2023-08-14 14:24:52 +02:00
|
|
|
|
|
|
|
char info[DNS_NAME_MAXTEXT + 32];
|
1999-08-20 05:35:16 +00:00
|
|
|
};
|
|
|
|
|
2001-06-04 19:33:39 +00:00
|
|
|
#define XFRIN_MAGIC ISC_MAGIC('X', 'f', 'r', 'I')
|
2000-03-29 05:03:07 +00:00
|
|
|
#define VALID_XFRIN(x) ISC_MAGIC_VALID(x, XFRIN_MAGIC)
|
|
|
|
|
2024-11-03 21:25:15 +01:00
|
|
|
#define XFRIN_WORK_MAGIC ISC_MAGIC('X', 'f', 'r', 'W')
|
|
|
|
#define VALID_XFRIN_WORK(x) ISC_MAGIC_VALID(x, XFRIN_WORK_MAGIC)
|
|
|
|
|
2023-10-20 07:58:26 +02:00
|
|
|
typedef struct xfrin_work {
|
2024-11-03 21:25:15 +01:00
|
|
|
unsigned int magic;
|
2023-10-20 07:58:26 +02:00
|
|
|
isc_result_t result;
|
2024-11-03 21:25:15 +01:00
|
|
|
dns_xfrin_t *xfr;
|
2023-10-20 07:58:26 +02:00
|
|
|
} xfrin_work_t;
|
|
|
|
|
1999-08-20 05:35:16 +00:00
|
|
|
/**************************************************************************/
|
|
|
|
/*
|
|
|
|
* Forward declarations.
|
|
|
|
*/
|
|
|
|
|
2020-10-09 16:34:22 -07:00
|
|
|
static void
|
2024-03-04 13:21:35 +01:00
|
|
|
xfrin_create(isc_mem_t *mctx, dns_zone_t *zone, dns_db_t *db, isc_loop_t *loop,
|
2020-10-09 16:38:30 -07:00
|
|
|
dns_name_t *zonename, dns_rdataclass_t rdclass,
|
2024-06-07 14:47:55 +00:00
|
|
|
dns_rdatatype_t reqtype, uint32_t ixfr_maxdiffs,
|
|
|
|
const isc_sockaddr_t *primaryaddr,
|
2023-01-05 22:18:55 -08:00
|
|
|
const isc_sockaddr_t *sourceaddr, dns_tsigkey_t *tsigkey,
|
2023-08-23 10:46:44 +00:00
|
|
|
dns_transport_type_t soa_transport_type,
|
2023-01-05 22:18:55 -08:00
|
|
|
dns_transport_t *transport, isc_tlsctx_cache_t *tlsctx_cache,
|
2023-02-23 10:29:33 -08:00
|
|
|
dns_xfrin_t **xfrp);
|
2020-02-12 13:59:18 +01:00
|
|
|
|
2000-01-28 23:48:58 +00:00
|
|
|
static isc_result_t
|
2023-02-23 10:29:33 -08:00
|
|
|
axfr_init(dns_xfrin_t *xfr);
|
2000-01-28 23:48:58 +00:00
|
|
|
static isc_result_t
|
2023-02-23 10:29:33 -08:00
|
|
|
axfr_putdata(dns_xfrin_t *xfr, dns_diffop_t op, dns_name_t *name, dns_ttl_t ttl,
|
|
|
|
dns_rdata_t *rdata);
|
2023-10-13 14:41:22 +02:00
|
|
|
static void
|
2023-02-23 10:29:33 -08:00
|
|
|
axfr_commit(dns_xfrin_t *xfr);
|
2011-02-18 21:22:12 +00:00
|
|
|
static isc_result_t
|
2023-02-23 10:29:33 -08:00
|
|
|
axfr_finalize(dns_xfrin_t *xfr);
|
2020-02-14 08:14:03 +01:00
|
|
|
|
2000-01-28 23:48:58 +00:00
|
|
|
static isc_result_t
|
2023-02-23 10:29:33 -08:00
|
|
|
ixfr_init(dns_xfrin_t *xfr);
|
2000-01-28 23:48:58 +00:00
|
|
|
static isc_result_t
|
2023-02-23 10:29:33 -08:00
|
|
|
ixfr_putdata(dns_xfrin_t *xfr, dns_diffop_t op, dns_name_t *name, dns_ttl_t ttl,
|
|
|
|
dns_rdata_t *rdata);
|
2000-01-28 23:48:58 +00:00
|
|
|
static isc_result_t
|
2023-02-23 10:29:33 -08:00
|
|
|
ixfr_commit(dns_xfrin_t *xfr);
|
2020-02-14 08:14:03 +01:00
|
|
|
|
2000-01-28 23:48:58 +00:00
|
|
|
static isc_result_t
|
2023-02-23 10:29:33 -08:00
|
|
|
xfr_rr(dns_xfrin_t *xfr, dns_name_t *name, uint32_t ttl, dns_rdata_t *rdata);
|
2020-02-14 08:14:03 +01:00
|
|
|
|
2000-01-28 23:48:58 +00:00
|
|
|
static isc_result_t
|
2023-02-23 10:29:33 -08:00
|
|
|
xfrin_start(dns_xfrin_t *xfr);
|
2020-02-14 08:14:03 +01:00
|
|
|
|
1999-08-20 05:35:16 +00:00
|
|
|
static void
|
2023-02-21 20:14:30 -08:00
|
|
|
xfrin_connect_done(isc_result_t result, isc_region_t *region, void *arg);
|
2000-01-28 23:48:58 +00:00
|
|
|
static isc_result_t
|
2023-02-23 10:29:33 -08:00
|
|
|
xfrin_send_request(dns_xfrin_t *xfr);
|
1999-08-20 05:35:16 +00:00
|
|
|
static void
|
2023-02-21 20:14:30 -08:00
|
|
|
xfrin_send_done(isc_result_t eresult, isc_region_t *region, void *arg);
|
1999-08-20 05:35:16 +00:00
|
|
|
static void
|
2023-02-21 20:14:30 -08:00
|
|
|
xfrin_recv_done(isc_result_t result, isc_region_t *region, void *arg);
|
2020-02-14 08:14:03 +01:00
|
|
|
|
2023-10-13 14:41:22 +02:00
|
|
|
static void
|
|
|
|
xfrin_end(dns_xfrin_t *xfr, isc_result_t result);
|
|
|
|
|
2000-01-28 23:48:58 +00:00
|
|
|
static void
|
2023-02-23 10:29:33 -08:00
|
|
|
xfrin_destroy(dns_xfrin_t *xfr);
|
2020-02-14 08:14:03 +01:00
|
|
|
|
2023-04-05 22:35:00 +02:00
|
|
|
static void
|
|
|
|
xfrin_timedout(void *);
|
|
|
|
static void
|
|
|
|
xfrin_idledout(void *);
|
2000-06-01 13:48:55 +00:00
|
|
|
static void
|
2024-06-10 16:48:26 +00:00
|
|
|
xfrin_minratecheck(void *);
|
|
|
|
static void
|
2023-02-23 10:29:33 -08:00
|
|
|
xfrin_fail(dns_xfrin_t *xfr, isc_result_t result, const char *msg);
|
2001-03-05 21:15:47 +00:00
|
|
|
static isc_result_t
|
|
|
|
render(dns_message_t *msg, isc_mem_t *mctx, isc_buffer_t *buf);
|
2020-02-14 08:14:03 +01:00
|
|
|
|
2005-10-14 01:18:47 +00:00
|
|
|
static void
|
2023-02-23 10:29:33 -08:00
|
|
|
xfrin_log(dns_xfrin_t *xfr, int level, const char *fmt, ...)
|
2001-08-08 22:54:55 +00:00
|
|
|
ISC_FORMAT_PRINTF(3, 4);
|
1999-10-30 01:08:52 +00:00
|
|
|
|
1999-08-20 05:35:16 +00:00
|
|
|
/**************************************************************************/
|
1999-08-27 18:30:59 +00:00
|
|
|
/*
|
|
|
|
* AXFR handling
|
|
|
|
*/
|
1999-08-20 05:35:16 +00:00
|
|
|
|
1999-12-23 00:09:04 +00:00
|
|
|
static isc_result_t
|
2023-02-23 10:29:33 -08:00
|
|
|
axfr_init(dns_xfrin_t *xfr) {
|
1999-12-23 00:09:04 +00:00
|
|
|
isc_result_t result;
|
2000-06-01 18:04:37 +00:00
|
|
|
|
2023-07-06 14:00:48 +10:00
|
|
|
atomic_store(&xfr->is_ixfr, false);
|
1999-08-20 05:35:16 +00:00
|
|
|
|
1999-10-14 01:37:00 +00:00
|
|
|
if (xfr->db != NULL) {
|
|
|
|
dns_db_detach(&xfr->db);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
1999-10-14 01:37:00 +00:00
|
|
|
|
2024-05-28 16:13:31 +02:00
|
|
|
CHECK(dns_zone_makedb(xfr->zone, &xfr->db));
|
|
|
|
|
|
|
|
dns_zone_rpz_enable_db(xfr->zone, xfr->db);
|
|
|
|
dns_zone_catz_enable_db(xfr->zone, xfr->db);
|
|
|
|
|
2012-06-20 14:13:12 -05:00
|
|
|
dns_rdatacallbacks_init(&xfr->axfr);
|
|
|
|
CHECK(dns_db_beginload(xfr->db, &xfr->axfr));
|
2000-04-06 22:03:35 +00:00
|
|
|
result = ISC_R_SUCCESS;
|
1999-08-20 05:35:16 +00:00
|
|
|
failure:
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2024-11-03 21:25:15 +01:00
|
|
|
static void
|
|
|
|
axfr_apply(void *arg);
|
|
|
|
|
1999-12-23 00:09:04 +00:00
|
|
|
static isc_result_t
|
2023-02-23 10:29:33 -08:00
|
|
|
axfr_putdata(dns_xfrin_t *xfr, dns_diffop_t op, dns_name_t *name, dns_ttl_t ttl,
|
|
|
|
dns_rdata_t *rdata) {
|
1999-12-23 00:09:04 +00:00
|
|
|
isc_result_t result;
|
2000-06-01 18:04:37 +00:00
|
|
|
|
1999-08-20 05:35:16 +00:00
|
|
|
dns_difftuple_t *tuple = NULL;
|
2004-02-27 20:41:51 +00:00
|
|
|
|
2015-09-16 10:43:22 +10:00
|
|
|
if (rdata->rdclass != xfr->rdclass) {
|
|
|
|
return DNS_R_BADCLASS;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-09-16 10:43:22 +10:00
|
|
|
|
2004-02-27 20:41:51 +00:00
|
|
|
CHECK(dns_zone_checknames(xfr->zone, name, rdata));
|
2024-11-03 21:25:15 +01:00
|
|
|
if (dns_diff_size(&xfr->diff) > 128 &&
|
|
|
|
dns_diff_is_boundary(&xfr->diff, name))
|
|
|
|
{
|
|
|
|
xfrin_work_t work = (xfrin_work_t){
|
|
|
|
.magic = XFRIN_WORK_MAGIC,
|
|
|
|
.result = ISC_R_UNSET,
|
|
|
|
.xfr = xfr,
|
|
|
|
};
|
|
|
|
axfr_apply((void *)&work);
|
|
|
|
CHECK(work.result);
|
|
|
|
}
|
|
|
|
|
2024-07-11 17:00:38 -07:00
|
|
|
dns_difftuple_create(xfr->diff.mctx, op, name, ttl, rdata, &tuple);
|
1999-08-20 05:35:16 +00:00
|
|
|
dns_diff_append(&xfr->diff, &tuple);
|
2024-11-03 21:25:15 +01:00
|
|
|
|
2000-04-06 22:03:35 +00:00
|
|
|
result = ISC_R_SUCCESS;
|
1999-08-20 05:35:16 +00:00
|
|
|
failure:
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2000-06-01 13:48:55 +00:00
|
|
|
/*
|
|
|
|
* Store a set of AXFR RRs in the database.
|
|
|
|
*/
|
2023-10-13 14:41:22 +02:00
|
|
|
static void
|
|
|
|
axfr_apply(void *arg) {
|
2023-10-20 07:58:26 +02:00
|
|
|
xfrin_work_t *work = arg;
|
2024-11-03 21:25:15 +01:00
|
|
|
REQUIRE(VALID_XFRIN_WORK(work));
|
|
|
|
|
2023-10-20 07:58:26 +02:00
|
|
|
dns_xfrin_t *xfr = work->xfr;
|
2024-11-03 21:25:15 +01:00
|
|
|
REQUIRE(VALID_XFRIN(xfr));
|
|
|
|
|
2023-10-13 14:41:22 +02:00
|
|
|
isc_result_t result = ISC_R_SUCCESS;
|
2018-03-28 14:19:37 +02:00
|
|
|
uint64_t records;
|
2000-06-01 18:04:37 +00:00
|
|
|
|
2023-10-13 14:41:22 +02:00
|
|
|
if (atomic_load(&xfr->shuttingdown)) {
|
|
|
|
result = ISC_R_SHUTTINGDOWN;
|
|
|
|
goto failure;
|
|
|
|
}
|
|
|
|
|
2024-02-05 16:11:16 -08:00
|
|
|
CHECK(dns_diff_load(&xfr->diff, &xfr->axfr));
|
2016-11-02 17:31:27 +11:00
|
|
|
if (xfr->maxrecords != 0U) {
|
|
|
|
result = dns_db_getsize(xfr->db, xfr->ver, &records, NULL);
|
|
|
|
if (result == ISC_R_SUCCESS && records > xfr->maxrecords) {
|
|
|
|
result = DNS_R_TOOMANYRECORDS;
|
|
|
|
goto failure;
|
|
|
|
}
|
|
|
|
}
|
2023-10-13 14:41:22 +02:00
|
|
|
|
1999-08-20 05:35:16 +00:00
|
|
|
failure:
|
2023-10-13 14:41:22 +02:00
|
|
|
dns_diff_clear(&xfr->diff);
|
2023-10-20 07:58:26 +02:00
|
|
|
work->result = result;
|
1999-08-20 05:35:16 +00:00
|
|
|
}
|
|
|
|
|
2023-10-13 14:41:22 +02:00
|
|
|
static void
|
|
|
|
axfr_apply_done(void *arg) {
|
2023-10-20 07:58:26 +02:00
|
|
|
xfrin_work_t *work = arg;
|
|
|
|
dns_xfrin_t *xfr = work->xfr;
|
|
|
|
isc_result_t result = work->result;
|
|
|
|
|
|
|
|
REQUIRE(VALID_XFRIN(xfr));
|
2024-11-03 21:25:15 +01:00
|
|
|
REQUIRE(VALID_XFRIN_WORK(work));
|
1999-08-27 18:30:59 +00:00
|
|
|
|
2023-10-13 14:41:22 +02:00
|
|
|
if (atomic_load(&xfr->shuttingdown)) {
|
|
|
|
result = ISC_R_SHUTTINGDOWN;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
CHECK(dns_db_endload(xfr->db, &xfr->axfr));
|
|
|
|
CHECK(dns_zone_verifydb(xfr->zone, xfr->db, NULL));
|
|
|
|
CHECK(axfr_finalize(xfr));
|
|
|
|
} else {
|
|
|
|
(void)dns_db_endload(xfr->db, &xfr->axfr);
|
|
|
|
}
|
2011-02-18 21:22:12 +00:00
|
|
|
|
|
|
|
failure:
|
2023-10-13 14:41:22 +02:00
|
|
|
xfr->diff_running = false;
|
|
|
|
|
2023-10-20 07:58:26 +02:00
|
|
|
isc_mem_put(xfr->mctx, work, sizeof(*work));
|
|
|
|
|
2023-10-13 14:41:22 +02:00
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
if (atomic_load(&xfr->state) == XFRST_AXFR_END) {
|
|
|
|
xfrin_end(xfr, result);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
xfrin_fail(xfr, result, "failed while processing responses");
|
|
|
|
}
|
|
|
|
|
|
|
|
dns_xfrin_detach(&xfr);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
axfr_commit(dns_xfrin_t *xfr) {
|
2023-10-20 07:58:26 +02:00
|
|
|
REQUIRE(!xfr->diff_running);
|
|
|
|
|
|
|
|
xfrin_work_t *work = isc_mem_get(xfr->mctx, sizeof(*work));
|
|
|
|
*work = (xfrin_work_t){
|
2024-11-03 21:25:15 +01:00
|
|
|
.magic = XFRIN_WORK_MAGIC,
|
2023-10-20 07:58:26 +02:00
|
|
|
.result = ISC_R_UNSET,
|
2024-11-03 21:25:15 +01:00
|
|
|
.xfr = dns_xfrin_ref(xfr),
|
2023-10-20 07:58:26 +02:00
|
|
|
};
|
2023-10-13 14:41:22 +02:00
|
|
|
xfr->diff_running = true;
|
2024-03-04 13:21:35 +01:00
|
|
|
isc_work_enqueue(xfr->loop, axfr_apply, axfr_apply_done, work);
|
2011-02-18 21:22:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
2023-02-23 10:29:33 -08:00
|
|
|
axfr_finalize(dns_xfrin_t *xfr) {
|
2011-02-18 21:22:12 +00:00
|
|
|
isc_result_t result;
|
|
|
|
|
2023-08-14 14:24:52 +02:00
|
|
|
LIBDNS_XFRIN_AXFR_FINALIZE_BEGIN(xfr, xfr->info);
|
2023-01-31 10:14:21 +01:00
|
|
|
result = dns_zone_replacedb(xfr->zone, xfr->db, true);
|
2023-08-14 14:24:52 +02:00
|
|
|
LIBDNS_XFRIN_AXFR_FINALIZE_END(xfr, xfr->info, result);
|
1999-08-20 05:35:16 +00:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**************************************************************************/
|
1999-08-27 18:30:59 +00:00
|
|
|
/*
|
|
|
|
* IXFR handling
|
|
|
|
*/
|
1999-08-20 05:35:16 +00:00
|
|
|
|
2023-10-13 14:41:22 +02:00
|
|
|
typedef struct ixfr_apply_data {
|
|
|
|
dns_diff_t diff; /*%< Pending database changes */
|
|
|
|
struct cds_wfcq_node wfcq_node;
|
|
|
|
} ixfr_apply_data_t;
|
|
|
|
|
1999-12-23 00:09:04 +00:00
|
|
|
static isc_result_t
|
2023-02-23 10:29:33 -08:00
|
|
|
ixfr_init(dns_xfrin_t *xfr) {
|
1999-12-23 00:09:04 +00:00
|
|
|
isc_result_t result;
|
2020-09-06 00:38:50 -07:00
|
|
|
char *journalfile = NULL;
|
2000-06-01 18:04:37 +00:00
|
|
|
|
2000-07-03 22:42:36 +00:00
|
|
|
if (xfr->reqtype != dns_rdatatype_ixfr) {
|
2023-09-01 10:17:00 +10:00
|
|
|
xfrin_log(xfr, ISC_LOG_NOTICE,
|
2000-07-03 22:42:36 +00:00
|
|
|
"got incremental response to AXFR request");
|
|
|
|
return DNS_R_FORMERR;
|
|
|
|
}
|
|
|
|
|
2023-07-06 14:00:48 +10:00
|
|
|
atomic_store(&xfr->is_ixfr, true);
|
1999-08-20 05:35:16 +00:00
|
|
|
INSIST(xfr->db != NULL);
|
2000-08-31 23:56:00 +00:00
|
|
|
|
|
|
|
journalfile = dns_zone_getjournal(xfr->zone);
|
|
|
|
if (journalfile != NULL) {
|
|
|
|
CHECK(dns_journal_open(xfr->mctx, journalfile,
|
2011-12-22 07:32:41 +00:00
|
|
|
DNS_JOURNAL_CREATE, &xfr->ixfr.journal));
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2000-08-31 23:56:00 +00:00
|
|
|
|
2000-04-06 22:03:35 +00:00
|
|
|
result = ISC_R_SUCCESS;
|
1999-08-20 05:35:16 +00:00
|
|
|
failure:
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
1999-12-23 00:09:04 +00:00
|
|
|
static isc_result_t
|
2023-02-23 10:29:33 -08:00
|
|
|
ixfr_putdata(dns_xfrin_t *xfr, dns_diffop_t op, dns_name_t *name, dns_ttl_t ttl,
|
|
|
|
dns_rdata_t *rdata) {
|
2024-07-11 17:00:38 -07:00
|
|
|
isc_result_t result = ISC_R_SUCCESS;
|
1999-08-27 18:30:59 +00:00
|
|
|
dns_difftuple_t *tuple = NULL;
|
2015-09-16 10:43:22 +10:00
|
|
|
|
|
|
|
if (rdata->rdclass != xfr->rdclass) {
|
|
|
|
return DNS_R_BADCLASS;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-09-16 10:43:22 +10:00
|
|
|
|
2004-02-27 20:41:51 +00:00
|
|
|
if (op == DNS_DIFFOP_ADD) {
|
|
|
|
CHECK(dns_zone_checknames(xfr->zone, name, rdata));
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2024-07-11 17:00:38 -07:00
|
|
|
|
|
|
|
dns_difftuple_create(xfr->diff.mctx, op, name, ttl, rdata, &tuple);
|
1999-08-27 18:30:59 +00:00
|
|
|
dns_diff_append(&xfr->diff, &tuple);
|
2024-07-11 17:00:38 -07:00
|
|
|
|
2024-06-07 14:47:55 +00:00
|
|
|
xfr->ixfr.diffs++;
|
1999-08-20 05:35:16 +00:00
|
|
|
failure:
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
1999-12-23 00:09:04 +00:00
|
|
|
static isc_result_t
|
2023-10-13 14:41:22 +02:00
|
|
|
ixfr_begin_transaction(dns_xfrin_t *xfr) {
|
|
|
|
isc_result_t result = ISC_R_SUCCESS;
|
2000-06-01 18:04:37 +00:00
|
|
|
|
2023-10-13 14:41:22 +02:00
|
|
|
if (xfr->ixfr.journal != NULL) {
|
|
|
|
CHECK(dns_journal_begin_transaction(xfr->ixfr.journal));
|
1999-08-20 05:35:16 +00:00
|
|
|
}
|
2023-10-13 14:41:22 +02:00
|
|
|
failure:
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
ixfr_end_transaction(dns_xfrin_t *xfr) {
|
|
|
|
isc_result_t result = ISC_R_SUCCESS;
|
|
|
|
|
|
|
|
CHECK(dns_zone_verifydb(xfr->zone, xfr->db, xfr->ver));
|
|
|
|
/* XXX enter ready-to-commit state here */
|
|
|
|
if (xfr->ixfr.journal != NULL) {
|
|
|
|
CHECK(dns_journal_commit(xfr->ixfr.journal));
|
|
|
|
}
|
|
|
|
failure:
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
ixfr_apply_one(dns_xfrin_t *xfr, ixfr_apply_data_t *data) {
|
|
|
|
isc_result_t result = ISC_R_SUCCESS;
|
|
|
|
uint64_t records;
|
|
|
|
|
|
|
|
CHECK(ixfr_begin_transaction(xfr));
|
|
|
|
|
|
|
|
CHECK(dns_diff_apply(&data->diff, xfr->db, xfr->ver));
|
2016-11-02 17:31:27 +11:00
|
|
|
if (xfr->maxrecords != 0U) {
|
|
|
|
result = dns_db_getsize(xfr->db, xfr->ver, &records, NULL);
|
|
|
|
if (result == ISC_R_SUCCESS && records > xfr->maxrecords) {
|
|
|
|
result = DNS_R_TOOMANYRECORDS;
|
|
|
|
goto failure;
|
|
|
|
}
|
|
|
|
}
|
2001-11-30 01:59:49 +00:00
|
|
|
if (xfr->ixfr.journal != NULL) {
|
2023-10-13 14:41:22 +02:00
|
|
|
CHECK(dns_journal_writediff(xfr->ixfr.journal, &data->diff));
|
2001-11-30 01:59:49 +00:00
|
|
|
}
|
2023-10-13 14:41:22 +02:00
|
|
|
|
|
|
|
result = ixfr_end_transaction(xfr);
|
|
|
|
|
|
|
|
return result;
|
1999-08-20 05:35:16 +00:00
|
|
|
failure:
|
2023-10-13 14:41:22 +02:00
|
|
|
/* We need to end the transaction, but keep the previous error */
|
|
|
|
(void)ixfr_end_transaction(xfr);
|
|
|
|
|
1999-08-20 05:35:16 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2023-10-13 14:41:22 +02:00
|
|
|
static void
|
|
|
|
ixfr_apply(void *arg) {
|
2023-10-20 07:58:26 +02:00
|
|
|
xfrin_work_t *work = arg;
|
|
|
|
dns_xfrin_t *xfr = work->xfr;
|
2023-10-13 14:41:22 +02:00
|
|
|
isc_result_t result = ISC_R_SUCCESS;
|
2000-06-01 18:04:37 +00:00
|
|
|
|
2023-10-20 07:58:26 +02:00
|
|
|
REQUIRE(VALID_XFRIN(xfr));
|
2024-11-03 21:25:15 +01:00
|
|
|
REQUIRE(VALID_XFRIN_WORK(work));
|
2023-10-20 07:58:26 +02:00
|
|
|
|
2023-10-13 14:41:22 +02:00
|
|
|
struct __cds_wfcq_head diff_head;
|
|
|
|
struct cds_wfcq_tail diff_tail;
|
|
|
|
|
|
|
|
/* Initialize local wfcqueue */
|
|
|
|
__cds_wfcq_init(&diff_head, &diff_tail);
|
|
|
|
|
|
|
|
enum cds_wfcq_ret ret = __cds_wfcq_splice_blocking(
|
|
|
|
&diff_head, &diff_tail, &xfr->diff_head, &xfr->diff_tail);
|
|
|
|
INSIST(ret == CDS_WFCQ_RET_DEST_EMPTY);
|
|
|
|
|
|
|
|
struct cds_wfcq_node *node, *next;
|
|
|
|
__cds_wfcq_for_each_blocking_safe(&diff_head, &diff_tail, node, next) {
|
|
|
|
ixfr_apply_data_t *data =
|
|
|
|
caa_container_of(node, ixfr_apply_data_t, wfcq_node);
|
|
|
|
|
|
|
|
if (atomic_load(&xfr->shuttingdown)) {
|
|
|
|
result = ISC_R_SHUTTINGDOWN;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Apply only until first failure */
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
/* This also checks for shuttingdown condition */
|
|
|
|
result = ixfr_apply_one(xfr, data);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2023-10-13 14:41:22 +02:00
|
|
|
|
|
|
|
/* We need to clear and free all data chunks */
|
|
|
|
dns_diff_clear(&data->diff);
|
|
|
|
isc_mem_put(xfr->mctx, data, sizeof(*data));
|
|
|
|
}
|
|
|
|
|
2023-10-20 07:58:26 +02:00
|
|
|
work->result = result;
|
2023-10-13 14:41:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
ixfr_apply_done(void *arg) {
|
2023-10-20 07:58:26 +02:00
|
|
|
xfrin_work_t *work = arg;
|
2024-11-03 21:25:15 +01:00
|
|
|
REQUIRE(VALID_XFRIN_WORK(work));
|
2023-10-20 07:58:26 +02:00
|
|
|
|
2024-11-03 21:25:15 +01:00
|
|
|
dns_xfrin_t *xfr = work->xfr;
|
2023-10-20 07:58:26 +02:00
|
|
|
REQUIRE(VALID_XFRIN(xfr));
|
2023-10-13 14:41:22 +02:00
|
|
|
|
2024-11-03 21:25:15 +01:00
|
|
|
isc_result_t result = work->result;
|
|
|
|
|
2023-10-13 14:41:22 +02:00
|
|
|
if (atomic_load(&xfr->shuttingdown)) {
|
|
|
|
result = ISC_R_SHUTTINGDOWN;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
goto failure;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Reschedule */
|
|
|
|
if (!cds_wfcq_empty(&xfr->diff_head, &xfr->diff_tail)) {
|
2024-03-04 13:21:35 +01:00
|
|
|
isc_work_enqueue(xfr->loop, ixfr_apply, ixfr_apply_done, work);
|
2023-10-13 14:41:22 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
failure:
|
|
|
|
xfr->diff_running = false;
|
|
|
|
|
2023-10-20 07:58:26 +02:00
|
|
|
isc_mem_put(xfr->mctx, work, sizeof(*work));
|
|
|
|
|
2023-10-13 14:41:22 +02:00
|
|
|
if (result == ISC_R_SUCCESS) {
|
2018-04-17 08:29:14 -07:00
|
|
|
dns_db_closeversion(xfr->db, &xfr->ver, true);
|
2000-10-02 23:55:44 +00:00
|
|
|
dns_zone_markdirty(xfr->zone);
|
2023-10-13 14:41:22 +02:00
|
|
|
|
|
|
|
if (atomic_load(&xfr->state) == XFRST_IXFR_END) {
|
|
|
|
xfrin_end(xfr, result);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
dns_db_closeversion(xfr->db, &xfr->ver, false);
|
|
|
|
|
|
|
|
xfrin_fail(xfr, result, "failed while processing responses");
|
1999-08-20 05:35:16 +00:00
|
|
|
}
|
2023-10-13 14:41:22 +02:00
|
|
|
|
|
|
|
dns_xfrin_detach(&xfr);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Apply a set of IXFR changes to the database.
|
|
|
|
*/
|
|
|
|
static isc_result_t
|
|
|
|
ixfr_commit(dns_xfrin_t *xfr) {
|
|
|
|
isc_result_t result = ISC_R_SUCCESS;
|
|
|
|
ixfr_apply_data_t *data = isc_mem_get(xfr->mctx, sizeof(*data));
|
|
|
|
|
|
|
|
*data = (ixfr_apply_data_t){ 0 };
|
|
|
|
cds_wfcq_node_init(&data->wfcq_node);
|
|
|
|
|
|
|
|
if (xfr->ver == NULL) {
|
|
|
|
CHECK(dns_db_newversion(xfr->db, &xfr->ver));
|
|
|
|
}
|
|
|
|
|
|
|
|
dns_diff_init(xfr->mctx, &data->diff);
|
|
|
|
/* FIXME: Should we add dns_diff_move() */
|
|
|
|
ISC_LIST_MOVE(data->diff.tuples, xfr->diff.tuples);
|
|
|
|
|
|
|
|
(void)cds_wfcq_enqueue(&xfr->diff_head, &xfr->diff_tail,
|
|
|
|
&data->wfcq_node);
|
|
|
|
|
|
|
|
if (!xfr->diff_running) {
|
2023-10-20 07:58:26 +02:00
|
|
|
xfrin_work_t *work = isc_mem_get(xfr->mctx, sizeof(*work));
|
|
|
|
*work = (xfrin_work_t){
|
2024-11-03 21:25:15 +01:00
|
|
|
.magic = XFRIN_WORK_MAGIC,
|
2023-10-20 07:58:26 +02:00
|
|
|
.result = ISC_R_UNSET,
|
2024-11-03 21:25:15 +01:00
|
|
|
.xfr = dns_xfrin_ref(xfr),
|
2023-10-20 07:58:26 +02:00
|
|
|
};
|
2023-10-13 14:41:22 +02:00
|
|
|
xfr->diff_running = true;
|
2024-03-04 13:21:35 +01:00
|
|
|
isc_work_enqueue(xfr->loop, ixfr_apply, ixfr_apply_done, work);
|
2023-10-13 14:41:22 +02:00
|
|
|
}
|
|
|
|
|
1999-08-20 05:35:16 +00:00
|
|
|
failure:
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**************************************************************************/
|
1999-08-27 18:30:59 +00:00
|
|
|
/*
|
|
|
|
* Common AXFR/IXFR protocol code
|
|
|
|
*/
|
1999-08-20 05:35:16 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Handle a single incoming resource record according to the current
|
|
|
|
* state.
|
|
|
|
*/
|
1999-12-23 00:09:04 +00:00
|
|
|
static isc_result_t
|
2023-02-23 10:29:33 -08:00
|
|
|
xfr_rr(dns_xfrin_t *xfr, dns_name_t *name, uint32_t ttl, dns_rdata_t *rdata) {
|
1999-12-23 00:09:04 +00:00
|
|
|
isc_result_t result;
|
2023-10-13 12:16:37 +02:00
|
|
|
uint_fast32_t end_serial;
|
2000-06-01 18:04:37 +00:00
|
|
|
|
2023-10-13 12:16:37 +02:00
|
|
|
atomic_fetch_add_relaxed(&xfr->nrecs, 1);
|
2007-12-02 23:21:19 +00:00
|
|
|
|
2008-09-25 04:12:39 +00:00
|
|
|
if (rdata->type == dns_rdatatype_none ||
|
2022-11-02 19:33:14 +01:00
|
|
|
dns_rdatatype_ismeta(rdata->type))
|
|
|
|
{
|
2023-09-01 10:17:00 +10:00
|
|
|
char buf[64];
|
|
|
|
dns_rdatatype_format(rdata->type, buf, sizeof(buf));
|
|
|
|
xfrin_log(xfr, ISC_LOG_NOTICE,
|
|
|
|
"Unexpected %s record in zone transfer", buf);
|
2023-10-12 17:44:51 +02:00
|
|
|
result = DNS_R_FORMERR;
|
|
|
|
goto failure;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2008-09-25 03:49:55 +00:00
|
|
|
|
2021-02-03 11:10:20 +11:00
|
|
|
/*
|
|
|
|
* Immediately reject the entire transfer if the RR that is currently
|
|
|
|
* being processed is an SOA record that is not placed at the zone
|
|
|
|
* apex.
|
|
|
|
*/
|
|
|
|
if (rdata->type == dns_rdatatype_soa &&
|
2022-11-02 19:33:14 +01:00
|
|
|
!dns_name_equal(&xfr->name, name))
|
|
|
|
{
|
2021-02-03 11:10:20 +11:00
|
|
|
char namebuf[DNS_NAME_FORMATSIZE];
|
|
|
|
dns_name_format(name, namebuf, sizeof(namebuf));
|
|
|
|
xfrin_log(xfr, ISC_LOG_DEBUG(3), "SOA name mismatch: '%s'",
|
|
|
|
namebuf);
|
2023-10-12 17:44:51 +02:00
|
|
|
result = DNS_R_NOTZONETOP;
|
|
|
|
goto failure;
|
2021-02-03 11:10:20 +11:00
|
|
|
}
|
|
|
|
|
1999-08-20 05:35:16 +00:00
|
|
|
redo:
|
2023-07-06 14:00:48 +10:00
|
|
|
switch (atomic_load(&xfr->state)) {
|
2006-07-19 00:53:42 +00:00
|
|
|
case XFRST_SOAQUERY:
|
|
|
|
if (rdata->type != dns_rdatatype_soa) {
|
2023-09-01 10:17:00 +10:00
|
|
|
xfrin_log(xfr, ISC_LOG_NOTICE,
|
2006-07-19 00:53:42 +00:00
|
|
|
"non-SOA response to SOA query");
|
2023-10-12 17:44:51 +02:00
|
|
|
result = DNS_R_FORMERR;
|
|
|
|
goto failure;
|
2006-07-19 00:53:42 +00:00
|
|
|
}
|
2023-10-13 12:16:37 +02:00
|
|
|
end_serial = dns_soa_getserial(rdata);
|
|
|
|
atomic_store_relaxed(&xfr->end_serial, end_serial);
|
|
|
|
if (!DNS_SERIAL_GT(end_serial, xfr->ixfr.request_serial) &&
|
2006-07-19 00:53:42 +00:00
|
|
|
!dns_zone_isforced(xfr->zone))
|
|
|
|
{
|
|
|
|
xfrin_log(xfr, ISC_LOG_DEBUG(3),
|
|
|
|
"requested serial %u, "
|
2023-10-13 12:16:37 +02:00
|
|
|
"primary has %" PRIuFAST32 ", not updating",
|
|
|
|
xfr->ixfr.request_serial, end_serial);
|
2023-10-12 17:44:51 +02:00
|
|
|
result = DNS_R_UPTODATE;
|
|
|
|
goto failure;
|
2006-07-19 00:53:42 +00:00
|
|
|
}
|
2023-07-06 14:00:48 +10:00
|
|
|
atomic_store(&xfr->state, XFRST_GOTSOA);
|
2006-07-19 00:53:42 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case XFRST_GOTSOA:
|
|
|
|
/*
|
|
|
|
* Skip other records in the answer section.
|
|
|
|
*/
|
|
|
|
break;
|
|
|
|
|
2023-09-19 09:35:20 +00:00
|
|
|
case XFRST_ZONEXFRREQUEST:
|
2000-04-07 19:41:07 +00:00
|
|
|
if (rdata->type != dns_rdatatype_soa) {
|
2023-09-01 10:17:00 +10:00
|
|
|
xfrin_log(xfr, ISC_LOG_NOTICE,
|
2000-04-07 19:41:07 +00:00
|
|
|
"first RR in zone transfer must be SOA");
|
2023-10-12 17:44:51 +02:00
|
|
|
result = DNS_R_FORMERR;
|
|
|
|
goto failure;
|
2000-04-07 19:41:07 +00:00
|
|
|
}
|
1999-08-20 05:35:16 +00:00
|
|
|
/*
|
2004-06-27 10:10:55 +00:00
|
|
|
* Remember the serial number in the initial SOA.
|
1999-08-20 05:35:16 +00:00
|
|
|
* We need it to recognize the end of an IXFR.
|
|
|
|
*/
|
2023-10-13 12:16:37 +02:00
|
|
|
end_serial = dns_soa_getserial(rdata);
|
|
|
|
atomic_store_relaxed(&xfr->end_serial, end_serial);
|
1999-08-20 05:35:16 +00:00
|
|
|
if (xfr->reqtype == dns_rdatatype_ixfr &&
|
2023-10-13 12:16:37 +02:00
|
|
|
!DNS_SERIAL_GT(end_serial, xfr->ixfr.request_serial) &&
|
2000-10-12 21:52:00 +00:00
|
|
|
!dns_zone_isforced(xfr->zone))
|
|
|
|
{
|
1999-08-20 05:35:16 +00:00
|
|
|
/*
|
1999-08-24 06:43:19 +00:00
|
|
|
* This must be the single SOA record that is
|
2021-10-05 11:07:44 +02:00
|
|
|
* sent when the current version on the primary
|
1999-08-24 06:43:19 +00:00
|
|
|
* is not newer than the version in the request.
|
1999-08-20 05:35:16 +00:00
|
|
|
*/
|
2000-01-26 21:12:04 +00:00
|
|
|
xfrin_log(xfr, ISC_LOG_DEBUG(3),
|
|
|
|
"requested serial %u, "
|
2023-10-13 12:16:37 +02:00
|
|
|
"primary has %" PRIuFAST32 ", not updating",
|
|
|
|
xfr->ixfr.request_serial, end_serial);
|
2023-10-12 17:44:51 +02:00
|
|
|
result = DNS_R_UPTODATE;
|
|
|
|
goto failure;
|
1999-08-27 18:30:59 +00:00
|
|
|
}
|
2021-03-15 15:43:26 +11:00
|
|
|
xfr->firstsoa = *rdata;
|
|
|
|
if (xfr->firstsoa_data != NULL) {
|
|
|
|
isc_mem_free(xfr->mctx, xfr->firstsoa_data);
|
|
|
|
}
|
|
|
|
xfr->firstsoa_data = isc_mem_allocate(xfr->mctx, rdata->length);
|
|
|
|
memcpy(xfr->firstsoa_data, rdata->data, rdata->length);
|
|
|
|
xfr->firstsoa.data = xfr->firstsoa_data;
|
2023-07-06 14:00:48 +10:00
|
|
|
atomic_store(&xfr->state, XFRST_FIRSTDATA);
|
1999-08-20 05:35:16 +00:00
|
|
|
break;
|
2000-08-01 01:33:37 +00:00
|
|
|
|
1999-08-20 05:35:16 +00:00
|
|
|
case XFRST_FIRSTDATA:
|
|
|
|
/*
|
|
|
|
* If the transfer begins with one SOA record, it is an AXFR,
|
|
|
|
* if it begins with two SOAs, it is an IXFR.
|
|
|
|
*/
|
2000-07-05 20:28:34 +00:00
|
|
|
if (xfr->reqtype == dns_rdatatype_ixfr &&
|
|
|
|
rdata->type == dns_rdatatype_soa &&
|
2000-07-03 13:33:05 +00:00
|
|
|
xfr->ixfr.request_serial == dns_soa_getserial(rdata))
|
|
|
|
{
|
2000-03-20 21:07:48 +00:00
|
|
|
xfrin_log(xfr, ISC_LOG_DEBUG(3),
|
|
|
|
"got incremental response");
|
1999-08-20 05:35:16 +00:00
|
|
|
CHECK(ixfr_init(xfr));
|
2023-07-06 14:00:48 +10:00
|
|
|
atomic_store(&xfr->state, XFRST_IXFR_DELSOA);
|
1999-08-20 05:35:16 +00:00
|
|
|
} else {
|
2000-03-20 21:07:48 +00:00
|
|
|
xfrin_log(xfr, ISC_LOG_DEBUG(3),
|
|
|
|
"got nonincremental response");
|
1999-08-20 05:35:16 +00:00
|
|
|
CHECK(axfr_init(xfr));
|
2023-07-06 14:00:48 +10:00
|
|
|
atomic_store(&xfr->state, XFRST_AXFR);
|
1999-08-20 05:35:16 +00:00
|
|
|
}
|
1999-08-27 18:30:59 +00:00
|
|
|
goto redo;
|
1999-08-20 05:35:16 +00:00
|
|
|
|
|
|
|
case XFRST_IXFR_DELSOA:
|
|
|
|
INSIST(rdata->type == dns_rdatatype_soa);
|
|
|
|
CHECK(ixfr_putdata(xfr, DNS_DIFFOP_DEL, name, ttl, rdata));
|
2023-07-06 14:00:48 +10:00
|
|
|
atomic_store(&xfr->state, XFRST_IXFR_DEL);
|
1999-08-20 05:35:16 +00:00
|
|
|
break;
|
2000-08-01 01:33:37 +00:00
|
|
|
|
1999-08-20 05:35:16 +00:00
|
|
|
case XFRST_IXFR_DEL:
|
|
|
|
if (rdata->type == dns_rdatatype_soa) {
|
2018-03-28 14:19:37 +02:00
|
|
|
uint32_t soa_serial = dns_soa_getserial(rdata);
|
2023-07-06 14:00:48 +10:00
|
|
|
atomic_store(&xfr->state, XFRST_IXFR_ADDSOA);
|
2002-09-24 01:04:03 +00:00
|
|
|
xfr->ixfr.current_serial = soa_serial;
|
1999-08-20 05:35:16 +00:00
|
|
|
goto redo;
|
|
|
|
}
|
|
|
|
CHECK(ixfr_putdata(xfr, DNS_DIFFOP_DEL, name, ttl, rdata));
|
|
|
|
break;
|
2000-08-01 01:33:37 +00:00
|
|
|
|
1999-08-20 05:35:16 +00:00
|
|
|
case XFRST_IXFR_ADDSOA:
|
|
|
|
INSIST(rdata->type == dns_rdatatype_soa);
|
|
|
|
CHECK(ixfr_putdata(xfr, DNS_DIFFOP_ADD, name, ttl, rdata));
|
2023-07-06 14:00:48 +10:00
|
|
|
atomic_store(&xfr->state, XFRST_IXFR_ADD);
|
1999-08-20 05:35:16 +00:00
|
|
|
break;
|
2000-08-01 01:33:37 +00:00
|
|
|
|
1999-08-20 05:35:16 +00:00
|
|
|
case XFRST_IXFR_ADD:
|
|
|
|
if (rdata->type == dns_rdatatype_soa) {
|
2018-03-28 14:19:37 +02:00
|
|
|
uint32_t soa_serial = dns_soa_getserial(rdata);
|
2023-10-13 12:16:37 +02:00
|
|
|
if (soa_serial == atomic_load_relaxed(&xfr->end_serial))
|
|
|
|
{
|
2004-09-16 04:54:03 +00:00
|
|
|
CHECK(ixfr_commit(xfr));
|
2023-07-06 14:00:48 +10:00
|
|
|
atomic_store(&xfr->state, XFRST_IXFR_END);
|
1999-08-20 05:35:16 +00:00
|
|
|
break;
|
2002-09-24 01:04:03 +00:00
|
|
|
} else if (soa_serial != xfr->ixfr.current_serial) {
|
2023-09-01 10:17:00 +10:00
|
|
|
xfrin_log(xfr, ISC_LOG_NOTICE,
|
2002-09-24 01:04:03 +00:00
|
|
|
"IXFR out of sync: "
|
|
|
|
"expected serial %u, got %u",
|
|
|
|
xfr->ixfr.current_serial, soa_serial);
|
2023-10-12 17:44:51 +02:00
|
|
|
result = DNS_R_FORMERR;
|
|
|
|
goto failure;
|
1999-08-20 05:35:16 +00:00
|
|
|
} else {
|
2004-09-16 04:54:03 +00:00
|
|
|
CHECK(ixfr_commit(xfr));
|
2023-07-06 14:00:48 +10:00
|
|
|
atomic_store(&xfr->state, XFRST_IXFR_DELSOA);
|
1999-08-20 05:35:16 +00:00
|
|
|
goto redo;
|
|
|
|
}
|
|
|
|
}
|
2002-11-12 20:16:30 +00:00
|
|
|
if (rdata->type == dns_rdatatype_ns &&
|
2022-11-02 19:33:14 +01:00
|
|
|
dns_name_iswildcard(name))
|
|
|
|
{
|
2023-10-12 17:44:51 +02:00
|
|
|
result = DNS_R_INVALIDNS;
|
|
|
|
goto failure;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
1999-08-20 05:35:16 +00:00
|
|
|
CHECK(ixfr_putdata(xfr, DNS_DIFFOP_ADD, name, ttl, rdata));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case XFRST_AXFR:
|
2001-06-05 23:43:15 +00:00
|
|
|
/*
|
2001-06-07 20:11:30 +00:00
|
|
|
* Old BINDs sent cross class A records for non IN classes.
|
2001-06-05 23:43:15 +00:00
|
|
|
*/
|
|
|
|
if (rdata->type == dns_rdatatype_a &&
|
|
|
|
rdata->rdclass != xfr->rdclass &&
|
|
|
|
xfr->rdclass != dns_rdataclass_in)
|
|
|
|
{
|
|
|
|
break;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
1999-08-20 05:35:16 +00:00
|
|
|
CHECK(axfr_putdata(xfr, DNS_DIFFOP_ADD, name, ttl, rdata));
|
|
|
|
if (rdata->type == dns_rdatatype_soa) {
|
2021-03-15 15:43:26 +11:00
|
|
|
/*
|
|
|
|
* Use dns_rdata_compare instead of memcmp to
|
|
|
|
* allow for case differences.
|
|
|
|
*/
|
|
|
|
if (dns_rdata_compare(rdata, &xfr->firstsoa) != 0) {
|
2023-09-01 10:17:00 +10:00
|
|
|
xfrin_log(xfr, ISC_LOG_NOTICE,
|
2021-03-15 15:43:26 +11:00
|
|
|
"start and ending SOA records "
|
|
|
|
"mismatch");
|
2023-10-12 17:44:51 +02:00
|
|
|
result = DNS_R_FORMERR;
|
|
|
|
goto failure;
|
2021-03-15 15:43:26 +11:00
|
|
|
}
|
2023-10-13 14:41:22 +02:00
|
|
|
axfr_commit(xfr);
|
2023-07-06 14:00:48 +10:00
|
|
|
atomic_store(&xfr->state, XFRST_AXFR_END);
|
1999-08-20 05:35:16 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
2011-02-19 01:24:46 +00:00
|
|
|
case XFRST_AXFR_END:
|
|
|
|
case XFRST_IXFR_END:
|
2023-10-12 17:44:51 +02:00
|
|
|
result = DNS_R_EXTRADATA;
|
|
|
|
goto failure;
|
1999-08-20 05:35:16 +00:00
|
|
|
default:
|
2021-10-11 12:50:17 +02:00
|
|
|
UNREACHABLE();
|
1999-08-20 05:35:16 +00:00
|
|
|
}
|
2000-04-06 22:03:35 +00:00
|
|
|
result = ISC_R_SUCCESS;
|
1999-08-20 05:35:16 +00:00
|
|
|
failure:
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2024-11-05 10:28:37 +00:00
|
|
|
void
|
2000-05-14 20:01:34 +00:00
|
|
|
dns_xfrin_create(dns_zone_t *zone, dns_rdatatype_t xfrtype,
|
2024-06-07 14:47:55 +00:00
|
|
|
uint32_t ixfr_maxdiffs, const isc_sockaddr_t *primaryaddr,
|
2023-01-05 22:18:55 -08:00
|
|
|
const isc_sockaddr_t *sourceaddr, dns_tsigkey_t *tsigkey,
|
2023-08-23 10:46:44 +00:00
|
|
|
dns_transport_type_t soa_transport_type,
|
2023-01-05 22:18:55 -08:00
|
|
|
dns_transport_t *transport, isc_tlsctx_cache_t *tlsctx_cache,
|
2024-11-05 10:28:37 +00:00
|
|
|
isc_mem_t *mctx, dns_xfrin_t **xfrp) {
|
2000-05-14 20:01:34 +00:00
|
|
|
dns_name_t *zonename = dns_zone_getorigin(zone);
|
2023-02-23 10:29:33 -08:00
|
|
|
dns_xfrin_t *xfr = NULL;
|
1999-10-14 00:05:02 +00:00
|
|
|
dns_db_t *db = NULL;
|
2024-03-04 13:21:35 +01:00
|
|
|
isc_loop_t *loop = NULL;
|
1999-08-20 05:35:16 +00:00
|
|
|
|
2000-05-14 20:01:34 +00:00
|
|
|
REQUIRE(xfrp != NULL && *xfrp == NULL);
|
2021-10-05 11:28:24 +02:00
|
|
|
REQUIRE(isc_sockaddr_getport(primaryaddr) != 0);
|
2024-11-07 11:44:13 +00:00
|
|
|
REQUIRE(zone != NULL);
|
|
|
|
REQUIRE(dns_zone_getview(zone) != NULL);
|
2024-03-04 13:21:35 +01:00
|
|
|
|
|
|
|
loop = dns_zone_getloop(zone);
|
2000-04-08 04:42:42 +00:00
|
|
|
|
2000-06-01 18:04:37 +00:00
|
|
|
(void)dns_zone_getdb(zone, &db);
|
2000-08-01 01:33:37 +00:00
|
|
|
|
2006-07-19 00:53:42 +00:00
|
|
|
if (xfrtype == dns_rdatatype_soa || xfrtype == dns_rdatatype_ixfr) {
|
|
|
|
REQUIRE(db != NULL);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2006-07-19 00:53:42 +00:00
|
|
|
|
2024-03-04 13:21:35 +01:00
|
|
|
xfrin_create(mctx, zone, db, loop, zonename, dns_zone_getclass(zone),
|
2024-06-07 14:47:55 +00:00
|
|
|
xfrtype, ixfr_maxdiffs, primaryaddr, sourceaddr, tsigkey,
|
2024-03-04 13:21:35 +01:00
|
|
|
soa_transport_type, transport, tlsctx_cache, &xfr);
|
1999-08-20 05:35:16 +00:00
|
|
|
|
Log a message when a transferred mirror zone comes into effect
Log a message when a mirror zone is successfully transferred and
verified, but only if no database for that zone was yet loaded at the
time the transfer was initiated.
This could have been implemented in a simpler manner, e.g. by modifying
zone_replacedb(), but (due to the calling order of the functions
involved in finalizing a zone transfer) that would cause the resulting
logs to suggest that a mirror zone comes into effect before its transfer
is finished, which would be confusing given the nature of mirror zones
and the fact that no message is logged upon successful mirror zone
verification.
Once the dns_zone_replacedb() call in axfr_finalize() is made, it
becomes impossible to determine whether the transferred zone had a
database attached before the transfer was started. Thus, that check is
instead performed when the transfer context is first created and the
result of this check is passed around in a field of the transfer context
structure. If it turns out to be desired, the relevant log message is
then emitted just before the transfer context is freed.
Taking this approach means that the log message added by this commit is
not timed precisely, i.e. mirror zone data may be used before this
message is logged. However, that can only be fixed by logging the
message inside zone_replacedb(), which causes arguably more dire issues
discussed above.
dns_zone_isloaded() is not used to double-check that transferred zone
data was correctly loaded since the 'shutdown_result' field of the zone
transfer context will not be set to ISC_R_SUCCESS unless axfr_finalize()
succeeds (and that in turn will not happen unless dns_zone_replacedb()
succeeds).
2019-01-16 15:31:48 +01:00
|
|
|
if (db != NULL) {
|
|
|
|
xfr->zone_had_db = true;
|
2024-11-05 10:28:37 +00:00
|
|
|
dns_db_detach(&db);
|
Log a message when a transferred mirror zone comes into effect
Log a message when a mirror zone is successfully transferred and
verified, but only if no database for that zone was yet loaded at the
time the transfer was initiated.
This could have been implemented in a simpler manner, e.g. by modifying
zone_replacedb(), but (due to the calling order of the functions
involved in finalizing a zone transfer) that would cause the resulting
logs to suggest that a mirror zone comes into effect before its transfer
is finished, which would be confusing given the nature of mirror zones
and the fact that no message is logged upon successful mirror zone
verification.
Once the dns_zone_replacedb() call in axfr_finalize() is made, it
becomes impossible to determine whether the transferred zone had a
database attached before the transfer was started. Thus, that check is
instead performed when the transfer context is first created and the
result of this check is passed around in a field of the transfer context
structure. If it turns out to be desired, the relevant log message is
then emitted just before the transfer context is freed.
Taking this approach means that the log message added by this commit is
not timed precisely, i.e. mirror zone data may be used before this
message is logged. However, that can only be fixed by logging the
message inside zone_replacedb(), which causes arguably more dire issues
discussed above.
dns_zone_isloaded() is not used to double-check that transferred zone
data was correctly loaded since the 'shutdown_result' field of the zone
transfer context will not be set to ISC_R_SUCCESS unless axfr_finalize()
succeeds (and that in turn will not happen unless dns_zone_replacedb()
succeeds).
2019-01-16 15:31:48 +01:00
|
|
|
}
|
|
|
|
|
2000-01-28 23:48:58 +00:00
|
|
|
*xfrp = xfr;
|
2024-11-05 10:28:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t
|
|
|
|
dns_xfrin_start(dns_xfrin_t *xfr, dns_xfrindone_t done) {
|
|
|
|
isc_result_t result;
|
|
|
|
|
|
|
|
REQUIRE(xfr != NULL);
|
|
|
|
REQUIRE(xfr->zone != NULL);
|
|
|
|
REQUIRE(done != NULL);
|
|
|
|
|
|
|
|
xfr->done = done;
|
1999-12-13 03:01:53 +00:00
|
|
|
|
2020-09-06 00:38:50 -07:00
|
|
|
result = xfrin_start(xfr);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
2024-08-19 10:14:19 +02:00
|
|
|
xfr->done = NULL;
|
2024-11-05 10:28:37 +00:00
|
|
|
xfrin_fail(xfr, result, "zone transfer start failed");
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2020-10-09 16:34:22 -07:00
|
|
|
|
2000-01-28 23:48:58 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2023-04-05 22:35:00 +02:00
|
|
|
static void
|
|
|
|
xfrin_timedout(void *xfr) {
|
|
|
|
REQUIRE(VALID_XFRIN(xfr));
|
|
|
|
|
|
|
|
xfrin_fail(xfr, ISC_R_TIMEDOUT, "maximum transfer time exceeded");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
xfrin_idledout(void *xfr) {
|
|
|
|
REQUIRE(VALID_XFRIN(xfr));
|
|
|
|
|
|
|
|
xfrin_fail(xfr, ISC_R_TIMEDOUT, "maximum idle time exceeded");
|
|
|
|
}
|
|
|
|
|
2024-06-10 16:48:26 +00:00
|
|
|
static void
|
|
|
|
xfrin_minratecheck(void *arg) {
|
|
|
|
dns_xfrin_t *xfr = arg;
|
|
|
|
|
|
|
|
REQUIRE(VALID_XFRIN(xfr));
|
|
|
|
|
|
|
|
const uint64_t nbytes = atomic_load_relaxed(&xfr->nbytes);
|
|
|
|
const uint64_t min = dns_zone_getminxfrratebytesin(xfr->zone);
|
2024-11-27 10:34:40 +00:00
|
|
|
uint64_t rate = nbytes - xfr->nbytes_saved;
|
2024-06-10 16:48:26 +00:00
|
|
|
|
2024-11-27 10:34:40 +00:00
|
|
|
if (rate < min) {
|
2024-06-10 16:48:26 +00:00
|
|
|
isc_timer_stop(xfr->min_rate_timer);
|
|
|
|
xfrin_fail(xfr, ISC_R_TIMEDOUT,
|
|
|
|
"minimum transfer rate reached");
|
|
|
|
} else {
|
|
|
|
xfr->nbytes_saved = nbytes;
|
2024-11-27 10:34:40 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Calculate and store for the statistics channel the transfer
|
|
|
|
* rate in bytes-per-second for the latest interval.
|
|
|
|
*/
|
|
|
|
rate /= dns_zone_getminxfrratesecondsin(xfr->zone);
|
|
|
|
atomic_store_relaxed(&xfr->rate_bytes_per_second, rate);
|
2024-06-10 16:48:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-30 14:56:32 +00:00
|
|
|
isc_time_t
|
2023-09-22 15:38:14 +00:00
|
|
|
dns_xfrin_getstarttime(dns_xfrin_t *xfr) {
|
2023-05-30 14:56:32 +00:00
|
|
|
REQUIRE(VALID_XFRIN(xfr));
|
|
|
|
|
2023-10-13 12:16:37 +02:00
|
|
|
return atomic_load_relaxed(&xfr->start);
|
2023-05-30 14:56:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
dns_xfrin_getstate(const dns_xfrin_t *xfr, const char **statestr,
|
|
|
|
bool *is_first_data_received, bool *is_ixfr) {
|
|
|
|
xfrin_state_t state;
|
|
|
|
|
|
|
|
REQUIRE(VALID_XFRIN(xfr));
|
|
|
|
REQUIRE(statestr != NULL && *statestr == NULL);
|
|
|
|
REQUIRE(is_ixfr != NULL);
|
|
|
|
|
2023-07-06 14:00:48 +10:00
|
|
|
state = atomic_load(&xfr->state);
|
2023-05-30 14:56:32 +00:00
|
|
|
*statestr = "";
|
|
|
|
*is_first_data_received = (state > XFRST_FIRSTDATA);
|
2023-07-06 14:00:48 +10:00
|
|
|
*is_ixfr = atomic_load(&xfr->is_ixfr);
|
2023-05-30 14:56:32 +00:00
|
|
|
|
|
|
|
switch (state) {
|
|
|
|
case XFRST_SOAQUERY:
|
|
|
|
*statestr = "SOA Query";
|
|
|
|
break;
|
|
|
|
case XFRST_GOTSOA:
|
|
|
|
*statestr = "Got SOA";
|
|
|
|
break;
|
2023-09-19 09:35:20 +00:00
|
|
|
case XFRST_ZONEXFRREQUEST:
|
|
|
|
*statestr = "Zone Transfer Request";
|
2023-05-30 14:56:32 +00:00
|
|
|
break;
|
|
|
|
case XFRST_FIRSTDATA:
|
|
|
|
*statestr = "First Data";
|
|
|
|
break;
|
|
|
|
case XFRST_IXFR_DELSOA:
|
|
|
|
case XFRST_IXFR_DEL:
|
|
|
|
case XFRST_IXFR_ADDSOA:
|
|
|
|
case XFRST_IXFR_ADD:
|
|
|
|
*statestr = "Receiving IXFR Data";
|
|
|
|
break;
|
|
|
|
case XFRST_IXFR_END:
|
|
|
|
*statestr = "Finalizing IXFR";
|
|
|
|
break;
|
|
|
|
case XFRST_AXFR:
|
|
|
|
*statestr = "Receiving AXFR Data";
|
|
|
|
break;
|
|
|
|
case XFRST_AXFR_END:
|
|
|
|
*statestr = "Finalizing AXFR";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t
|
2023-09-22 15:38:14 +00:00
|
|
|
dns_xfrin_getendserial(dns_xfrin_t *xfr) {
|
2023-05-30 14:56:32 +00:00
|
|
|
REQUIRE(VALID_XFRIN(xfr));
|
|
|
|
|
2023-10-13 12:16:37 +02:00
|
|
|
return atomic_load_relaxed(&xfr->end_serial);
|
2023-05-30 14:56:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2023-07-06 14:00:48 +10:00
|
|
|
dns_xfrin_getstats(dns_xfrin_t *xfr, unsigned int *nmsgp, unsigned int *nrecsp,
|
2024-11-27 10:34:40 +00:00
|
|
|
uint64_t *nbytesp, uint64_t *ratep) {
|
2023-05-30 14:56:32 +00:00
|
|
|
REQUIRE(VALID_XFRIN(xfr));
|
|
|
|
REQUIRE(nmsgp != NULL && nrecsp != NULL && nbytesp != NULL);
|
|
|
|
|
2024-11-27 10:34:40 +00:00
|
|
|
uint64_t rate = atomic_load_relaxed(&xfr->rate_bytes_per_second);
|
|
|
|
if (rate == 0) {
|
|
|
|
/*
|
|
|
|
* Likely the first 'min-transfer-rate-in <bytes> <minutes>'
|
|
|
|
* minutes interval hasn't passed yet. Calculate the overall
|
|
|
|
* average transfer rate instead.
|
|
|
|
*/
|
|
|
|
isc_time_t now = isc_time_now();
|
|
|
|
isc_time_t start = atomic_load_relaxed(&xfr->start);
|
|
|
|
uint64_t sec = isc_time_microdiff(&now, &start) / US_PER_SEC;
|
|
|
|
if (sec > 0) {
|
|
|
|
rate = atomic_load_relaxed(&xfr->nbytes) / sec;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-13 12:16:37 +02:00
|
|
|
SET_IF_NOT_NULL(nmsgp, atomic_load_relaxed(&xfr->nmsg));
|
|
|
|
SET_IF_NOT_NULL(nrecsp, atomic_load_relaxed(&xfr->nrecs));
|
|
|
|
SET_IF_NOT_NULL(nbytesp, atomic_load_relaxed(&xfr->nbytes));
|
2024-11-27 10:34:40 +00:00
|
|
|
SET_IF_NOT_NULL(ratep, rate);
|
2023-05-30 14:56:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const isc_sockaddr_t *
|
|
|
|
dns_xfrin_getsourceaddr(const dns_xfrin_t *xfr) {
|
|
|
|
REQUIRE(VALID_XFRIN(xfr));
|
|
|
|
|
|
|
|
return &xfr->sourceaddr;
|
|
|
|
}
|
|
|
|
|
|
|
|
const isc_sockaddr_t *
|
|
|
|
dns_xfrin_getprimaryaddr(const dns_xfrin_t *xfr) {
|
|
|
|
REQUIRE(VALID_XFRIN(xfr));
|
|
|
|
|
|
|
|
return &xfr->primaryaddr;
|
|
|
|
}
|
|
|
|
|
2023-08-23 10:46:44 +00:00
|
|
|
dns_transport_type_t
|
|
|
|
dns_xfrin_gettransporttype(const dns_xfrin_t *xfr) {
|
2023-05-30 14:56:32 +00:00
|
|
|
REQUIRE(VALID_XFRIN(xfr));
|
|
|
|
|
2023-08-23 10:46:44 +00:00
|
|
|
if (xfr->transport != NULL) {
|
|
|
|
return dns_transport_get_type(xfr->transport);
|
|
|
|
}
|
|
|
|
|
|
|
|
return DNS_TRANSPORT_TCP;
|
|
|
|
}
|
|
|
|
|
|
|
|
dns_transport_type_t
|
2023-09-22 15:38:14 +00:00
|
|
|
dns_xfrin_getsoatransporttype(dns_xfrin_t *xfr) {
|
2023-08-23 10:46:44 +00:00
|
|
|
REQUIRE(VALID_XFRIN(xfr));
|
|
|
|
|
2023-10-13 12:16:37 +02:00
|
|
|
return atomic_load_relaxed(&xfr->soa_transport_type);
|
2023-05-30 14:56:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const dns_name_t *
|
|
|
|
dns_xfrin_gettsigkeyname(const dns_xfrin_t *xfr) {
|
|
|
|
REQUIRE(VALID_XFRIN(xfr));
|
|
|
|
|
|
|
|
if (xfr->tsigkey == NULL || xfr->tsigkey->key == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return dst_key_name(xfr->tsigkey->key);
|
|
|
|
}
|
|
|
|
|
2024-06-11 10:57:15 +00:00
|
|
|
static void
|
|
|
|
xfrin_shutdown(void *arg) {
|
|
|
|
dns_xfrin_t *xfr = arg;
|
|
|
|
|
|
|
|
REQUIRE(VALID_XFRIN(xfr));
|
|
|
|
|
xfrin: refactor and fix the ISC_R_CANCELED case handling
Previously a ISC_R_CANCELED result code switch-case has been added to
the zone.c:zone_xfrdone() function, which did two things:
1. Schedule a new zone transfer if there's a scheduled force reload of
the zone.
2. Reset the primaries list.
This proved to be not a well-thought change and causes problems,
because the ISC_R_CANCELED code is used not only when the whole transfer
is canceled, but also when, for example, a particular primary server is
unreachable, and named still needs to continue the transfer process by
trying the next server, which it now no longer does in some cases. To
solve this issue, three changes are made:
1. Make sure dns_zone_refresh() runs on the zone's loop, so that the
sequential calls of dns_zone_stopxfr() and dns_zone_forcexfr()
functions (like done in 'rndc retransfer -force') run in intended
order and don't race with each other.
2. Since starting the new transfer is now guaranteed to run after the
previous transfer is shut down (see the previous change), remove the
special handling of the ISC_R_CANCELED case, and let the default
handler to handle it like before. This will bring back the ability to
try the next primary if the current one was interrupted with a
ISC_R_CANCELED result code.
3. Change the xfrin.c:xfrin_shutdown() function to pass the
ISC_R_SHUTTINGDOWN result code instead of ISC_R_CANCELED, as it makes
more sense.
2024-11-26 12:06:03 +00:00
|
|
|
xfrin_fail(xfr, ISC_R_SHUTTINGDOWN, "shut down");
|
2024-06-11 10:57:15 +00:00
|
|
|
dns_xfrin_detach(&xfr);
|
|
|
|
}
|
|
|
|
|
2000-06-01 13:48:55 +00:00
|
|
|
void
|
2023-02-23 10:29:33 -08:00
|
|
|
dns_xfrin_shutdown(dns_xfrin_t *xfr) {
|
2020-09-06 00:38:50 -07:00
|
|
|
REQUIRE(VALID_XFRIN(xfr));
|
2021-04-16 11:08:05 +02:00
|
|
|
|
2024-06-11 10:57:15 +00:00
|
|
|
if (xfr->loop != isc_loop()) {
|
|
|
|
dns_xfrin_ref(xfr);
|
|
|
|
isc_async_run(xfr->loop, xfrin_shutdown, xfr);
|
|
|
|
} else {
|
xfrin: refactor and fix the ISC_R_CANCELED case handling
Previously a ISC_R_CANCELED result code switch-case has been added to
the zone.c:zone_xfrdone() function, which did two things:
1. Schedule a new zone transfer if there's a scheduled force reload of
the zone.
2. Reset the primaries list.
This proved to be not a well-thought change and causes problems,
because the ISC_R_CANCELED code is used not only when the whole transfer
is canceled, but also when, for example, a particular primary server is
unreachable, and named still needs to continue the transfer process by
trying the next server, which it now no longer does in some cases. To
solve this issue, three changes are made:
1. Make sure dns_zone_refresh() runs on the zone's loop, so that the
sequential calls of dns_zone_stopxfr() and dns_zone_forcexfr()
functions (like done in 'rndc retransfer -force') run in intended
order and don't race with each other.
2. Since starting the new transfer is now guaranteed to run after the
previous transfer is shut down (see the previous change), remove the
special handling of the ISC_R_CANCELED case, and let the default
handler to handle it like before. This will bring back the ability to
try the next primary if the current one was interrupted with a
ISC_R_CANCELED result code.
3. Change the xfrin.c:xfrin_shutdown() function to pass the
ISC_R_SHUTTINGDOWN result code instead of ISC_R_CANCELED, as it makes
more sense.
2024-11-26 12:06:03 +00:00
|
|
|
xfrin_fail(xfr, ISC_R_SHUTTINGDOWN, "shut down");
|
2024-06-11 10:57:15 +00:00
|
|
|
}
|
2000-01-28 23:48:58 +00:00
|
|
|
}
|
|
|
|
|
2023-02-23 10:29:33 -08:00
|
|
|
#if DNS_XFRIN_TRACE
|
|
|
|
ISC_REFCOUNT_TRACE_IMPL(dns_xfrin, xfrin_destroy);
|
|
|
|
#else
|
|
|
|
ISC_REFCOUNT_IMPL(dns_xfrin, xfrin_destroy);
|
|
|
|
#endif
|
1999-08-20 05:35:16 +00:00
|
|
|
|
|
|
|
static void
|
2023-02-23 10:29:33 -08:00
|
|
|
xfrin_cancelio(dns_xfrin_t *xfr) {
|
2023-10-13 14:41:22 +02:00
|
|
|
if (xfr->dispentry != NULL) {
|
|
|
|
dns_dispatch_done(&xfr->dispentry);
|
|
|
|
}
|
|
|
|
if (xfr->disp != NULL) {
|
|
|
|
dns_dispatch_detach(&xfr->disp);
|
|
|
|
}
|
2000-10-12 03:32:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-02-23 10:29:33 -08:00
|
|
|
xfrin_reset(dns_xfrin_t *xfr) {
|
2000-10-12 03:32:14 +00:00
|
|
|
REQUIRE(VALID_XFRIN(xfr));
|
|
|
|
|
|
|
|
xfrin_log(xfr, ISC_LOG_INFO, "resetting");
|
|
|
|
|
|
|
|
if (xfr->lasttsig != NULL) {
|
|
|
|
isc_buffer_free(&xfr->lasttsig);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2000-10-12 03:32:14 +00:00
|
|
|
|
|
|
|
dns_diff_clear(&xfr->diff);
|
2024-06-07 14:47:55 +00:00
|
|
|
xfr->ixfr.diffs = 0;
|
|
|
|
|
2000-10-12 03:32:14 +00:00
|
|
|
if (xfr->ixfr.journal != NULL) {
|
|
|
|
dns_journal_destroy(&xfr->ixfr.journal);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2000-10-12 03:32:14 +00:00
|
|
|
|
2012-06-20 14:13:12 -05:00
|
|
|
if (xfr->axfr.add_private != NULL) {
|
|
|
|
(void)dns_db_endload(xfr->db, &xfr->axfr);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2000-10-12 03:32:14 +00:00
|
|
|
|
|
|
|
if (xfr->ver != NULL) {
|
2018-04-17 08:29:14 -07:00
|
|
|
dns_db_closeversion(xfr->db, &xfr->ver, false);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2000-10-12 03:32:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-02-23 10:29:33 -08:00
|
|
|
xfrin_fail(dns_xfrin_t *xfr, isc_result_t result, const char *msg) {
|
2024-03-04 13:21:35 +01:00
|
|
|
REQUIRE(VALID_XFRIN(xfr));
|
|
|
|
|
2023-02-21 20:14:30 -08:00
|
|
|
dns_xfrin_ref(xfr);
|
|
|
|
|
2021-04-16 11:08:05 +02:00
|
|
|
/* Make sure only the first xfrin_fail() trumps */
|
|
|
|
if (atomic_compare_exchange_strong(&xfr->shuttingdown, &(bool){ false },
|
2022-11-02 19:33:14 +01:00
|
|
|
true))
|
|
|
|
{
|
2024-08-16 16:53:38 +09:00
|
|
|
if (result != DNS_R_UPTODATE) {
|
2021-04-16 11:08:05 +02:00
|
|
|
xfrin_log(xfr, ISC_LOG_ERROR, "%s: %s", msg,
|
|
|
|
isc_result_totext(result));
|
2024-06-11 10:53:06 +00:00
|
|
|
if (atomic_load(&xfr->is_ixfr) &&
|
|
|
|
result != ISC_R_CANCELED &&
|
|
|
|
result != ISC_R_SHUTTINGDOWN)
|
|
|
|
{
|
2023-02-21 20:14:30 -08:00
|
|
|
/*
|
|
|
|
* Pass special result code to force AXFR retry
|
2021-04-16 11:08:05 +02:00
|
|
|
*/
|
|
|
|
result = DNS_R_BADIXFR;
|
|
|
|
}
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2023-10-13 14:41:22 +02:00
|
|
|
|
2021-04-16 11:08:05 +02:00
|
|
|
xfrin_cancelio(xfr);
|
2023-02-21 20:14:30 -08:00
|
|
|
|
2023-10-13 14:41:22 +02:00
|
|
|
xfrin_end(xfr, result);
|
2000-10-12 03:32:14 +00:00
|
|
|
}
|
2023-02-21 20:14:30 -08:00
|
|
|
|
|
|
|
dns_xfrin_detach(&xfr);
|
1999-08-20 05:35:16 +00:00
|
|
|
}
|
|
|
|
|
2020-10-09 16:34:22 -07:00
|
|
|
static void
|
2024-03-04 13:21:35 +01:00
|
|
|
xfrin_create(isc_mem_t *mctx, dns_zone_t *zone, dns_db_t *db, isc_loop_t *loop,
|
2020-10-09 16:38:30 -07:00
|
|
|
dns_name_t *zonename, dns_rdataclass_t rdclass,
|
2024-06-07 14:47:55 +00:00
|
|
|
dns_rdatatype_t reqtype, uint32_t ixfr_maxdiffs,
|
|
|
|
const isc_sockaddr_t *primaryaddr,
|
2023-01-05 22:18:55 -08:00
|
|
|
const isc_sockaddr_t *sourceaddr, dns_tsigkey_t *tsigkey,
|
2023-08-23 10:46:44 +00:00
|
|
|
dns_transport_type_t soa_transport_type,
|
2023-01-05 22:18:55 -08:00
|
|
|
dns_transport_t *transport, isc_tlsctx_cache_t *tlsctx_cache,
|
2023-02-23 10:29:33 -08:00
|
|
|
dns_xfrin_t **xfrp) {
|
|
|
|
dns_xfrin_t *xfr = NULL;
|
2000-08-01 01:33:37 +00:00
|
|
|
|
1999-08-20 05:35:16 +00:00
|
|
|
xfr = isc_mem_get(mctx, sizeof(*xfr));
|
2023-04-05 22:35:00 +02:00
|
|
|
*xfr = (dns_xfrin_t){
|
|
|
|
.shutdown_result = ISC_R_UNSET,
|
|
|
|
.rdclass = rdclass,
|
|
|
|
.reqtype = reqtype,
|
2024-06-07 14:47:55 +00:00
|
|
|
.ixfr.maxdiffs = ixfr_maxdiffs,
|
2023-04-05 22:35:00 +02:00
|
|
|
.maxrecords = dns_zone_getmaxrecords(zone),
|
|
|
|
.primaryaddr = *primaryaddr,
|
|
|
|
.sourceaddr = *sourceaddr,
|
2023-08-23 10:46:44 +00:00
|
|
|
.soa_transport_type = soa_transport_type,
|
2023-04-05 22:35:00 +02:00
|
|
|
.firstsoa = DNS_RDATA_INIT,
|
2023-07-04 14:22:29 +10:00
|
|
|
.edns = true,
|
2024-08-19 10:14:19 +02:00
|
|
|
.references = 1,
|
2023-04-05 22:35:00 +02:00
|
|
|
.magic = XFRIN_MAGIC,
|
|
|
|
};
|
2020-09-06 00:38:50 -07:00
|
|
|
|
2024-03-04 13:21:35 +01:00
|
|
|
isc_loop_attach(loop, &xfr->loop);
|
2013-03-08 14:38:03 +11:00
|
|
|
isc_mem_attach(mctx, &xfr->mctx);
|
2000-08-31 17:48:47 +00:00
|
|
|
dns_zone_iattach(zone, &xfr->zone);
|
2023-02-21 20:14:30 -08:00
|
|
|
dns_view_weakattach(dns_zone_getview(zone), &xfr->view);
|
2025-02-21 12:09:39 +01:00
|
|
|
dns_name_init(&xfr->name);
|
2020-09-06 00:38:50 -07:00
|
|
|
|
2023-10-13 14:41:22 +02:00
|
|
|
__cds_wfcq_init(&xfr->diff_head, &xfr->diff_tail);
|
|
|
|
|
2023-07-06 14:00:48 +10:00
|
|
|
atomic_init(&xfr->is_ixfr, false);
|
2021-05-26 17:55:43 +10:00
|
|
|
|
1999-10-25 12:18:43 +00:00
|
|
|
if (db != NULL) {
|
|
|
|
dns_db_attach(db, &xfr->db);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2020-09-06 00:38:50 -07:00
|
|
|
|
1999-08-20 05:35:16 +00:00
|
|
|
dns_diff_init(xfr->mctx, &xfr->diff);
|
|
|
|
|
2006-07-19 00:53:42 +00:00
|
|
|
if (reqtype == dns_rdatatype_soa) {
|
2023-07-06 14:00:48 +10:00
|
|
|
atomic_init(&xfr->state, XFRST_SOAQUERY);
|
2006-07-19 00:53:42 +00:00
|
|
|
} else {
|
2023-09-19 09:35:20 +00:00
|
|
|
atomic_init(&xfr->state, XFRST_ZONEXFRREQUEST);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
1999-09-10 15:01:04 +00:00
|
|
|
|
2023-10-13 12:16:37 +02:00
|
|
|
atomic_init(&xfr->start, isc_time_now());
|
1999-09-10 15:01:04 +00:00
|
|
|
|
2000-07-21 23:00:31 +00:00
|
|
|
if (tsigkey != NULL) {
|
|
|
|
dns_tsigkey_attach(tsigkey, &xfr->tsigkey);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
1999-08-20 05:35:16 +00:00
|
|
|
|
2021-01-14 12:51:25 +01:00
|
|
|
if (transport != NULL) {
|
|
|
|
dns_transport_attach(transport, &xfr->transport);
|
|
|
|
}
|
|
|
|
|
2019-11-01 08:31:13 -05:00
|
|
|
dns_name_dup(zonename, mctx, &xfr->name);
|
2000-08-01 01:33:37 +00:00
|
|
|
|
2021-10-05 11:28:24 +02:00
|
|
|
INSIST(isc_sockaddr_pf(primaryaddr) == isc_sockaddr_pf(sourceaddr));
|
2001-04-10 23:54:03 +00:00
|
|
|
isc_sockaddr_setport(&xfr->sourceaddr, 0);
|
2000-08-01 01:33:37 +00:00
|
|
|
|
2013-09-25 09:57:34 +10:00
|
|
|
/*
|
|
|
|
* Reserve 2 bytes for TCP length at the beginning of the buffer.
|
|
|
|
*/
|
|
|
|
isc_buffer_init(&xfr->qbuffer, &xfr->qbuffer_data[2],
|
|
|
|
sizeof(xfr->qbuffer_data) - 2);
|
1999-08-20 05:35:16 +00:00
|
|
|
|
2021-12-23 16:08:41 +02:00
|
|
|
isc_tlsctx_cache_attach(tlsctx_cache, &xfr->tlsctx_cache);
|
|
|
|
|
2023-08-14 14:24:52 +02:00
|
|
|
dns_zone_name(xfr->zone, xfr->info, sizeof(xfr->info));
|
|
|
|
|
1999-08-20 05:35:16 +00:00
|
|
|
*xfrp = xfr;
|
|
|
|
}
|
|
|
|
|
2022-05-24 11:39:26 +03:00
|
|
|
static isc_result_t
|
2023-02-23 10:29:33 -08:00
|
|
|
xfrin_start(dns_xfrin_t *xfr) {
|
2023-02-21 20:14:30 -08:00
|
|
|
isc_result_t result = ISC_R_FAILURE;
|
2023-04-05 22:35:00 +02:00
|
|
|
isc_interval_t interval;
|
2025-02-18 14:44:29 +00:00
|
|
|
uint32_t primaries_timeout;
|
2022-05-24 11:39:26 +03:00
|
|
|
|
2023-02-21 20:14:30 -08:00
|
|
|
dns_xfrin_ref(xfr);
|
2022-05-24 11:39:26 +03:00
|
|
|
|
2023-10-18 13:07:24 -07:00
|
|
|
/* If this is a retry, we need to cancel the previous dispentry */
|
2023-10-20 08:14:27 +02:00
|
|
|
xfrin_cancelio(xfr);
|
|
|
|
|
|
|
|
dns_dispatchmgr_t *dispmgr = dns_view_getdispatchmgr(xfr->view);
|
|
|
|
if (dispmgr == NULL) {
|
|
|
|
result = ISC_R_SHUTTINGDOWN;
|
|
|
|
goto failure;
|
2024-10-30 09:23:33 +00:00
|
|
|
}
|
|
|
|
|
2025-07-14 17:12:35 +02:00
|
|
|
primaries_timeout = isc_nm_getprimariestimeout();
|
2024-10-30 09:23:33 +00:00
|
|
|
result = dns_dispatch_createtcp(dispmgr, &xfr->sourceaddr,
|
|
|
|
&xfr->primaryaddr, xfr->transport,
|
|
|
|
DNS_DISPATCHOPT_UNSHARED, &xfr->disp);
|
|
|
|
dns_dispatchmgr_detach(&dispmgr);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
goto failure;
|
2023-10-18 13:07:24 -07:00
|
|
|
}
|
|
|
|
|
2023-08-14 14:24:52 +02:00
|
|
|
LIBDNS_XFRIN_START(xfr, xfr->info);
|
2023-01-31 10:14:21 +01:00
|
|
|
|
2023-08-23 10:46:44 +00:00
|
|
|
/*
|
|
|
|
* 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
|
2023-09-19 09:35:20 +00:00
|
|
|
* be initiated starting from the XFRST_ZONEXFRREQUEST 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
|
2023-08-23 10:46:44 +00:00
|
|
|
* 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.
|
|
|
|
*/
|
2023-12-15 09:43:36 +00:00
|
|
|
atomic_store_relaxed(&xfr->soa_transport_type,
|
|
|
|
dns_xfrin_gettransporttype(xfr));
|
2023-08-23 10:46:44 +00:00
|
|
|
}
|
|
|
|
|
2024-10-30 09:23:33 +00:00
|
|
|
/*
|
2025-02-18 14:44:29 +00:00
|
|
|
* The read timeout timer is disabled on the dispatch level because
|
2024-10-30 09:23:33 +00:00
|
|
|
* the xfr module has its own timeouts.
|
|
|
|
*/
|
2025-02-18 14:44:29 +00:00
|
|
|
const unsigned int read_timeout = 0;
|
2024-10-30 09:23:33 +00:00
|
|
|
|
2025-02-18 14:44:29 +00:00
|
|
|
CHECK(dns_dispatch_add(xfr->disp, xfr->loop, 0, primaries_timeout,
|
|
|
|
read_timeout, &xfr->primaryaddr, xfr->transport,
|
2024-10-30 09:23:33 +00:00
|
|
|
xfr->tlsctx_cache, xfrin_connect_done,
|
|
|
|
xfrin_send_done, xfrin_recv_done, xfr, &xfr->id,
|
|
|
|
&xfr->dispentry));
|
2024-08-19 10:14:19 +02:00
|
|
|
|
2023-04-05 22:35:00 +02:00
|
|
|
/* Set the maximum timer */
|
2024-08-19 10:14:19 +02:00
|
|
|
if (xfr->max_time_timer == NULL) {
|
|
|
|
isc_timer_create(dns_zone_getloop(xfr->zone), xfrin_timedout,
|
|
|
|
xfr, &xfr->max_time_timer);
|
|
|
|
}
|
2023-04-05 22:35:00 +02:00
|
|
|
isc_interval_set(&interval, dns_zone_getmaxxfrin(xfr->zone), 0);
|
|
|
|
isc_timer_start(xfr->max_time_timer, isc_timertype_once, &interval);
|
|
|
|
|
|
|
|
/* Set the idle timer */
|
2024-08-19 10:14:19 +02:00
|
|
|
if (xfr->max_idle_timer == NULL) {
|
|
|
|
isc_timer_create(dns_zone_getloop(xfr->zone), xfrin_idledout,
|
|
|
|
xfr, &xfr->max_idle_timer);
|
|
|
|
}
|
2023-04-05 22:35:00 +02:00
|
|
|
isc_interval_set(&interval, dns_zone_getidlein(xfr->zone), 0);
|
|
|
|
isc_timer_start(xfr->max_idle_timer, isc_timertype_once, &interval);
|
|
|
|
|
2024-06-10 16:48:26 +00:00
|
|
|
/* Set the minimum transfer rate checking timer */
|
|
|
|
if (xfr->min_rate_timer == NULL) {
|
|
|
|
isc_timer_create(dns_zone_getloop(xfr->zone),
|
|
|
|
xfrin_minratecheck, xfr, &xfr->min_rate_timer);
|
|
|
|
}
|
|
|
|
isc_interval_set(&interval, dns_zone_getminxfrratesecondsin(xfr->zone),
|
|
|
|
0);
|
|
|
|
isc_timer_start(xfr->min_rate_timer, isc_timertype_ticker, &interval);
|
|
|
|
|
2022-05-24 11:39:26 +03:00
|
|
|
/*
|
2024-08-19 10:14:19 +02:00
|
|
|
* The connect has to be the last thing that is called before returning,
|
|
|
|
* as it can end synchronously and destroy the xfr object.
|
2022-05-24 11:39:26 +03:00
|
|
|
*/
|
2023-02-21 20:14:30 -08:00
|
|
|
CHECK(dns_dispatch_connect(xfr->dispentry));
|
2023-04-05 22:35:00 +02:00
|
|
|
|
2022-05-24 11:39:26 +03:00
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
|
|
|
|
failure:
|
2023-10-13 14:41:22 +02:00
|
|
|
xfrin_cancelio(xfr);
|
2023-02-21 20:14:30 -08:00
|
|
|
dns_xfrin_detach(&xfr);
|
|
|
|
|
2000-01-28 23:48:58 +00:00
|
|
|
return result;
|
1999-08-20 05:35:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX the resolver could use this, too */
|
|
|
|
|
1999-12-23 00:09:04 +00:00
|
|
|
static isc_result_t
|
2001-03-05 21:15:47 +00:00
|
|
|
render(dns_message_t *msg, isc_mem_t *mctx, isc_buffer_t *buf) {
|
|
|
|
dns_compress_t cctx;
|
1999-12-23 00:09:04 +00:00
|
|
|
isc_result_t result;
|
2000-06-01 18:04:37 +00:00
|
|
|
|
2022-06-23 21:53:46 +01:00
|
|
|
dns_compress_init(&cctx, mctx, 0);
|
2001-03-05 21:15:47 +00:00
|
|
|
CHECK(dns_message_renderbegin(msg, &cctx, buf));
|
1999-12-22 03:22:59 +00:00
|
|
|
CHECK(dns_message_rendersection(msg, DNS_SECTION_QUESTION, 0));
|
|
|
|
CHECK(dns_message_rendersection(msg, DNS_SECTION_ANSWER, 0));
|
|
|
|
CHECK(dns_message_rendersection(msg, DNS_SECTION_AUTHORITY, 0));
|
|
|
|
CHECK(dns_message_rendersection(msg, DNS_SECTION_ADDITIONAL, 0));
|
1999-08-20 05:35:16 +00:00
|
|
|
CHECK(dns_message_renderend(msg));
|
2000-04-06 22:03:35 +00:00
|
|
|
result = ISC_R_SUCCESS;
|
1999-08-20 05:35:16 +00:00
|
|
|
failure:
|
2022-06-23 21:53:46 +01:00
|
|
|
dns_compress_invalidate(&cctx);
|
1999-08-20 05:35:16 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
1999-08-27 18:30:59 +00:00
|
|
|
* A connection has been established.
|
1999-08-20 05:35:16 +00:00
|
|
|
*/
|
|
|
|
static void
|
2023-04-03 14:56:17 +02:00
|
|
|
xfrin_connect_done(isc_result_t result, isc_region_t *region ISC_ATTR_UNUSED,
|
|
|
|
void *arg) {
|
2023-02-21 20:14:30 -08:00
|
|
|
dns_xfrin_t *xfr = (dns_xfrin_t *)arg;
|
|
|
|
char addrtext[ISC_SOCKADDR_FORMATSIZE];
|
2015-11-02 20:13:13 -08:00
|
|
|
char signerbuf[DNS_NAME_FORMATSIZE];
|
|
|
|
const char *signer = "", *sep = "";
|
2020-09-06 00:38:50 -07:00
|
|
|
dns_zonemgr_t *zmgr = NULL;
|
2000-03-29 05:03:07 +00:00
|
|
|
|
2023-02-21 20:14:30 -08:00
|
|
|
REQUIRE(VALID_XFRIN(xfr));
|
2020-11-09 11:32:55 +01:00
|
|
|
|
2021-04-16 11:08:05 +02:00
|
|
|
if (atomic_load(&xfr->shuttingdown)) {
|
2020-11-09 11:32:55 +01:00
|
|
|
result = ISC_R_SHUTTINGDOWN;
|
2000-01-28 23:48:58 +00:00
|
|
|
}
|
2000-08-01 01:33:37 +00:00
|
|
|
|
2023-08-14 14:24:52 +02:00
|
|
|
LIBDNS_XFRIN_CONNECTED(xfr, xfr->info, result);
|
2023-01-31 10:14:21 +01:00
|
|
|
|
2023-02-21 20:14:30 -08:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
xfrin_fail(xfr, result, "failed to connect");
|
2023-04-03 14:56:17 +02:00
|
|
|
goto failure;
|
2023-02-21 20:14:30 -08:00
|
|
|
}
|
2020-09-06 00:38:50 -07:00
|
|
|
|
2023-04-03 14:56:17 +02:00
|
|
|
result = dns_dispatch_checkperm(xfr->disp);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
xfrin_fail(xfr, result, "connected but unable to transfer");
|
|
|
|
goto failure;
|
|
|
|
}
|
2021-08-30 17:13:00 +03:00
|
|
|
|
2013-09-21 17:12:39 +10:00
|
|
|
zmgr = dns_zone_getmgr(xfr->zone);
|
|
|
|
if (zmgr != NULL) {
|
2025-02-18 08:34:41 +00:00
|
|
|
dns_view_t *view = dns_zone_getview(xfr->zone);
|
|
|
|
dns_unreachcache_remove(view->unreachcache, &xfr->primaryaddr,
|
|
|
|
&xfr->sourceaddr);
|
2006-12-18 23:58:14 +00:00
|
|
|
}
|
|
|
|
|
2015-11-02 20:13:13 -08:00
|
|
|
if (xfr->tsigkey != NULL && xfr->tsigkey->key != NULL) {
|
|
|
|
dns_name_format(dst_key_name(xfr->tsigkey->key), signerbuf,
|
|
|
|
sizeof(signerbuf));
|
|
|
|
sep = " TSIG ";
|
|
|
|
signer = signerbuf;
|
|
|
|
}
|
|
|
|
|
2023-02-21 20:14:30 -08:00
|
|
|
isc_sockaddr_format(&xfr->primaryaddr, addrtext, sizeof(addrtext));
|
|
|
|
xfrin_log(xfr, ISC_LOG_INFO, "connected using %s%s%s", addrtext, sep,
|
2015-11-02 20:13:13 -08:00
|
|
|
signer);
|
2000-08-01 01:33:37 +00:00
|
|
|
|
2023-04-03 14:56:17 +02:00
|
|
|
result = xfrin_send_request(xfr);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
xfrin_fail(xfr, result, "connected but unable to send");
|
|
|
|
goto detach;
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
2020-09-06 00:38:50 -07:00
|
|
|
|
1999-08-27 18:30:59 +00:00
|
|
|
failure:
|
2023-04-03 14:56:17 +02:00
|
|
|
switch (result) {
|
|
|
|
case ISC_R_NETDOWN:
|
|
|
|
case ISC_R_HOSTDOWN:
|
|
|
|
case ISC_R_NETUNREACH:
|
|
|
|
case ISC_R_HOSTUNREACH:
|
|
|
|
case ISC_R_CONNREFUSED:
|
2023-07-20 09:16:03 +10:00
|
|
|
case ISC_R_TIMEDOUT:
|
2023-04-03 14:56:17 +02:00
|
|
|
/*
|
2025-02-18 08:34:41 +00:00
|
|
|
* Add the server to unreachable primaries cache if
|
2023-07-20 09:16:03 +10:00
|
|
|
* the server has a permanent networking error or
|
|
|
|
* the connection attempt as timed out.
|
2023-04-03 14:56:17 +02:00
|
|
|
*/
|
|
|
|
zmgr = dns_zone_getmgr(xfr->zone);
|
|
|
|
if (zmgr != NULL) {
|
2025-02-18 08:34:41 +00:00
|
|
|
dns_view_t *view = dns_zone_getview(xfr->zone);
|
|
|
|
dns_unreachcache_add(view->unreachcache,
|
|
|
|
&xfr->primaryaddr,
|
|
|
|
&xfr->sourceaddr);
|
2023-04-03 14:56:17 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* Retry sooner than in 10 minutes */
|
|
|
|
break;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2023-04-03 14:56:17 +02:00
|
|
|
|
|
|
|
detach:
|
2024-08-19 10:14:19 +02:00
|
|
|
dns_xfrin_detach(&xfr);
|
1999-08-27 18:30:59 +00:00
|
|
|
}
|
|
|
|
|
1999-10-28 19:11:33 +00:00
|
|
|
/*
|
|
|
|
* Convert a tuple into a dns_name_t suitable for inserting
|
|
|
|
* into the given dns_message_t.
|
|
|
|
*/
|
2022-07-29 12:40:45 +00:00
|
|
|
static void
|
1999-10-28 19:11:33 +00:00
|
|
|
tuple2msgname(dns_difftuple_t *tuple, dns_message_t *msg, dns_name_t **target) {
|
|
|
|
dns_rdata_t *rdata = NULL;
|
|
|
|
dns_rdatalist_t *rdl = NULL;
|
|
|
|
dns_rdataset_t *rds = NULL;
|
|
|
|
dns_name_t *name = NULL;
|
|
|
|
|
|
|
|
REQUIRE(target != NULL && *target == NULL);
|
|
|
|
|
2022-05-16 13:28:13 +02:00
|
|
|
dns_message_gettemprdata(msg, &rdata);
|
2000-10-25 04:26:57 +00:00
|
|
|
dns_rdata_clone(&tuple->rdata, rdata);
|
2000-08-01 01:33:37 +00:00
|
|
|
|
2022-05-16 13:28:13 +02:00
|
|
|
dns_message_gettemprdatalist(msg, &rdl);
|
1999-10-28 19:11:33 +00:00
|
|
|
rdl->type = tuple->rdata.type;
|
|
|
|
rdl->rdclass = tuple->rdata.rdclass;
|
|
|
|
rdl->ttl = tuple->ttl;
|
|
|
|
ISC_LIST_APPEND(rdl->rdata, rdata, link);
|
|
|
|
|
2022-05-16 13:28:13 +02:00
|
|
|
dns_message_gettemprdataset(msg, &rds);
|
2022-07-29 12:40:45 +00:00
|
|
|
dns_rdatalist_tordataset(rdl, rds);
|
1999-10-28 19:11:33 +00:00
|
|
|
|
2022-05-16 13:28:13 +02:00
|
|
|
dns_message_gettempname(msg, &name);
|
1999-10-28 19:11:33 +00:00
|
|
|
dns_name_clone(&tuple->name, name);
|
|
|
|
ISC_LIST_APPEND(name->list, rds, link);
|
|
|
|
|
|
|
|
*target = name;
|
|
|
|
}
|
2000-08-01 01:33:37 +00:00
|
|
|
|
2023-02-21 20:14:30 -08:00
|
|
|
static const char *
|
|
|
|
request_type(dns_xfrin_t *xfr) {
|
|
|
|
switch (xfr->reqtype) {
|
|
|
|
case dns_rdatatype_soa:
|
2024-10-17 13:22:48 -07:00
|
|
|
return "SOA";
|
2023-02-21 20:14:30 -08:00
|
|
|
case dns_rdatatype_axfr:
|
2024-10-17 13:22:48 -07:00
|
|
|
return "AXFR";
|
2023-02-21 20:14:30 -08:00
|
|
|
case dns_rdatatype_ixfr:
|
2024-10-17 13:22:48 -07:00
|
|
|
return "IXFR";
|
2023-02-21 20:14:30 -08:00
|
|
|
default:
|
|
|
|
ISC_UNREACHABLE();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-29 17:25:15 +10:00
|
|
|
static isc_result_t
|
|
|
|
add_opt(dns_message_t *message, uint16_t udpsize, bool reqnsid,
|
|
|
|
bool reqexpire) {
|
|
|
|
isc_result_t result;
|
|
|
|
dns_rdataset_t *rdataset = NULL;
|
|
|
|
dns_ednsopt_t ednsopts[DNS_EDNSOPTIONS];
|
|
|
|
int count = 0;
|
|
|
|
|
|
|
|
/* Set EDNS options if applicable. */
|
|
|
|
if (reqnsid) {
|
|
|
|
INSIST(count < DNS_EDNSOPTIONS);
|
|
|
|
ednsopts[count].code = DNS_OPT_NSID;
|
|
|
|
ednsopts[count].length = 0;
|
|
|
|
ednsopts[count].value = NULL;
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
if (reqexpire) {
|
|
|
|
INSIST(count < DNS_EDNSOPTIONS);
|
|
|
|
ednsopts[count].code = DNS_OPT_EXPIRE;
|
|
|
|
ednsopts[count].length = 0;
|
|
|
|
ednsopts[count].value = NULL;
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
result = dns_message_buildopt(message, &rdataset, 0, udpsize, 0,
|
|
|
|
ednsopts, count);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
return dns_message_setopt(message, rdataset);
|
|
|
|
}
|
|
|
|
|
1999-08-27 18:30:59 +00:00
|
|
|
/*
|
|
|
|
* Build an *XFR request and send its length prefix.
|
|
|
|
*/
|
1999-12-23 00:09:04 +00:00
|
|
|
static isc_result_t
|
2023-02-23 10:29:33 -08:00
|
|
|
xfrin_send_request(dns_xfrin_t *xfr) {
|
1999-12-23 00:09:04 +00:00
|
|
|
isc_result_t result;
|
1999-08-20 05:35:16 +00:00
|
|
|
isc_region_t region;
|
1999-10-28 01:10:38 +00:00
|
|
|
dns_rdataset_t *qrdataset = NULL;
|
1999-08-20 05:35:16 +00:00
|
|
|
dns_message_t *msg = NULL;
|
|
|
|
dns_difftuple_t *soatuple = NULL;
|
1999-10-28 00:02:08 +00:00
|
|
|
dns_name_t *qname = NULL;
|
1999-10-28 19:11:33 +00:00
|
|
|
dns_dbversion_t *ver = NULL;
|
1999-10-29 02:41:56 +00:00
|
|
|
dns_name_t *msgsoaname = NULL;
|
2023-07-04 14:22:29 +10:00
|
|
|
bool edns = xfr->edns;
|
2023-06-29 17:25:15 +10:00
|
|
|
bool reqnsid = xfr->view->requestnsid;
|
|
|
|
bool reqexpire = dns_zone_getrequestexpire(xfr->zone);
|
|
|
|
uint16_t udpsize = dns_view_getudpsize(xfr->view);
|
1999-10-28 01:10:38 +00:00
|
|
|
|
2023-08-14 14:24:52 +02:00
|
|
|
LIBDNS_XFRIN_RECV_SEND_REQUEST(xfr, xfr->info);
|
2023-01-31 10:14:21 +01:00
|
|
|
|
1999-10-28 01:10:38 +00:00
|
|
|
/* Create the request message */
|
2023-09-22 15:00:40 +02:00
|
|
|
dns_message_create(xfr->mctx, NULL, NULL, DNS_MESSAGE_INTENTRENDER,
|
|
|
|
&msg);
|
2000-11-03 21:36:37 +00:00
|
|
|
CHECK(dns_message_settsigkey(msg, xfr->tsigkey));
|
1999-10-28 01:10:38 +00:00
|
|
|
|
|
|
|
/* Create a name for the question section. */
|
2022-05-16 13:28:13 +02:00
|
|
|
dns_message_gettempname(msg, &qname);
|
1999-10-28 00:02:08 +00:00
|
|
|
dns_name_clone(&xfr->name, qname);
|
1999-10-28 01:10:38 +00:00
|
|
|
|
|
|
|
/* Formulate the question and attach it to the question name. */
|
2022-05-16 13:28:13 +02:00
|
|
|
dns_message_gettemprdataset(msg, &qrdataset);
|
1999-10-28 01:10:38 +00:00
|
|
|
dns_rdataset_makequestion(qrdataset, xfr->rdclass, xfr->reqtype);
|
|
|
|
ISC_LIST_APPEND(qname->list, qrdataset, link);
|
2000-11-03 21:36:37 +00:00
|
|
|
qrdataset = NULL;
|
2000-08-01 01:33:37 +00:00
|
|
|
|
1999-10-28 00:02:08 +00:00
|
|
|
dns_message_addname(msg, qname, DNS_SECTION_QUESTION);
|
2000-11-03 21:36:37 +00:00
|
|
|
qname = NULL;
|
1999-08-20 05:35:16 +00:00
|
|
|
|
|
|
|
if (xfr->reqtype == dns_rdatatype_ixfr) {
|
1999-10-28 19:11:33 +00:00
|
|
|
/* Get the SOA and add it to the authority section. */
|
1999-08-20 05:35:16 +00:00
|
|
|
dns_db_currentversion(xfr->db, &ver);
|
1999-10-28 19:11:33 +00:00
|
|
|
CHECK(dns_db_createsoatuple(xfr->db, ver, xfr->mctx,
|
|
|
|
DNS_DIFFOP_EXISTS, &soatuple));
|
1999-08-20 05:35:16 +00:00
|
|
|
xfr->ixfr.request_serial = dns_soa_getserial(&soatuple->rdata);
|
2002-09-24 01:04:03 +00:00
|
|
|
xfr->ixfr.current_serial = xfr->ixfr.request_serial;
|
2000-01-26 21:12:04 +00:00
|
|
|
xfrin_log(xfr, ISC_LOG_DEBUG(3),
|
|
|
|
"requesting IXFR for serial %u",
|
1999-10-29 22:42:44 +00:00
|
|
|
xfr->ixfr.request_serial);
|
1999-08-20 05:35:16 +00:00
|
|
|
|
2022-07-29 12:40:45 +00:00
|
|
|
tuple2msgname(soatuple, msg, &msgsoaname);
|
1999-10-28 19:11:33 +00:00
|
|
|
dns_message_addname(msg, msgsoaname, DNS_SECTION_AUTHORITY);
|
2006-07-19 00:53:42 +00:00
|
|
|
} else if (xfr->reqtype == dns_rdatatype_soa) {
|
|
|
|
CHECK(dns_db_getsoaserial(xfr->db, NULL,
|
|
|
|
&xfr->ixfr.request_serial));
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
1999-08-20 05:35:16 +00:00
|
|
|
|
2023-07-04 14:22:29 +10:00
|
|
|
if (edns && xfr->view->peers != NULL) {
|
2023-06-29 17:25:15 +10:00
|
|
|
dns_peer_t *peer = NULL;
|
|
|
|
isc_netaddr_t primaryip;
|
|
|
|
isc_netaddr_fromsockaddr(&primaryip, &xfr->primaryaddr);
|
|
|
|
result = dns_peerlist_peerbyaddr(xfr->view->peers, &primaryip,
|
|
|
|
&peer);
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
(void)dns_peer_getsupportedns(peer, &edns);
|
|
|
|
(void)dns_peer_getudpsize(peer, &udpsize);
|
|
|
|
(void)dns_peer_getrequestnsid(peer, &reqnsid);
|
|
|
|
(void)dns_peer_getrequestexpire(peer, &reqexpire);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (edns) {
|
|
|
|
CHECK(add_opt(msg, udpsize, reqnsid, reqexpire));
|
|
|
|
}
|
|
|
|
|
2023-12-15 09:43:36 +00:00
|
|
|
atomic_store_relaxed(&xfr->nmsg, 0);
|
|
|
|
atomic_store_relaxed(&xfr->nrecs, 0);
|
|
|
|
atomic_store_relaxed(&xfr->nbytes, 0);
|
|
|
|
atomic_store_relaxed(&xfr->start, isc_time_now());
|
2023-10-13 12:16:37 +02:00
|
|
|
|
2024-06-10 16:48:26 +00:00
|
|
|
xfr->nbytes_saved = 0;
|
|
|
|
|
2000-10-16 04:26:08 +00:00
|
|
|
msg->id = xfr->id;
|
2008-07-28 08:39:52 +00:00
|
|
|
if (xfr->tsigctx != NULL) {
|
|
|
|
dst_context_destroy(&xfr->tsigctx);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
1999-09-10 15:01:04 +00:00
|
|
|
|
2001-03-05 21:15:47 +00:00
|
|
|
CHECK(render(msg, xfr->mctx, &xfr->qbuffer));
|
1999-08-20 05:35:16 +00:00
|
|
|
|
2000-07-24 05:30:30 +00:00
|
|
|
/*
|
|
|
|
* Free the last tsig, if there is one.
|
|
|
|
*/
|
|
|
|
if (xfr->lasttsig != NULL) {
|
|
|
|
isc_buffer_free(&xfr->lasttsig);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2000-07-24 05:30:30 +00:00
|
|
|
|
2000-05-08 14:38:29 +00:00
|
|
|
/*
|
|
|
|
* Save the query TSIG and don't let message_destroy free it.
|
|
|
|
*/
|
2000-05-30 23:14:57 +00:00
|
|
|
CHECK(dns_message_getquerytsig(msg, xfr->mctx, &xfr->lasttsig));
|
1999-09-10 15:01:04 +00:00
|
|
|
|
103. [func] libisc buffer API changes for <isc/buffer.h>:
Added:
isc_buffer_base(b) (pointer)
isc_buffer_current(b) (pointer)
isc_buffer_active(b) (pointer)
isc_buffer_used(b) (pointer)
isc_buffer_length(b) (int)
isc_buffer_usedlength(b) (int)
isc_buffer_consumedlength(b) (int)
isc_buffer_remaininglength(b) (int)
isc_buffer_activelength(b) (int)
isc_buffer_availablelength(b) (int)
Removed:
ISC_BUFFER_USEDCOUNT(b)
ISC_BUFFER_AVAILABLECOUNT(b)
isc_buffer_type(b)
Changed names:
isc_buffer_used(b, r) ->
isc_buffer_usedregion(b, r)
isc_buffer_available(b, r) ->
isc_buffer_available_region(b, r)
isc_buffer_consumed(b, r) ->
isc_buffer_consumedregion(b, r)
isc_buffer_active(b, r) ->
isc_buffer_activeregion(b, r)
isc_buffer_remaining(b, r) ->
isc_buffer_remainingregion(b, r)
Buffer types were removed, so the ISC_BUFFERTYPE_*
macros are no more, and the type argument to
isc_buffer_init and isc_buffer_allocate were removed.
isc_buffer_putstr is now void (instead of isc_result_t)
and requires that the caller ensure that there
is enough available buffer space for the string.
2000-04-27 00:03:12 +00:00
|
|
|
isc_buffer_usedregion(&xfr->qbuffer, ®ion);
|
1999-08-20 05:35:16 +00:00
|
|
|
INSIST(region.length <= 65535);
|
|
|
|
|
2023-02-21 20:14:30 -08:00
|
|
|
dns_xfrin_ref(xfr);
|
|
|
|
dns_dispatch_send(xfr->dispentry, ®ion);
|
|
|
|
xfrin_log(xfr, ISC_LOG_DEBUG(3), "sending %s request, QID %d",
|
|
|
|
request_type(xfr), xfr->id);
|
1999-10-28 19:11:33 +00:00
|
|
|
|
1999-08-20 05:35:16 +00:00
|
|
|
failure:
|
2022-07-18 16:42:00 +10:00
|
|
|
dns_message_detach(&msg);
|
1999-08-20 05:35:16 +00:00
|
|
|
if (soatuple != NULL) {
|
|
|
|
dns_difftuple_free(&soatuple);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
1999-10-28 19:11:33 +00:00
|
|
|
if (ver != NULL) {
|
2018-04-17 08:29:14 -07:00
|
|
|
dns_db_closeversion(xfr->db, &ver, false);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2020-09-06 00:38:50 -07:00
|
|
|
|
1999-08-27 18:30:59 +00:00
|
|
|
return result;
|
1999-08-20 05:35:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-02-21 20:14:30 -08:00
|
|
|
xfrin_send_done(isc_result_t result, isc_region_t *region, void *arg) {
|
|
|
|
dns_xfrin_t *xfr = (dns_xfrin_t *)arg;
|
|
|
|
|
|
|
|
UNUSED(region);
|
1999-08-20 05:35:16 +00:00
|
|
|
|
2000-03-29 05:03:07 +00:00
|
|
|
REQUIRE(VALID_XFRIN(xfr));
|
|
|
|
|
2021-04-16 11:08:05 +02:00
|
|
|
if (atomic_load(&xfr->shuttingdown)) {
|
2020-11-09 11:32:55 +01:00
|
|
|
result = ISC_R_SHUTTINGDOWN;
|
2020-09-06 00:38:50 -07:00
|
|
|
}
|
1999-12-02 22:33:15 +00:00
|
|
|
|
2023-08-14 14:24:52 +02:00
|
|
|
LIBDNS_XFRIN_SENT(xfr, xfr->info, result);
|
2023-01-31 10:14:21 +01:00
|
|
|
|
2020-11-09 11:32:55 +01:00
|
|
|
CHECK(result);
|
|
|
|
|
1999-10-29 22:42:44 +00:00
|
|
|
xfrin_log(xfr, ISC_LOG_DEBUG(3), "sent request data");
|
1999-08-20 05:35:16 +00:00
|
|
|
|
2020-11-09 11:32:55 +01:00
|
|
|
failure:
|
2021-04-16 11:08:05 +02:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2020-11-09 11:32:55 +01:00
|
|
|
xfrin_fail(xfr, result, "failed sending request data");
|
|
|
|
}
|
2020-09-06 00:38:50 -07:00
|
|
|
|
2023-02-21 20:14:30 -08:00
|
|
|
dns_xfrin_detach(&xfr);
|
1999-08-20 05:35:16 +00:00
|
|
|
}
|
|
|
|
|
2023-06-29 17:59:24 +10:00
|
|
|
static void
|
|
|
|
get_edns_expire(dns_xfrin_t *xfr, dns_message_t *msg) {
|
|
|
|
isc_result_t result;
|
|
|
|
dns_rdata_t rdata = DNS_RDATA_INIT;
|
|
|
|
isc_buffer_t optbuf;
|
|
|
|
uint16_t optcode;
|
|
|
|
uint16_t optlen;
|
|
|
|
|
|
|
|
result = dns_rdataset_first(msg->opt);
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
dns_rdataset_current(msg->opt, &rdata);
|
|
|
|
isc_buffer_init(&optbuf, rdata.data, rdata.length);
|
|
|
|
isc_buffer_add(&optbuf, rdata.length);
|
|
|
|
while (isc_buffer_remaininglength(&optbuf) >= 4) {
|
|
|
|
optcode = isc_buffer_getuint16(&optbuf);
|
|
|
|
optlen = isc_buffer_getuint16(&optbuf);
|
|
|
|
/*
|
|
|
|
* A EDNS EXPIRE response has a length of 4.
|
|
|
|
*/
|
|
|
|
if (optcode != DNS_OPT_EXPIRE || optlen != 4) {
|
|
|
|
isc_buffer_forward(&optbuf, optlen);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
xfr->expireopt = isc_buffer_getuint32(&optbuf);
|
|
|
|
xfr->expireoptset = true;
|
|
|
|
dns_zone_log(xfr->zone, ISC_LOG_DEBUG(1),
|
|
|
|
"got EDNS EXPIRE of %u", xfr->expireopt);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-13 14:41:22 +02:00
|
|
|
static void
|
|
|
|
xfrin_end(dns_xfrin_t *xfr, isc_result_t result) {
|
|
|
|
/* Inform the caller. */
|
|
|
|
if (xfr->done != NULL) {
|
|
|
|
LIBDNS_XFRIN_DONE_CALLBACK_BEGIN(xfr, xfr->info, result);
|
|
|
|
(xfr->done)(xfr->zone,
|
|
|
|
xfr->expireoptset ? &xfr->expireopt : NULL, result);
|
|
|
|
xfr->done = NULL;
|
|
|
|
LIBDNS_XFRIN_DONE_CALLBACK_END(xfr, xfr->info, result);
|
|
|
|
}
|
|
|
|
|
|
|
|
atomic_store(&xfr->shuttingdown, true);
|
2024-08-19 10:14:19 +02:00
|
|
|
|
|
|
|
if (xfr->max_time_timer != NULL) {
|
|
|
|
isc_timer_stop(xfr->max_time_timer);
|
|
|
|
isc_timer_destroy(&xfr->max_time_timer);
|
|
|
|
}
|
|
|
|
if (xfr->max_idle_timer != NULL) {
|
|
|
|
isc_timer_stop(xfr->max_idle_timer);
|
|
|
|
isc_timer_destroy(&xfr->max_idle_timer);
|
|
|
|
}
|
2024-06-10 16:48:26 +00:00
|
|
|
if (xfr->min_rate_timer != NULL) {
|
|
|
|
isc_timer_stop(xfr->min_rate_timer);
|
|
|
|
isc_timer_destroy(&xfr->min_rate_timer);
|
|
|
|
}
|
2024-03-04 13:21:35 +01:00
|
|
|
|
2023-10-13 14:41:22 +02:00
|
|
|
if (xfr->shutdown_result == ISC_R_UNSET) {
|
|
|
|
xfr->shutdown_result = result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-08-20 05:35:16 +00:00
|
|
|
static void
|
2023-02-21 20:14:30 -08:00
|
|
|
xfrin_recv_done(isc_result_t result, isc_region_t *region, void *arg) {
|
|
|
|
dns_xfrin_t *xfr = (dns_xfrin_t *)arg;
|
1999-08-20 05:35:16 +00:00
|
|
|
dns_message_t *msg = NULL;
|
2016-12-30 15:45:08 +11:00
|
|
|
const dns_name_t *tsigowner = NULL;
|
2020-09-06 00:38:50 -07:00
|
|
|
isc_buffer_t buffer;
|
2000-03-29 05:03:07 +00:00
|
|
|
|
|
|
|
REQUIRE(VALID_XFRIN(xfr));
|
|
|
|
|
2021-04-16 11:08:05 +02:00
|
|
|
if (atomic_load(&xfr->shuttingdown)) {
|
2020-11-09 11:32:55 +01:00
|
|
|
result = ISC_R_SHUTTINGDOWN;
|
2000-01-28 23:48:58 +00:00
|
|
|
}
|
1999-09-10 15:01:04 +00:00
|
|
|
|
2023-04-05 22:35:00 +02:00
|
|
|
/* Stop the idle timer */
|
|
|
|
isc_timer_stop(xfr->max_idle_timer);
|
|
|
|
|
2023-08-14 14:24:52 +02:00
|
|
|
LIBDNS_XFRIN_RECV_START(xfr, xfr->info, result);
|
2023-01-31 10:14:21 +01:00
|
|
|
|
2020-09-06 00:38:50 -07:00
|
|
|
CHECK(result);
|
1999-08-20 05:35:16 +00:00
|
|
|
|
2020-09-06 00:38:50 -07:00
|
|
|
xfrin_log(xfr, ISC_LOG_DEBUG(7), "received %u bytes", region->length);
|
1999-12-06 18:00:31 +00:00
|
|
|
|
2023-09-22 15:00:40 +02:00
|
|
|
dns_message_create(xfr->mctx, NULL, NULL, DNS_MESSAGE_INTENTPARSE,
|
|
|
|
&msg);
|
1999-09-10 15:01:04 +00:00
|
|
|
|
2001-11-30 01:59:49 +00:00
|
|
|
CHECK(dns_message_settsigkey(msg, xfr->tsigkey));
|
2022-07-29 12:40:45 +00:00
|
|
|
dns_message_setquerytsig(msg, xfr->lasttsig);
|
2008-07-28 08:39:52 +00:00
|
|
|
|
1999-09-10 15:01:04 +00:00
|
|
|
msg->tsigctx = xfr->tsigctx;
|
2008-07-28 08:39:52 +00:00
|
|
|
xfr->tsigctx = NULL;
|
2008-07-28 23:47:22 +00:00
|
|
|
|
2015-11-16 13:12:20 +11:00
|
|
|
dns_message_setclass(msg, xfr->rdclass);
|
|
|
|
|
2023-10-13 12:16:37 +02:00
|
|
|
msg->tcp_continuation = (atomic_load_relaxed(&xfr->nmsg) > 0) ? 1 : 0;
|
1999-09-10 15:01:04 +00:00
|
|
|
|
2020-09-06 00:38:50 -07:00
|
|
|
isc_buffer_init(&buffer, region->base, region->length);
|
|
|
|
isc_buffer_add(&buffer, region->length);
|
1999-08-27 18:30:59 +00:00
|
|
|
|
2020-09-06 00:38:50 -07:00
|
|
|
result = dns_message_parse(msg, &buffer,
|
|
|
|
DNS_MESSAGEPARSE_PRESERVEORDER);
|
2012-02-22 05:03:39 +00:00
|
|
|
if (result == ISC_R_SUCCESS) {
|
2024-12-31 05:40:48 +01:00
|
|
|
dns_message_logpacketfrom(
|
2024-12-31 05:40:48 +01:00
|
|
|
msg, "received message", &xfr->primaryaddr,
|
2023-02-21 20:14:30 -08:00
|
|
|
DNS_LOGCATEGORY_XFER_IN, DNS_LOGMODULE_XFER_IN,
|
|
|
|
ISC_LOG_DEBUG(10), xfr->mctx);
|
2012-02-22 05:03:39 +00:00
|
|
|
} else {
|
|
|
|
xfrin_log(xfr, ISC_LOG_DEBUG(10), "dns_message_parse: %s",
|
2021-10-04 17:14:53 +02:00
|
|
|
isc_result_totext(result));
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2012-02-22 05:03:39 +00:00
|
|
|
|
2023-08-14 14:24:52 +02:00
|
|
|
LIBDNS_XFRIN_RECV_PARSED(xfr, xfr->info, result);
|
2023-01-31 10:14:21 +01:00
|
|
|
|
2000-10-16 04:26:08 +00:00
|
|
|
if (result != ISC_R_SUCCESS || msg->rcode != dns_rcode_noerror ||
|
2023-02-21 20:14:30 -08:00
|
|
|
msg->opcode != dns_opcode_query || msg->rdclass != xfr->rdclass)
|
2000-10-16 04:26:08 +00:00
|
|
|
{
|
2023-07-04 14:22:29 +10:00
|
|
|
if (result == ISC_R_SUCCESS &&
|
|
|
|
msg->rcode == dns_rcode_formerr && xfr->edns &&
|
2023-07-06 14:00:48 +10:00
|
|
|
(atomic_load(&xfr->state) == XFRST_SOAQUERY ||
|
2023-09-19 09:35:20 +00:00
|
|
|
atomic_load(&xfr->state) == XFRST_ZONEXFRREQUEST))
|
2023-07-04 14:22:29 +10:00
|
|
|
{
|
|
|
|
xfr->edns = false;
|
|
|
|
dns_message_detach(&msg);
|
|
|
|
xfrin_reset(xfr);
|
|
|
|
goto try_again;
|
|
|
|
} else if (result == ISC_R_SUCCESS &&
|
|
|
|
msg->rcode != dns_rcode_noerror)
|
2015-09-16 10:43:22 +10:00
|
|
|
{
|
2021-10-04 17:14:53 +02:00
|
|
|
result = dns_result_fromrcode(msg->rcode);
|
2015-09-16 10:43:22 +10:00
|
|
|
} else if (result == ISC_R_SUCCESS &&
|
2022-11-02 19:33:14 +01:00
|
|
|
msg->opcode != dns_opcode_query)
|
|
|
|
{
|
2015-09-16 10:43:22 +10:00
|
|
|
result = DNS_R_UNEXPECTEDOPCODE;
|
|
|
|
} else if (result == ISC_R_SUCCESS &&
|
2022-11-02 19:33:14 +01:00
|
|
|
msg->rdclass != xfr->rdclass)
|
|
|
|
{
|
2015-09-16 10:43:22 +10:00
|
|
|
result = DNS_R_BADCLASS;
|
|
|
|
} else if (result == ISC_R_SUCCESS || result == DNS_R_NOERROR) {
|
2000-10-16 04:26:08 +00:00
|
|
|
result = DNS_R_UNEXPECTEDID;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2020-09-06 00:38:50 -07:00
|
|
|
|
1999-12-13 03:01:53 +00:00
|
|
|
if (xfr->reqtype == dns_rdatatype_axfr ||
|
2022-11-02 19:33:14 +01:00
|
|
|
xfr->reqtype == dns_rdatatype_soa)
|
|
|
|
{
|
2011-03-11 06:11:27 +00:00
|
|
|
goto failure;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2020-09-06 00:38:50 -07:00
|
|
|
|
1999-12-02 05:11:28 +00:00
|
|
|
xfrin_log(xfr, ISC_LOG_DEBUG(3), "got %s, retrying with AXFR",
|
1999-08-27 18:30:59 +00:00
|
|
|
isc_result_totext(result));
|
2001-06-01 15:22:56 +00:00
|
|
|
try_axfr:
|
2023-08-14 14:24:52 +02:00
|
|
|
LIBDNS_XFRIN_RECV_TRY_AXFR(xfr, xfr->info, result);
|
2020-09-21 16:16:15 -03:00
|
|
|
dns_message_detach(&msg);
|
2000-10-12 03:32:14 +00:00
|
|
|
xfrin_reset(xfr);
|
2006-07-19 00:53:42 +00:00
|
|
|
xfr->reqtype = dns_rdatatype_soa;
|
2023-07-06 14:00:48 +10:00
|
|
|
atomic_store(&xfr->state, XFRST_SOAQUERY);
|
2023-07-04 14:22:29 +10:00
|
|
|
try_again:
|
2020-09-06 00:38:50 -07:00
|
|
|
result = xfrin_start(xfr);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
xfrin_fail(xfr, result, "failed setting up socket");
|
|
|
|
}
|
2023-02-21 20:14:30 -08:00
|
|
|
dns_xfrin_detach(&xfr);
|
1999-08-27 18:30:59 +00:00
|
|
|
return;
|
|
|
|
}
|
2000-04-08 04:42:42 +00:00
|
|
|
|
2020-03-17 15:25:47 +11:00
|
|
|
/*
|
|
|
|
* The question section should exist for SOA and in the first
|
|
|
|
* message of a AXFR or IXFR response. The question section
|
|
|
|
* may exist in the 2nd and subsequent messages in a AXFR or
|
|
|
|
* IXFR response. If the question section exists it should
|
|
|
|
* match the question that was sent.
|
|
|
|
*/
|
|
|
|
if (msg->counts[DNS_SECTION_QUESTION] > 1) {
|
2023-09-01 10:17:00 +10:00
|
|
|
xfrin_log(xfr, ISC_LOG_NOTICE, "too many questions (%u)",
|
2020-03-17 15:25:47 +11:00
|
|
|
msg->counts[DNS_SECTION_QUESTION]);
|
|
|
|
result = DNS_R_FORMERR;
|
|
|
|
goto failure;
|
|
|
|
}
|
|
|
|
|
2023-07-06 14:00:48 +10:00
|
|
|
if ((atomic_load(&xfr->state) == XFRST_SOAQUERY ||
|
2023-09-19 09:35:20 +00:00
|
|
|
atomic_load(&xfr->state) == XFRST_ZONEXFRREQUEST) &&
|
2020-03-17 15:25:47 +11:00
|
|
|
msg->counts[DNS_SECTION_QUESTION] != 1)
|
|
|
|
{
|
2023-09-01 10:17:00 +10:00
|
|
|
xfrin_log(xfr, ISC_LOG_NOTICE, "missing question section");
|
2020-03-17 15:25:47 +11:00
|
|
|
result = DNS_R_FORMERR;
|
|
|
|
goto failure;
|
|
|
|
}
|
|
|
|
|
2025-03-19 20:29:17 +01:00
|
|
|
MSG_SECTION_FOREACH(msg, DNS_SECTION_QUESTION, name) {
|
2020-09-06 00:38:50 -07:00
|
|
|
dns_rdataset_t *rds = NULL;
|
2020-03-17 15:25:47 +11:00
|
|
|
|
2023-08-14 14:24:52 +02:00
|
|
|
LIBDNS_XFRIN_RECV_QUESTION(xfr, xfr->info, msg);
|
2023-01-31 10:14:21 +01:00
|
|
|
|
2020-03-17 15:25:47 +11:00
|
|
|
if (!dns_name_equal(name, &xfr->name)) {
|
2023-09-01 10:17:00 +10:00
|
|
|
xfrin_log(xfr, ISC_LOG_NOTICE,
|
2020-03-17 15:25:47 +11:00
|
|
|
"question name mismatch");
|
2023-10-12 17:44:51 +02:00
|
|
|
result = DNS_R_FORMERR;
|
2020-03-17 15:25:47 +11:00
|
|
|
goto failure;
|
|
|
|
}
|
|
|
|
rds = ISC_LIST_HEAD(name->list);
|
|
|
|
INSIST(rds != NULL);
|
|
|
|
if (rds->type != xfr->reqtype) {
|
2023-09-01 10:17:00 +10:00
|
|
|
xfrin_log(xfr, ISC_LOG_NOTICE,
|
2020-03-17 15:25:47 +11:00
|
|
|
"question type mismatch");
|
2023-10-12 17:44:51 +02:00
|
|
|
result = DNS_R_FORMERR;
|
2020-03-17 15:25:47 +11:00
|
|
|
goto failure;
|
|
|
|
}
|
|
|
|
if (rds->rdclass != xfr->rdclass) {
|
2023-09-01 10:17:00 +10:00
|
|
|
xfrin_log(xfr, ISC_LOG_NOTICE,
|
2020-03-17 15:25:47 +11:00
|
|
|
"question class mismatch");
|
2023-10-12 17:44:51 +02:00
|
|
|
result = DNS_R_FORMERR;
|
2020-03-17 15:25:47 +11:00
|
|
|
goto failure;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-06-01 15:22:56 +00:00
|
|
|
/*
|
|
|
|
* Does the server know about IXFR? If it doesn't we will get
|
|
|
|
* a message with a empty answer section or a potentially a CNAME /
|
|
|
|
* DNAME, the later is handled by xfr_rr() which will return FORMERR
|
|
|
|
* if the first RR in the answer section is not a SOA record.
|
|
|
|
*/
|
|
|
|
if (xfr->reqtype == dns_rdatatype_ixfr &&
|
2023-09-19 09:35:20 +00:00
|
|
|
atomic_load(&xfr->state) == XFRST_ZONEXFRREQUEST &&
|
2001-06-01 15:22:56 +00:00
|
|
|
msg->counts[DNS_SECTION_ANSWER] == 0)
|
|
|
|
{
|
|
|
|
xfrin_log(xfr, ISC_LOG_DEBUG(3),
|
|
|
|
"empty answer section, retrying with AXFR");
|
|
|
|
goto try_axfr;
|
|
|
|
}
|
|
|
|
|
2001-08-30 05:12:39 +00:00
|
|
|
if (xfr->reqtype == dns_rdatatype_soa &&
|
2022-11-02 19:33:14 +01:00
|
|
|
(msg->flags & DNS_MESSAGEFLAG_AA) == 0)
|
|
|
|
{
|
2023-10-12 17:44:51 +02:00
|
|
|
result = DNS_R_NOTAUTHORITATIVE;
|
|
|
|
goto failure;
|
2001-08-30 05:12:39 +00:00
|
|
|
}
|
|
|
|
|
2023-02-21 20:14:30 -08:00
|
|
|
result = dns_message_checksig(msg, xfr->view);
|
2000-04-08 04:42:42 +00:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
xfrin_log(xfr, ISC_LOG_DEBUG(3), "TSIG check failed: %s",
|
|
|
|
isc_result_totext(result));
|
2011-03-11 06:11:27 +00:00
|
|
|
goto failure;
|
2000-04-08 04:42:42 +00:00
|
|
|
}
|
|
|
|
|
2025-03-19 20:29:17 +01:00
|
|
|
MSG_SECTION_FOREACH(msg, DNS_SECTION_ANSWER, name) {
|
2023-08-14 14:24:52 +02:00
|
|
|
LIBDNS_XFRIN_RECV_ANSWER(xfr, xfr->info, msg);
|
2023-01-31 10:14:21 +01:00
|
|
|
|
2025-03-19 20:29:17 +01:00
|
|
|
ISC_LIST_FOREACH(name->list, rds, link) {
|
2025-03-21 23:32:27 -07:00
|
|
|
DNS_RDATASET_FOREACH(rds) {
|
2000-10-25 04:26:57 +00:00
|
|
|
dns_rdata_t rdata = DNS_RDATA_INIT;
|
1999-08-20 05:35:16 +00:00
|
|
|
dns_rdataset_current(rds, &rdata);
|
|
|
|
CHECK(xfr_rr(xfr, name, rds->ttl, &rdata));
|
2024-06-07 14:47:55 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Did we hit the maximum ixfr diffs limit?
|
|
|
|
*/
|
|
|
|
if (xfr->reqtype == dns_rdatatype_ixfr &&
|
|
|
|
xfr->ixfr.maxdiffs != 0 &&
|
|
|
|
xfr->ixfr.diffs >= xfr->ixfr.maxdiffs)
|
|
|
|
{
|
|
|
|
xfrin_log(xfr, ISC_LOG_DEBUG(3),
|
|
|
|
"too many diffs, "
|
|
|
|
"retrying with AXFR");
|
|
|
|
goto try_axfr;
|
|
|
|
}
|
1999-08-20 05:35:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1999-09-10 15:01:04 +00:00
|
|
|
|
2000-05-30 23:14:57 +00:00
|
|
|
if (dns_message_gettsig(msg, &tsigowner) != NULL) {
|
2000-05-08 14:38:29 +00:00
|
|
|
/*
|
|
|
|
* Reset the counter.
|
|
|
|
*/
|
1999-09-10 15:01:04 +00:00
|
|
|
xfr->sincetsig = 0;
|
|
|
|
|
2000-05-08 14:38:29 +00:00
|
|
|
/*
|
|
|
|
* Free the last tsig, if there is one.
|
|
|
|
*/
|
2000-05-30 23:14:57 +00:00
|
|
|
if (xfr->lasttsig != NULL) {
|
|
|
|
isc_buffer_free(&xfr->lasttsig);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
1999-09-10 15:01:04 +00:00
|
|
|
|
2000-05-08 14:38:29 +00:00
|
|
|
/*
|
|
|
|
* Update the last tsig pointer.
|
|
|
|
*/
|
2000-06-23 00:29:20 +00:00
|
|
|
CHECK(dns_message_getquerytsig(msg, xfr->mctx, &xfr->lasttsig));
|
2000-05-26 00:16:46 +00:00
|
|
|
} else if (dns_message_gettsigkey(msg) != NULL) {
|
1999-09-10 15:01:04 +00:00
|
|
|
xfr->sincetsig++;
|
2023-10-13 12:16:37 +02:00
|
|
|
if (xfr->sincetsig > 100 ||
|
|
|
|
atomic_load_relaxed(&xfr->nmsg) == 0 ||
|
2023-07-06 14:00:48 +10:00
|
|
|
atomic_load(&xfr->state) == XFRST_AXFR_END ||
|
|
|
|
atomic_load(&xfr->state) == XFRST_IXFR_END)
|
2011-02-19 01:24:46 +00:00
|
|
|
{
|
1999-09-10 15:01:04 +00:00
|
|
|
result = DNS_R_EXPECTEDTSIG;
|
|
|
|
goto failure;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-05-08 14:38:29 +00:00
|
|
|
/*
|
2023-10-13 12:16:37 +02:00
|
|
|
* Update the number of messages and bytes received.
|
2007-12-02 23:21:19 +00:00
|
|
|
*/
|
2023-10-13 12:16:37 +02:00
|
|
|
atomic_fetch_add_relaxed(&xfr->nmsg, 1);
|
|
|
|
atomic_fetch_add_relaxed(&xfr->nbytes, buffer.used);
|
2007-12-02 23:21:19 +00:00
|
|
|
|
2000-05-08 14:38:29 +00:00
|
|
|
/*
|
2008-07-28 08:39:52 +00:00
|
|
|
* Take the context back.
|
2000-05-08 14:38:29 +00:00
|
|
|
*/
|
2008-07-28 08:39:52 +00:00
|
|
|
INSIST(xfr->tsigctx == NULL);
|
1999-09-10 15:01:04 +00:00
|
|
|
xfr->tsigctx = msg->tsigctx;
|
2008-07-28 08:39:52 +00:00
|
|
|
msg->tsigctx = NULL;
|
1999-09-10 15:01:04 +00:00
|
|
|
|
2023-06-29 17:59:24 +10:00
|
|
|
if (!xfr->expireoptset && msg->opt != NULL) {
|
|
|
|
get_edns_expire(xfr, msg);
|
|
|
|
}
|
|
|
|
|
2023-07-06 14:00:48 +10:00
|
|
|
switch (atomic_load(&xfr->state)) {
|
2011-02-19 01:24:46 +00:00
|
|
|
case XFRST_GOTSOA:
|
2006-07-19 00:53:42 +00:00
|
|
|
xfr->reqtype = dns_rdatatype_axfr;
|
2023-09-19 09:35:20 +00:00
|
|
|
atomic_store(&xfr->state, XFRST_ZONEXFRREQUEST);
|
2023-10-18 13:07:24 -07:00
|
|
|
CHECK(xfrin_start(xfr));
|
2011-02-19 01:24:46 +00:00
|
|
|
break;
|
|
|
|
case XFRST_AXFR_END:
|
|
|
|
case XFRST_IXFR_END:
|
2023-10-13 14:41:22 +02:00
|
|
|
/* We are at the end, cancel the timers and IO */
|
2024-06-10 16:48:26 +00:00
|
|
|
isc_timer_stop(xfr->min_rate_timer);
|
2023-10-13 14:41:22 +02:00
|
|
|
isc_timer_stop(xfr->max_idle_timer);
|
2023-04-05 22:35:00 +02:00
|
|
|
isc_timer_stop(xfr->max_time_timer);
|
2023-10-13 14:41:22 +02:00
|
|
|
xfrin_cancelio(xfr);
|
2011-02-19 01:24:46 +00:00
|
|
|
break;
|
|
|
|
default:
|
2000-05-08 14:38:29 +00:00
|
|
|
/*
|
|
|
|
* Read the next message.
|
|
|
|
*/
|
2020-11-09 11:32:55 +01:00
|
|
|
dns_message_detach(&msg);
|
2024-09-20 15:13:09 +02:00
|
|
|
result = dns_dispatch_getnext(xfr->dispentry);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
goto failure;
|
|
|
|
}
|
2023-04-05 22:35:00 +02:00
|
|
|
|
|
|
|
isc_interval_t interval;
|
|
|
|
isc_interval_set(&interval, dns_zone_getidlein(xfr->zone), 0);
|
|
|
|
isc_timer_start(xfr->max_idle_timer, isc_timertype_once,
|
|
|
|
&interval);
|
2023-01-31 10:14:21 +01:00
|
|
|
|
2023-08-14 14:24:52 +02:00
|
|
|
LIBDNS_XFRIN_READ(xfr, xfr->info, result);
|
2020-11-09 11:32:55 +01:00
|
|
|
return;
|
1999-08-20 05:35:16 +00:00
|
|
|
}
|
2000-08-01 01:33:37 +00:00
|
|
|
|
1999-08-20 05:35:16 +00:00
|
|
|
failure:
|
2021-04-16 11:08:05 +02:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2000-12-30 13:03:48 +00:00
|
|
|
xfrin_fail(xfr, result, "failed while receiving responses");
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2020-09-06 00:38:50 -07:00
|
|
|
|
2020-11-09 11:32:55 +01:00
|
|
|
if (msg != NULL) {
|
|
|
|
dns_message_detach(&msg);
|
|
|
|
}
|
2023-02-21 20:14:30 -08:00
|
|
|
dns_xfrin_detach(&xfr);
|
2023-08-14 14:24:52 +02:00
|
|
|
LIBDNS_XFRIN_RECV_DONE(xfr, xfr->info, result);
|
1999-08-20 05:35:16 +00:00
|
|
|
}
|
|
|
|
|
2000-01-28 23:48:58 +00:00
|
|
|
static void
|
2023-02-23 10:29:33 -08:00
|
|
|
xfrin_destroy(dns_xfrin_t *xfr) {
|
2023-02-21 20:14:30 -08:00
|
|
|
uint64_t msecs, persec;
|
2023-09-22 15:59:32 +00:00
|
|
|
isc_time_t now = isc_time_now();
|
2024-10-26 07:50:23 +11:00
|
|
|
char expireopt[sizeof("4000000000")] = { 0 };
|
|
|
|
const char *sep = "";
|
2007-12-02 23:21:19 +00:00
|
|
|
|
2000-03-29 05:03:07 +00:00
|
|
|
REQUIRE(VALID_XFRIN(xfr));
|
|
|
|
|
2020-11-09 11:32:55 +01:00
|
|
|
/* Safe-guards */
|
2021-04-16 11:08:05 +02:00
|
|
|
REQUIRE(atomic_load(&xfr->shuttingdown));
|
1999-08-20 05:35:16 +00:00
|
|
|
|
2020-09-06 00:38:50 -07:00
|
|
|
INSIST(xfr->shutdown_result != ISC_R_UNSET);
|
2015-04-14 12:13:06 +05:30
|
|
|
|
2020-09-06 00:38:50 -07:00
|
|
|
/*
|
|
|
|
* If we're called through dns_xfrin_detach() and are not
|
2015-04-14 12:13:06 +05:30
|
|
|
* shutting down, we can't know what the transfer status is as
|
|
|
|
* we are only called when the last reference is lost.
|
|
|
|
*/
|
2023-02-21 20:14:30 -08:00
|
|
|
xfrin_log(xfr, ISC_LOG_INFO, "Transfer status: %s",
|
|
|
|
isc_result_totext(xfr->shutdown_result));
|
2015-04-14 12:13:06 +05:30
|
|
|
|
2007-12-02 23:21:19 +00:00
|
|
|
/*
|
|
|
|
* Calculate the length of time the transfer took,
|
|
|
|
* and print a log message with the bytes and rate.
|
|
|
|
*/
|
2023-10-13 12:16:37 +02:00
|
|
|
isc_time_t start = atomic_load_relaxed(&xfr->start);
|
|
|
|
msecs = isc_time_microdiff(&now, &start) / 1000;
|
2007-12-02 23:47:01 +00:00
|
|
|
if (msecs == 0) {
|
|
|
|
msecs = 1;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2023-10-13 12:16:37 +02:00
|
|
|
persec = (atomic_load_relaxed(&xfr->nbytes) * 1000) / msecs;
|
2024-10-26 07:50:23 +11:00
|
|
|
|
|
|
|
if (xfr->expireoptset) {
|
|
|
|
sep = ", expire option ";
|
|
|
|
snprintf(expireopt, sizeof(expireopt), "%u", xfr->expireopt);
|
|
|
|
}
|
|
|
|
|
2008-07-22 23:47:04 +00:00
|
|
|
xfrin_log(xfr, ISC_LOG_INFO,
|
2007-12-02 23:21:19 +00:00
|
|
|
"Transfer completed: %d messages, %d records, "
|
2018-03-28 14:56:40 +02:00
|
|
|
"%" PRIu64 " bytes, "
|
2024-10-26 07:50:23 +11:00
|
|
|
"%u.%03u secs (%u bytes/sec) (serial %" PRIuFAST32 "%s%s)",
|
2023-10-13 12:16:37 +02:00
|
|
|
atomic_load_relaxed(&xfr->nmsg),
|
|
|
|
atomic_load_relaxed(&xfr->nrecs),
|
|
|
|
atomic_load_relaxed(&xfr->nbytes),
|
2007-12-02 23:47:01 +00:00
|
|
|
(unsigned int)(msecs / 1000), (unsigned int)(msecs % 1000),
|
2024-10-26 07:50:23 +11:00
|
|
|
(unsigned int)persec, atomic_load_relaxed(&xfr->end_serial),
|
|
|
|
sep, expireopt);
|
1999-12-02 22:33:15 +00:00
|
|
|
|
2023-10-13 14:41:22 +02:00
|
|
|
/* Cleanup unprocessed IXFR data */
|
|
|
|
struct cds_wfcq_node *node, *next;
|
|
|
|
__cds_wfcq_for_each_blocking_safe(&xfr->diff_head, &xfr->diff_tail,
|
|
|
|
node, next) {
|
|
|
|
ixfr_apply_data_t *data =
|
|
|
|
caa_container_of(node, ixfr_apply_data_t, wfcq_node);
|
|
|
|
/* We need to clear and free all data chunks */
|
|
|
|
dns_diff_clear(&data->diff);
|
|
|
|
isc_mem_put(xfr->mctx, data, sizeof(*data));
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
1999-12-02 22:33:15 +00:00
|
|
|
|
2023-10-13 14:41:22 +02:00
|
|
|
/* Cleanup unprocessed AXFR data */
|
|
|
|
dns_diff_clear(&xfr->diff);
|
|
|
|
|
|
|
|
xfrin_cancelio(xfr);
|
|
|
|
|
2021-01-14 12:51:25 +01:00
|
|
|
if (xfr->transport != NULL) {
|
|
|
|
dns_transport_detach(&xfr->transport);
|
|
|
|
}
|
|
|
|
|
2000-07-21 23:00:31 +00:00
|
|
|
if (xfr->tsigkey != NULL) {
|
|
|
|
dns_tsigkey_detach(&xfr->tsigkey);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2000-07-21 23:00:31 +00:00
|
|
|
|
2000-05-30 23:14:57 +00:00
|
|
|
if (xfr->lasttsig != NULL) {
|
|
|
|
isc_buffer_free(&xfr->lasttsig);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
1999-12-02 22:33:15 +00:00
|
|
|
|
1999-08-20 05:35:16 +00:00
|
|
|
if (xfr->ixfr.journal != NULL) {
|
|
|
|
dns_journal_destroy(&xfr->ixfr.journal);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
1999-08-27 18:30:59 +00:00
|
|
|
|
1999-08-25 06:39:19 +00:00
|
|
|
if (xfr->axfr.add_private != NULL) {
|
2012-06-20 14:13:12 -05:00
|
|
|
(void)dns_db_endload(xfr->db, &xfr->axfr);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
1999-08-20 05:35:16 +00:00
|
|
|
|
2008-07-28 08:39:52 +00:00
|
|
|
if (xfr->tsigctx != NULL) {
|
|
|
|
dst_context_destroy(&xfr->tsigctx);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2008-07-28 08:39:52 +00:00
|
|
|
|
2022-10-13 10:33:41 +02:00
|
|
|
if (xfr->name.attributes.dynamic) {
|
1999-08-20 05:35:16 +00:00
|
|
|
dns_name_free(&xfr->name, xfr->mctx);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
1999-08-25 06:39:19 +00:00
|
|
|
|
1999-08-20 05:35:16 +00:00
|
|
|
if (xfr->ver != NULL) {
|
2018-04-17 08:29:14 -07:00
|
|
|
dns_db_closeversion(xfr->db, &xfr->ver, false);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
1999-08-20 05:35:16 +00:00
|
|
|
|
1999-10-14 00:05:02 +00:00
|
|
|
if (xfr->db != NULL) {
|
1999-10-14 01:37:00 +00:00
|
|
|
dns_db_detach(&xfr->db);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
1999-08-20 05:35:16 +00:00
|
|
|
|
Log a message when a transferred mirror zone comes into effect
Log a message when a mirror zone is successfully transferred and
verified, but only if no database for that zone was yet loaded at the
time the transfer was initiated.
This could have been implemented in a simpler manner, e.g. by modifying
zone_replacedb(), but (due to the calling order of the functions
involved in finalizing a zone transfer) that would cause the resulting
logs to suggest that a mirror zone comes into effect before its transfer
is finished, which would be confusing given the nature of mirror zones
and the fact that no message is logged upon successful mirror zone
verification.
Once the dns_zone_replacedb() call in axfr_finalize() is made, it
becomes impossible to determine whether the transferred zone had a
database attached before the transfer was started. Thus, that check is
instead performed when the transfer context is first created and the
result of this check is passed around in a field of the transfer context
structure. If it turns out to be desired, the relevant log message is
then emitted just before the transfer context is freed.
Taking this approach means that the log message added by this commit is
not timed precisely, i.e. mirror zone data may be used before this
message is logged. However, that can only be fixed by logging the
message inside zone_replacedb(), which causes arguably more dire issues
discussed above.
dns_zone_isloaded() is not used to double-check that transferred zone
data was correctly loaded since the 'shutdown_result' field of the zone
transfer context will not be set to ISC_R_SUCCESS unless axfr_finalize()
succeeds (and that in turn will not happen unless dns_zone_replacedb()
succeeds).
2019-01-16 15:31:48 +01:00
|
|
|
if (xfr->zone != NULL) {
|
2020-09-06 00:38:50 -07:00
|
|
|
if (!xfr->zone_had_db &&
|
Log a message when a transferred mirror zone comes into effect
Log a message when a mirror zone is successfully transferred and
verified, but only if no database for that zone was yet loaded at the
time the transfer was initiated.
This could have been implemented in a simpler manner, e.g. by modifying
zone_replacedb(), but (due to the calling order of the functions
involved in finalizing a zone transfer) that would cause the resulting
logs to suggest that a mirror zone comes into effect before its transfer
is finished, which would be confusing given the nature of mirror zones
and the fact that no message is logged upon successful mirror zone
verification.
Once the dns_zone_replacedb() call in axfr_finalize() is made, it
becomes impossible to determine whether the transferred zone had a
database attached before the transfer was started. Thus, that check is
instead performed when the transfer context is first created and the
result of this check is passed around in a field of the transfer context
structure. If it turns out to be desired, the relevant log message is
then emitted just before the transfer context is freed.
Taking this approach means that the log message added by this commit is
not timed precisely, i.e. mirror zone data may be used before this
message is logged. However, that can only be fixed by logging the
message inside zone_replacedb(), which causes arguably more dire issues
discussed above.
dns_zone_isloaded() is not used to double-check that transferred zone
data was correctly loaded since the 'shutdown_result' field of the zone
transfer context will not be set to ISC_R_SUCCESS unless axfr_finalize()
succeeds (and that in turn will not happen unless dns_zone_replacedb()
succeeds).
2019-01-16 15:31:48 +01:00
|
|
|
xfr->shutdown_result == ISC_R_SUCCESS &&
|
|
|
|
dns_zone_gettype(xfr->zone) == dns_zone_mirror)
|
|
|
|
{
|
|
|
|
dns_zone_log(xfr->zone, ISC_LOG_INFO,
|
|
|
|
"mirror zone is now in use");
|
|
|
|
}
|
2019-02-14 10:41:56 +01:00
|
|
|
xfrin_log(xfr, ISC_LOG_DEBUG(99), "freeing transfer context");
|
|
|
|
/*
|
|
|
|
* xfr->zone must not be detached before xfrin_log() is called.
|
|
|
|
*/
|
2000-08-31 17:48:47 +00:00
|
|
|
dns_zone_idetach(&xfr->zone);
|
Log a message when a transferred mirror zone comes into effect
Log a message when a mirror zone is successfully transferred and
verified, but only if no database for that zone was yet loaded at the
time the transfer was initiated.
This could have been implemented in a simpler manner, e.g. by modifying
zone_replacedb(), but (due to the calling order of the functions
involved in finalizing a zone transfer) that would cause the resulting
logs to suggest that a mirror zone comes into effect before its transfer
is finished, which would be confusing given the nature of mirror zones
and the fact that no message is logged upon successful mirror zone
verification.
Once the dns_zone_replacedb() call in axfr_finalize() is made, it
becomes impossible to determine whether the transferred zone had a
database attached before the transfer was started. Thus, that check is
instead performed when the transfer context is first created and the
result of this check is passed around in a field of the transfer context
structure. If it turns out to be desired, the relevant log message is
then emitted just before the transfer context is freed.
Taking this approach means that the log message added by this commit is
not timed precisely, i.e. mirror zone data may be used before this
message is logged. However, that can only be fixed by logging the
message inside zone_replacedb(), which causes arguably more dire issues
discussed above.
dns_zone_isloaded() is not used to double-check that transferred zone
data was correctly loaded since the 'shutdown_result' field of the zone
transfer context will not be set to ISC_R_SUCCESS unless axfr_finalize()
succeeds (and that in turn will not happen unless dns_zone_replacedb()
succeeds).
2019-01-16 15:31:48 +01:00
|
|
|
}
|
2000-08-01 01:33:37 +00:00
|
|
|
|
2023-02-21 20:14:30 -08:00
|
|
|
if (xfr->view != NULL) {
|
|
|
|
dns_view_weakdetach(&xfr->view);
|
|
|
|
}
|
|
|
|
|
2021-03-15 15:43:26 +11:00
|
|
|
if (xfr->firstsoa_data != NULL) {
|
|
|
|
isc_mem_free(xfr->mctx, xfr->firstsoa_data);
|
|
|
|
}
|
|
|
|
|
2021-12-23 16:08:41 +02:00
|
|
|
if (xfr->tlsctx_cache != NULL) {
|
|
|
|
isc_tlsctx_cache_detach(&xfr->tlsctx_cache);
|
|
|
|
}
|
|
|
|
|
2024-08-19 10:14:19 +02:00
|
|
|
INSIST(xfr->max_time_timer == NULL);
|
|
|
|
INSIST(xfr->max_idle_timer == NULL);
|
2024-06-10 16:48:26 +00:00
|
|
|
INSIST(xfr->min_rate_timer == NULL);
|
2023-04-05 22:35:00 +02:00
|
|
|
|
2024-03-04 13:21:35 +01:00
|
|
|
isc_loop_detach(&xfr->loop);
|
|
|
|
|
2013-03-08 14:38:03 +11:00
|
|
|
isc_mem_putanddetach(&xfr->mctx, xfr, sizeof(*xfr));
|
1999-08-20 05:35:16 +00:00
|
|
|
}
|
1999-10-29 22:42:44 +00:00
|
|
|
|
1999-10-30 01:08:52 +00:00
|
|
|
/*
|
|
|
|
* Log incoming zone transfer messages in a format like
|
|
|
|
* transfer of <zone> from <address>: <message>
|
|
|
|
*/
|
1999-10-29 22:42:44 +00:00
|
|
|
|
|
|
|
static void
|
2023-02-23 10:29:33 -08:00
|
|
|
xfrin_log(dns_xfrin_t *xfr, int level, const char *fmt, ...) {
|
2000-12-11 19:24:30 +00:00
|
|
|
va_list ap;
|
2023-08-14 14:24:52 +02:00
|
|
|
char primarytext[ISC_SOCKADDR_FORMATSIZE];
|
|
|
|
char msgtext[2048];
|
2000-06-01 18:04:37 +00:00
|
|
|
|
2024-08-13 18:20:26 +02:00
|
|
|
if (!isc_log_wouldlog(level)) {
|
2000-07-13 00:27:17 +00:00
|
|
|
return;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2000-07-13 00:27:17 +00:00
|
|
|
|
2023-08-14 14:24:52 +02:00
|
|
|
isc_sockaddr_format(&xfr->primaryaddr, primarytext,
|
|
|
|
sizeof(primarytext));
|
1999-10-29 22:42:44 +00:00
|
|
|
va_start(ap, fmt);
|
2023-08-14 14:24:52 +02:00
|
|
|
vsnprintf(msgtext, sizeof(msgtext), fmt, ap);
|
1999-10-29 22:42:44 +00:00
|
|
|
va_end(ap);
|
2023-08-14 14:24:52 +02:00
|
|
|
|
2024-08-13 18:20:26 +02:00
|
|
|
isc_log_write(DNS_LOGCATEGORY_XFER_IN, DNS_LOGMODULE_XFER_IN, level,
|
|
|
|
"%p: transfer of '%s' from %s: %s", xfr, xfr->info,
|
2023-08-14 14:24:52 +02:00
|
|
|
primarytext, msgtext);
|
1999-10-29 22:42:44 +00:00
|
|
|
}
|