xfrout.c revision dafcb997e390efa4423883dafd100c975c4095d6
* copyright notice and this permission notice appear in all copies. * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL ISC 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.115 2004/03/05 04:57:49 marka Exp $ */ * Outgoing AXFR and IXFR. * 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". "bad zone transfer request: %s (%s)", \
"bad zone transfer request: '%s/%s': %s (%s)", \
/**************************************************************************/ * A db_rr_iterator_t is an iterator that iterates over an entire database, * returning one RR at a time, in some arbitrary order. * The top node may be empty when out of zone glue exists. * Walk the tree to find the first node with data. * This node is empty. Try next node. * The while loop body is executed more than once * only when an empty dbnode needs to be skipped. /* We are at the end of the entire database. */ /**************************************************************************/ /* Log an RR (for debugging) */ * We could use xfrout_log(), but that would produce * very long lines with a repetitive prefix. * Get rid of final newline. /**************************************************************************/ * 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. /**************************************************************************/ * 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 /* Forward declarations. */ * Returns: anything dns_journal_open() or dns_journal_iter_init() /**************************************************************************/ * An 'axfr_rrstream_t' is an 'rrstream_t' that returns * an AXFR-like RR stream from a database. * The SOAs at the beginning and end of the transfer are * not included in the stream. /**************************************************************************/ * An 'soa_rrstream_t' is a degenerate 'rrstream_t' that returns /**************************************************************************/ * A 'compound_rrstream_t' objects owns a soa_rrstream * and another rrstream, the "data stream". It returns * a concatenated stream consisting of the soa_rrstream, then * the data stream, then the soa_rrstream again. * The component streams are owned by the compound_rrstream_t * and are destroyed with it. * soa_stream != NULL && *soa_stream != NULL * data_stream != NULL && *data_stream != NULL * sp != NULL && *sp == NULL * *sp points to a valid compound_rrstream_t * The soa and data streams will be destroyed * when the compound_rrstream_t is destroyed. * Make sure locks held by the current stream * are released before we switch streams. /**************************************************************************/ * An 'xfrout_ctx_t' contains the state of an outgoing AXFR or IXFR unsigned int id;
/* ID of request */ unsigned int nmsg;
/* Number of messages sent */ int sends;
/* Send in progress */ const char *
mnemonic;
/* Style of transfer */ /**************************************************************************/ * Interpret the question section. * The question section must contain exactly one question, and * it must be for AXFR/IXFR as appropriate. break;
/* Master and slave zones are OK for transfer. */ * Check the authority section. Look for a SOA record with * the same name and class as the question. * Ignore data whose owner name is not the zone apex. "IXFR authority section " * Decide whether to allow this transfer. * AXFR over UDP is not possible. * Look up the requesting server in the peer table. * Decide on the transfer format (one-answer or many-answers). * Get a dynamically allocated copy of the current SOA. * Outgoing IXFR may have been disabled for this peer "IXFR request missing SOA");
* RFC1995 says "If an IXFR query with the same or * newer version number than that of the server * is received, it is replied to with a single SOA * record of the server's current version, just as * in AXFR". The claim about AXFR is incorrect, * but other than that, we do as the RFC says. * Sending a single SOA record is also how we refuse * IXFR over UDP (currently, we always do). "IXFR version not in journal, " * Bracket the the data stream with SOAs. * Create the xfrout context object. This transfers the ownership * of "stream", "db", "ver", and "quota" to the xfrout context object. * Hand the context over to sendstream(). Set xfr to NULL; * sendstream() is responsible for either passing the * context on to a later event handler or destroying it. * Allocate a temporary buffer for the uncompressed response * message data. The size should be no more than 65535 bytes * so that the compressed data will fit in a TCP message, * and no less than 65535 bytes so that an almost maximum-sized * RR will fit. Note that although 65535-byte RRs are allowed * in principle, they cannot be zone-transferred (at least not * if uncompressible), because the message and RR headers would * push the size of the TCP message over the 65536 byte limit. * Allocate another temporary buffer for the compressed * response message and its TCP length prefix. * Register a shutdown callback with the client, so that we * can stop the transfer immediately when the client task * Arrange to send as much as we can of "stream" without blocking. * The stream iterator is initialized and points at an RR, * or possiby at the end of the stream (that is, the * _first method of the iterator has been called). * In the UDP case, we put the response data directly into * TCP. Build a response dns_message_t, temporarily storing * the raw, uncompressed owner names and RR data contiguously * in xfr->buf. We know that if the uncompressed data fits * in xfr->buf, the compressed data will surely fit in a TCP * Include a question section in the first message only. * BIND 8.2.1 will not recognize an IXFR if it does not * have a question section. * Reserve space for the 12-byte message header * and 4 bytes of question. * Try to fit in as many RRs as possible, unless "one-answer" * format has been requested. * RR would not fit. If there are other RRs in the * buffer, send them now and leave this RR to the * next message. If this RR overflows the buffer * In theory some RRs might fit in a TCP message * when compressed even if they do not fit when * uncompressed, but surely we don't want * to send such monstrosities to an unsuspecting "RR too large for zone transfer " /* XXX DNS_R_RRTOOLARGE? */ /* Reserve space for RR header. */ "sending TCP message of %d bytes",
/* Advance lasttsig to be the last TSIG generated */ * Make sure to release any locks held by database * iterators before returning from the event handler. /* End of zone transfer stream. */ * If we are currently sending, cancel it and wait for * cancel event before destroying the context. * Log outgoing zone transfer messages in a format like * <client>: transfer of <zone>: <message> * Logging function for use when a xfrout_ctx_t has not yet been created. * Logging function for use when there is a xfrout_ctx_t.