Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / external / bsd / bind / dist / lib / dns / xfrin.c
blobd53d74b5c4242e42122f9a78fda885e3ef5616b8
1 /* $NetBSD$ */
3 /*
4 * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 1999-2003 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
20 /* Id: xfrin.c,v 1.166 2008/09/25 04:12:39 marka Exp */
22 /*! \file */
24 #include <config.h>
26 #include <isc/mem.h>
27 #include <isc/print.h>
28 #include <isc/random.h>
29 #include <isc/string.h> /* Required for HP/UX (and others?) */
30 #include <isc/task.h>
31 #include <isc/timer.h>
32 #include <isc/util.h>
34 #include <dns/db.h>
35 #include <dns/diff.h>
36 #include <dns/events.h>
37 #include <dns/journal.h>
38 #include <dns/log.h>
39 #include <dns/message.h>
40 #include <dns/rdataclass.h>
41 #include <dns/rdatalist.h>
42 #include <dns/rdataset.h>
43 #include <dns/result.h>
44 #include <dns/soa.h>
45 #include <dns/tcpmsg.h>
46 #include <dns/timer.h>
47 #include <dns/tsig.h>
48 #include <dns/view.h>
49 #include <dns/xfrin.h>
50 #include <dns/zone.h>
52 #include <dst/dst.h>
55 * Incoming AXFR and IXFR.
58 /*%
59 * It would be non-sensical (or at least obtuse) to use FAIL() with an
60 * ISC_R_SUCCESS code, but the test is there to keep the Solaris compiler
61 * from complaining about "end-of-loop code not reached".
63 #define FAIL(code) \
64 do { result = (code); \
65 if (result != ISC_R_SUCCESS) goto failure; \
66 } while (0)
68 #define CHECK(op) \
69 do { result = (op); \
70 if (result != ISC_R_SUCCESS) goto failure; \
71 } while (0)
73 /*%
74 * The states of the *XFR state machine. We handle both IXFR and AXFR
75 * with a single integrated state machine because they cannot be distinguished
76 * immediately - an AXFR response to an IXFR request can only be detected
77 * when the first two (2) response RRs have already been received.
79 typedef enum {
80 XFRST_SOAQUERY,
81 XFRST_GOTSOA,
82 XFRST_INITIALSOA,
83 XFRST_FIRSTDATA,
84 XFRST_IXFR_DELSOA,
85 XFRST_IXFR_DEL,
86 XFRST_IXFR_ADDSOA,
87 XFRST_IXFR_ADD,
88 XFRST_AXFR,
89 XFRST_END
90 } xfrin_state_t;
92 /*%
93 * Incoming zone transfer context.
96 struct dns_xfrin_ctx {
97 unsigned int magic;
98 isc_mem_t *mctx;
99 dns_zone_t *zone;
101 int refcount;
103 isc_task_t *task;
104 isc_timer_t *timer;
105 isc_socketmgr_t *socketmgr;
107 int connects; /*%< Connect in progress */
108 int sends; /*%< Send in progress */
109 int recvs; /*%< Receive in progress */
110 isc_boolean_t shuttingdown;
112 dns_name_t name; /*%< Name of zone to transfer */
113 dns_rdataclass_t rdclass;
115 isc_boolean_t checkid;
116 dns_messageid_t id;
119 * Requested transfer type (dns_rdatatype_axfr or
120 * dns_rdatatype_ixfr). The actual transfer type
121 * may differ due to IXFR->AXFR fallback.
123 dns_rdatatype_t reqtype;
125 isc_sockaddr_t masteraddr;
126 isc_sockaddr_t sourceaddr;
127 isc_socket_t *socket;
129 /*% Buffer for IXFR/AXFR request message */
130 isc_buffer_t qbuffer;
131 unsigned char qbuffer_data[512];
133 /*% Incoming reply TCP message */
134 dns_tcpmsg_t tcpmsg;
135 isc_boolean_t tcpmsg_valid;
137 dns_db_t *db;
138 dns_dbversion_t *ver;
139 dns_diff_t diff; /*%< Pending database changes */
140 int difflen; /*%< Number of pending tuples */
142 xfrin_state_t state;
143 isc_uint32_t end_serial;
144 isc_boolean_t is_ixfr;
146 unsigned int nmsg; /*%< Number of messages recvd */
147 unsigned int nrecs; /*%< Number of records recvd */
148 isc_uint64_t nbytes; /*%< Number of bytes received */
150 isc_time_t start; /*%< Start time of the transfer */
151 isc_time_t end; /*%< End time of the transfer */
153 dns_tsigkey_t *tsigkey; /*%< Key used to create TSIG */
154 isc_buffer_t *lasttsig; /*%< The last TSIG */
155 dst_context_t *tsigctx; /*%< TSIG verification context */
156 unsigned int sincetsig; /*%< recvd since the last TSIG */
157 dns_xfrindone_t done;
160 * AXFR- and IXFR-specific data. Only one is used at a time
161 * according to the is_ixfr flag, so this could be a union,
162 * but keeping them separate makes it a bit simpler to clean
163 * things up when destroying the context.
165 struct {
166 dns_addrdatasetfunc_t add_func;
167 dns_dbload_t *add_private;
168 } axfr;
170 struct {
171 isc_uint32_t request_serial;
172 isc_uint32_t current_serial;
173 dns_journal_t *journal;
175 } ixfr;
178 #define XFRIN_MAGIC ISC_MAGIC('X', 'f', 'r', 'I')
179 #define VALID_XFRIN(x) ISC_MAGIC_VALID(x, XFRIN_MAGIC)
181 /**************************************************************************/
183 * Forward declarations.
186 static isc_result_t
187 xfrin_create(isc_mem_t *mctx,
188 dns_zone_t *zone,
189 dns_db_t *db,
190 isc_task_t *task,
191 isc_timermgr_t *timermgr,
192 isc_socketmgr_t *socketmgr,
193 dns_name_t *zonename,
194 dns_rdataclass_t rdclass,
195 dns_rdatatype_t reqtype,
196 isc_sockaddr_t *masteraddr,
197 isc_sockaddr_t *sourceaddr,
198 dns_tsigkey_t *tsigkey,
199 dns_xfrin_ctx_t **xfrp);
201 static isc_result_t axfr_init(dns_xfrin_ctx_t *xfr);
202 static isc_result_t axfr_makedb(dns_xfrin_ctx_t *xfr, dns_db_t **dbp);
203 static isc_result_t axfr_putdata(dns_xfrin_ctx_t *xfr, dns_diffop_t op,
204 dns_name_t *name, dns_ttl_t ttl,
205 dns_rdata_t *rdata);
206 static isc_result_t axfr_apply(dns_xfrin_ctx_t *xfr);
207 static isc_result_t axfr_commit(dns_xfrin_ctx_t *xfr);
209 static isc_result_t ixfr_init(dns_xfrin_ctx_t *xfr);
210 static isc_result_t ixfr_apply(dns_xfrin_ctx_t *xfr);
211 static isc_result_t ixfr_putdata(dns_xfrin_ctx_t *xfr, dns_diffop_t op,
212 dns_name_t *name, dns_ttl_t ttl,
213 dns_rdata_t *rdata);
214 static isc_result_t ixfr_commit(dns_xfrin_ctx_t *xfr);
216 static isc_result_t xfr_rr(dns_xfrin_ctx_t *xfr, dns_name_t *name,
217 isc_uint32_t ttl, dns_rdata_t *rdata);
219 static isc_result_t xfrin_start(dns_xfrin_ctx_t *xfr);
221 static void xfrin_connect_done(isc_task_t *task, isc_event_t *event);
222 static isc_result_t xfrin_send_request(dns_xfrin_ctx_t *xfr);
223 static void xfrin_send_done(isc_task_t *task, isc_event_t *event);
224 static void xfrin_sendlen_done(isc_task_t *task, isc_event_t *event);
225 static void xfrin_recv_done(isc_task_t *task, isc_event_t *event);
226 static void xfrin_timeout(isc_task_t *task, isc_event_t *event);
228 static void maybe_free(dns_xfrin_ctx_t *xfr);
230 static void
231 xfrin_fail(dns_xfrin_ctx_t *xfr, isc_result_t result, const char *msg);
232 static isc_result_t
233 render(dns_message_t *msg, isc_mem_t *mctx, isc_buffer_t *buf);
235 static void
236 xfrin_logv(int level, const char *zonetext, isc_sockaddr_t *masteraddr,
237 const char *fmt, va_list ap)
238 ISC_FORMAT_PRINTF(4, 0);
240 static void
241 xfrin_log1(int level, const char *zonetext, isc_sockaddr_t *masteraddr,
242 const char *fmt, ...)
243 ISC_FORMAT_PRINTF(4, 5);
245 static void
246 xfrin_log(dns_xfrin_ctx_t *xfr, int level, const char *fmt, ...)
247 ISC_FORMAT_PRINTF(3, 4);
249 /**************************************************************************/
251 * AXFR handling
254 static isc_result_t
255 axfr_init(dns_xfrin_ctx_t *xfr) {
256 isc_result_t result;
258 xfr->is_ixfr = ISC_FALSE;
260 if (xfr->db != NULL)
261 dns_db_detach(&xfr->db);
263 CHECK(axfr_makedb(xfr, &xfr->db));
264 CHECK(dns_db_beginload(xfr->db, &xfr->axfr.add_func,
265 &xfr->axfr.add_private));
266 result = ISC_R_SUCCESS;
267 failure:
268 return (result);
271 static isc_result_t
272 axfr_makedb(dns_xfrin_ctx_t *xfr, dns_db_t **dbp) {
273 return (dns_db_create(xfr->mctx, /* XXX */
274 "rbt", /* XXX guess */
275 &xfr->name,
276 dns_dbtype_zone,
277 xfr->rdclass,
278 0, NULL, /* XXX guess */
279 dbp));
282 static isc_result_t
283 axfr_putdata(dns_xfrin_ctx_t *xfr, dns_diffop_t op,
284 dns_name_t *name, dns_ttl_t ttl, dns_rdata_t *rdata)
286 isc_result_t result;
288 dns_difftuple_t *tuple = NULL;
290 CHECK(dns_zone_checknames(xfr->zone, name, rdata));
291 CHECK(dns_difftuple_create(xfr->diff.mctx, op,
292 name, ttl, rdata, &tuple));
293 dns_diff_append(&xfr->diff, &tuple);
294 if (++xfr->difflen > 100)
295 CHECK(axfr_apply(xfr));
296 result = ISC_R_SUCCESS;
297 failure:
298 return (result);
302 * Store a set of AXFR RRs in the database.
304 static isc_result_t
305 axfr_apply(dns_xfrin_ctx_t *xfr) {
306 isc_result_t result;
308 CHECK(dns_diff_load(&xfr->diff,
309 xfr->axfr.add_func, xfr->axfr.add_private));
310 xfr->difflen = 0;
311 dns_diff_clear(&xfr->diff);
312 result = ISC_R_SUCCESS;
313 failure:
314 return (result);
317 static isc_result_t
318 axfr_commit(dns_xfrin_ctx_t *xfr) {
319 isc_result_t result;
321 CHECK(axfr_apply(xfr));
322 CHECK(dns_db_endload(xfr->db, &xfr->axfr.add_private));
323 CHECK(dns_zone_replacedb(xfr->zone, xfr->db, ISC_TRUE));
325 result = ISC_R_SUCCESS;
326 failure:
327 return (result);
330 /**************************************************************************/
332 * IXFR handling
335 static isc_result_t
336 ixfr_init(dns_xfrin_ctx_t *xfr) {
337 isc_result_t result;
338 char *journalfile;
340 if (xfr->reqtype != dns_rdatatype_ixfr) {
341 xfrin_log(xfr, ISC_LOG_ERROR,
342 "got incremental response to AXFR request");
343 return (DNS_R_FORMERR);
346 xfr->is_ixfr = ISC_TRUE;
347 INSIST(xfr->db != NULL);
348 xfr->difflen = 0;
350 journalfile = dns_zone_getjournal(xfr->zone);
351 if (journalfile != NULL)
352 CHECK(dns_journal_open(xfr->mctx, journalfile,
353 ISC_TRUE, &xfr->ixfr.journal));
355 result = ISC_R_SUCCESS;
356 failure:
357 return (result);
360 static isc_result_t
361 ixfr_putdata(dns_xfrin_ctx_t *xfr, dns_diffop_t op,
362 dns_name_t *name, dns_ttl_t ttl, dns_rdata_t *rdata)
364 isc_result_t result;
366 dns_difftuple_t *tuple = NULL;
367 if (op == DNS_DIFFOP_ADD)
368 CHECK(dns_zone_checknames(xfr->zone, name, rdata));
369 CHECK(dns_difftuple_create(xfr->diff.mctx, op,
370 name, ttl, rdata, &tuple));
371 dns_diff_append(&xfr->diff, &tuple);
372 if (++xfr->difflen > 100)
373 CHECK(ixfr_apply(xfr));
374 result = ISC_R_SUCCESS;
375 failure:
376 return (result);
380 * Apply a set of IXFR changes to the database.
382 static isc_result_t
383 ixfr_apply(dns_xfrin_ctx_t *xfr) {
384 isc_result_t result;
386 if (xfr->ver == NULL) {
387 CHECK(dns_db_newversion(xfr->db, &xfr->ver));
388 if (xfr->ixfr.journal != NULL)
389 CHECK(dns_journal_begin_transaction(xfr->ixfr.journal));
391 CHECK(dns_diff_apply(&xfr->diff, xfr->db, xfr->ver));
392 if (xfr->ixfr.journal != NULL) {
393 result = dns_journal_writediff(xfr->ixfr.journal, &xfr->diff);
394 if (result != ISC_R_SUCCESS)
395 goto failure;
397 dns_diff_clear(&xfr->diff);
398 xfr->difflen = 0;
399 result = ISC_R_SUCCESS;
400 failure:
401 return (result);
404 static isc_result_t
405 ixfr_commit(dns_xfrin_ctx_t *xfr) {
406 isc_result_t result;
408 CHECK(ixfr_apply(xfr));
409 if (xfr->ver != NULL) {
410 /* XXX enter ready-to-commit state here */
411 if (xfr->ixfr.journal != NULL)
412 CHECK(dns_journal_commit(xfr->ixfr.journal));
413 dns_db_closeversion(xfr->db, &xfr->ver, ISC_TRUE);
414 dns_zone_markdirty(xfr->zone);
416 result = ISC_R_SUCCESS;
417 failure:
418 return (result);
421 /**************************************************************************/
423 * Common AXFR/IXFR protocol code
427 * Handle a single incoming resource record according to the current
428 * state.
430 static isc_result_t
431 xfr_rr(dns_xfrin_ctx_t *xfr, dns_name_t *name, isc_uint32_t ttl,
432 dns_rdata_t *rdata)
434 isc_result_t result;
436 xfr->nrecs++;
438 if (rdata->type == dns_rdatatype_none ||
439 dns_rdatatype_ismeta(rdata->type))
440 FAIL(DNS_R_FORMERR);
442 redo:
443 switch (xfr->state) {
444 case XFRST_SOAQUERY:
445 if (rdata->type != dns_rdatatype_soa) {
446 xfrin_log(xfr, ISC_LOG_ERROR,
447 "non-SOA response to SOA query");
448 FAIL(DNS_R_FORMERR);
450 xfr->end_serial = dns_soa_getserial(rdata);
451 if (!DNS_SERIAL_GT(xfr->end_serial, xfr->ixfr.request_serial) &&
452 !dns_zone_isforced(xfr->zone)) {
453 xfrin_log(xfr, ISC_LOG_DEBUG(3),
454 "requested serial %u, "
455 "master has %u, not updating",
456 xfr->ixfr.request_serial, xfr->end_serial);
457 FAIL(DNS_R_UPTODATE);
459 xfr->state = XFRST_GOTSOA;
460 break;
462 case XFRST_GOTSOA:
464 * Skip other records in the answer section.
466 break;
468 case XFRST_INITIALSOA:
469 if (rdata->type != dns_rdatatype_soa) {
470 xfrin_log(xfr, ISC_LOG_ERROR,
471 "first RR in zone transfer must be SOA");
472 FAIL(DNS_R_FORMERR);
475 * Remember the serial number in the initial SOA.
476 * We need it to recognize the end of an IXFR.
478 xfr->end_serial = dns_soa_getserial(rdata);
479 if (xfr->reqtype == dns_rdatatype_ixfr &&
480 ! DNS_SERIAL_GT(xfr->end_serial, xfr->ixfr.request_serial)
481 && !dns_zone_isforced(xfr->zone))
484 * This must be the single SOA record that is
485 * sent when the current version on the master
486 * is not newer than the version in the request.
488 xfrin_log(xfr, ISC_LOG_DEBUG(3),
489 "requested serial %u, "
490 "master has %u, not updating",
491 xfr->ixfr.request_serial, xfr->end_serial);
492 FAIL(DNS_R_UPTODATE);
494 if (xfr->reqtype == dns_rdatatype_axfr)
495 xfr->checkid = ISC_FALSE;
496 xfr->state = XFRST_FIRSTDATA;
497 break;
499 case XFRST_FIRSTDATA:
501 * If the transfer begins with one SOA record, it is an AXFR,
502 * if it begins with two SOAs, it is an IXFR.
504 if (xfr->reqtype == dns_rdatatype_ixfr &&
505 rdata->type == dns_rdatatype_soa &&
506 xfr->ixfr.request_serial == dns_soa_getserial(rdata)) {
507 xfrin_log(xfr, ISC_LOG_DEBUG(3),
508 "got incremental response");
509 CHECK(ixfr_init(xfr));
510 xfr->state = XFRST_IXFR_DELSOA;
511 } else {
512 xfrin_log(xfr, ISC_LOG_DEBUG(3),
513 "got nonincremental response");
514 CHECK(axfr_init(xfr));
515 xfr->state = XFRST_AXFR;
517 goto redo;
519 case XFRST_IXFR_DELSOA:
520 INSIST(rdata->type == dns_rdatatype_soa);
521 CHECK(ixfr_putdata(xfr, DNS_DIFFOP_DEL, name, ttl, rdata));
522 xfr->state = XFRST_IXFR_DEL;
523 break;
525 case XFRST_IXFR_DEL:
526 if (rdata->type == dns_rdatatype_soa) {
527 isc_uint32_t soa_serial = dns_soa_getserial(rdata);
528 xfr->state = XFRST_IXFR_ADDSOA;
529 xfr->ixfr.current_serial = soa_serial;
530 goto redo;
532 CHECK(ixfr_putdata(xfr, DNS_DIFFOP_DEL, name, ttl, rdata));
533 break;
535 case XFRST_IXFR_ADDSOA:
536 INSIST(rdata->type == dns_rdatatype_soa);
537 CHECK(ixfr_putdata(xfr, DNS_DIFFOP_ADD, name, ttl, rdata));
538 xfr->state = XFRST_IXFR_ADD;
539 break;
541 case XFRST_IXFR_ADD:
542 if (rdata->type == dns_rdatatype_soa) {
543 isc_uint32_t soa_serial = dns_soa_getserial(rdata);
544 if (soa_serial == xfr->end_serial) {
545 CHECK(ixfr_commit(xfr));
546 xfr->state = XFRST_END;
547 break;
548 } else if (soa_serial != xfr->ixfr.current_serial) {
549 xfrin_log(xfr, ISC_LOG_ERROR,
550 "IXFR out of sync: "
551 "expected serial %u, got %u",
552 xfr->ixfr.current_serial, soa_serial);
553 FAIL(DNS_R_FORMERR);
554 } else {
555 CHECK(ixfr_commit(xfr));
556 xfr->state = XFRST_IXFR_DELSOA;
557 goto redo;
560 if (rdata->type == dns_rdatatype_ns &&
561 dns_name_iswildcard(name))
562 FAIL(DNS_R_INVALIDNS);
563 CHECK(ixfr_putdata(xfr, DNS_DIFFOP_ADD, name, ttl, rdata));
564 break;
566 case XFRST_AXFR:
568 * Old BINDs sent cross class A records for non IN classes.
570 if (rdata->type == dns_rdatatype_a &&
571 rdata->rdclass != xfr->rdclass &&
572 xfr->rdclass != dns_rdataclass_in)
573 break;
574 CHECK(axfr_putdata(xfr, DNS_DIFFOP_ADD, name, ttl, rdata));
575 if (rdata->type == dns_rdatatype_soa) {
576 CHECK(axfr_commit(xfr));
577 xfr->state = XFRST_END;
578 break;
580 break;
581 case XFRST_END:
582 FAIL(DNS_R_EXTRADATA);
583 default:
584 INSIST(0);
585 break;
587 result = ISC_R_SUCCESS;
588 failure:
589 return (result);
592 isc_result_t
593 dns_xfrin_create(dns_zone_t *zone, dns_rdatatype_t xfrtype,
594 isc_sockaddr_t *masteraddr, dns_tsigkey_t *tsigkey,
595 isc_mem_t *mctx, isc_timermgr_t *timermgr,
596 isc_socketmgr_t *socketmgr, isc_task_t *task,
597 dns_xfrindone_t done, dns_xfrin_ctx_t **xfrp)
599 isc_sockaddr_t sourceaddr;
601 switch (isc_sockaddr_pf(masteraddr)) {
602 case PF_INET:
603 sourceaddr = *dns_zone_getxfrsource4(zone);
604 break;
605 case PF_INET6:
606 sourceaddr = *dns_zone_getxfrsource6(zone);
607 break;
608 default:
609 INSIST(0);
612 return(dns_xfrin_create2(zone, xfrtype, masteraddr, &sourceaddr,
613 tsigkey, mctx, timermgr, socketmgr,
614 task, done, xfrp));
617 isc_result_t
618 dns_xfrin_create2(dns_zone_t *zone, dns_rdatatype_t xfrtype,
619 isc_sockaddr_t *masteraddr, isc_sockaddr_t *sourceaddr,
620 dns_tsigkey_t *tsigkey, isc_mem_t *mctx,
621 isc_timermgr_t *timermgr, isc_socketmgr_t *socketmgr,
622 isc_task_t *task, dns_xfrindone_t done, dns_xfrin_ctx_t **xfrp)
624 dns_name_t *zonename = dns_zone_getorigin(zone);
625 dns_xfrin_ctx_t *xfr = NULL;
626 isc_result_t result;
627 dns_db_t *db = NULL;
629 REQUIRE(xfrp != NULL && *xfrp == NULL);
631 (void)dns_zone_getdb(zone, &db);
633 if (xfrtype == dns_rdatatype_soa || xfrtype == dns_rdatatype_ixfr)
634 REQUIRE(db != NULL);
636 CHECK(xfrin_create(mctx, zone, db, task, timermgr, socketmgr, zonename,
637 dns_zone_getclass(zone), xfrtype, masteraddr,
638 sourceaddr, tsigkey, &xfr));
640 CHECK(xfrin_start(xfr));
642 xfr->done = done;
643 xfr->refcount++;
644 *xfrp = xfr;
646 failure:
647 if (db != NULL)
648 dns_db_detach(&db);
649 if (result != ISC_R_SUCCESS) {
650 char zonetext[DNS_NAME_MAXTEXT+32];
651 dns_zone_name(zone, zonetext, sizeof(zonetext));
652 xfrin_log1(ISC_LOG_ERROR, zonetext, masteraddr,
653 "zone transfer setup failed");
655 return (result);
658 void
659 dns_xfrin_shutdown(dns_xfrin_ctx_t *xfr) {
660 if (! xfr->shuttingdown)
661 xfrin_fail(xfr, ISC_R_CANCELED, "shut down");
664 void
665 dns_xfrin_attach(dns_xfrin_ctx_t *source, dns_xfrin_ctx_t **target) {
666 REQUIRE(target != NULL && *target == NULL);
667 source->refcount++;
668 *target = source;
671 void
672 dns_xfrin_detach(dns_xfrin_ctx_t **xfrp) {
673 dns_xfrin_ctx_t *xfr = *xfrp;
674 INSIST(xfr->refcount > 0);
675 xfr->refcount--;
676 maybe_free(xfr);
677 *xfrp = NULL;
680 static void
681 xfrin_cancelio(dns_xfrin_ctx_t *xfr) {
682 if (xfr->connects > 0) {
683 isc_socket_cancel(xfr->socket, xfr->task,
684 ISC_SOCKCANCEL_CONNECT);
685 } else if (xfr->recvs > 0) {
686 dns_tcpmsg_cancelread(&xfr->tcpmsg);
687 } else if (xfr->sends > 0) {
688 isc_socket_cancel(xfr->socket, xfr->task,
689 ISC_SOCKCANCEL_SEND);
693 static void
694 xfrin_reset(dns_xfrin_ctx_t *xfr) {
695 REQUIRE(VALID_XFRIN(xfr));
697 xfrin_log(xfr, ISC_LOG_INFO, "resetting");
699 xfrin_cancelio(xfr);
701 if (xfr->socket != NULL)
702 isc_socket_detach(&xfr->socket);
704 if (xfr->lasttsig != NULL)
705 isc_buffer_free(&xfr->lasttsig);
707 dns_diff_clear(&xfr->diff);
708 xfr->difflen = 0;
710 if (xfr->ixfr.journal != NULL)
711 dns_journal_destroy(&xfr->ixfr.journal);
713 if (xfr->axfr.add_private != NULL) {
714 (void)dns_db_endload(xfr->db, &xfr->axfr.add_private);
715 xfr->axfr.add_func = NULL;
718 if (xfr->tcpmsg_valid) {
719 dns_tcpmsg_invalidate(&xfr->tcpmsg);
720 xfr->tcpmsg_valid = ISC_FALSE;
723 if (xfr->ver != NULL)
724 dns_db_closeversion(xfr->db, &xfr->ver, ISC_FALSE);
728 static void
729 xfrin_fail(dns_xfrin_ctx_t *xfr, isc_result_t result, const char *msg) {
730 if (result != DNS_R_UPTODATE) {
731 xfrin_log(xfr, ISC_LOG_ERROR, "%s: %s",
732 msg, isc_result_totext(result));
733 if (xfr->is_ixfr)
734 /* Pass special result code to force AXFR retry */
735 result = DNS_R_BADIXFR;
737 xfrin_cancelio(xfr);
739 * Close the journal.
741 if (xfr->ixfr.journal != NULL)
742 dns_journal_destroy(&xfr->ixfr.journal);
743 if (xfr->done != NULL) {
744 (xfr->done)(xfr->zone, result);
745 xfr->done = NULL;
747 xfr->shuttingdown = ISC_TRUE;
748 maybe_free(xfr);
751 static isc_result_t
752 xfrin_create(isc_mem_t *mctx,
753 dns_zone_t *zone,
754 dns_db_t *db,
755 isc_task_t *task,
756 isc_timermgr_t *timermgr,
757 isc_socketmgr_t *socketmgr,
758 dns_name_t *zonename,
759 dns_rdataclass_t rdclass,
760 dns_rdatatype_t reqtype,
761 isc_sockaddr_t *masteraddr,
762 isc_sockaddr_t *sourceaddr,
763 dns_tsigkey_t *tsigkey,
764 dns_xfrin_ctx_t **xfrp)
766 dns_xfrin_ctx_t *xfr = NULL;
767 isc_result_t result;
768 isc_uint32_t tmp;
770 xfr = isc_mem_get(mctx, sizeof(*xfr));
771 if (xfr == NULL)
772 return (ISC_R_NOMEMORY);
773 xfr->mctx = mctx;
774 xfr->refcount = 0;
775 xfr->zone = NULL;
776 dns_zone_iattach(zone, &xfr->zone);
777 xfr->task = NULL;
778 isc_task_attach(task, &xfr->task);
779 xfr->timer = NULL;
780 xfr->socketmgr = socketmgr;
781 xfr->done = NULL;
783 xfr->connects = 0;
784 xfr->sends = 0;
785 xfr->recvs = 0;
786 xfr->shuttingdown = ISC_FALSE;
788 dns_name_init(&xfr->name, NULL);
789 xfr->rdclass = rdclass;
790 isc_random_get(&tmp);
791 xfr->checkid = ISC_TRUE;
792 xfr->id = (isc_uint16_t)(tmp & 0xffff);
793 xfr->reqtype = reqtype;
795 /* sockaddr */
796 xfr->socket = NULL;
797 /* qbuffer */
798 /* qbuffer_data */
799 /* tcpmsg */
800 xfr->tcpmsg_valid = ISC_FALSE;
802 xfr->db = NULL;
803 if (db != NULL)
804 dns_db_attach(db, &xfr->db);
805 xfr->ver = NULL;
806 dns_diff_init(xfr->mctx, &xfr->diff);
807 xfr->difflen = 0;
809 if (reqtype == dns_rdatatype_soa)
810 xfr->state = XFRST_SOAQUERY;
811 else
812 xfr->state = XFRST_INITIALSOA;
813 /* end_serial */
815 xfr->nmsg = 0;
816 xfr->nrecs = 0;
817 xfr->nbytes = 0;
818 isc_time_now(&xfr->start);
820 xfr->tsigkey = NULL;
821 if (tsigkey != NULL)
822 dns_tsigkey_attach(tsigkey, &xfr->tsigkey);
823 xfr->lasttsig = NULL;
824 xfr->tsigctx = NULL;
825 xfr->sincetsig = 0;
826 xfr->is_ixfr = ISC_FALSE;
828 /* ixfr.request_serial */
829 /* ixfr.current_serial */
830 xfr->ixfr.journal = NULL;
832 xfr->axfr.add_func = NULL;
833 xfr->axfr.add_private = NULL;
835 CHECK(dns_name_dup(zonename, mctx, &xfr->name));
837 CHECK(isc_timer_create(timermgr, isc_timertype_inactive, NULL, NULL,
838 task, xfrin_timeout, xfr, &xfr->timer));
839 CHECK(dns_timer_setidle(xfr->timer,
840 dns_zone_getmaxxfrin(xfr->zone),
841 dns_zone_getidlein(xfr->zone),
842 ISC_FALSE));
844 xfr->masteraddr = *masteraddr;
846 INSIST(isc_sockaddr_pf(masteraddr) == isc_sockaddr_pf(sourceaddr));
847 xfr->sourceaddr = *sourceaddr;
848 isc_sockaddr_setport(&xfr->sourceaddr, 0);
850 isc_buffer_init(&xfr->qbuffer, xfr->qbuffer_data,
851 sizeof(xfr->qbuffer_data));
853 xfr->magic = XFRIN_MAGIC;
854 *xfrp = xfr;
855 return (ISC_R_SUCCESS);
857 failure:
858 if (xfr->timer != NULL)
859 isc_timer_detach(&xfr->timer);
860 if (dns_name_dynamic(&xfr->name))
861 dns_name_free(&xfr->name, xfr->mctx);
862 if (xfr->tsigkey != NULL)
863 dns_tsigkey_detach(&xfr->tsigkey);
864 if (xfr->db != NULL)
865 dns_db_detach(&xfr->db);
866 isc_task_detach(&xfr->task);
867 dns_zone_idetach(&xfr->zone);
868 isc_mem_put(mctx, xfr, sizeof(*xfr));
870 return (result);
873 static isc_result_t
874 xfrin_start(dns_xfrin_ctx_t *xfr) {
875 isc_result_t result;
876 CHECK(isc_socket_create(xfr->socketmgr,
877 isc_sockaddr_pf(&xfr->sourceaddr),
878 isc_sockettype_tcp,
879 &xfr->socket));
880 isc_socket_setname(xfr->socket, "xfrin", NULL);
881 #ifndef BROKEN_TCP_BIND_BEFORE_CONNECT
882 CHECK(isc_socket_bind(xfr->socket, &xfr->sourceaddr,
883 ISC_SOCKET_REUSEADDRESS));
884 #endif
885 CHECK(isc_socket_connect(xfr->socket, &xfr->masteraddr, xfr->task,
886 xfrin_connect_done, xfr));
887 xfr->connects++;
888 return (ISC_R_SUCCESS);
889 failure:
890 xfrin_fail(xfr, result, "failed setting up socket");
891 return (result);
894 /* XXX the resolver could use this, too */
896 static isc_result_t
897 render(dns_message_t *msg, isc_mem_t *mctx, isc_buffer_t *buf) {
898 dns_compress_t cctx;
899 isc_boolean_t cleanup_cctx = ISC_FALSE;
900 isc_result_t result;
902 CHECK(dns_compress_init(&cctx, -1, mctx));
903 cleanup_cctx = ISC_TRUE;
904 CHECK(dns_message_renderbegin(msg, &cctx, buf));
905 CHECK(dns_message_rendersection(msg, DNS_SECTION_QUESTION, 0));
906 CHECK(dns_message_rendersection(msg, DNS_SECTION_ANSWER, 0));
907 CHECK(dns_message_rendersection(msg, DNS_SECTION_AUTHORITY, 0));
908 CHECK(dns_message_rendersection(msg, DNS_SECTION_ADDITIONAL, 0));
909 CHECK(dns_message_renderend(msg));
910 result = ISC_R_SUCCESS;
911 failure:
912 if (cleanup_cctx)
913 dns_compress_invalidate(&cctx);
914 return (result);
918 * A connection has been established.
920 static void
921 xfrin_connect_done(isc_task_t *task, isc_event_t *event) {
922 isc_socket_connev_t *cev = (isc_socket_connev_t *) event;
923 dns_xfrin_ctx_t *xfr = (dns_xfrin_ctx_t *) event->ev_arg;
924 isc_result_t result = cev->result;
925 char sourcetext[ISC_SOCKADDR_FORMATSIZE];
926 isc_sockaddr_t sockaddr;
928 REQUIRE(VALID_XFRIN(xfr));
930 UNUSED(task);
932 INSIST(event->ev_type == ISC_SOCKEVENT_CONNECT);
933 isc_event_free(&event);
935 xfr->connects--;
936 if (xfr->shuttingdown) {
937 maybe_free(xfr);
938 return;
941 if (result != ISC_R_SUCCESS) {
942 dns_zonemgr_t * zmgr = dns_zone_getmgr(xfr->zone);
943 isc_time_t now;
945 if (zmgr != NULL) {
946 TIME_NOW(&now);
947 dns_zonemgr_unreachableadd(zmgr, &xfr->masteraddr,
948 &xfr->sourceaddr, &now);
950 goto failure;
953 result = isc_socket_getsockname(xfr->socket, &sockaddr);
954 if (result == ISC_R_SUCCESS) {
955 isc_sockaddr_format(&sockaddr, sourcetext, sizeof(sourcetext));
956 } else
957 strcpy(sourcetext, "<UNKNOWN>");
958 xfrin_log(xfr, ISC_LOG_INFO, "connected using %s", sourcetext);
960 dns_tcpmsg_init(xfr->mctx, xfr->socket, &xfr->tcpmsg);
961 xfr->tcpmsg_valid = ISC_TRUE;
963 CHECK(xfrin_send_request(xfr));
964 failure:
965 if (result != ISC_R_SUCCESS)
966 xfrin_fail(xfr, result, "failed to connect");
970 * Convert a tuple into a dns_name_t suitable for inserting
971 * into the given dns_message_t.
973 static isc_result_t
974 tuple2msgname(dns_difftuple_t *tuple, dns_message_t *msg, dns_name_t **target)
976 isc_result_t result;
977 dns_rdata_t *rdata = NULL;
978 dns_rdatalist_t *rdl = NULL;
979 dns_rdataset_t *rds = NULL;
980 dns_name_t *name = NULL;
982 REQUIRE(target != NULL && *target == NULL);
984 CHECK(dns_message_gettemprdata(msg, &rdata));
985 dns_rdata_init(rdata);
986 dns_rdata_clone(&tuple->rdata, rdata);
988 CHECK(dns_message_gettemprdatalist(msg, &rdl));
989 dns_rdatalist_init(rdl);
990 rdl->type = tuple->rdata.type;
991 rdl->rdclass = tuple->rdata.rdclass;
992 rdl->ttl = tuple->ttl;
993 ISC_LIST_APPEND(rdl->rdata, rdata, link);
995 CHECK(dns_message_gettemprdataset(msg, &rds));
996 dns_rdataset_init(rds);
997 CHECK(dns_rdatalist_tordataset(rdl, rds));
999 CHECK(dns_message_gettempname(msg, &name));
1000 dns_name_init(name, NULL);
1001 dns_name_clone(&tuple->name, name);
1002 ISC_LIST_APPEND(name->list, rds, link);
1004 *target = name;
1005 return (ISC_R_SUCCESS);
1007 failure:
1009 if (rds != NULL) {
1010 dns_rdataset_disassociate(rds);
1011 dns_message_puttemprdataset(msg, &rds);
1013 if (rdl != NULL) {
1014 ISC_LIST_UNLINK(rdl->rdata, rdata, link);
1015 dns_message_puttemprdatalist(msg, &rdl);
1017 if (rdata != NULL)
1018 dns_message_puttemprdata(msg, &rdata);
1020 return (result);
1025 * Build an *XFR request and send its length prefix.
1027 static isc_result_t
1028 xfrin_send_request(dns_xfrin_ctx_t *xfr) {
1029 isc_result_t result;
1030 isc_region_t region;
1031 isc_region_t lregion;
1032 dns_rdataset_t *qrdataset = NULL;
1033 dns_message_t *msg = NULL;
1034 unsigned char length[2];
1035 dns_difftuple_t *soatuple = NULL;
1036 dns_name_t *qname = NULL;
1037 dns_dbversion_t *ver = NULL;
1038 dns_name_t *msgsoaname = NULL;
1040 /* Create the request message */
1041 CHECK(dns_message_create(xfr->mctx, DNS_MESSAGE_INTENTRENDER, &msg));
1042 CHECK(dns_message_settsigkey(msg, xfr->tsigkey));
1044 /* Create a name for the question section. */
1045 CHECK(dns_message_gettempname(msg, &qname));
1046 dns_name_init(qname, NULL);
1047 dns_name_clone(&xfr->name, qname);
1049 /* Formulate the question and attach it to the question name. */
1050 CHECK(dns_message_gettemprdataset(msg, &qrdataset));
1051 dns_rdataset_init(qrdataset);
1052 dns_rdataset_makequestion(qrdataset, xfr->rdclass, xfr->reqtype);
1053 ISC_LIST_APPEND(qname->list, qrdataset, link);
1054 qrdataset = NULL;
1056 dns_message_addname(msg, qname, DNS_SECTION_QUESTION);
1057 qname = NULL;
1059 if (xfr->reqtype == dns_rdatatype_ixfr) {
1060 /* Get the SOA and add it to the authority section. */
1061 /* XXX is using the current version the right thing? */
1062 dns_db_currentversion(xfr->db, &ver);
1063 CHECK(dns_db_createsoatuple(xfr->db, ver, xfr->mctx,
1064 DNS_DIFFOP_EXISTS, &soatuple));
1065 xfr->ixfr.request_serial = dns_soa_getserial(&soatuple->rdata);
1066 xfr->ixfr.current_serial = xfr->ixfr.request_serial;
1067 xfrin_log(xfr, ISC_LOG_DEBUG(3),
1068 "requesting IXFR for serial %u",
1069 xfr->ixfr.request_serial);
1071 CHECK(tuple2msgname(soatuple, msg, &msgsoaname));
1072 dns_message_addname(msg, msgsoaname, DNS_SECTION_AUTHORITY);
1073 } else if (xfr->reqtype == dns_rdatatype_soa)
1074 CHECK(dns_db_getsoaserial(xfr->db, NULL,
1075 &xfr->ixfr.request_serial));
1077 xfr->checkid = ISC_TRUE;
1078 xfr->id++;
1079 xfr->nmsg = 0;
1080 xfr->nrecs = 0;
1081 xfr->nbytes = 0;
1082 isc_time_now(&xfr->start);
1083 msg->id = xfr->id;
1084 if (xfr->tsigctx != NULL)
1085 dst_context_destroy(&xfr->tsigctx);
1087 CHECK(render(msg, xfr->mctx, &xfr->qbuffer));
1090 * Free the last tsig, if there is one.
1092 if (xfr->lasttsig != NULL)
1093 isc_buffer_free(&xfr->lasttsig);
1096 * Save the query TSIG and don't let message_destroy free it.
1098 CHECK(dns_message_getquerytsig(msg, xfr->mctx, &xfr->lasttsig));
1100 isc_buffer_usedregion(&xfr->qbuffer, &region);
1101 INSIST(region.length <= 65535);
1103 length[0] = region.length >> 8;
1104 length[1] = region.length & 0xFF;
1105 lregion.base = length;
1106 lregion.length = 2;
1107 CHECK(isc_socket_send(xfr->socket, &lregion, xfr->task,
1108 xfrin_sendlen_done, xfr));
1109 xfr->sends++;
1111 failure:
1112 if (qname != NULL)
1113 dns_message_puttempname(msg, &qname);
1114 if (qrdataset != NULL)
1115 dns_message_puttemprdataset(msg, &qrdataset);
1116 if (msg != NULL)
1117 dns_message_destroy(&msg);
1118 if (soatuple != NULL)
1119 dns_difftuple_free(&soatuple);
1120 if (ver != NULL)
1121 dns_db_closeversion(xfr->db, &ver, ISC_FALSE);
1122 return (result);
1125 /* XXX there should be library support for sending DNS TCP messages */
1127 static void
1128 xfrin_sendlen_done(isc_task_t *task, isc_event_t *event) {
1129 isc_socketevent_t *sev = (isc_socketevent_t *) event;
1130 dns_xfrin_ctx_t *xfr = (dns_xfrin_ctx_t *) event->ev_arg;
1131 isc_result_t evresult = sev->result;
1132 isc_result_t result;
1133 isc_region_t region;
1135 REQUIRE(VALID_XFRIN(xfr));
1137 UNUSED(task);
1139 INSIST(event->ev_type == ISC_SOCKEVENT_SENDDONE);
1140 isc_event_free(&event);
1142 xfr->sends--;
1143 if (xfr->shuttingdown) {
1144 maybe_free(xfr);
1145 return;
1148 xfrin_log(xfr, ISC_LOG_DEBUG(3), "sent request length prefix");
1149 CHECK(evresult);
1151 isc_buffer_usedregion(&xfr->qbuffer, &region);
1152 CHECK(isc_socket_send(xfr->socket, &region, xfr->task,
1153 xfrin_send_done, xfr));
1154 xfr->sends++;
1155 failure:
1156 if (result != ISC_R_SUCCESS)
1157 xfrin_fail(xfr, result, "failed sending request length prefix");
1161 static void
1162 xfrin_send_done(isc_task_t *task, isc_event_t *event) {
1163 isc_socketevent_t *sev = (isc_socketevent_t *) event;
1164 dns_xfrin_ctx_t *xfr = (dns_xfrin_ctx_t *) event->ev_arg;
1165 isc_result_t result;
1167 REQUIRE(VALID_XFRIN(xfr));
1169 UNUSED(task);
1171 INSIST(event->ev_type == ISC_SOCKEVENT_SENDDONE);
1173 xfr->sends--;
1174 xfrin_log(xfr, ISC_LOG_DEBUG(3), "sent request data");
1175 CHECK(sev->result);
1177 CHECK(dns_tcpmsg_readmessage(&xfr->tcpmsg, xfr->task,
1178 xfrin_recv_done, xfr));
1179 xfr->recvs++;
1180 failure:
1181 isc_event_free(&event);
1182 if (result != ISC_R_SUCCESS)
1183 xfrin_fail(xfr, result, "failed sending request data");
1187 static void
1188 xfrin_recv_done(isc_task_t *task, isc_event_t *ev) {
1189 dns_xfrin_ctx_t *xfr = (dns_xfrin_ctx_t *) ev->ev_arg;
1190 isc_result_t result;
1191 dns_message_t *msg = NULL;
1192 dns_name_t *name;
1193 dns_tcpmsg_t *tcpmsg;
1194 dns_name_t *tsigowner = NULL;
1196 REQUIRE(VALID_XFRIN(xfr));
1198 UNUSED(task);
1200 INSIST(ev->ev_type == DNS_EVENT_TCPMSG);
1201 tcpmsg = ev->ev_sender;
1202 isc_event_free(&ev);
1204 xfr->recvs--;
1205 if (xfr->shuttingdown) {
1206 maybe_free(xfr);
1207 return;
1210 CHECK(tcpmsg->result);
1212 xfrin_log(xfr, ISC_LOG_DEBUG(7), "received %u bytes",
1213 tcpmsg->buffer.used);
1215 CHECK(isc_timer_touch(xfr->timer));
1217 CHECK(dns_message_create(xfr->mctx, DNS_MESSAGE_INTENTPARSE, &msg));
1219 CHECK(dns_message_settsigkey(msg, xfr->tsigkey));
1220 CHECK(dns_message_setquerytsig(msg, xfr->lasttsig));
1222 msg->tsigctx = xfr->tsigctx;
1223 xfr->tsigctx = NULL;
1225 if (xfr->nmsg > 0)
1226 msg->tcp_continuation = 1;
1228 result = dns_message_parse(msg, &tcpmsg->buffer,
1229 DNS_MESSAGEPARSE_PRESERVEORDER);
1231 if (result != ISC_R_SUCCESS || msg->rcode != dns_rcode_noerror ||
1232 (xfr->checkid && msg->id != xfr->id)) {
1233 if (result == ISC_R_SUCCESS)
1234 result = ISC_RESULTCLASS_DNSRCODE + msg->rcode; /*XXX*/
1235 if (result == ISC_R_SUCCESS || result == DNS_R_NOERROR)
1236 result = DNS_R_UNEXPECTEDID;
1237 if (xfr->reqtype == dns_rdatatype_axfr ||
1238 xfr->reqtype == dns_rdatatype_soa)
1239 FAIL(result);
1240 xfrin_log(xfr, ISC_LOG_DEBUG(3), "got %s, retrying with AXFR",
1241 isc_result_totext(result));
1242 try_axfr:
1243 dns_message_destroy(&msg);
1244 xfrin_reset(xfr);
1245 xfr->reqtype = dns_rdatatype_soa;
1246 xfr->state = XFRST_SOAQUERY;
1247 (void)xfrin_start(xfr);
1248 return;
1252 * Does the server know about IXFR? If it doesn't we will get
1253 * a message with a empty answer section or a potentially a CNAME /
1254 * DNAME, the later is handled by xfr_rr() which will return FORMERR
1255 * if the first RR in the answer section is not a SOA record.
1257 if (xfr->reqtype == dns_rdatatype_ixfr &&
1258 xfr->state == XFRST_INITIALSOA &&
1259 msg->counts[DNS_SECTION_ANSWER] == 0) {
1260 xfrin_log(xfr, ISC_LOG_DEBUG(3),
1261 "empty answer section, retrying with AXFR");
1262 goto try_axfr;
1265 if (xfr->reqtype == dns_rdatatype_soa &&
1266 (msg->flags & DNS_MESSAGEFLAG_AA) == 0) {
1267 FAIL(DNS_R_NOTAUTHORITATIVE);
1271 result = dns_message_checksig(msg, dns_zone_getview(xfr->zone));
1272 if (result != ISC_R_SUCCESS) {
1273 xfrin_log(xfr, ISC_LOG_DEBUG(3), "TSIG check failed: %s",
1274 isc_result_totext(result));
1275 FAIL(result);
1278 for (result = dns_message_firstname(msg, DNS_SECTION_ANSWER);
1279 result == ISC_R_SUCCESS;
1280 result = dns_message_nextname(msg, DNS_SECTION_ANSWER))
1282 dns_rdataset_t *rds;
1284 name = NULL;
1285 dns_message_currentname(msg, DNS_SECTION_ANSWER, &name);
1286 for (rds = ISC_LIST_HEAD(name->list);
1287 rds != NULL;
1288 rds = ISC_LIST_NEXT(rds, link))
1290 for (result = dns_rdataset_first(rds);
1291 result == ISC_R_SUCCESS;
1292 result = dns_rdataset_next(rds))
1294 dns_rdata_t rdata = DNS_RDATA_INIT;
1295 dns_rdataset_current(rds, &rdata);
1296 CHECK(xfr_rr(xfr, name, rds->ttl, &rdata));
1300 if (result != ISC_R_NOMORE)
1301 goto failure;
1303 if (dns_message_gettsig(msg, &tsigowner) != NULL) {
1305 * Reset the counter.
1307 xfr->sincetsig = 0;
1310 * Free the last tsig, if there is one.
1312 if (xfr->lasttsig != NULL)
1313 isc_buffer_free(&xfr->lasttsig);
1316 * Update the last tsig pointer.
1318 CHECK(dns_message_getquerytsig(msg, xfr->mctx,
1319 &xfr->lasttsig));
1321 } else if (dns_message_gettsigkey(msg) != NULL) {
1322 xfr->sincetsig++;
1323 if (xfr->sincetsig > 100 ||
1324 xfr->nmsg == 0 || xfr->state == XFRST_END)
1326 result = DNS_R_EXPECTEDTSIG;
1327 goto failure;
1332 * Update the number of messages received.
1334 xfr->nmsg++;
1337 * Update the number of bytes received.
1339 xfr->nbytes += tcpmsg->buffer.used;
1342 * Take the context back.
1344 INSIST(xfr->tsigctx == NULL);
1345 xfr->tsigctx = msg->tsigctx;
1346 msg->tsigctx = NULL;
1348 dns_message_destroy(&msg);
1350 if (xfr->state == XFRST_GOTSOA) {
1351 xfr->reqtype = dns_rdatatype_axfr;
1352 xfr->state = XFRST_INITIALSOA;
1353 CHECK(xfrin_send_request(xfr));
1354 } else if (xfr->state == XFRST_END) {
1356 * Close the journal.
1358 if (xfr->ixfr.journal != NULL)
1359 dns_journal_destroy(&xfr->ixfr.journal);
1361 * Inform the caller we succeeded.
1363 if (xfr->done != NULL) {
1364 (xfr->done)(xfr->zone, ISC_R_SUCCESS);
1365 xfr->done = NULL;
1368 * We should have no outstanding events at this
1369 * point, thus maybe_free() should succeed.
1371 xfr->shuttingdown = ISC_TRUE;
1372 maybe_free(xfr);
1373 } else {
1375 * Read the next message.
1377 CHECK(dns_tcpmsg_readmessage(&xfr->tcpmsg, xfr->task,
1378 xfrin_recv_done, xfr));
1379 xfr->recvs++;
1381 return;
1383 failure:
1384 if (msg != NULL)
1385 dns_message_destroy(&msg);
1386 if (result != ISC_R_SUCCESS)
1387 xfrin_fail(xfr, result, "failed while receiving responses");
1390 static void
1391 xfrin_timeout(isc_task_t *task, isc_event_t *event) {
1392 dns_xfrin_ctx_t *xfr = (dns_xfrin_ctx_t *) event->ev_arg;
1394 REQUIRE(VALID_XFRIN(xfr));
1396 UNUSED(task);
1398 isc_event_free(&event);
1400 * This will log "giving up: timeout".
1402 xfrin_fail(xfr, ISC_R_TIMEDOUT, "giving up");
1405 static void
1406 maybe_free(dns_xfrin_ctx_t *xfr) {
1407 isc_uint64_t msecs;
1408 isc_uint64_t persec;
1410 REQUIRE(VALID_XFRIN(xfr));
1412 if (! xfr->shuttingdown || xfr->refcount != 0 ||
1413 xfr->connects != 0 || xfr->sends != 0 ||
1414 xfr->recvs != 0)
1415 return;
1418 * Calculate the length of time the transfer took,
1419 * and print a log message with the bytes and rate.
1421 isc_time_now(&xfr->end);
1422 msecs = isc_time_microdiff(&xfr->end, &xfr->start) / 1000;
1423 if (msecs == 0)
1424 msecs = 1;
1425 persec = (xfr->nbytes * 1000) / msecs;
1426 xfrin_log(xfr, ISC_LOG_INFO,
1427 "Transfer completed: %d messages, %d records, "
1428 "%" ISC_PRINT_QUADFORMAT "u bytes, "
1429 "%u.%03u secs (%u bytes/sec)",
1430 xfr->nmsg, xfr->nrecs, xfr->nbytes,
1431 (unsigned int) (msecs / 1000), (unsigned int) (msecs % 1000),
1432 (unsigned int) persec);
1434 if (xfr->socket != NULL)
1435 isc_socket_detach(&xfr->socket);
1437 if (xfr->timer != NULL)
1438 isc_timer_detach(&xfr->timer);
1440 if (xfr->task != NULL)
1441 isc_task_detach(&xfr->task);
1443 if (xfr->tsigkey != NULL)
1444 dns_tsigkey_detach(&xfr->tsigkey);
1446 if (xfr->lasttsig != NULL)
1447 isc_buffer_free(&xfr->lasttsig);
1449 dns_diff_clear(&xfr->diff);
1451 if (xfr->ixfr.journal != NULL)
1452 dns_journal_destroy(&xfr->ixfr.journal);
1454 if (xfr->axfr.add_private != NULL)
1455 (void)dns_db_endload(xfr->db, &xfr->axfr.add_private);
1457 if (xfr->tcpmsg_valid)
1458 dns_tcpmsg_invalidate(&xfr->tcpmsg);
1460 if (xfr->tsigctx != NULL)
1461 dst_context_destroy(&xfr->tsigctx);
1463 if ((xfr->name.attributes & DNS_NAMEATTR_DYNAMIC) != 0)
1464 dns_name_free(&xfr->name, xfr->mctx);
1466 if (xfr->ver != NULL)
1467 dns_db_closeversion(xfr->db, &xfr->ver, ISC_FALSE);
1469 if (xfr->db != NULL)
1470 dns_db_detach(&xfr->db);
1472 if (xfr->zone != NULL)
1473 dns_zone_idetach(&xfr->zone);
1475 isc_mem_put(xfr->mctx, xfr, sizeof(*xfr));
1479 * Log incoming zone transfer messages in a format like
1480 * transfer of <zone> from <address>: <message>
1482 static void
1483 xfrin_logv(int level, const char *zonetext, isc_sockaddr_t *masteraddr,
1484 const char *fmt, va_list ap)
1486 char mastertext[ISC_SOCKADDR_FORMATSIZE];
1487 char msgtext[2048];
1489 isc_sockaddr_format(masteraddr, mastertext, sizeof(mastertext));
1490 vsnprintf(msgtext, sizeof(msgtext), fmt, ap);
1492 isc_log_write(dns_lctx, DNS_LOGCATEGORY_XFER_IN,
1493 DNS_LOGMODULE_XFER_IN, level,
1494 "transfer of '%s' from %s: %s",
1495 zonetext, mastertext, msgtext);
1499 * Logging function for use when a xfrin_ctx_t has not yet been created.
1502 static void
1503 xfrin_log1(int level, const char *zonetext, isc_sockaddr_t *masteraddr,
1504 const char *fmt, ...)
1506 va_list ap;
1508 if (isc_log_wouldlog(dns_lctx, level) == ISC_FALSE)
1509 return;
1511 va_start(ap, fmt);
1512 xfrin_logv(level, zonetext, masteraddr, fmt, ap);
1513 va_end(ap);
1517 * Logging function for use when there is a xfrin_ctx_t.
1520 static void
1521 xfrin_log(dns_xfrin_ctx_t *xfr, int level, const char *fmt, ...)
1523 va_list ap;
1524 char zonetext[DNS_NAME_MAXTEXT+32];
1526 if (isc_log_wouldlog(dns_lctx, level) == ISC_FALSE)
1527 return;
1529 dns_zone_name(xfr->zone, zonetext, sizeof(zonetext));
1531 va_start(ap, fmt);
1532 xfrin_logv(level, zonetext, &xfr->masteraddr, fmt, ap);
1533 va_end(ap);