Import bind 9.5.2 vendor sources.
[dragonfly.git] / contrib / bind-9.5.2 / lib / dns / xfrin.c
blobab7af0be280f68d781c6723bc64a53862f86678d
1 /*
2 * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
18 /* $Id: xfrin.c,v 1.157.12.7 2008/09/25 04:15:41 marka Exp $ */
20 /*! \file */
22 #include <config.h>
24 #include <isc/mem.h>
25 #include <isc/print.h>
26 #include <isc/random.h>
27 #include <isc/string.h> /* Required for HP/UX (and others?) */
28 #include <isc/task.h>
29 #include <isc/timer.h>
30 #include <isc/util.h>
32 #include <dns/db.h>
33 #include <dns/diff.h>
34 #include <dns/events.h>
35 #include <dns/journal.h>
36 #include <dns/log.h>
37 #include <dns/message.h>
38 #include <dns/rdataclass.h>
39 #include <dns/rdatalist.h>
40 #include <dns/rdataset.h>
41 #include <dns/result.h>
42 #include <dns/soa.h>
43 #include <dns/tcpmsg.h>
44 #include <dns/timer.h>
45 #include <dns/tsig.h>
46 #include <dns/view.h>
47 #include <dns/xfrin.h>
48 #include <dns/zone.h>
50 #include <dst/dst.h>
53 * Incoming AXFR and IXFR.
56 /*%
57 * It would be non-sensical (or at least obtuse) to use FAIL() with an
58 * ISC_R_SUCCESS code, but the test is there to keep the Solaris compiler
59 * from complaining about "end-of-loop code not reached".
61 #define FAIL(code) \
62 do { result = (code); \
63 if (result != ISC_R_SUCCESS) goto failure; \
64 } while (0)
66 #define CHECK(op) \
67 do { result = (op); \
68 if (result != ISC_R_SUCCESS) goto failure; \
69 } while (0)
71 /*%
72 * The states of the *XFR state machine. We handle both IXFR and AXFR
73 * with a single integrated state machine because they cannot be distinguished
74 * immediately - an AXFR response to an IXFR request can only be detected
75 * when the first two (2) response RRs have already been received.
77 typedef enum {
78 XFRST_SOAQUERY,
79 XFRST_GOTSOA,
80 XFRST_INITIALSOA,
81 XFRST_FIRSTDATA,
82 XFRST_IXFR_DELSOA,
83 XFRST_IXFR_DEL,
84 XFRST_IXFR_ADDSOA,
85 XFRST_IXFR_ADD,
86 XFRST_AXFR,
87 XFRST_END
88 } xfrin_state_t;
90 /*%
91 * Incoming zone transfer context.
94 struct dns_xfrin_ctx {
95 unsigned int magic;
96 isc_mem_t *mctx;
97 dns_zone_t *zone;
99 int refcount;
101 isc_task_t *task;
102 isc_timer_t *timer;
103 isc_socketmgr_t *socketmgr;
105 int connects; /*%< Connect in progress */
106 int sends; /*%< Send in progress */
107 int recvs; /*%< Receive in progress */
108 isc_boolean_t shuttingdown;
110 dns_name_t name; /*%< Name of zone to transfer */
111 dns_rdataclass_t rdclass;
113 isc_boolean_t checkid;
114 dns_messageid_t id;
117 * Requested transfer type (dns_rdatatype_axfr or
118 * dns_rdatatype_ixfr). The actual transfer type
119 * may differ due to IXFR->AXFR fallback.
121 dns_rdatatype_t reqtype;
123 isc_sockaddr_t masteraddr;
124 isc_sockaddr_t sourceaddr;
125 isc_socket_t *socket;
127 /*% Buffer for IXFR/AXFR request message */
128 isc_buffer_t qbuffer;
129 unsigned char qbuffer_data[512];
131 /*% Incoming reply TCP message */
132 dns_tcpmsg_t tcpmsg;
133 isc_boolean_t tcpmsg_valid;
135 dns_db_t *db;
136 dns_dbversion_t *ver;
137 dns_diff_t diff; /*%< Pending database changes */
138 int difflen; /*%< Number of pending tuples */
140 xfrin_state_t state;
141 isc_uint32_t end_serial;
142 isc_boolean_t is_ixfr;
144 unsigned int nmsg; /*%< Number of messages recvd */
145 unsigned int nrecs; /*%< Number of records recvd */
146 isc_uint64_t nbytes; /*%< Number of bytes received */
148 isc_time_t start; /*%< Start time of the transfer */
149 isc_time_t end; /*%< End time of the transfer */
151 dns_tsigkey_t *tsigkey; /*%< Key used to create TSIG */
152 isc_buffer_t *lasttsig; /*%< The last TSIG */
153 dst_context_t *tsigctx; /*%< TSIG verification context */
154 unsigned int sincetsig; /*%< recvd since the last TSIG */
155 dns_xfrindone_t done;
158 * AXFR- and IXFR-specific data. Only one is used at a time
159 * according to the is_ixfr flag, so this could be a union,
160 * but keeping them separate makes it a bit simpler to clean
161 * things up when destroying the context.
163 struct {
164 dns_addrdatasetfunc_t add_func;
165 dns_dbload_t *add_private;
166 } axfr;
168 struct {
169 isc_uint32_t request_serial;
170 isc_uint32_t current_serial;
171 dns_journal_t *journal;
173 } ixfr;
176 #define XFRIN_MAGIC ISC_MAGIC('X', 'f', 'r', 'I')
177 #define VALID_XFRIN(x) ISC_MAGIC_VALID(x, XFRIN_MAGIC)
179 /**************************************************************************/
181 * Forward declarations.
184 static isc_result_t
185 xfrin_create(isc_mem_t *mctx,
186 dns_zone_t *zone,
187 dns_db_t *db,
188 isc_task_t *task,
189 isc_timermgr_t *timermgr,
190 isc_socketmgr_t *socketmgr,
191 dns_name_t *zonename,
192 dns_rdataclass_t rdclass,
193 dns_rdatatype_t reqtype,
194 isc_sockaddr_t *masteraddr,
195 isc_sockaddr_t *sourceaddr,
196 dns_tsigkey_t *tsigkey,
197 dns_xfrin_ctx_t **xfrp);
199 static isc_result_t axfr_init(dns_xfrin_ctx_t *xfr);
200 static isc_result_t axfr_makedb(dns_xfrin_ctx_t *xfr, dns_db_t **dbp);
201 static isc_result_t axfr_putdata(dns_xfrin_ctx_t *xfr, dns_diffop_t op,
202 dns_name_t *name, dns_ttl_t ttl,
203 dns_rdata_t *rdata);
204 static isc_result_t axfr_apply(dns_xfrin_ctx_t *xfr);
205 static isc_result_t axfr_commit(dns_xfrin_ctx_t *xfr);
207 static isc_result_t ixfr_init(dns_xfrin_ctx_t *xfr);
208 static isc_result_t ixfr_apply(dns_xfrin_ctx_t *xfr);
209 static isc_result_t ixfr_putdata(dns_xfrin_ctx_t *xfr, dns_diffop_t op,
210 dns_name_t *name, dns_ttl_t ttl,
211 dns_rdata_t *rdata);
212 static isc_result_t ixfr_commit(dns_xfrin_ctx_t *xfr);
214 static isc_result_t xfr_rr(dns_xfrin_ctx_t *xfr, dns_name_t *name,
215 isc_uint32_t ttl, dns_rdata_t *rdata);
217 static isc_result_t xfrin_start(dns_xfrin_ctx_t *xfr);
219 static void xfrin_connect_done(isc_task_t *task, isc_event_t *event);
220 static isc_result_t xfrin_send_request(dns_xfrin_ctx_t *xfr);
221 static void xfrin_send_done(isc_task_t *task, isc_event_t *event);
222 static void xfrin_sendlen_done(isc_task_t *task, isc_event_t *event);
223 static void xfrin_recv_done(isc_task_t *task, isc_event_t *event);
224 static void xfrin_timeout(isc_task_t *task, isc_event_t *event);
226 static void maybe_free(dns_xfrin_ctx_t *xfr);
228 static void
229 xfrin_fail(dns_xfrin_ctx_t *xfr, isc_result_t result, const char *msg);
230 static isc_result_t
231 render(dns_message_t *msg, isc_mem_t *mctx, isc_buffer_t *buf);
233 static void
234 xfrin_logv(int level, const char *zonetext, isc_sockaddr_t *masteraddr,
235 const char *fmt, va_list ap)
236 ISC_FORMAT_PRINTF(4, 0);
238 static void
239 xfrin_log1(int level, const char *zonetext, isc_sockaddr_t *masteraddr,
240 const char *fmt, ...)
241 ISC_FORMAT_PRINTF(4, 5);
243 static void
244 xfrin_log(dns_xfrin_ctx_t *xfr, int level, const char *fmt, ...)
245 ISC_FORMAT_PRINTF(3, 4);
247 /**************************************************************************/
249 * AXFR handling
252 static isc_result_t
253 axfr_init(dns_xfrin_ctx_t *xfr) {
254 isc_result_t result;
256 xfr->is_ixfr = ISC_FALSE;
258 if (xfr->db != NULL)
259 dns_db_detach(&xfr->db);
261 CHECK(axfr_makedb(xfr, &xfr->db));
262 CHECK(dns_db_beginload(xfr->db, &xfr->axfr.add_func,
263 &xfr->axfr.add_private));
264 result = ISC_R_SUCCESS;
265 failure:
266 return (result);
269 static isc_result_t
270 axfr_makedb(dns_xfrin_ctx_t *xfr, dns_db_t **dbp) {
271 return (dns_db_create(xfr->mctx, /* XXX */
272 "rbt", /* XXX guess */
273 &xfr->name,
274 dns_dbtype_zone,
275 xfr->rdclass,
276 0, NULL, /* XXX guess */
277 dbp));
280 static isc_result_t
281 axfr_putdata(dns_xfrin_ctx_t *xfr, dns_diffop_t op,
282 dns_name_t *name, dns_ttl_t ttl, dns_rdata_t *rdata)
284 isc_result_t result;
286 dns_difftuple_t *tuple = NULL;
288 CHECK(dns_zone_checknames(xfr->zone, name, rdata));
289 CHECK(dns_difftuple_create(xfr->diff.mctx, op,
290 name, ttl, rdata, &tuple));
291 dns_diff_append(&xfr->diff, &tuple);
292 if (++xfr->difflen > 100)
293 CHECK(axfr_apply(xfr));
294 result = ISC_R_SUCCESS;
295 failure:
296 return (result);
300 * Store a set of AXFR RRs in the database.
302 static isc_result_t
303 axfr_apply(dns_xfrin_ctx_t *xfr) {
304 isc_result_t result;
306 CHECK(dns_diff_load(&xfr->diff,
307 xfr->axfr.add_func, xfr->axfr.add_private));
308 xfr->difflen = 0;
309 dns_diff_clear(&xfr->diff);
310 result = ISC_R_SUCCESS;
311 failure:
312 return (result);
315 static isc_result_t
316 axfr_commit(dns_xfrin_ctx_t *xfr) {
317 isc_result_t result;
319 CHECK(axfr_apply(xfr));
320 CHECK(dns_db_endload(xfr->db, &xfr->axfr.add_private));
321 CHECK(dns_zone_replacedb(xfr->zone, xfr->db, ISC_TRUE));
323 result = ISC_R_SUCCESS;
324 failure:
325 return (result);
328 /**************************************************************************/
330 * IXFR handling
333 static isc_result_t
334 ixfr_init(dns_xfrin_ctx_t *xfr) {
335 isc_result_t result;
336 char *journalfile;
338 if (xfr->reqtype != dns_rdatatype_ixfr) {
339 xfrin_log(xfr, ISC_LOG_ERROR,
340 "got incremental response to AXFR request");
341 return (DNS_R_FORMERR);
344 xfr->is_ixfr = ISC_TRUE;
345 INSIST(xfr->db != NULL);
346 xfr->difflen = 0;
348 journalfile = dns_zone_getjournal(xfr->zone);
349 if (journalfile != NULL)
350 CHECK(dns_journal_open(xfr->mctx, journalfile,
351 ISC_TRUE, &xfr->ixfr.journal));
353 result = ISC_R_SUCCESS;
354 failure:
355 return (result);
358 static isc_result_t
359 ixfr_putdata(dns_xfrin_ctx_t *xfr, dns_diffop_t op,
360 dns_name_t *name, dns_ttl_t ttl, dns_rdata_t *rdata)
362 isc_result_t result;
364 dns_difftuple_t *tuple = NULL;
365 if (op == DNS_DIFFOP_ADD)
366 CHECK(dns_zone_checknames(xfr->zone, name, rdata));
367 CHECK(dns_difftuple_create(xfr->diff.mctx, op,
368 name, ttl, rdata, &tuple));
369 dns_diff_append(&xfr->diff, &tuple);
370 if (++xfr->difflen > 100)
371 CHECK(ixfr_apply(xfr));
372 result = ISC_R_SUCCESS;
373 failure:
374 return (result);
378 * Apply a set of IXFR changes to the database.
380 static isc_result_t
381 ixfr_apply(dns_xfrin_ctx_t *xfr) {
382 isc_result_t result;
384 if (xfr->ver == NULL) {
385 CHECK(dns_db_newversion(xfr->db, &xfr->ver));
386 if (xfr->ixfr.journal != NULL)
387 CHECK(dns_journal_begin_transaction(xfr->ixfr.journal));
389 CHECK(dns_diff_apply(&xfr->diff, xfr->db, xfr->ver));
390 if (xfr->ixfr.journal != NULL) {
391 result = dns_journal_writediff(xfr->ixfr.journal, &xfr->diff);
392 if (result != ISC_R_SUCCESS)
393 goto failure;
395 dns_diff_clear(&xfr->diff);
396 xfr->difflen = 0;
397 result = ISC_R_SUCCESS;
398 failure:
399 return (result);
402 static isc_result_t
403 ixfr_commit(dns_xfrin_ctx_t *xfr) {
404 isc_result_t result;
406 CHECK(ixfr_apply(xfr));
407 if (xfr->ver != NULL) {
408 /* XXX enter ready-to-commit state here */
409 if (xfr->ixfr.journal != NULL)
410 CHECK(dns_journal_commit(xfr->ixfr.journal));
411 dns_db_closeversion(xfr->db, &xfr->ver, ISC_TRUE);
412 dns_zone_markdirty(xfr->zone);
414 result = ISC_R_SUCCESS;
415 failure:
416 return (result);
419 /**************************************************************************/
421 * Common AXFR/IXFR protocol code
425 * Handle a single incoming resource record according to the current
426 * state.
428 static isc_result_t
429 xfr_rr(dns_xfrin_ctx_t *xfr, dns_name_t *name, isc_uint32_t ttl,
430 dns_rdata_t *rdata)
432 isc_result_t result;
434 xfr->nrecs++;
436 if (rdata->type == dns_rdatatype_none ||
437 dns_rdatatype_ismeta(rdata->type))
438 FAIL(DNS_R_FORMERR);
440 redo:
441 switch (xfr->state) {
442 case XFRST_SOAQUERY:
443 if (rdata->type != dns_rdatatype_soa) {
444 xfrin_log(xfr, ISC_LOG_ERROR,
445 "non-SOA response to SOA query");
446 FAIL(DNS_R_FORMERR);
448 xfr->end_serial = dns_soa_getserial(rdata);
449 if (!DNS_SERIAL_GT(xfr->end_serial, xfr->ixfr.request_serial) &&
450 !dns_zone_isforced(xfr->zone)) {
451 xfrin_log(xfr, ISC_LOG_DEBUG(3),
452 "requested serial %u, "
453 "master has %u, not updating",
454 xfr->ixfr.request_serial, xfr->end_serial);
455 FAIL(DNS_R_UPTODATE);
457 xfr->state = XFRST_GOTSOA;
458 break;
460 case XFRST_GOTSOA:
462 * Skip other records in the answer section.
464 break;
466 case XFRST_INITIALSOA:
467 if (rdata->type != dns_rdatatype_soa) {
468 xfrin_log(xfr, ISC_LOG_ERROR,
469 "first RR in zone transfer must be SOA");
470 FAIL(DNS_R_FORMERR);
473 * Remember the serial number in the initial SOA.
474 * We need it to recognize the end of an IXFR.
476 xfr->end_serial = dns_soa_getserial(rdata);
477 if (xfr->reqtype == dns_rdatatype_ixfr &&
478 ! DNS_SERIAL_GT(xfr->end_serial, xfr->ixfr.request_serial)
479 && !dns_zone_isforced(xfr->zone))
482 * This must be the single SOA record that is
483 * sent when the current version on the master
484 * is not newer than the version in the request.
486 xfrin_log(xfr, ISC_LOG_DEBUG(3),
487 "requested serial %u, "
488 "master has %u, not updating",
489 xfr->ixfr.request_serial, xfr->end_serial);
490 FAIL(DNS_R_UPTODATE);
492 if (xfr->reqtype == dns_rdatatype_axfr)
493 xfr->checkid = ISC_FALSE;
494 xfr->state = XFRST_FIRSTDATA;
495 break;
497 case XFRST_FIRSTDATA:
499 * If the transfer begins with one SOA record, it is an AXFR,
500 * if it begins with two SOAs, it is an IXFR.
502 if (xfr->reqtype == dns_rdatatype_ixfr &&
503 rdata->type == dns_rdatatype_soa &&
504 xfr->ixfr.request_serial == dns_soa_getserial(rdata)) {
505 xfrin_log(xfr, ISC_LOG_DEBUG(3),
506 "got incremental response");
507 CHECK(ixfr_init(xfr));
508 xfr->state = XFRST_IXFR_DELSOA;
509 } else {
510 xfrin_log(xfr, ISC_LOG_DEBUG(3),
511 "got nonincremental response");
512 CHECK(axfr_init(xfr));
513 xfr->state = XFRST_AXFR;
515 goto redo;
517 case XFRST_IXFR_DELSOA:
518 INSIST(rdata->type == dns_rdatatype_soa);
519 CHECK(ixfr_putdata(xfr, DNS_DIFFOP_DEL, name, ttl, rdata));
520 xfr->state = XFRST_IXFR_DEL;
521 break;
523 case XFRST_IXFR_DEL:
524 if (rdata->type == dns_rdatatype_soa) {
525 isc_uint32_t soa_serial = dns_soa_getserial(rdata);
526 xfr->state = XFRST_IXFR_ADDSOA;
527 xfr->ixfr.current_serial = soa_serial;
528 goto redo;
530 CHECK(ixfr_putdata(xfr, DNS_DIFFOP_DEL, name, ttl, rdata));
531 break;
533 case XFRST_IXFR_ADDSOA:
534 INSIST(rdata->type == dns_rdatatype_soa);
535 CHECK(ixfr_putdata(xfr, DNS_DIFFOP_ADD, name, ttl, rdata));
536 xfr->state = XFRST_IXFR_ADD;
537 break;
539 case XFRST_IXFR_ADD:
540 if (rdata->type == dns_rdatatype_soa) {
541 isc_uint32_t soa_serial = dns_soa_getserial(rdata);
542 if (soa_serial == xfr->end_serial) {
543 CHECK(ixfr_commit(xfr));
544 xfr->state = XFRST_END;
545 break;
546 } else if (soa_serial != xfr->ixfr.current_serial) {
547 xfrin_log(xfr, ISC_LOG_ERROR,
548 "IXFR out of sync: "
549 "expected serial %u, got %u",
550 xfr->ixfr.current_serial, soa_serial);
551 FAIL(DNS_R_FORMERR);
552 } else {
553 CHECK(ixfr_commit(xfr));
554 xfr->state = XFRST_IXFR_DELSOA;
555 goto redo;
558 if (rdata->type == dns_rdatatype_ns &&
559 dns_name_iswildcard(name))
560 FAIL(DNS_R_INVALIDNS);
561 CHECK(ixfr_putdata(xfr, DNS_DIFFOP_ADD, name, ttl, rdata));
562 break;
564 case XFRST_AXFR:
566 * Old BINDs sent cross class A records for non IN classes.
568 if (rdata->type == dns_rdatatype_a &&
569 rdata->rdclass != xfr->rdclass &&
570 xfr->rdclass != dns_rdataclass_in)
571 break;
572 CHECK(axfr_putdata(xfr, DNS_DIFFOP_ADD, name, ttl, rdata));
573 if (rdata->type == dns_rdatatype_soa) {
574 CHECK(axfr_commit(xfr));
575 xfr->state = XFRST_END;
576 break;
578 break;
579 case XFRST_END:
580 FAIL(DNS_R_EXTRADATA);
581 default:
582 INSIST(0);
583 break;
585 result = ISC_R_SUCCESS;
586 failure:
587 return (result);
590 isc_result_t
591 dns_xfrin_create(dns_zone_t *zone, dns_rdatatype_t xfrtype,
592 isc_sockaddr_t *masteraddr, dns_tsigkey_t *tsigkey,
593 isc_mem_t *mctx, isc_timermgr_t *timermgr,
594 isc_socketmgr_t *socketmgr, isc_task_t *task,
595 dns_xfrindone_t done, dns_xfrin_ctx_t **xfrp)
597 isc_sockaddr_t sourceaddr;
599 switch (isc_sockaddr_pf(masteraddr)) {
600 case PF_INET:
601 sourceaddr = *dns_zone_getxfrsource4(zone);
602 break;
603 case PF_INET6:
604 sourceaddr = *dns_zone_getxfrsource6(zone);
605 break;
606 default:
607 INSIST(0);
610 return(dns_xfrin_create2(zone, xfrtype, masteraddr, &sourceaddr,
611 tsigkey, mctx, timermgr, socketmgr,
612 task, done, xfrp));
615 isc_result_t
616 dns_xfrin_create2(dns_zone_t *zone, dns_rdatatype_t xfrtype,
617 isc_sockaddr_t *masteraddr, isc_sockaddr_t *sourceaddr,
618 dns_tsigkey_t *tsigkey, isc_mem_t *mctx,
619 isc_timermgr_t *timermgr, isc_socketmgr_t *socketmgr,
620 isc_task_t *task, dns_xfrindone_t done, dns_xfrin_ctx_t **xfrp)
622 dns_name_t *zonename = dns_zone_getorigin(zone);
623 dns_xfrin_ctx_t *xfr = NULL;
624 isc_result_t result;
625 dns_db_t *db = NULL;
627 REQUIRE(xfrp != NULL && *xfrp == NULL);
629 (void)dns_zone_getdb(zone, &db);
631 if (xfrtype == dns_rdatatype_soa || xfrtype == dns_rdatatype_ixfr)
632 REQUIRE(db != NULL);
634 CHECK(xfrin_create(mctx, zone, db, task, timermgr, socketmgr, zonename,
635 dns_zone_getclass(zone), xfrtype, masteraddr,
636 sourceaddr, tsigkey, &xfr));
638 CHECK(xfrin_start(xfr));
640 xfr->done = done;
641 xfr->refcount++;
642 *xfrp = xfr;
644 failure:
645 if (db != NULL)
646 dns_db_detach(&db);
647 if (result != ISC_R_SUCCESS) {
648 char zonetext[DNS_NAME_MAXTEXT+32];
649 dns_zone_name(zone, zonetext, sizeof(zonetext));
650 xfrin_log1(ISC_LOG_ERROR, zonetext, masteraddr,
651 "zone transfer setup failed");
653 return (result);
656 void
657 dns_xfrin_shutdown(dns_xfrin_ctx_t *xfr) {
658 if (! xfr->shuttingdown)
659 xfrin_fail(xfr, ISC_R_CANCELED, "shut down");
662 void
663 dns_xfrin_attach(dns_xfrin_ctx_t *source, dns_xfrin_ctx_t **target) {
664 REQUIRE(target != NULL && *target == NULL);
665 source->refcount++;
666 *target = source;
669 void
670 dns_xfrin_detach(dns_xfrin_ctx_t **xfrp) {
671 dns_xfrin_ctx_t *xfr = *xfrp;
672 INSIST(xfr->refcount > 0);
673 xfr->refcount--;
674 maybe_free(xfr);
675 *xfrp = NULL;
678 static void
679 xfrin_cancelio(dns_xfrin_ctx_t *xfr) {
680 if (xfr->connects > 0) {
681 isc_socket_cancel(xfr->socket, xfr->task,
682 ISC_SOCKCANCEL_CONNECT);
683 } else if (xfr->recvs > 0) {
684 dns_tcpmsg_cancelread(&xfr->tcpmsg);
685 } else if (xfr->sends > 0) {
686 isc_socket_cancel(xfr->socket, xfr->task,
687 ISC_SOCKCANCEL_SEND);
691 static void
692 xfrin_reset(dns_xfrin_ctx_t *xfr) {
693 REQUIRE(VALID_XFRIN(xfr));
695 xfrin_log(xfr, ISC_LOG_INFO, "resetting");
697 xfrin_cancelio(xfr);
699 if (xfr->socket != NULL)
700 isc_socket_detach(&xfr->socket);
702 if (xfr->lasttsig != NULL)
703 isc_buffer_free(&xfr->lasttsig);
705 dns_diff_clear(&xfr->diff);
706 xfr->difflen = 0;
708 if (xfr->ixfr.journal != NULL)
709 dns_journal_destroy(&xfr->ixfr.journal);
711 if (xfr->axfr.add_private != NULL) {
712 (void)dns_db_endload(xfr->db, &xfr->axfr.add_private);
713 xfr->axfr.add_func = NULL;
716 if (xfr->tcpmsg_valid) {
717 dns_tcpmsg_invalidate(&xfr->tcpmsg);
718 xfr->tcpmsg_valid = ISC_FALSE;
721 if (xfr->ver != NULL)
722 dns_db_closeversion(xfr->db, &xfr->ver, ISC_FALSE);
726 static void
727 xfrin_fail(dns_xfrin_ctx_t *xfr, isc_result_t result, const char *msg) {
728 if (result != DNS_R_UPTODATE) {
729 xfrin_log(xfr, ISC_LOG_ERROR, "%s: %s",
730 msg, isc_result_totext(result));
731 if (xfr->is_ixfr)
732 /* Pass special result code to force AXFR retry */
733 result = DNS_R_BADIXFR;
735 xfrin_cancelio(xfr);
737 * Close the journal.
739 if (xfr->ixfr.journal != NULL)
740 dns_journal_destroy(&xfr->ixfr.journal);
741 if (xfr->done != NULL) {
742 (xfr->done)(xfr->zone, result);
743 xfr->done = NULL;
745 xfr->shuttingdown = ISC_TRUE;
746 maybe_free(xfr);
749 static isc_result_t
750 xfrin_create(isc_mem_t *mctx,
751 dns_zone_t *zone,
752 dns_db_t *db,
753 isc_task_t *task,
754 isc_timermgr_t *timermgr,
755 isc_socketmgr_t *socketmgr,
756 dns_name_t *zonename,
757 dns_rdataclass_t rdclass,
758 dns_rdatatype_t reqtype,
759 isc_sockaddr_t *masteraddr,
760 isc_sockaddr_t *sourceaddr,
761 dns_tsigkey_t *tsigkey,
762 dns_xfrin_ctx_t **xfrp)
764 dns_xfrin_ctx_t *xfr = NULL;
765 isc_result_t result;
766 isc_uint32_t tmp;
768 xfr = isc_mem_get(mctx, sizeof(*xfr));
769 if (xfr == NULL)
770 return (ISC_R_NOMEMORY);
771 xfr->mctx = mctx;
772 xfr->refcount = 0;
773 xfr->zone = NULL;
774 dns_zone_iattach(zone, &xfr->zone);
775 xfr->task = NULL;
776 isc_task_attach(task, &xfr->task);
777 xfr->timer = NULL;
778 xfr->socketmgr = socketmgr;
779 xfr->done = NULL;
781 xfr->connects = 0;
782 xfr->sends = 0;
783 xfr->recvs = 0;
784 xfr->shuttingdown = ISC_FALSE;
786 dns_name_init(&xfr->name, NULL);
787 xfr->rdclass = rdclass;
788 isc_random_get(&tmp);
789 xfr->checkid = ISC_TRUE;
790 xfr->id = (isc_uint16_t)(tmp & 0xffff);
791 xfr->reqtype = reqtype;
793 /* sockaddr */
794 xfr->socket = NULL;
795 /* qbuffer */
796 /* qbuffer_data */
797 /* tcpmsg */
798 xfr->tcpmsg_valid = ISC_FALSE;
800 xfr->db = NULL;
801 if (db != NULL)
802 dns_db_attach(db, &xfr->db);
803 xfr->ver = NULL;
804 dns_diff_init(xfr->mctx, &xfr->diff);
805 xfr->difflen = 0;
807 if (reqtype == dns_rdatatype_soa)
808 xfr->state = XFRST_SOAQUERY;
809 else
810 xfr->state = XFRST_INITIALSOA;
811 /* end_serial */
813 xfr->nmsg = 0;
814 xfr->nrecs = 0;
815 xfr->nbytes = 0;
816 isc_time_now(&xfr->start);
818 xfr->tsigkey = NULL;
819 if (tsigkey != NULL)
820 dns_tsigkey_attach(tsigkey, &xfr->tsigkey);
821 xfr->lasttsig = NULL;
822 xfr->tsigctx = NULL;
823 xfr->sincetsig = 0;
824 xfr->is_ixfr = ISC_FALSE;
826 /* ixfr.request_serial */
827 /* ixfr.current_serial */
828 xfr->ixfr.journal = NULL;
830 xfr->axfr.add_func = NULL;
831 xfr->axfr.add_private = NULL;
833 CHECK(dns_name_dup(zonename, mctx, &xfr->name));
835 CHECK(isc_timer_create(timermgr, isc_timertype_inactive, NULL, NULL,
836 task, xfrin_timeout, xfr, &xfr->timer));
837 CHECK(dns_timer_setidle(xfr->timer,
838 dns_zone_getmaxxfrin(xfr->zone),
839 dns_zone_getidlein(xfr->zone),
840 ISC_FALSE));
842 xfr->masteraddr = *masteraddr;
844 INSIST(isc_sockaddr_pf(masteraddr) == isc_sockaddr_pf(sourceaddr));
845 xfr->sourceaddr = *sourceaddr;
846 isc_sockaddr_setport(&xfr->sourceaddr, 0);
848 isc_buffer_init(&xfr->qbuffer, xfr->qbuffer_data,
849 sizeof(xfr->qbuffer_data));
851 xfr->magic = XFRIN_MAGIC;
852 *xfrp = xfr;
853 return (ISC_R_SUCCESS);
855 failure:
856 if (xfr->timer != NULL)
857 isc_timer_detach(&xfr->timer);
858 if (dns_name_dynamic(&xfr->name))
859 dns_name_free(&xfr->name, xfr->mctx);
860 if (xfr->tsigkey != NULL)
861 dns_tsigkey_detach(&xfr->tsigkey);
862 if (xfr->db != NULL)
863 dns_db_detach(&xfr->db);
864 isc_task_detach(&xfr->task);
865 dns_zone_idetach(&xfr->zone);
866 isc_mem_put(mctx, xfr, sizeof(*xfr));
868 return (result);
871 static isc_result_t
872 xfrin_start(dns_xfrin_ctx_t *xfr) {
873 isc_result_t result;
874 CHECK(isc_socket_create(xfr->socketmgr,
875 isc_sockaddr_pf(&xfr->sourceaddr),
876 isc_sockettype_tcp,
877 &xfr->socket));
878 isc_socket_setname(xfr->socket, "xfrin", NULL);
879 #ifndef BROKEN_TCP_BIND_BEFORE_CONNECT
880 CHECK(isc_socket_bind(xfr->socket, &xfr->sourceaddr,
881 ISC_SOCKET_REUSEADDRESS));
882 #endif
883 CHECK(isc_socket_connect(xfr->socket, &xfr->masteraddr, xfr->task,
884 xfrin_connect_done, xfr));
885 xfr->connects++;
886 return (ISC_R_SUCCESS);
887 failure:
888 xfrin_fail(xfr, result, "failed setting up socket");
889 return (result);
892 /* XXX the resolver could use this, too */
894 static isc_result_t
895 render(dns_message_t *msg, isc_mem_t *mctx, isc_buffer_t *buf) {
896 dns_compress_t cctx;
897 isc_boolean_t cleanup_cctx = ISC_FALSE;
898 isc_result_t result;
900 CHECK(dns_compress_init(&cctx, -1, mctx));
901 cleanup_cctx = ISC_TRUE;
902 CHECK(dns_message_renderbegin(msg, &cctx, buf));
903 CHECK(dns_message_rendersection(msg, DNS_SECTION_QUESTION, 0));
904 CHECK(dns_message_rendersection(msg, DNS_SECTION_ANSWER, 0));
905 CHECK(dns_message_rendersection(msg, DNS_SECTION_AUTHORITY, 0));
906 CHECK(dns_message_rendersection(msg, DNS_SECTION_ADDITIONAL, 0));
907 CHECK(dns_message_renderend(msg));
908 result = ISC_R_SUCCESS;
909 failure:
910 if (cleanup_cctx)
911 dns_compress_invalidate(&cctx);
912 return (result);
916 * A connection has been established.
918 static void
919 xfrin_connect_done(isc_task_t *task, isc_event_t *event) {
920 isc_socket_connev_t *cev = (isc_socket_connev_t *) event;
921 dns_xfrin_ctx_t *xfr = (dns_xfrin_ctx_t *) event->ev_arg;
922 isc_result_t result = cev->result;
923 char sourcetext[ISC_SOCKADDR_FORMATSIZE];
924 isc_sockaddr_t sockaddr;
926 REQUIRE(VALID_XFRIN(xfr));
928 UNUSED(task);
930 INSIST(event->ev_type == ISC_SOCKEVENT_CONNECT);
931 isc_event_free(&event);
933 xfr->connects--;
934 if (xfr->shuttingdown) {
935 maybe_free(xfr);
936 return;
939 if (result != ISC_R_SUCCESS) {
940 dns_zonemgr_t * zmgr = dns_zone_getmgr(xfr->zone);
941 isc_time_t now;
943 if (zmgr != NULL) {
944 TIME_NOW(&now);
945 dns_zonemgr_unreachableadd(zmgr, &xfr->masteraddr,
946 &xfr->sourceaddr, &now);
948 goto failure;
951 result = isc_socket_getsockname(xfr->socket, &sockaddr);
952 if (result == ISC_R_SUCCESS) {
953 isc_sockaddr_format(&sockaddr, sourcetext, sizeof(sourcetext));
954 } else
955 strcpy(sourcetext, "<UNKNOWN>");
956 xfrin_log(xfr, ISC_LOG_INFO, "connected using %s", sourcetext);
958 dns_tcpmsg_init(xfr->mctx, xfr->socket, &xfr->tcpmsg);
959 xfr->tcpmsg_valid = ISC_TRUE;
961 CHECK(xfrin_send_request(xfr));
962 failure:
963 if (result != ISC_R_SUCCESS)
964 xfrin_fail(xfr, result, "failed to connect");
968 * Convert a tuple into a dns_name_t suitable for inserting
969 * into the given dns_message_t.
971 static isc_result_t
972 tuple2msgname(dns_difftuple_t *tuple, dns_message_t *msg, dns_name_t **target)
974 isc_result_t result;
975 dns_rdata_t *rdata = NULL;
976 dns_rdatalist_t *rdl = NULL;
977 dns_rdataset_t *rds = NULL;
978 dns_name_t *name = NULL;
980 REQUIRE(target != NULL && *target == NULL);
982 CHECK(dns_message_gettemprdata(msg, &rdata));
983 dns_rdata_init(rdata);
984 dns_rdata_clone(&tuple->rdata, rdata);
986 CHECK(dns_message_gettemprdatalist(msg, &rdl));
987 dns_rdatalist_init(rdl);
988 rdl->type = tuple->rdata.type;
989 rdl->rdclass = tuple->rdata.rdclass;
990 rdl->ttl = tuple->ttl;
991 ISC_LIST_APPEND(rdl->rdata, rdata, link);
993 CHECK(dns_message_gettemprdataset(msg, &rds));
994 dns_rdataset_init(rds);
995 CHECK(dns_rdatalist_tordataset(rdl, rds));
997 CHECK(dns_message_gettempname(msg, &name));
998 dns_name_init(name, NULL);
999 dns_name_clone(&tuple->name, name);
1000 ISC_LIST_APPEND(name->list, rds, link);
1002 *target = name;
1003 return (ISC_R_SUCCESS);
1005 failure:
1007 if (rds != NULL) {
1008 dns_rdataset_disassociate(rds);
1009 dns_message_puttemprdataset(msg, &rds);
1011 if (rdl != NULL) {
1012 ISC_LIST_UNLINK(rdl->rdata, rdata, link);
1013 dns_message_puttemprdatalist(msg, &rdl);
1015 if (rdata != NULL)
1016 dns_message_puttemprdata(msg, &rdata);
1018 return (result);
1023 * Build an *XFR request and send its length prefix.
1025 static isc_result_t
1026 xfrin_send_request(dns_xfrin_ctx_t *xfr) {
1027 isc_result_t result;
1028 isc_region_t region;
1029 isc_region_t lregion;
1030 dns_rdataset_t *qrdataset = NULL;
1031 dns_message_t *msg = NULL;
1032 unsigned char length[2];
1033 dns_difftuple_t *soatuple = NULL;
1034 dns_name_t *qname = NULL;
1035 dns_dbversion_t *ver = NULL;
1036 dns_name_t *msgsoaname = NULL;
1038 /* Create the request message */
1039 CHECK(dns_message_create(xfr->mctx, DNS_MESSAGE_INTENTRENDER, &msg));
1040 CHECK(dns_message_settsigkey(msg, xfr->tsigkey));
1042 /* Create a name for the question section. */
1043 CHECK(dns_message_gettempname(msg, &qname));
1044 dns_name_init(qname, NULL);
1045 dns_name_clone(&xfr->name, qname);
1047 /* Formulate the question and attach it to the question name. */
1048 CHECK(dns_message_gettemprdataset(msg, &qrdataset));
1049 dns_rdataset_init(qrdataset);
1050 dns_rdataset_makequestion(qrdataset, xfr->rdclass, xfr->reqtype);
1051 ISC_LIST_APPEND(qname->list, qrdataset, link);
1052 qrdataset = NULL;
1054 dns_message_addname(msg, qname, DNS_SECTION_QUESTION);
1055 qname = NULL;
1057 if (xfr->reqtype == dns_rdatatype_ixfr) {
1058 /* Get the SOA and add it to the authority section. */
1059 /* XXX is using the current version the right thing? */
1060 dns_db_currentversion(xfr->db, &ver);
1061 CHECK(dns_db_createsoatuple(xfr->db, ver, xfr->mctx,
1062 DNS_DIFFOP_EXISTS, &soatuple));
1063 xfr->ixfr.request_serial = dns_soa_getserial(&soatuple->rdata);
1064 xfr->ixfr.current_serial = xfr->ixfr.request_serial;
1065 xfrin_log(xfr, ISC_LOG_DEBUG(3),
1066 "requesting IXFR for serial %u",
1067 xfr->ixfr.request_serial);
1069 CHECK(tuple2msgname(soatuple, msg, &msgsoaname));
1070 dns_message_addname(msg, msgsoaname, DNS_SECTION_AUTHORITY);
1071 } else if (xfr->reqtype == dns_rdatatype_soa)
1072 CHECK(dns_db_getsoaserial(xfr->db, NULL,
1073 &xfr->ixfr.request_serial));
1075 xfr->checkid = ISC_TRUE;
1076 xfr->id++;
1077 xfr->nmsg = 0;
1078 xfr->nrecs = 0;
1079 xfr->nbytes = 0;
1080 isc_time_now(&xfr->start);
1081 msg->id = xfr->id;
1082 if (xfr->tsigctx != NULL)
1083 dst_context_destroy(&xfr->tsigctx);
1085 CHECK(render(msg, xfr->mctx, &xfr->qbuffer));
1088 * Free the last tsig, if there is one.
1090 if (xfr->lasttsig != NULL)
1091 isc_buffer_free(&xfr->lasttsig);
1094 * Save the query TSIG and don't let message_destroy free it.
1096 CHECK(dns_message_getquerytsig(msg, xfr->mctx, &xfr->lasttsig));
1098 isc_buffer_usedregion(&xfr->qbuffer, &region);
1099 INSIST(region.length <= 65535);
1101 length[0] = region.length >> 8;
1102 length[1] = region.length & 0xFF;
1103 lregion.base = length;
1104 lregion.length = 2;
1105 CHECK(isc_socket_send(xfr->socket, &lregion, xfr->task,
1106 xfrin_sendlen_done, xfr));
1107 xfr->sends++;
1109 failure:
1110 if (qname != NULL)
1111 dns_message_puttempname(msg, &qname);
1112 if (qrdataset != NULL)
1113 dns_message_puttemprdataset(msg, &qrdataset);
1114 if (msg != NULL)
1115 dns_message_destroy(&msg);
1116 if (soatuple != NULL)
1117 dns_difftuple_free(&soatuple);
1118 if (ver != NULL)
1119 dns_db_closeversion(xfr->db, &ver, ISC_FALSE);
1120 return (result);
1123 /* XXX there should be library support for sending DNS TCP messages */
1125 static void
1126 xfrin_sendlen_done(isc_task_t *task, isc_event_t *event) {
1127 isc_socketevent_t *sev = (isc_socketevent_t *) event;
1128 dns_xfrin_ctx_t *xfr = (dns_xfrin_ctx_t *) event->ev_arg;
1129 isc_result_t evresult = sev->result;
1130 isc_result_t result;
1131 isc_region_t region;
1133 REQUIRE(VALID_XFRIN(xfr));
1135 UNUSED(task);
1137 INSIST(event->ev_type == ISC_SOCKEVENT_SENDDONE);
1138 isc_event_free(&event);
1140 xfr->sends--;
1141 if (xfr->shuttingdown) {
1142 maybe_free(xfr);
1143 return;
1146 xfrin_log(xfr, ISC_LOG_DEBUG(3), "sent request length prefix");
1147 CHECK(evresult);
1149 isc_buffer_usedregion(&xfr->qbuffer, &region);
1150 CHECK(isc_socket_send(xfr->socket, &region, xfr->task,
1151 xfrin_send_done, xfr));
1152 xfr->sends++;
1153 failure:
1154 if (result != ISC_R_SUCCESS)
1155 xfrin_fail(xfr, result, "failed sending request length prefix");
1159 static void
1160 xfrin_send_done(isc_task_t *task, isc_event_t *event) {
1161 isc_socketevent_t *sev = (isc_socketevent_t *) event;
1162 dns_xfrin_ctx_t *xfr = (dns_xfrin_ctx_t *) event->ev_arg;
1163 isc_result_t result;
1165 REQUIRE(VALID_XFRIN(xfr));
1167 UNUSED(task);
1169 INSIST(event->ev_type == ISC_SOCKEVENT_SENDDONE);
1171 xfr->sends--;
1172 xfrin_log(xfr, ISC_LOG_DEBUG(3), "sent request data");
1173 CHECK(sev->result);
1175 CHECK(dns_tcpmsg_readmessage(&xfr->tcpmsg, xfr->task,
1176 xfrin_recv_done, xfr));
1177 xfr->recvs++;
1178 failure:
1179 isc_event_free(&event);
1180 if (result != ISC_R_SUCCESS)
1181 xfrin_fail(xfr, result, "failed sending request data");
1185 static void
1186 xfrin_recv_done(isc_task_t *task, isc_event_t *ev) {
1187 dns_xfrin_ctx_t *xfr = (dns_xfrin_ctx_t *) ev->ev_arg;
1188 isc_result_t result;
1189 dns_message_t *msg = NULL;
1190 dns_name_t *name;
1191 dns_tcpmsg_t *tcpmsg;
1192 dns_name_t *tsigowner = NULL;
1194 REQUIRE(VALID_XFRIN(xfr));
1196 UNUSED(task);
1198 INSIST(ev->ev_type == DNS_EVENT_TCPMSG);
1199 tcpmsg = ev->ev_sender;
1200 isc_event_free(&ev);
1202 xfr->recvs--;
1203 if (xfr->shuttingdown) {
1204 maybe_free(xfr);
1205 return;
1208 CHECK(tcpmsg->result);
1210 xfrin_log(xfr, ISC_LOG_DEBUG(7), "received %u bytes",
1211 tcpmsg->buffer.used);
1213 CHECK(isc_timer_touch(xfr->timer));
1215 CHECK(dns_message_create(xfr->mctx, DNS_MESSAGE_INTENTPARSE, &msg));
1217 CHECK(dns_message_settsigkey(msg, xfr->tsigkey));
1218 CHECK(dns_message_setquerytsig(msg, xfr->lasttsig));
1220 msg->tsigctx = xfr->tsigctx;
1221 xfr->tsigctx = NULL;
1223 if (xfr->nmsg > 0)
1224 msg->tcp_continuation = 1;
1226 result = dns_message_parse(msg, &tcpmsg->buffer,
1227 DNS_MESSAGEPARSE_PRESERVEORDER);
1229 if (result != ISC_R_SUCCESS || msg->rcode != dns_rcode_noerror ||
1230 (xfr->checkid && msg->id != xfr->id)) {
1231 if (result == ISC_R_SUCCESS)
1232 result = ISC_RESULTCLASS_DNSRCODE + msg->rcode; /*XXX*/
1233 if (result == ISC_R_SUCCESS || result == DNS_R_NOERROR)
1234 result = DNS_R_UNEXPECTEDID;
1235 if (xfr->reqtype == dns_rdatatype_axfr ||
1236 xfr->reqtype == dns_rdatatype_soa)
1237 FAIL(result);
1238 xfrin_log(xfr, ISC_LOG_DEBUG(3), "got %s, retrying with AXFR",
1239 isc_result_totext(result));
1240 try_axfr:
1241 dns_message_destroy(&msg);
1242 xfrin_reset(xfr);
1243 xfr->reqtype = dns_rdatatype_soa;
1244 xfr->state = XFRST_SOAQUERY;
1245 (void)xfrin_start(xfr);
1246 return;
1250 * Does the server know about IXFR? If it doesn't we will get
1251 * a message with a empty answer section or a potentially a CNAME /
1252 * DNAME, the later is handled by xfr_rr() which will return FORMERR
1253 * if the first RR in the answer section is not a SOA record.
1255 if (xfr->reqtype == dns_rdatatype_ixfr &&
1256 xfr->state == XFRST_INITIALSOA &&
1257 msg->counts[DNS_SECTION_ANSWER] == 0) {
1258 xfrin_log(xfr, ISC_LOG_DEBUG(3),
1259 "empty answer section, retrying with AXFR");
1260 goto try_axfr;
1263 if (xfr->reqtype == dns_rdatatype_soa &&
1264 (msg->flags & DNS_MESSAGEFLAG_AA) == 0) {
1265 FAIL(DNS_R_NOTAUTHORITATIVE);
1269 result = dns_message_checksig(msg, dns_zone_getview(xfr->zone));
1270 if (result != ISC_R_SUCCESS) {
1271 xfrin_log(xfr, ISC_LOG_DEBUG(3), "TSIG check failed: %s",
1272 isc_result_totext(result));
1273 FAIL(result);
1276 for (result = dns_message_firstname(msg, DNS_SECTION_ANSWER);
1277 result == ISC_R_SUCCESS;
1278 result = dns_message_nextname(msg, DNS_SECTION_ANSWER))
1280 dns_rdataset_t *rds;
1282 name = NULL;
1283 dns_message_currentname(msg, DNS_SECTION_ANSWER, &name);
1284 for (rds = ISC_LIST_HEAD(name->list);
1285 rds != NULL;
1286 rds = ISC_LIST_NEXT(rds, link))
1288 for (result = dns_rdataset_first(rds);
1289 result == ISC_R_SUCCESS;
1290 result = dns_rdataset_next(rds))
1292 dns_rdata_t rdata = DNS_RDATA_INIT;
1293 dns_rdataset_current(rds, &rdata);
1294 CHECK(xfr_rr(xfr, name, rds->ttl, &rdata));
1298 if (result != ISC_R_NOMORE)
1299 goto failure;
1301 if (dns_message_gettsig(msg, &tsigowner) != NULL) {
1303 * Reset the counter.
1305 xfr->sincetsig = 0;
1308 * Free the last tsig, if there is one.
1310 if (xfr->lasttsig != NULL)
1311 isc_buffer_free(&xfr->lasttsig);
1314 * Update the last tsig pointer.
1316 CHECK(dns_message_getquerytsig(msg, xfr->mctx,
1317 &xfr->lasttsig));
1319 } else if (dns_message_gettsigkey(msg) != NULL) {
1320 xfr->sincetsig++;
1321 if (xfr->sincetsig > 100 ||
1322 xfr->nmsg == 0 || xfr->state == XFRST_END)
1324 result = DNS_R_EXPECTEDTSIG;
1325 goto failure;
1330 * Update the number of messages received.
1332 xfr->nmsg++;
1335 * Update the number of bytes received.
1337 xfr->nbytes += tcpmsg->buffer.used;
1340 * Take the context back.
1342 INSIST(xfr->tsigctx == NULL);
1343 xfr->tsigctx = msg->tsigctx;
1344 msg->tsigctx = NULL;
1346 dns_message_destroy(&msg);
1348 if (xfr->state == XFRST_GOTSOA) {
1349 xfr->reqtype = dns_rdatatype_axfr;
1350 xfr->state = XFRST_INITIALSOA;
1351 CHECK(xfrin_send_request(xfr));
1352 } else if (xfr->state == XFRST_END) {
1354 * Close the journal.
1356 if (xfr->ixfr.journal != NULL)
1357 dns_journal_destroy(&xfr->ixfr.journal);
1359 * Inform the caller we succeeded.
1361 if (xfr->done != NULL) {
1362 (xfr->done)(xfr->zone, ISC_R_SUCCESS);
1363 xfr->done = NULL;
1366 * We should have no outstanding events at this
1367 * point, thus maybe_free() should succeed.
1369 xfr->shuttingdown = ISC_TRUE;
1370 maybe_free(xfr);
1371 } else {
1373 * Read the next message.
1375 CHECK(dns_tcpmsg_readmessage(&xfr->tcpmsg, xfr->task,
1376 xfrin_recv_done, xfr));
1377 xfr->recvs++;
1379 return;
1381 failure:
1382 if (msg != NULL)
1383 dns_message_destroy(&msg);
1384 if (result != ISC_R_SUCCESS)
1385 xfrin_fail(xfr, result, "failed while receiving responses");
1388 static void
1389 xfrin_timeout(isc_task_t *task, isc_event_t *event) {
1390 dns_xfrin_ctx_t *xfr = (dns_xfrin_ctx_t *) event->ev_arg;
1392 REQUIRE(VALID_XFRIN(xfr));
1394 UNUSED(task);
1396 isc_event_free(&event);
1398 * This will log "giving up: timeout".
1400 xfrin_fail(xfr, ISC_R_TIMEDOUT, "giving up");
1403 static void
1404 maybe_free(dns_xfrin_ctx_t *xfr) {
1405 isc_uint64_t msecs;
1406 isc_uint64_t persec;
1408 REQUIRE(VALID_XFRIN(xfr));
1410 if (! xfr->shuttingdown || xfr->refcount != 0 ||
1411 xfr->connects != 0 || xfr->sends != 0 ||
1412 xfr->recvs != 0)
1413 return;
1416 * Calculate the length of time the transfer took,
1417 * and print a log message with the bytes and rate.
1419 isc_time_now(&xfr->end);
1420 msecs = isc_time_microdiff(&xfr->end, &xfr->start) / 1000;
1421 if (msecs == 0)
1422 msecs = 1;
1423 persec = (xfr->nbytes * 1000) / msecs;
1424 xfrin_log(xfr, ISC_LOG_INFO,
1425 "Transfer completed: %d messages, %d records, "
1426 "%" ISC_PRINT_QUADFORMAT "u bytes, "
1427 "%u.%03u secs (%u bytes/sec)",
1428 xfr->nmsg, xfr->nrecs, xfr->nbytes,
1429 (unsigned int) (msecs / 1000), (unsigned int) (msecs % 1000),
1430 (unsigned int) persec);
1432 if (xfr->socket != NULL)
1433 isc_socket_detach(&xfr->socket);
1435 if (xfr->timer != NULL)
1436 isc_timer_detach(&xfr->timer);
1438 if (xfr->task != NULL)
1439 isc_task_detach(&xfr->task);
1441 if (xfr->tsigkey != NULL)
1442 dns_tsigkey_detach(&xfr->tsigkey);
1444 if (xfr->lasttsig != NULL)
1445 isc_buffer_free(&xfr->lasttsig);
1447 dns_diff_clear(&xfr->diff);
1449 if (xfr->ixfr.journal != NULL)
1450 dns_journal_destroy(&xfr->ixfr.journal);
1452 if (xfr->axfr.add_private != NULL)
1453 (void)dns_db_endload(xfr->db, &xfr->axfr.add_private);
1455 if (xfr->tcpmsg_valid)
1456 dns_tcpmsg_invalidate(&xfr->tcpmsg);
1458 if (xfr->tsigctx != NULL)
1459 dst_context_destroy(&xfr->tsigctx);
1461 if ((xfr->name.attributes & DNS_NAMEATTR_DYNAMIC) != 0)
1462 dns_name_free(&xfr->name, xfr->mctx);
1464 if (xfr->ver != NULL)
1465 dns_db_closeversion(xfr->db, &xfr->ver, ISC_FALSE);
1467 if (xfr->db != NULL)
1468 dns_db_detach(&xfr->db);
1470 if (xfr->zone != NULL)
1471 dns_zone_idetach(&xfr->zone);
1473 isc_mem_put(xfr->mctx, xfr, sizeof(*xfr));
1477 * Log incoming zone transfer messages in a format like
1478 * transfer of <zone> from <address>: <message>
1480 static void
1481 xfrin_logv(int level, const char *zonetext, isc_sockaddr_t *masteraddr,
1482 const char *fmt, va_list ap)
1484 char mastertext[ISC_SOCKADDR_FORMATSIZE];
1485 char msgtext[2048];
1487 isc_sockaddr_format(masteraddr, mastertext, sizeof(mastertext));
1488 vsnprintf(msgtext, sizeof(msgtext), fmt, ap);
1490 isc_log_write(dns_lctx, DNS_LOGCATEGORY_XFER_IN,
1491 DNS_LOGMODULE_XFER_IN, level,
1492 "transfer of '%s' from %s: %s",
1493 zonetext, mastertext, msgtext);
1497 * Logging function for use when a xfrin_ctx_t has not yet been created.
1500 static void
1501 xfrin_log1(int level, const char *zonetext, isc_sockaddr_t *masteraddr,
1502 const char *fmt, ...)
1504 va_list ap;
1506 if (isc_log_wouldlog(dns_lctx, level) == ISC_FALSE)
1507 return;
1509 va_start(ap, fmt);
1510 xfrin_logv(level, zonetext, masteraddr, fmt, ap);
1511 va_end(ap);
1515 * Logging function for use when there is a xfrin_ctx_t.
1518 static void
1519 xfrin_log(dns_xfrin_ctx_t *xfr, int level, const char *fmt, ...)
1521 va_list ap;
1522 char zonetext[DNS_NAME_MAXTEXT+32];
1524 if (isc_log_wouldlog(dns_lctx, level) == ISC_FALSE)
1525 return;
1527 dns_zone_name(xfr->zone, zonetext, sizeof(zonetext));
1529 va_start(ap, fmt);
1530 xfrin_logv(level, zonetext, &xfr->masteraddr, fmt, ap);
1531 va_end(ap);