xfrout.c revision 225361
1135446Strhodes/* 2225361Sdougb * Copyright (C) 2004-2011 Internet Systems Consortium, Inc. ("ISC") 3135446Strhodes * Copyright (C) 1999-2003 Internet Software Consortium. 4135446Strhodes * 5193149Sdougb * 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 18225361Sdougb/* $Id: xfrout.c,v 1.139.16.3 2011-07-28 04:30:54 marka Exp $ */ 19135446Strhodes 20135446Strhodes#include <config.h> 21135446Strhodes 22135446Strhodes#include <isc/formatcheck.h> 23135446Strhodes#include <isc/mem.h> 24135446Strhodes#include <isc/timer.h> 25135446Strhodes#include <isc/print.h> 26193149Sdougb#include <isc/stats.h> 27135446Strhodes#include <isc/util.h> 28135446Strhodes 29135446Strhodes#include <dns/db.h> 30135446Strhodes#include <dns/dbiterator.h> 31170222Sdougb#include <dns/dlz.h> 32135446Strhodes#include <dns/fixedname.h> 33135446Strhodes#include <dns/journal.h> 34135446Strhodes#include <dns/message.h> 35135446Strhodes#include <dns/peer.h> 36135446Strhodes#include <dns/rdataclass.h> 37135446Strhodes#include <dns/rdatalist.h> 38135446Strhodes#include <dns/rdataset.h> 39135446Strhodes#include <dns/rdatasetiter.h> 40135446Strhodes#include <dns/result.h> 41224092Sdougb#include <dns/rriterator.h> 42135446Strhodes#include <dns/soa.h> 43193149Sdougb#include <dns/stats.h> 44135446Strhodes#include <dns/timer.h> 45135446Strhodes#include <dns/tsig.h> 46135446Strhodes#include <dns/view.h> 47135446Strhodes#include <dns/zone.h> 48135446Strhodes#include <dns/zt.h> 49135446Strhodes 50135446Strhodes#include <named/client.h> 51135446Strhodes#include <named/log.h> 52135446Strhodes#include <named/server.h> 53135446Strhodes#include <named/xfrout.h> 54135446Strhodes 55193149Sdougb/*! \file 56170222Sdougb * \brief 57135446Strhodes * Outgoing AXFR and IXFR. 58135446Strhodes */ 59135446Strhodes 60135446Strhodes/* 61135446Strhodes * TODO: 62135446Strhodes * - IXFR over UDP 63135446Strhodes */ 64135446Strhodes 65135446Strhodes#define XFROUT_COMMON_LOGARGS \ 66135446Strhodes ns_g_lctx, DNS_LOGCATEGORY_XFER_OUT, NS_LOGMODULE_XFER_OUT 67135446Strhodes 68135446Strhodes#define XFROUT_PROTOCOL_LOGARGS \ 69135446Strhodes XFROUT_COMMON_LOGARGS, ISC_LOG_INFO 70135446Strhodes 71135446Strhodes#define XFROUT_DEBUG_LOGARGS(n) \ 72135446Strhodes XFROUT_COMMON_LOGARGS, ISC_LOG_DEBUG(n) 73135446Strhodes 74135446Strhodes#define XFROUT_RR_LOGARGS \ 75135446Strhodes XFROUT_COMMON_LOGARGS, XFROUT_RR_LOGLEVEL 76135446Strhodes 77135446Strhodes#define XFROUT_RR_LOGLEVEL ISC_LOG_DEBUG(8) 78135446Strhodes 79170222Sdougb/*% 80135446Strhodes * Fail unconditionally and log as a client error. 81135446Strhodes * The test against ISC_R_SUCCESS is there to keep the Solaris compiler 82135446Strhodes * from complaining about "end-of-loop code not reached". 83135446Strhodes */ 84135446Strhodes#define FAILC(code, msg) \ 85135446Strhodes do { \ 86135446Strhodes result = (code); \ 87135446Strhodes ns_client_log(client, DNS_LOGCATEGORY_XFER_OUT, \ 88135446Strhodes NS_LOGMODULE_XFER_OUT, ISC_LOG_INFO, \ 89135446Strhodes "bad zone transfer request: %s (%s)", \ 90193149Sdougb msg, isc_result_totext(code)); \ 91135446Strhodes if (result != ISC_R_SUCCESS) goto failure; \ 92135446Strhodes } while (0) 93135446Strhodes 94135446Strhodes#define FAILQ(code, msg, question, rdclass) \ 95135446Strhodes do { \ 96135446Strhodes char _buf1[DNS_NAME_FORMATSIZE]; \ 97135446Strhodes char _buf2[DNS_RDATACLASS_FORMATSIZE]; \ 98135446Strhodes result = (code); \ 99135446Strhodes dns_name_format(question, _buf1, sizeof(_buf1)); \ 100135446Strhodes dns_rdataclass_format(rdclass, _buf2, sizeof(_buf2)); \ 101135446Strhodes ns_client_log(client, DNS_LOGCATEGORY_XFER_OUT, \ 102135446Strhodes NS_LOGMODULE_XFER_OUT, ISC_LOG_INFO, \ 103135446Strhodes "bad zone transfer request: '%s/%s': %s (%s)", \ 104193149Sdougb _buf1, _buf2, msg, isc_result_totext(code)); \ 105135446Strhodes if (result != ISC_R_SUCCESS) goto failure; \ 106135446Strhodes } while (0) 107135446Strhodes 108135446Strhodes#define CHECK(op) \ 109193149Sdougb do { result = (op); \ 110135446Strhodes if (result != ISC_R_SUCCESS) goto failure; \ 111135446Strhodes } while (0) 112135446Strhodes 113135446Strhodes/**************************************************************************/ 114135446Strhodes 115193149Sdougbstatic inline void 116193149Sdougbinc_stats(dns_zone_t *zone, isc_statscounter_t counter) { 117193149Sdougb isc_stats_increment(ns_g_server->nsstats, counter); 118193149Sdougb if (zone != NULL) { 119193149Sdougb isc_stats_t *zonestats = dns_zone_getrequeststats(zone); 120193149Sdougb if (zonestats != NULL) 121193149Sdougb isc_stats_increment(zonestats, counter); 122193149Sdougb } 123193149Sdougb} 124193149Sdougb 125135446Strhodes/**************************************************************************/ 126135446Strhodes 127170222Sdougb/*% Log an RR (for debugging) */ 128135446Strhodes 129135446Strhodesstatic void 130135446Strhodeslog_rr(dns_name_t *name, dns_rdata_t *rdata, isc_uint32_t ttl) { 131135446Strhodes isc_result_t result; 132135446Strhodes isc_buffer_t buf; 133135446Strhodes char mem[2000]; 134135446Strhodes dns_rdatalist_t rdl; 135135446Strhodes dns_rdataset_t rds; 136135446Strhodes dns_rdata_t rd = DNS_RDATA_INIT; 137135446Strhodes 138135446Strhodes rdl.type = rdata->type; 139135446Strhodes rdl.rdclass = rdata->rdclass; 140135446Strhodes rdl.ttl = ttl; 141193149Sdougb if (rdata->type == dns_rdatatype_sig || 142193149Sdougb rdata->type == dns_rdatatype_rrsig) 143193149Sdougb rdl.covers = dns_rdata_covers(rdata); 144193149Sdougb else 145193149Sdougb rdl.covers = dns_rdatatype_none; 146135446Strhodes ISC_LIST_INIT(rdl.rdata); 147135446Strhodes ISC_LINK_INIT(&rdl, link); 148135446Strhodes dns_rdataset_init(&rds); 149135446Strhodes dns_rdata_init(&rd); 150135446Strhodes dns_rdata_clone(rdata, &rd); 151135446Strhodes ISC_LIST_APPEND(rdl.rdata, &rd, link); 152135446Strhodes RUNTIME_CHECK(dns_rdatalist_tordataset(&rdl, &rds) == ISC_R_SUCCESS); 153135446Strhodes 154135446Strhodes isc_buffer_init(&buf, mem, sizeof(mem)); 155135446Strhodes result = dns_rdataset_totext(&rds, name, 156135446Strhodes ISC_FALSE, ISC_FALSE, &buf); 157135446Strhodes 158135446Strhodes /* 159135446Strhodes * We could use xfrout_log(), but that would produce 160135446Strhodes * very long lines with a repetitive prefix. 161135446Strhodes */ 162135446Strhodes if (result == ISC_R_SUCCESS) { 163135446Strhodes /* 164135446Strhodes * Get rid of final newline. 165135446Strhodes */ 166135446Strhodes INSIST(buf.used >= 1 && 167135446Strhodes ((char *) buf.base)[buf.used - 1] == '\n'); 168135446Strhodes buf.used--; 169193149Sdougb 170135446Strhodes isc_log_write(XFROUT_RR_LOGARGS, "%.*s", 171135446Strhodes (int)isc_buffer_usedlength(&buf), 172135446Strhodes (char *)isc_buffer_base(&buf)); 173135446Strhodes } else { 174135446Strhodes isc_log_write(XFROUT_RR_LOGARGS, "<RR too large to print>"); 175135446Strhodes } 176135446Strhodes} 177135446Strhodes 178135446Strhodes/**************************************************************************/ 179135446Strhodes/* 180135446Strhodes * An 'rrstream_t' is a polymorphic iterator that returns 181135446Strhodes * a stream of resource records. There are multiple implementations, 182135446Strhodes * e.g. for generating AXFR and IXFR records streams. 183135446Strhodes */ 184135446Strhodes 185135446Strhodestypedef struct rrstream_methods rrstream_methods_t; 186135446Strhodes 187135446Strhodestypedef struct rrstream { 188135446Strhodes isc_mem_t *mctx; 189135446Strhodes rrstream_methods_t *methods; 190135446Strhodes} rrstream_t; 191135446Strhodes 192135446Strhodesstruct rrstream_methods { 193135446Strhodes isc_result_t (*first)(rrstream_t *); 194135446Strhodes isc_result_t (*next)(rrstream_t *); 195135446Strhodes void (*current)(rrstream_t *, 196135446Strhodes dns_name_t **, 197135446Strhodes isc_uint32_t *, 198135446Strhodes dns_rdata_t **); 199135446Strhodes void (*pause)(rrstream_t *); 200135446Strhodes void (*destroy)(rrstream_t **); 201135446Strhodes}; 202135446Strhodes 203135446Strhodesstatic void 204135446Strhodesrrstream_noop_pause(rrstream_t *rs) { 205135446Strhodes UNUSED(rs); 206135446Strhodes} 207135446Strhodes 208135446Strhodes/**************************************************************************/ 209135446Strhodes/* 210135446Strhodes * An 'ixfr_rrstream_t' is an 'rrstream_t' that returns 211135446Strhodes * an IXFR-like RR stream from a journal file. 212135446Strhodes * 213135446Strhodes * The SOA at the beginning of each sequence of additions 214135446Strhodes * or deletions are included in the stream, but the extra 215135446Strhodes * SOAs at the beginning and end of the entire transfer are 216135446Strhodes * not included. 217135446Strhodes */ 218135446Strhodes 219135446Strhodestypedef struct ixfr_rrstream { 220135446Strhodes rrstream_t common; 221135446Strhodes dns_journal_t *journal; 222135446Strhodes} ixfr_rrstream_t; 223135446Strhodes 224135446Strhodes/* Forward declarations. */ 225135446Strhodesstatic void 226135446Strhodesixfr_rrstream_destroy(rrstream_t **sp); 227135446Strhodes 228135446Strhodesstatic rrstream_methods_t ixfr_rrstream_methods; 229135446Strhodes 230135446Strhodes/* 231135446Strhodes * Returns: anything dns_journal_open() or dns_journal_iter_init() 232135446Strhodes * may return. 233135446Strhodes */ 234135446Strhodes 235135446Strhodesstatic isc_result_t 236135446Strhodesixfr_rrstream_create(isc_mem_t *mctx, 237135446Strhodes const char *journal_filename, 238135446Strhodes isc_uint32_t begin_serial, 239135446Strhodes isc_uint32_t end_serial, 240135446Strhodes rrstream_t **sp) 241135446Strhodes{ 242135446Strhodes ixfr_rrstream_t *s; 243135446Strhodes isc_result_t result; 244135446Strhodes 245135446Strhodes INSIST(sp != NULL && *sp == NULL); 246135446Strhodes 247135446Strhodes s = isc_mem_get(mctx, sizeof(*s)); 248135446Strhodes if (s == NULL) 249135446Strhodes return (ISC_R_NOMEMORY); 250135446Strhodes s->common.mctx = mctx; 251135446Strhodes s->common.methods = &ixfr_rrstream_methods; 252135446Strhodes s->journal = NULL; 253135446Strhodes 254135446Strhodes CHECK(dns_journal_open(mctx, journal_filename, 255135446Strhodes ISC_FALSE, &s->journal)); 256135446Strhodes CHECK(dns_journal_iter_init(s->journal, begin_serial, end_serial)); 257135446Strhodes 258135446Strhodes *sp = (rrstream_t *) s; 259135446Strhodes return (ISC_R_SUCCESS); 260135446Strhodes 261135446Strhodes failure: 262135446Strhodes ixfr_rrstream_destroy((rrstream_t **) (void *)&s); 263135446Strhodes return (result); 264135446Strhodes} 265135446Strhodes 266135446Strhodesstatic isc_result_t 267135446Strhodesixfr_rrstream_first(rrstream_t *rs) { 268135446Strhodes ixfr_rrstream_t *s = (ixfr_rrstream_t *) rs; 269135446Strhodes return (dns_journal_first_rr(s->journal)); 270135446Strhodes} 271135446Strhodes 272135446Strhodesstatic isc_result_t 273135446Strhodesixfr_rrstream_next(rrstream_t *rs) { 274135446Strhodes ixfr_rrstream_t *s = (ixfr_rrstream_t *) rs; 275135446Strhodes return (dns_journal_next_rr(s->journal)); 276135446Strhodes} 277135446Strhodes 278135446Strhodesstatic void 279135446Strhodesixfr_rrstream_current(rrstream_t *rs, 280135446Strhodes dns_name_t **name, isc_uint32_t *ttl, 281135446Strhodes dns_rdata_t **rdata) 282135446Strhodes{ 283135446Strhodes ixfr_rrstream_t *s = (ixfr_rrstream_t *) rs; 284135446Strhodes dns_journal_current_rr(s->journal, name, ttl, rdata); 285135446Strhodes} 286135446Strhodes 287135446Strhodesstatic void 288135446Strhodesixfr_rrstream_destroy(rrstream_t **rsp) { 289135446Strhodes ixfr_rrstream_t *s = (ixfr_rrstream_t *) *rsp; 290135446Strhodes if (s->journal != 0) 291135446Strhodes dns_journal_destroy(&s->journal); 292135446Strhodes isc_mem_put(s->common.mctx, s, sizeof(*s)); 293135446Strhodes} 294135446Strhodes 295135446Strhodesstatic rrstream_methods_t ixfr_rrstream_methods = { 296135446Strhodes ixfr_rrstream_first, 297135446Strhodes ixfr_rrstream_next, 298135446Strhodes ixfr_rrstream_current, 299135446Strhodes rrstream_noop_pause, 300135446Strhodes ixfr_rrstream_destroy 301135446Strhodes}; 302135446Strhodes 303135446Strhodes/**************************************************************************/ 304135446Strhodes/* 305135446Strhodes * An 'axfr_rrstream_t' is an 'rrstream_t' that returns 306135446Strhodes * an AXFR-like RR stream from a database. 307135446Strhodes * 308135446Strhodes * The SOAs at the beginning and end of the transfer are 309135446Strhodes * not included in the stream. 310135446Strhodes */ 311135446Strhodes 312135446Strhodestypedef struct axfr_rrstream { 313135446Strhodes rrstream_t common; 314224092Sdougb dns_rriterator_t it; 315135446Strhodes isc_boolean_t it_valid; 316135446Strhodes} axfr_rrstream_t; 317135446Strhodes 318135446Strhodes/* 319135446Strhodes * Forward declarations. 320135446Strhodes */ 321135446Strhodesstatic void 322135446Strhodesaxfr_rrstream_destroy(rrstream_t **rsp); 323135446Strhodes 324135446Strhodesstatic rrstream_methods_t axfr_rrstream_methods; 325135446Strhodes 326135446Strhodesstatic isc_result_t 327135446Strhodesaxfr_rrstream_create(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *ver, 328135446Strhodes rrstream_t **sp) 329135446Strhodes{ 330135446Strhodes axfr_rrstream_t *s; 331135446Strhodes isc_result_t result; 332135446Strhodes 333135446Strhodes INSIST(sp != NULL && *sp == NULL); 334135446Strhodes 335135446Strhodes s = isc_mem_get(mctx, sizeof(*s)); 336135446Strhodes if (s == NULL) 337135446Strhodes return (ISC_R_NOMEMORY); 338135446Strhodes s->common.mctx = mctx; 339135446Strhodes s->common.methods = &axfr_rrstream_methods; 340135446Strhodes s->it_valid = ISC_FALSE; 341135446Strhodes 342224092Sdougb CHECK(dns_rriterator_init(&s->it, db, ver, 0)); 343135446Strhodes s->it_valid = ISC_TRUE; 344135446Strhodes 345135446Strhodes *sp = (rrstream_t *) s; 346135446Strhodes return (ISC_R_SUCCESS); 347135446Strhodes 348135446Strhodes failure: 349135446Strhodes axfr_rrstream_destroy((rrstream_t **) (void *)&s); 350135446Strhodes return (result); 351135446Strhodes} 352135446Strhodes 353135446Strhodesstatic isc_result_t 354135446Strhodesaxfr_rrstream_first(rrstream_t *rs) { 355135446Strhodes axfr_rrstream_t *s = (axfr_rrstream_t *) rs; 356135446Strhodes isc_result_t result; 357224092Sdougb result = dns_rriterator_first(&s->it); 358135446Strhodes if (result != ISC_R_SUCCESS) 359135446Strhodes return (result); 360135446Strhodes /* Skip SOA records. */ 361135446Strhodes for (;;) { 362135446Strhodes dns_name_t *name_dummy = NULL; 363135446Strhodes isc_uint32_t ttl_dummy; 364135446Strhodes dns_rdata_t *rdata = NULL; 365224092Sdougb dns_rriterator_current(&s->it, &name_dummy, 366224092Sdougb &ttl_dummy, NULL, &rdata); 367135446Strhodes if (rdata->type != dns_rdatatype_soa) 368135446Strhodes break; 369224092Sdougb result = dns_rriterator_next(&s->it); 370135446Strhodes if (result != ISC_R_SUCCESS) 371135446Strhodes break; 372135446Strhodes } 373135446Strhodes return (result); 374135446Strhodes} 375135446Strhodes 376135446Strhodesstatic isc_result_t 377135446Strhodesaxfr_rrstream_next(rrstream_t *rs) { 378135446Strhodes axfr_rrstream_t *s = (axfr_rrstream_t *) rs; 379135446Strhodes isc_result_t result; 380135446Strhodes 381135446Strhodes /* Skip SOA records. */ 382135446Strhodes for (;;) { 383135446Strhodes dns_name_t *name_dummy = NULL; 384135446Strhodes isc_uint32_t ttl_dummy; 385135446Strhodes dns_rdata_t *rdata = NULL; 386224092Sdougb result = dns_rriterator_next(&s->it); 387135446Strhodes if (result != ISC_R_SUCCESS) 388135446Strhodes break; 389224092Sdougb dns_rriterator_current(&s->it, &name_dummy, 390224092Sdougb &ttl_dummy, NULL, &rdata); 391135446Strhodes if (rdata->type != dns_rdatatype_soa) 392135446Strhodes break; 393135446Strhodes } 394135446Strhodes return (result); 395135446Strhodes} 396135446Strhodes 397135446Strhodesstatic void 398135446Strhodesaxfr_rrstream_current(rrstream_t *rs, dns_name_t **name, isc_uint32_t *ttl, 399135446Strhodes dns_rdata_t **rdata) 400135446Strhodes{ 401135446Strhodes axfr_rrstream_t *s = (axfr_rrstream_t *) rs; 402224092Sdougb dns_rriterator_current(&s->it, name, ttl, NULL, rdata); 403135446Strhodes} 404135446Strhodes 405135446Strhodesstatic void 406135446Strhodesaxfr_rrstream_pause(rrstream_t *rs) { 407135446Strhodes axfr_rrstream_t *s = (axfr_rrstream_t *) rs; 408224092Sdougb dns_rriterator_pause(&s->it); 409135446Strhodes} 410135446Strhodes 411135446Strhodesstatic void 412135446Strhodesaxfr_rrstream_destroy(rrstream_t **rsp) { 413135446Strhodes axfr_rrstream_t *s = (axfr_rrstream_t *) *rsp; 414135446Strhodes if (s->it_valid) 415224092Sdougb dns_rriterator_destroy(&s->it); 416135446Strhodes isc_mem_put(s->common.mctx, s, sizeof(*s)); 417135446Strhodes} 418135446Strhodes 419135446Strhodesstatic rrstream_methods_t axfr_rrstream_methods = { 420135446Strhodes axfr_rrstream_first, 421135446Strhodes axfr_rrstream_next, 422135446Strhodes axfr_rrstream_current, 423135446Strhodes axfr_rrstream_pause, 424135446Strhodes axfr_rrstream_destroy 425135446Strhodes}; 426135446Strhodes 427135446Strhodes/**************************************************************************/ 428135446Strhodes/* 429135446Strhodes * An 'soa_rrstream_t' is a degenerate 'rrstream_t' that returns 430135446Strhodes * a single SOA record. 431135446Strhodes */ 432135446Strhodes 433135446Strhodestypedef struct soa_rrstream { 434135446Strhodes rrstream_t common; 435135446Strhodes dns_difftuple_t *soa_tuple; 436135446Strhodes} soa_rrstream_t; 437135446Strhodes 438135446Strhodes/* 439135446Strhodes * Forward declarations. 440135446Strhodes */ 441135446Strhodesstatic void 442135446Strhodessoa_rrstream_destroy(rrstream_t **rsp); 443135446Strhodes 444135446Strhodesstatic rrstream_methods_t soa_rrstream_methods; 445135446Strhodes 446135446Strhodesstatic isc_result_t 447135446Strhodessoa_rrstream_create(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *ver, 448135446Strhodes rrstream_t **sp) 449135446Strhodes{ 450135446Strhodes soa_rrstream_t *s; 451135446Strhodes isc_result_t result; 452135446Strhodes 453135446Strhodes INSIST(sp != NULL && *sp == NULL); 454135446Strhodes 455135446Strhodes s = isc_mem_get(mctx, sizeof(*s)); 456135446Strhodes if (s == NULL) 457135446Strhodes return (ISC_R_NOMEMORY); 458135446Strhodes s->common.mctx = mctx; 459135446Strhodes s->common.methods = &soa_rrstream_methods; 460135446Strhodes s->soa_tuple = NULL; 461135446Strhodes 462135446Strhodes CHECK(dns_db_createsoatuple(db, ver, mctx, DNS_DIFFOP_EXISTS, 463135446Strhodes &s->soa_tuple)); 464135446Strhodes 465135446Strhodes *sp = (rrstream_t *) s; 466135446Strhodes return (ISC_R_SUCCESS); 467135446Strhodes 468135446Strhodes failure: 469135446Strhodes soa_rrstream_destroy((rrstream_t **) (void *)&s); 470135446Strhodes return (result); 471135446Strhodes} 472135446Strhodes 473135446Strhodesstatic isc_result_t 474135446Strhodessoa_rrstream_first(rrstream_t *rs) { 475135446Strhodes UNUSED(rs); 476135446Strhodes return (ISC_R_SUCCESS); 477135446Strhodes} 478135446Strhodes 479135446Strhodesstatic isc_result_t 480135446Strhodessoa_rrstream_next(rrstream_t *rs) { 481135446Strhodes UNUSED(rs); 482135446Strhodes return (ISC_R_NOMORE); 483135446Strhodes} 484135446Strhodes 485135446Strhodesstatic void 486135446Strhodessoa_rrstream_current(rrstream_t *rs, dns_name_t **name, isc_uint32_t *ttl, 487135446Strhodes dns_rdata_t **rdata) 488135446Strhodes{ 489135446Strhodes soa_rrstream_t *s = (soa_rrstream_t *) rs; 490135446Strhodes *name = &s->soa_tuple->name; 491135446Strhodes *ttl = s->soa_tuple->ttl; 492135446Strhodes *rdata = &s->soa_tuple->rdata; 493135446Strhodes} 494135446Strhodes 495135446Strhodesstatic void 496135446Strhodessoa_rrstream_destroy(rrstream_t **rsp) { 497135446Strhodes soa_rrstream_t *s = (soa_rrstream_t *) *rsp; 498135446Strhodes if (s->soa_tuple != NULL) 499135446Strhodes dns_difftuple_free(&s->soa_tuple); 500135446Strhodes isc_mem_put(s->common.mctx, s, sizeof(*s)); 501135446Strhodes} 502135446Strhodes 503135446Strhodesstatic rrstream_methods_t soa_rrstream_methods = { 504135446Strhodes soa_rrstream_first, 505135446Strhodes soa_rrstream_next, 506135446Strhodes soa_rrstream_current, 507135446Strhodes rrstream_noop_pause, 508135446Strhodes soa_rrstream_destroy 509135446Strhodes}; 510135446Strhodes 511135446Strhodes/**************************************************************************/ 512135446Strhodes/* 513135446Strhodes * A 'compound_rrstream_t' objects owns a soa_rrstream 514135446Strhodes * and another rrstream, the "data stream". It returns 515135446Strhodes * a concatenated stream consisting of the soa_rrstream, then 516135446Strhodes * the data stream, then the soa_rrstream again. 517135446Strhodes * 518135446Strhodes * The component streams are owned by the compound_rrstream_t 519135446Strhodes * and are destroyed with it. 520135446Strhodes */ 521135446Strhodes 522135446Strhodestypedef struct compound_rrstream { 523135446Strhodes rrstream_t common; 524135446Strhodes rrstream_t *components[3]; 525135446Strhodes int state; 526135446Strhodes isc_result_t result; 527135446Strhodes} compound_rrstream_t; 528135446Strhodes 529135446Strhodes/* 530135446Strhodes * Forward declarations. 531135446Strhodes */ 532135446Strhodesstatic void 533135446Strhodescompound_rrstream_destroy(rrstream_t **rsp); 534135446Strhodes 535135446Strhodesstatic isc_result_t 536135446Strhodescompound_rrstream_next(rrstream_t *rs); 537135446Strhodes 538135446Strhodesstatic rrstream_methods_t compound_rrstream_methods; 539135446Strhodes 540135446Strhodes/* 541135446Strhodes * Requires: 542135446Strhodes * soa_stream != NULL && *soa_stream != NULL 543135446Strhodes * data_stream != NULL && *data_stream != NULL 544135446Strhodes * sp != NULL && *sp == NULL 545135446Strhodes * 546135446Strhodes * Ensures: 547135446Strhodes * *soa_stream == NULL 548135446Strhodes * *data_stream == NULL 549135446Strhodes * *sp points to a valid compound_rrstream_t 550135446Strhodes * The soa and data streams will be destroyed 551135446Strhodes * when the compound_rrstream_t is destroyed. 552135446Strhodes */ 553135446Strhodesstatic isc_result_t 554135446Strhodescompound_rrstream_create(isc_mem_t *mctx, rrstream_t **soa_stream, 555135446Strhodes rrstream_t **data_stream, rrstream_t **sp) 556135446Strhodes{ 557135446Strhodes compound_rrstream_t *s; 558135446Strhodes 559135446Strhodes INSIST(sp != NULL && *sp == NULL); 560135446Strhodes 561135446Strhodes s = isc_mem_get(mctx, sizeof(*s)); 562135446Strhodes if (s == NULL) 563135446Strhodes return (ISC_R_NOMEMORY); 564135446Strhodes s->common.mctx = mctx; 565135446Strhodes s->common.methods = &compound_rrstream_methods; 566135446Strhodes s->components[0] = *soa_stream; 567135446Strhodes s->components[1] = *data_stream; 568135446Strhodes s->components[2] = *soa_stream; 569135446Strhodes s->state = -1; 570135446Strhodes s->result = ISC_R_FAILURE; 571135446Strhodes 572135446Strhodes *soa_stream = NULL; 573135446Strhodes *data_stream = NULL; 574135446Strhodes *sp = (rrstream_t *) s; 575135446Strhodes return (ISC_R_SUCCESS); 576135446Strhodes} 577135446Strhodes 578135446Strhodesstatic isc_result_t 579135446Strhodescompound_rrstream_first(rrstream_t *rs) { 580135446Strhodes compound_rrstream_t *s = (compound_rrstream_t *) rs; 581135446Strhodes s->state = 0; 582135446Strhodes do { 583135446Strhodes rrstream_t *curstream = s->components[s->state]; 584135446Strhodes s->result = curstream->methods->first(curstream); 585135446Strhodes } while (s->result == ISC_R_NOMORE && s->state < 2); 586135446Strhodes return (s->result); 587135446Strhodes} 588135446Strhodes 589135446Strhodesstatic isc_result_t 590135446Strhodescompound_rrstream_next(rrstream_t *rs) { 591135446Strhodes compound_rrstream_t *s = (compound_rrstream_t *) rs; 592135446Strhodes rrstream_t *curstream = s->components[s->state]; 593135446Strhodes s->result = curstream->methods->next(curstream); 594135446Strhodes while (s->result == ISC_R_NOMORE) { 595135446Strhodes /* 596135446Strhodes * Make sure locks held by the current stream 597135446Strhodes * are released before we switch streams. 598135446Strhodes */ 599135446Strhodes curstream->methods->pause(curstream); 600135446Strhodes if (s->state == 2) 601135446Strhodes return (ISC_R_NOMORE); 602135446Strhodes s->state++; 603135446Strhodes curstream = s->components[s->state]; 604135446Strhodes s->result = curstream->methods->first(curstream); 605135446Strhodes } 606135446Strhodes return (s->result); 607135446Strhodes} 608135446Strhodes 609135446Strhodesstatic void 610135446Strhodescompound_rrstream_current(rrstream_t *rs, dns_name_t **name, isc_uint32_t *ttl, 611135446Strhodes dns_rdata_t **rdata) 612135446Strhodes{ 613135446Strhodes compound_rrstream_t *s = (compound_rrstream_t *) rs; 614135446Strhodes rrstream_t *curstream; 615135446Strhodes INSIST(0 <= s->state && s->state < 3); 616135446Strhodes INSIST(s->result == ISC_R_SUCCESS); 617135446Strhodes curstream = s->components[s->state]; 618135446Strhodes curstream->methods->current(curstream, name, ttl, rdata); 619135446Strhodes} 620135446Strhodes 621135446Strhodesstatic void 622135446Strhodescompound_rrstream_pause(rrstream_t *rs) 623135446Strhodes{ 624135446Strhodes compound_rrstream_t *s = (compound_rrstream_t *) rs; 625135446Strhodes rrstream_t *curstream; 626135446Strhodes INSIST(0 <= s->state && s->state < 3); 627135446Strhodes curstream = s->components[s->state]; 628135446Strhodes curstream->methods->pause(curstream); 629135446Strhodes} 630135446Strhodes 631135446Strhodesstatic void 632135446Strhodescompound_rrstream_destroy(rrstream_t **rsp) { 633135446Strhodes compound_rrstream_t *s = (compound_rrstream_t *) *rsp; 634135446Strhodes s->components[0]->methods->destroy(&s->components[0]); 635135446Strhodes s->components[1]->methods->destroy(&s->components[1]); 636135446Strhodes s->components[2] = NULL; /* Copy of components[0]. */ 637135446Strhodes isc_mem_put(s->common.mctx, s, sizeof(*s)); 638135446Strhodes} 639135446Strhodes 640135446Strhodesstatic rrstream_methods_t compound_rrstream_methods = { 641135446Strhodes compound_rrstream_first, 642135446Strhodes compound_rrstream_next, 643135446Strhodes compound_rrstream_current, 644135446Strhodes compound_rrstream_pause, 645135446Strhodes compound_rrstream_destroy 646135446Strhodes}; 647135446Strhodes 648135446Strhodes/**************************************************************************/ 649135446Strhodes/* 650135446Strhodes * An 'xfrout_ctx_t' contains the state of an outgoing AXFR or IXFR 651135446Strhodes * in progress. 652135446Strhodes */ 653135446Strhodes 654135446Strhodestypedef struct { 655135446Strhodes isc_mem_t *mctx; 656135446Strhodes ns_client_t *client; 657135446Strhodes unsigned int id; /* ID of request */ 658135446Strhodes dns_name_t *qname; /* Question name of request */ 659135446Strhodes dns_rdatatype_t qtype; /* dns_rdatatype_{a,i}xfr */ 660135446Strhodes dns_rdataclass_t qclass; 661193149Sdougb dns_zone_t *zone; /* (necessary for stats) */ 662135446Strhodes dns_db_t *db; 663135446Strhodes dns_dbversion_t *ver; 664135446Strhodes isc_quota_t *quota; 665135446Strhodes rrstream_t *stream; /* The XFR RR stream */ 666135446Strhodes isc_boolean_t end_of_stream; /* EOS has been reached */ 667135446Strhodes isc_buffer_t buf; /* Buffer for message owner 668135446Strhodes names and rdatas */ 669135446Strhodes isc_buffer_t txlenbuf; /* Transmit length buffer */ 670135446Strhodes isc_buffer_t txbuf; /* Transmit message buffer */ 671135446Strhodes void *txmem; 672135446Strhodes unsigned int txmemlen; 673135446Strhodes unsigned int nmsg; /* Number of messages sent */ 674135446Strhodes dns_tsigkey_t *tsigkey; /* Key used to create TSIG */ 675135446Strhodes isc_buffer_t *lasttsig; /* the last TSIG */ 676135446Strhodes isc_boolean_t many_answers; 677135446Strhodes int sends; /* Send in progress */ 678135446Strhodes isc_boolean_t shuttingdown; 679135446Strhodes const char *mnemonic; /* Style of transfer */ 680135446Strhodes} xfrout_ctx_t; 681135446Strhodes 682135446Strhodesstatic isc_result_t 683135446Strhodesxfrout_ctx_create(isc_mem_t *mctx, ns_client_t *client, 684135446Strhodes unsigned int id, dns_name_t *qname, dns_rdatatype_t qtype, 685193149Sdougb dns_rdataclass_t qclass, dns_zone_t *zone, 686135446Strhodes dns_db_t *db, dns_dbversion_t *ver, isc_quota_t *quota, 687135446Strhodes rrstream_t *stream, dns_tsigkey_t *tsigkey, 688135446Strhodes isc_buffer_t *lasttsig, 689135446Strhodes unsigned int maxtime, 690135446Strhodes unsigned int idletime, 691135446Strhodes isc_boolean_t many_answers, 692135446Strhodes xfrout_ctx_t **xfrp); 693135446Strhodes 694135446Strhodesstatic void 695135446Strhodessendstream(xfrout_ctx_t *xfr); 696135446Strhodes 697135446Strhodesstatic void 698135446Strhodesxfrout_senddone(isc_task_t *task, isc_event_t *event); 699135446Strhodes 700135446Strhodesstatic void 701135446Strhodesxfrout_fail(xfrout_ctx_t *xfr, isc_result_t result, const char *msg); 702135446Strhodes 703135446Strhodesstatic void 704135446Strhodesxfrout_maybe_destroy(xfrout_ctx_t *xfr); 705135446Strhodes 706135446Strhodesstatic void 707135446Strhodesxfrout_ctx_destroy(xfrout_ctx_t **xfrp); 708135446Strhodes 709135446Strhodesstatic void 710135446Strhodesxfrout_client_shutdown(void *arg, isc_result_t result); 711135446Strhodes 712135446Strhodesstatic void 713135446Strhodesxfrout_log1(ns_client_t *client, dns_name_t *zonename, 714135446Strhodes dns_rdataclass_t rdclass, int level, 715135446Strhodes const char *fmt, ...) ISC_FORMAT_PRINTF(5, 6); 716135446Strhodes 717135446Strhodesstatic void 718153816Sdougbxfrout_log(xfrout_ctx_t *xfr, int level, const char *fmt, ...) 719135446Strhodes ISC_FORMAT_PRINTF(3, 4); 720135446Strhodes 721135446Strhodes/**************************************************************************/ 722135446Strhodes 723135446Strhodesvoid 724135446Strhodesns_xfr_start(ns_client_t *client, dns_rdatatype_t reqtype) { 725135446Strhodes isc_result_t result; 726135446Strhodes dns_name_t *question_name; 727135446Strhodes dns_rdataset_t *question_rdataset; 728135446Strhodes dns_zone_t *zone = NULL; 729135446Strhodes dns_db_t *db = NULL; 730135446Strhodes dns_dbversion_t *ver = NULL; 731135446Strhodes dns_rdataclass_t question_class; 732135446Strhodes rrstream_t *soa_stream = NULL; 733135446Strhodes rrstream_t *data_stream = NULL; 734135446Strhodes rrstream_t *stream = NULL; 735135446Strhodes dns_difftuple_t *current_soa_tuple = NULL; 736135446Strhodes dns_name_t *soa_name; 737135446Strhodes dns_rdataset_t *soa_rdataset; 738135446Strhodes dns_rdata_t soa_rdata = DNS_RDATA_INIT; 739135446Strhodes isc_boolean_t have_soa = ISC_FALSE; 740135446Strhodes const char *mnemonic = NULL; 741135446Strhodes isc_mem_t *mctx = client->mctx; 742135446Strhodes dns_message_t *request = client->message; 743135446Strhodes xfrout_ctx_t *xfr = NULL; 744135446Strhodes isc_quota_t *quota = NULL; 745135446Strhodes dns_transfer_format_t format = client->view->transfer_format; 746135446Strhodes isc_netaddr_t na; 747135446Strhodes dns_peer_t *peer = NULL; 748135446Strhodes isc_buffer_t *tsigbuf = NULL; 749135446Strhodes char *journalfile; 750135446Strhodes char msg[NS_CLIENT_ACLMSGSIZE("zone transfer")]; 751135446Strhodes char keyname[DNS_NAME_FORMATSIZE]; 752135446Strhodes isc_boolean_t is_poll = ISC_FALSE; 753170222Sdougb isc_boolean_t is_dlz = ISC_FALSE; 754135446Strhodes 755135446Strhodes switch (reqtype) { 756135446Strhodes case dns_rdatatype_axfr: 757135446Strhodes mnemonic = "AXFR"; 758135446Strhodes break; 759135446Strhodes case dns_rdatatype_ixfr: 760135446Strhodes mnemonic = "IXFR"; 761135446Strhodes break; 762135446Strhodes default: 763135446Strhodes INSIST(0); 764135446Strhodes break; 765135446Strhodes } 766135446Strhodes 767135446Strhodes ns_client_log(client, 768135446Strhodes DNS_LOGCATEGORY_XFER_OUT, NS_LOGMODULE_XFER_OUT, 769135446Strhodes ISC_LOG_DEBUG(6), "%s request", mnemonic); 770135446Strhodes /* 771135446Strhodes * Apply quota. 772135446Strhodes */ 773135446Strhodes result = isc_quota_attach(&ns_g_server->xfroutquota, "a); 774135446Strhodes if (result != ISC_R_SUCCESS) { 775135446Strhodes isc_log_write(XFROUT_COMMON_LOGARGS, ISC_LOG_WARNING, 776135446Strhodes "%s request denied: %s", mnemonic, 777135446Strhodes isc_result_totext(result)); 778135446Strhodes goto failure; 779135446Strhodes } 780135446Strhodes 781135446Strhodes /* 782135446Strhodes * Interpret the question section. 783135446Strhodes */ 784135446Strhodes result = dns_message_firstname(request, DNS_SECTION_QUESTION); 785135446Strhodes INSIST(result == ISC_R_SUCCESS); 786135446Strhodes 787135446Strhodes /* 788135446Strhodes * The question section must contain exactly one question, and 789135446Strhodes * it must be for AXFR/IXFR as appropriate. 790135446Strhodes */ 791135446Strhodes question_name = NULL; 792135446Strhodes dns_message_currentname(request, DNS_SECTION_QUESTION, &question_name); 793135446Strhodes question_rdataset = ISC_LIST_HEAD(question_name->list); 794135446Strhodes question_class = question_rdataset->rdclass; 795135446Strhodes INSIST(question_rdataset->type == reqtype); 796135446Strhodes if (ISC_LIST_NEXT(question_rdataset, link) != NULL) 797135446Strhodes FAILC(DNS_R_FORMERR, "multiple questions"); 798135446Strhodes result = dns_message_nextname(request, DNS_SECTION_QUESTION); 799135446Strhodes if (result != ISC_R_NOMORE) 800135446Strhodes FAILC(DNS_R_FORMERR, "multiple questions"); 801135446Strhodes 802135446Strhodes result = dns_zt_find(client->view->zonetable, question_name, 0, NULL, 803135446Strhodes &zone); 804170222Sdougb 805225361Sdougb if (result != ISC_R_SUCCESS) { 806170222Sdougb /* 807218384Sdougb * Normal zone table does not have a match. 808218384Sdougb * Try the DLZ database 809170222Sdougb */ 810193149Sdougb if (client->view->dlzdatabase != NULL) { 811170222Sdougb result = dns_dlzallowzonexfr(client->view, 812218384Sdougb question_name, 813218384Sdougb &client->peeraddr, 814170222Sdougb &db); 815170222Sdougb 816170222Sdougb if (result == ISC_R_NOPERM) { 817170222Sdougb char _buf1[DNS_NAME_FORMATSIZE]; 818170222Sdougb char _buf2[DNS_RDATACLASS_FORMATSIZE]; 819170222Sdougb 820170222Sdougb result = DNS_R_REFUSED; 821170222Sdougb dns_name_format(question_name, _buf1, 822170222Sdougb sizeof(_buf1)); 823170222Sdougb dns_rdataclass_format(question_class, 824170222Sdougb _buf2, sizeof(_buf2)); 825170222Sdougb ns_client_log(client, DNS_LOGCATEGORY_SECURITY, 826170222Sdougb NS_LOGMODULE_XFER_OUT, 827170222Sdougb ISC_LOG_ERROR, 828170222Sdougb "zone transfer '%s/%s' denied", 829170222Sdougb _buf1, _buf2); 830170222Sdougb goto failure; 831170222Sdougb } 832170222Sdougb if (result != ISC_R_SUCCESS) 833225361Sdougb FAILQ(DNS_R_NOTAUTH, "non-authoritative zone", 834225361Sdougb question_name, question_class); 835170222Sdougb is_dlz = ISC_TRUE; 836170222Sdougb /* 837170222Sdougb * DLZ only support full zone transfer, not incremental 838170222Sdougb */ 839170222Sdougb if (reqtype != dns_rdatatype_axfr) { 840170222Sdougb mnemonic = "AXFR-style IXFR"; 841170222Sdougb reqtype = dns_rdatatype_axfr; 842170222Sdougb } 843170222Sdougb 844170222Sdougb } else { 845170222Sdougb /* 846193149Sdougb * not DLZ and not in normal zone table, we are 847170222Sdougb * not authoritative 848170222Sdougb */ 849170222Sdougb FAILQ(DNS_R_NOTAUTH, "non-authoritative zone", 850170222Sdougb question_name, question_class); 851170222Sdougb } 852170222Sdougb } else { 853170222Sdougb /* zone table has a match */ 854170222Sdougb switch(dns_zone_gettype(zone)) { 855170222Sdougb case dns_zone_master: 856170222Sdougb case dns_zone_slave: 857224092Sdougb case dns_zone_dlz: 858170222Sdougb break; /* Master and slave zones are OK for transfer. */ 859170222Sdougb default: 860170222Sdougb FAILQ(DNS_R_NOTAUTH, "non-authoritative zone", question_name, question_class); 861170222Sdougb } 862170222Sdougb CHECK(dns_zone_getdb(zone, &db)); 863170222Sdougb dns_db_currentversion(db, &ver); 864135446Strhodes } 865135446Strhodes 866135446Strhodes xfrout_log1(client, question_name, question_class, ISC_LOG_DEBUG(6), 867135446Strhodes "%s question section OK", mnemonic); 868135446Strhodes 869135446Strhodes /* 870135446Strhodes * Check the authority section. Look for a SOA record with 871135446Strhodes * the same name and class as the question. 872135446Strhodes */ 873135446Strhodes for (result = dns_message_firstname(request, DNS_SECTION_AUTHORITY); 874135446Strhodes result == ISC_R_SUCCESS; 875135446Strhodes result = dns_message_nextname(request, DNS_SECTION_AUTHORITY)) 876135446Strhodes { 877135446Strhodes soa_name = NULL; 878135446Strhodes dns_message_currentname(request, DNS_SECTION_AUTHORITY, 879135446Strhodes &soa_name); 880135446Strhodes 881135446Strhodes /* 882135446Strhodes * Ignore data whose owner name is not the zone apex. 883135446Strhodes */ 884135446Strhodes if (! dns_name_equal(soa_name, question_name)) 885135446Strhodes continue; 886135446Strhodes 887135446Strhodes for (soa_rdataset = ISC_LIST_HEAD(soa_name->list); 888135446Strhodes soa_rdataset != NULL; 889135446Strhodes soa_rdataset = ISC_LIST_NEXT(soa_rdataset, link)) 890135446Strhodes { 891135446Strhodes /* 892135446Strhodes * Ignore non-SOA data. 893135446Strhodes */ 894135446Strhodes if (soa_rdataset->type != dns_rdatatype_soa) 895135446Strhodes continue; 896135446Strhodes if (soa_rdataset->rdclass != question_class) 897135446Strhodes continue; 898135446Strhodes 899135446Strhodes CHECK(dns_rdataset_first(soa_rdataset)); 900135446Strhodes dns_rdataset_current(soa_rdataset, &soa_rdata); 901135446Strhodes result = dns_rdataset_next(soa_rdataset); 902135446Strhodes if (result == ISC_R_SUCCESS) 903135446Strhodes FAILC(DNS_R_FORMERR, 904135446Strhodes "IXFR authority section " 905135446Strhodes "has multiple SOAs"); 906135446Strhodes have_soa = ISC_TRUE; 907135446Strhodes goto got_soa; 908135446Strhodes } 909135446Strhodes } 910135446Strhodes got_soa: 911135446Strhodes if (result != ISC_R_NOMORE) 912135446Strhodes CHECK(result); 913135446Strhodes 914135446Strhodes xfrout_log1(client, question_name, question_class, ISC_LOG_DEBUG(6), 915135446Strhodes "%s authority section OK", mnemonic); 916135446Strhodes 917135446Strhodes /* 918225361Sdougb * If not a DLZ zone, decide whether to allow this transfer. 919135446Strhodes */ 920170222Sdougb if (!is_dlz) { 921170222Sdougb ns_client_aclmsg("zone transfer", question_name, reqtype, 922170222Sdougb client->view->rdclass, msg, sizeof(msg)); 923193149Sdougb CHECK(ns_client_checkacl(client, NULL, msg, 924193149Sdougb dns_zone_getxfracl(zone), 925193149Sdougb ISC_TRUE, ISC_LOG_ERROR)); 926170222Sdougb } 927135446Strhodes 928135446Strhodes /* 929135446Strhodes * AXFR over UDP is not possible. 930135446Strhodes */ 931135446Strhodes if (reqtype == dns_rdatatype_axfr && 932135446Strhodes (client->attributes & NS_CLIENTATTR_TCP) == 0) 933135446Strhodes FAILC(DNS_R_FORMERR, "attempted AXFR over UDP"); 934135446Strhodes 935135446Strhodes /* 936135446Strhodes * Look up the requesting server in the peer table. 937135446Strhodes */ 938135446Strhodes isc_netaddr_fromsockaddr(&na, &client->peeraddr); 939135446Strhodes (void)dns_peerlist_peerbyaddr(client->view->peers, &na, &peer); 940135446Strhodes 941135446Strhodes /* 942135446Strhodes * Decide on the transfer format (one-answer or many-answers). 943135446Strhodes */ 944135446Strhodes if (peer != NULL) 945135446Strhodes (void)dns_peer_gettransferformat(peer, &format); 946135446Strhodes 947135446Strhodes /* 948135446Strhodes * Get a dynamically allocated copy of the current SOA. 949135446Strhodes */ 950170222Sdougb if (is_dlz) 951170222Sdougb dns_db_currentversion(db, &ver); 952225361Sdougb 953135446Strhodes CHECK(dns_db_createsoatuple(db, ver, mctx, DNS_DIFFOP_EXISTS, 954135446Strhodes ¤t_soa_tuple)); 955135446Strhodes 956135446Strhodes if (reqtype == dns_rdatatype_ixfr) { 957135446Strhodes isc_uint32_t begin_serial, current_serial; 958135446Strhodes isc_boolean_t provide_ixfr; 959135446Strhodes 960135446Strhodes /* 961135446Strhodes * Outgoing IXFR may have been disabled for this peer 962135446Strhodes * or globally. 963135446Strhodes */ 964135446Strhodes provide_ixfr = client->view->provideixfr; 965135446Strhodes if (peer != NULL) 966135446Strhodes (void) dns_peer_getprovideixfr(peer, &provide_ixfr); 967135446Strhodes if (provide_ixfr == ISC_FALSE) 968135446Strhodes goto axfr_fallback; 969135446Strhodes 970135446Strhodes if (! have_soa) 971135446Strhodes FAILC(DNS_R_FORMERR, 972135446Strhodes "IXFR request missing SOA"); 973135446Strhodes 974135446Strhodes begin_serial = dns_soa_getserial(&soa_rdata); 975135446Strhodes current_serial = dns_soa_getserial(¤t_soa_tuple->rdata); 976135446Strhodes 977135446Strhodes /* 978135446Strhodes * RFC1995 says "If an IXFR query with the same or 979135446Strhodes * newer version number than that of the server 980135446Strhodes * is received, it is replied to with a single SOA 981135446Strhodes * record of the server's current version, just as 982135446Strhodes * in AXFR". The claim about AXFR is incorrect, 983135446Strhodes * but other than that, we do as the RFC says. 984135446Strhodes * 985135446Strhodes * Sending a single SOA record is also how we refuse 986135446Strhodes * IXFR over UDP (currently, we always do). 987135446Strhodes */ 988135446Strhodes if (DNS_SERIAL_GE(begin_serial, current_serial) || 989135446Strhodes (client->attributes & NS_CLIENTATTR_TCP) == 0) 990135446Strhodes { 991135446Strhodes CHECK(soa_rrstream_create(mctx, db, ver, &stream)); 992135446Strhodes is_poll = ISC_TRUE; 993135446Strhodes goto have_stream; 994135446Strhodes } 995135446Strhodes journalfile = dns_zone_getjournal(zone); 996135446Strhodes if (journalfile != NULL) 997135446Strhodes result = ixfr_rrstream_create(mctx, 998135446Strhodes journalfile, 999135446Strhodes begin_serial, 1000135446Strhodes current_serial, 1001135446Strhodes &data_stream); 1002135446Strhodes else 1003135446Strhodes result = ISC_R_NOTFOUND; 1004135446Strhodes if (result == ISC_R_NOTFOUND || 1005135446Strhodes result == ISC_R_RANGE) { 1006135446Strhodes xfrout_log1(client, question_name, question_class, 1007135446Strhodes ISC_LOG_DEBUG(4), 1008135446Strhodes "IXFR version not in journal, " 1009135446Strhodes "falling back to AXFR"); 1010135446Strhodes mnemonic = "AXFR-style IXFR"; 1011135446Strhodes goto axfr_fallback; 1012135446Strhodes } 1013135446Strhodes CHECK(result); 1014135446Strhodes } else { 1015135446Strhodes axfr_fallback: 1016135446Strhodes CHECK(axfr_rrstream_create(mctx, db, ver, 1017135446Strhodes &data_stream)); 1018135446Strhodes } 1019135446Strhodes 1020135446Strhodes /* 1021193149Sdougb * Bracket the data stream with SOAs. 1022135446Strhodes */ 1023135446Strhodes CHECK(soa_rrstream_create(mctx, db, ver, &soa_stream)); 1024135446Strhodes CHECK(compound_rrstream_create(mctx, &soa_stream, &data_stream, 1025135446Strhodes &stream)); 1026135446Strhodes soa_stream = NULL; 1027135446Strhodes data_stream = NULL; 1028135446Strhodes 1029135446Strhodes have_stream: 1030135446Strhodes CHECK(dns_message_getquerytsig(request, mctx, &tsigbuf)); 1031135446Strhodes /* 1032135446Strhodes * Create the xfrout context object. This transfers the ownership 1033135446Strhodes * of "stream", "db", "ver", and "quota" to the xfrout context object. 1034135446Strhodes */ 1035170222Sdougb 1036170222Sdougb 1037170222Sdougb 1038170222Sdougb if (is_dlz) 1039218384Sdougb CHECK(xfrout_ctx_create(mctx, client, request->id, 1040218384Sdougb question_name, reqtype, question_class, 1041218384Sdougb zone, db, ver, quota, stream, 1042193149Sdougb dns_message_gettsigkey(request), 1043193149Sdougb tsigbuf, 1044193149Sdougb 3600, 1045193149Sdougb 3600, 1046193149Sdougb (format == dns_many_answers) ? 1047193149Sdougb ISC_TRUE : ISC_FALSE, 1048193149Sdougb &xfr)); 1049193149Sdougb else 1050218384Sdougb CHECK(xfrout_ctx_create(mctx, client, request->id, 1051218384Sdougb question_name, reqtype, question_class, 1052218384Sdougb zone, db, ver, quota, stream, 1053193149Sdougb dns_message_gettsigkey(request), 1054193149Sdougb tsigbuf, 1055193149Sdougb dns_zone_getmaxxfrout(zone), 1056193149Sdougb dns_zone_getidleout(zone), 1057193149Sdougb (format == dns_many_answers) ? 1058193149Sdougb ISC_TRUE : ISC_FALSE, 1059193149Sdougb &xfr)); 1060170222Sdougb 1061135446Strhodes xfr->mnemonic = mnemonic; 1062135446Strhodes stream = NULL; 1063135446Strhodes quota = NULL; 1064135446Strhodes 1065135446Strhodes CHECK(xfr->stream->methods->first(xfr->stream)); 1066135446Strhodes 1067225361Sdougb if (xfr->tsigkey != NULL) 1068135446Strhodes dns_name_format(&xfr->tsigkey->name, keyname, sizeof(keyname)); 1069225361Sdougb else 1070135446Strhodes keyname[0] = '\0'; 1071135446Strhodes if (is_poll) 1072135446Strhodes xfrout_log1(client, question_name, question_class, 1073135446Strhodes ISC_LOG_DEBUG(1), "IXFR poll up to date%s%s", 1074135446Strhodes (xfr->tsigkey != NULL) ? ": TSIG " : "", keyname); 1075135446Strhodes else 1076135446Strhodes xfrout_log1(client, question_name, question_class, 1077135446Strhodes ISC_LOG_INFO, "%s started%s%s", mnemonic, 1078135446Strhodes (xfr->tsigkey != NULL) ? ": TSIG " : "", keyname); 1079135446Strhodes 1080135446Strhodes /* 1081135446Strhodes * Hand the context over to sendstream(). Set xfr to NULL; 1082135446Strhodes * sendstream() is responsible for either passing the 1083135446Strhodes * context on to a later event handler or destroying it. 1084135446Strhodes */ 1085135446Strhodes sendstream(xfr); 1086135446Strhodes xfr = NULL; 1087135446Strhodes 1088135446Strhodes result = ISC_R_SUCCESS; 1089135446Strhodes 1090135446Strhodes failure: 1091193149Sdougb if (result == DNS_R_REFUSED) 1092193149Sdougb inc_stats(zone, dns_nsstatscounter_xfrrej); 1093135446Strhodes if (quota != NULL) 1094135446Strhodes isc_quota_detach("a); 1095135446Strhodes if (current_soa_tuple != NULL) 1096135446Strhodes dns_difftuple_free(¤t_soa_tuple); 1097135446Strhodes if (stream != NULL) 1098135446Strhodes stream->methods->destroy(&stream); 1099135446Strhodes if (soa_stream != NULL) 1100135446Strhodes soa_stream->methods->destroy(&soa_stream); 1101135446Strhodes if (data_stream != NULL) 1102135446Strhodes data_stream->methods->destroy(&data_stream); 1103135446Strhodes if (ver != NULL) 1104135446Strhodes dns_db_closeversion(db, &ver, ISC_FALSE); 1105135446Strhodes if (db != NULL) 1106135446Strhodes dns_db_detach(&db); 1107135446Strhodes if (zone != NULL) 1108135446Strhodes dns_zone_detach(&zone); 1109135446Strhodes /* XXX kludge */ 1110135446Strhodes if (xfr != NULL) { 1111135446Strhodes xfrout_fail(xfr, result, "setting up zone transfer"); 1112135446Strhodes } else if (result != ISC_R_SUCCESS) { 1113135446Strhodes ns_client_log(client, DNS_LOGCATEGORY_XFER_OUT, 1114135446Strhodes NS_LOGMODULE_XFER_OUT, 1115135446Strhodes ISC_LOG_DEBUG(3), "zone transfer setup failed"); 1116135446Strhodes ns_client_error(client, result); 1117135446Strhodes } 1118135446Strhodes} 1119135446Strhodes 1120135446Strhodesstatic isc_result_t 1121135446Strhodesxfrout_ctx_create(isc_mem_t *mctx, ns_client_t *client, unsigned int id, 1122135446Strhodes dns_name_t *qname, dns_rdatatype_t qtype, 1123193149Sdougb dns_rdataclass_t qclass, dns_zone_t *zone, 1124135446Strhodes dns_db_t *db, dns_dbversion_t *ver, isc_quota_t *quota, 1125135446Strhodes rrstream_t *stream, dns_tsigkey_t *tsigkey, 1126135446Strhodes isc_buffer_t *lasttsig, unsigned int maxtime, 1127135446Strhodes unsigned int idletime, isc_boolean_t many_answers, 1128135446Strhodes xfrout_ctx_t **xfrp) 1129135446Strhodes{ 1130135446Strhodes xfrout_ctx_t *xfr; 1131135446Strhodes isc_result_t result; 1132135446Strhodes unsigned int len; 1133135446Strhodes void *mem; 1134135446Strhodes 1135135446Strhodes INSIST(xfrp != NULL && *xfrp == NULL); 1136135446Strhodes xfr = isc_mem_get(mctx, sizeof(*xfr)); 1137135446Strhodes if (xfr == NULL) 1138135446Strhodes return (ISC_R_NOMEMORY); 1139225361Sdougb xfr->mctx = NULL; 1140225361Sdougb isc_mem_attach(mctx, &xfr->mctx); 1141135446Strhodes xfr->client = NULL; 1142135446Strhodes ns_client_attach(client, &xfr->client); 1143135446Strhodes xfr->id = id; 1144135446Strhodes xfr->qname = qname; 1145135446Strhodes xfr->qtype = qtype; 1146135446Strhodes xfr->qclass = qclass; 1147193149Sdougb xfr->zone = NULL; 1148135446Strhodes xfr->db = NULL; 1149135446Strhodes xfr->ver = NULL; 1150193149Sdougb if (zone != NULL) /* zone will be NULL if it's DLZ */ 1151193149Sdougb dns_zone_attach(zone, &xfr->zone); 1152135446Strhodes dns_db_attach(db, &xfr->db); 1153135446Strhodes dns_db_attachversion(db, ver, &xfr->ver); 1154135446Strhodes xfr->end_of_stream = ISC_FALSE; 1155135446Strhodes xfr->tsigkey = tsigkey; 1156135446Strhodes xfr->lasttsig = lasttsig; 1157135446Strhodes xfr->txmem = NULL; 1158135446Strhodes xfr->txmemlen = 0; 1159135446Strhodes xfr->nmsg = 0; 1160135446Strhodes xfr->many_answers = many_answers, 1161135446Strhodes xfr->sends = 0; 1162135446Strhodes xfr->shuttingdown = ISC_FALSE; 1163135446Strhodes xfr->mnemonic = NULL; 1164135446Strhodes xfr->buf.base = NULL; 1165135446Strhodes xfr->buf.length = 0; 1166135446Strhodes xfr->txmem = NULL; 1167135446Strhodes xfr->txmemlen = 0; 1168135446Strhodes xfr->stream = NULL; 1169135446Strhodes xfr->quota = NULL; 1170135446Strhodes 1171135446Strhodes /* 1172135446Strhodes * Allocate a temporary buffer for the uncompressed response 1173135446Strhodes * message data. The size should be no more than 65535 bytes 1174135446Strhodes * so that the compressed data will fit in a TCP message, 1175135446Strhodes * and no less than 65535 bytes so that an almost maximum-sized 1176135446Strhodes * RR will fit. Note that although 65535-byte RRs are allowed 1177135446Strhodes * in principle, they cannot be zone-transferred (at least not 1178135446Strhodes * if uncompressible), because the message and RR headers would 1179135446Strhodes * push the size of the TCP message over the 65536 byte limit. 1180135446Strhodes */ 1181135446Strhodes len = 65535; 1182135446Strhodes mem = isc_mem_get(mctx, len); 1183135446Strhodes if (mem == NULL) { 1184135446Strhodes result = ISC_R_NOMEMORY; 1185135446Strhodes goto failure; 1186135446Strhodes } 1187135446Strhodes isc_buffer_init(&xfr->buf, mem, len); 1188135446Strhodes 1189135446Strhodes /* 1190135446Strhodes * Allocate another temporary buffer for the compressed 1191135446Strhodes * response message and its TCP length prefix. 1192135446Strhodes */ 1193135446Strhodes len = 2 + 65535; 1194135446Strhodes mem = isc_mem_get(mctx, len); 1195135446Strhodes if (mem == NULL) { 1196135446Strhodes result = ISC_R_NOMEMORY; 1197135446Strhodes goto failure; 1198135446Strhodes } 1199135446Strhodes isc_buffer_init(&xfr->txlenbuf, mem, 2); 1200135446Strhodes isc_buffer_init(&xfr->txbuf, (char *) mem + 2, len - 2); 1201135446Strhodes xfr->txmem = mem; 1202135446Strhodes xfr->txmemlen = len; 1203135446Strhodes 1204135446Strhodes CHECK(dns_timer_setidle(xfr->client->timer, 1205135446Strhodes maxtime, idletime, ISC_FALSE)); 1206135446Strhodes 1207135446Strhodes /* 1208135446Strhodes * Register a shutdown callback with the client, so that we 1209135446Strhodes * can stop the transfer immediately when the client task 1210135446Strhodes * gets a shutdown event. 1211135446Strhodes */ 1212135446Strhodes xfr->client->shutdown = xfrout_client_shutdown; 1213135446Strhodes xfr->client->shutdown_arg = xfr; 1214135446Strhodes /* 1215135446Strhodes * These MUST be after the last "goto failure;" / CHECK to 1216135446Strhodes * prevent a double free by the caller. 1217135446Strhodes */ 1218135446Strhodes xfr->quota = quota; 1219135446Strhodes xfr->stream = stream; 1220135446Strhodes 1221135446Strhodes *xfrp = xfr; 1222135446Strhodes return (ISC_R_SUCCESS); 1223135446Strhodes 1224135446Strhodesfailure: 1225135446Strhodes xfrout_ctx_destroy(&xfr); 1226135446Strhodes return (result); 1227135446Strhodes} 1228135446Strhodes 1229135446Strhodes 1230135446Strhodes/* 1231135446Strhodes * Arrange to send as much as we can of "stream" without blocking. 1232135446Strhodes * 1233135446Strhodes * Requires: 1234135446Strhodes * The stream iterator is initialized and points at an RR, 1235193149Sdougb * or possibly at the end of the stream (that is, the 1236135446Strhodes * _first method of the iterator has been called). 1237135446Strhodes */ 1238135446Strhodesstatic void 1239135446Strhodessendstream(xfrout_ctx_t *xfr) { 1240135446Strhodes dns_message_t *tcpmsg = NULL; 1241135446Strhodes dns_message_t *msg = NULL; /* Client message if UDP, tcpmsg if TCP */ 1242135446Strhodes isc_result_t result; 1243135446Strhodes isc_region_t used; 1244135446Strhodes isc_region_t region; 1245135446Strhodes dns_rdataset_t *qrdataset; 1246135446Strhodes dns_name_t *msgname = NULL; 1247135446Strhodes dns_rdata_t *msgrdata = NULL; 1248135446Strhodes dns_rdatalist_t *msgrdl = NULL; 1249135446Strhodes dns_rdataset_t *msgrds = NULL; 1250135446Strhodes dns_compress_t cctx; 1251135446Strhodes isc_boolean_t cleanup_cctx = ISC_FALSE; 1252135446Strhodes 1253135446Strhodes int n_rrs; 1254135446Strhodes 1255135446Strhodes isc_buffer_clear(&xfr->buf); 1256135446Strhodes isc_buffer_clear(&xfr->txlenbuf); 1257135446Strhodes isc_buffer_clear(&xfr->txbuf); 1258135446Strhodes 1259135446Strhodes if ((xfr->client->attributes & NS_CLIENTATTR_TCP) == 0) { 1260135446Strhodes /* 1261135446Strhodes * In the UDP case, we put the response data directly into 1262135446Strhodes * the client message. 1263135446Strhodes */ 1264135446Strhodes msg = xfr->client->message; 1265135446Strhodes CHECK(dns_message_reply(msg, ISC_TRUE)); 1266135446Strhodes } else { 1267135446Strhodes /* 1268135446Strhodes * TCP. Build a response dns_message_t, temporarily storing 1269135446Strhodes * the raw, uncompressed owner names and RR data contiguously 1270135446Strhodes * in xfr->buf. We know that if the uncompressed data fits 1271135446Strhodes * in xfr->buf, the compressed data will surely fit in a TCP 1272135446Strhodes * message. 1273135446Strhodes */ 1274135446Strhodes 1275135446Strhodes CHECK(dns_message_create(xfr->mctx, 1276135446Strhodes DNS_MESSAGE_INTENTRENDER, &tcpmsg)); 1277135446Strhodes msg = tcpmsg; 1278135446Strhodes 1279135446Strhodes msg->id = xfr->id; 1280135446Strhodes msg->rcode = dns_rcode_noerror; 1281135446Strhodes msg->flags = DNS_MESSAGEFLAG_QR | DNS_MESSAGEFLAG_AA; 1282135446Strhodes if ((xfr->client->attributes & NS_CLIENTATTR_RA) != 0) 1283135446Strhodes msg->flags |= DNS_MESSAGEFLAG_RA; 1284135446Strhodes CHECK(dns_message_settsigkey(msg, xfr->tsigkey)); 1285135446Strhodes CHECK(dns_message_setquerytsig(msg, xfr->lasttsig)); 1286135446Strhodes if (xfr->lasttsig != NULL) 1287135446Strhodes isc_buffer_free(&xfr->lasttsig); 1288135446Strhodes 1289135446Strhodes /* 1290135446Strhodes * Include a question section in the first message only. 1291135446Strhodes * BIND 8.2.1 will not recognize an IXFR if it does not 1292135446Strhodes * have a question section. 1293135446Strhodes */ 1294135446Strhodes if (xfr->nmsg == 0) { 1295135446Strhodes dns_name_t *qname = NULL; 1296135446Strhodes isc_region_t r; 1297135446Strhodes 1298135446Strhodes /* 1299135446Strhodes * Reserve space for the 12-byte message header 1300135446Strhodes * and 4 bytes of question. 1301135446Strhodes */ 1302135446Strhodes isc_buffer_add(&xfr->buf, 12 + 4); 1303135446Strhodes 1304135446Strhodes qrdataset = NULL; 1305135446Strhodes result = dns_message_gettemprdataset(msg, &qrdataset); 1306135446Strhodes if (result != ISC_R_SUCCESS) 1307135446Strhodes goto failure; 1308135446Strhodes dns_rdataset_init(qrdataset); 1309135446Strhodes dns_rdataset_makequestion(qrdataset, 1310135446Strhodes xfr->client->message->rdclass, 1311135446Strhodes xfr->qtype); 1312135446Strhodes 1313135446Strhodes result = dns_message_gettempname(msg, &qname); 1314135446Strhodes if (result != ISC_R_SUCCESS) 1315135446Strhodes goto failure; 1316135446Strhodes dns_name_init(qname, NULL); 1317135446Strhodes isc_buffer_availableregion(&xfr->buf, &r); 1318135446Strhodes INSIST(r.length >= xfr->qname->length); 1319135446Strhodes r.length = xfr->qname->length; 1320135446Strhodes isc_buffer_putmem(&xfr->buf, xfr->qname->ndata, 1321135446Strhodes xfr->qname->length); 1322135446Strhodes dns_name_fromregion(qname, &r); 1323135446Strhodes ISC_LIST_INIT(qname->list); 1324135446Strhodes ISC_LIST_APPEND(qname->list, qrdataset, link); 1325135446Strhodes 1326135446Strhodes dns_message_addname(msg, qname, DNS_SECTION_QUESTION); 1327135446Strhodes } 1328135446Strhodes else 1329135446Strhodes msg->tcp_continuation = 1; 1330135446Strhodes } 1331135446Strhodes 1332135446Strhodes /* 1333135446Strhodes * Try to fit in as many RRs as possible, unless "one-answer" 1334135446Strhodes * format has been requested. 1335135446Strhodes */ 1336135446Strhodes for (n_rrs = 0; ; n_rrs++) { 1337135446Strhodes dns_name_t *name = NULL; 1338135446Strhodes isc_uint32_t ttl; 1339135446Strhodes dns_rdata_t *rdata = NULL; 1340135446Strhodes 1341135446Strhodes unsigned int size; 1342135446Strhodes isc_region_t r; 1343135446Strhodes 1344135446Strhodes msgname = NULL; 1345135446Strhodes msgrdata = NULL; 1346135446Strhodes msgrdl = NULL; 1347135446Strhodes msgrds = NULL; 1348135446Strhodes 1349135446Strhodes xfr->stream->methods->current(xfr->stream, 1350135446Strhodes &name, &ttl, &rdata); 1351135446Strhodes size = name->length + 10 + rdata->length; 1352135446Strhodes isc_buffer_availableregion(&xfr->buf, &r); 1353135446Strhodes if (size >= r.length) { 1354135446Strhodes /* 1355135446Strhodes * RR would not fit. If there are other RRs in the 1356135446Strhodes * buffer, send them now and leave this RR to the 1357135446Strhodes * next message. If this RR overflows the buffer 1358135446Strhodes * all by itself, fail. 1359135446Strhodes * 1360135446Strhodes * In theory some RRs might fit in a TCP message 1361135446Strhodes * when compressed even if they do not fit when 1362135446Strhodes * uncompressed, but surely we don't want 1363135446Strhodes * to send such monstrosities to an unsuspecting 1364135446Strhodes * slave. 1365135446Strhodes */ 1366135446Strhodes if (n_rrs == 0) { 1367135446Strhodes xfrout_log(xfr, ISC_LOG_WARNING, 1368135446Strhodes "RR too large for zone transfer " 1369135446Strhodes "(%d bytes)", size); 1370135446Strhodes /* XXX DNS_R_RRTOOLARGE? */ 1371135446Strhodes result = ISC_R_NOSPACE; 1372135446Strhodes goto failure; 1373135446Strhodes } 1374135446Strhodes break; 1375135446Strhodes } 1376135446Strhodes 1377135446Strhodes if (isc_log_wouldlog(ns_g_lctx, XFROUT_RR_LOGLEVEL)) 1378135446Strhodes log_rr(name, rdata, ttl); /* XXX */ 1379135446Strhodes 1380135446Strhodes result = dns_message_gettempname(msg, &msgname); 1381135446Strhodes if (result != ISC_R_SUCCESS) 1382135446Strhodes goto failure; 1383135446Strhodes dns_name_init(msgname, NULL); 1384135446Strhodes isc_buffer_availableregion(&xfr->buf, &r); 1385135446Strhodes INSIST(r.length >= name->length); 1386135446Strhodes r.length = name->length; 1387135446Strhodes isc_buffer_putmem(&xfr->buf, name->ndata, name->length); 1388135446Strhodes dns_name_fromregion(msgname, &r); 1389135446Strhodes 1390135446Strhodes /* Reserve space for RR header. */ 1391135446Strhodes isc_buffer_add(&xfr->buf, 10); 1392135446Strhodes 1393135446Strhodes result = dns_message_gettemprdata(msg, &msgrdata); 1394135446Strhodes if (result != ISC_R_SUCCESS) 1395135446Strhodes goto failure; 1396135446Strhodes isc_buffer_availableregion(&xfr->buf, &r); 1397135446Strhodes r.length = rdata->length; 1398135446Strhodes isc_buffer_putmem(&xfr->buf, rdata->data, rdata->length); 1399135446Strhodes dns_rdata_init(msgrdata); 1400135446Strhodes dns_rdata_fromregion(msgrdata, 1401135446Strhodes rdata->rdclass, rdata->type, &r); 1402135446Strhodes 1403135446Strhodes result = dns_message_gettemprdatalist(msg, &msgrdl); 1404135446Strhodes if (result != ISC_R_SUCCESS) 1405135446Strhodes goto failure; 1406135446Strhodes msgrdl->type = rdata->type; 1407135446Strhodes msgrdl->rdclass = rdata->rdclass; 1408135446Strhodes msgrdl->ttl = ttl; 1409193149Sdougb if (rdata->type == dns_rdatatype_sig || 1410193149Sdougb rdata->type == dns_rdatatype_rrsig) 1411193149Sdougb msgrdl->covers = dns_rdata_covers(rdata); 1412193149Sdougb else 1413193149Sdougb msgrdl->covers = dns_rdatatype_none; 1414135446Strhodes ISC_LINK_INIT(msgrdl, link); 1415135446Strhodes ISC_LIST_INIT(msgrdl->rdata); 1416135446Strhodes ISC_LIST_APPEND(msgrdl->rdata, msgrdata, link); 1417135446Strhodes 1418135446Strhodes result = dns_message_gettemprdataset(msg, &msgrds); 1419135446Strhodes if (result != ISC_R_SUCCESS) 1420135446Strhodes goto failure; 1421135446Strhodes dns_rdataset_init(msgrds); 1422135446Strhodes result = dns_rdatalist_tordataset(msgrdl, msgrds); 1423135446Strhodes INSIST(result == ISC_R_SUCCESS); 1424135446Strhodes 1425135446Strhodes ISC_LIST_APPEND(msgname->list, msgrds, link); 1426135446Strhodes 1427135446Strhodes dns_message_addname(msg, msgname, DNS_SECTION_ANSWER); 1428135446Strhodes msgname = NULL; 1429135446Strhodes 1430135446Strhodes result = xfr->stream->methods->next(xfr->stream); 1431135446Strhodes if (result == ISC_R_NOMORE) { 1432135446Strhodes xfr->end_of_stream = ISC_TRUE; 1433135446Strhodes break; 1434135446Strhodes } 1435135446Strhodes CHECK(result); 1436135446Strhodes 1437135446Strhodes if (! xfr->many_answers) 1438135446Strhodes break; 1439135446Strhodes } 1440135446Strhodes 1441135446Strhodes if ((xfr->client->attributes & NS_CLIENTATTR_TCP) != 0) { 1442135446Strhodes CHECK(dns_compress_init(&cctx, -1, xfr->mctx)); 1443170222Sdougb dns_compress_setsensitive(&cctx, ISC_TRUE); 1444135446Strhodes cleanup_cctx = ISC_TRUE; 1445135446Strhodes CHECK(dns_message_renderbegin(msg, &cctx, &xfr->txbuf)); 1446135446Strhodes CHECK(dns_message_rendersection(msg, DNS_SECTION_QUESTION, 0)); 1447135446Strhodes CHECK(dns_message_rendersection(msg, DNS_SECTION_ANSWER, 0)); 1448135446Strhodes CHECK(dns_message_renderend(msg)); 1449135446Strhodes dns_compress_invalidate(&cctx); 1450135446Strhodes cleanup_cctx = ISC_FALSE; 1451135446Strhodes 1452135446Strhodes isc_buffer_usedregion(&xfr->txbuf, &used); 1453135446Strhodes isc_buffer_putuint16(&xfr->txlenbuf, 1454135446Strhodes (isc_uint16_t)used.length); 1455135446Strhodes region.base = xfr->txlenbuf.base; 1456135446Strhodes region.length = 2 + used.length; 1457135446Strhodes xfrout_log(xfr, ISC_LOG_DEBUG(8), 1458135446Strhodes "sending TCP message of %d bytes", 1459135446Strhodes used.length); 1460135446Strhodes CHECK(isc_socket_send(xfr->client->tcpsocket, /* XXX */ 1461135446Strhodes ®ion, xfr->client->task, 1462135446Strhodes xfrout_senddone, 1463135446Strhodes xfr)); 1464135446Strhodes xfr->sends++; 1465135446Strhodes } else { 1466135446Strhodes xfrout_log(xfr, ISC_LOG_DEBUG(8), "sending IXFR UDP response"); 1467135446Strhodes ns_client_send(xfr->client); 1468135446Strhodes xfr->stream->methods->pause(xfr->stream); 1469135446Strhodes xfrout_ctx_destroy(&xfr); 1470135446Strhodes return; 1471135446Strhodes } 1472135446Strhodes 1473135446Strhodes /* Advance lasttsig to be the last TSIG generated */ 1474135446Strhodes CHECK(dns_message_getquerytsig(msg, xfr->mctx, &xfr->lasttsig)); 1475135446Strhodes 1476135446Strhodes xfr->nmsg++; 1477135446Strhodes 1478135446Strhodes failure: 1479135446Strhodes if (msgname != NULL) { 1480135446Strhodes if (msgrds != NULL) { 1481135446Strhodes if (dns_rdataset_isassociated(msgrds)) 1482135446Strhodes dns_rdataset_disassociate(msgrds); 1483135446Strhodes dns_message_puttemprdataset(msg, &msgrds); 1484135446Strhodes } 1485135446Strhodes if (msgrdl != NULL) { 1486135446Strhodes ISC_LIST_UNLINK(msgrdl->rdata, msgrdata, link); 1487135446Strhodes dns_message_puttemprdatalist(msg, &msgrdl); 1488135446Strhodes } 1489135446Strhodes if (msgrdata != NULL) 1490135446Strhodes dns_message_puttemprdata(msg, &msgrdata); 1491135446Strhodes dns_message_puttempname(msg, &msgname); 1492135446Strhodes } 1493135446Strhodes 1494135446Strhodes if (tcpmsg != NULL) 1495135446Strhodes dns_message_destroy(&tcpmsg); 1496135446Strhodes 1497135446Strhodes if (cleanup_cctx) 1498135446Strhodes dns_compress_invalidate(&cctx); 1499135446Strhodes /* 1500135446Strhodes * Make sure to release any locks held by database 1501135446Strhodes * iterators before returning from the event handler. 1502135446Strhodes */ 1503135446Strhodes xfr->stream->methods->pause(xfr->stream); 1504193149Sdougb 1505135446Strhodes if (result == ISC_R_SUCCESS) 1506135446Strhodes return; 1507135446Strhodes 1508135446Strhodes xfrout_fail(xfr, result, "sending zone data"); 1509135446Strhodes} 1510135446Strhodes 1511135446Strhodesstatic void 1512135446Strhodesxfrout_ctx_destroy(xfrout_ctx_t **xfrp) { 1513135446Strhodes xfrout_ctx_t *xfr = *xfrp; 1514225361Sdougb ns_client_t *client = NULL; 1515135446Strhodes 1516135446Strhodes INSIST(xfr->sends == 0); 1517135446Strhodes 1518135446Strhodes xfr->client->shutdown = NULL; 1519135446Strhodes xfr->client->shutdown_arg = NULL; 1520135446Strhodes 1521135446Strhodes if (xfr->stream != NULL) 1522135446Strhodes xfr->stream->methods->destroy(&xfr->stream); 1523135446Strhodes if (xfr->buf.base != NULL) 1524135446Strhodes isc_mem_put(xfr->mctx, xfr->buf.base, xfr->buf.length); 1525135446Strhodes if (xfr->txmem != NULL) 1526135446Strhodes isc_mem_put(xfr->mctx, xfr->txmem, xfr->txmemlen); 1527135446Strhodes if (xfr->lasttsig != NULL) 1528135446Strhodes isc_buffer_free(&xfr->lasttsig); 1529135446Strhodes if (xfr->quota != NULL) 1530135446Strhodes isc_quota_detach(&xfr->quota); 1531135446Strhodes if (xfr->ver != NULL) 1532135446Strhodes dns_db_closeversion(xfr->db, &xfr->ver, ISC_FALSE); 1533193149Sdougb if (xfr->zone != NULL) 1534193149Sdougb dns_zone_detach(&xfr->zone); 1535135446Strhodes if (xfr->db != NULL) 1536135446Strhodes dns_db_detach(&xfr->db); 1537135446Strhodes 1538225361Sdougb /* 1539225361Sdougb * We want to detch the client after we have released the memory 1540225361Sdougb * context as ns_client_detach checks the memory reference count. 1541225361Sdougb */ 1542225361Sdougb ns_client_attach(xfr->client, &client); 1543135446Strhodes ns_client_detach(&xfr->client); 1544225361Sdougb isc_mem_putanddetach(&xfr->mctx, xfr, sizeof(*xfr)); 1545225361Sdougb ns_client_detach(&client); 1546135446Strhodes 1547135446Strhodes *xfrp = NULL; 1548135446Strhodes} 1549135446Strhodes 1550135446Strhodesstatic void 1551135446Strhodesxfrout_senddone(isc_task_t *task, isc_event_t *event) { 1552135446Strhodes isc_socketevent_t *sev = (isc_socketevent_t *)event; 1553135446Strhodes xfrout_ctx_t *xfr = (xfrout_ctx_t *)event->ev_arg; 1554135446Strhodes isc_result_t evresult = sev->result; 1555135446Strhodes 1556135446Strhodes UNUSED(task); 1557135446Strhodes 1558135446Strhodes INSIST(event->ev_type == ISC_SOCKEVENT_SENDDONE); 1559135446Strhodes 1560135446Strhodes isc_event_free(&event); 1561135446Strhodes xfr->sends--; 1562135446Strhodes INSIST(xfr->sends == 0); 1563135446Strhodes 1564135446Strhodes (void)isc_timer_touch(xfr->client->timer); 1565135446Strhodes if (xfr->shuttingdown == ISC_TRUE) { 1566135446Strhodes xfrout_maybe_destroy(xfr); 1567135446Strhodes } else if (evresult != ISC_R_SUCCESS) { 1568135446Strhodes xfrout_fail(xfr, evresult, "send"); 1569135446Strhodes } else if (xfr->end_of_stream == ISC_FALSE) { 1570135446Strhodes sendstream(xfr); 1571135446Strhodes } else { 1572135446Strhodes /* End of zone transfer stream. */ 1573193149Sdougb inc_stats(xfr->zone, dns_nsstatscounter_xfrdone); 1574135446Strhodes xfrout_log(xfr, ISC_LOG_INFO, "%s ended", xfr->mnemonic); 1575135446Strhodes ns_client_next(xfr->client, ISC_R_SUCCESS); 1576135446Strhodes xfrout_ctx_destroy(&xfr); 1577135446Strhodes } 1578135446Strhodes} 1579135446Strhodes 1580135446Strhodesstatic void 1581135446Strhodesxfrout_fail(xfrout_ctx_t *xfr, isc_result_t result, const char *msg) { 1582135446Strhodes xfr->shuttingdown = ISC_TRUE; 1583135446Strhodes xfrout_log(xfr, ISC_LOG_ERROR, "%s: %s", 1584135446Strhodes msg, isc_result_totext(result)); 1585135446Strhodes xfrout_maybe_destroy(xfr); 1586135446Strhodes} 1587135446Strhodes 1588135446Strhodesstatic void 1589135446Strhodesxfrout_maybe_destroy(xfrout_ctx_t *xfr) { 1590135446Strhodes INSIST(xfr->shuttingdown == ISC_TRUE); 1591135446Strhodes if (xfr->sends > 0) { 1592135446Strhodes /* 1593135446Strhodes * If we are currently sending, cancel it and wait for 1594135446Strhodes * cancel event before destroying the context. 1595135446Strhodes */ 1596135446Strhodes isc_socket_cancel(xfr->client->tcpsocket, xfr->client->task, 1597135446Strhodes ISC_SOCKCANCEL_SEND); 1598135446Strhodes } else { 1599135446Strhodes ns_client_next(xfr->client, ISC_R_CANCELED); 1600135446Strhodes xfrout_ctx_destroy(&xfr); 1601135446Strhodes } 1602135446Strhodes} 1603135446Strhodes 1604135446Strhodesstatic void 1605135446Strhodesxfrout_client_shutdown(void *arg, isc_result_t result) { 1606135446Strhodes xfrout_ctx_t *xfr = (xfrout_ctx_t *) arg; 1607135446Strhodes xfrout_fail(xfr, result, "aborted"); 1608135446Strhodes} 1609135446Strhodes 1610135446Strhodes/* 1611135446Strhodes * Log outgoing zone transfer messages in a format like 1612135446Strhodes * <client>: transfer of <zone>: <message> 1613135446Strhodes */ 1614135446Strhodes 1615135446Strhodesstatic void 1616135446Strhodesxfrout_logv(ns_client_t *client, dns_name_t *zonename, 1617135446Strhodes dns_rdataclass_t rdclass, int level, const char *fmt, va_list ap) 1618135446Strhodes ISC_FORMAT_PRINTF(5, 0); 1619135446Strhodes 1620135446Strhodesstatic void 1621135446Strhodesxfrout_logv(ns_client_t *client, dns_name_t *zonename, 1622135446Strhodes dns_rdataclass_t rdclass, int level, const char *fmt, va_list ap) 1623135446Strhodes{ 1624135446Strhodes char msgbuf[2048]; 1625135446Strhodes char namebuf[DNS_NAME_FORMATSIZE]; 1626135446Strhodes char classbuf[DNS_RDATACLASS_FORMATSIZE]; 1627135446Strhodes 1628135446Strhodes dns_name_format(zonename, namebuf, sizeof(namebuf)); 1629135446Strhodes dns_rdataclass_format(rdclass, classbuf, sizeof(classbuf)); 1630135446Strhodes vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap); 1631135446Strhodes ns_client_log(client, DNS_LOGCATEGORY_XFER_OUT, 1632135446Strhodes NS_LOGMODULE_XFER_OUT, level, 1633135446Strhodes "transfer of '%s/%s': %s", namebuf, classbuf, msgbuf); 1634135446Strhodes} 1635135446Strhodes 1636135446Strhodes/* 1637135446Strhodes * Logging function for use when a xfrout_ctx_t has not yet been created. 1638135446Strhodes */ 1639135446Strhodesstatic void 1640135446Strhodesxfrout_log1(ns_client_t *client, dns_name_t *zonename, 1641135446Strhodes dns_rdataclass_t rdclass, int level, const char *fmt, ...) { 1642135446Strhodes va_list ap; 1643135446Strhodes va_start(ap, fmt); 1644135446Strhodes xfrout_logv(client, zonename, rdclass, level, fmt, ap); 1645135446Strhodes va_end(ap); 1646135446Strhodes} 1647135446Strhodes 1648135446Strhodes/* 1649135446Strhodes * Logging function for use when there is a xfrout_ctx_t. 1650135446Strhodes */ 1651135446Strhodesstatic void 1652153816Sdougbxfrout_log(xfrout_ctx_t *xfr, int level, const char *fmt, ...) { 1653135446Strhodes va_list ap; 1654135446Strhodes va_start(ap, fmt); 1655135446Strhodes xfrout_logv(xfr->client, xfr->qname, xfr->qclass, level, fmt, ap); 1656135446Strhodes va_end(ap); 1657135446Strhodes} 1658