1135446Strhodes/* 2254897Serwin * Copyright (C) 2004-2013 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 18254897Serwin/* $Id$ */ 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); 250254897Serwin s->common.mctx = NULL; 251254897Serwin isc_mem_attach(mctx, &s->common.mctx); 252135446Strhodes s->common.methods = &ixfr_rrstream_methods; 253135446Strhodes s->journal = NULL; 254135446Strhodes 255135446Strhodes CHECK(dns_journal_open(mctx, journal_filename, 256254897Serwin DNS_JOURNAL_READ, &s->journal)); 257135446Strhodes CHECK(dns_journal_iter_init(s->journal, begin_serial, end_serial)); 258135446Strhodes 259135446Strhodes *sp = (rrstream_t *) s; 260135446Strhodes return (ISC_R_SUCCESS); 261135446Strhodes 262135446Strhodes failure: 263135446Strhodes ixfr_rrstream_destroy((rrstream_t **) (void *)&s); 264135446Strhodes return (result); 265135446Strhodes} 266135446Strhodes 267135446Strhodesstatic isc_result_t 268135446Strhodesixfr_rrstream_first(rrstream_t *rs) { 269135446Strhodes ixfr_rrstream_t *s = (ixfr_rrstream_t *) rs; 270135446Strhodes return (dns_journal_first_rr(s->journal)); 271135446Strhodes} 272135446Strhodes 273135446Strhodesstatic isc_result_t 274135446Strhodesixfr_rrstream_next(rrstream_t *rs) { 275135446Strhodes ixfr_rrstream_t *s = (ixfr_rrstream_t *) rs; 276135446Strhodes return (dns_journal_next_rr(s->journal)); 277135446Strhodes} 278135446Strhodes 279135446Strhodesstatic void 280135446Strhodesixfr_rrstream_current(rrstream_t *rs, 281135446Strhodes dns_name_t **name, isc_uint32_t *ttl, 282135446Strhodes dns_rdata_t **rdata) 283135446Strhodes{ 284135446Strhodes ixfr_rrstream_t *s = (ixfr_rrstream_t *) rs; 285135446Strhodes dns_journal_current_rr(s->journal, name, ttl, rdata); 286135446Strhodes} 287135446Strhodes 288135446Strhodesstatic void 289135446Strhodesixfr_rrstream_destroy(rrstream_t **rsp) { 290135446Strhodes ixfr_rrstream_t *s = (ixfr_rrstream_t *) *rsp; 291135446Strhodes if (s->journal != 0) 292135446Strhodes dns_journal_destroy(&s->journal); 293254897Serwin isc_mem_putanddetach(&s->common.mctx, s, sizeof(*s)); 294135446Strhodes} 295135446Strhodes 296135446Strhodesstatic rrstream_methods_t ixfr_rrstream_methods = { 297135446Strhodes ixfr_rrstream_first, 298135446Strhodes ixfr_rrstream_next, 299135446Strhodes ixfr_rrstream_current, 300135446Strhodes rrstream_noop_pause, 301135446Strhodes ixfr_rrstream_destroy 302135446Strhodes}; 303135446Strhodes 304135446Strhodes/**************************************************************************/ 305135446Strhodes/* 306135446Strhodes * An 'axfr_rrstream_t' is an 'rrstream_t' that returns 307135446Strhodes * an AXFR-like RR stream from a database. 308135446Strhodes * 309135446Strhodes * The SOAs at the beginning and end of the transfer are 310135446Strhodes * not included in the stream. 311135446Strhodes */ 312135446Strhodes 313135446Strhodestypedef struct axfr_rrstream { 314135446Strhodes rrstream_t common; 315224092Sdougb dns_rriterator_t it; 316135446Strhodes isc_boolean_t it_valid; 317135446Strhodes} axfr_rrstream_t; 318135446Strhodes 319135446Strhodes/* 320135446Strhodes * Forward declarations. 321135446Strhodes */ 322135446Strhodesstatic void 323135446Strhodesaxfr_rrstream_destroy(rrstream_t **rsp); 324135446Strhodes 325135446Strhodesstatic rrstream_methods_t axfr_rrstream_methods; 326135446Strhodes 327135446Strhodesstatic isc_result_t 328135446Strhodesaxfr_rrstream_create(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *ver, 329135446Strhodes rrstream_t **sp) 330135446Strhodes{ 331135446Strhodes axfr_rrstream_t *s; 332135446Strhodes isc_result_t result; 333135446Strhodes 334135446Strhodes INSIST(sp != NULL && *sp == NULL); 335135446Strhodes 336135446Strhodes s = isc_mem_get(mctx, sizeof(*s)); 337135446Strhodes if (s == NULL) 338135446Strhodes return (ISC_R_NOMEMORY); 339254897Serwin s->common.mctx = NULL; 340254897Serwin isc_mem_attach(mctx, &s->common.mctx); 341135446Strhodes s->common.methods = &axfr_rrstream_methods; 342135446Strhodes s->it_valid = ISC_FALSE; 343135446Strhodes 344224092Sdougb CHECK(dns_rriterator_init(&s->it, db, ver, 0)); 345135446Strhodes s->it_valid = ISC_TRUE; 346135446Strhodes 347135446Strhodes *sp = (rrstream_t *) s; 348135446Strhodes return (ISC_R_SUCCESS); 349135446Strhodes 350135446Strhodes failure: 351135446Strhodes axfr_rrstream_destroy((rrstream_t **) (void *)&s); 352135446Strhodes return (result); 353135446Strhodes} 354135446Strhodes 355135446Strhodesstatic isc_result_t 356135446Strhodesaxfr_rrstream_first(rrstream_t *rs) { 357135446Strhodes axfr_rrstream_t *s = (axfr_rrstream_t *) rs; 358135446Strhodes isc_result_t result; 359224092Sdougb result = dns_rriterator_first(&s->it); 360135446Strhodes if (result != ISC_R_SUCCESS) 361135446Strhodes return (result); 362135446Strhodes /* Skip SOA records. */ 363135446Strhodes for (;;) { 364135446Strhodes dns_name_t *name_dummy = NULL; 365135446Strhodes isc_uint32_t ttl_dummy; 366135446Strhodes dns_rdata_t *rdata = NULL; 367224092Sdougb dns_rriterator_current(&s->it, &name_dummy, 368224092Sdougb &ttl_dummy, NULL, &rdata); 369135446Strhodes if (rdata->type != dns_rdatatype_soa) 370135446Strhodes break; 371224092Sdougb result = dns_rriterator_next(&s->it); 372135446Strhodes if (result != ISC_R_SUCCESS) 373135446Strhodes break; 374135446Strhodes } 375135446Strhodes return (result); 376135446Strhodes} 377135446Strhodes 378135446Strhodesstatic isc_result_t 379135446Strhodesaxfr_rrstream_next(rrstream_t *rs) { 380135446Strhodes axfr_rrstream_t *s = (axfr_rrstream_t *) rs; 381135446Strhodes isc_result_t result; 382135446Strhodes 383135446Strhodes /* Skip SOA records. */ 384135446Strhodes for (;;) { 385135446Strhodes dns_name_t *name_dummy = NULL; 386135446Strhodes isc_uint32_t ttl_dummy; 387135446Strhodes dns_rdata_t *rdata = NULL; 388224092Sdougb result = dns_rriterator_next(&s->it); 389135446Strhodes if (result != ISC_R_SUCCESS) 390135446Strhodes break; 391224092Sdougb dns_rriterator_current(&s->it, &name_dummy, 392224092Sdougb &ttl_dummy, NULL, &rdata); 393135446Strhodes if (rdata->type != dns_rdatatype_soa) 394135446Strhodes break; 395135446Strhodes } 396135446Strhodes return (result); 397135446Strhodes} 398135446Strhodes 399135446Strhodesstatic void 400135446Strhodesaxfr_rrstream_current(rrstream_t *rs, dns_name_t **name, isc_uint32_t *ttl, 401135446Strhodes dns_rdata_t **rdata) 402135446Strhodes{ 403135446Strhodes axfr_rrstream_t *s = (axfr_rrstream_t *) rs; 404224092Sdougb dns_rriterator_current(&s->it, name, ttl, NULL, rdata); 405135446Strhodes} 406135446Strhodes 407135446Strhodesstatic void 408135446Strhodesaxfr_rrstream_pause(rrstream_t *rs) { 409135446Strhodes axfr_rrstream_t *s = (axfr_rrstream_t *) rs; 410224092Sdougb dns_rriterator_pause(&s->it); 411135446Strhodes} 412135446Strhodes 413135446Strhodesstatic void 414135446Strhodesaxfr_rrstream_destroy(rrstream_t **rsp) { 415135446Strhodes axfr_rrstream_t *s = (axfr_rrstream_t *) *rsp; 416135446Strhodes if (s->it_valid) 417224092Sdougb dns_rriterator_destroy(&s->it); 418254897Serwin isc_mem_putanddetach(&s->common.mctx, s, sizeof(*s)); 419135446Strhodes} 420135446Strhodes 421135446Strhodesstatic rrstream_methods_t axfr_rrstream_methods = { 422135446Strhodes axfr_rrstream_first, 423135446Strhodes axfr_rrstream_next, 424135446Strhodes axfr_rrstream_current, 425135446Strhodes axfr_rrstream_pause, 426135446Strhodes axfr_rrstream_destroy 427135446Strhodes}; 428135446Strhodes 429135446Strhodes/**************************************************************************/ 430135446Strhodes/* 431135446Strhodes * An 'soa_rrstream_t' is a degenerate 'rrstream_t' that returns 432135446Strhodes * a single SOA record. 433135446Strhodes */ 434135446Strhodes 435135446Strhodestypedef struct soa_rrstream { 436135446Strhodes rrstream_t common; 437135446Strhodes dns_difftuple_t *soa_tuple; 438135446Strhodes} soa_rrstream_t; 439135446Strhodes 440135446Strhodes/* 441135446Strhodes * Forward declarations. 442135446Strhodes */ 443135446Strhodesstatic void 444135446Strhodessoa_rrstream_destroy(rrstream_t **rsp); 445135446Strhodes 446135446Strhodesstatic rrstream_methods_t soa_rrstream_methods; 447135446Strhodes 448135446Strhodesstatic isc_result_t 449135446Strhodessoa_rrstream_create(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *ver, 450135446Strhodes rrstream_t **sp) 451135446Strhodes{ 452135446Strhodes soa_rrstream_t *s; 453135446Strhodes isc_result_t result; 454135446Strhodes 455135446Strhodes INSIST(sp != NULL && *sp == NULL); 456135446Strhodes 457135446Strhodes s = isc_mem_get(mctx, sizeof(*s)); 458135446Strhodes if (s == NULL) 459135446Strhodes return (ISC_R_NOMEMORY); 460254897Serwin s->common.mctx = NULL; 461254897Serwin isc_mem_attach(mctx, &s->common.mctx); 462135446Strhodes s->common.methods = &soa_rrstream_methods; 463135446Strhodes s->soa_tuple = NULL; 464135446Strhodes 465135446Strhodes CHECK(dns_db_createsoatuple(db, ver, mctx, DNS_DIFFOP_EXISTS, 466135446Strhodes &s->soa_tuple)); 467135446Strhodes 468135446Strhodes *sp = (rrstream_t *) s; 469135446Strhodes return (ISC_R_SUCCESS); 470135446Strhodes 471135446Strhodes failure: 472135446Strhodes soa_rrstream_destroy((rrstream_t **) (void *)&s); 473135446Strhodes return (result); 474135446Strhodes} 475135446Strhodes 476135446Strhodesstatic isc_result_t 477135446Strhodessoa_rrstream_first(rrstream_t *rs) { 478135446Strhodes UNUSED(rs); 479135446Strhodes return (ISC_R_SUCCESS); 480135446Strhodes} 481135446Strhodes 482135446Strhodesstatic isc_result_t 483135446Strhodessoa_rrstream_next(rrstream_t *rs) { 484135446Strhodes UNUSED(rs); 485135446Strhodes return (ISC_R_NOMORE); 486135446Strhodes} 487135446Strhodes 488135446Strhodesstatic void 489135446Strhodessoa_rrstream_current(rrstream_t *rs, dns_name_t **name, isc_uint32_t *ttl, 490135446Strhodes dns_rdata_t **rdata) 491135446Strhodes{ 492135446Strhodes soa_rrstream_t *s = (soa_rrstream_t *) rs; 493135446Strhodes *name = &s->soa_tuple->name; 494135446Strhodes *ttl = s->soa_tuple->ttl; 495135446Strhodes *rdata = &s->soa_tuple->rdata; 496135446Strhodes} 497135446Strhodes 498135446Strhodesstatic void 499135446Strhodessoa_rrstream_destroy(rrstream_t **rsp) { 500135446Strhodes soa_rrstream_t *s = (soa_rrstream_t *) *rsp; 501135446Strhodes if (s->soa_tuple != NULL) 502135446Strhodes dns_difftuple_free(&s->soa_tuple); 503254897Serwin isc_mem_putanddetach(&s->common.mctx, s, sizeof(*s)); 504135446Strhodes} 505135446Strhodes 506135446Strhodesstatic rrstream_methods_t soa_rrstream_methods = { 507135446Strhodes soa_rrstream_first, 508135446Strhodes soa_rrstream_next, 509135446Strhodes soa_rrstream_current, 510135446Strhodes rrstream_noop_pause, 511135446Strhodes soa_rrstream_destroy 512135446Strhodes}; 513135446Strhodes 514135446Strhodes/**************************************************************************/ 515135446Strhodes/* 516135446Strhodes * A 'compound_rrstream_t' objects owns a soa_rrstream 517135446Strhodes * and another rrstream, the "data stream". It returns 518135446Strhodes * a concatenated stream consisting of the soa_rrstream, then 519135446Strhodes * the data stream, then the soa_rrstream again. 520135446Strhodes * 521135446Strhodes * The component streams are owned by the compound_rrstream_t 522135446Strhodes * and are destroyed with it. 523135446Strhodes */ 524135446Strhodes 525135446Strhodestypedef struct compound_rrstream { 526135446Strhodes rrstream_t common; 527135446Strhodes rrstream_t *components[3]; 528135446Strhodes int state; 529135446Strhodes isc_result_t result; 530135446Strhodes} compound_rrstream_t; 531135446Strhodes 532135446Strhodes/* 533135446Strhodes * Forward declarations. 534135446Strhodes */ 535135446Strhodesstatic void 536135446Strhodescompound_rrstream_destroy(rrstream_t **rsp); 537135446Strhodes 538135446Strhodesstatic isc_result_t 539135446Strhodescompound_rrstream_next(rrstream_t *rs); 540135446Strhodes 541135446Strhodesstatic rrstream_methods_t compound_rrstream_methods; 542135446Strhodes 543135446Strhodes/* 544135446Strhodes * Requires: 545135446Strhodes * soa_stream != NULL && *soa_stream != NULL 546135446Strhodes * data_stream != NULL && *data_stream != NULL 547135446Strhodes * sp != NULL && *sp == NULL 548135446Strhodes * 549135446Strhodes * Ensures: 550135446Strhodes * *soa_stream == NULL 551135446Strhodes * *data_stream == NULL 552135446Strhodes * *sp points to a valid compound_rrstream_t 553135446Strhodes * The soa and data streams will be destroyed 554135446Strhodes * when the compound_rrstream_t is destroyed. 555135446Strhodes */ 556135446Strhodesstatic isc_result_t 557135446Strhodescompound_rrstream_create(isc_mem_t *mctx, rrstream_t **soa_stream, 558135446Strhodes rrstream_t **data_stream, rrstream_t **sp) 559135446Strhodes{ 560135446Strhodes compound_rrstream_t *s; 561135446Strhodes 562135446Strhodes INSIST(sp != NULL && *sp == NULL); 563135446Strhodes 564135446Strhodes s = isc_mem_get(mctx, sizeof(*s)); 565135446Strhodes if (s == NULL) 566135446Strhodes return (ISC_R_NOMEMORY); 567254897Serwin s->common.mctx = NULL; 568254897Serwin isc_mem_attach(mctx, &s->common.mctx); 569135446Strhodes s->common.methods = &compound_rrstream_methods; 570135446Strhodes s->components[0] = *soa_stream; 571135446Strhodes s->components[1] = *data_stream; 572135446Strhodes s->components[2] = *soa_stream; 573135446Strhodes s->state = -1; 574135446Strhodes s->result = ISC_R_FAILURE; 575135446Strhodes 576135446Strhodes *soa_stream = NULL; 577135446Strhodes *data_stream = NULL; 578135446Strhodes *sp = (rrstream_t *) s; 579135446Strhodes return (ISC_R_SUCCESS); 580135446Strhodes} 581135446Strhodes 582135446Strhodesstatic isc_result_t 583135446Strhodescompound_rrstream_first(rrstream_t *rs) { 584135446Strhodes compound_rrstream_t *s = (compound_rrstream_t *) rs; 585135446Strhodes s->state = 0; 586135446Strhodes do { 587135446Strhodes rrstream_t *curstream = s->components[s->state]; 588135446Strhodes s->result = curstream->methods->first(curstream); 589135446Strhodes } while (s->result == ISC_R_NOMORE && s->state < 2); 590135446Strhodes return (s->result); 591135446Strhodes} 592135446Strhodes 593135446Strhodesstatic isc_result_t 594135446Strhodescompound_rrstream_next(rrstream_t *rs) { 595135446Strhodes compound_rrstream_t *s = (compound_rrstream_t *) rs; 596135446Strhodes rrstream_t *curstream = s->components[s->state]; 597135446Strhodes s->result = curstream->methods->next(curstream); 598135446Strhodes while (s->result == ISC_R_NOMORE) { 599135446Strhodes /* 600135446Strhodes * Make sure locks held by the current stream 601135446Strhodes * are released before we switch streams. 602135446Strhodes */ 603135446Strhodes curstream->methods->pause(curstream); 604135446Strhodes if (s->state == 2) 605135446Strhodes return (ISC_R_NOMORE); 606135446Strhodes s->state++; 607135446Strhodes curstream = s->components[s->state]; 608135446Strhodes s->result = curstream->methods->first(curstream); 609135446Strhodes } 610135446Strhodes return (s->result); 611135446Strhodes} 612135446Strhodes 613135446Strhodesstatic void 614135446Strhodescompound_rrstream_current(rrstream_t *rs, dns_name_t **name, isc_uint32_t *ttl, 615135446Strhodes dns_rdata_t **rdata) 616135446Strhodes{ 617135446Strhodes compound_rrstream_t *s = (compound_rrstream_t *) rs; 618135446Strhodes rrstream_t *curstream; 619135446Strhodes INSIST(0 <= s->state && s->state < 3); 620135446Strhodes INSIST(s->result == ISC_R_SUCCESS); 621135446Strhodes curstream = s->components[s->state]; 622135446Strhodes curstream->methods->current(curstream, name, ttl, rdata); 623135446Strhodes} 624135446Strhodes 625135446Strhodesstatic void 626135446Strhodescompound_rrstream_pause(rrstream_t *rs) 627135446Strhodes{ 628135446Strhodes compound_rrstream_t *s = (compound_rrstream_t *) rs; 629135446Strhodes rrstream_t *curstream; 630135446Strhodes INSIST(0 <= s->state && s->state < 3); 631135446Strhodes curstream = s->components[s->state]; 632135446Strhodes curstream->methods->pause(curstream); 633135446Strhodes} 634135446Strhodes 635135446Strhodesstatic void 636135446Strhodescompound_rrstream_destroy(rrstream_t **rsp) { 637135446Strhodes compound_rrstream_t *s = (compound_rrstream_t *) *rsp; 638135446Strhodes s->components[0]->methods->destroy(&s->components[0]); 639135446Strhodes s->components[1]->methods->destroy(&s->components[1]); 640135446Strhodes s->components[2] = NULL; /* Copy of components[0]. */ 641254897Serwin isc_mem_putanddetach(&s->common.mctx, s, sizeof(*s)); 642135446Strhodes} 643135446Strhodes 644135446Strhodesstatic rrstream_methods_t compound_rrstream_methods = { 645135446Strhodes compound_rrstream_first, 646135446Strhodes compound_rrstream_next, 647135446Strhodes compound_rrstream_current, 648135446Strhodes compound_rrstream_pause, 649135446Strhodes compound_rrstream_destroy 650135446Strhodes}; 651135446Strhodes 652135446Strhodes/**************************************************************************/ 653135446Strhodes/* 654135446Strhodes * An 'xfrout_ctx_t' contains the state of an outgoing AXFR or IXFR 655135446Strhodes * in progress. 656135446Strhodes */ 657135446Strhodes 658135446Strhodestypedef struct { 659135446Strhodes isc_mem_t *mctx; 660135446Strhodes ns_client_t *client; 661135446Strhodes unsigned int id; /* ID of request */ 662135446Strhodes dns_name_t *qname; /* Question name of request */ 663135446Strhodes dns_rdatatype_t qtype; /* dns_rdatatype_{a,i}xfr */ 664135446Strhodes dns_rdataclass_t qclass; 665193149Sdougb dns_zone_t *zone; /* (necessary for stats) */ 666135446Strhodes dns_db_t *db; 667135446Strhodes dns_dbversion_t *ver; 668135446Strhodes isc_quota_t *quota; 669135446Strhodes rrstream_t *stream; /* The XFR RR stream */ 670135446Strhodes isc_boolean_t end_of_stream; /* EOS has been reached */ 671135446Strhodes isc_buffer_t buf; /* Buffer for message owner 672135446Strhodes names and rdatas */ 673135446Strhodes isc_buffer_t txlenbuf; /* Transmit length buffer */ 674135446Strhodes isc_buffer_t txbuf; /* Transmit message buffer */ 675135446Strhodes void *txmem; 676135446Strhodes unsigned int txmemlen; 677135446Strhodes unsigned int nmsg; /* Number of messages sent */ 678135446Strhodes dns_tsigkey_t *tsigkey; /* Key used to create TSIG */ 679135446Strhodes isc_buffer_t *lasttsig; /* the last TSIG */ 680135446Strhodes isc_boolean_t many_answers; 681135446Strhodes int sends; /* Send in progress */ 682135446Strhodes isc_boolean_t shuttingdown; 683135446Strhodes const char *mnemonic; /* Style of transfer */ 684135446Strhodes} xfrout_ctx_t; 685135446Strhodes 686135446Strhodesstatic isc_result_t 687135446Strhodesxfrout_ctx_create(isc_mem_t *mctx, ns_client_t *client, 688135446Strhodes unsigned int id, dns_name_t *qname, dns_rdatatype_t qtype, 689193149Sdougb dns_rdataclass_t qclass, dns_zone_t *zone, 690135446Strhodes dns_db_t *db, dns_dbversion_t *ver, isc_quota_t *quota, 691135446Strhodes rrstream_t *stream, dns_tsigkey_t *tsigkey, 692135446Strhodes isc_buffer_t *lasttsig, 693135446Strhodes unsigned int maxtime, 694135446Strhodes unsigned int idletime, 695135446Strhodes isc_boolean_t many_answers, 696135446Strhodes xfrout_ctx_t **xfrp); 697135446Strhodes 698135446Strhodesstatic void 699135446Strhodessendstream(xfrout_ctx_t *xfr); 700135446Strhodes 701135446Strhodesstatic void 702135446Strhodesxfrout_senddone(isc_task_t *task, isc_event_t *event); 703135446Strhodes 704135446Strhodesstatic void 705135446Strhodesxfrout_fail(xfrout_ctx_t *xfr, isc_result_t result, const char *msg); 706135446Strhodes 707135446Strhodesstatic void 708135446Strhodesxfrout_maybe_destroy(xfrout_ctx_t *xfr); 709135446Strhodes 710135446Strhodesstatic void 711135446Strhodesxfrout_ctx_destroy(xfrout_ctx_t **xfrp); 712135446Strhodes 713135446Strhodesstatic void 714135446Strhodesxfrout_client_shutdown(void *arg, isc_result_t result); 715135446Strhodes 716135446Strhodesstatic void 717135446Strhodesxfrout_log1(ns_client_t *client, dns_name_t *zonename, 718135446Strhodes dns_rdataclass_t rdclass, int level, 719135446Strhodes const char *fmt, ...) ISC_FORMAT_PRINTF(5, 6); 720135446Strhodes 721135446Strhodesstatic void 722153816Sdougbxfrout_log(xfrout_ctx_t *xfr, int level, const char *fmt, ...) 723135446Strhodes ISC_FORMAT_PRINTF(3, 4); 724135446Strhodes 725135446Strhodes/**************************************************************************/ 726135446Strhodes 727135446Strhodesvoid 728135446Strhodesns_xfr_start(ns_client_t *client, dns_rdatatype_t reqtype) { 729135446Strhodes isc_result_t result; 730135446Strhodes dns_name_t *question_name; 731135446Strhodes dns_rdataset_t *question_rdataset; 732135446Strhodes dns_zone_t *zone = NULL; 733135446Strhodes dns_db_t *db = NULL; 734135446Strhodes dns_dbversion_t *ver = NULL; 735135446Strhodes dns_rdataclass_t question_class; 736135446Strhodes rrstream_t *soa_stream = NULL; 737135446Strhodes rrstream_t *data_stream = NULL; 738135446Strhodes rrstream_t *stream = NULL; 739135446Strhodes dns_difftuple_t *current_soa_tuple = NULL; 740135446Strhodes dns_name_t *soa_name; 741135446Strhodes dns_rdataset_t *soa_rdataset; 742135446Strhodes dns_rdata_t soa_rdata = DNS_RDATA_INIT; 743135446Strhodes isc_boolean_t have_soa = ISC_FALSE; 744135446Strhodes const char *mnemonic = NULL; 745135446Strhodes isc_mem_t *mctx = client->mctx; 746135446Strhodes dns_message_t *request = client->message; 747135446Strhodes xfrout_ctx_t *xfr = NULL; 748135446Strhodes isc_quota_t *quota = NULL; 749135446Strhodes dns_transfer_format_t format = client->view->transfer_format; 750135446Strhodes isc_netaddr_t na; 751135446Strhodes dns_peer_t *peer = NULL; 752135446Strhodes isc_buffer_t *tsigbuf = NULL; 753135446Strhodes char *journalfile; 754135446Strhodes char msg[NS_CLIENT_ACLMSGSIZE("zone transfer")]; 755135446Strhodes char keyname[DNS_NAME_FORMATSIZE]; 756135446Strhodes isc_boolean_t is_poll = ISC_FALSE; 757170222Sdougb isc_boolean_t is_dlz = ISC_FALSE; 758135446Strhodes 759135446Strhodes switch (reqtype) { 760135446Strhodes case dns_rdatatype_axfr: 761135446Strhodes mnemonic = "AXFR"; 762135446Strhodes break; 763135446Strhodes case dns_rdatatype_ixfr: 764135446Strhodes mnemonic = "IXFR"; 765135446Strhodes break; 766135446Strhodes default: 767135446Strhodes INSIST(0); 768135446Strhodes break; 769135446Strhodes } 770135446Strhodes 771135446Strhodes ns_client_log(client, 772135446Strhodes DNS_LOGCATEGORY_XFER_OUT, NS_LOGMODULE_XFER_OUT, 773135446Strhodes ISC_LOG_DEBUG(6), "%s request", mnemonic); 774135446Strhodes /* 775135446Strhodes * Apply quota. 776135446Strhodes */ 777135446Strhodes result = isc_quota_attach(&ns_g_server->xfroutquota, "a); 778135446Strhodes if (result != ISC_R_SUCCESS) { 779135446Strhodes isc_log_write(XFROUT_COMMON_LOGARGS, ISC_LOG_WARNING, 780135446Strhodes "%s request denied: %s", mnemonic, 781135446Strhodes isc_result_totext(result)); 782135446Strhodes goto failure; 783135446Strhodes } 784135446Strhodes 785135446Strhodes /* 786135446Strhodes * Interpret the question section. 787135446Strhodes */ 788135446Strhodes result = dns_message_firstname(request, DNS_SECTION_QUESTION); 789135446Strhodes INSIST(result == ISC_R_SUCCESS); 790135446Strhodes 791135446Strhodes /* 792135446Strhodes * The question section must contain exactly one question, and 793135446Strhodes * it must be for AXFR/IXFR as appropriate. 794135446Strhodes */ 795135446Strhodes question_name = NULL; 796135446Strhodes dns_message_currentname(request, DNS_SECTION_QUESTION, &question_name); 797135446Strhodes question_rdataset = ISC_LIST_HEAD(question_name->list); 798135446Strhodes question_class = question_rdataset->rdclass; 799135446Strhodes INSIST(question_rdataset->type == reqtype); 800135446Strhodes if (ISC_LIST_NEXT(question_rdataset, link) != NULL) 801135446Strhodes FAILC(DNS_R_FORMERR, "multiple questions"); 802135446Strhodes result = dns_message_nextname(request, DNS_SECTION_QUESTION); 803135446Strhodes if (result != ISC_R_NOMORE) 804135446Strhodes FAILC(DNS_R_FORMERR, "multiple questions"); 805135446Strhodes 806135446Strhodes result = dns_zt_find(client->view->zonetable, question_name, 0, NULL, 807135446Strhodes &zone); 808170222Sdougb 809225361Sdougb if (result != ISC_R_SUCCESS) { 810170222Sdougb /* 811218384Sdougb * Normal zone table does not have a match. 812218384Sdougb * Try the DLZ database 813170222Sdougb */ 814193149Sdougb if (client->view->dlzdatabase != NULL) { 815170222Sdougb result = dns_dlzallowzonexfr(client->view, 816218384Sdougb question_name, 817218384Sdougb &client->peeraddr, 818170222Sdougb &db); 819170222Sdougb 820170222Sdougb if (result == ISC_R_NOPERM) { 821170222Sdougb char _buf1[DNS_NAME_FORMATSIZE]; 822170222Sdougb char _buf2[DNS_RDATACLASS_FORMATSIZE]; 823170222Sdougb 824170222Sdougb result = DNS_R_REFUSED; 825170222Sdougb dns_name_format(question_name, _buf1, 826170222Sdougb sizeof(_buf1)); 827170222Sdougb dns_rdataclass_format(question_class, 828170222Sdougb _buf2, sizeof(_buf2)); 829170222Sdougb ns_client_log(client, DNS_LOGCATEGORY_SECURITY, 830170222Sdougb NS_LOGMODULE_XFER_OUT, 831170222Sdougb ISC_LOG_ERROR, 832170222Sdougb "zone transfer '%s/%s' denied", 833170222Sdougb _buf1, _buf2); 834170222Sdougb goto failure; 835170222Sdougb } 836170222Sdougb if (result != ISC_R_SUCCESS) 837225361Sdougb FAILQ(DNS_R_NOTAUTH, "non-authoritative zone", 838225361Sdougb question_name, question_class); 839170222Sdougb is_dlz = ISC_TRUE; 840170222Sdougb } else { 841170222Sdougb /* 842193149Sdougb * not DLZ and not in normal zone table, we are 843170222Sdougb * not authoritative 844170222Sdougb */ 845170222Sdougb FAILQ(DNS_R_NOTAUTH, "non-authoritative zone", 846170222Sdougb question_name, question_class); 847170222Sdougb } 848170222Sdougb } else { 849170222Sdougb /* zone table has a match */ 850170222Sdougb switch(dns_zone_gettype(zone)) { 851254402Serwin /* Master and slave zones are OK for transfer. */ 852170222Sdougb case dns_zone_master: 853170222Sdougb case dns_zone_slave: 854224092Sdougb case dns_zone_dlz: 855254402Serwin break; 856170222Sdougb default: 857254402Serwin FAILQ(DNS_R_NOTAUTH, "non-authoritative zone", 858254402Serwin question_name, question_class); 859170222Sdougb } 860170222Sdougb CHECK(dns_zone_getdb(zone, &db)); 861170222Sdougb dns_db_currentversion(db, &ver); 862135446Strhodes } 863135446Strhodes 864135446Strhodes xfrout_log1(client, question_name, question_class, ISC_LOG_DEBUG(6), 865135446Strhodes "%s question section OK", mnemonic); 866135446Strhodes 867135446Strhodes /* 868135446Strhodes * Check the authority section. Look for a SOA record with 869135446Strhodes * the same name and class as the question. 870135446Strhodes */ 871135446Strhodes for (result = dns_message_firstname(request, DNS_SECTION_AUTHORITY); 872135446Strhodes result == ISC_R_SUCCESS; 873135446Strhodes result = dns_message_nextname(request, DNS_SECTION_AUTHORITY)) 874135446Strhodes { 875135446Strhodes soa_name = NULL; 876135446Strhodes dns_message_currentname(request, DNS_SECTION_AUTHORITY, 877135446Strhodes &soa_name); 878135446Strhodes 879135446Strhodes /* 880135446Strhodes * Ignore data whose owner name is not the zone apex. 881135446Strhodes */ 882135446Strhodes if (! dns_name_equal(soa_name, question_name)) 883135446Strhodes continue; 884135446Strhodes 885135446Strhodes for (soa_rdataset = ISC_LIST_HEAD(soa_name->list); 886135446Strhodes soa_rdataset != NULL; 887135446Strhodes soa_rdataset = ISC_LIST_NEXT(soa_rdataset, link)) 888135446Strhodes { 889135446Strhodes /* 890135446Strhodes * Ignore non-SOA data. 891135446Strhodes */ 892135446Strhodes if (soa_rdataset->type != dns_rdatatype_soa) 893135446Strhodes continue; 894135446Strhodes if (soa_rdataset->rdclass != question_class) 895135446Strhodes continue; 896135446Strhodes 897135446Strhodes CHECK(dns_rdataset_first(soa_rdataset)); 898135446Strhodes dns_rdataset_current(soa_rdataset, &soa_rdata); 899135446Strhodes result = dns_rdataset_next(soa_rdataset); 900135446Strhodes if (result == ISC_R_SUCCESS) 901135446Strhodes FAILC(DNS_R_FORMERR, 902135446Strhodes "IXFR authority section " 903135446Strhodes "has multiple SOAs"); 904135446Strhodes have_soa = ISC_TRUE; 905135446Strhodes goto got_soa; 906135446Strhodes } 907135446Strhodes } 908135446Strhodes got_soa: 909135446Strhodes if (result != ISC_R_NOMORE) 910135446Strhodes CHECK(result); 911135446Strhodes 912135446Strhodes xfrout_log1(client, question_name, question_class, ISC_LOG_DEBUG(6), 913135446Strhodes "%s authority section OK", mnemonic); 914135446Strhodes 915135446Strhodes /* 916225361Sdougb * If not a DLZ zone, decide whether to allow this transfer. 917135446Strhodes */ 918170222Sdougb if (!is_dlz) { 919170222Sdougb ns_client_aclmsg("zone transfer", question_name, reqtype, 920170222Sdougb client->view->rdclass, msg, sizeof(msg)); 921193149Sdougb CHECK(ns_client_checkacl(client, NULL, msg, 922193149Sdougb dns_zone_getxfracl(zone), 923193149Sdougb ISC_TRUE, ISC_LOG_ERROR)); 924170222Sdougb } 925135446Strhodes 926135446Strhodes /* 927135446Strhodes * AXFR over UDP is not possible. 928135446Strhodes */ 929135446Strhodes if (reqtype == dns_rdatatype_axfr && 930135446Strhodes (client->attributes & NS_CLIENTATTR_TCP) == 0) 931135446Strhodes FAILC(DNS_R_FORMERR, "attempted AXFR over UDP"); 932135446Strhodes 933135446Strhodes /* 934135446Strhodes * Look up the requesting server in the peer table. 935135446Strhodes */ 936135446Strhodes isc_netaddr_fromsockaddr(&na, &client->peeraddr); 937135446Strhodes (void)dns_peerlist_peerbyaddr(client->view->peers, &na, &peer); 938135446Strhodes 939135446Strhodes /* 940135446Strhodes * Decide on the transfer format (one-answer or many-answers). 941135446Strhodes */ 942135446Strhodes if (peer != NULL) 943135446Strhodes (void)dns_peer_gettransferformat(peer, &format); 944135446Strhodes 945135446Strhodes /* 946135446Strhodes * Get a dynamically allocated copy of the current SOA. 947135446Strhodes */ 948170222Sdougb if (is_dlz) 949170222Sdougb dns_db_currentversion(db, &ver); 950225361Sdougb 951135446Strhodes CHECK(dns_db_createsoatuple(db, ver, mctx, DNS_DIFFOP_EXISTS, 952135446Strhodes ¤t_soa_tuple)); 953135446Strhodes 954135446Strhodes if (reqtype == dns_rdatatype_ixfr) { 955135446Strhodes isc_uint32_t begin_serial, current_serial; 956135446Strhodes isc_boolean_t provide_ixfr; 957135446Strhodes 958135446Strhodes /* 959135446Strhodes * Outgoing IXFR may have been disabled for this peer 960135446Strhodes * or globally. 961135446Strhodes */ 962135446Strhodes provide_ixfr = client->view->provideixfr; 963135446Strhodes if (peer != NULL) 964135446Strhodes (void) dns_peer_getprovideixfr(peer, &provide_ixfr); 965135446Strhodes if (provide_ixfr == ISC_FALSE) 966135446Strhodes goto axfr_fallback; 967135446Strhodes 968135446Strhodes if (! have_soa) 969135446Strhodes FAILC(DNS_R_FORMERR, 970135446Strhodes "IXFR request missing SOA"); 971135446Strhodes 972135446Strhodes begin_serial = dns_soa_getserial(&soa_rdata); 973135446Strhodes current_serial = dns_soa_getserial(¤t_soa_tuple->rdata); 974135446Strhodes 975135446Strhodes /* 976135446Strhodes * RFC1995 says "If an IXFR query with the same or 977135446Strhodes * newer version number than that of the server 978135446Strhodes * is received, it is replied to with a single SOA 979135446Strhodes * record of the server's current version, just as 980135446Strhodes * in AXFR". The claim about AXFR is incorrect, 981135446Strhodes * but other than that, we do as the RFC says. 982135446Strhodes * 983135446Strhodes * Sending a single SOA record is also how we refuse 984135446Strhodes * IXFR over UDP (currently, we always do). 985135446Strhodes */ 986135446Strhodes if (DNS_SERIAL_GE(begin_serial, current_serial) || 987135446Strhodes (client->attributes & NS_CLIENTATTR_TCP) == 0) 988135446Strhodes { 989135446Strhodes CHECK(soa_rrstream_create(mctx, db, ver, &stream)); 990135446Strhodes is_poll = ISC_TRUE; 991135446Strhodes goto have_stream; 992135446Strhodes } 993254402Serwin journalfile = is_dlz ? NULL : dns_zone_getjournal(zone); 994135446Strhodes if (journalfile != NULL) 995135446Strhodes result = ixfr_rrstream_create(mctx, 996135446Strhodes journalfile, 997135446Strhodes begin_serial, 998135446Strhodes current_serial, 999135446Strhodes &data_stream); 1000135446Strhodes else 1001135446Strhodes result = ISC_R_NOTFOUND; 1002135446Strhodes if (result == ISC_R_NOTFOUND || 1003135446Strhodes result == ISC_R_RANGE) { 1004135446Strhodes xfrout_log1(client, question_name, question_class, 1005135446Strhodes ISC_LOG_DEBUG(4), 1006135446Strhodes "IXFR version not in journal, " 1007135446Strhodes "falling back to AXFR"); 1008135446Strhodes mnemonic = "AXFR-style IXFR"; 1009135446Strhodes goto axfr_fallback; 1010135446Strhodes } 1011135446Strhodes CHECK(result); 1012135446Strhodes } else { 1013135446Strhodes axfr_fallback: 1014135446Strhodes CHECK(axfr_rrstream_create(mctx, db, ver, 1015135446Strhodes &data_stream)); 1016135446Strhodes } 1017135446Strhodes 1018135446Strhodes /* 1019193149Sdougb * Bracket the data stream with SOAs. 1020135446Strhodes */ 1021135446Strhodes CHECK(soa_rrstream_create(mctx, db, ver, &soa_stream)); 1022135446Strhodes CHECK(compound_rrstream_create(mctx, &soa_stream, &data_stream, 1023135446Strhodes &stream)); 1024135446Strhodes soa_stream = NULL; 1025135446Strhodes data_stream = NULL; 1026135446Strhodes 1027135446Strhodes have_stream: 1028135446Strhodes CHECK(dns_message_getquerytsig(request, mctx, &tsigbuf)); 1029135446Strhodes /* 1030135446Strhodes * Create the xfrout context object. This transfers the ownership 1031135446Strhodes * of "stream", "db", "ver", and "quota" to the xfrout context object. 1032135446Strhodes */ 1033170222Sdougb 1034170222Sdougb 1035170222Sdougb 1036170222Sdougb if (is_dlz) 1037218384Sdougb CHECK(xfrout_ctx_create(mctx, client, request->id, 1038218384Sdougb question_name, reqtype, question_class, 1039218384Sdougb zone, db, ver, quota, stream, 1040193149Sdougb dns_message_gettsigkey(request), 1041193149Sdougb tsigbuf, 1042193149Sdougb 3600, 1043193149Sdougb 3600, 1044193149Sdougb (format == dns_many_answers) ? 1045193149Sdougb ISC_TRUE : ISC_FALSE, 1046193149Sdougb &xfr)); 1047193149Sdougb else 1048218384Sdougb CHECK(xfrout_ctx_create(mctx, client, request->id, 1049218384Sdougb question_name, reqtype, question_class, 1050218384Sdougb zone, db, ver, quota, stream, 1051193149Sdougb dns_message_gettsigkey(request), 1052193149Sdougb tsigbuf, 1053193149Sdougb dns_zone_getmaxxfrout(zone), 1054193149Sdougb dns_zone_getidleout(zone), 1055193149Sdougb (format == dns_many_answers) ? 1056193149Sdougb ISC_TRUE : ISC_FALSE, 1057193149Sdougb &xfr)); 1058170222Sdougb 1059135446Strhodes xfr->mnemonic = mnemonic; 1060135446Strhodes stream = NULL; 1061135446Strhodes quota = NULL; 1062135446Strhodes 1063135446Strhodes CHECK(xfr->stream->methods->first(xfr->stream)); 1064135446Strhodes 1065225361Sdougb if (xfr->tsigkey != NULL) 1066135446Strhodes dns_name_format(&xfr->tsigkey->name, keyname, sizeof(keyname)); 1067225361Sdougb else 1068135446Strhodes keyname[0] = '\0'; 1069135446Strhodes if (is_poll) 1070135446Strhodes xfrout_log1(client, question_name, question_class, 1071135446Strhodes ISC_LOG_DEBUG(1), "IXFR poll up to date%s%s", 1072135446Strhodes (xfr->tsigkey != NULL) ? ": TSIG " : "", keyname); 1073135446Strhodes else 1074135446Strhodes xfrout_log1(client, question_name, question_class, 1075135446Strhodes ISC_LOG_INFO, "%s started%s%s", mnemonic, 1076135446Strhodes (xfr->tsigkey != NULL) ? ": TSIG " : "", keyname); 1077135446Strhodes 1078135446Strhodes /* 1079135446Strhodes * Hand the context over to sendstream(). Set xfr to NULL; 1080135446Strhodes * sendstream() is responsible for either passing the 1081135446Strhodes * context on to a later event handler or destroying it. 1082135446Strhodes */ 1083135446Strhodes sendstream(xfr); 1084135446Strhodes xfr = NULL; 1085135446Strhodes 1086135446Strhodes result = ISC_R_SUCCESS; 1087135446Strhodes 1088135446Strhodes failure: 1089193149Sdougb if (result == DNS_R_REFUSED) 1090193149Sdougb inc_stats(zone, dns_nsstatscounter_xfrrej); 1091135446Strhodes if (quota != NULL) 1092135446Strhodes isc_quota_detach("a); 1093135446Strhodes if (current_soa_tuple != NULL) 1094135446Strhodes dns_difftuple_free(¤t_soa_tuple); 1095135446Strhodes if (stream != NULL) 1096135446Strhodes stream->methods->destroy(&stream); 1097135446Strhodes if (soa_stream != NULL) 1098135446Strhodes soa_stream->methods->destroy(&soa_stream); 1099135446Strhodes if (data_stream != NULL) 1100135446Strhodes data_stream->methods->destroy(&data_stream); 1101135446Strhodes if (ver != NULL) 1102135446Strhodes dns_db_closeversion(db, &ver, ISC_FALSE); 1103135446Strhodes if (db != NULL) 1104135446Strhodes dns_db_detach(&db); 1105135446Strhodes if (zone != NULL) 1106135446Strhodes dns_zone_detach(&zone); 1107135446Strhodes /* XXX kludge */ 1108135446Strhodes if (xfr != NULL) { 1109135446Strhodes xfrout_fail(xfr, result, "setting up zone transfer"); 1110135446Strhodes } else if (result != ISC_R_SUCCESS) { 1111135446Strhodes ns_client_log(client, DNS_LOGCATEGORY_XFER_OUT, 1112135446Strhodes NS_LOGMODULE_XFER_OUT, 1113135446Strhodes ISC_LOG_DEBUG(3), "zone transfer setup failed"); 1114135446Strhodes ns_client_error(client, result); 1115135446Strhodes } 1116135446Strhodes} 1117135446Strhodes 1118135446Strhodesstatic isc_result_t 1119135446Strhodesxfrout_ctx_create(isc_mem_t *mctx, ns_client_t *client, unsigned int id, 1120135446Strhodes dns_name_t *qname, dns_rdatatype_t qtype, 1121193149Sdougb dns_rdataclass_t qclass, dns_zone_t *zone, 1122135446Strhodes dns_db_t *db, dns_dbversion_t *ver, isc_quota_t *quota, 1123135446Strhodes rrstream_t *stream, dns_tsigkey_t *tsigkey, 1124135446Strhodes isc_buffer_t *lasttsig, unsigned int maxtime, 1125135446Strhodes unsigned int idletime, isc_boolean_t many_answers, 1126135446Strhodes xfrout_ctx_t **xfrp) 1127135446Strhodes{ 1128135446Strhodes xfrout_ctx_t *xfr; 1129135446Strhodes isc_result_t result; 1130135446Strhodes unsigned int len; 1131135446Strhodes void *mem; 1132135446Strhodes 1133135446Strhodes INSIST(xfrp != NULL && *xfrp == NULL); 1134135446Strhodes xfr = isc_mem_get(mctx, sizeof(*xfr)); 1135135446Strhodes if (xfr == NULL) 1136135446Strhodes return (ISC_R_NOMEMORY); 1137225361Sdougb xfr->mctx = NULL; 1138225361Sdougb isc_mem_attach(mctx, &xfr->mctx); 1139135446Strhodes xfr->client = NULL; 1140135446Strhodes ns_client_attach(client, &xfr->client); 1141135446Strhodes xfr->id = id; 1142135446Strhodes xfr->qname = qname; 1143135446Strhodes xfr->qtype = qtype; 1144135446Strhodes xfr->qclass = qclass; 1145193149Sdougb xfr->zone = NULL; 1146135446Strhodes xfr->db = NULL; 1147135446Strhodes xfr->ver = NULL; 1148193149Sdougb if (zone != NULL) /* zone will be NULL if it's DLZ */ 1149193149Sdougb dns_zone_attach(zone, &xfr->zone); 1150135446Strhodes dns_db_attach(db, &xfr->db); 1151135446Strhodes dns_db_attachversion(db, ver, &xfr->ver); 1152135446Strhodes xfr->end_of_stream = ISC_FALSE; 1153135446Strhodes xfr->tsigkey = tsigkey; 1154135446Strhodes xfr->lasttsig = lasttsig; 1155135446Strhodes xfr->txmem = NULL; 1156135446Strhodes xfr->txmemlen = 0; 1157135446Strhodes xfr->nmsg = 0; 1158135446Strhodes xfr->many_answers = many_answers, 1159135446Strhodes xfr->sends = 0; 1160135446Strhodes xfr->shuttingdown = ISC_FALSE; 1161135446Strhodes xfr->mnemonic = NULL; 1162135446Strhodes xfr->buf.base = NULL; 1163135446Strhodes xfr->buf.length = 0; 1164135446Strhodes xfr->txmem = NULL; 1165135446Strhodes xfr->txmemlen = 0; 1166135446Strhodes xfr->stream = NULL; 1167135446Strhodes xfr->quota = NULL; 1168135446Strhodes 1169135446Strhodes /* 1170135446Strhodes * Allocate a temporary buffer for the uncompressed response 1171135446Strhodes * message data. The size should be no more than 65535 bytes 1172135446Strhodes * so that the compressed data will fit in a TCP message, 1173135446Strhodes * and no less than 65535 bytes so that an almost maximum-sized 1174135446Strhodes * RR will fit. Note that although 65535-byte RRs are allowed 1175135446Strhodes * in principle, they cannot be zone-transferred (at least not 1176135446Strhodes * if uncompressible), because the message and RR headers would 1177135446Strhodes * push the size of the TCP message over the 65536 byte limit. 1178135446Strhodes */ 1179135446Strhodes len = 65535; 1180135446Strhodes mem = isc_mem_get(mctx, len); 1181135446Strhodes if (mem == NULL) { 1182135446Strhodes result = ISC_R_NOMEMORY; 1183135446Strhodes goto failure; 1184135446Strhodes } 1185135446Strhodes isc_buffer_init(&xfr->buf, mem, len); 1186135446Strhodes 1187135446Strhodes /* 1188135446Strhodes * Allocate another temporary buffer for the compressed 1189135446Strhodes * response message and its TCP length prefix. 1190135446Strhodes */ 1191135446Strhodes len = 2 + 65535; 1192135446Strhodes mem = isc_mem_get(mctx, len); 1193135446Strhodes if (mem == NULL) { 1194135446Strhodes result = ISC_R_NOMEMORY; 1195135446Strhodes goto failure; 1196135446Strhodes } 1197135446Strhodes isc_buffer_init(&xfr->txlenbuf, mem, 2); 1198135446Strhodes isc_buffer_init(&xfr->txbuf, (char *) mem + 2, len - 2); 1199135446Strhodes xfr->txmem = mem; 1200135446Strhodes xfr->txmemlen = len; 1201135446Strhodes 1202135446Strhodes CHECK(dns_timer_setidle(xfr->client->timer, 1203135446Strhodes maxtime, idletime, ISC_FALSE)); 1204135446Strhodes 1205135446Strhodes /* 1206135446Strhodes * Register a shutdown callback with the client, so that we 1207135446Strhodes * can stop the transfer immediately when the client task 1208135446Strhodes * gets a shutdown event. 1209135446Strhodes */ 1210135446Strhodes xfr->client->shutdown = xfrout_client_shutdown; 1211135446Strhodes xfr->client->shutdown_arg = xfr; 1212135446Strhodes /* 1213135446Strhodes * These MUST be after the last "goto failure;" / CHECK to 1214135446Strhodes * prevent a double free by the caller. 1215135446Strhodes */ 1216135446Strhodes xfr->quota = quota; 1217135446Strhodes xfr->stream = stream; 1218135446Strhodes 1219135446Strhodes *xfrp = xfr; 1220135446Strhodes return (ISC_R_SUCCESS); 1221135446Strhodes 1222135446Strhodesfailure: 1223135446Strhodes xfrout_ctx_destroy(&xfr); 1224135446Strhodes return (result); 1225135446Strhodes} 1226135446Strhodes 1227135446Strhodes 1228135446Strhodes/* 1229135446Strhodes * Arrange to send as much as we can of "stream" without blocking. 1230135446Strhodes * 1231135446Strhodes * Requires: 1232135446Strhodes * The stream iterator is initialized and points at an RR, 1233193149Sdougb * or possibly at the end of the stream (that is, the 1234135446Strhodes * _first method of the iterator has been called). 1235135446Strhodes */ 1236135446Strhodesstatic void 1237135446Strhodessendstream(xfrout_ctx_t *xfr) { 1238135446Strhodes dns_message_t *tcpmsg = NULL; 1239135446Strhodes dns_message_t *msg = NULL; /* Client message if UDP, tcpmsg if TCP */ 1240135446Strhodes isc_result_t result; 1241135446Strhodes isc_region_t used; 1242135446Strhodes isc_region_t region; 1243135446Strhodes dns_rdataset_t *qrdataset; 1244135446Strhodes dns_name_t *msgname = NULL; 1245135446Strhodes dns_rdata_t *msgrdata = NULL; 1246135446Strhodes dns_rdatalist_t *msgrdl = NULL; 1247135446Strhodes dns_rdataset_t *msgrds = NULL; 1248135446Strhodes dns_compress_t cctx; 1249135446Strhodes isc_boolean_t cleanup_cctx = ISC_FALSE; 1250135446Strhodes 1251135446Strhodes int n_rrs; 1252135446Strhodes 1253135446Strhodes isc_buffer_clear(&xfr->buf); 1254135446Strhodes isc_buffer_clear(&xfr->txlenbuf); 1255135446Strhodes isc_buffer_clear(&xfr->txbuf); 1256135446Strhodes 1257135446Strhodes if ((xfr->client->attributes & NS_CLIENTATTR_TCP) == 0) { 1258135446Strhodes /* 1259135446Strhodes * In the UDP case, we put the response data directly into 1260135446Strhodes * the client message. 1261135446Strhodes */ 1262135446Strhodes msg = xfr->client->message; 1263135446Strhodes CHECK(dns_message_reply(msg, ISC_TRUE)); 1264135446Strhodes } else { 1265135446Strhodes /* 1266135446Strhodes * TCP. Build a response dns_message_t, temporarily storing 1267135446Strhodes * the raw, uncompressed owner names and RR data contiguously 1268135446Strhodes * in xfr->buf. We know that if the uncompressed data fits 1269135446Strhodes * in xfr->buf, the compressed data will surely fit in a TCP 1270135446Strhodes * message. 1271135446Strhodes */ 1272135446Strhodes 1273135446Strhodes CHECK(dns_message_create(xfr->mctx, 1274135446Strhodes DNS_MESSAGE_INTENTRENDER, &tcpmsg)); 1275135446Strhodes msg = tcpmsg; 1276135446Strhodes 1277135446Strhodes msg->id = xfr->id; 1278135446Strhodes msg->rcode = dns_rcode_noerror; 1279135446Strhodes msg->flags = DNS_MESSAGEFLAG_QR | DNS_MESSAGEFLAG_AA; 1280135446Strhodes if ((xfr->client->attributes & NS_CLIENTATTR_RA) != 0) 1281135446Strhodes msg->flags |= DNS_MESSAGEFLAG_RA; 1282135446Strhodes CHECK(dns_message_settsigkey(msg, xfr->tsigkey)); 1283135446Strhodes CHECK(dns_message_setquerytsig(msg, xfr->lasttsig)); 1284135446Strhodes if (xfr->lasttsig != NULL) 1285135446Strhodes isc_buffer_free(&xfr->lasttsig); 1286135446Strhodes 1287135446Strhodes /* 1288234010Sdougb * Account for reserved space. 1289234010Sdougb */ 1290234010Sdougb if (xfr->tsigkey != NULL) 1291234010Sdougb INSIST(msg->reserved != 0U); 1292234010Sdougb isc_buffer_add(&xfr->buf, msg->reserved); 1293234010Sdougb 1294234010Sdougb /* 1295135446Strhodes * Include a question section in the first message only. 1296135446Strhodes * BIND 8.2.1 will not recognize an IXFR if it does not 1297135446Strhodes * have a question section. 1298135446Strhodes */ 1299135446Strhodes if (xfr->nmsg == 0) { 1300135446Strhodes dns_name_t *qname = NULL; 1301135446Strhodes isc_region_t r; 1302135446Strhodes 1303135446Strhodes /* 1304135446Strhodes * Reserve space for the 12-byte message header 1305135446Strhodes * and 4 bytes of question. 1306135446Strhodes */ 1307135446Strhodes isc_buffer_add(&xfr->buf, 12 + 4); 1308135446Strhodes 1309135446Strhodes qrdataset = NULL; 1310135446Strhodes result = dns_message_gettemprdataset(msg, &qrdataset); 1311135446Strhodes if (result != ISC_R_SUCCESS) 1312135446Strhodes goto failure; 1313135446Strhodes dns_rdataset_init(qrdataset); 1314135446Strhodes dns_rdataset_makequestion(qrdataset, 1315135446Strhodes xfr->client->message->rdclass, 1316135446Strhodes xfr->qtype); 1317135446Strhodes 1318135446Strhodes result = dns_message_gettempname(msg, &qname); 1319135446Strhodes if (result != ISC_R_SUCCESS) 1320135446Strhodes goto failure; 1321135446Strhodes dns_name_init(qname, NULL); 1322135446Strhodes isc_buffer_availableregion(&xfr->buf, &r); 1323135446Strhodes INSIST(r.length >= xfr->qname->length); 1324135446Strhodes r.length = xfr->qname->length; 1325135446Strhodes isc_buffer_putmem(&xfr->buf, xfr->qname->ndata, 1326135446Strhodes xfr->qname->length); 1327135446Strhodes dns_name_fromregion(qname, &r); 1328135446Strhodes ISC_LIST_INIT(qname->list); 1329135446Strhodes ISC_LIST_APPEND(qname->list, qrdataset, link); 1330135446Strhodes 1331135446Strhodes dns_message_addname(msg, qname, DNS_SECTION_QUESTION); 1332234010Sdougb } else { 1333234010Sdougb /* 1334234010Sdougb * Reserve space for the 12-byte message header 1335234010Sdougb */ 1336234010Sdougb isc_buffer_add(&xfr->buf, 12); 1337234010Sdougb msg->tcp_continuation = 1; 1338135446Strhodes } 1339135446Strhodes } 1340135446Strhodes 1341135446Strhodes /* 1342135446Strhodes * Try to fit in as many RRs as possible, unless "one-answer" 1343135446Strhodes * format has been requested. 1344135446Strhodes */ 1345135446Strhodes for (n_rrs = 0; ; n_rrs++) { 1346135446Strhodes dns_name_t *name = NULL; 1347135446Strhodes isc_uint32_t ttl; 1348135446Strhodes dns_rdata_t *rdata = NULL; 1349135446Strhodes 1350135446Strhodes unsigned int size; 1351135446Strhodes isc_region_t r; 1352135446Strhodes 1353135446Strhodes msgname = NULL; 1354135446Strhodes msgrdata = NULL; 1355135446Strhodes msgrdl = NULL; 1356135446Strhodes msgrds = NULL; 1357135446Strhodes 1358135446Strhodes xfr->stream->methods->current(xfr->stream, 1359135446Strhodes &name, &ttl, &rdata); 1360135446Strhodes size = name->length + 10 + rdata->length; 1361135446Strhodes isc_buffer_availableregion(&xfr->buf, &r); 1362135446Strhodes if (size >= r.length) { 1363135446Strhodes /* 1364135446Strhodes * RR would not fit. If there are other RRs in the 1365135446Strhodes * buffer, send them now and leave this RR to the 1366135446Strhodes * next message. If this RR overflows the buffer 1367135446Strhodes * all by itself, fail. 1368135446Strhodes * 1369135446Strhodes * In theory some RRs might fit in a TCP message 1370135446Strhodes * when compressed even if they do not fit when 1371135446Strhodes * uncompressed, but surely we don't want 1372135446Strhodes * to send such monstrosities to an unsuspecting 1373135446Strhodes * slave. 1374135446Strhodes */ 1375135446Strhodes if (n_rrs == 0) { 1376135446Strhodes xfrout_log(xfr, ISC_LOG_WARNING, 1377135446Strhodes "RR too large for zone transfer " 1378135446Strhodes "(%d bytes)", size); 1379135446Strhodes /* XXX DNS_R_RRTOOLARGE? */ 1380135446Strhodes result = ISC_R_NOSPACE; 1381135446Strhodes goto failure; 1382135446Strhodes } 1383135446Strhodes break; 1384135446Strhodes } 1385135446Strhodes 1386135446Strhodes if (isc_log_wouldlog(ns_g_lctx, XFROUT_RR_LOGLEVEL)) 1387135446Strhodes log_rr(name, rdata, ttl); /* XXX */ 1388135446Strhodes 1389135446Strhodes result = dns_message_gettempname(msg, &msgname); 1390135446Strhodes if (result != ISC_R_SUCCESS) 1391135446Strhodes goto failure; 1392135446Strhodes dns_name_init(msgname, NULL); 1393135446Strhodes isc_buffer_availableregion(&xfr->buf, &r); 1394135446Strhodes INSIST(r.length >= name->length); 1395135446Strhodes r.length = name->length; 1396135446Strhodes isc_buffer_putmem(&xfr->buf, name->ndata, name->length); 1397135446Strhodes dns_name_fromregion(msgname, &r); 1398135446Strhodes 1399135446Strhodes /* Reserve space for RR header. */ 1400135446Strhodes isc_buffer_add(&xfr->buf, 10); 1401135446Strhodes 1402135446Strhodes result = dns_message_gettemprdata(msg, &msgrdata); 1403135446Strhodes if (result != ISC_R_SUCCESS) 1404135446Strhodes goto failure; 1405135446Strhodes isc_buffer_availableregion(&xfr->buf, &r); 1406135446Strhodes r.length = rdata->length; 1407135446Strhodes isc_buffer_putmem(&xfr->buf, rdata->data, rdata->length); 1408135446Strhodes dns_rdata_init(msgrdata); 1409135446Strhodes dns_rdata_fromregion(msgrdata, 1410135446Strhodes rdata->rdclass, rdata->type, &r); 1411135446Strhodes 1412135446Strhodes result = dns_message_gettemprdatalist(msg, &msgrdl); 1413135446Strhodes if (result != ISC_R_SUCCESS) 1414135446Strhodes goto failure; 1415135446Strhodes msgrdl->type = rdata->type; 1416135446Strhodes msgrdl->rdclass = rdata->rdclass; 1417135446Strhodes msgrdl->ttl = ttl; 1418193149Sdougb if (rdata->type == dns_rdatatype_sig || 1419193149Sdougb rdata->type == dns_rdatatype_rrsig) 1420193149Sdougb msgrdl->covers = dns_rdata_covers(rdata); 1421193149Sdougb else 1422193149Sdougb msgrdl->covers = dns_rdatatype_none; 1423135446Strhodes ISC_LINK_INIT(msgrdl, link); 1424135446Strhodes ISC_LIST_INIT(msgrdl->rdata); 1425135446Strhodes ISC_LIST_APPEND(msgrdl->rdata, msgrdata, link); 1426135446Strhodes 1427135446Strhodes result = dns_message_gettemprdataset(msg, &msgrds); 1428135446Strhodes if (result != ISC_R_SUCCESS) 1429135446Strhodes goto failure; 1430135446Strhodes dns_rdataset_init(msgrds); 1431135446Strhodes result = dns_rdatalist_tordataset(msgrdl, msgrds); 1432135446Strhodes INSIST(result == ISC_R_SUCCESS); 1433135446Strhodes 1434135446Strhodes ISC_LIST_APPEND(msgname->list, msgrds, link); 1435135446Strhodes 1436135446Strhodes dns_message_addname(msg, msgname, DNS_SECTION_ANSWER); 1437135446Strhodes msgname = NULL; 1438135446Strhodes 1439135446Strhodes result = xfr->stream->methods->next(xfr->stream); 1440135446Strhodes if (result == ISC_R_NOMORE) { 1441135446Strhodes xfr->end_of_stream = ISC_TRUE; 1442135446Strhodes break; 1443135446Strhodes } 1444135446Strhodes CHECK(result); 1445135446Strhodes 1446135446Strhodes if (! xfr->many_answers) 1447135446Strhodes break; 1448135446Strhodes } 1449135446Strhodes 1450135446Strhodes if ((xfr->client->attributes & NS_CLIENTATTR_TCP) != 0) { 1451135446Strhodes CHECK(dns_compress_init(&cctx, -1, xfr->mctx)); 1452170222Sdougb dns_compress_setsensitive(&cctx, ISC_TRUE); 1453135446Strhodes cleanup_cctx = ISC_TRUE; 1454135446Strhodes CHECK(dns_message_renderbegin(msg, &cctx, &xfr->txbuf)); 1455135446Strhodes CHECK(dns_message_rendersection(msg, DNS_SECTION_QUESTION, 0)); 1456135446Strhodes CHECK(dns_message_rendersection(msg, DNS_SECTION_ANSWER, 0)); 1457135446Strhodes CHECK(dns_message_renderend(msg)); 1458135446Strhodes dns_compress_invalidate(&cctx); 1459135446Strhodes cleanup_cctx = ISC_FALSE; 1460135446Strhodes 1461135446Strhodes isc_buffer_usedregion(&xfr->txbuf, &used); 1462135446Strhodes isc_buffer_putuint16(&xfr->txlenbuf, 1463135446Strhodes (isc_uint16_t)used.length); 1464135446Strhodes region.base = xfr->txlenbuf.base; 1465135446Strhodes region.length = 2 + used.length; 1466135446Strhodes xfrout_log(xfr, ISC_LOG_DEBUG(8), 1467135446Strhodes "sending TCP message of %d bytes", 1468135446Strhodes used.length); 1469135446Strhodes CHECK(isc_socket_send(xfr->client->tcpsocket, /* XXX */ 1470135446Strhodes ®ion, xfr->client->task, 1471135446Strhodes xfrout_senddone, 1472135446Strhodes xfr)); 1473135446Strhodes xfr->sends++; 1474135446Strhodes } else { 1475135446Strhodes xfrout_log(xfr, ISC_LOG_DEBUG(8), "sending IXFR UDP response"); 1476135446Strhodes ns_client_send(xfr->client); 1477135446Strhodes xfr->stream->methods->pause(xfr->stream); 1478135446Strhodes xfrout_ctx_destroy(&xfr); 1479135446Strhodes return; 1480135446Strhodes } 1481135446Strhodes 1482135446Strhodes /* Advance lasttsig to be the last TSIG generated */ 1483135446Strhodes CHECK(dns_message_getquerytsig(msg, xfr->mctx, &xfr->lasttsig)); 1484135446Strhodes 1485135446Strhodes xfr->nmsg++; 1486135446Strhodes 1487135446Strhodes failure: 1488135446Strhodes if (msgname != NULL) { 1489135446Strhodes if (msgrds != NULL) { 1490135446Strhodes if (dns_rdataset_isassociated(msgrds)) 1491135446Strhodes dns_rdataset_disassociate(msgrds); 1492135446Strhodes dns_message_puttemprdataset(msg, &msgrds); 1493135446Strhodes } 1494135446Strhodes if (msgrdl != NULL) { 1495135446Strhodes ISC_LIST_UNLINK(msgrdl->rdata, msgrdata, link); 1496135446Strhodes dns_message_puttemprdatalist(msg, &msgrdl); 1497135446Strhodes } 1498135446Strhodes if (msgrdata != NULL) 1499135446Strhodes dns_message_puttemprdata(msg, &msgrdata); 1500135446Strhodes dns_message_puttempname(msg, &msgname); 1501135446Strhodes } 1502135446Strhodes 1503135446Strhodes if (tcpmsg != NULL) 1504135446Strhodes dns_message_destroy(&tcpmsg); 1505135446Strhodes 1506135446Strhodes if (cleanup_cctx) 1507135446Strhodes dns_compress_invalidate(&cctx); 1508135446Strhodes /* 1509135446Strhodes * Make sure to release any locks held by database 1510135446Strhodes * iterators before returning from the event handler. 1511135446Strhodes */ 1512135446Strhodes xfr->stream->methods->pause(xfr->stream); 1513193149Sdougb 1514135446Strhodes if (result == ISC_R_SUCCESS) 1515135446Strhodes return; 1516135446Strhodes 1517135446Strhodes xfrout_fail(xfr, result, "sending zone data"); 1518135446Strhodes} 1519135446Strhodes 1520135446Strhodesstatic void 1521135446Strhodesxfrout_ctx_destroy(xfrout_ctx_t **xfrp) { 1522135446Strhodes xfrout_ctx_t *xfr = *xfrp; 1523225361Sdougb ns_client_t *client = NULL; 1524135446Strhodes 1525135446Strhodes INSIST(xfr->sends == 0); 1526135446Strhodes 1527135446Strhodes xfr->client->shutdown = NULL; 1528135446Strhodes xfr->client->shutdown_arg = NULL; 1529135446Strhodes 1530135446Strhodes if (xfr->stream != NULL) 1531135446Strhodes xfr->stream->methods->destroy(&xfr->stream); 1532135446Strhodes if (xfr->buf.base != NULL) 1533135446Strhodes isc_mem_put(xfr->mctx, xfr->buf.base, xfr->buf.length); 1534135446Strhodes if (xfr->txmem != NULL) 1535135446Strhodes isc_mem_put(xfr->mctx, xfr->txmem, xfr->txmemlen); 1536135446Strhodes if (xfr->lasttsig != NULL) 1537135446Strhodes isc_buffer_free(&xfr->lasttsig); 1538135446Strhodes if (xfr->quota != NULL) 1539135446Strhodes isc_quota_detach(&xfr->quota); 1540135446Strhodes if (xfr->ver != NULL) 1541135446Strhodes dns_db_closeversion(xfr->db, &xfr->ver, ISC_FALSE); 1542193149Sdougb if (xfr->zone != NULL) 1543193149Sdougb dns_zone_detach(&xfr->zone); 1544135446Strhodes if (xfr->db != NULL) 1545135446Strhodes dns_db_detach(&xfr->db); 1546135446Strhodes 1547225361Sdougb /* 1548225361Sdougb * We want to detch the client after we have released the memory 1549225361Sdougb * context as ns_client_detach checks the memory reference count. 1550225361Sdougb */ 1551225361Sdougb ns_client_attach(xfr->client, &client); 1552135446Strhodes ns_client_detach(&xfr->client); 1553225361Sdougb isc_mem_putanddetach(&xfr->mctx, xfr, sizeof(*xfr)); 1554225361Sdougb ns_client_detach(&client); 1555135446Strhodes 1556135446Strhodes *xfrp = NULL; 1557135446Strhodes} 1558135446Strhodes 1559135446Strhodesstatic void 1560135446Strhodesxfrout_senddone(isc_task_t *task, isc_event_t *event) { 1561135446Strhodes isc_socketevent_t *sev = (isc_socketevent_t *)event; 1562135446Strhodes xfrout_ctx_t *xfr = (xfrout_ctx_t *)event->ev_arg; 1563135446Strhodes isc_result_t evresult = sev->result; 1564135446Strhodes 1565135446Strhodes UNUSED(task); 1566135446Strhodes 1567135446Strhodes INSIST(event->ev_type == ISC_SOCKEVENT_SENDDONE); 1568135446Strhodes 1569135446Strhodes isc_event_free(&event); 1570135446Strhodes xfr->sends--; 1571135446Strhodes INSIST(xfr->sends == 0); 1572135446Strhodes 1573135446Strhodes (void)isc_timer_touch(xfr->client->timer); 1574135446Strhodes if (xfr->shuttingdown == ISC_TRUE) { 1575135446Strhodes xfrout_maybe_destroy(xfr); 1576135446Strhodes } else if (evresult != ISC_R_SUCCESS) { 1577135446Strhodes xfrout_fail(xfr, evresult, "send"); 1578135446Strhodes } else if (xfr->end_of_stream == ISC_FALSE) { 1579135446Strhodes sendstream(xfr); 1580135446Strhodes } else { 1581135446Strhodes /* End of zone transfer stream. */ 1582193149Sdougb inc_stats(xfr->zone, dns_nsstatscounter_xfrdone); 1583135446Strhodes xfrout_log(xfr, ISC_LOG_INFO, "%s ended", xfr->mnemonic); 1584135446Strhodes ns_client_next(xfr->client, ISC_R_SUCCESS); 1585135446Strhodes xfrout_ctx_destroy(&xfr); 1586135446Strhodes } 1587135446Strhodes} 1588135446Strhodes 1589135446Strhodesstatic void 1590135446Strhodesxfrout_fail(xfrout_ctx_t *xfr, isc_result_t result, const char *msg) { 1591135446Strhodes xfr->shuttingdown = ISC_TRUE; 1592135446Strhodes xfrout_log(xfr, ISC_LOG_ERROR, "%s: %s", 1593135446Strhodes msg, isc_result_totext(result)); 1594135446Strhodes xfrout_maybe_destroy(xfr); 1595135446Strhodes} 1596135446Strhodes 1597135446Strhodesstatic void 1598135446Strhodesxfrout_maybe_destroy(xfrout_ctx_t *xfr) { 1599135446Strhodes INSIST(xfr->shuttingdown == ISC_TRUE); 1600135446Strhodes if (xfr->sends > 0) { 1601135446Strhodes /* 1602135446Strhodes * If we are currently sending, cancel it and wait for 1603135446Strhodes * cancel event before destroying the context. 1604135446Strhodes */ 1605135446Strhodes isc_socket_cancel(xfr->client->tcpsocket, xfr->client->task, 1606135446Strhodes ISC_SOCKCANCEL_SEND); 1607135446Strhodes } else { 1608135446Strhodes ns_client_next(xfr->client, ISC_R_CANCELED); 1609135446Strhodes xfrout_ctx_destroy(&xfr); 1610135446Strhodes } 1611135446Strhodes} 1612135446Strhodes 1613135446Strhodesstatic void 1614135446Strhodesxfrout_client_shutdown(void *arg, isc_result_t result) { 1615135446Strhodes xfrout_ctx_t *xfr = (xfrout_ctx_t *) arg; 1616135446Strhodes xfrout_fail(xfr, result, "aborted"); 1617135446Strhodes} 1618135446Strhodes 1619135446Strhodes/* 1620135446Strhodes * Log outgoing zone transfer messages in a format like 1621135446Strhodes * <client>: transfer of <zone>: <message> 1622135446Strhodes */ 1623135446Strhodes 1624135446Strhodesstatic void 1625135446Strhodesxfrout_logv(ns_client_t *client, dns_name_t *zonename, 1626135446Strhodes dns_rdataclass_t rdclass, int level, const char *fmt, va_list ap) 1627135446Strhodes ISC_FORMAT_PRINTF(5, 0); 1628135446Strhodes 1629135446Strhodesstatic void 1630135446Strhodesxfrout_logv(ns_client_t *client, dns_name_t *zonename, 1631135446Strhodes dns_rdataclass_t rdclass, int level, const char *fmt, va_list ap) 1632135446Strhodes{ 1633135446Strhodes char msgbuf[2048]; 1634135446Strhodes char namebuf[DNS_NAME_FORMATSIZE]; 1635135446Strhodes char classbuf[DNS_RDATACLASS_FORMATSIZE]; 1636135446Strhodes 1637135446Strhodes dns_name_format(zonename, namebuf, sizeof(namebuf)); 1638135446Strhodes dns_rdataclass_format(rdclass, classbuf, sizeof(classbuf)); 1639135446Strhodes vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap); 1640135446Strhodes ns_client_log(client, DNS_LOGCATEGORY_XFER_OUT, 1641135446Strhodes NS_LOGMODULE_XFER_OUT, level, 1642135446Strhodes "transfer of '%s/%s': %s", namebuf, classbuf, msgbuf); 1643135446Strhodes} 1644135446Strhodes 1645135446Strhodes/* 1646135446Strhodes * Logging function for use when a xfrout_ctx_t has not yet been created. 1647135446Strhodes */ 1648135446Strhodesstatic void 1649135446Strhodesxfrout_log1(ns_client_t *client, dns_name_t *zonename, 1650135446Strhodes dns_rdataclass_t rdclass, int level, const char *fmt, ...) { 1651135446Strhodes va_list ap; 1652135446Strhodes va_start(ap, fmt); 1653135446Strhodes xfrout_logv(client, zonename, rdclass, level, fmt, ap); 1654135446Strhodes va_end(ap); 1655135446Strhodes} 1656135446Strhodes 1657135446Strhodes/* 1658135446Strhodes * Logging function for use when there is a xfrout_ctx_t. 1659135446Strhodes */ 1660135446Strhodesstatic void 1661153816Sdougbxfrout_log(xfrout_ctx_t *xfr, int level, const char *fmt, ...) { 1662135446Strhodes va_list ap; 1663135446Strhodes va_start(ap, fmt); 1664135446Strhodes xfrout_logv(xfr->client, xfr->qname, xfr->qclass, level, fmt, ap); 1665135446Strhodes va_end(ap); 1666135446Strhodes} 1667