1135446Strhodes/* 2254402Serwin * Copyright (C) 2004-2008, 2011-2013 Internet Systems Consortium, Inc. ("ISC") 3135446Strhodes * Copyright (C) 1999-2003 Internet Software Consortium. 4135446Strhodes * 5174187Sdougb * Permission to use, copy, modify, and/or distribute this software for any 6135446Strhodes * purpose with or without fee is hereby granted, provided that the above 7135446Strhodes * copyright notice and this permission notice appear in all copies. 8135446Strhodes * 9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11135446Strhodes * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15135446Strhodes * PERFORMANCE OF THIS SOFTWARE. 16135446Strhodes */ 17135446Strhodes 18234010Sdougb/* $Id$ */ 19135446Strhodes 20170222Sdougb/*! \file */ 21170222Sdougb 22135446Strhodes#include <config.h> 23135446Strhodes 24135446Strhodes#include <isc/mem.h> 25135446Strhodes#include <isc/print.h> 26135446Strhodes#include <isc/random.h> 27135446Strhodes#include <isc/string.h> /* Required for HP/UX (and others?) */ 28135446Strhodes#include <isc/task.h> 29135446Strhodes#include <isc/timer.h> 30135446Strhodes#include <isc/util.h> 31135446Strhodes 32135446Strhodes#include <dns/db.h> 33135446Strhodes#include <dns/diff.h> 34135446Strhodes#include <dns/events.h> 35135446Strhodes#include <dns/journal.h> 36135446Strhodes#include <dns/log.h> 37135446Strhodes#include <dns/message.h> 38135446Strhodes#include <dns/rdataclass.h> 39135446Strhodes#include <dns/rdatalist.h> 40135446Strhodes#include <dns/rdataset.h> 41135446Strhodes#include <dns/result.h> 42135446Strhodes#include <dns/soa.h> 43135446Strhodes#include <dns/tcpmsg.h> 44135446Strhodes#include <dns/timer.h> 45135446Strhodes#include <dns/tsig.h> 46135446Strhodes#include <dns/view.h> 47135446Strhodes#include <dns/xfrin.h> 48135446Strhodes#include <dns/zone.h> 49135446Strhodes 50135446Strhodes#include <dst/dst.h> 51135446Strhodes 52135446Strhodes/* 53135446Strhodes * Incoming AXFR and IXFR. 54135446Strhodes */ 55135446Strhodes 56170222Sdougb/*% 57135446Strhodes * It would be non-sensical (or at least obtuse) to use FAIL() with an 58135446Strhodes * ISC_R_SUCCESS code, but the test is there to keep the Solaris compiler 59135446Strhodes * from complaining about "end-of-loop code not reached". 60135446Strhodes */ 61135446Strhodes#define FAIL(code) \ 62135446Strhodes do { result = (code); \ 63135446Strhodes if (result != ISC_R_SUCCESS) goto failure; \ 64135446Strhodes } while (0) 65135446Strhodes 66135446Strhodes#define CHECK(op) \ 67135446Strhodes do { result = (op); \ 68135446Strhodes if (result != ISC_R_SUCCESS) goto failure; \ 69135446Strhodes } while (0) 70135446Strhodes 71170222Sdougb/*% 72135446Strhodes * The states of the *XFR state machine. We handle both IXFR and AXFR 73135446Strhodes * with a single integrated state machine because they cannot be distinguished 74135446Strhodes * immediately - an AXFR response to an IXFR request can only be detected 75135446Strhodes * when the first two (2) response RRs have already been received. 76135446Strhodes */ 77135446Strhodestypedef enum { 78165071Sdougb XFRST_SOAQUERY, 79165071Sdougb XFRST_GOTSOA, 80135446Strhodes XFRST_INITIALSOA, 81135446Strhodes XFRST_FIRSTDATA, 82135446Strhodes XFRST_IXFR_DELSOA, 83135446Strhodes XFRST_IXFR_DEL, 84135446Strhodes XFRST_IXFR_ADDSOA, 85135446Strhodes XFRST_IXFR_ADD, 86224092Sdougb XFRST_IXFR_END, 87135446Strhodes XFRST_AXFR, 88224092Sdougb XFRST_AXFR_END 89135446Strhodes} xfrin_state_t; 90135446Strhodes 91170222Sdougb/*% 92135446Strhodes * Incoming zone transfer context. 93135446Strhodes */ 94135446Strhodes 95135446Strhodesstruct dns_xfrin_ctx { 96135446Strhodes unsigned int magic; 97135446Strhodes isc_mem_t *mctx; 98135446Strhodes dns_zone_t *zone; 99135446Strhodes 100135446Strhodes int refcount; 101135446Strhodes 102135446Strhodes isc_task_t *task; 103135446Strhodes isc_timer_t *timer; 104135446Strhodes isc_socketmgr_t *socketmgr; 105135446Strhodes 106170222Sdougb int connects; /*%< Connect in progress */ 107170222Sdougb int sends; /*%< Send in progress */ 108170222Sdougb int recvs; /*%< Receive in progress */ 109135446Strhodes isc_boolean_t shuttingdown; 110135446Strhodes 111170222Sdougb dns_name_t name; /*%< Name of zone to transfer */ 112135446Strhodes dns_rdataclass_t rdclass; 113135446Strhodes 114135446Strhodes isc_boolean_t checkid; 115135446Strhodes dns_messageid_t id; 116135446Strhodes 117170222Sdougb /*% 118135446Strhodes * Requested transfer type (dns_rdatatype_axfr or 119135446Strhodes * dns_rdatatype_ixfr). The actual transfer type 120135446Strhodes * may differ due to IXFR->AXFR fallback. 121135446Strhodes */ 122135446Strhodes dns_rdatatype_t reqtype; 123135446Strhodes 124135446Strhodes isc_sockaddr_t masteraddr; 125135446Strhodes isc_sockaddr_t sourceaddr; 126135446Strhodes isc_socket_t *socket; 127135446Strhodes 128170222Sdougb /*% Buffer for IXFR/AXFR request message */ 129135446Strhodes isc_buffer_t qbuffer; 130135446Strhodes unsigned char qbuffer_data[512]; 131135446Strhodes 132170222Sdougb /*% Incoming reply TCP message */ 133135446Strhodes dns_tcpmsg_t tcpmsg; 134135446Strhodes isc_boolean_t tcpmsg_valid; 135135446Strhodes 136135446Strhodes dns_db_t *db; 137135446Strhodes dns_dbversion_t *ver; 138170222Sdougb dns_diff_t diff; /*%< Pending database changes */ 139170222Sdougb int difflen; /*%< Number of pending tuples */ 140135446Strhodes 141135446Strhodes xfrin_state_t state; 142135446Strhodes isc_uint32_t end_serial; 143135446Strhodes isc_boolean_t is_ixfr; 144135446Strhodes 145170222Sdougb unsigned int nmsg; /*%< Number of messages recvd */ 146193149Sdougb unsigned int nrecs; /*%< Number of records recvd */ 147193149Sdougb isc_uint64_t nbytes; /*%< Number of bytes received */ 148135446Strhodes 149193149Sdougb isc_time_t start; /*%< Start time of the transfer */ 150193149Sdougb isc_time_t end; /*%< End time of the transfer */ 151193149Sdougb 152170222Sdougb dns_tsigkey_t *tsigkey; /*%< Key used to create TSIG */ 153170222Sdougb isc_buffer_t *lasttsig; /*%< The last TSIG */ 154170222Sdougb dst_context_t *tsigctx; /*%< TSIG verification context */ 155170222Sdougb unsigned int sincetsig; /*%< recvd since the last TSIG */ 156135446Strhodes dns_xfrindone_t done; 157135446Strhodes 158170222Sdougb /*% 159135446Strhodes * AXFR- and IXFR-specific data. Only one is used at a time 160135446Strhodes * according to the is_ixfr flag, so this could be a union, 161135446Strhodes * but keeping them separate makes it a bit simpler to clean 162135446Strhodes * things up when destroying the context. 163135446Strhodes */ 164135446Strhodes struct { 165135446Strhodes dns_addrdatasetfunc_t add_func; 166135446Strhodes dns_dbload_t *add_private; 167135446Strhodes } axfr; 168135446Strhodes 169135446Strhodes struct { 170135446Strhodes isc_uint32_t request_serial; 171135446Strhodes isc_uint32_t current_serial; 172135446Strhodes dns_journal_t *journal; 173135446Strhodes 174135446Strhodes } ixfr; 175135446Strhodes}; 176135446Strhodes 177135446Strhodes#define XFRIN_MAGIC ISC_MAGIC('X', 'f', 'r', 'I') 178135446Strhodes#define VALID_XFRIN(x) ISC_MAGIC_VALID(x, XFRIN_MAGIC) 179135446Strhodes 180135446Strhodes/**************************************************************************/ 181135446Strhodes/* 182135446Strhodes * Forward declarations. 183135446Strhodes */ 184135446Strhodes 185135446Strhodesstatic isc_result_t 186135446Strhodesxfrin_create(isc_mem_t *mctx, 187135446Strhodes dns_zone_t *zone, 188135446Strhodes dns_db_t *db, 189135446Strhodes isc_task_t *task, 190135446Strhodes isc_timermgr_t *timermgr, 191135446Strhodes isc_socketmgr_t *socketmgr, 192135446Strhodes dns_name_t *zonename, 193135446Strhodes dns_rdataclass_t rdclass, 194135446Strhodes dns_rdatatype_t reqtype, 195135446Strhodes isc_sockaddr_t *masteraddr, 196135446Strhodes isc_sockaddr_t *sourceaddr, 197135446Strhodes dns_tsigkey_t *tsigkey, 198135446Strhodes dns_xfrin_ctx_t **xfrp); 199135446Strhodes 200135446Strhodesstatic isc_result_t axfr_init(dns_xfrin_ctx_t *xfr); 201135446Strhodesstatic isc_result_t axfr_makedb(dns_xfrin_ctx_t *xfr, dns_db_t **dbp); 202135446Strhodesstatic isc_result_t axfr_putdata(dns_xfrin_ctx_t *xfr, dns_diffop_t op, 203135446Strhodes dns_name_t *name, dns_ttl_t ttl, 204135446Strhodes dns_rdata_t *rdata); 205135446Strhodesstatic isc_result_t axfr_apply(dns_xfrin_ctx_t *xfr); 206135446Strhodesstatic isc_result_t axfr_commit(dns_xfrin_ctx_t *xfr); 207224092Sdougbstatic isc_result_t axfr_finalize(dns_xfrin_ctx_t *xfr); 208135446Strhodes 209135446Strhodesstatic isc_result_t ixfr_init(dns_xfrin_ctx_t *xfr); 210135446Strhodesstatic isc_result_t ixfr_apply(dns_xfrin_ctx_t *xfr); 211135446Strhodesstatic isc_result_t ixfr_putdata(dns_xfrin_ctx_t *xfr, dns_diffop_t op, 212135446Strhodes dns_name_t *name, dns_ttl_t ttl, 213135446Strhodes dns_rdata_t *rdata); 214135446Strhodesstatic isc_result_t ixfr_commit(dns_xfrin_ctx_t *xfr); 215135446Strhodes 216135446Strhodesstatic isc_result_t xfr_rr(dns_xfrin_ctx_t *xfr, dns_name_t *name, 217135446Strhodes isc_uint32_t ttl, dns_rdata_t *rdata); 218135446Strhodes 219135446Strhodesstatic isc_result_t xfrin_start(dns_xfrin_ctx_t *xfr); 220135446Strhodes 221135446Strhodesstatic void xfrin_connect_done(isc_task_t *task, isc_event_t *event); 222135446Strhodesstatic isc_result_t xfrin_send_request(dns_xfrin_ctx_t *xfr); 223135446Strhodesstatic void xfrin_send_done(isc_task_t *task, isc_event_t *event); 224135446Strhodesstatic void xfrin_recv_done(isc_task_t *task, isc_event_t *event); 225135446Strhodesstatic void xfrin_timeout(isc_task_t *task, isc_event_t *event); 226135446Strhodes 227135446Strhodesstatic void maybe_free(dns_xfrin_ctx_t *xfr); 228135446Strhodes 229135446Strhodesstatic void 230135446Strhodesxfrin_fail(dns_xfrin_ctx_t *xfr, isc_result_t result, const char *msg); 231135446Strhodesstatic isc_result_t 232135446Strhodesrender(dns_message_t *msg, isc_mem_t *mctx, isc_buffer_t *buf); 233135446Strhodes 234135446Strhodesstatic void 235170222Sdougbxfrin_logv(int level, const char *zonetext, isc_sockaddr_t *masteraddr, 236170222Sdougb const char *fmt, va_list ap) 237170222Sdougb ISC_FORMAT_PRINTF(4, 0); 238135446Strhodes 239135446Strhodesstatic void 240170222Sdougbxfrin_log1(int level, const char *zonetext, isc_sockaddr_t *masteraddr, 241170222Sdougb const char *fmt, ...) 242170222Sdougb ISC_FORMAT_PRINTF(4, 5); 243135446Strhodes 244135446Strhodesstatic void 245153816Sdougbxfrin_log(dns_xfrin_ctx_t *xfr, int level, const char *fmt, ...) 246135446Strhodes ISC_FORMAT_PRINTF(3, 4); 247135446Strhodes 248135446Strhodes/**************************************************************************/ 249135446Strhodes/* 250135446Strhodes * AXFR handling 251135446Strhodes */ 252135446Strhodes 253135446Strhodesstatic isc_result_t 254135446Strhodesaxfr_init(dns_xfrin_ctx_t *xfr) { 255135446Strhodes isc_result_t result; 256135446Strhodes 257186462Sdougb xfr->is_ixfr = ISC_FALSE; 258135446Strhodes 259135446Strhodes if (xfr->db != NULL) 260135446Strhodes dns_db_detach(&xfr->db); 261135446Strhodes 262135446Strhodes CHECK(axfr_makedb(xfr, &xfr->db)); 263135446Strhodes CHECK(dns_db_beginload(xfr->db, &xfr->axfr.add_func, 264135446Strhodes &xfr->axfr.add_private)); 265135446Strhodes result = ISC_R_SUCCESS; 266135446Strhodes failure: 267135446Strhodes return (result); 268135446Strhodes} 269135446Strhodes 270135446Strhodesstatic isc_result_t 271135446Strhodesaxfr_makedb(dns_xfrin_ctx_t *xfr, dns_db_t **dbp) { 272262706Serwin isc_result_t result; 273262706Serwin 274262706Serwin result = dns_db_create(xfr->mctx, /* XXX */ 275262706Serwin "rbt", /* XXX guess */ 276262706Serwin &xfr->name, 277262706Serwin dns_dbtype_zone, 278262706Serwin xfr->rdclass, 279262706Serwin 0, NULL, /* XXX guess */ 280262706Serwin dbp); 281262706Serwin if (result == ISC_R_SUCCESS) 282262706Serwin result = dns_zone_rpz_enable_db(xfr->zone, *dbp); 283262706Serwin return (result); 284135446Strhodes} 285135446Strhodes 286135446Strhodesstatic isc_result_t 287135446Strhodesaxfr_putdata(dns_xfrin_ctx_t *xfr, dns_diffop_t op, 288135446Strhodes dns_name_t *name, dns_ttl_t ttl, dns_rdata_t *rdata) 289135446Strhodes{ 290135446Strhodes isc_result_t result; 291135446Strhodes 292135446Strhodes dns_difftuple_t *tuple = NULL; 293135446Strhodes 294135446Strhodes CHECK(dns_zone_checknames(xfr->zone, name, rdata)); 295135446Strhodes CHECK(dns_difftuple_create(xfr->diff.mctx, op, 296135446Strhodes name, ttl, rdata, &tuple)); 297135446Strhodes dns_diff_append(&xfr->diff, &tuple); 298135446Strhodes if (++xfr->difflen > 100) 299135446Strhodes CHECK(axfr_apply(xfr)); 300135446Strhodes result = ISC_R_SUCCESS; 301135446Strhodes failure: 302135446Strhodes return (result); 303135446Strhodes} 304135446Strhodes 305135446Strhodes/* 306135446Strhodes * Store a set of AXFR RRs in the database. 307135446Strhodes */ 308135446Strhodesstatic isc_result_t 309135446Strhodesaxfr_apply(dns_xfrin_ctx_t *xfr) { 310135446Strhodes isc_result_t result; 311135446Strhodes 312135446Strhodes CHECK(dns_diff_load(&xfr->diff, 313135446Strhodes xfr->axfr.add_func, xfr->axfr.add_private)); 314135446Strhodes xfr->difflen = 0; 315135446Strhodes dns_diff_clear(&xfr->diff); 316135446Strhodes result = ISC_R_SUCCESS; 317135446Strhodes failure: 318135446Strhodes return (result); 319135446Strhodes} 320135446Strhodes 321135446Strhodesstatic isc_result_t 322135446Strhodesaxfr_commit(dns_xfrin_ctx_t *xfr) { 323135446Strhodes isc_result_t result; 324135446Strhodes 325135446Strhodes CHECK(axfr_apply(xfr)); 326135446Strhodes CHECK(dns_db_endload(xfr->db, &xfr->axfr.add_private)); 327224092Sdougb 328224092Sdougb result = ISC_R_SUCCESS; 329224092Sdougb failure: 330224092Sdougb return (result); 331224092Sdougb} 332224092Sdougb 333224092Sdougbstatic isc_result_t 334224092Sdougbaxfr_finalize(dns_xfrin_ctx_t *xfr) { 335224092Sdougb isc_result_t result; 336224092Sdougb 337135446Strhodes CHECK(dns_zone_replacedb(xfr->zone, xfr->db, ISC_TRUE)); 338135446Strhodes 339135446Strhodes result = ISC_R_SUCCESS; 340135446Strhodes failure: 341135446Strhodes return (result); 342135446Strhodes} 343135446Strhodes 344135446Strhodes/**************************************************************************/ 345135446Strhodes/* 346135446Strhodes * IXFR handling 347135446Strhodes */ 348135446Strhodes 349135446Strhodesstatic isc_result_t 350135446Strhodesixfr_init(dns_xfrin_ctx_t *xfr) { 351135446Strhodes isc_result_t result; 352135446Strhodes char *journalfile; 353135446Strhodes 354135446Strhodes if (xfr->reqtype != dns_rdatatype_ixfr) { 355135446Strhodes xfrin_log(xfr, ISC_LOG_ERROR, 356135446Strhodes "got incremental response to AXFR request"); 357135446Strhodes return (DNS_R_FORMERR); 358135446Strhodes } 359135446Strhodes 360135446Strhodes xfr->is_ixfr = ISC_TRUE; 361135446Strhodes INSIST(xfr->db != NULL); 362135446Strhodes xfr->difflen = 0; 363135446Strhodes 364135446Strhodes journalfile = dns_zone_getjournal(xfr->zone); 365135446Strhodes if (journalfile != NULL) 366135446Strhodes CHECK(dns_journal_open(xfr->mctx, journalfile, 367254897Serwin DNS_JOURNAL_CREATE, &xfr->ixfr.journal)); 368135446Strhodes 369135446Strhodes result = ISC_R_SUCCESS; 370135446Strhodes failure: 371135446Strhodes return (result); 372135446Strhodes} 373135446Strhodes 374135446Strhodesstatic isc_result_t 375135446Strhodesixfr_putdata(dns_xfrin_ctx_t *xfr, dns_diffop_t op, 376135446Strhodes dns_name_t *name, dns_ttl_t ttl, dns_rdata_t *rdata) 377135446Strhodes{ 378135446Strhodes isc_result_t result; 379135446Strhodes 380135446Strhodes dns_difftuple_t *tuple = NULL; 381135446Strhodes if (op == DNS_DIFFOP_ADD) 382135446Strhodes CHECK(dns_zone_checknames(xfr->zone, name, rdata)); 383135446Strhodes CHECK(dns_difftuple_create(xfr->diff.mctx, op, 384135446Strhodes name, ttl, rdata, &tuple)); 385135446Strhodes dns_diff_append(&xfr->diff, &tuple); 386135446Strhodes if (++xfr->difflen > 100) 387135446Strhodes CHECK(ixfr_apply(xfr)); 388135446Strhodes result = ISC_R_SUCCESS; 389135446Strhodes failure: 390135446Strhodes return (result); 391135446Strhodes} 392135446Strhodes 393135446Strhodes/* 394135446Strhodes * Apply a set of IXFR changes to the database. 395135446Strhodes */ 396135446Strhodesstatic isc_result_t 397135446Strhodesixfr_apply(dns_xfrin_ctx_t *xfr) { 398135446Strhodes isc_result_t result; 399135446Strhodes 400135446Strhodes if (xfr->ver == NULL) { 401135446Strhodes CHECK(dns_db_newversion(xfr->db, &xfr->ver)); 402135446Strhodes if (xfr->ixfr.journal != NULL) 403135446Strhodes CHECK(dns_journal_begin_transaction(xfr->ixfr.journal)); 404135446Strhodes } 405135446Strhodes CHECK(dns_diff_apply(&xfr->diff, xfr->db, xfr->ver)); 406135446Strhodes if (xfr->ixfr.journal != NULL) { 407135446Strhodes result = dns_journal_writediff(xfr->ixfr.journal, &xfr->diff); 408135446Strhodes if (result != ISC_R_SUCCESS) 409135446Strhodes goto failure; 410135446Strhodes } 411135446Strhodes dns_diff_clear(&xfr->diff); 412135446Strhodes xfr->difflen = 0; 413135446Strhodes result = ISC_R_SUCCESS; 414135446Strhodes failure: 415135446Strhodes return (result); 416135446Strhodes} 417135446Strhodes 418135446Strhodesstatic isc_result_t 419135446Strhodesixfr_commit(dns_xfrin_ctx_t *xfr) { 420135446Strhodes isc_result_t result; 421135446Strhodes 422135446Strhodes CHECK(ixfr_apply(xfr)); 423135446Strhodes if (xfr->ver != NULL) { 424135446Strhodes /* XXX enter ready-to-commit state here */ 425135446Strhodes if (xfr->ixfr.journal != NULL) 426135446Strhodes CHECK(dns_journal_commit(xfr->ixfr.journal)); 427135446Strhodes dns_db_closeversion(xfr->db, &xfr->ver, ISC_TRUE); 428135446Strhodes dns_zone_markdirty(xfr->zone); 429135446Strhodes } 430135446Strhodes result = ISC_R_SUCCESS; 431135446Strhodes failure: 432135446Strhodes return (result); 433135446Strhodes} 434135446Strhodes 435135446Strhodes/**************************************************************************/ 436135446Strhodes/* 437135446Strhodes * Common AXFR/IXFR protocol code 438135446Strhodes */ 439135446Strhodes 440135446Strhodes/* 441135446Strhodes * Handle a single incoming resource record according to the current 442135446Strhodes * state. 443135446Strhodes */ 444135446Strhodesstatic isc_result_t 445135446Strhodesxfr_rr(dns_xfrin_ctx_t *xfr, dns_name_t *name, isc_uint32_t ttl, 446135446Strhodes dns_rdata_t *rdata) 447135446Strhodes{ 448135446Strhodes isc_result_t result; 449135446Strhodes 450193149Sdougb xfr->nrecs++; 451193149Sdougb 452186462Sdougb if (rdata->type == dns_rdatatype_none || 453186462Sdougb dns_rdatatype_ismeta(rdata->type)) 454186462Sdougb FAIL(DNS_R_FORMERR); 455186462Sdougb 456135446Strhodes redo: 457135446Strhodes switch (xfr->state) { 458165071Sdougb case XFRST_SOAQUERY: 459165071Sdougb if (rdata->type != dns_rdatatype_soa) { 460165071Sdougb xfrin_log(xfr, ISC_LOG_ERROR, 461165071Sdougb "non-SOA response to SOA query"); 462165071Sdougb FAIL(DNS_R_FORMERR); 463165071Sdougb } 464165071Sdougb xfr->end_serial = dns_soa_getserial(rdata); 465165071Sdougb if (!DNS_SERIAL_GT(xfr->end_serial, xfr->ixfr.request_serial) && 466165071Sdougb !dns_zone_isforced(xfr->zone)) { 467165071Sdougb xfrin_log(xfr, ISC_LOG_DEBUG(3), 468165071Sdougb "requested serial %u, " 469165071Sdougb "master has %u, not updating", 470165071Sdougb xfr->ixfr.request_serial, xfr->end_serial); 471165071Sdougb FAIL(DNS_R_UPTODATE); 472165071Sdougb } 473165071Sdougb xfr->state = XFRST_GOTSOA; 474165071Sdougb break; 475165071Sdougb 476165071Sdougb case XFRST_GOTSOA: 477165071Sdougb /* 478165071Sdougb * Skip other records in the answer section. 479165071Sdougb */ 480165071Sdougb break; 481165071Sdougb 482135446Strhodes case XFRST_INITIALSOA: 483135446Strhodes if (rdata->type != dns_rdatatype_soa) { 484135446Strhodes xfrin_log(xfr, ISC_LOG_ERROR, 485135446Strhodes "first RR in zone transfer must be SOA"); 486135446Strhodes FAIL(DNS_R_FORMERR); 487135446Strhodes } 488135446Strhodes /* 489170222Sdougb * Remember the serial number in the initial SOA. 490135446Strhodes * We need it to recognize the end of an IXFR. 491135446Strhodes */ 492135446Strhodes xfr->end_serial = dns_soa_getserial(rdata); 493135446Strhodes if (xfr->reqtype == dns_rdatatype_ixfr && 494135446Strhodes ! DNS_SERIAL_GT(xfr->end_serial, xfr->ixfr.request_serial) 495135446Strhodes && !dns_zone_isforced(xfr->zone)) 496135446Strhodes { 497135446Strhodes /* 498135446Strhodes * This must be the single SOA record that is 499135446Strhodes * sent when the current version on the master 500135446Strhodes * is not newer than the version in the request. 501135446Strhodes */ 502135446Strhodes xfrin_log(xfr, ISC_LOG_DEBUG(3), 503135446Strhodes "requested serial %u, " 504135446Strhodes "master has %u, not updating", 505135446Strhodes xfr->ixfr.request_serial, xfr->end_serial); 506135446Strhodes FAIL(DNS_R_UPTODATE); 507135446Strhodes } 508135446Strhodes if (xfr->reqtype == dns_rdatatype_axfr) 509135446Strhodes xfr->checkid = ISC_FALSE; 510135446Strhodes xfr->state = XFRST_FIRSTDATA; 511135446Strhodes break; 512135446Strhodes 513135446Strhodes case XFRST_FIRSTDATA: 514135446Strhodes /* 515135446Strhodes * If the transfer begins with one SOA record, it is an AXFR, 516135446Strhodes * if it begins with two SOAs, it is an IXFR. 517135446Strhodes */ 518135446Strhodes if (xfr->reqtype == dns_rdatatype_ixfr && 519135446Strhodes rdata->type == dns_rdatatype_soa && 520135446Strhodes xfr->ixfr.request_serial == dns_soa_getserial(rdata)) { 521135446Strhodes xfrin_log(xfr, ISC_LOG_DEBUG(3), 522135446Strhodes "got incremental response"); 523135446Strhodes CHECK(ixfr_init(xfr)); 524135446Strhodes xfr->state = XFRST_IXFR_DELSOA; 525135446Strhodes } else { 526135446Strhodes xfrin_log(xfr, ISC_LOG_DEBUG(3), 527135446Strhodes "got nonincremental response"); 528135446Strhodes CHECK(axfr_init(xfr)); 529135446Strhodes xfr->state = XFRST_AXFR; 530135446Strhodes } 531135446Strhodes goto redo; 532135446Strhodes 533135446Strhodes case XFRST_IXFR_DELSOA: 534135446Strhodes INSIST(rdata->type == dns_rdatatype_soa); 535135446Strhodes CHECK(ixfr_putdata(xfr, DNS_DIFFOP_DEL, name, ttl, rdata)); 536135446Strhodes xfr->state = XFRST_IXFR_DEL; 537135446Strhodes break; 538135446Strhodes 539135446Strhodes case XFRST_IXFR_DEL: 540135446Strhodes if (rdata->type == dns_rdatatype_soa) { 541135446Strhodes isc_uint32_t soa_serial = dns_soa_getserial(rdata); 542135446Strhodes xfr->state = XFRST_IXFR_ADDSOA; 543135446Strhodes xfr->ixfr.current_serial = soa_serial; 544135446Strhodes goto redo; 545135446Strhodes } 546135446Strhodes CHECK(ixfr_putdata(xfr, DNS_DIFFOP_DEL, name, ttl, rdata)); 547135446Strhodes break; 548135446Strhodes 549135446Strhodes case XFRST_IXFR_ADDSOA: 550135446Strhodes INSIST(rdata->type == dns_rdatatype_soa); 551135446Strhodes CHECK(ixfr_putdata(xfr, DNS_DIFFOP_ADD, name, ttl, rdata)); 552135446Strhodes xfr->state = XFRST_IXFR_ADD; 553135446Strhodes break; 554135446Strhodes 555135446Strhodes case XFRST_IXFR_ADD: 556135446Strhodes if (rdata->type == dns_rdatatype_soa) { 557135446Strhodes isc_uint32_t soa_serial = dns_soa_getserial(rdata); 558135446Strhodes if (soa_serial == xfr->end_serial) { 559143731Sdougb CHECK(ixfr_commit(xfr)); 560224092Sdougb xfr->state = XFRST_IXFR_END; 561135446Strhodes break; 562135446Strhodes } else if (soa_serial != xfr->ixfr.current_serial) { 563135446Strhodes xfrin_log(xfr, ISC_LOG_ERROR, 564135446Strhodes "IXFR out of sync: " 565135446Strhodes "expected serial %u, got %u", 566135446Strhodes xfr->ixfr.current_serial, soa_serial); 567135446Strhodes FAIL(DNS_R_FORMERR); 568135446Strhodes } else { 569143731Sdougb CHECK(ixfr_commit(xfr)); 570135446Strhodes xfr->state = XFRST_IXFR_DELSOA; 571135446Strhodes goto redo; 572135446Strhodes } 573135446Strhodes } 574135446Strhodes if (rdata->type == dns_rdatatype_ns && 575135446Strhodes dns_name_iswildcard(name)) 576135446Strhodes FAIL(DNS_R_INVALIDNS); 577135446Strhodes CHECK(ixfr_putdata(xfr, DNS_DIFFOP_ADD, name, ttl, rdata)); 578135446Strhodes break; 579135446Strhodes 580135446Strhodes case XFRST_AXFR: 581135446Strhodes /* 582135446Strhodes * Old BINDs sent cross class A records for non IN classes. 583135446Strhodes */ 584135446Strhodes if (rdata->type == dns_rdatatype_a && 585135446Strhodes rdata->rdclass != xfr->rdclass && 586135446Strhodes xfr->rdclass != dns_rdataclass_in) 587135446Strhodes break; 588135446Strhodes CHECK(axfr_putdata(xfr, DNS_DIFFOP_ADD, name, ttl, rdata)); 589135446Strhodes if (rdata->type == dns_rdatatype_soa) { 590135446Strhodes CHECK(axfr_commit(xfr)); 591224092Sdougb xfr->state = XFRST_AXFR_END; 592135446Strhodes break; 593135446Strhodes } 594135446Strhodes break; 595224092Sdougb case XFRST_AXFR_END: 596224092Sdougb case XFRST_IXFR_END: 597135446Strhodes FAIL(DNS_R_EXTRADATA); 598254402Serwin /* NOTREACHED */ 599135446Strhodes default: 600135446Strhodes INSIST(0); 601135446Strhodes break; 602135446Strhodes } 603135446Strhodes result = ISC_R_SUCCESS; 604135446Strhodes failure: 605135446Strhodes return (result); 606135446Strhodes} 607135446Strhodes 608135446Strhodesisc_result_t 609135446Strhodesdns_xfrin_create(dns_zone_t *zone, dns_rdatatype_t xfrtype, 610135446Strhodes isc_sockaddr_t *masteraddr, dns_tsigkey_t *tsigkey, 611135446Strhodes isc_mem_t *mctx, isc_timermgr_t *timermgr, 612135446Strhodes isc_socketmgr_t *socketmgr, isc_task_t *task, 613135446Strhodes dns_xfrindone_t done, dns_xfrin_ctx_t **xfrp) 614135446Strhodes{ 615135446Strhodes isc_sockaddr_t sourceaddr; 616135446Strhodes 617135446Strhodes switch (isc_sockaddr_pf(masteraddr)) { 618135446Strhodes case PF_INET: 619135446Strhodes sourceaddr = *dns_zone_getxfrsource4(zone); 620135446Strhodes break; 621135446Strhodes case PF_INET6: 622135446Strhodes sourceaddr = *dns_zone_getxfrsource6(zone); 623135446Strhodes break; 624135446Strhodes default: 625135446Strhodes INSIST(0); 626135446Strhodes } 627135446Strhodes 628135446Strhodes return(dns_xfrin_create2(zone, xfrtype, masteraddr, &sourceaddr, 629135446Strhodes tsigkey, mctx, timermgr, socketmgr, 630135446Strhodes task, done, xfrp)); 631135446Strhodes} 632135446Strhodes 633135446Strhodesisc_result_t 634135446Strhodesdns_xfrin_create2(dns_zone_t *zone, dns_rdatatype_t xfrtype, 635135446Strhodes isc_sockaddr_t *masteraddr, isc_sockaddr_t *sourceaddr, 636135446Strhodes dns_tsigkey_t *tsigkey, isc_mem_t *mctx, 637135446Strhodes isc_timermgr_t *timermgr, isc_socketmgr_t *socketmgr, 638254897Serwin isc_task_t *task, dns_xfrindone_t done, 639254897Serwin dns_xfrin_ctx_t **xfrp) 640135446Strhodes{ 641135446Strhodes dns_name_t *zonename = dns_zone_getorigin(zone); 642153816Sdougb dns_xfrin_ctx_t *xfr = NULL; 643135446Strhodes isc_result_t result; 644135446Strhodes dns_db_t *db = NULL; 645135446Strhodes 646135446Strhodes REQUIRE(xfrp != NULL && *xfrp == NULL); 647135446Strhodes 648135446Strhodes (void)dns_zone_getdb(zone, &db); 649135446Strhodes 650165071Sdougb if (xfrtype == dns_rdatatype_soa || xfrtype == dns_rdatatype_ixfr) 651165071Sdougb REQUIRE(db != NULL); 652165071Sdougb 653135446Strhodes CHECK(xfrin_create(mctx, zone, db, task, timermgr, socketmgr, zonename, 654135446Strhodes dns_zone_getclass(zone), xfrtype, masteraddr, 655135446Strhodes sourceaddr, tsigkey, &xfr)); 656135446Strhodes 657135446Strhodes CHECK(xfrin_start(xfr)); 658135446Strhodes 659135446Strhodes xfr->done = done; 660135446Strhodes xfr->refcount++; 661135446Strhodes *xfrp = xfr; 662135446Strhodes 663135446Strhodes failure: 664135446Strhodes if (db != NULL) 665135446Strhodes dns_db_detach(&db); 666170222Sdougb if (result != ISC_R_SUCCESS) { 667170222Sdougb char zonetext[DNS_NAME_MAXTEXT+32]; 668170222Sdougb dns_zone_name(zone, zonetext, sizeof(zonetext)); 669170222Sdougb xfrin_log1(ISC_LOG_ERROR, zonetext, masteraddr, 670170222Sdougb "zone transfer setup failed"); 671170222Sdougb } 672135446Strhodes return (result); 673135446Strhodes} 674135446Strhodes 675135446Strhodesvoid 676135446Strhodesdns_xfrin_shutdown(dns_xfrin_ctx_t *xfr) { 677135446Strhodes if (! xfr->shuttingdown) 678135446Strhodes xfrin_fail(xfr, ISC_R_CANCELED, "shut down"); 679135446Strhodes} 680135446Strhodes 681135446Strhodesvoid 682135446Strhodesdns_xfrin_attach(dns_xfrin_ctx_t *source, dns_xfrin_ctx_t **target) { 683135446Strhodes REQUIRE(target != NULL && *target == NULL); 684135446Strhodes source->refcount++; 685135446Strhodes *target = source; 686135446Strhodes} 687135446Strhodes 688135446Strhodesvoid 689135446Strhodesdns_xfrin_detach(dns_xfrin_ctx_t **xfrp) { 690135446Strhodes dns_xfrin_ctx_t *xfr = *xfrp; 691135446Strhodes INSIST(xfr->refcount > 0); 692135446Strhodes xfr->refcount--; 693135446Strhodes maybe_free(xfr); 694135446Strhodes *xfrp = NULL; 695135446Strhodes} 696135446Strhodes 697135446Strhodesstatic void 698135446Strhodesxfrin_cancelio(dns_xfrin_ctx_t *xfr) { 699135446Strhodes if (xfr->connects > 0) { 700135446Strhodes isc_socket_cancel(xfr->socket, xfr->task, 701135446Strhodes ISC_SOCKCANCEL_CONNECT); 702135446Strhodes } else if (xfr->recvs > 0) { 703135446Strhodes dns_tcpmsg_cancelread(&xfr->tcpmsg); 704135446Strhodes } else if (xfr->sends > 0) { 705135446Strhodes isc_socket_cancel(xfr->socket, xfr->task, 706135446Strhodes ISC_SOCKCANCEL_SEND); 707135446Strhodes } 708135446Strhodes} 709135446Strhodes 710135446Strhodesstatic void 711135446Strhodesxfrin_reset(dns_xfrin_ctx_t *xfr) { 712135446Strhodes REQUIRE(VALID_XFRIN(xfr)); 713135446Strhodes 714135446Strhodes xfrin_log(xfr, ISC_LOG_INFO, "resetting"); 715135446Strhodes 716135446Strhodes xfrin_cancelio(xfr); 717135446Strhodes 718135446Strhodes if (xfr->socket != NULL) 719135446Strhodes isc_socket_detach(&xfr->socket); 720135446Strhodes 721135446Strhodes if (xfr->lasttsig != NULL) 722135446Strhodes isc_buffer_free(&xfr->lasttsig); 723135446Strhodes 724135446Strhodes dns_diff_clear(&xfr->diff); 725135446Strhodes xfr->difflen = 0; 726135446Strhodes 727135446Strhodes if (xfr->ixfr.journal != NULL) 728135446Strhodes dns_journal_destroy(&xfr->ixfr.journal); 729135446Strhodes 730135446Strhodes if (xfr->axfr.add_private != NULL) { 731135446Strhodes (void)dns_db_endload(xfr->db, &xfr->axfr.add_private); 732135446Strhodes xfr->axfr.add_func = NULL; 733135446Strhodes } 734135446Strhodes 735135446Strhodes if (xfr->tcpmsg_valid) { 736135446Strhodes dns_tcpmsg_invalidate(&xfr->tcpmsg); 737135446Strhodes xfr->tcpmsg_valid = ISC_FALSE; 738135446Strhodes } 739135446Strhodes 740135446Strhodes if (xfr->ver != NULL) 741135446Strhodes dns_db_closeversion(xfr->db, &xfr->ver, ISC_FALSE); 742135446Strhodes} 743135446Strhodes 744135446Strhodes 745135446Strhodesstatic void 746135446Strhodesxfrin_fail(dns_xfrin_ctx_t *xfr, isc_result_t result, const char *msg) { 747135446Strhodes if (result != DNS_R_UPTODATE) { 748135446Strhodes xfrin_log(xfr, ISC_LOG_ERROR, "%s: %s", 749135446Strhodes msg, isc_result_totext(result)); 750135446Strhodes if (xfr->is_ixfr) 751135446Strhodes /* Pass special result code to force AXFR retry */ 752135446Strhodes result = DNS_R_BADIXFR; 753135446Strhodes } 754135446Strhodes xfrin_cancelio(xfr); 755174187Sdougb /* 756174187Sdougb * Close the journal. 757174187Sdougb */ 758174187Sdougb if (xfr->ixfr.journal != NULL) 759174187Sdougb dns_journal_destroy(&xfr->ixfr.journal); 760135446Strhodes if (xfr->done != NULL) { 761135446Strhodes (xfr->done)(xfr->zone, result); 762135446Strhodes xfr->done = NULL; 763135446Strhodes } 764135446Strhodes xfr->shuttingdown = ISC_TRUE; 765135446Strhodes maybe_free(xfr); 766135446Strhodes} 767135446Strhodes 768135446Strhodesstatic isc_result_t 769135446Strhodesxfrin_create(isc_mem_t *mctx, 770135446Strhodes dns_zone_t *zone, 771135446Strhodes dns_db_t *db, 772135446Strhodes isc_task_t *task, 773135446Strhodes isc_timermgr_t *timermgr, 774135446Strhodes isc_socketmgr_t *socketmgr, 775135446Strhodes dns_name_t *zonename, 776135446Strhodes dns_rdataclass_t rdclass, 777135446Strhodes dns_rdatatype_t reqtype, 778135446Strhodes isc_sockaddr_t *masteraddr, 779135446Strhodes isc_sockaddr_t *sourceaddr, 780135446Strhodes dns_tsigkey_t *tsigkey, 781135446Strhodes dns_xfrin_ctx_t **xfrp) 782135446Strhodes{ 783135446Strhodes dns_xfrin_ctx_t *xfr = NULL; 784135446Strhodes isc_result_t result; 785135446Strhodes isc_uint32_t tmp; 786135446Strhodes 787135446Strhodes xfr = isc_mem_get(mctx, sizeof(*xfr)); 788135446Strhodes if (xfr == NULL) 789135446Strhodes return (ISC_R_NOMEMORY); 790254402Serwin xfr->mctx = NULL; 791254402Serwin isc_mem_attach(mctx, &xfr->mctx); 792135446Strhodes xfr->refcount = 0; 793135446Strhodes xfr->zone = NULL; 794135446Strhodes dns_zone_iattach(zone, &xfr->zone); 795135446Strhodes xfr->task = NULL; 796135446Strhodes isc_task_attach(task, &xfr->task); 797135446Strhodes xfr->timer = NULL; 798135446Strhodes xfr->socketmgr = socketmgr; 799135446Strhodes xfr->done = NULL; 800135446Strhodes 801135446Strhodes xfr->connects = 0; 802135446Strhodes xfr->sends = 0; 803135446Strhodes xfr->recvs = 0; 804135446Strhodes xfr->shuttingdown = ISC_FALSE; 805135446Strhodes 806135446Strhodes dns_name_init(&xfr->name, NULL); 807135446Strhodes xfr->rdclass = rdclass; 808135446Strhodes isc_random_get(&tmp); 809135446Strhodes xfr->checkid = ISC_TRUE; 810135446Strhodes xfr->id = (isc_uint16_t)(tmp & 0xffff); 811135446Strhodes xfr->reqtype = reqtype; 812135446Strhodes 813135446Strhodes /* sockaddr */ 814135446Strhodes xfr->socket = NULL; 815135446Strhodes /* qbuffer */ 816135446Strhodes /* qbuffer_data */ 817135446Strhodes /* tcpmsg */ 818135446Strhodes xfr->tcpmsg_valid = ISC_FALSE; 819135446Strhodes 820135446Strhodes xfr->db = NULL; 821135446Strhodes if (db != NULL) 822135446Strhodes dns_db_attach(db, &xfr->db); 823135446Strhodes xfr->ver = NULL; 824135446Strhodes dns_diff_init(xfr->mctx, &xfr->diff); 825135446Strhodes xfr->difflen = 0; 826135446Strhodes 827165071Sdougb if (reqtype == dns_rdatatype_soa) 828165071Sdougb xfr->state = XFRST_SOAQUERY; 829165071Sdougb else 830165071Sdougb xfr->state = XFRST_INITIALSOA; 831135446Strhodes /* end_serial */ 832135446Strhodes 833135446Strhodes xfr->nmsg = 0; 834193149Sdougb xfr->nrecs = 0; 835193149Sdougb xfr->nbytes = 0; 836193149Sdougb isc_time_now(&xfr->start); 837135446Strhodes 838135446Strhodes xfr->tsigkey = NULL; 839135446Strhodes if (tsigkey != NULL) 840135446Strhodes dns_tsigkey_attach(tsigkey, &xfr->tsigkey); 841135446Strhodes xfr->lasttsig = NULL; 842135446Strhodes xfr->tsigctx = NULL; 843135446Strhodes xfr->sincetsig = 0; 844135446Strhodes xfr->is_ixfr = ISC_FALSE; 845135446Strhodes 846135446Strhodes /* ixfr.request_serial */ 847135446Strhodes /* ixfr.current_serial */ 848135446Strhodes xfr->ixfr.journal = NULL; 849135446Strhodes 850135446Strhodes xfr->axfr.add_func = NULL; 851135446Strhodes xfr->axfr.add_private = NULL; 852135446Strhodes 853135446Strhodes CHECK(dns_name_dup(zonename, mctx, &xfr->name)); 854135446Strhodes 855135446Strhodes CHECK(isc_timer_create(timermgr, isc_timertype_inactive, NULL, NULL, 856135446Strhodes task, xfrin_timeout, xfr, &xfr->timer)); 857135446Strhodes CHECK(dns_timer_setidle(xfr->timer, 858135446Strhodes dns_zone_getmaxxfrin(xfr->zone), 859135446Strhodes dns_zone_getidlein(xfr->zone), 860135446Strhodes ISC_FALSE)); 861135446Strhodes 862135446Strhodes xfr->masteraddr = *masteraddr; 863135446Strhodes 864135446Strhodes INSIST(isc_sockaddr_pf(masteraddr) == isc_sockaddr_pf(sourceaddr)); 865135446Strhodes xfr->sourceaddr = *sourceaddr; 866135446Strhodes isc_sockaddr_setport(&xfr->sourceaddr, 0); 867135446Strhodes 868262706Serwin /* 869262706Serwin * Reserve 2 bytes for TCP length at the begining of the buffer. 870262706Serwin */ 871262706Serwin isc_buffer_init(&xfr->qbuffer, &xfr->qbuffer_data[2], 872262706Serwin sizeof(xfr->qbuffer_data) - 2); 873135446Strhodes 874135446Strhodes xfr->magic = XFRIN_MAGIC; 875135446Strhodes *xfrp = xfr; 876135446Strhodes return (ISC_R_SUCCESS); 877135446Strhodes 878135446Strhodes failure: 879165071Sdougb if (xfr->timer != NULL) 880165071Sdougb isc_timer_detach(&xfr->timer); 881165071Sdougb if (dns_name_dynamic(&xfr->name)) 882165071Sdougb dns_name_free(&xfr->name, xfr->mctx); 883165071Sdougb if (xfr->tsigkey != NULL) 884165071Sdougb dns_tsigkey_detach(&xfr->tsigkey); 885165071Sdougb if (xfr->db != NULL) 886165071Sdougb dns_db_detach(&xfr->db); 887165071Sdougb isc_task_detach(&xfr->task); 888165071Sdougb dns_zone_idetach(&xfr->zone); 889254402Serwin isc_mem_putanddetach(&xfr->mctx, xfr, sizeof(*xfr)); 890165071Sdougb 891135446Strhodes return (result); 892135446Strhodes} 893135446Strhodes 894135446Strhodesstatic isc_result_t 895135446Strhodesxfrin_start(dns_xfrin_ctx_t *xfr) { 896135446Strhodes isc_result_t result; 897135446Strhodes CHECK(isc_socket_create(xfr->socketmgr, 898135446Strhodes isc_sockaddr_pf(&xfr->sourceaddr), 899135446Strhodes isc_sockettype_tcp, 900135446Strhodes &xfr->socket)); 901193149Sdougb isc_socket_setname(xfr->socket, "xfrin", NULL); 902165071Sdougb#ifndef BROKEN_TCP_BIND_BEFORE_CONNECT 903182645Sdougb CHECK(isc_socket_bind(xfr->socket, &xfr->sourceaddr, 904182645Sdougb ISC_SOCKET_REUSEADDRESS)); 905165071Sdougb#endif 906135446Strhodes CHECK(isc_socket_connect(xfr->socket, &xfr->masteraddr, xfr->task, 907135446Strhodes xfrin_connect_done, xfr)); 908135446Strhodes xfr->connects++; 909135446Strhodes return (ISC_R_SUCCESS); 910135446Strhodes failure: 911135446Strhodes xfrin_fail(xfr, result, "failed setting up socket"); 912135446Strhodes return (result); 913135446Strhodes} 914135446Strhodes 915135446Strhodes/* XXX the resolver could use this, too */ 916135446Strhodes 917135446Strhodesstatic isc_result_t 918135446Strhodesrender(dns_message_t *msg, isc_mem_t *mctx, isc_buffer_t *buf) { 919135446Strhodes dns_compress_t cctx; 920135446Strhodes isc_boolean_t cleanup_cctx = ISC_FALSE; 921135446Strhodes isc_result_t result; 922135446Strhodes 923135446Strhodes CHECK(dns_compress_init(&cctx, -1, mctx)); 924135446Strhodes cleanup_cctx = ISC_TRUE; 925135446Strhodes CHECK(dns_message_renderbegin(msg, &cctx, buf)); 926135446Strhodes CHECK(dns_message_rendersection(msg, DNS_SECTION_QUESTION, 0)); 927135446Strhodes CHECK(dns_message_rendersection(msg, DNS_SECTION_ANSWER, 0)); 928135446Strhodes CHECK(dns_message_rendersection(msg, DNS_SECTION_AUTHORITY, 0)); 929135446Strhodes CHECK(dns_message_rendersection(msg, DNS_SECTION_ADDITIONAL, 0)); 930135446Strhodes CHECK(dns_message_renderend(msg)); 931135446Strhodes result = ISC_R_SUCCESS; 932135446Strhodes failure: 933186462Sdougb if (cleanup_cctx) 934186462Sdougb dns_compress_invalidate(&cctx); 935135446Strhodes return (result); 936135446Strhodes} 937135446Strhodes 938135446Strhodes/* 939135446Strhodes * A connection has been established. 940135446Strhodes */ 941135446Strhodesstatic void 942135446Strhodesxfrin_connect_done(isc_task_t *task, isc_event_t *event) { 943135446Strhodes isc_socket_connev_t *cev = (isc_socket_connev_t *) event; 944135446Strhodes dns_xfrin_ctx_t *xfr = (dns_xfrin_ctx_t *) event->ev_arg; 945193149Sdougb isc_result_t result = cev->result; 946135446Strhodes char sourcetext[ISC_SOCKADDR_FORMATSIZE]; 947135446Strhodes isc_sockaddr_t sockaddr; 948262706Serwin dns_zonemgr_t * zmgr; 949262706Serwin isc_time_t now; 950135446Strhodes 951135446Strhodes REQUIRE(VALID_XFRIN(xfr)); 952135446Strhodes 953135446Strhodes UNUSED(task); 954135446Strhodes 955135446Strhodes INSIST(event->ev_type == ISC_SOCKEVENT_CONNECT); 956135446Strhodes isc_event_free(&event); 957135446Strhodes 958135446Strhodes xfr->connects--; 959135446Strhodes if (xfr->shuttingdown) { 960135446Strhodes maybe_free(xfr); 961135446Strhodes return; 962135446Strhodes } 963135446Strhodes 964262706Serwin zmgr = dns_zone_getmgr(xfr->zone); 965262706Serwin if (zmgr != NULL) { 966262706Serwin if (result != ISC_R_SUCCESS) { 967193149Sdougb TIME_NOW(&now); 968193149Sdougb dns_zonemgr_unreachableadd(zmgr, &xfr->masteraddr, 969193149Sdougb &xfr->sourceaddr, &now); 970262706Serwin goto failure; 971262706Serwin } else 972262706Serwin dns_zonemgr_unreachabledel(zmgr, &xfr->masteraddr, 973262706Serwin &xfr->sourceaddr); 974193149Sdougb } 975193149Sdougb 976135446Strhodes result = isc_socket_getsockname(xfr->socket, &sockaddr); 977135446Strhodes if (result == ISC_R_SUCCESS) { 978135446Strhodes isc_sockaddr_format(&sockaddr, sourcetext, sizeof(sourcetext)); 979135446Strhodes } else 980135446Strhodes strcpy(sourcetext, "<UNKNOWN>"); 981135446Strhodes xfrin_log(xfr, ISC_LOG_INFO, "connected using %s", sourcetext); 982135446Strhodes 983135446Strhodes dns_tcpmsg_init(xfr->mctx, xfr->socket, &xfr->tcpmsg); 984135446Strhodes xfr->tcpmsg_valid = ISC_TRUE; 985135446Strhodes 986135446Strhodes CHECK(xfrin_send_request(xfr)); 987135446Strhodes failure: 988135446Strhodes if (result != ISC_R_SUCCESS) 989135446Strhodes xfrin_fail(xfr, result, "failed to connect"); 990135446Strhodes} 991135446Strhodes 992135446Strhodes/* 993135446Strhodes * Convert a tuple into a dns_name_t suitable for inserting 994135446Strhodes * into the given dns_message_t. 995135446Strhodes */ 996135446Strhodesstatic isc_result_t 997135446Strhodestuple2msgname(dns_difftuple_t *tuple, dns_message_t *msg, dns_name_t **target) 998135446Strhodes{ 999135446Strhodes isc_result_t result; 1000135446Strhodes dns_rdata_t *rdata = NULL; 1001135446Strhodes dns_rdatalist_t *rdl = NULL; 1002135446Strhodes dns_rdataset_t *rds = NULL; 1003135446Strhodes dns_name_t *name = NULL; 1004135446Strhodes 1005135446Strhodes REQUIRE(target != NULL && *target == NULL); 1006135446Strhodes 1007135446Strhodes CHECK(dns_message_gettemprdata(msg, &rdata)); 1008135446Strhodes dns_rdata_init(rdata); 1009135446Strhodes dns_rdata_clone(&tuple->rdata, rdata); 1010135446Strhodes 1011135446Strhodes CHECK(dns_message_gettemprdatalist(msg, &rdl)); 1012135446Strhodes dns_rdatalist_init(rdl); 1013135446Strhodes rdl->type = tuple->rdata.type; 1014135446Strhodes rdl->rdclass = tuple->rdata.rdclass; 1015135446Strhodes rdl->ttl = tuple->ttl; 1016135446Strhodes ISC_LIST_APPEND(rdl->rdata, rdata, link); 1017135446Strhodes 1018135446Strhodes CHECK(dns_message_gettemprdataset(msg, &rds)); 1019135446Strhodes dns_rdataset_init(rds); 1020135446Strhodes CHECK(dns_rdatalist_tordataset(rdl, rds)); 1021135446Strhodes 1022135446Strhodes CHECK(dns_message_gettempname(msg, &name)); 1023135446Strhodes dns_name_init(name, NULL); 1024135446Strhodes dns_name_clone(&tuple->name, name); 1025135446Strhodes ISC_LIST_APPEND(name->list, rds, link); 1026135446Strhodes 1027135446Strhodes *target = name; 1028135446Strhodes return (ISC_R_SUCCESS); 1029135446Strhodes 1030135446Strhodes failure: 1031135446Strhodes 1032143731Sdougb if (rds != NULL) { 1033135446Strhodes dns_rdataset_disassociate(rds); 1034135446Strhodes dns_message_puttemprdataset(msg, &rds); 1035143731Sdougb } 1036135446Strhodes if (rdl != NULL) { 1037135446Strhodes ISC_LIST_UNLINK(rdl->rdata, rdata, link); 1038135446Strhodes dns_message_puttemprdatalist(msg, &rdl); 1039135446Strhodes } 1040135446Strhodes if (rdata != NULL) 1041135446Strhodes dns_message_puttemprdata(msg, &rdata); 1042135446Strhodes 1043135446Strhodes return (result); 1044135446Strhodes} 1045135446Strhodes 1046135446Strhodes 1047135446Strhodes/* 1048135446Strhodes * Build an *XFR request and send its length prefix. 1049135446Strhodes */ 1050135446Strhodesstatic isc_result_t 1051135446Strhodesxfrin_send_request(dns_xfrin_ctx_t *xfr) { 1052135446Strhodes isc_result_t result; 1053135446Strhodes isc_region_t region; 1054135446Strhodes dns_rdataset_t *qrdataset = NULL; 1055135446Strhodes dns_message_t *msg = NULL; 1056135446Strhodes dns_difftuple_t *soatuple = NULL; 1057135446Strhodes dns_name_t *qname = NULL; 1058135446Strhodes dns_dbversion_t *ver = NULL; 1059135446Strhodes dns_name_t *msgsoaname = NULL; 1060135446Strhodes 1061135446Strhodes /* Create the request message */ 1062135446Strhodes CHECK(dns_message_create(xfr->mctx, DNS_MESSAGE_INTENTRENDER, &msg)); 1063135446Strhodes CHECK(dns_message_settsigkey(msg, xfr->tsigkey)); 1064135446Strhodes 1065135446Strhodes /* Create a name for the question section. */ 1066135446Strhodes CHECK(dns_message_gettempname(msg, &qname)); 1067135446Strhodes dns_name_init(qname, NULL); 1068135446Strhodes dns_name_clone(&xfr->name, qname); 1069135446Strhodes 1070135446Strhodes /* Formulate the question and attach it to the question name. */ 1071135446Strhodes CHECK(dns_message_gettemprdataset(msg, &qrdataset)); 1072135446Strhodes dns_rdataset_init(qrdataset); 1073135446Strhodes dns_rdataset_makequestion(qrdataset, xfr->rdclass, xfr->reqtype); 1074135446Strhodes ISC_LIST_APPEND(qname->list, qrdataset, link); 1075135446Strhodes qrdataset = NULL; 1076135446Strhodes 1077135446Strhodes dns_message_addname(msg, qname, DNS_SECTION_QUESTION); 1078135446Strhodes qname = NULL; 1079135446Strhodes 1080135446Strhodes if (xfr->reqtype == dns_rdatatype_ixfr) { 1081135446Strhodes /* Get the SOA and add it to the authority section. */ 1082135446Strhodes /* XXX is using the current version the right thing? */ 1083135446Strhodes dns_db_currentversion(xfr->db, &ver); 1084135446Strhodes CHECK(dns_db_createsoatuple(xfr->db, ver, xfr->mctx, 1085135446Strhodes DNS_DIFFOP_EXISTS, &soatuple)); 1086135446Strhodes xfr->ixfr.request_serial = dns_soa_getserial(&soatuple->rdata); 1087135446Strhodes xfr->ixfr.current_serial = xfr->ixfr.request_serial; 1088135446Strhodes xfrin_log(xfr, ISC_LOG_DEBUG(3), 1089135446Strhodes "requesting IXFR for serial %u", 1090135446Strhodes xfr->ixfr.request_serial); 1091135446Strhodes 1092135446Strhodes CHECK(tuple2msgname(soatuple, msg, &msgsoaname)); 1093135446Strhodes dns_message_addname(msg, msgsoaname, DNS_SECTION_AUTHORITY); 1094165071Sdougb } else if (xfr->reqtype == dns_rdatatype_soa) 1095165071Sdougb CHECK(dns_db_getsoaserial(xfr->db, NULL, 1096165071Sdougb &xfr->ixfr.request_serial)); 1097135446Strhodes 1098135446Strhodes xfr->checkid = ISC_TRUE; 1099135446Strhodes xfr->id++; 1100174187Sdougb xfr->nmsg = 0; 1101193149Sdougb xfr->nrecs = 0; 1102193149Sdougb xfr->nbytes = 0; 1103193149Sdougb isc_time_now(&xfr->start); 1104135446Strhodes msg->id = xfr->id; 1105186462Sdougb if (xfr->tsigctx != NULL) 1106186462Sdougb dst_context_destroy(&xfr->tsigctx); 1107135446Strhodes 1108135446Strhodes CHECK(render(msg, xfr->mctx, &xfr->qbuffer)); 1109135446Strhodes 1110135446Strhodes /* 1111135446Strhodes * Free the last tsig, if there is one. 1112135446Strhodes */ 1113135446Strhodes if (xfr->lasttsig != NULL) 1114135446Strhodes isc_buffer_free(&xfr->lasttsig); 1115135446Strhodes 1116135446Strhodes /* 1117135446Strhodes * Save the query TSIG and don't let message_destroy free it. 1118135446Strhodes */ 1119135446Strhodes CHECK(dns_message_getquerytsig(msg, xfr->mctx, &xfr->lasttsig)); 1120135446Strhodes 1121135446Strhodes isc_buffer_usedregion(&xfr->qbuffer, ®ion); 1122135446Strhodes INSIST(region.length <= 65535); 1123135446Strhodes 1124262706Serwin /* 1125262706Serwin * Record message length and adjust region to include TCP 1126262706Serwin * length field. 1127262706Serwin */ 1128262706Serwin xfr->qbuffer_data[0] = (region.length >> 8) & 0xff; 1129262706Serwin xfr->qbuffer_data[1] = region.length & 0xff; 1130262706Serwin region.base -= 2; 1131262706Serwin region.length += 2; 1132262706Serwin CHECK(isc_socket_send(xfr->socket, ®ion, xfr->task, 1133262706Serwin xfrin_send_done, xfr)); 1134135446Strhodes xfr->sends++; 1135135446Strhodes 1136135446Strhodes failure: 1137135446Strhodes if (qname != NULL) 1138135446Strhodes dns_message_puttempname(msg, &qname); 1139135446Strhodes if (qrdataset != NULL) 1140135446Strhodes dns_message_puttemprdataset(msg, &qrdataset); 1141135446Strhodes if (msg != NULL) 1142135446Strhodes dns_message_destroy(&msg); 1143135446Strhodes if (soatuple != NULL) 1144135446Strhodes dns_difftuple_free(&soatuple); 1145135446Strhodes if (ver != NULL) 1146135446Strhodes dns_db_closeversion(xfr->db, &ver, ISC_FALSE); 1147135446Strhodes return (result); 1148135446Strhodes} 1149135446Strhodes 1150135446Strhodesstatic void 1151135446Strhodesxfrin_send_done(isc_task_t *task, isc_event_t *event) { 1152135446Strhodes isc_socketevent_t *sev = (isc_socketevent_t *) event; 1153135446Strhodes dns_xfrin_ctx_t *xfr = (dns_xfrin_ctx_t *) event->ev_arg; 1154135446Strhodes isc_result_t result; 1155135446Strhodes 1156135446Strhodes REQUIRE(VALID_XFRIN(xfr)); 1157135446Strhodes 1158135446Strhodes UNUSED(task); 1159135446Strhodes 1160135446Strhodes INSIST(event->ev_type == ISC_SOCKEVENT_SENDDONE); 1161135446Strhodes 1162135446Strhodes xfr->sends--; 1163135446Strhodes xfrin_log(xfr, ISC_LOG_DEBUG(3), "sent request data"); 1164135446Strhodes CHECK(sev->result); 1165135446Strhodes 1166135446Strhodes CHECK(dns_tcpmsg_readmessage(&xfr->tcpmsg, xfr->task, 1167135446Strhodes xfrin_recv_done, xfr)); 1168135446Strhodes xfr->recvs++; 1169135446Strhodes failure: 1170135446Strhodes isc_event_free(&event); 1171135446Strhodes if (result != ISC_R_SUCCESS) 1172135446Strhodes xfrin_fail(xfr, result, "failed sending request data"); 1173135446Strhodes} 1174135446Strhodes 1175135446Strhodes 1176135446Strhodesstatic void 1177135446Strhodesxfrin_recv_done(isc_task_t *task, isc_event_t *ev) { 1178135446Strhodes dns_xfrin_ctx_t *xfr = (dns_xfrin_ctx_t *) ev->ev_arg; 1179135446Strhodes isc_result_t result; 1180135446Strhodes dns_message_t *msg = NULL; 1181135446Strhodes dns_name_t *name; 1182135446Strhodes dns_tcpmsg_t *tcpmsg; 1183135446Strhodes dns_name_t *tsigowner = NULL; 1184135446Strhodes 1185135446Strhodes REQUIRE(VALID_XFRIN(xfr)); 1186135446Strhodes 1187135446Strhodes UNUSED(task); 1188135446Strhodes 1189135446Strhodes INSIST(ev->ev_type == DNS_EVENT_TCPMSG); 1190135446Strhodes tcpmsg = ev->ev_sender; 1191135446Strhodes isc_event_free(&ev); 1192135446Strhodes 1193135446Strhodes xfr->recvs--; 1194135446Strhodes if (xfr->shuttingdown) { 1195135446Strhodes maybe_free(xfr); 1196135446Strhodes return; 1197135446Strhodes } 1198135446Strhodes 1199135446Strhodes CHECK(tcpmsg->result); 1200135446Strhodes 1201135446Strhodes xfrin_log(xfr, ISC_LOG_DEBUG(7), "received %u bytes", 1202135446Strhodes tcpmsg->buffer.used); 1203135446Strhodes 1204135446Strhodes CHECK(isc_timer_touch(xfr->timer)); 1205135446Strhodes 1206135446Strhodes CHECK(dns_message_create(xfr->mctx, DNS_MESSAGE_INTENTPARSE, &msg)); 1207135446Strhodes 1208135446Strhodes CHECK(dns_message_settsigkey(msg, xfr->tsigkey)); 1209135446Strhodes CHECK(dns_message_setquerytsig(msg, xfr->lasttsig)); 1210186462Sdougb 1211135446Strhodes msg->tsigctx = xfr->tsigctx; 1212186462Sdougb xfr->tsigctx = NULL; 1213186462Sdougb 1214292321Sdelphij dns_message_setclass(msg, xfr->rdclass); 1215292321Sdelphij 1216135446Strhodes if (xfr->nmsg > 0) 1217135446Strhodes msg->tcp_continuation = 1; 1218135446Strhodes 1219135446Strhodes result = dns_message_parse(msg, &tcpmsg->buffer, 1220135446Strhodes DNS_MESSAGEPARSE_PRESERVEORDER); 1221135446Strhodes 1222135446Strhodes if (result != ISC_R_SUCCESS || msg->rcode != dns_rcode_noerror || 1223135446Strhodes (xfr->checkid && msg->id != xfr->id)) { 1224135446Strhodes if (result == ISC_R_SUCCESS) 1225135446Strhodes result = ISC_RESULTCLASS_DNSRCODE + msg->rcode; /*XXX*/ 1226135446Strhodes if (result == ISC_R_SUCCESS || result == DNS_R_NOERROR) 1227135446Strhodes result = DNS_R_UNEXPECTEDID; 1228135446Strhodes if (xfr->reqtype == dns_rdatatype_axfr || 1229135446Strhodes xfr->reqtype == dns_rdatatype_soa) 1230225361Sdougb goto failure; 1231135446Strhodes xfrin_log(xfr, ISC_LOG_DEBUG(3), "got %s, retrying with AXFR", 1232135446Strhodes isc_result_totext(result)); 1233135446Strhodes try_axfr: 1234135446Strhodes dns_message_destroy(&msg); 1235135446Strhodes xfrin_reset(xfr); 1236165071Sdougb xfr->reqtype = dns_rdatatype_soa; 1237165071Sdougb xfr->state = XFRST_SOAQUERY; 1238135446Strhodes (void)xfrin_start(xfr); 1239135446Strhodes return; 1240135446Strhodes } 1241135446Strhodes 1242135446Strhodes /* 1243135446Strhodes * Does the server know about IXFR? If it doesn't we will get 1244135446Strhodes * a message with a empty answer section or a potentially a CNAME / 1245135446Strhodes * DNAME, the later is handled by xfr_rr() which will return FORMERR 1246135446Strhodes * if the first RR in the answer section is not a SOA record. 1247135446Strhodes */ 1248135446Strhodes if (xfr->reqtype == dns_rdatatype_ixfr && 1249135446Strhodes xfr->state == XFRST_INITIALSOA && 1250135446Strhodes msg->counts[DNS_SECTION_ANSWER] == 0) { 1251135446Strhodes xfrin_log(xfr, ISC_LOG_DEBUG(3), 1252135446Strhodes "empty answer section, retrying with AXFR"); 1253135446Strhodes goto try_axfr; 1254135446Strhodes } 1255135446Strhodes 1256135446Strhodes if (xfr->reqtype == dns_rdatatype_soa && 1257135446Strhodes (msg->flags & DNS_MESSAGEFLAG_AA) == 0) { 1258135446Strhodes FAIL(DNS_R_NOTAUTHORITATIVE); 1259135446Strhodes } 1260135446Strhodes 1261135446Strhodes 1262135446Strhodes result = dns_message_checksig(msg, dns_zone_getview(xfr->zone)); 1263135446Strhodes if (result != ISC_R_SUCCESS) { 1264135446Strhodes xfrin_log(xfr, ISC_LOG_DEBUG(3), "TSIG check failed: %s", 1265135446Strhodes isc_result_totext(result)); 1266225361Sdougb goto failure; 1267135446Strhodes } 1268135446Strhodes 1269135446Strhodes for (result = dns_message_firstname(msg, DNS_SECTION_ANSWER); 1270135446Strhodes result == ISC_R_SUCCESS; 1271135446Strhodes result = dns_message_nextname(msg, DNS_SECTION_ANSWER)) 1272135446Strhodes { 1273135446Strhodes dns_rdataset_t *rds; 1274135446Strhodes 1275135446Strhodes name = NULL; 1276135446Strhodes dns_message_currentname(msg, DNS_SECTION_ANSWER, &name); 1277135446Strhodes for (rds = ISC_LIST_HEAD(name->list); 1278135446Strhodes rds != NULL; 1279135446Strhodes rds = ISC_LIST_NEXT(rds, link)) 1280135446Strhodes { 1281135446Strhodes for (result = dns_rdataset_first(rds); 1282135446Strhodes result == ISC_R_SUCCESS; 1283135446Strhodes result = dns_rdataset_next(rds)) 1284135446Strhodes { 1285135446Strhodes dns_rdata_t rdata = DNS_RDATA_INIT; 1286135446Strhodes dns_rdataset_current(rds, &rdata); 1287135446Strhodes CHECK(xfr_rr(xfr, name, rds->ttl, &rdata)); 1288135446Strhodes } 1289135446Strhodes } 1290135446Strhodes } 1291135446Strhodes if (result != ISC_R_NOMORE) 1292135446Strhodes goto failure; 1293135446Strhodes 1294135446Strhodes if (dns_message_gettsig(msg, &tsigowner) != NULL) { 1295135446Strhodes /* 1296135446Strhodes * Reset the counter. 1297135446Strhodes */ 1298135446Strhodes xfr->sincetsig = 0; 1299135446Strhodes 1300135446Strhodes /* 1301135446Strhodes * Free the last tsig, if there is one. 1302135446Strhodes */ 1303135446Strhodes if (xfr->lasttsig != NULL) 1304135446Strhodes isc_buffer_free(&xfr->lasttsig); 1305135446Strhodes 1306135446Strhodes /* 1307135446Strhodes * Update the last tsig pointer. 1308135446Strhodes */ 1309135446Strhodes CHECK(dns_message_getquerytsig(msg, xfr->mctx, 1310135446Strhodes &xfr->lasttsig)); 1311135446Strhodes 1312135446Strhodes } else if (dns_message_gettsigkey(msg) != NULL) { 1313135446Strhodes xfr->sincetsig++; 1314224092Sdougb if (xfr->sincetsig > 100 || xfr->nmsg == 0 || 1315224092Sdougb xfr->state == XFRST_AXFR_END || 1316224092Sdougb xfr->state == XFRST_IXFR_END) 1317135446Strhodes { 1318135446Strhodes result = DNS_R_EXPECTEDTSIG; 1319135446Strhodes goto failure; 1320135446Strhodes } 1321135446Strhodes } 1322135446Strhodes 1323135446Strhodes /* 1324135446Strhodes * Update the number of messages received. 1325135446Strhodes */ 1326135446Strhodes xfr->nmsg++; 1327135446Strhodes 1328135446Strhodes /* 1329193149Sdougb * Update the number of bytes received. 1330193149Sdougb */ 1331193149Sdougb xfr->nbytes += tcpmsg->buffer.used; 1332193149Sdougb 1333193149Sdougb /* 1334186462Sdougb * Take the context back. 1335135446Strhodes */ 1336186462Sdougb INSIST(xfr->tsigctx == NULL); 1337135446Strhodes xfr->tsigctx = msg->tsigctx; 1338186462Sdougb msg->tsigctx = NULL; 1339135446Strhodes 1340135446Strhodes dns_message_destroy(&msg); 1341135446Strhodes 1342224092Sdougb switch (xfr->state) { 1343224092Sdougb case XFRST_GOTSOA: 1344165071Sdougb xfr->reqtype = dns_rdatatype_axfr; 1345165071Sdougb xfr->state = XFRST_INITIALSOA; 1346165071Sdougb CHECK(xfrin_send_request(xfr)); 1347224092Sdougb break; 1348224092Sdougb case XFRST_AXFR_END: 1349224092Sdougb CHECK(axfr_finalize(xfr)); 1350224092Sdougb /* FALLTHROUGH */ 1351224092Sdougb case XFRST_IXFR_END: 1352135446Strhodes /* 1353174187Sdougb * Close the journal. 1354174187Sdougb */ 1355174187Sdougb if (xfr->ixfr.journal != NULL) 1356174187Sdougb dns_journal_destroy(&xfr->ixfr.journal); 1357224092Sdougb 1358174187Sdougb /* 1359135446Strhodes * Inform the caller we succeeded. 1360135446Strhodes */ 1361135446Strhodes if (xfr->done != NULL) { 1362135446Strhodes (xfr->done)(xfr->zone, ISC_R_SUCCESS); 1363135446Strhodes xfr->done = NULL; 1364135446Strhodes } 1365135446Strhodes /* 1366135446Strhodes * We should have no outstanding events at this 1367135446Strhodes * point, thus maybe_free() should succeed. 1368135446Strhodes */ 1369135446Strhodes xfr->shuttingdown = ISC_TRUE; 1370135446Strhodes maybe_free(xfr); 1371224092Sdougb break; 1372224092Sdougb default: 1373135446Strhodes /* 1374135446Strhodes * Read the next message. 1375135446Strhodes */ 1376135446Strhodes CHECK(dns_tcpmsg_readmessage(&xfr->tcpmsg, xfr->task, 1377135446Strhodes xfrin_recv_done, xfr)); 1378135446Strhodes xfr->recvs++; 1379135446Strhodes } 1380135446Strhodes return; 1381135446Strhodes 1382135446Strhodes failure: 1383135446Strhodes if (msg != NULL) 1384135446Strhodes dns_message_destroy(&msg); 1385135446Strhodes if (result != ISC_R_SUCCESS) 1386135446Strhodes xfrin_fail(xfr, result, "failed while receiving responses"); 1387135446Strhodes} 1388135446Strhodes 1389135446Strhodesstatic void 1390135446Strhodesxfrin_timeout(isc_task_t *task, isc_event_t *event) { 1391135446Strhodes dns_xfrin_ctx_t *xfr = (dns_xfrin_ctx_t *) event->ev_arg; 1392135446Strhodes 1393135446Strhodes REQUIRE(VALID_XFRIN(xfr)); 1394135446Strhodes 1395135446Strhodes UNUSED(task); 1396135446Strhodes 1397135446Strhodes isc_event_free(&event); 1398135446Strhodes /* 1399135446Strhodes * This will log "giving up: timeout". 1400135446Strhodes */ 1401135446Strhodes xfrin_fail(xfr, ISC_R_TIMEDOUT, "giving up"); 1402135446Strhodes} 1403135446Strhodes 1404135446Strhodesstatic void 1405135446Strhodesmaybe_free(dns_xfrin_ctx_t *xfr) { 1406193149Sdougb isc_uint64_t msecs; 1407193149Sdougb isc_uint64_t persec; 1408193149Sdougb 1409135446Strhodes REQUIRE(VALID_XFRIN(xfr)); 1410135446Strhodes 1411135446Strhodes if (! xfr->shuttingdown || xfr->refcount != 0 || 1412135446Strhodes xfr->connects != 0 || xfr->sends != 0 || 1413135446Strhodes xfr->recvs != 0) 1414135446Strhodes return; 1415135446Strhodes 1416193149Sdougb /* 1417193149Sdougb * Calculate the length of time the transfer took, 1418193149Sdougb * and print a log message with the bytes and rate. 1419193149Sdougb */ 1420193149Sdougb isc_time_now(&xfr->end); 1421193149Sdougb msecs = isc_time_microdiff(&xfr->end, &xfr->start) / 1000; 1422193149Sdougb if (msecs == 0) 1423193149Sdougb msecs = 1; 1424193149Sdougb persec = (xfr->nbytes * 1000) / msecs; 1425193149Sdougb xfrin_log(xfr, ISC_LOG_INFO, 1426193149Sdougb "Transfer completed: %d messages, %d records, " 1427193149Sdougb "%" ISC_PRINT_QUADFORMAT "u bytes, " 1428193149Sdougb "%u.%03u secs (%u bytes/sec)", 1429193149Sdougb xfr->nmsg, xfr->nrecs, xfr->nbytes, 1430193149Sdougb (unsigned int) (msecs / 1000), (unsigned int) (msecs % 1000), 1431193149Sdougb (unsigned int) persec); 1432135446Strhodes 1433135446Strhodes if (xfr->socket != NULL) 1434135446Strhodes isc_socket_detach(&xfr->socket); 1435135446Strhodes 1436135446Strhodes if (xfr->timer != NULL) 1437135446Strhodes isc_timer_detach(&xfr->timer); 1438135446Strhodes 1439135446Strhodes if (xfr->task != NULL) 1440135446Strhodes isc_task_detach(&xfr->task); 1441135446Strhodes 1442135446Strhodes if (xfr->tsigkey != NULL) 1443135446Strhodes dns_tsigkey_detach(&xfr->tsigkey); 1444135446Strhodes 1445135446Strhodes if (xfr->lasttsig != NULL) 1446135446Strhodes isc_buffer_free(&xfr->lasttsig); 1447135446Strhodes 1448135446Strhodes dns_diff_clear(&xfr->diff); 1449135446Strhodes 1450135446Strhodes if (xfr->ixfr.journal != NULL) 1451135446Strhodes dns_journal_destroy(&xfr->ixfr.journal); 1452135446Strhodes 1453135446Strhodes if (xfr->axfr.add_private != NULL) 1454135446Strhodes (void)dns_db_endload(xfr->db, &xfr->axfr.add_private); 1455135446Strhodes 1456135446Strhodes if (xfr->tcpmsg_valid) 1457135446Strhodes dns_tcpmsg_invalidate(&xfr->tcpmsg); 1458135446Strhodes 1459186462Sdougb if (xfr->tsigctx != NULL) 1460186462Sdougb dst_context_destroy(&xfr->tsigctx); 1461186462Sdougb 1462135446Strhodes if ((xfr->name.attributes & DNS_NAMEATTR_DYNAMIC) != 0) 1463135446Strhodes dns_name_free(&xfr->name, xfr->mctx); 1464135446Strhodes 1465135446Strhodes if (xfr->ver != NULL) 1466135446Strhodes dns_db_closeversion(xfr->db, &xfr->ver, ISC_FALSE); 1467135446Strhodes 1468135446Strhodes if (xfr->db != NULL) 1469135446Strhodes dns_db_detach(&xfr->db); 1470135446Strhodes 1471135446Strhodes if (xfr->zone != NULL) 1472135446Strhodes dns_zone_idetach(&xfr->zone); 1473135446Strhodes 1474254402Serwin isc_mem_putanddetach(&xfr->mctx, xfr, sizeof(*xfr)); 1475135446Strhodes} 1476135446Strhodes 1477135446Strhodes/* 1478135446Strhodes * Log incoming zone transfer messages in a format like 1479135446Strhodes * transfer of <zone> from <address>: <message> 1480135446Strhodes */ 1481135446Strhodesstatic void 1482170222Sdougbxfrin_logv(int level, const char *zonetext, isc_sockaddr_t *masteraddr, 1483170222Sdougb const char *fmt, va_list ap) 1484135446Strhodes{ 1485135446Strhodes char mastertext[ISC_SOCKADDR_FORMATSIZE]; 1486135446Strhodes char msgtext[2048]; 1487135446Strhodes 1488135446Strhodes isc_sockaddr_format(masteraddr, mastertext, sizeof(mastertext)); 1489135446Strhodes vsnprintf(msgtext, sizeof(msgtext), fmt, ap); 1490135446Strhodes 1491135446Strhodes isc_log_write(dns_lctx, DNS_LOGCATEGORY_XFER_IN, 1492135446Strhodes DNS_LOGMODULE_XFER_IN, level, 1493170222Sdougb "transfer of '%s' from %s: %s", 1494170222Sdougb zonetext, mastertext, msgtext); 1495135446Strhodes} 1496135446Strhodes 1497135446Strhodes/* 1498135446Strhodes * Logging function for use when a xfrin_ctx_t has not yet been created. 1499135446Strhodes */ 1500135446Strhodes 1501135446Strhodesstatic void 1502170222Sdougbxfrin_log1(int level, const char *zonetext, isc_sockaddr_t *masteraddr, 1503186462Sdougb const char *fmt, ...) 1504135446Strhodes{ 1505135446Strhodes va_list ap; 1506135446Strhodes 1507135446Strhodes if (isc_log_wouldlog(dns_lctx, level) == ISC_FALSE) 1508135446Strhodes return; 1509135446Strhodes 1510135446Strhodes va_start(ap, fmt); 1511170222Sdougb xfrin_logv(level, zonetext, masteraddr, fmt, ap); 1512135446Strhodes va_end(ap); 1513135446Strhodes} 1514135446Strhodes 1515135446Strhodes/* 1516135446Strhodes * Logging function for use when there is a xfrin_ctx_t. 1517135446Strhodes */ 1518135446Strhodes 1519135446Strhodesstatic void 1520153816Sdougbxfrin_log(dns_xfrin_ctx_t *xfr, int level, const char *fmt, ...) 1521135446Strhodes{ 1522135446Strhodes va_list ap; 1523170222Sdougb char zonetext[DNS_NAME_MAXTEXT+32]; 1524135446Strhodes 1525135446Strhodes if (isc_log_wouldlog(dns_lctx, level) == ISC_FALSE) 1526135446Strhodes return; 1527135446Strhodes 1528170222Sdougb dns_zone_name(xfr->zone, zonetext, sizeof(zonetext)); 1529170222Sdougb 1530135446Strhodes va_start(ap, fmt); 1531170222Sdougb xfrin_logv(level, zonetext, &xfr->masteraddr, fmt, ap); 1532135446Strhodes va_end(ap); 1533135446Strhodes} 1534