📄 xfrout.c
字号:
/* * Copyright (C) 1999-2001, 2003 Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *//* $Id: xfrout.c,v 1.101.2.5 2003/07/22 04:03:35 marka Exp $ */#include <config.h>#include <isc/formatcheck.h>#include <isc/mem.h>#include <isc/timer.h>#include <isc/print.h>#include <isc/util.h>#include <dns/db.h>#include <dns/dbiterator.h>#include <dns/fixedname.h>#include <dns/journal.h>#include <dns/message.h>#include <dns/peer.h>#include <dns/rdataclass.h>#include <dns/rdatalist.h>#include <dns/rdataset.h>#include <dns/rdatasetiter.h>#include <dns/result.h>#include <dns/soa.h>#include <dns/timer.h>#include <dns/view.h>#include <dns/zone.h>#include <dns/zt.h>#include <named/client.h>#include <named/log.h>#include <named/server.h>#include <named/xfrout.h>/* * Outgoing AXFR and IXFR. *//* * TODO: * - IXFR over UDP */#define XFROUT_COMMON_LOGARGS \ ns_g_lctx, DNS_LOGCATEGORY_XFER_OUT, NS_LOGMODULE_XFER_OUT#define XFROUT_PROTOCOL_LOGARGS \ XFROUT_COMMON_LOGARGS, ISC_LOG_INFO#define XFROUT_DEBUG_LOGARGS(n) \ XFROUT_COMMON_LOGARGS, ISC_LOG_DEBUG(n)#define XFROUT_RR_LOGARGS \ XFROUT_COMMON_LOGARGS, XFROUT_RR_LOGLEVEL#define XFROUT_RR_LOGLEVEL ISC_LOG_DEBUG(8)/* * Fail unconditionally and log as a client error. * The test against ISC_R_SUCCESS is there to keep the Solaris compiler * from complaining about "end-of-loop code not reached". */#define FAILC(code, msg) \ do { \ result = (code); \ ns_client_log(client, DNS_LOGCATEGORY_XFER_OUT, \ NS_LOGMODULE_XFER_OUT, ISC_LOG_INFO, \ "bad zone transfer request: %s (%s)", \ msg, isc_result_totext(code)); \ if (result != ISC_R_SUCCESS) goto failure; \ } while (0)#define FAILQ(code, msg, question, rdclass) \ do { \ char _buf1[DNS_NAME_FORMATSIZE]; \ char _buf2[DNS_RDATACLASS_FORMATSIZE]; \ result = (code); \ dns_name_format(question, _buf1, sizeof(_buf1)); \ dns_rdataclass_format(rdclass, _buf2, sizeof(_buf2)); \ ns_client_log(client, DNS_LOGCATEGORY_XFER_OUT, \ NS_LOGMODULE_XFER_OUT, ISC_LOG_INFO, \ "bad zone transfer request: '%s/%s': %s (%s)", \ _buf1, _buf2, msg, isc_result_totext(code)); \ if (result != ISC_R_SUCCESS) goto failure; \ } while (0)#define CHECK(op) \ do { result = (op); \ if (result != ISC_R_SUCCESS) goto failure; \ } while (0)/**************************************************************************//* * A db_rr_iterator_t is an iterator that iterates over an entire database, * returning one RR at a time, in some arbitrary order. */typedef struct db_rr_iterator db_rr_iterator_t;struct db_rr_iterator { isc_result_t result; dns_db_t *db; dns_dbiterator_t *dbit; dns_dbversion_t *ver; isc_stdtime_t now; dns_dbnode_t *node; dns_fixedname_t fixedname; dns_rdatasetiter_t *rdatasetit; dns_rdataset_t rdataset; dns_rdata_t rdata;};static isc_result_tdb_rr_iterator_init(db_rr_iterator_t *it, dns_db_t *db, dns_dbversion_t *ver, isc_stdtime_t now);static isc_result_tdb_rr_iterator_first(db_rr_iterator_t *it);static isc_result_tdb_rr_iterator_next(db_rr_iterator_t *it);static voiddb_rr_iterator_current(db_rr_iterator_t *it, dns_name_t **name, isc_uint32_t *ttl, dns_rdata_t **rdata);static voiddb_rr_iterator_destroy(db_rr_iterator_t *it);static isc_result_tdb_rr_iterator_init(db_rr_iterator_t *it, dns_db_t *db, dns_dbversion_t *ver, isc_stdtime_t now){ isc_result_t result; it->db = db; it->dbit = NULL; it->ver = ver; it->now = now; it->node = NULL; result = dns_db_createiterator(it->db, ISC_FALSE, &it->dbit); if (result != ISC_R_SUCCESS) return (result); it->rdatasetit = NULL; dns_rdata_init(&it->rdata); dns_rdataset_init(&it->rdataset); dns_fixedname_init(&it->fixedname); INSIST(! dns_rdataset_isassociated(&it->rdataset)); it->result = ISC_R_SUCCESS; return (it->result);}static isc_result_tdb_rr_iterator_first(db_rr_iterator_t *it) { it->result = dns_dbiterator_first(it->dbit); /* * The top node may be empty when out of zone glue exists. * Walk the tree to find the first node with data. */ while (it->result == ISC_R_SUCCESS) { it->result = dns_dbiterator_current(it->dbit, &it->node, dns_fixedname_name(&it->fixedname)); if (it->result != ISC_R_SUCCESS) return (it->result); it->result = dns_db_allrdatasets(it->db, it->node, it->ver, it->now, &it->rdatasetit); if (it->result != ISC_R_SUCCESS) return (it->result); it->result = dns_rdatasetiter_first(it->rdatasetit); if (it->result != ISC_R_SUCCESS) { /* * This node is empty. Try next node. */ dns_rdatasetiter_destroy(&it->rdatasetit); dns_db_detachnode(it->db, &it->node); it->result = dns_dbiterator_next(it->dbit); continue; } dns_rdatasetiter_current(it->rdatasetit, &it->rdataset); it->result = dns_rdataset_first(&it->rdataset); return (it->result); } return (it->result);}static isc_result_tdb_rr_iterator_next(db_rr_iterator_t *it) { if (it->result != ISC_R_SUCCESS) return (it->result); INSIST(it->dbit != NULL); INSIST(it->node != NULL); INSIST(it->rdatasetit != NULL); it->result = dns_rdataset_next(&it->rdataset); if (it->result == ISC_R_NOMORE) { dns_rdataset_disassociate(&it->rdataset); it->result = dns_rdatasetiter_next(it->rdatasetit); /* * The while loop body is executed more than once * only when an empty dbnode needs to be skipped. */ while (it->result == ISC_R_NOMORE) { dns_rdatasetiter_destroy(&it->rdatasetit); dns_db_detachnode(it->db, &it->node); it->result = dns_dbiterator_next(it->dbit); if (it->result == ISC_R_NOMORE) { /* We are at the end of the entire database. */ return (it->result); } if (it->result != ISC_R_SUCCESS) return (it->result); it->result = dns_dbiterator_current(it->dbit, &it->node, dns_fixedname_name(&it->fixedname)); if (it->result != ISC_R_SUCCESS) return (it->result); it->result = dns_db_allrdatasets(it->db, it->node, it->ver, it->now, &it->rdatasetit); if (it->result != ISC_R_SUCCESS) return (it->result); it->result = dns_rdatasetiter_first(it->rdatasetit); } if (it->result != ISC_R_SUCCESS) return (it->result); dns_rdatasetiter_current(it->rdatasetit, &it->rdataset); it->result = dns_rdataset_first(&it->rdataset); if (it->result != ISC_R_SUCCESS) return (it->result); } return (it->result);}static voiddb_rr_iterator_pause(db_rr_iterator_t *it) { dns_dbiterator_pause(it->dbit);}static voiddb_rr_iterator_destroy(db_rr_iterator_t *it) { if (dns_rdataset_isassociated(&it->rdataset)) dns_rdataset_disassociate(&it->rdataset); if (it->rdatasetit != NULL) dns_rdatasetiter_destroy(&it->rdatasetit); if (it->node != NULL) dns_db_detachnode(it->db, &it->node); dns_dbiterator_destroy(&it->dbit);}static voiddb_rr_iterator_current(db_rr_iterator_t *it, dns_name_t **name, isc_uint32_t *ttl, dns_rdata_t **rdata){ REQUIRE(name != NULL && *name == NULL); REQUIRE(it->result == ISC_R_SUCCESS); *name = dns_fixedname_name(&it->fixedname); *ttl = it->rdataset.ttl; dns_rdata_reset(&it->rdata); dns_rdataset_current(&it->rdataset, &it->rdata); *rdata = &it->rdata;}/**************************************************************************//* Log an RR (for debugging) */static voidlog_rr(dns_name_t *name, dns_rdata_t *rdata, isc_uint32_t ttl) { isc_result_t result; isc_buffer_t buf; char mem[2000]; dns_rdatalist_t rdl; dns_rdataset_t rds; dns_rdata_t rd = DNS_RDATA_INIT; rdl.type = rdata->type; rdl.rdclass = rdata->rdclass; rdl.ttl = ttl; ISC_LIST_INIT(rdl.rdata); ISC_LINK_INIT(&rdl, link); dns_rdataset_init(&rds); dns_rdata_init(&rd); dns_rdata_clone(rdata, &rd); ISC_LIST_APPEND(rdl.rdata, &rd, link); RUNTIME_CHECK(dns_rdatalist_tordataset(&rdl, &rds) == ISC_R_SUCCESS); isc_buffer_init(&buf, mem, sizeof(mem)); result = dns_rdataset_totext(&rds, name, ISC_FALSE, ISC_FALSE, &buf); /* * We could use xfrout_log(), but that would produce * very long lines with a repetitive prefix. */ if (result == ISC_R_SUCCESS) { /* * Get rid of final newline. */ INSIST(buf.used >= 1 && ((char *) buf.base)[buf.used - 1] == '\n'); buf.used--; isc_log_write(XFROUT_RR_LOGARGS, "%.*s", (int)isc_buffer_usedlength(&buf), (char *)isc_buffer_base(&buf)); } else { isc_log_write(XFROUT_RR_LOGARGS, "<RR too large to print>"); }}/**************************************************************************//* * An 'rrstream_t' is a polymorphic iterator that returns * a stream of resource records. There are multiple implementations, * e.g. for generating AXFR and IXFR records streams. */typedef struct rrstream_methods rrstream_methods_t;typedef struct rrstream { isc_mem_t *mctx; rrstream_methods_t *methods;} rrstream_t;struct rrstream_methods { isc_result_t (*first)(rrstream_t *); isc_result_t (*next)(rrstream_t *); void (*current)(rrstream_t *, dns_name_t **, isc_uint32_t *, dns_rdata_t **); void (*pause)(rrstream_t *); void (*destroy)(rrstream_t **);};static voidrrstream_noop_pause(rrstream_t *rs) { UNUSED(rs);}/**************************************************************************//* * An 'ixfr_rrstream_t' is an 'rrstream_t' that returns * an IXFR-like RR stream from a journal file. * * The SOA at the beginning of each sequence of additions * or deletions are included in the stream, but the extra * SOAs at the beginning and end of the entire transfer are * not included. */typedef struct ixfr_rrstream { rrstream_t common; dns_journal_t *journal;} ixfr_rrstream_t;/* Forward declarations. */static voidixfr_rrstream_destroy(rrstream_t **sp);static rrstream_methods_t ixfr_rrstream_methods;/* * Returns: anything dns_journal_open() or dns_journal_iter_init() * may return. */static isc_result_tixfr_rrstream_create(isc_mem_t *mctx, const char *journal_filename, isc_uint32_t begin_serial, isc_uint32_t end_serial, rrstream_t **sp){ ixfr_rrstream_t *s; isc_result_t result; INSIST(sp != NULL && *sp == NULL); s = isc_mem_get(mctx, sizeof(*s)); if (s == NULL) return (ISC_R_NOMEMORY); s->common.mctx = mctx; s->common.methods = &ixfr_rrstream_methods; s->journal = NULL; CHECK(dns_journal_open(mctx, journal_filename, ISC_FALSE, &s->journal)); CHECK(dns_journal_iter_init(s->journal, begin_serial, end_serial)); *sp = (rrstream_t *) s; return (ISC_R_SUCCESS); failure: ixfr_rrstream_destroy((rrstream_t **) &s); return (result);}static isc_result_tixfr_rrstream_first(rrstream_t *rs) { ixfr_rrstream_t *s = (ixfr_rrstream_t *) rs; return (dns_journal_first_rr(s->journal));}static isc_result_t
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -