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