1*4afad4b7Schristos /* $NetBSD: xfrin.c,v 1.1 2024/02/18 20:57:34 christos Exp $ */
2*4afad4b7Schristos
3*4afad4b7Schristos /*
4*4afad4b7Schristos * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5*4afad4b7Schristos *
6*4afad4b7Schristos * SPDX-License-Identifier: MPL-2.0
7*4afad4b7Schristos *
8*4afad4b7Schristos * This Source Code Form is subject to the terms of the Mozilla Public
9*4afad4b7Schristos * License, v. 2.0. If a copy of the MPL was not distributed with this
10*4afad4b7Schristos * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11*4afad4b7Schristos *
12*4afad4b7Schristos * See the COPYRIGHT file distributed with this work for additional
13*4afad4b7Schristos * information regarding copyright ownership.
14*4afad4b7Schristos */
15*4afad4b7Schristos
16*4afad4b7Schristos /*! \file */
17*4afad4b7Schristos
18*4afad4b7Schristos #include <inttypes.h>
19*4afad4b7Schristos #include <stdbool.h>
20*4afad4b7Schristos
21*4afad4b7Schristos #include <isc/mem.h>
22*4afad4b7Schristos #include <isc/print.h>
23*4afad4b7Schristos #include <isc/random.h>
24*4afad4b7Schristos #include <isc/string.h> /* Required for HP/UX (and others?) */
25*4afad4b7Schristos #include <isc/task.h>
26*4afad4b7Schristos #include <isc/timer.h>
27*4afad4b7Schristos #include <isc/util.h>
28*4afad4b7Schristos
29*4afad4b7Schristos #include <dns/callbacks.h>
30*4afad4b7Schristos #include <dns/catz.h>
31*4afad4b7Schristos #include <dns/db.h>
32*4afad4b7Schristos #include <dns/diff.h>
33*4afad4b7Schristos #include <dns/events.h>
34*4afad4b7Schristos #include <dns/journal.h>
35*4afad4b7Schristos #include <dns/log.h>
36*4afad4b7Schristos #include <dns/message.h>
37*4afad4b7Schristos #include <dns/rdataclass.h>
38*4afad4b7Schristos #include <dns/rdatalist.h>
39*4afad4b7Schristos #include <dns/rdataset.h>
40*4afad4b7Schristos #include <dns/result.h>
41*4afad4b7Schristos #include <dns/soa.h>
42*4afad4b7Schristos #include <dns/tcpmsg.h>
43*4afad4b7Schristos #include <dns/timer.h>
44*4afad4b7Schristos #include <dns/tsig.h>
45*4afad4b7Schristos #include <dns/view.h>
46*4afad4b7Schristos #include <dns/xfrin.h>
47*4afad4b7Schristos #include <dns/zone.h>
48*4afad4b7Schristos
49*4afad4b7Schristos #include <dst/dst.h>
50*4afad4b7Schristos
51*4afad4b7Schristos /*
52*4afad4b7Schristos * Incoming AXFR and IXFR.
53*4afad4b7Schristos */
54*4afad4b7Schristos
55*4afad4b7Schristos /*%
56*4afad4b7Schristos * It would be non-sensical (or at least obtuse) to use FAIL() with an
57*4afad4b7Schristos * ISC_R_SUCCESS code, but the test is there to keep the Solaris compiler
58*4afad4b7Schristos * from complaining about "end-of-loop code not reached".
59*4afad4b7Schristos */
60*4afad4b7Schristos #define FAIL(code) \
61*4afad4b7Schristos do { \
62*4afad4b7Schristos result = (code); \
63*4afad4b7Schristos if (result != ISC_R_SUCCESS) \
64*4afad4b7Schristos goto failure; \
65*4afad4b7Schristos } while (0)
66*4afad4b7Schristos
67*4afad4b7Schristos #define CHECK(op) \
68*4afad4b7Schristos do { \
69*4afad4b7Schristos result = (op); \
70*4afad4b7Schristos if (result != ISC_R_SUCCESS) \
71*4afad4b7Schristos goto failure; \
72*4afad4b7Schristos } while (0)
73*4afad4b7Schristos
74*4afad4b7Schristos /*%
75*4afad4b7Schristos * The states of the *XFR state machine. We handle both IXFR and AXFR
76*4afad4b7Schristos * with a single integrated state machine because they cannot be distinguished
77*4afad4b7Schristos * immediately - an AXFR response to an IXFR request can only be detected
78*4afad4b7Schristos * when the first two (2) response RRs have already been received.
79*4afad4b7Schristos */
80*4afad4b7Schristos typedef enum {
81*4afad4b7Schristos XFRST_SOAQUERY,
82*4afad4b7Schristos XFRST_GOTSOA,
83*4afad4b7Schristos XFRST_INITIALSOA,
84*4afad4b7Schristos XFRST_FIRSTDATA,
85*4afad4b7Schristos XFRST_IXFR_DELSOA,
86*4afad4b7Schristos XFRST_IXFR_DEL,
87*4afad4b7Schristos XFRST_IXFR_ADDSOA,
88*4afad4b7Schristos XFRST_IXFR_ADD,
89*4afad4b7Schristos XFRST_IXFR_END,
90*4afad4b7Schristos XFRST_AXFR,
91*4afad4b7Schristos XFRST_AXFR_END
92*4afad4b7Schristos } xfrin_state_t;
93*4afad4b7Schristos
94*4afad4b7Schristos /*%
95*4afad4b7Schristos * Incoming zone transfer context.
96*4afad4b7Schristos */
97*4afad4b7Schristos
98*4afad4b7Schristos struct dns_xfrin_ctx {
99*4afad4b7Schristos unsigned int magic;
100*4afad4b7Schristos isc_mem_t *mctx;
101*4afad4b7Schristos dns_zone_t *zone;
102*4afad4b7Schristos
103*4afad4b7Schristos int refcount;
104*4afad4b7Schristos
105*4afad4b7Schristos isc_task_t *task;
106*4afad4b7Schristos isc_timer_t *timer;
107*4afad4b7Schristos isc_socketmgr_t *socketmgr;
108*4afad4b7Schristos
109*4afad4b7Schristos int connects; /*%< Connect in progress */
110*4afad4b7Schristos int sends; /*%< Send in progress */
111*4afad4b7Schristos int recvs; /*%< Receive in progress */
112*4afad4b7Schristos bool shuttingdown;
113*4afad4b7Schristos isc_result_t shutdown_result;
114*4afad4b7Schristos
115*4afad4b7Schristos dns_name_t name; /*%< Name of zone to transfer */
116*4afad4b7Schristos dns_rdataclass_t rdclass;
117*4afad4b7Schristos
118*4afad4b7Schristos bool checkid, logit;
119*4afad4b7Schristos dns_messageid_t id;
120*4afad4b7Schristos
121*4afad4b7Schristos /*%
122*4afad4b7Schristos * Requested transfer type (dns_rdatatype_axfr or
123*4afad4b7Schristos * dns_rdatatype_ixfr). The actual transfer type
124*4afad4b7Schristos * may differ due to IXFR->AXFR fallback.
125*4afad4b7Schristos */
126*4afad4b7Schristos dns_rdatatype_t reqtype;
127*4afad4b7Schristos isc_dscp_t dscp;
128*4afad4b7Schristos
129*4afad4b7Schristos isc_sockaddr_t masteraddr;
130*4afad4b7Schristos isc_sockaddr_t sourceaddr;
131*4afad4b7Schristos isc_socket_t *socket;
132*4afad4b7Schristos
133*4afad4b7Schristos /*% Buffer for IXFR/AXFR request message */
134*4afad4b7Schristos isc_buffer_t qbuffer;
135*4afad4b7Schristos unsigned char qbuffer_data[512];
136*4afad4b7Schristos
137*4afad4b7Schristos /*% Incoming reply TCP message */
138*4afad4b7Schristos dns_tcpmsg_t tcpmsg;
139*4afad4b7Schristos bool tcpmsg_valid;
140*4afad4b7Schristos
141*4afad4b7Schristos /*%
142*4afad4b7Schristos * Whether the zone originally had a database attached at the time this
143*4afad4b7Schristos * transfer context was created. Used by maybe_free() when making
144*4afad4b7Schristos * logging decisions.
145*4afad4b7Schristos */
146*4afad4b7Schristos bool zone_had_db;
147*4afad4b7Schristos
148*4afad4b7Schristos dns_db_t *db;
149*4afad4b7Schristos dns_dbversion_t *ver;
150*4afad4b7Schristos dns_diff_t diff; /*%< Pending database changes */
151*4afad4b7Schristos int difflen; /*%< Number of pending tuples */
152*4afad4b7Schristos
153*4afad4b7Schristos xfrin_state_t state;
154*4afad4b7Schristos uint32_t end_serial;
155*4afad4b7Schristos bool is_ixfr;
156*4afad4b7Schristos
157*4afad4b7Schristos unsigned int nmsg; /*%< Number of messages recvd */
158*4afad4b7Schristos unsigned int nrecs; /*%< Number of records recvd */
159*4afad4b7Schristos uint64_t nbytes; /*%< Number of bytes received */
160*4afad4b7Schristos
161*4afad4b7Schristos unsigned int maxrecords; /*%< The maximum number of
162*4afad4b7Schristos * records set for the zone */
163*4afad4b7Schristos
164*4afad4b7Schristos isc_time_t start; /*%< Start time of the transfer */
165*4afad4b7Schristos isc_time_t end; /*%< End time of the transfer */
166*4afad4b7Schristos
167*4afad4b7Schristos dns_tsigkey_t *tsigkey; /*%< Key used to create TSIG */
168*4afad4b7Schristos isc_buffer_t *lasttsig; /*%< The last TSIG */
169*4afad4b7Schristos dst_context_t *tsigctx; /*%< TSIG verification context */
170*4afad4b7Schristos unsigned int sincetsig; /*%< recvd since the last TSIG */
171*4afad4b7Schristos dns_xfrindone_t done;
172*4afad4b7Schristos
173*4afad4b7Schristos /*%
174*4afad4b7Schristos * AXFR- and IXFR-specific data. Only one is used at a time
175*4afad4b7Schristos * according to the is_ixfr flag, so this could be a union,
176*4afad4b7Schristos * but keeping them separate makes it a bit simpler to clean
177*4afad4b7Schristos * things up when destroying the context.
178*4afad4b7Schristos */
179*4afad4b7Schristos dns_rdatacallbacks_t axfr;
180*4afad4b7Schristos
181*4afad4b7Schristos struct {
182*4afad4b7Schristos uint32_t request_serial;
183*4afad4b7Schristos uint32_t current_serial;
184*4afad4b7Schristos dns_journal_t *journal;
185*4afad4b7Schristos } ixfr;
186*4afad4b7Schristos
187*4afad4b7Schristos dns_rdata_t firstsoa;
188*4afad4b7Schristos unsigned char *firstsoa_data;
189*4afad4b7Schristos };
190*4afad4b7Schristos
191*4afad4b7Schristos #define XFRIN_MAGIC ISC_MAGIC('X', 'f', 'r', 'I')
192*4afad4b7Schristos #define VALID_XFRIN(x) ISC_MAGIC_VALID(x, XFRIN_MAGIC)
193*4afad4b7Schristos
194*4afad4b7Schristos /**************************************************************************/
195*4afad4b7Schristos /*
196*4afad4b7Schristos * Forward declarations.
197*4afad4b7Schristos */
198*4afad4b7Schristos
199*4afad4b7Schristos static isc_result_t
200*4afad4b7Schristos xfrin_create(isc_mem_t *mctx, dns_zone_t *zone, dns_db_t *db, isc_task_t *task,
201*4afad4b7Schristos isc_timermgr_t *timermgr, isc_socketmgr_t *socketmgr,
202*4afad4b7Schristos dns_name_t *zonename, dns_rdataclass_t rdclass,
203*4afad4b7Schristos dns_rdatatype_t reqtype, const isc_sockaddr_t *masteraddr,
204*4afad4b7Schristos const isc_sockaddr_t *sourceaddr, isc_dscp_t dscp,
205*4afad4b7Schristos dns_tsigkey_t *tsigkey, dns_xfrin_ctx_t **xfrp);
206*4afad4b7Schristos
207*4afad4b7Schristos static isc_result_t
208*4afad4b7Schristos axfr_init(dns_xfrin_ctx_t *xfr);
209*4afad4b7Schristos static isc_result_t
210*4afad4b7Schristos axfr_makedb(dns_xfrin_ctx_t *xfr, dns_db_t **dbp);
211*4afad4b7Schristos static isc_result_t
212*4afad4b7Schristos axfr_putdata(dns_xfrin_ctx_t *xfr, dns_diffop_t op, dns_name_t *name,
213*4afad4b7Schristos dns_ttl_t ttl, dns_rdata_t *rdata);
214*4afad4b7Schristos static isc_result_t
215*4afad4b7Schristos axfr_apply(dns_xfrin_ctx_t *xfr);
216*4afad4b7Schristos static isc_result_t
217*4afad4b7Schristos axfr_commit(dns_xfrin_ctx_t *xfr);
218*4afad4b7Schristos static isc_result_t
219*4afad4b7Schristos axfr_finalize(dns_xfrin_ctx_t *xfr);
220*4afad4b7Schristos
221*4afad4b7Schristos static isc_result_t
222*4afad4b7Schristos ixfr_init(dns_xfrin_ctx_t *xfr);
223*4afad4b7Schristos static isc_result_t
224*4afad4b7Schristos ixfr_apply(dns_xfrin_ctx_t *xfr);
225*4afad4b7Schristos static isc_result_t
226*4afad4b7Schristos ixfr_putdata(dns_xfrin_ctx_t *xfr, dns_diffop_t op, dns_name_t *name,
227*4afad4b7Schristos dns_ttl_t ttl, dns_rdata_t *rdata);
228*4afad4b7Schristos static isc_result_t
229*4afad4b7Schristos ixfr_commit(dns_xfrin_ctx_t *xfr);
230*4afad4b7Schristos
231*4afad4b7Schristos static isc_result_t
232*4afad4b7Schristos xfr_rr(dns_xfrin_ctx_t *xfr, dns_name_t *name, uint32_t ttl,
233*4afad4b7Schristos dns_rdata_t *rdata);
234*4afad4b7Schristos
235*4afad4b7Schristos static isc_result_t
236*4afad4b7Schristos xfrin_start(dns_xfrin_ctx_t *xfr);
237*4afad4b7Schristos
238*4afad4b7Schristos static void
239*4afad4b7Schristos xfrin_connect_done(isc_task_t *task, isc_event_t *event);
240*4afad4b7Schristos static isc_result_t
241*4afad4b7Schristos xfrin_send_request(dns_xfrin_ctx_t *xfr);
242*4afad4b7Schristos static void
243*4afad4b7Schristos xfrin_send_done(isc_task_t *task, isc_event_t *event);
244*4afad4b7Schristos static void
245*4afad4b7Schristos xfrin_recv_done(isc_task_t *task, isc_event_t *event);
246*4afad4b7Schristos static void
247*4afad4b7Schristos xfrin_timeout(isc_task_t *task, isc_event_t *event);
248*4afad4b7Schristos
249*4afad4b7Schristos static void
250*4afad4b7Schristos maybe_free(dns_xfrin_ctx_t *xfr);
251*4afad4b7Schristos
252*4afad4b7Schristos static void
253*4afad4b7Schristos xfrin_fail(dns_xfrin_ctx_t *xfr, isc_result_t result, const char *msg);
254*4afad4b7Schristos static isc_result_t
255*4afad4b7Schristos render(dns_message_t *msg, isc_mem_t *mctx, isc_buffer_t *buf);
256*4afad4b7Schristos
257*4afad4b7Schristos static void
258*4afad4b7Schristos xfrin_logv(int level, const char *zonetext, const isc_sockaddr_t *masteraddr,
259*4afad4b7Schristos const char *fmt, va_list ap) ISC_FORMAT_PRINTF(4, 0);
260*4afad4b7Schristos
261*4afad4b7Schristos static void
262*4afad4b7Schristos xfrin_log1(int level, const char *zonetext, const isc_sockaddr_t *masteraddr,
263*4afad4b7Schristos const char *fmt, ...) ISC_FORMAT_PRINTF(4, 5);
264*4afad4b7Schristos
265*4afad4b7Schristos static void
266*4afad4b7Schristos xfrin_log(dns_xfrin_ctx_t *xfr, int level, const char *fmt, ...)
267*4afad4b7Schristos ISC_FORMAT_PRINTF(3, 4);
268*4afad4b7Schristos
269*4afad4b7Schristos /**************************************************************************/
270*4afad4b7Schristos /*
271*4afad4b7Schristos * AXFR handling
272*4afad4b7Schristos */
273*4afad4b7Schristos
274*4afad4b7Schristos static isc_result_t
axfr_init(dns_xfrin_ctx_t * xfr)275*4afad4b7Schristos axfr_init(dns_xfrin_ctx_t *xfr) {
276*4afad4b7Schristos isc_result_t result;
277*4afad4b7Schristos
278*4afad4b7Schristos xfr->is_ixfr = false;
279*4afad4b7Schristos
280*4afad4b7Schristos if (xfr->db != NULL) {
281*4afad4b7Schristos dns_db_detach(&xfr->db);
282*4afad4b7Schristos }
283*4afad4b7Schristos
284*4afad4b7Schristos CHECK(axfr_makedb(xfr, &xfr->db));
285*4afad4b7Schristos dns_rdatacallbacks_init(&xfr->axfr);
286*4afad4b7Schristos CHECK(dns_db_beginload(xfr->db, &xfr->axfr));
287*4afad4b7Schristos result = ISC_R_SUCCESS;
288*4afad4b7Schristos failure:
289*4afad4b7Schristos return (result);
290*4afad4b7Schristos }
291*4afad4b7Schristos
292*4afad4b7Schristos static isc_result_t
axfr_makedb(dns_xfrin_ctx_t * xfr,dns_db_t ** dbp)293*4afad4b7Schristos axfr_makedb(dns_xfrin_ctx_t *xfr, dns_db_t **dbp) {
294*4afad4b7Schristos isc_result_t result;
295*4afad4b7Schristos
296*4afad4b7Schristos result = dns_db_create(xfr->mctx, /* XXX */
297*4afad4b7Schristos "rbt", /* XXX guess */
298*4afad4b7Schristos &xfr->name, dns_dbtype_zone, xfr->rdclass, 0,
299*4afad4b7Schristos NULL, /* XXX guess */
300*4afad4b7Schristos dbp);
301*4afad4b7Schristos if (result == ISC_R_SUCCESS) {
302*4afad4b7Schristos dns_zone_rpz_enable_db(xfr->zone, *dbp);
303*4afad4b7Schristos dns_zone_catz_enable_db(xfr->zone, *dbp);
304*4afad4b7Schristos }
305*4afad4b7Schristos return (result);
306*4afad4b7Schristos }
307*4afad4b7Schristos
308*4afad4b7Schristos static isc_result_t
axfr_putdata(dns_xfrin_ctx_t * xfr,dns_diffop_t op,dns_name_t * name,dns_ttl_t ttl,dns_rdata_t * rdata)309*4afad4b7Schristos axfr_putdata(dns_xfrin_ctx_t *xfr, dns_diffop_t op, dns_name_t *name,
310*4afad4b7Schristos dns_ttl_t ttl, dns_rdata_t *rdata) {
311*4afad4b7Schristos isc_result_t result;
312*4afad4b7Schristos
313*4afad4b7Schristos dns_difftuple_t *tuple = NULL;
314*4afad4b7Schristos
315*4afad4b7Schristos if (rdata->rdclass != xfr->rdclass) {
316*4afad4b7Schristos return (DNS_R_BADCLASS);
317*4afad4b7Schristos }
318*4afad4b7Schristos
319*4afad4b7Schristos CHECK(dns_zone_checknames(xfr->zone, name, rdata));
320*4afad4b7Schristos CHECK(dns_difftuple_create(xfr->diff.mctx, op, name, ttl, rdata,
321*4afad4b7Schristos &tuple));
322*4afad4b7Schristos dns_diff_append(&xfr->diff, &tuple);
323*4afad4b7Schristos if (++xfr->difflen > 100) {
324*4afad4b7Schristos CHECK(axfr_apply(xfr));
325*4afad4b7Schristos }
326*4afad4b7Schristos result = ISC_R_SUCCESS;
327*4afad4b7Schristos failure:
328*4afad4b7Schristos return (result);
329*4afad4b7Schristos }
330*4afad4b7Schristos
331*4afad4b7Schristos /*
332*4afad4b7Schristos * Store a set of AXFR RRs in the database.
333*4afad4b7Schristos */
334*4afad4b7Schristos static isc_result_t
axfr_apply(dns_xfrin_ctx_t * xfr)335*4afad4b7Schristos axfr_apply(dns_xfrin_ctx_t *xfr) {
336*4afad4b7Schristos isc_result_t result;
337*4afad4b7Schristos uint64_t records;
338*4afad4b7Schristos
339*4afad4b7Schristos CHECK(dns_diff_load(&xfr->diff, xfr->axfr.add, xfr->axfr.add_private));
340*4afad4b7Schristos xfr->difflen = 0;
341*4afad4b7Schristos dns_diff_clear(&xfr->diff);
342*4afad4b7Schristos if (xfr->maxrecords != 0U) {
343*4afad4b7Schristos result = dns_db_getsize(xfr->db, xfr->ver, &records, NULL);
344*4afad4b7Schristos if (result == ISC_R_SUCCESS && records > xfr->maxrecords) {
345*4afad4b7Schristos result = DNS_R_TOOMANYRECORDS;
346*4afad4b7Schristos goto failure;
347*4afad4b7Schristos }
348*4afad4b7Schristos }
349*4afad4b7Schristos result = ISC_R_SUCCESS;
350*4afad4b7Schristos failure:
351*4afad4b7Schristos return (result);
352*4afad4b7Schristos }
353*4afad4b7Schristos
354*4afad4b7Schristos static isc_result_t
axfr_commit(dns_xfrin_ctx_t * xfr)355*4afad4b7Schristos axfr_commit(dns_xfrin_ctx_t *xfr) {
356*4afad4b7Schristos isc_result_t result;
357*4afad4b7Schristos
358*4afad4b7Schristos CHECK(axfr_apply(xfr));
359*4afad4b7Schristos CHECK(dns_db_endload(xfr->db, &xfr->axfr));
360*4afad4b7Schristos CHECK(dns_zone_verifydb(xfr->zone, xfr->db, NULL));
361*4afad4b7Schristos
362*4afad4b7Schristos result = ISC_R_SUCCESS;
363*4afad4b7Schristos failure:
364*4afad4b7Schristos return (result);
365*4afad4b7Schristos }
366*4afad4b7Schristos
367*4afad4b7Schristos static isc_result_t
axfr_finalize(dns_xfrin_ctx_t * xfr)368*4afad4b7Schristos axfr_finalize(dns_xfrin_ctx_t *xfr) {
369*4afad4b7Schristos isc_result_t result;
370*4afad4b7Schristos
371*4afad4b7Schristos CHECK(dns_zone_replacedb(xfr->zone, xfr->db, true));
372*4afad4b7Schristos
373*4afad4b7Schristos result = ISC_R_SUCCESS;
374*4afad4b7Schristos failure:
375*4afad4b7Schristos return (result);
376*4afad4b7Schristos }
377*4afad4b7Schristos
378*4afad4b7Schristos /**************************************************************************/
379*4afad4b7Schristos /*
380*4afad4b7Schristos * IXFR handling
381*4afad4b7Schristos */
382*4afad4b7Schristos
383*4afad4b7Schristos static isc_result_t
ixfr_init(dns_xfrin_ctx_t * xfr)384*4afad4b7Schristos ixfr_init(dns_xfrin_ctx_t *xfr) {
385*4afad4b7Schristos isc_result_t result;
386*4afad4b7Schristos char *journalfile;
387*4afad4b7Schristos
388*4afad4b7Schristos if (xfr->reqtype != dns_rdatatype_ixfr) {
389*4afad4b7Schristos xfrin_log(xfr, ISC_LOG_ERROR,
390*4afad4b7Schristos "got incremental response to AXFR request");
391*4afad4b7Schristos return (DNS_R_FORMERR);
392*4afad4b7Schristos }
393*4afad4b7Schristos
394*4afad4b7Schristos xfr->is_ixfr = true;
395*4afad4b7Schristos INSIST(xfr->db != NULL);
396*4afad4b7Schristos xfr->difflen = 0;
397*4afad4b7Schristos
398*4afad4b7Schristos journalfile = dns_zone_getjournal(xfr->zone);
399*4afad4b7Schristos if (journalfile != NULL) {
400*4afad4b7Schristos CHECK(dns_journal_open(xfr->mctx, journalfile,
401*4afad4b7Schristos DNS_JOURNAL_CREATE, &xfr->ixfr.journal));
402*4afad4b7Schristos }
403*4afad4b7Schristos
404*4afad4b7Schristos result = ISC_R_SUCCESS;
405*4afad4b7Schristos failure:
406*4afad4b7Schristos return (result);
407*4afad4b7Schristos }
408*4afad4b7Schristos
409*4afad4b7Schristos static isc_result_t
ixfr_putdata(dns_xfrin_ctx_t * xfr,dns_diffop_t op,dns_name_t * name,dns_ttl_t ttl,dns_rdata_t * rdata)410*4afad4b7Schristos ixfr_putdata(dns_xfrin_ctx_t *xfr, dns_diffop_t op, dns_name_t *name,
411*4afad4b7Schristos dns_ttl_t ttl, dns_rdata_t *rdata) {
412*4afad4b7Schristos isc_result_t result;
413*4afad4b7Schristos dns_difftuple_t *tuple = NULL;
414*4afad4b7Schristos
415*4afad4b7Schristos if (rdata->rdclass != xfr->rdclass) {
416*4afad4b7Schristos return (DNS_R_BADCLASS);
417*4afad4b7Schristos }
418*4afad4b7Schristos
419*4afad4b7Schristos if (op == DNS_DIFFOP_ADD) {
420*4afad4b7Schristos CHECK(dns_zone_checknames(xfr->zone, name, rdata));
421*4afad4b7Schristos }
422*4afad4b7Schristos CHECK(dns_difftuple_create(xfr->diff.mctx, op, name, ttl, rdata,
423*4afad4b7Schristos &tuple));
424*4afad4b7Schristos dns_diff_append(&xfr->diff, &tuple);
425*4afad4b7Schristos if (++xfr->difflen > 100) {
426*4afad4b7Schristos CHECK(ixfr_apply(xfr));
427*4afad4b7Schristos }
428*4afad4b7Schristos result = ISC_R_SUCCESS;
429*4afad4b7Schristos failure:
430*4afad4b7Schristos return (result);
431*4afad4b7Schristos }
432*4afad4b7Schristos
433*4afad4b7Schristos /*
434*4afad4b7Schristos * Apply a set of IXFR changes to the database.
435*4afad4b7Schristos */
436*4afad4b7Schristos static isc_result_t
ixfr_apply(dns_xfrin_ctx_t * xfr)437*4afad4b7Schristos ixfr_apply(dns_xfrin_ctx_t *xfr) {
438*4afad4b7Schristos isc_result_t result;
439*4afad4b7Schristos uint64_t records;
440*4afad4b7Schristos
441*4afad4b7Schristos if (xfr->ver == NULL) {
442*4afad4b7Schristos CHECK(dns_db_newversion(xfr->db, &xfr->ver));
443*4afad4b7Schristos if (xfr->ixfr.journal != NULL) {
444*4afad4b7Schristos CHECK(dns_journal_begin_transaction(xfr->ixfr.journal));
445*4afad4b7Schristos }
446*4afad4b7Schristos }
447*4afad4b7Schristos CHECK(dns_diff_apply(&xfr->diff, xfr->db, xfr->ver));
448*4afad4b7Schristos if (xfr->maxrecords != 0U) {
449*4afad4b7Schristos result = dns_db_getsize(xfr->db, xfr->ver, &records, NULL);
450*4afad4b7Schristos if (result == ISC_R_SUCCESS && records > xfr->maxrecords) {
451*4afad4b7Schristos result = DNS_R_TOOMANYRECORDS;
452*4afad4b7Schristos goto failure;
453*4afad4b7Schristos }
454*4afad4b7Schristos }
455*4afad4b7Schristos if (xfr->ixfr.journal != NULL) {
456*4afad4b7Schristos result = dns_journal_writediff(xfr->ixfr.journal, &xfr->diff);
457*4afad4b7Schristos if (result != ISC_R_SUCCESS) {
458*4afad4b7Schristos goto failure;
459*4afad4b7Schristos }
460*4afad4b7Schristos }
461*4afad4b7Schristos dns_diff_clear(&xfr->diff);
462*4afad4b7Schristos xfr->difflen = 0;
463*4afad4b7Schristos result = ISC_R_SUCCESS;
464*4afad4b7Schristos failure:
465*4afad4b7Schristos return (result);
466*4afad4b7Schristos }
467*4afad4b7Schristos
468*4afad4b7Schristos static isc_result_t
ixfr_commit(dns_xfrin_ctx_t * xfr)469*4afad4b7Schristos ixfr_commit(dns_xfrin_ctx_t *xfr) {
470*4afad4b7Schristos isc_result_t result;
471*4afad4b7Schristos
472*4afad4b7Schristos CHECK(ixfr_apply(xfr));
473*4afad4b7Schristos if (xfr->ver != NULL) {
474*4afad4b7Schristos CHECK(dns_zone_verifydb(xfr->zone, xfr->db, xfr->ver));
475*4afad4b7Schristos /* XXX enter ready-to-commit state here */
476*4afad4b7Schristos if (xfr->ixfr.journal != NULL) {
477*4afad4b7Schristos CHECK(dns_journal_commit(xfr->ixfr.journal));
478*4afad4b7Schristos }
479*4afad4b7Schristos dns_db_closeversion(xfr->db, &xfr->ver, true);
480*4afad4b7Schristos dns_zone_markdirty(xfr->zone);
481*4afad4b7Schristos }
482*4afad4b7Schristos result = ISC_R_SUCCESS;
483*4afad4b7Schristos failure:
484*4afad4b7Schristos return (result);
485*4afad4b7Schristos }
486*4afad4b7Schristos
487*4afad4b7Schristos /**************************************************************************/
488*4afad4b7Schristos /*
489*4afad4b7Schristos * Common AXFR/IXFR protocol code
490*4afad4b7Schristos */
491*4afad4b7Schristos
492*4afad4b7Schristos /*
493*4afad4b7Schristos * Handle a single incoming resource record according to the current
494*4afad4b7Schristos * state.
495*4afad4b7Schristos */
496*4afad4b7Schristos static isc_result_t
xfr_rr(dns_xfrin_ctx_t * xfr,dns_name_t * name,uint32_t ttl,dns_rdata_t * rdata)497*4afad4b7Schristos xfr_rr(dns_xfrin_ctx_t *xfr, dns_name_t *name, uint32_t ttl,
498*4afad4b7Schristos dns_rdata_t *rdata) {
499*4afad4b7Schristos isc_result_t result;
500*4afad4b7Schristos
501*4afad4b7Schristos xfr->nrecs++;
502*4afad4b7Schristos
503*4afad4b7Schristos if (rdata->type == dns_rdatatype_none ||
504*4afad4b7Schristos dns_rdatatype_ismeta(rdata->type))
505*4afad4b7Schristos {
506*4afad4b7Schristos FAIL(DNS_R_FORMERR);
507*4afad4b7Schristos }
508*4afad4b7Schristos
509*4afad4b7Schristos /*
510*4afad4b7Schristos * Immediately reject the entire transfer if the RR that is currently
511*4afad4b7Schristos * being processed is an SOA record that is not placed at the zone
512*4afad4b7Schristos * apex.
513*4afad4b7Schristos */
514*4afad4b7Schristos if (rdata->type == dns_rdatatype_soa &&
515*4afad4b7Schristos !dns_name_equal(&xfr->name, name))
516*4afad4b7Schristos {
517*4afad4b7Schristos char namebuf[DNS_NAME_FORMATSIZE];
518*4afad4b7Schristos dns_name_format(name, namebuf, sizeof(namebuf));
519*4afad4b7Schristos xfrin_log(xfr, ISC_LOG_DEBUG(3), "SOA name mismatch: '%s'",
520*4afad4b7Schristos namebuf);
521*4afad4b7Schristos FAIL(DNS_R_NOTZONETOP);
522*4afad4b7Schristos }
523*4afad4b7Schristos
524*4afad4b7Schristos redo:
525*4afad4b7Schristos switch (xfr->state) {
526*4afad4b7Schristos case XFRST_SOAQUERY:
527*4afad4b7Schristos if (rdata->type != dns_rdatatype_soa) {
528*4afad4b7Schristos xfrin_log(xfr, ISC_LOG_ERROR,
529*4afad4b7Schristos "non-SOA response to SOA query");
530*4afad4b7Schristos FAIL(DNS_R_FORMERR);
531*4afad4b7Schristos }
532*4afad4b7Schristos xfr->end_serial = dns_soa_getserial(rdata);
533*4afad4b7Schristos if (!DNS_SERIAL_GT(xfr->end_serial, xfr->ixfr.request_serial) &&
534*4afad4b7Schristos !dns_zone_isforced(xfr->zone))
535*4afad4b7Schristos {
536*4afad4b7Schristos xfrin_log(xfr, ISC_LOG_DEBUG(3),
537*4afad4b7Schristos "requested serial %u, "
538*4afad4b7Schristos "master has %u, not updating",
539*4afad4b7Schristos xfr->ixfr.request_serial, xfr->end_serial);
540*4afad4b7Schristos FAIL(DNS_R_UPTODATE);
541*4afad4b7Schristos }
542*4afad4b7Schristos xfr->state = XFRST_GOTSOA;
543*4afad4b7Schristos break;
544*4afad4b7Schristos
545*4afad4b7Schristos case XFRST_GOTSOA:
546*4afad4b7Schristos /*
547*4afad4b7Schristos * Skip other records in the answer section.
548*4afad4b7Schristos */
549*4afad4b7Schristos break;
550*4afad4b7Schristos
551*4afad4b7Schristos case XFRST_INITIALSOA:
552*4afad4b7Schristos if (rdata->type != dns_rdatatype_soa) {
553*4afad4b7Schristos xfrin_log(xfr, ISC_LOG_ERROR,
554*4afad4b7Schristos "first RR in zone transfer must be SOA");
555*4afad4b7Schristos FAIL(DNS_R_FORMERR);
556*4afad4b7Schristos }
557*4afad4b7Schristos /*
558*4afad4b7Schristos * Remember the serial number in the initial SOA.
559*4afad4b7Schristos * We need it to recognize the end of an IXFR.
560*4afad4b7Schristos */
561*4afad4b7Schristos xfr->end_serial = dns_soa_getserial(rdata);
562*4afad4b7Schristos if (xfr->reqtype == dns_rdatatype_ixfr &&
563*4afad4b7Schristos !DNS_SERIAL_GT(xfr->end_serial, xfr->ixfr.request_serial) &&
564*4afad4b7Schristos !dns_zone_isforced(xfr->zone))
565*4afad4b7Schristos {
566*4afad4b7Schristos /*
567*4afad4b7Schristos * This must be the single SOA record that is
568*4afad4b7Schristos * sent when the current version on the master
569*4afad4b7Schristos * is not newer than the version in the request.
570*4afad4b7Schristos */
571*4afad4b7Schristos xfrin_log(xfr, ISC_LOG_DEBUG(3),
572*4afad4b7Schristos "requested serial %u, "
573*4afad4b7Schristos "master has %u, not updating",
574*4afad4b7Schristos xfr->ixfr.request_serial, xfr->end_serial);
575*4afad4b7Schristos FAIL(DNS_R_UPTODATE);
576*4afad4b7Schristos }
577*4afad4b7Schristos if (xfr->reqtype == dns_rdatatype_axfr) {
578*4afad4b7Schristos xfr->checkid = false;
579*4afad4b7Schristos }
580*4afad4b7Schristos xfr->firstsoa = *rdata;
581*4afad4b7Schristos if (xfr->firstsoa_data != NULL) {
582*4afad4b7Schristos isc_mem_free(xfr->mctx, xfr->firstsoa_data);
583*4afad4b7Schristos }
584*4afad4b7Schristos xfr->firstsoa_data = isc_mem_allocate(xfr->mctx, rdata->length);
585*4afad4b7Schristos memcpy(xfr->firstsoa_data, rdata->data, rdata->length);
586*4afad4b7Schristos xfr->firstsoa.data = xfr->firstsoa_data;
587*4afad4b7Schristos xfr->state = XFRST_FIRSTDATA;
588*4afad4b7Schristos break;
589*4afad4b7Schristos
590*4afad4b7Schristos case XFRST_FIRSTDATA:
591*4afad4b7Schristos /*
592*4afad4b7Schristos * If the transfer begins with one SOA record, it is an AXFR,
593*4afad4b7Schristos * if it begins with two SOAs, it is an IXFR.
594*4afad4b7Schristos */
595*4afad4b7Schristos if (xfr->reqtype == dns_rdatatype_ixfr &&
596*4afad4b7Schristos rdata->type == dns_rdatatype_soa &&
597*4afad4b7Schristos xfr->ixfr.request_serial == dns_soa_getserial(rdata))
598*4afad4b7Schristos {
599*4afad4b7Schristos xfrin_log(xfr, ISC_LOG_DEBUG(3),
600*4afad4b7Schristos "got incremental response");
601*4afad4b7Schristos CHECK(ixfr_init(xfr));
602*4afad4b7Schristos xfr->state = XFRST_IXFR_DELSOA;
603*4afad4b7Schristos } else {
604*4afad4b7Schristos xfrin_log(xfr, ISC_LOG_DEBUG(3),
605*4afad4b7Schristos "got nonincremental response");
606*4afad4b7Schristos CHECK(axfr_init(xfr));
607*4afad4b7Schristos xfr->state = XFRST_AXFR;
608*4afad4b7Schristos }
609*4afad4b7Schristos goto redo;
610*4afad4b7Schristos
611*4afad4b7Schristos case XFRST_IXFR_DELSOA:
612*4afad4b7Schristos INSIST(rdata->type == dns_rdatatype_soa);
613*4afad4b7Schristos CHECK(ixfr_putdata(xfr, DNS_DIFFOP_DEL, name, ttl, rdata));
614*4afad4b7Schristos xfr->state = XFRST_IXFR_DEL;
615*4afad4b7Schristos break;
616*4afad4b7Schristos
617*4afad4b7Schristos case XFRST_IXFR_DEL:
618*4afad4b7Schristos if (rdata->type == dns_rdatatype_soa) {
619*4afad4b7Schristos uint32_t soa_serial = dns_soa_getserial(rdata);
620*4afad4b7Schristos xfr->state = XFRST_IXFR_ADDSOA;
621*4afad4b7Schristos xfr->ixfr.current_serial = soa_serial;
622*4afad4b7Schristos goto redo;
623*4afad4b7Schristos }
624*4afad4b7Schristos CHECK(ixfr_putdata(xfr, DNS_DIFFOP_DEL, name, ttl, rdata));
625*4afad4b7Schristos break;
626*4afad4b7Schristos
627*4afad4b7Schristos case XFRST_IXFR_ADDSOA:
628*4afad4b7Schristos INSIST(rdata->type == dns_rdatatype_soa);
629*4afad4b7Schristos CHECK(ixfr_putdata(xfr, DNS_DIFFOP_ADD, name, ttl, rdata));
630*4afad4b7Schristos xfr->state = XFRST_IXFR_ADD;
631*4afad4b7Schristos break;
632*4afad4b7Schristos
633*4afad4b7Schristos case XFRST_IXFR_ADD:
634*4afad4b7Schristos if (rdata->type == dns_rdatatype_soa) {
635*4afad4b7Schristos uint32_t soa_serial = dns_soa_getserial(rdata);
636*4afad4b7Schristos if (soa_serial == xfr->end_serial) {
637*4afad4b7Schristos CHECK(ixfr_commit(xfr));
638*4afad4b7Schristos xfr->state = XFRST_IXFR_END;
639*4afad4b7Schristos break;
640*4afad4b7Schristos } else if (soa_serial != xfr->ixfr.current_serial) {
641*4afad4b7Schristos xfrin_log(xfr, ISC_LOG_ERROR,
642*4afad4b7Schristos "IXFR out of sync: "
643*4afad4b7Schristos "expected serial %u, got %u",
644*4afad4b7Schristos xfr->ixfr.current_serial, soa_serial);
645*4afad4b7Schristos FAIL(DNS_R_FORMERR);
646*4afad4b7Schristos } else {
647*4afad4b7Schristos CHECK(ixfr_commit(xfr));
648*4afad4b7Schristos xfr->state = XFRST_IXFR_DELSOA;
649*4afad4b7Schristos goto redo;
650*4afad4b7Schristos }
651*4afad4b7Schristos }
652*4afad4b7Schristos if (rdata->type == dns_rdatatype_ns &&
653*4afad4b7Schristos dns_name_iswildcard(name))
654*4afad4b7Schristos {
655*4afad4b7Schristos FAIL(DNS_R_INVALIDNS);
656*4afad4b7Schristos }
657*4afad4b7Schristos CHECK(ixfr_putdata(xfr, DNS_DIFFOP_ADD, name, ttl, rdata));
658*4afad4b7Schristos break;
659*4afad4b7Schristos
660*4afad4b7Schristos case XFRST_AXFR:
661*4afad4b7Schristos /*
662*4afad4b7Schristos * Old BINDs sent cross class A records for non IN classes.
663*4afad4b7Schristos */
664*4afad4b7Schristos if (rdata->type == dns_rdatatype_a &&
665*4afad4b7Schristos rdata->rdclass != xfr->rdclass &&
666*4afad4b7Schristos xfr->rdclass != dns_rdataclass_in)
667*4afad4b7Schristos {
668*4afad4b7Schristos break;
669*4afad4b7Schristos }
670*4afad4b7Schristos CHECK(axfr_putdata(xfr, DNS_DIFFOP_ADD, name, ttl, rdata));
671*4afad4b7Schristos if (rdata->type == dns_rdatatype_soa) {
672*4afad4b7Schristos /*
673*4afad4b7Schristos * Use dns_rdata_compare instead of memcmp to
674*4afad4b7Schristos * allow for case differences.
675*4afad4b7Schristos */
676*4afad4b7Schristos if (dns_rdata_compare(rdata, &xfr->firstsoa) != 0) {
677*4afad4b7Schristos xfrin_log(xfr, ISC_LOG_ERROR,
678*4afad4b7Schristos "start and ending SOA records "
679*4afad4b7Schristos "mismatch");
680*4afad4b7Schristos FAIL(DNS_R_FORMERR);
681*4afad4b7Schristos }
682*4afad4b7Schristos CHECK(axfr_commit(xfr));
683*4afad4b7Schristos xfr->state = XFRST_AXFR_END;
684*4afad4b7Schristos break;
685*4afad4b7Schristos }
686*4afad4b7Schristos break;
687*4afad4b7Schristos case XFRST_AXFR_END:
688*4afad4b7Schristos case XFRST_IXFR_END:
689*4afad4b7Schristos FAIL(DNS_R_EXTRADATA);
690*4afad4b7Schristos FALLTHROUGH;
691*4afad4b7Schristos default:
692*4afad4b7Schristos UNREACHABLE();
693*4afad4b7Schristos }
694*4afad4b7Schristos result = ISC_R_SUCCESS;
695*4afad4b7Schristos failure:
696*4afad4b7Schristos return (result);
697*4afad4b7Schristos }
698*4afad4b7Schristos
699*4afad4b7Schristos isc_result_t
dns_xfrin_create(dns_zone_t * zone,dns_rdatatype_t xfrtype,const isc_sockaddr_t * masteraddr,const isc_sockaddr_t * sourceaddr,isc_dscp_t dscp,dns_tsigkey_t * tsigkey,isc_mem_t * mctx,isc_timermgr_t * timermgr,isc_socketmgr_t * socketmgr,isc_task_t * task,dns_xfrindone_t done,dns_xfrin_ctx_t ** xfrp)700*4afad4b7Schristos dns_xfrin_create(dns_zone_t *zone, dns_rdatatype_t xfrtype,
701*4afad4b7Schristos const isc_sockaddr_t *masteraddr,
702*4afad4b7Schristos const isc_sockaddr_t *sourceaddr, isc_dscp_t dscp,
703*4afad4b7Schristos dns_tsigkey_t *tsigkey, isc_mem_t *mctx,
704*4afad4b7Schristos isc_timermgr_t *timermgr, isc_socketmgr_t *socketmgr,
705*4afad4b7Schristos isc_task_t *task, dns_xfrindone_t done,
706*4afad4b7Schristos dns_xfrin_ctx_t **xfrp) {
707*4afad4b7Schristos dns_name_t *zonename = dns_zone_getorigin(zone);
708*4afad4b7Schristos dns_xfrin_ctx_t *xfr = NULL;
709*4afad4b7Schristos isc_result_t result;
710*4afad4b7Schristos dns_db_t *db = NULL;
711*4afad4b7Schristos
712*4afad4b7Schristos REQUIRE(xfrp != NULL && *xfrp == NULL);
713*4afad4b7Schristos
714*4afad4b7Schristos (void)dns_zone_getdb(zone, &db);
715*4afad4b7Schristos
716*4afad4b7Schristos if (xfrtype == dns_rdatatype_soa || xfrtype == dns_rdatatype_ixfr) {
717*4afad4b7Schristos REQUIRE(db != NULL);
718*4afad4b7Schristos }
719*4afad4b7Schristos
720*4afad4b7Schristos CHECK(xfrin_create(mctx, zone, db, task, timermgr, socketmgr, zonename,
721*4afad4b7Schristos dns_zone_getclass(zone), xfrtype, masteraddr,
722*4afad4b7Schristos sourceaddr, dscp, tsigkey, &xfr));
723*4afad4b7Schristos
724*4afad4b7Schristos if (db != NULL) {
725*4afad4b7Schristos xfr->zone_had_db = true;
726*4afad4b7Schristos }
727*4afad4b7Schristos
728*4afad4b7Schristos CHECK(xfrin_start(xfr));
729*4afad4b7Schristos
730*4afad4b7Schristos xfr->done = done;
731*4afad4b7Schristos if (xfr->done != NULL) {
732*4afad4b7Schristos xfr->refcount++;
733*4afad4b7Schristos }
734*4afad4b7Schristos *xfrp = xfr;
735*4afad4b7Schristos
736*4afad4b7Schristos failure:
737*4afad4b7Schristos if (db != NULL) {
738*4afad4b7Schristos dns_db_detach(&db);
739*4afad4b7Schristos }
740*4afad4b7Schristos if (result != ISC_R_SUCCESS) {
741*4afad4b7Schristos char zonetext[DNS_NAME_MAXTEXT + 32];
742*4afad4b7Schristos dns_zone_name(zone, zonetext, sizeof(zonetext));
743*4afad4b7Schristos xfrin_log1(ISC_LOG_ERROR, zonetext, masteraddr,
744*4afad4b7Schristos "zone transfer setup failed");
745*4afad4b7Schristos }
746*4afad4b7Schristos return (result);
747*4afad4b7Schristos }
748*4afad4b7Schristos
749*4afad4b7Schristos void
dns_xfrin_shutdown(dns_xfrin_ctx_t * xfr)750*4afad4b7Schristos dns_xfrin_shutdown(dns_xfrin_ctx_t *xfr) {
751*4afad4b7Schristos if (!xfr->shuttingdown) {
752*4afad4b7Schristos xfrin_fail(xfr, ISC_R_CANCELED, "shut down");
753*4afad4b7Schristos }
754*4afad4b7Schristos }
755*4afad4b7Schristos
756*4afad4b7Schristos void
dns_xfrin_attach(dns_xfrin_ctx_t * source,dns_xfrin_ctx_t ** target)757*4afad4b7Schristos dns_xfrin_attach(dns_xfrin_ctx_t *source, dns_xfrin_ctx_t **target) {
758*4afad4b7Schristos REQUIRE(target != NULL && *target == NULL);
759*4afad4b7Schristos source->refcount++;
760*4afad4b7Schristos *target = source;
761*4afad4b7Schristos }
762*4afad4b7Schristos
763*4afad4b7Schristos void
dns_xfrin_detach(dns_xfrin_ctx_t ** xfrp)764*4afad4b7Schristos dns_xfrin_detach(dns_xfrin_ctx_t **xfrp) {
765*4afad4b7Schristos dns_xfrin_ctx_t *xfr = *xfrp;
766*4afad4b7Schristos *xfrp = NULL;
767*4afad4b7Schristos INSIST(xfr->refcount > 0);
768*4afad4b7Schristos xfr->refcount--;
769*4afad4b7Schristos maybe_free(xfr);
770*4afad4b7Schristos }
771*4afad4b7Schristos
772*4afad4b7Schristos static void
xfrin_cancelio(dns_xfrin_ctx_t * xfr)773*4afad4b7Schristos xfrin_cancelio(dns_xfrin_ctx_t *xfr) {
774*4afad4b7Schristos if (xfr->connects > 0) {
775*4afad4b7Schristos isc_socket_cancel(xfr->socket, xfr->task,
776*4afad4b7Schristos ISC_SOCKCANCEL_CONNECT);
777*4afad4b7Schristos } else if (xfr->recvs > 0) {
778*4afad4b7Schristos dns_tcpmsg_cancelread(&xfr->tcpmsg);
779*4afad4b7Schristos } else if (xfr->sends > 0) {
780*4afad4b7Schristos isc_socket_cancel(xfr->socket, xfr->task, ISC_SOCKCANCEL_SEND);
781*4afad4b7Schristos }
782*4afad4b7Schristos }
783*4afad4b7Schristos
784*4afad4b7Schristos static void
xfrin_reset(dns_xfrin_ctx_t * xfr)785*4afad4b7Schristos xfrin_reset(dns_xfrin_ctx_t *xfr) {
786*4afad4b7Schristos REQUIRE(VALID_XFRIN(xfr));
787*4afad4b7Schristos
788*4afad4b7Schristos xfrin_log(xfr, ISC_LOG_INFO, "resetting");
789*4afad4b7Schristos
790*4afad4b7Schristos xfrin_cancelio(xfr);
791*4afad4b7Schristos
792*4afad4b7Schristos if (xfr->socket != NULL) {
793*4afad4b7Schristos isc_socket_detach(&xfr->socket);
794*4afad4b7Schristos }
795*4afad4b7Schristos
796*4afad4b7Schristos if (xfr->lasttsig != NULL) {
797*4afad4b7Schristos isc_buffer_free(&xfr->lasttsig);
798*4afad4b7Schristos }
799*4afad4b7Schristos
800*4afad4b7Schristos dns_diff_clear(&xfr->diff);
801*4afad4b7Schristos xfr->difflen = 0;
802*4afad4b7Schristos
803*4afad4b7Schristos if (xfr->ixfr.journal != NULL) {
804*4afad4b7Schristos dns_journal_destroy(&xfr->ixfr.journal);
805*4afad4b7Schristos }
806*4afad4b7Schristos
807*4afad4b7Schristos if (xfr->axfr.add_private != NULL) {
808*4afad4b7Schristos (void)dns_db_endload(xfr->db, &xfr->axfr);
809*4afad4b7Schristos }
810*4afad4b7Schristos
811*4afad4b7Schristos if (xfr->tcpmsg_valid) {
812*4afad4b7Schristos dns_tcpmsg_invalidate(&xfr->tcpmsg);
813*4afad4b7Schristos xfr->tcpmsg_valid = false;
814*4afad4b7Schristos }
815*4afad4b7Schristos
816*4afad4b7Schristos if (xfr->ver != NULL) {
817*4afad4b7Schristos dns_db_closeversion(xfr->db, &xfr->ver, false);
818*4afad4b7Schristos }
819*4afad4b7Schristos }
820*4afad4b7Schristos
821*4afad4b7Schristos static void
xfrin_fail(dns_xfrin_ctx_t * xfr,isc_result_t result,const char * msg)822*4afad4b7Schristos xfrin_fail(dns_xfrin_ctx_t *xfr, isc_result_t result, const char *msg) {
823*4afad4b7Schristos if (result != DNS_R_UPTODATE && result != DNS_R_TOOMANYRECORDS) {
824*4afad4b7Schristos xfrin_log(xfr, ISC_LOG_ERROR, "%s: %s", msg,
825*4afad4b7Schristos isc_result_totext(result));
826*4afad4b7Schristos if (xfr->is_ixfr) {
827*4afad4b7Schristos /* Pass special result code to force AXFR retry */
828*4afad4b7Schristos result = DNS_R_BADIXFR;
829*4afad4b7Schristos }
830*4afad4b7Schristos }
831*4afad4b7Schristos xfrin_cancelio(xfr);
832*4afad4b7Schristos /*
833*4afad4b7Schristos * Close the journal.
834*4afad4b7Schristos */
835*4afad4b7Schristos if (xfr->ixfr.journal != NULL) {
836*4afad4b7Schristos dns_journal_destroy(&xfr->ixfr.journal);
837*4afad4b7Schristos }
838*4afad4b7Schristos if (xfr->done != NULL) {
839*4afad4b7Schristos (xfr->done)(xfr->zone, result);
840*4afad4b7Schristos xfr->done = NULL;
841*4afad4b7Schristos }
842*4afad4b7Schristos xfr->shuttingdown = true;
843*4afad4b7Schristos xfr->shutdown_result = result;
844*4afad4b7Schristos maybe_free(xfr);
845*4afad4b7Schristos }
846*4afad4b7Schristos
847*4afad4b7Schristos static isc_result_t
xfrin_create(isc_mem_t * mctx,dns_zone_t * zone,dns_db_t * db,isc_task_t * task,isc_timermgr_t * timermgr,isc_socketmgr_t * socketmgr,dns_name_t * zonename,dns_rdataclass_t rdclass,dns_rdatatype_t reqtype,const isc_sockaddr_t * masteraddr,const isc_sockaddr_t * sourceaddr,isc_dscp_t dscp,dns_tsigkey_t * tsigkey,dns_xfrin_ctx_t ** xfrp)848*4afad4b7Schristos xfrin_create(isc_mem_t *mctx, dns_zone_t *zone, dns_db_t *db, isc_task_t *task,
849*4afad4b7Schristos isc_timermgr_t *timermgr, isc_socketmgr_t *socketmgr,
850*4afad4b7Schristos dns_name_t *zonename, dns_rdataclass_t rdclass,
851*4afad4b7Schristos dns_rdatatype_t reqtype, const isc_sockaddr_t *masteraddr,
852*4afad4b7Schristos const isc_sockaddr_t *sourceaddr, isc_dscp_t dscp,
853*4afad4b7Schristos dns_tsigkey_t *tsigkey, dns_xfrin_ctx_t **xfrp) {
854*4afad4b7Schristos dns_xfrin_ctx_t *xfr = NULL;
855*4afad4b7Schristos isc_result_t result;
856*4afad4b7Schristos
857*4afad4b7Schristos xfr = isc_mem_get(mctx, sizeof(*xfr));
858*4afad4b7Schristos xfr->mctx = NULL;
859*4afad4b7Schristos isc_mem_attach(mctx, &xfr->mctx);
860*4afad4b7Schristos xfr->refcount = 0;
861*4afad4b7Schristos xfr->zone = NULL;
862*4afad4b7Schristos dns_zone_iattach(zone, &xfr->zone);
863*4afad4b7Schristos xfr->task = NULL;
864*4afad4b7Schristos isc_task_attach(task, &xfr->task);
865*4afad4b7Schristos xfr->timer = NULL;
866*4afad4b7Schristos xfr->socketmgr = socketmgr;
867*4afad4b7Schristos xfr->done = NULL;
868*4afad4b7Schristos
869*4afad4b7Schristos xfr->connects = 0;
870*4afad4b7Schristos xfr->sends = 0;
871*4afad4b7Schristos xfr->recvs = 0;
872*4afad4b7Schristos xfr->shuttingdown = false;
873*4afad4b7Schristos xfr->shutdown_result = ISC_R_UNSET;
874*4afad4b7Schristos
875*4afad4b7Schristos dns_name_init(&xfr->name, NULL);
876*4afad4b7Schristos xfr->rdclass = rdclass;
877*4afad4b7Schristos xfr->checkid = true;
878*4afad4b7Schristos xfr->logit = true;
879*4afad4b7Schristos xfr->id = (dns_messageid_t)isc_random16();
880*4afad4b7Schristos xfr->reqtype = reqtype;
881*4afad4b7Schristos xfr->dscp = dscp;
882*4afad4b7Schristos
883*4afad4b7Schristos /* sockaddr */
884*4afad4b7Schristos xfr->socket = NULL;
885*4afad4b7Schristos /* qbuffer */
886*4afad4b7Schristos /* qbuffer_data */
887*4afad4b7Schristos /* tcpmsg */
888*4afad4b7Schristos xfr->tcpmsg_valid = false;
889*4afad4b7Schristos
890*4afad4b7Schristos xfr->zone_had_db = false;
891*4afad4b7Schristos xfr->db = NULL;
892*4afad4b7Schristos if (db != NULL) {
893*4afad4b7Schristos dns_db_attach(db, &xfr->db);
894*4afad4b7Schristos }
895*4afad4b7Schristos xfr->ver = NULL;
896*4afad4b7Schristos dns_diff_init(xfr->mctx, &xfr->diff);
897*4afad4b7Schristos xfr->difflen = 0;
898*4afad4b7Schristos
899*4afad4b7Schristos if (reqtype == dns_rdatatype_soa) {
900*4afad4b7Schristos xfr->state = XFRST_SOAQUERY;
901*4afad4b7Schristos } else {
902*4afad4b7Schristos xfr->state = XFRST_INITIALSOA;
903*4afad4b7Schristos }
904*4afad4b7Schristos /* end_serial */
905*4afad4b7Schristos
906*4afad4b7Schristos xfr->nmsg = 0;
907*4afad4b7Schristos xfr->nrecs = 0;
908*4afad4b7Schristos xfr->nbytes = 0;
909*4afad4b7Schristos xfr->maxrecords = dns_zone_getmaxrecords(zone);
910*4afad4b7Schristos isc_time_now(&xfr->start);
911*4afad4b7Schristos
912*4afad4b7Schristos xfr->tsigkey = NULL;
913*4afad4b7Schristos if (tsigkey != NULL) {
914*4afad4b7Schristos dns_tsigkey_attach(tsigkey, &xfr->tsigkey);
915*4afad4b7Schristos }
916*4afad4b7Schristos xfr->lasttsig = NULL;
917*4afad4b7Schristos xfr->tsigctx = NULL;
918*4afad4b7Schristos xfr->sincetsig = 0;
919*4afad4b7Schristos xfr->is_ixfr = false;
920*4afad4b7Schristos
921*4afad4b7Schristos /* ixfr.request_serial */
922*4afad4b7Schristos /* ixfr.current_serial */
923*4afad4b7Schristos xfr->ixfr.journal = NULL;
924*4afad4b7Schristos
925*4afad4b7Schristos xfr->axfr.add = NULL;
926*4afad4b7Schristos xfr->axfr.add_private = NULL;
927*4afad4b7Schristos dns_rdata_init(&xfr->firstsoa);
928*4afad4b7Schristos xfr->firstsoa_data = NULL;
929*4afad4b7Schristos
930*4afad4b7Schristos dns_name_dup(zonename, mctx, &xfr->name);
931*4afad4b7Schristos
932*4afad4b7Schristos CHECK(isc_timer_create(timermgr, isc_timertype_inactive, NULL, NULL,
933*4afad4b7Schristos task, xfrin_timeout, xfr, &xfr->timer));
934*4afad4b7Schristos CHECK(dns_timer_setidle(xfr->timer, dns_zone_getmaxxfrin(xfr->zone),
935*4afad4b7Schristos dns_zone_getidlein(xfr->zone), false));
936*4afad4b7Schristos
937*4afad4b7Schristos xfr->masteraddr = *masteraddr;
938*4afad4b7Schristos
939*4afad4b7Schristos INSIST(isc_sockaddr_pf(masteraddr) == isc_sockaddr_pf(sourceaddr));
940*4afad4b7Schristos xfr->sourceaddr = *sourceaddr;
941*4afad4b7Schristos isc_sockaddr_setport(&xfr->sourceaddr, 0);
942*4afad4b7Schristos
943*4afad4b7Schristos /*
944*4afad4b7Schristos * Reserve 2 bytes for TCP length at the beginning of the buffer.
945*4afad4b7Schristos */
946*4afad4b7Schristos isc_buffer_init(&xfr->qbuffer, &xfr->qbuffer_data[2],
947*4afad4b7Schristos sizeof(xfr->qbuffer_data) - 2);
948*4afad4b7Schristos
949*4afad4b7Schristos xfr->magic = XFRIN_MAGIC;
950*4afad4b7Schristos *xfrp = xfr;
951*4afad4b7Schristos return (ISC_R_SUCCESS);
952*4afad4b7Schristos
953*4afad4b7Schristos failure:
954*4afad4b7Schristos if (xfr->timer != NULL) {
955*4afad4b7Schristos isc_timer_destroy(&xfr->timer);
956*4afad4b7Schristos }
957*4afad4b7Schristos if (dns_name_dynamic(&xfr->name)) {
958*4afad4b7Schristos dns_name_free(&xfr->name, xfr->mctx);
959*4afad4b7Schristos }
960*4afad4b7Schristos if (xfr->tsigkey != NULL) {
961*4afad4b7Schristos dns_tsigkey_detach(&xfr->tsigkey);
962*4afad4b7Schristos }
963*4afad4b7Schristos if (xfr->db != NULL) {
964*4afad4b7Schristos dns_db_detach(&xfr->db);
965*4afad4b7Schristos }
966*4afad4b7Schristos isc_task_detach(&xfr->task);
967*4afad4b7Schristos dns_zone_idetach(&xfr->zone);
968*4afad4b7Schristos isc_mem_putanddetach(&xfr->mctx, xfr, sizeof(*xfr));
969*4afad4b7Schristos
970*4afad4b7Schristos return (result);
971*4afad4b7Schristos }
972*4afad4b7Schristos
973*4afad4b7Schristos static isc_result_t
xfrin_start(dns_xfrin_ctx_t * xfr)974*4afad4b7Schristos xfrin_start(dns_xfrin_ctx_t *xfr) {
975*4afad4b7Schristos isc_result_t result;
976*4afad4b7Schristos CHECK(isc_socket_create(xfr->socketmgr,
977*4afad4b7Schristos isc_sockaddr_pf(&xfr->sourceaddr),
978*4afad4b7Schristos isc_sockettype_tcp, &xfr->socket));
979*4afad4b7Schristos isc_socket_setname(xfr->socket, "xfrin", NULL);
980*4afad4b7Schristos #ifndef BROKEN_TCP_BIND_BEFORE_CONNECT
981*4afad4b7Schristos CHECK(isc_socket_bind(xfr->socket, &xfr->sourceaddr,
982*4afad4b7Schristos ISC_SOCKET_REUSEADDRESS));
983*4afad4b7Schristos #endif /* ifndef BROKEN_TCP_BIND_BEFORE_CONNECT */
984*4afad4b7Schristos isc_socket_dscp(xfr->socket, xfr->dscp);
985*4afad4b7Schristos CHECK(isc_socket_connect(xfr->socket, &xfr->masteraddr, xfr->task,
986*4afad4b7Schristos xfrin_connect_done, xfr));
987*4afad4b7Schristos xfr->connects++;
988*4afad4b7Schristos return (ISC_R_SUCCESS);
989*4afad4b7Schristos failure:
990*4afad4b7Schristos xfrin_fail(xfr, result, "failed setting up socket");
991*4afad4b7Schristos return (result);
992*4afad4b7Schristos }
993*4afad4b7Schristos
994*4afad4b7Schristos /* XXX the resolver could use this, too */
995*4afad4b7Schristos
996*4afad4b7Schristos static isc_result_t
render(dns_message_t * msg,isc_mem_t * mctx,isc_buffer_t * buf)997*4afad4b7Schristos render(dns_message_t *msg, isc_mem_t *mctx, isc_buffer_t *buf) {
998*4afad4b7Schristos dns_compress_t cctx;
999*4afad4b7Schristos bool cleanup_cctx = false;
1000*4afad4b7Schristos isc_result_t result;
1001*4afad4b7Schristos
1002*4afad4b7Schristos CHECK(dns_compress_init(&cctx, -1, mctx));
1003*4afad4b7Schristos cleanup_cctx = true;
1004*4afad4b7Schristos CHECK(dns_message_renderbegin(msg, &cctx, buf));
1005*4afad4b7Schristos CHECK(dns_message_rendersection(msg, DNS_SECTION_QUESTION, 0));
1006*4afad4b7Schristos CHECK(dns_message_rendersection(msg, DNS_SECTION_ANSWER, 0));
1007*4afad4b7Schristos CHECK(dns_message_rendersection(msg, DNS_SECTION_AUTHORITY, 0));
1008*4afad4b7Schristos CHECK(dns_message_rendersection(msg, DNS_SECTION_ADDITIONAL, 0));
1009*4afad4b7Schristos CHECK(dns_message_renderend(msg));
1010*4afad4b7Schristos result = ISC_R_SUCCESS;
1011*4afad4b7Schristos failure:
1012*4afad4b7Schristos if (cleanup_cctx) {
1013*4afad4b7Schristos dns_compress_invalidate(&cctx);
1014*4afad4b7Schristos }
1015*4afad4b7Schristos return (result);
1016*4afad4b7Schristos }
1017*4afad4b7Schristos
1018*4afad4b7Schristos /*
1019*4afad4b7Schristos * A connection has been established.
1020*4afad4b7Schristos */
1021*4afad4b7Schristos static void
xfrin_connect_done(isc_task_t * task,isc_event_t * event)1022*4afad4b7Schristos xfrin_connect_done(isc_task_t *task, isc_event_t *event) {
1023*4afad4b7Schristos isc_socket_connev_t *cev = (isc_socket_connev_t *)event;
1024*4afad4b7Schristos dns_xfrin_ctx_t *xfr = (dns_xfrin_ctx_t *)event->ev_arg;
1025*4afad4b7Schristos isc_result_t result = cev->result;
1026*4afad4b7Schristos char sourcetext[ISC_SOCKADDR_FORMATSIZE];
1027*4afad4b7Schristos char signerbuf[DNS_NAME_FORMATSIZE];
1028*4afad4b7Schristos const char *signer = "", *sep = "";
1029*4afad4b7Schristos isc_sockaddr_t sockaddr;
1030*4afad4b7Schristos dns_zonemgr_t *zmgr;
1031*4afad4b7Schristos isc_time_t now;
1032*4afad4b7Schristos
1033*4afad4b7Schristos REQUIRE(VALID_XFRIN(xfr));
1034*4afad4b7Schristos
1035*4afad4b7Schristos UNUSED(task);
1036*4afad4b7Schristos
1037*4afad4b7Schristos INSIST(event->ev_type == ISC_SOCKEVENT_CONNECT);
1038*4afad4b7Schristos isc_event_free(&event);
1039*4afad4b7Schristos
1040*4afad4b7Schristos xfr->connects--;
1041*4afad4b7Schristos if (xfr->shuttingdown) {
1042*4afad4b7Schristos maybe_free(xfr);
1043*4afad4b7Schristos return;
1044*4afad4b7Schristos }
1045*4afad4b7Schristos
1046*4afad4b7Schristos zmgr = dns_zone_getmgr(xfr->zone);
1047*4afad4b7Schristos if (zmgr != NULL) {
1048*4afad4b7Schristos if (result != ISC_R_SUCCESS) {
1049*4afad4b7Schristos TIME_NOW(&now);
1050*4afad4b7Schristos dns_zonemgr_unreachableadd(zmgr, &xfr->masteraddr,
1051*4afad4b7Schristos &xfr->sourceaddr, &now);
1052*4afad4b7Schristos goto failure;
1053*4afad4b7Schristos } else {
1054*4afad4b7Schristos dns_zonemgr_unreachabledel(zmgr, &xfr->masteraddr,
1055*4afad4b7Schristos &xfr->sourceaddr);
1056*4afad4b7Schristos }
1057*4afad4b7Schristos }
1058*4afad4b7Schristos
1059*4afad4b7Schristos result = isc_socket_getsockname(xfr->socket, &sockaddr);
1060*4afad4b7Schristos if (result == ISC_R_SUCCESS) {
1061*4afad4b7Schristos isc_sockaddr_format(&sockaddr, sourcetext, sizeof(sourcetext));
1062*4afad4b7Schristos } else {
1063*4afad4b7Schristos strlcpy(sourcetext, "<UNKNOWN>", sizeof(sourcetext));
1064*4afad4b7Schristos }
1065*4afad4b7Schristos
1066*4afad4b7Schristos if (xfr->tsigkey != NULL && xfr->tsigkey->key != NULL) {
1067*4afad4b7Schristos dns_name_format(dst_key_name(xfr->tsigkey->key), signerbuf,
1068*4afad4b7Schristos sizeof(signerbuf));
1069*4afad4b7Schristos sep = " TSIG ";
1070*4afad4b7Schristos signer = signerbuf;
1071*4afad4b7Schristos }
1072*4afad4b7Schristos
1073*4afad4b7Schristos xfrin_log(xfr, ISC_LOG_INFO, "connected using %s%s%s", sourcetext, sep,
1074*4afad4b7Schristos signer);
1075*4afad4b7Schristos
1076*4afad4b7Schristos dns_tcpmsg_init(xfr->mctx, xfr->socket, &xfr->tcpmsg);
1077*4afad4b7Schristos xfr->tcpmsg_valid = true;
1078*4afad4b7Schristos
1079*4afad4b7Schristos CHECK(xfrin_send_request(xfr));
1080*4afad4b7Schristos failure:
1081*4afad4b7Schristos if (result != ISC_R_SUCCESS) {
1082*4afad4b7Schristos xfrin_fail(xfr, result, "failed to connect");
1083*4afad4b7Schristos }
1084*4afad4b7Schristos }
1085*4afad4b7Schristos
1086*4afad4b7Schristos /*
1087*4afad4b7Schristos * Convert a tuple into a dns_name_t suitable for inserting
1088*4afad4b7Schristos * into the given dns_message_t.
1089*4afad4b7Schristos */
1090*4afad4b7Schristos static isc_result_t
tuple2msgname(dns_difftuple_t * tuple,dns_message_t * msg,dns_name_t ** target)1091*4afad4b7Schristos tuple2msgname(dns_difftuple_t *tuple, dns_message_t *msg, dns_name_t **target) {
1092*4afad4b7Schristos isc_result_t result;
1093*4afad4b7Schristos dns_rdata_t *rdata = NULL;
1094*4afad4b7Schristos dns_rdatalist_t *rdl = NULL;
1095*4afad4b7Schristos dns_rdataset_t *rds = NULL;
1096*4afad4b7Schristos dns_name_t *name = NULL;
1097*4afad4b7Schristos
1098*4afad4b7Schristos REQUIRE(target != NULL && *target == NULL);
1099*4afad4b7Schristos
1100*4afad4b7Schristos CHECK(dns_message_gettemprdata(msg, &rdata));
1101*4afad4b7Schristos dns_rdata_init(rdata);
1102*4afad4b7Schristos dns_rdata_clone(&tuple->rdata, rdata);
1103*4afad4b7Schristos
1104*4afad4b7Schristos CHECK(dns_message_gettemprdatalist(msg, &rdl));
1105*4afad4b7Schristos dns_rdatalist_init(rdl);
1106*4afad4b7Schristos rdl->type = tuple->rdata.type;
1107*4afad4b7Schristos rdl->rdclass = tuple->rdata.rdclass;
1108*4afad4b7Schristos rdl->ttl = tuple->ttl;
1109*4afad4b7Schristos ISC_LIST_APPEND(rdl->rdata, rdata, link);
1110*4afad4b7Schristos
1111*4afad4b7Schristos CHECK(dns_message_gettemprdataset(msg, &rds));
1112*4afad4b7Schristos CHECK(dns_rdatalist_tordataset(rdl, rds));
1113*4afad4b7Schristos
1114*4afad4b7Schristos CHECK(dns_message_gettempname(msg, &name));
1115*4afad4b7Schristos dns_name_clone(&tuple->name, name);
1116*4afad4b7Schristos ISC_LIST_APPEND(name->list, rds, link);
1117*4afad4b7Schristos
1118*4afad4b7Schristos *target = name;
1119*4afad4b7Schristos return (ISC_R_SUCCESS);
1120*4afad4b7Schristos
1121*4afad4b7Schristos failure:
1122*4afad4b7Schristos
1123*4afad4b7Schristos if (rds != NULL) {
1124*4afad4b7Schristos dns_rdataset_disassociate(rds);
1125*4afad4b7Schristos dns_message_puttemprdataset(msg, &rds);
1126*4afad4b7Schristos }
1127*4afad4b7Schristos if (rdl != NULL) {
1128*4afad4b7Schristos ISC_LIST_UNLINK(rdl->rdata, rdata, link);
1129*4afad4b7Schristos dns_message_puttemprdatalist(msg, &rdl);
1130*4afad4b7Schristos }
1131*4afad4b7Schristos if (rdata != NULL) {
1132*4afad4b7Schristos dns_message_puttemprdata(msg, &rdata);
1133*4afad4b7Schristos }
1134*4afad4b7Schristos
1135*4afad4b7Schristos return (result);
1136*4afad4b7Schristos }
1137*4afad4b7Schristos
1138*4afad4b7Schristos /*
1139*4afad4b7Schristos * Build an *XFR request and send its length prefix.
1140*4afad4b7Schristos */
1141*4afad4b7Schristos static isc_result_t
xfrin_send_request(dns_xfrin_ctx_t * xfr)1142*4afad4b7Schristos xfrin_send_request(dns_xfrin_ctx_t *xfr) {
1143*4afad4b7Schristos isc_result_t result;
1144*4afad4b7Schristos isc_region_t region;
1145*4afad4b7Schristos dns_rdataset_t *qrdataset = NULL;
1146*4afad4b7Schristos dns_message_t *msg = NULL;
1147*4afad4b7Schristos dns_difftuple_t *soatuple = NULL;
1148*4afad4b7Schristos dns_name_t *qname = NULL;
1149*4afad4b7Schristos dns_dbversion_t *ver = NULL;
1150*4afad4b7Schristos dns_name_t *msgsoaname = NULL;
1151*4afad4b7Schristos
1152*4afad4b7Schristos /* Create the request message */
1153*4afad4b7Schristos dns_message_create(xfr->mctx, DNS_MESSAGE_INTENTRENDER, &msg);
1154*4afad4b7Schristos CHECK(dns_message_settsigkey(msg, xfr->tsigkey));
1155*4afad4b7Schristos
1156*4afad4b7Schristos /* Create a name for the question section. */
1157*4afad4b7Schristos CHECK(dns_message_gettempname(msg, &qname));
1158*4afad4b7Schristos dns_name_clone(&xfr->name, qname);
1159*4afad4b7Schristos
1160*4afad4b7Schristos /* Formulate the question and attach it to the question name. */
1161*4afad4b7Schristos CHECK(dns_message_gettemprdataset(msg, &qrdataset));
1162*4afad4b7Schristos dns_rdataset_makequestion(qrdataset, xfr->rdclass, xfr->reqtype);
1163*4afad4b7Schristos ISC_LIST_APPEND(qname->list, qrdataset, link);
1164*4afad4b7Schristos qrdataset = NULL;
1165*4afad4b7Schristos
1166*4afad4b7Schristos dns_message_addname(msg, qname, DNS_SECTION_QUESTION);
1167*4afad4b7Schristos qname = NULL;
1168*4afad4b7Schristos
1169*4afad4b7Schristos if (xfr->reqtype == dns_rdatatype_ixfr) {
1170*4afad4b7Schristos /* Get the SOA and add it to the authority section. */
1171*4afad4b7Schristos /* XXX is using the current version the right thing? */
1172*4afad4b7Schristos dns_db_currentversion(xfr->db, &ver);
1173*4afad4b7Schristos CHECK(dns_db_createsoatuple(xfr->db, ver, xfr->mctx,
1174*4afad4b7Schristos DNS_DIFFOP_EXISTS, &soatuple));
1175*4afad4b7Schristos xfr->ixfr.request_serial = dns_soa_getserial(&soatuple->rdata);
1176*4afad4b7Schristos xfr->ixfr.current_serial = xfr->ixfr.request_serial;
1177*4afad4b7Schristos xfrin_log(xfr, ISC_LOG_DEBUG(3),
1178*4afad4b7Schristos "requesting IXFR for serial %u",
1179*4afad4b7Schristos xfr->ixfr.request_serial);
1180*4afad4b7Schristos
1181*4afad4b7Schristos CHECK(tuple2msgname(soatuple, msg, &msgsoaname));
1182*4afad4b7Schristos dns_message_addname(msg, msgsoaname, DNS_SECTION_AUTHORITY);
1183*4afad4b7Schristos } else if (xfr->reqtype == dns_rdatatype_soa) {
1184*4afad4b7Schristos CHECK(dns_db_getsoaserial(xfr->db, NULL,
1185*4afad4b7Schristos &xfr->ixfr.request_serial));
1186*4afad4b7Schristos }
1187*4afad4b7Schristos
1188*4afad4b7Schristos xfr->checkid = true;
1189*4afad4b7Schristos xfr->logit = true;
1190*4afad4b7Schristos xfr->id++;
1191*4afad4b7Schristos xfr->nmsg = 0;
1192*4afad4b7Schristos xfr->nrecs = 0;
1193*4afad4b7Schristos xfr->nbytes = 0;
1194*4afad4b7Schristos isc_time_now(&xfr->start);
1195*4afad4b7Schristos msg->id = xfr->id;
1196*4afad4b7Schristos if (xfr->tsigctx != NULL) {
1197*4afad4b7Schristos dst_context_destroy(&xfr->tsigctx);
1198*4afad4b7Schristos }
1199*4afad4b7Schristos
1200*4afad4b7Schristos CHECK(render(msg, xfr->mctx, &xfr->qbuffer));
1201*4afad4b7Schristos
1202*4afad4b7Schristos /*
1203*4afad4b7Schristos * Free the last tsig, if there is one.
1204*4afad4b7Schristos */
1205*4afad4b7Schristos if (xfr->lasttsig != NULL) {
1206*4afad4b7Schristos isc_buffer_free(&xfr->lasttsig);
1207*4afad4b7Schristos }
1208*4afad4b7Schristos
1209*4afad4b7Schristos /*
1210*4afad4b7Schristos * Save the query TSIG and don't let message_destroy free it.
1211*4afad4b7Schristos */
1212*4afad4b7Schristos CHECK(dns_message_getquerytsig(msg, xfr->mctx, &xfr->lasttsig));
1213*4afad4b7Schristos
1214*4afad4b7Schristos isc_buffer_usedregion(&xfr->qbuffer, ®ion);
1215*4afad4b7Schristos INSIST(region.length <= 65535);
1216*4afad4b7Schristos
1217*4afad4b7Schristos /*
1218*4afad4b7Schristos * Record message length and adjust region to include TCP
1219*4afad4b7Schristos * length field.
1220*4afad4b7Schristos */
1221*4afad4b7Schristos xfr->qbuffer_data[0] = (region.length >> 8) & 0xff;
1222*4afad4b7Schristos xfr->qbuffer_data[1] = region.length & 0xff;
1223*4afad4b7Schristos region.base -= 2;
1224*4afad4b7Schristos region.length += 2;
1225*4afad4b7Schristos CHECK(isc_socket_send(xfr->socket, ®ion, xfr->task, xfrin_send_done,
1226*4afad4b7Schristos xfr));
1227*4afad4b7Schristos xfr->sends++;
1228*4afad4b7Schristos
1229*4afad4b7Schristos failure:
1230*4afad4b7Schristos if (qname != NULL) {
1231*4afad4b7Schristos dns_message_puttempname(msg, &qname);
1232*4afad4b7Schristos }
1233*4afad4b7Schristos if (qrdataset != NULL) {
1234*4afad4b7Schristos dns_message_puttemprdataset(msg, &qrdataset);
1235*4afad4b7Schristos }
1236*4afad4b7Schristos if (msg != NULL) {
1237*4afad4b7Schristos dns_message_detach(&msg);
1238*4afad4b7Schristos }
1239*4afad4b7Schristos if (soatuple != NULL) {
1240*4afad4b7Schristos dns_difftuple_free(&soatuple);
1241*4afad4b7Schristos }
1242*4afad4b7Schristos if (ver != NULL) {
1243*4afad4b7Schristos dns_db_closeversion(xfr->db, &ver, false);
1244*4afad4b7Schristos }
1245*4afad4b7Schristos return (result);
1246*4afad4b7Schristos }
1247*4afad4b7Schristos
1248*4afad4b7Schristos static void
xfrin_send_done(isc_task_t * task,isc_event_t * event)1249*4afad4b7Schristos xfrin_send_done(isc_task_t *task, isc_event_t *event) {
1250*4afad4b7Schristos isc_socketevent_t *sev = (isc_socketevent_t *)event;
1251*4afad4b7Schristos dns_xfrin_ctx_t *xfr = (dns_xfrin_ctx_t *)event->ev_arg;
1252*4afad4b7Schristos isc_result_t result;
1253*4afad4b7Schristos
1254*4afad4b7Schristos REQUIRE(VALID_XFRIN(xfr));
1255*4afad4b7Schristos
1256*4afad4b7Schristos UNUSED(task);
1257*4afad4b7Schristos
1258*4afad4b7Schristos INSIST(event->ev_type == ISC_SOCKEVENT_SENDDONE);
1259*4afad4b7Schristos
1260*4afad4b7Schristos xfr->sends--;
1261*4afad4b7Schristos xfrin_log(xfr, ISC_LOG_DEBUG(3), "sent request data");
1262*4afad4b7Schristos CHECK(sev->result);
1263*4afad4b7Schristos
1264*4afad4b7Schristos CHECK(dns_tcpmsg_readmessage(&xfr->tcpmsg, xfr->task, xfrin_recv_done,
1265*4afad4b7Schristos xfr));
1266*4afad4b7Schristos xfr->recvs++;
1267*4afad4b7Schristos failure:
1268*4afad4b7Schristos isc_event_free(&event);
1269*4afad4b7Schristos if (result != ISC_R_SUCCESS) {
1270*4afad4b7Schristos xfrin_fail(xfr, result, "failed sending request data");
1271*4afad4b7Schristos }
1272*4afad4b7Schristos }
1273*4afad4b7Schristos
1274*4afad4b7Schristos static void
xfrin_recv_done(isc_task_t * task,isc_event_t * ev)1275*4afad4b7Schristos xfrin_recv_done(isc_task_t *task, isc_event_t *ev) {
1276*4afad4b7Schristos dns_xfrin_ctx_t *xfr = (dns_xfrin_ctx_t *)ev->ev_arg;
1277*4afad4b7Schristos isc_result_t result;
1278*4afad4b7Schristos dns_message_t *msg = NULL;
1279*4afad4b7Schristos dns_name_t *name;
1280*4afad4b7Schristos dns_tcpmsg_t *tcpmsg;
1281*4afad4b7Schristos const dns_name_t *tsigowner = NULL;
1282*4afad4b7Schristos
1283*4afad4b7Schristos REQUIRE(VALID_XFRIN(xfr));
1284*4afad4b7Schristos
1285*4afad4b7Schristos UNUSED(task);
1286*4afad4b7Schristos
1287*4afad4b7Schristos INSIST(ev->ev_type == DNS_EVENT_TCPMSG);
1288*4afad4b7Schristos tcpmsg = ev->ev_sender;
1289*4afad4b7Schristos isc_event_free(&ev);
1290*4afad4b7Schristos
1291*4afad4b7Schristos xfr->recvs--;
1292*4afad4b7Schristos if (xfr->shuttingdown) {
1293*4afad4b7Schristos maybe_free(xfr);
1294*4afad4b7Schristos return;
1295*4afad4b7Schristos }
1296*4afad4b7Schristos
1297*4afad4b7Schristos CHECK(tcpmsg->result);
1298*4afad4b7Schristos
1299*4afad4b7Schristos xfrin_log(xfr, ISC_LOG_DEBUG(7), "received %u bytes",
1300*4afad4b7Schristos tcpmsg->buffer.used);
1301*4afad4b7Schristos
1302*4afad4b7Schristos CHECK(isc_timer_touch(xfr->timer));
1303*4afad4b7Schristos
1304*4afad4b7Schristos dns_message_create(xfr->mctx, DNS_MESSAGE_INTENTPARSE, &msg);
1305*4afad4b7Schristos
1306*4afad4b7Schristos CHECK(dns_message_settsigkey(msg, xfr->tsigkey));
1307*4afad4b7Schristos CHECK(dns_message_setquerytsig(msg, xfr->lasttsig));
1308*4afad4b7Schristos
1309*4afad4b7Schristos msg->tsigctx = xfr->tsigctx;
1310*4afad4b7Schristos xfr->tsigctx = NULL;
1311*4afad4b7Schristos
1312*4afad4b7Schristos dns_message_setclass(msg, xfr->rdclass);
1313*4afad4b7Schristos
1314*4afad4b7Schristos if (xfr->nmsg > 0) {
1315*4afad4b7Schristos msg->tcp_continuation = 1;
1316*4afad4b7Schristos }
1317*4afad4b7Schristos
1318*4afad4b7Schristos result = dns_message_parse(msg, &tcpmsg->buffer,
1319*4afad4b7Schristos DNS_MESSAGEPARSE_PRESERVEORDER);
1320*4afad4b7Schristos
1321*4afad4b7Schristos if (result == ISC_R_SUCCESS) {
1322*4afad4b7Schristos dns_message_logpacket(msg, "received message from",
1323*4afad4b7Schristos &tcpmsg->address, DNS_LOGCATEGORY_XFER_IN,
1324*4afad4b7Schristos DNS_LOGMODULE_XFER_IN, ISC_LOG_DEBUG(10),
1325*4afad4b7Schristos xfr->mctx);
1326*4afad4b7Schristos } else {
1327*4afad4b7Schristos xfrin_log(xfr, ISC_LOG_DEBUG(10), "dns_message_parse: %s",
1328*4afad4b7Schristos dns_result_totext(result));
1329*4afad4b7Schristos }
1330*4afad4b7Schristos
1331*4afad4b7Schristos if (result != ISC_R_SUCCESS || msg->rcode != dns_rcode_noerror ||
1332*4afad4b7Schristos msg->opcode != dns_opcode_query || msg->rdclass != xfr->rdclass ||
1333*4afad4b7Schristos (xfr->checkid && msg->id != xfr->id))
1334*4afad4b7Schristos {
1335*4afad4b7Schristos if (result == ISC_R_SUCCESS && msg->rcode != dns_rcode_noerror)
1336*4afad4b7Schristos {
1337*4afad4b7Schristos result = ISC_RESULTCLASS_DNSRCODE + msg->rcode; /*XXX*/
1338*4afad4b7Schristos } else if (result == ISC_R_SUCCESS &&
1339*4afad4b7Schristos msg->opcode != dns_opcode_query)
1340*4afad4b7Schristos {
1341*4afad4b7Schristos result = DNS_R_UNEXPECTEDOPCODE;
1342*4afad4b7Schristos } else if (result == ISC_R_SUCCESS &&
1343*4afad4b7Schristos msg->rdclass != xfr->rdclass)
1344*4afad4b7Schristos {
1345*4afad4b7Schristos result = DNS_R_BADCLASS;
1346*4afad4b7Schristos } else if (result == ISC_R_SUCCESS || result == DNS_R_NOERROR) {
1347*4afad4b7Schristos result = DNS_R_UNEXPECTEDID;
1348*4afad4b7Schristos }
1349*4afad4b7Schristos if (xfr->reqtype == dns_rdatatype_axfr ||
1350*4afad4b7Schristos xfr->reqtype == dns_rdatatype_soa)
1351*4afad4b7Schristos {
1352*4afad4b7Schristos goto failure;
1353*4afad4b7Schristos }
1354*4afad4b7Schristos xfrin_log(xfr, ISC_LOG_DEBUG(3), "got %s, retrying with AXFR",
1355*4afad4b7Schristos isc_result_totext(result));
1356*4afad4b7Schristos try_axfr:
1357*4afad4b7Schristos dns_message_detach(&msg);
1358*4afad4b7Schristos xfrin_reset(xfr);
1359*4afad4b7Schristos xfr->reqtype = dns_rdatatype_soa;
1360*4afad4b7Schristos xfr->state = XFRST_SOAQUERY;
1361*4afad4b7Schristos (void)xfrin_start(xfr);
1362*4afad4b7Schristos return;
1363*4afad4b7Schristos } else if (!xfr->checkid && msg->id != xfr->id && xfr->logit) {
1364*4afad4b7Schristos xfrin_log(xfr, ISC_LOG_WARNING,
1365*4afad4b7Schristos "detected message ID mismatch on incoming AXFR "
1366*4afad4b7Schristos "stream, transfer will fail in BIND 9.17.2 and "
1367*4afad4b7Schristos "later if AXFR source is not fixed");
1368*4afad4b7Schristos xfr->logit = false;
1369*4afad4b7Schristos }
1370*4afad4b7Schristos
1371*4afad4b7Schristos /*
1372*4afad4b7Schristos * Does the server know about IXFR? If it doesn't we will get
1373*4afad4b7Schristos * a message with a empty answer section or a potentially a CNAME /
1374*4afad4b7Schristos * DNAME, the later is handled by xfr_rr() which will return FORMERR
1375*4afad4b7Schristos * if the first RR in the answer section is not a SOA record.
1376*4afad4b7Schristos */
1377*4afad4b7Schristos if (xfr->reqtype == dns_rdatatype_ixfr &&
1378*4afad4b7Schristos xfr->state == XFRST_INITIALSOA &&
1379*4afad4b7Schristos msg->counts[DNS_SECTION_ANSWER] == 0)
1380*4afad4b7Schristos {
1381*4afad4b7Schristos xfrin_log(xfr, ISC_LOG_DEBUG(3),
1382*4afad4b7Schristos "empty answer section, retrying with AXFR");
1383*4afad4b7Schristos goto try_axfr;
1384*4afad4b7Schristos }
1385*4afad4b7Schristos
1386*4afad4b7Schristos if (xfr->reqtype == dns_rdatatype_soa &&
1387*4afad4b7Schristos (msg->flags & DNS_MESSAGEFLAG_AA) == 0)
1388*4afad4b7Schristos {
1389*4afad4b7Schristos FAIL(DNS_R_NOTAUTHORITATIVE);
1390*4afad4b7Schristos }
1391*4afad4b7Schristos
1392*4afad4b7Schristos result = dns_message_checksig(msg, dns_zone_getview(xfr->zone));
1393*4afad4b7Schristos if (result != ISC_R_SUCCESS) {
1394*4afad4b7Schristos xfrin_log(xfr, ISC_LOG_DEBUG(3), "TSIG check failed: %s",
1395*4afad4b7Schristos isc_result_totext(result));
1396*4afad4b7Schristos goto failure;
1397*4afad4b7Schristos }
1398*4afad4b7Schristos
1399*4afad4b7Schristos for (result = dns_message_firstname(msg, DNS_SECTION_ANSWER);
1400*4afad4b7Schristos result == ISC_R_SUCCESS;
1401*4afad4b7Schristos result = dns_message_nextname(msg, DNS_SECTION_ANSWER))
1402*4afad4b7Schristos {
1403*4afad4b7Schristos dns_rdataset_t *rds;
1404*4afad4b7Schristos
1405*4afad4b7Schristos name = NULL;
1406*4afad4b7Schristos dns_message_currentname(msg, DNS_SECTION_ANSWER, &name);
1407*4afad4b7Schristos for (rds = ISC_LIST_HEAD(name->list); rds != NULL;
1408*4afad4b7Schristos rds = ISC_LIST_NEXT(rds, link))
1409*4afad4b7Schristos {
1410*4afad4b7Schristos for (result = dns_rdataset_first(rds);
1411*4afad4b7Schristos result == ISC_R_SUCCESS;
1412*4afad4b7Schristos result = dns_rdataset_next(rds))
1413*4afad4b7Schristos {
1414*4afad4b7Schristos dns_rdata_t rdata = DNS_RDATA_INIT;
1415*4afad4b7Schristos dns_rdataset_current(rds, &rdata);
1416*4afad4b7Schristos CHECK(xfr_rr(xfr, name, rds->ttl, &rdata));
1417*4afad4b7Schristos }
1418*4afad4b7Schristos }
1419*4afad4b7Schristos }
1420*4afad4b7Schristos if (result != ISC_R_NOMORE) {
1421*4afad4b7Schristos goto failure;
1422*4afad4b7Schristos }
1423*4afad4b7Schristos
1424*4afad4b7Schristos if (dns_message_gettsig(msg, &tsigowner) != NULL) {
1425*4afad4b7Schristos /*
1426*4afad4b7Schristos * Reset the counter.
1427*4afad4b7Schristos */
1428*4afad4b7Schristos xfr->sincetsig = 0;
1429*4afad4b7Schristos
1430*4afad4b7Schristos /*
1431*4afad4b7Schristos * Free the last tsig, if there is one.
1432*4afad4b7Schristos */
1433*4afad4b7Schristos if (xfr->lasttsig != NULL) {
1434*4afad4b7Schristos isc_buffer_free(&xfr->lasttsig);
1435*4afad4b7Schristos }
1436*4afad4b7Schristos
1437*4afad4b7Schristos /*
1438*4afad4b7Schristos * Update the last tsig pointer.
1439*4afad4b7Schristos */
1440*4afad4b7Schristos CHECK(dns_message_getquerytsig(msg, xfr->mctx, &xfr->lasttsig));
1441*4afad4b7Schristos } else if (dns_message_gettsigkey(msg) != NULL) {
1442*4afad4b7Schristos xfr->sincetsig++;
1443*4afad4b7Schristos if (xfr->sincetsig > 100 || xfr->nmsg == 0 ||
1444*4afad4b7Schristos xfr->state == XFRST_AXFR_END ||
1445*4afad4b7Schristos xfr->state == XFRST_IXFR_END)
1446*4afad4b7Schristos {
1447*4afad4b7Schristos result = DNS_R_EXPECTEDTSIG;
1448*4afad4b7Schristos goto failure;
1449*4afad4b7Schristos }
1450*4afad4b7Schristos }
1451*4afad4b7Schristos
1452*4afad4b7Schristos /*
1453*4afad4b7Schristos * Update the number of messages received.
1454*4afad4b7Schristos */
1455*4afad4b7Schristos xfr->nmsg++;
1456*4afad4b7Schristos
1457*4afad4b7Schristos /*
1458*4afad4b7Schristos * Update the number of bytes received.
1459*4afad4b7Schristos */
1460*4afad4b7Schristos xfr->nbytes += tcpmsg->buffer.used;
1461*4afad4b7Schristos
1462*4afad4b7Schristos /*
1463*4afad4b7Schristos * Take the context back.
1464*4afad4b7Schristos */
1465*4afad4b7Schristos INSIST(xfr->tsigctx == NULL);
1466*4afad4b7Schristos xfr->tsigctx = msg->tsigctx;
1467*4afad4b7Schristos msg->tsigctx = NULL;
1468*4afad4b7Schristos
1469*4afad4b7Schristos dns_message_detach(&msg);
1470*4afad4b7Schristos
1471*4afad4b7Schristos switch (xfr->state) {
1472*4afad4b7Schristos case XFRST_GOTSOA:
1473*4afad4b7Schristos xfr->reqtype = dns_rdatatype_axfr;
1474*4afad4b7Schristos xfr->state = XFRST_INITIALSOA;
1475*4afad4b7Schristos CHECK(xfrin_send_request(xfr));
1476*4afad4b7Schristos break;
1477*4afad4b7Schristos case XFRST_AXFR_END:
1478*4afad4b7Schristos CHECK(axfr_finalize(xfr));
1479*4afad4b7Schristos FALLTHROUGH;
1480*4afad4b7Schristos case XFRST_IXFR_END:
1481*4afad4b7Schristos /*
1482*4afad4b7Schristos * Close the journal.
1483*4afad4b7Schristos */
1484*4afad4b7Schristos if (xfr->ixfr.journal != NULL) {
1485*4afad4b7Schristos dns_journal_destroy(&xfr->ixfr.journal);
1486*4afad4b7Schristos }
1487*4afad4b7Schristos
1488*4afad4b7Schristos /*
1489*4afad4b7Schristos * Inform the caller we succeeded.
1490*4afad4b7Schristos */
1491*4afad4b7Schristos if (xfr->done != NULL) {
1492*4afad4b7Schristos (xfr->done)(xfr->zone, ISC_R_SUCCESS);
1493*4afad4b7Schristos xfr->done = NULL;
1494*4afad4b7Schristos }
1495*4afad4b7Schristos /*
1496*4afad4b7Schristos * We should have no outstanding events at this
1497*4afad4b7Schristos * point, thus maybe_free() should succeed.
1498*4afad4b7Schristos */
1499*4afad4b7Schristos xfr->shuttingdown = true;
1500*4afad4b7Schristos xfr->shutdown_result = ISC_R_SUCCESS;
1501*4afad4b7Schristos maybe_free(xfr);
1502*4afad4b7Schristos break;
1503*4afad4b7Schristos default:
1504*4afad4b7Schristos /*
1505*4afad4b7Schristos * Read the next message.
1506*4afad4b7Schristos */
1507*4afad4b7Schristos CHECK(dns_tcpmsg_readmessage(&xfr->tcpmsg, xfr->task,
1508*4afad4b7Schristos xfrin_recv_done, xfr));
1509*4afad4b7Schristos xfr->recvs++;
1510*4afad4b7Schristos }
1511*4afad4b7Schristos return;
1512*4afad4b7Schristos
1513*4afad4b7Schristos failure:
1514*4afad4b7Schristos if (msg != NULL) {
1515*4afad4b7Schristos dns_message_detach(&msg);
1516*4afad4b7Schristos }
1517*4afad4b7Schristos if (result != ISC_R_SUCCESS) {
1518*4afad4b7Schristos xfrin_fail(xfr, result, "failed while receiving responses");
1519*4afad4b7Schristos }
1520*4afad4b7Schristos }
1521*4afad4b7Schristos
1522*4afad4b7Schristos static void
xfrin_timeout(isc_task_t * task,isc_event_t * event)1523*4afad4b7Schristos xfrin_timeout(isc_task_t *task, isc_event_t *event) {
1524*4afad4b7Schristos dns_xfrin_ctx_t *xfr = (dns_xfrin_ctx_t *)event->ev_arg;
1525*4afad4b7Schristos
1526*4afad4b7Schristos REQUIRE(VALID_XFRIN(xfr));
1527*4afad4b7Schristos
1528*4afad4b7Schristos UNUSED(task);
1529*4afad4b7Schristos
1530*4afad4b7Schristos isc_event_free(&event);
1531*4afad4b7Schristos /*
1532*4afad4b7Schristos * This will log "giving up: timeout".
1533*4afad4b7Schristos */
1534*4afad4b7Schristos xfrin_fail(xfr, ISC_R_TIMEDOUT, "giving up");
1535*4afad4b7Schristos }
1536*4afad4b7Schristos
1537*4afad4b7Schristos static void
maybe_free(dns_xfrin_ctx_t * xfr)1538*4afad4b7Schristos maybe_free(dns_xfrin_ctx_t *xfr) {
1539*4afad4b7Schristos uint64_t msecs;
1540*4afad4b7Schristos uint64_t persec;
1541*4afad4b7Schristos const char *result_str;
1542*4afad4b7Schristos
1543*4afad4b7Schristos REQUIRE(VALID_XFRIN(xfr));
1544*4afad4b7Schristos
1545*4afad4b7Schristos if (!xfr->shuttingdown || xfr->refcount != 0 || xfr->connects != 0 ||
1546*4afad4b7Schristos xfr->sends != 0 || xfr->recvs != 0)
1547*4afad4b7Schristos {
1548*4afad4b7Schristos return;
1549*4afad4b7Schristos }
1550*4afad4b7Schristos
1551*4afad4b7Schristos INSIST(!xfr->shuttingdown || xfr->shutdown_result != ISC_R_UNSET);
1552*4afad4b7Schristos
1553*4afad4b7Schristos /* If we're called through dns_xfrin_detach() and are not
1554*4afad4b7Schristos * shutting down, we can't know what the transfer status is as
1555*4afad4b7Schristos * we are only called when the last reference is lost.
1556*4afad4b7Schristos */
1557*4afad4b7Schristos result_str = (xfr->shuttingdown
1558*4afad4b7Schristos ? isc_result_totext(xfr->shutdown_result)
1559*4afad4b7Schristos : "unknown");
1560*4afad4b7Schristos xfrin_log(xfr, ISC_LOG_INFO, "Transfer status: %s", result_str);
1561*4afad4b7Schristos
1562*4afad4b7Schristos /*
1563*4afad4b7Schristos * Calculate the length of time the transfer took,
1564*4afad4b7Schristos * and print a log message with the bytes and rate.
1565*4afad4b7Schristos */
1566*4afad4b7Schristos isc_time_now(&xfr->end);
1567*4afad4b7Schristos msecs = isc_time_microdiff(&xfr->end, &xfr->start) / 1000;
1568*4afad4b7Schristos if (msecs == 0) {
1569*4afad4b7Schristos msecs = 1;
1570*4afad4b7Schristos }
1571*4afad4b7Schristos persec = (xfr->nbytes * 1000) / msecs;
1572*4afad4b7Schristos xfrin_log(xfr, ISC_LOG_INFO,
1573*4afad4b7Schristos "Transfer completed: %d messages, %d records, "
1574*4afad4b7Schristos "%" PRIu64 " bytes, "
1575*4afad4b7Schristos "%u.%03u secs (%u bytes/sec) (serial %u)",
1576*4afad4b7Schristos xfr->nmsg, xfr->nrecs, xfr->nbytes,
1577*4afad4b7Schristos (unsigned int)(msecs / 1000), (unsigned int)(msecs % 1000),
1578*4afad4b7Schristos (unsigned int)persec, xfr->end_serial);
1579*4afad4b7Schristos
1580*4afad4b7Schristos if (xfr->socket != NULL) {
1581*4afad4b7Schristos isc_socket_detach(&xfr->socket);
1582*4afad4b7Schristos }
1583*4afad4b7Schristos
1584*4afad4b7Schristos if (xfr->timer != NULL) {
1585*4afad4b7Schristos isc_timer_destroy(&xfr->timer);
1586*4afad4b7Schristos }
1587*4afad4b7Schristos
1588*4afad4b7Schristos if (xfr->task != NULL) {
1589*4afad4b7Schristos isc_task_detach(&xfr->task);
1590*4afad4b7Schristos }
1591*4afad4b7Schristos
1592*4afad4b7Schristos if (xfr->tsigkey != NULL) {
1593*4afad4b7Schristos dns_tsigkey_detach(&xfr->tsigkey);
1594*4afad4b7Schristos }
1595*4afad4b7Schristos
1596*4afad4b7Schristos if (xfr->lasttsig != NULL) {
1597*4afad4b7Schristos isc_buffer_free(&xfr->lasttsig);
1598*4afad4b7Schristos }
1599*4afad4b7Schristos
1600*4afad4b7Schristos dns_diff_clear(&xfr->diff);
1601*4afad4b7Schristos
1602*4afad4b7Schristos if (xfr->ixfr.journal != NULL) {
1603*4afad4b7Schristos dns_journal_destroy(&xfr->ixfr.journal);
1604*4afad4b7Schristos }
1605*4afad4b7Schristos
1606*4afad4b7Schristos if (xfr->axfr.add_private != NULL) {
1607*4afad4b7Schristos (void)dns_db_endload(xfr->db, &xfr->axfr);
1608*4afad4b7Schristos }
1609*4afad4b7Schristos
1610*4afad4b7Schristos if (xfr->tcpmsg_valid) {
1611*4afad4b7Schristos dns_tcpmsg_invalidate(&xfr->tcpmsg);
1612*4afad4b7Schristos }
1613*4afad4b7Schristos
1614*4afad4b7Schristos if (xfr->tsigctx != NULL) {
1615*4afad4b7Schristos dst_context_destroy(&xfr->tsigctx);
1616*4afad4b7Schristos }
1617*4afad4b7Schristos
1618*4afad4b7Schristos if ((xfr->name.attributes & DNS_NAMEATTR_DYNAMIC) != 0) {
1619*4afad4b7Schristos dns_name_free(&xfr->name, xfr->mctx);
1620*4afad4b7Schristos }
1621*4afad4b7Schristos
1622*4afad4b7Schristos if (xfr->ver != NULL) {
1623*4afad4b7Schristos dns_db_closeversion(xfr->db, &xfr->ver, false);
1624*4afad4b7Schristos }
1625*4afad4b7Schristos
1626*4afad4b7Schristos if (xfr->db != NULL) {
1627*4afad4b7Schristos dns_db_detach(&xfr->db);
1628*4afad4b7Schristos }
1629*4afad4b7Schristos
1630*4afad4b7Schristos if (xfr->zone != NULL) {
1631*4afad4b7Schristos if (!xfr->zone_had_db && xfr->shuttingdown &&
1632*4afad4b7Schristos xfr->shutdown_result == ISC_R_SUCCESS &&
1633*4afad4b7Schristos dns_zone_gettype(xfr->zone) == dns_zone_mirror)
1634*4afad4b7Schristos {
1635*4afad4b7Schristos dns_zone_log(xfr->zone, ISC_LOG_INFO,
1636*4afad4b7Schristos "mirror zone is now in use");
1637*4afad4b7Schristos }
1638*4afad4b7Schristos xfrin_log(xfr, ISC_LOG_DEBUG(99), "freeing transfer context");
1639*4afad4b7Schristos /*
1640*4afad4b7Schristos * xfr->zone must not be detached before xfrin_log() is called.
1641*4afad4b7Schristos */
1642*4afad4b7Schristos dns_zone_idetach(&xfr->zone);
1643*4afad4b7Schristos }
1644*4afad4b7Schristos
1645*4afad4b7Schristos if (xfr->firstsoa_data != NULL) {
1646*4afad4b7Schristos isc_mem_free(xfr->mctx, xfr->firstsoa_data);
1647*4afad4b7Schristos }
1648*4afad4b7Schristos
1649*4afad4b7Schristos isc_mem_putanddetach(&xfr->mctx, xfr, sizeof(*xfr));
1650*4afad4b7Schristos }
1651*4afad4b7Schristos
1652*4afad4b7Schristos /*
1653*4afad4b7Schristos * Log incoming zone transfer messages in a format like
1654*4afad4b7Schristos * transfer of <zone> from <address>: <message>
1655*4afad4b7Schristos */
1656*4afad4b7Schristos static void
xfrin_logv(int level,const char * zonetext,const isc_sockaddr_t * masteraddr,const char * fmt,va_list ap)1657*4afad4b7Schristos xfrin_logv(int level, const char *zonetext, const isc_sockaddr_t *masteraddr,
1658*4afad4b7Schristos const char *fmt, va_list ap) {
1659*4afad4b7Schristos char mastertext[ISC_SOCKADDR_FORMATSIZE];
1660*4afad4b7Schristos char msgtext[2048];
1661*4afad4b7Schristos
1662*4afad4b7Schristos isc_sockaddr_format(masteraddr, mastertext, sizeof(mastertext));
1663*4afad4b7Schristos vsnprintf(msgtext, sizeof(msgtext), fmt, ap);
1664*4afad4b7Schristos
1665*4afad4b7Schristos isc_log_write(dns_lctx, DNS_LOGCATEGORY_XFER_IN, DNS_LOGMODULE_XFER_IN,
1666*4afad4b7Schristos level, "transfer of '%s' from %s: %s", zonetext,
1667*4afad4b7Schristos mastertext, msgtext);
1668*4afad4b7Schristos }
1669*4afad4b7Schristos
1670*4afad4b7Schristos /*
1671*4afad4b7Schristos * Logging function for use when a xfrin_ctx_t has not yet been created.
1672*4afad4b7Schristos */
1673*4afad4b7Schristos
1674*4afad4b7Schristos static void
xfrin_log1(int level,const char * zonetext,const isc_sockaddr_t * masteraddr,const char * fmt,...)1675*4afad4b7Schristos xfrin_log1(int level, const char *zonetext, const isc_sockaddr_t *masteraddr,
1676*4afad4b7Schristos const char *fmt, ...) {
1677*4afad4b7Schristos va_list ap;
1678*4afad4b7Schristos
1679*4afad4b7Schristos if (!isc_log_wouldlog(dns_lctx, level)) {
1680*4afad4b7Schristos return;
1681*4afad4b7Schristos }
1682*4afad4b7Schristos
1683*4afad4b7Schristos va_start(ap, fmt);
1684*4afad4b7Schristos xfrin_logv(level, zonetext, masteraddr, fmt, ap);
1685*4afad4b7Schristos va_end(ap);
1686*4afad4b7Schristos }
1687*4afad4b7Schristos
1688*4afad4b7Schristos /*
1689*4afad4b7Schristos * Logging function for use when there is a xfrin_ctx_t.
1690*4afad4b7Schristos */
1691*4afad4b7Schristos
1692*4afad4b7Schristos static void
xfrin_log(dns_xfrin_ctx_t * xfr,int level,const char * fmt,...)1693*4afad4b7Schristos xfrin_log(dns_xfrin_ctx_t *xfr, int level, const char *fmt, ...) {
1694*4afad4b7Schristos va_list ap;
1695*4afad4b7Schristos char zonetext[DNS_NAME_MAXTEXT + 32];
1696*4afad4b7Schristos
1697*4afad4b7Schristos if (!isc_log_wouldlog(dns_lctx, level)) {
1698*4afad4b7Schristos return;
1699*4afad4b7Schristos }
1700*4afad4b7Schristos
1701*4afad4b7Schristos dns_zone_name(xfr->zone, zonetext, sizeof(zonetext));
1702*4afad4b7Schristos
1703*4afad4b7Schristos va_start(ap, fmt);
1704*4afad4b7Schristos xfrin_logv(level, zonetext, &xfr->masteraddr, fmt, ap);
1705*4afad4b7Schristos va_end(ap);
1706*4afad4b7Schristos }
1707