xfrout.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004-2015  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 1999-2003  Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and/or distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00010  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00011  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00012  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00013  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00014  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00015  * PERFORMANCE OF THIS SOFTWARE.
00016  */
00017 
00018 /* $Id$ */
00019 
00020 #include <config.h>
00021 
00022 #include <isc/formatcheck.h>
00023 #include <isc/mem.h>
00024 #include <isc/timer.h>
00025 #include <isc/print.h>
00026 #include <isc/stats.h>
00027 #include <isc/util.h>
00028 
00029 #include <dns/db.h>
00030 #include <dns/dbiterator.h>
00031 #include <dns/dlz.h>
00032 #include <dns/fixedname.h>
00033 #include <dns/journal.h>
00034 #include <dns/message.h>
00035 #include <dns/peer.h>
00036 #include <dns/rdataclass.h>
00037 #include <dns/rdatalist.h>
00038 #include <dns/rdataset.h>
00039 #include <dns/rdatasetiter.h>
00040 #include <dns/result.h>
00041 #include <dns/rriterator.h>
00042 #include <dns/soa.h>
00043 #include <dns/stats.h>
00044 #include <dns/timer.h>
00045 #include <dns/tsig.h>
00046 #include <dns/view.h>
00047 #include <dns/zone.h>
00048 #include <dns/zt.h>
00049 
00050 #include <named/client.h>
00051 #include <named/log.h>
00052 #include <named/server.h>
00053 #include <named/xfrout.h>
00054 
00055 /*! \file
00056  * \brief
00057  * Outgoing AXFR and IXFR.
00058  */
00059 
00060 /*
00061  * TODO:
00062  *  - IXFR over UDP
00063  */
00064 
00065 #define XFROUT_COMMON_LOGARGS \
00066         ns_g_lctx, DNS_LOGCATEGORY_XFER_OUT, NS_LOGMODULE_XFER_OUT
00067 
00068 #define XFROUT_PROTOCOL_LOGARGS \
00069         XFROUT_COMMON_LOGARGS, ISC_LOG_INFO
00070 
00071 #define XFROUT_DEBUG_LOGARGS(n) \
00072         XFROUT_COMMON_LOGARGS, ISC_LOG_DEBUG(n)
00073 
00074 #define XFROUT_RR_LOGARGS \
00075         XFROUT_COMMON_LOGARGS, XFROUT_RR_LOGLEVEL
00076 
00077 #define XFROUT_RR_LOGLEVEL      ISC_LOG_DEBUG(8)
00078 
00079 /*%
00080  * Fail unconditionally and log as a client error.
00081  * The test against ISC_R_SUCCESS is there to keep the Solaris compiler
00082  * from complaining about "end-of-loop code not reached".
00083  */
00084 #define FAILC(code, msg) \
00085         do {                                                    \
00086                 result = (code);                                \
00087                 ns_client_log(client, DNS_LOGCATEGORY_XFER_OUT, \
00088                            NS_LOGMODULE_XFER_OUT, ISC_LOG_INFO, \
00089                            "bad zone transfer request: %s (%s)", \
00090                            msg, isc_result_totext(code));       \
00091                 if (result != ISC_R_SUCCESS) goto failure;      \
00092         } while (0)
00093 
00094 #define FAILQ(code, msg, question, rdclass) \
00095         do {                                                    \
00096                 char _buf1[DNS_NAME_FORMATSIZE];                \
00097                 char _buf2[DNS_RDATACLASS_FORMATSIZE];          \
00098                 result = (code);                                \
00099                 dns_name_format(question, _buf1, sizeof(_buf1));  \
00100                 dns_rdataclass_format(rdclass, _buf2, sizeof(_buf2)); \
00101                 ns_client_log(client, DNS_LOGCATEGORY_XFER_OUT, \
00102                            NS_LOGMODULE_XFER_OUT, ISC_LOG_INFO, \
00103                            "bad zone transfer request: '%s/%s': %s (%s)", \
00104                            _buf1, _buf2, msg, isc_result_totext(code)); \
00105                 if (result != ISC_R_SUCCESS) goto failure;      \
00106         } while (0)
00107 
00108 #define CHECK(op) \
00109         do { result = (op);                                     \
00110                 if (result != ISC_R_SUCCESS) goto failure;      \
00111         } while (0)
00112 
00113 /**************************************************************************/
00114 
00115 static inline void
00116 inc_stats(dns_zone_t *zone, isc_statscounter_t counter) {
00117         isc_stats_increment(ns_g_server->nsstats, counter);
00118         if (zone != NULL) {
00119                 isc_stats_t *zonestats = dns_zone_getrequeststats(zone);
00120                 if (zonestats != NULL)
00121                         isc_stats_increment(zonestats, counter);
00122         }
00123 }
00124 
00125 /**************************************************************************/
00126 
00127 /*% Log an RR (for debugging) */
00128 
00129 static void
00130 log_rr(dns_name_t *name, dns_rdata_t *rdata, isc_uint32_t ttl) {
00131         isc_result_t result;
00132         isc_buffer_t buf;
00133         char mem[2000];
00134         dns_rdatalist_t rdl;
00135         dns_rdataset_t rds;
00136         dns_rdata_t rd = DNS_RDATA_INIT;
00137 
00138         dns_rdatalist_init(&rdl);
00139         rdl.type = rdata->type;
00140         rdl.rdclass = rdata->rdclass;
00141         rdl.ttl = ttl;
00142         if (rdata->type == dns_rdatatype_sig ||
00143             rdata->type == dns_rdatatype_rrsig)
00144                 rdl.covers = dns_rdata_covers(rdata);
00145         else
00146                 rdl.covers = dns_rdatatype_none;
00147         dns_rdataset_init(&rds);
00148         dns_rdata_init(&rd);
00149         dns_rdata_clone(rdata, &rd);
00150         ISC_LIST_APPEND(rdl.rdata, &rd, link);
00151         RUNTIME_CHECK(dns_rdatalist_tordataset(&rdl, &rds) == ISC_R_SUCCESS);
00152 
00153         isc_buffer_init(&buf, mem, sizeof(mem));
00154         result = dns_rdataset_totext(&rds, name,
00155                                      ISC_FALSE, ISC_FALSE, &buf);
00156 
00157         /*
00158          * We could use xfrout_log(), but that would produce
00159          * very long lines with a repetitive prefix.
00160          */
00161         if (result == ISC_R_SUCCESS) {
00162                 /*
00163                  * Get rid of final newline.
00164                  */
00165                 INSIST(buf.used >= 1 &&
00166                        ((char *) buf.base)[buf.used - 1] == '\n');
00167                 buf.used--;
00168 
00169                 isc_log_write(XFROUT_RR_LOGARGS, "%.*s",
00170                               (int)isc_buffer_usedlength(&buf),
00171                               (char *)isc_buffer_base(&buf));
00172         } else {
00173                 isc_log_write(XFROUT_RR_LOGARGS, "<RR too large to print>");
00174         }
00175 }
00176 
00177 /**************************************************************************/
00178 /*
00179  * An 'rrstream_t' is a polymorphic iterator that returns
00180  * a stream of resource records.  There are multiple implementations,
00181  * e.g. for generating AXFR and IXFR records streams.
00182  */
00183 
00184 typedef struct rrstream_methods rrstream_methods_t;
00185 
00186 typedef struct rrstream {
00187         isc_mem_t               *mctx;
00188         rrstream_methods_t      *methods;
00189 } rrstream_t;
00190 
00191 struct rrstream_methods {
00192         isc_result_t            (*first)(rrstream_t *);
00193         isc_result_t            (*next)(rrstream_t *);
00194         void                    (*current)(rrstream_t *,
00195                                            dns_name_t **,
00196                                            isc_uint32_t *,
00197                                            dns_rdata_t **);
00198         void                    (*pause)(rrstream_t *);
00199         void                    (*destroy)(rrstream_t **);
00200 };
00201 
00202 static void
00203 rrstream_noop_pause(rrstream_t *rs) {
00204         UNUSED(rs);
00205 }
00206 
00207 /**************************************************************************/
00208 /*
00209  * An 'ixfr_rrstream_t' is an 'rrstream_t' that returns
00210  * an IXFR-like RR stream from a journal file.
00211  *
00212  * The SOA at the beginning of each sequence of additions
00213  * or deletions are included in the stream, but the extra
00214  * SOAs at the beginning and end of the entire transfer are
00215  * not included.
00216  */
00217 
00218 typedef struct ixfr_rrstream {
00219         rrstream_t              common;
00220         dns_journal_t           *journal;
00221 } ixfr_rrstream_t;
00222 
00223 /* Forward declarations. */
00224 static void
00225 ixfr_rrstream_destroy(rrstream_t **sp);
00226 
00227 static rrstream_methods_t ixfr_rrstream_methods;
00228 
00229 /*
00230  * Returns: anything dns_journal_open() or dns_journal_iter_init()
00231  * may return.
00232  */
00233 
00234 static isc_result_t
00235 ixfr_rrstream_create(isc_mem_t *mctx,
00236                      const char *journal_filename,
00237                      isc_uint32_t begin_serial,
00238                      isc_uint32_t end_serial,
00239                      rrstream_t **sp)
00240 {
00241         ixfr_rrstream_t *s;
00242         isc_result_t result;
00243 
00244         INSIST(sp != NULL && *sp == NULL);
00245 
00246         s = isc_mem_get(mctx, sizeof(*s));
00247         if (s == NULL)
00248                 return (ISC_R_NOMEMORY);
00249         s->common.mctx = NULL;
00250         isc_mem_attach(mctx, &s->common.mctx);
00251         s->common.methods = &ixfr_rrstream_methods;
00252         s->journal = NULL;
00253 
00254         CHECK(dns_journal_open(mctx, journal_filename,
00255                                DNS_JOURNAL_READ, &s->journal));
00256         CHECK(dns_journal_iter_init(s->journal, begin_serial, end_serial));
00257 
00258         *sp = (rrstream_t *) s;
00259         return (ISC_R_SUCCESS);
00260 
00261  failure:
00262         ixfr_rrstream_destroy((rrstream_t **) (void *)&s);
00263         return (result);
00264 }
00265 
00266 static isc_result_t
00267 ixfr_rrstream_first(rrstream_t *rs) {
00268         ixfr_rrstream_t *s = (ixfr_rrstream_t *) rs;
00269         return (dns_journal_first_rr(s->journal));
00270 }
00271 
00272 static isc_result_t
00273 ixfr_rrstream_next(rrstream_t *rs) {
00274         ixfr_rrstream_t *s = (ixfr_rrstream_t *) rs;
00275         return (dns_journal_next_rr(s->journal));
00276 }
00277 
00278 static void
00279 ixfr_rrstream_current(rrstream_t *rs,
00280                        dns_name_t **name, isc_uint32_t *ttl,
00281                        dns_rdata_t **rdata)
00282 {
00283         ixfr_rrstream_t *s = (ixfr_rrstream_t *) rs;
00284         dns_journal_current_rr(s->journal, name, ttl, rdata);
00285 }
00286 
00287 static void
00288 ixfr_rrstream_destroy(rrstream_t **rsp) {
00289         ixfr_rrstream_t *s = (ixfr_rrstream_t *) *rsp;
00290         if (s->journal != 0)
00291                 dns_journal_destroy(&s->journal);
00292         isc_mem_putanddetach(&s->common.mctx, s, sizeof(*s));
00293 }
00294 
00295 static rrstream_methods_t ixfr_rrstream_methods = {
00296         ixfr_rrstream_first,
00297         ixfr_rrstream_next,
00298         ixfr_rrstream_current,
00299         rrstream_noop_pause,
00300         ixfr_rrstream_destroy
00301 };
00302 
00303 /**************************************************************************/
00304 /*
00305  * An 'axfr_rrstream_t' is an 'rrstream_t' that returns
00306  * an AXFR-like RR stream from a database.
00307  *
00308  * The SOAs at the beginning and end of the transfer are
00309  * not included in the stream.
00310  */
00311 
00312 typedef struct axfr_rrstream {
00313         rrstream_t              common;
00314         dns_rriterator_t        it;
00315         isc_boolean_t           it_valid;
00316 } axfr_rrstream_t;
00317 
00318 /*
00319  * Forward declarations.
00320  */
00321 static void
00322 axfr_rrstream_destroy(rrstream_t **rsp);
00323 
00324 static rrstream_methods_t axfr_rrstream_methods;
00325 
00326 static isc_result_t
00327 axfr_rrstream_create(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *ver,
00328                      rrstream_t **sp)
00329 {
00330         axfr_rrstream_t *s;
00331         isc_result_t result;
00332 
00333         INSIST(sp != NULL && *sp == NULL);
00334 
00335         s = isc_mem_get(mctx, sizeof(*s));
00336         if (s == NULL)
00337                 return (ISC_R_NOMEMORY);
00338         s->common.mctx = NULL;
00339         isc_mem_attach(mctx, &s->common.mctx);
00340         s->common.methods = &axfr_rrstream_methods;
00341         s->it_valid = ISC_FALSE;
00342 
00343         CHECK(dns_rriterator_init(&s->it, db, ver, 0));
00344         s->it_valid = ISC_TRUE;
00345 
00346         *sp = (rrstream_t *) s;
00347         return (ISC_R_SUCCESS);
00348 
00349  failure:
00350         axfr_rrstream_destroy((rrstream_t **) (void *)&s);
00351         return (result);
00352 }
00353 
00354 static isc_result_t
00355 axfr_rrstream_first(rrstream_t *rs) {
00356         axfr_rrstream_t *s = (axfr_rrstream_t *) rs;
00357         isc_result_t result;
00358         result = dns_rriterator_first(&s->it);
00359         if (result != ISC_R_SUCCESS)
00360                 return (result);
00361         /* Skip SOA records. */
00362         for (;;) {
00363                 dns_name_t *name_dummy = NULL;
00364                 isc_uint32_t ttl_dummy;
00365                 dns_rdata_t *rdata = NULL;
00366                 dns_rriterator_current(&s->it, &name_dummy,
00367                                        &ttl_dummy, NULL, &rdata);
00368                 if (rdata->type != dns_rdatatype_soa)
00369                         break;
00370                 result = dns_rriterator_next(&s->it);
00371                 if (result != ISC_R_SUCCESS)
00372                         break;
00373         }
00374         return (result);
00375 }
00376 
00377 static isc_result_t
00378 axfr_rrstream_next(rrstream_t *rs) {
00379         axfr_rrstream_t *s = (axfr_rrstream_t *) rs;
00380         isc_result_t result;
00381 
00382         /* Skip SOA records. */
00383         for (;;) {
00384                 dns_name_t *name_dummy = NULL;
00385                 isc_uint32_t ttl_dummy;
00386                 dns_rdata_t *rdata = NULL;
00387                 result = dns_rriterator_next(&s->it);
00388                 if (result != ISC_R_SUCCESS)
00389                         break;
00390                 dns_rriterator_current(&s->it, &name_dummy,
00391                                        &ttl_dummy, NULL, &rdata);
00392                 if (rdata->type != dns_rdatatype_soa)
00393                         break;
00394         }
00395         return (result);
00396 }
00397 
00398 static void
00399 axfr_rrstream_current(rrstream_t *rs, dns_name_t **name, isc_uint32_t *ttl,
00400                       dns_rdata_t **rdata)
00401 {
00402         axfr_rrstream_t *s = (axfr_rrstream_t *) rs;
00403         dns_rriterator_current(&s->it, name, ttl, NULL, rdata);
00404 }
00405 
00406 static void
00407 axfr_rrstream_pause(rrstream_t *rs) {
00408         axfr_rrstream_t *s = (axfr_rrstream_t *) rs;
00409         dns_rriterator_pause(&s->it);
00410 }
00411 
00412 static void
00413 axfr_rrstream_destroy(rrstream_t **rsp) {
00414         axfr_rrstream_t *s = (axfr_rrstream_t *) *rsp;
00415         if (s->it_valid)
00416                 dns_rriterator_destroy(&s->it);
00417         isc_mem_putanddetach(&s->common.mctx, s, sizeof(*s));
00418 }
00419 
00420 static rrstream_methods_t axfr_rrstream_methods = {
00421         axfr_rrstream_first,
00422         axfr_rrstream_next,
00423         axfr_rrstream_current,
00424         axfr_rrstream_pause,
00425         axfr_rrstream_destroy
00426 };
00427 
00428 /**************************************************************************/
00429 /*
00430  * An 'soa_rrstream_t' is a degenerate 'rrstream_t' that returns
00431  * a single SOA record.
00432  */
00433 
00434 typedef struct soa_rrstream {
00435         rrstream_t              common;
00436         dns_difftuple_t         *soa_tuple;
00437 } soa_rrstream_t;
00438 
00439 /*
00440  * Forward declarations.
00441  */
00442 static void
00443 soa_rrstream_destroy(rrstream_t **rsp);
00444 
00445 static rrstream_methods_t soa_rrstream_methods;
00446 
00447 static isc_result_t
00448 soa_rrstream_create(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *ver,
00449                     rrstream_t **sp)
00450 {
00451         soa_rrstream_t *s;
00452         isc_result_t result;
00453 
00454         INSIST(sp != NULL && *sp == NULL);
00455 
00456         s = isc_mem_get(mctx, sizeof(*s));
00457         if (s == NULL)
00458                 return (ISC_R_NOMEMORY);
00459         s->common.mctx = NULL;
00460         isc_mem_attach(mctx, &s->common.mctx);
00461         s->common.methods = &soa_rrstream_methods;
00462         s->soa_tuple = NULL;
00463 
00464         CHECK(dns_db_createsoatuple(db, ver, mctx, DNS_DIFFOP_EXISTS,
00465                                     &s->soa_tuple));
00466 
00467         *sp = (rrstream_t *) s;
00468         return (ISC_R_SUCCESS);
00469 
00470  failure:
00471         soa_rrstream_destroy((rrstream_t **) (void *)&s);
00472         return (result);
00473 }
00474 
00475 static isc_result_t
00476 soa_rrstream_first(rrstream_t *rs) {
00477         UNUSED(rs);
00478         return (ISC_R_SUCCESS);
00479 }
00480 
00481 static isc_result_t
00482 soa_rrstream_next(rrstream_t *rs) {
00483         UNUSED(rs);
00484         return (ISC_R_NOMORE);
00485 }
00486 
00487 static void
00488 soa_rrstream_current(rrstream_t *rs, dns_name_t **name, isc_uint32_t *ttl,
00489                      dns_rdata_t **rdata)
00490 {
00491         soa_rrstream_t *s = (soa_rrstream_t *) rs;
00492         *name = &s->soa_tuple->name;
00493         *ttl = s->soa_tuple->ttl;
00494         *rdata = &s->soa_tuple->rdata;
00495 }
00496 
00497 static void
00498 soa_rrstream_destroy(rrstream_t **rsp) {
00499         soa_rrstream_t *s = (soa_rrstream_t *) *rsp;
00500         if (s->soa_tuple != NULL)
00501                 dns_difftuple_free(&s->soa_tuple);
00502         isc_mem_putanddetach(&s->common.mctx, s, sizeof(*s));
00503 }
00504 
00505 static rrstream_methods_t soa_rrstream_methods = {
00506         soa_rrstream_first,
00507         soa_rrstream_next,
00508         soa_rrstream_current,
00509         rrstream_noop_pause,
00510         soa_rrstream_destroy
00511 };
00512 
00513 /**************************************************************************/
00514 /*
00515  * A 'compound_rrstream_t' objects owns a soa_rrstream
00516  * and another rrstream, the "data stream".  It returns
00517  * a concatenated stream consisting of the soa_rrstream, then
00518  * the data stream, then the soa_rrstream again.
00519  *
00520  * The component streams are owned by the compound_rrstream_t
00521  * and are destroyed with it.
00522  */
00523 
00524 typedef struct compound_rrstream {
00525         rrstream_t              common;
00526         rrstream_t              *components[3];
00527         int                     state;
00528         isc_result_t            result;
00529 } compound_rrstream_t;
00530 
00531 /*
00532  * Forward declarations.
00533  */
00534 static void
00535 compound_rrstream_destroy(rrstream_t **rsp);
00536 
00537 static isc_result_t
00538 compound_rrstream_next(rrstream_t *rs);
00539 
00540 static rrstream_methods_t compound_rrstream_methods;
00541 
00542 /*
00543  * Requires:
00544  *      soa_stream != NULL && *soa_stream != NULL
00545  *      data_stream != NULL && *data_stream != NULL
00546  *      sp != NULL && *sp == NULL
00547  *
00548  * Ensures:
00549  *      *soa_stream == NULL
00550  *      *data_stream == NULL
00551  *      *sp points to a valid compound_rrstream_t
00552  *      The soa and data streams will be destroyed
00553  *      when the compound_rrstream_t is destroyed.
00554  */
00555 static isc_result_t
00556 compound_rrstream_create(isc_mem_t *mctx, rrstream_t **soa_stream,
00557                          rrstream_t **data_stream, rrstream_t **sp)
00558 {
00559         compound_rrstream_t *s;
00560 
00561         INSIST(sp != NULL && *sp == NULL);
00562 
00563         s = isc_mem_get(mctx, sizeof(*s));
00564         if (s == NULL)
00565                 return (ISC_R_NOMEMORY);
00566         s->common.mctx = NULL;
00567         isc_mem_attach(mctx, &s->common.mctx);
00568         s->common.methods = &compound_rrstream_methods;
00569         s->components[0] = *soa_stream;
00570         s->components[1] = *data_stream;
00571         s->components[2] = *soa_stream;
00572         s->state = -1;
00573         s->result = ISC_R_FAILURE;
00574 
00575         *soa_stream = NULL;
00576         *data_stream = NULL;
00577         *sp = (rrstream_t *) s;
00578         return (ISC_R_SUCCESS);
00579 }
00580 
00581 static isc_result_t
00582 compound_rrstream_first(rrstream_t *rs) {
00583         compound_rrstream_t *s = (compound_rrstream_t *) rs;
00584         s->state = 0;
00585         do {
00586                 rrstream_t *curstream = s->components[s->state];
00587                 s->result = curstream->methods->first(curstream);
00588         } while (s->result == ISC_R_NOMORE && s->state < 2);
00589         return (s->result);
00590 }
00591 
00592 static isc_result_t
00593 compound_rrstream_next(rrstream_t *rs) {
00594         compound_rrstream_t *s = (compound_rrstream_t *) rs;
00595         rrstream_t *curstream = s->components[s->state];
00596         s->result = curstream->methods->next(curstream);
00597         while (s->result == ISC_R_NOMORE) {
00598                 /*
00599                  * Make sure locks held by the current stream
00600                  * are released before we switch streams.
00601                  */
00602                 curstream->methods->pause(curstream);
00603                 if (s->state == 2)
00604                         return (ISC_R_NOMORE);
00605                 s->state++;
00606                 curstream = s->components[s->state];
00607                 s->result = curstream->methods->first(curstream);
00608         }
00609         return (s->result);
00610 }
00611 
00612 static void
00613 compound_rrstream_current(rrstream_t *rs, dns_name_t **name, isc_uint32_t *ttl,
00614                           dns_rdata_t **rdata)
00615 {
00616         compound_rrstream_t *s = (compound_rrstream_t *) rs;
00617         rrstream_t *curstream;
00618         INSIST(0 <= s->state && s->state < 3);
00619         INSIST(s->result == ISC_R_SUCCESS);
00620         curstream = s->components[s->state];
00621         curstream->methods->current(curstream, name, ttl, rdata);
00622 }
00623 
00624 static void
00625 compound_rrstream_pause(rrstream_t *rs)
00626 {
00627         compound_rrstream_t *s = (compound_rrstream_t *) rs;
00628         rrstream_t *curstream;
00629         INSIST(0 <= s->state && s->state < 3);
00630         curstream = s->components[s->state];
00631         curstream->methods->pause(curstream);
00632 }
00633 
00634 static void
00635 compound_rrstream_destroy(rrstream_t **rsp) {
00636         compound_rrstream_t *s = (compound_rrstream_t *) *rsp;
00637         s->components[0]->methods->destroy(&s->components[0]);
00638         s->components[1]->methods->destroy(&s->components[1]);
00639         s->components[2] = NULL; /* Copy of components[0]. */
00640         isc_mem_putanddetach(&s->common.mctx, s, sizeof(*s));
00641 }
00642 
00643 static rrstream_methods_t compound_rrstream_methods = {
00644         compound_rrstream_first,
00645         compound_rrstream_next,
00646         compound_rrstream_current,
00647         compound_rrstream_pause,
00648         compound_rrstream_destroy
00649 };
00650 
00651 /**************************************************************************/
00652 /*
00653  * An 'xfrout_ctx_t' contains the state of an outgoing AXFR or IXFR
00654  * in progress.
00655  */
00656 
00657 typedef struct {
00658         isc_mem_t               *mctx;
00659         ns_client_t             *client;
00660         unsigned int            id;             /* ID of request */
00661         dns_name_t              *qname;         /* Question name of request */
00662         dns_rdatatype_t         qtype;          /* dns_rdatatype_{a,i}xfr */
00663         dns_rdataclass_t        qclass;
00664         dns_zone_t              *zone;          /* (necessary for stats) */
00665         dns_db_t                *db;
00666         dns_dbversion_t         *ver;
00667         isc_quota_t             *quota;
00668         rrstream_t              *stream;        /* The XFR RR stream */
00669         isc_boolean_t           end_of_stream;  /* EOS has been reached */
00670         isc_buffer_t            buf;            /* Buffer for message owner
00671                                                    names and rdatas */
00672         isc_buffer_t            txlenbuf;       /* Transmit length buffer */
00673         isc_buffer_t            txbuf;          /* Transmit message buffer */
00674         void                    *txmem;
00675         unsigned int            txmemlen;
00676         unsigned int            nmsg;           /* Number of messages sent */
00677         dns_tsigkey_t           *tsigkey;       /* Key used to create TSIG */
00678         isc_buffer_t            *lasttsig;      /* the last TSIG */
00679         isc_boolean_t           many_answers;
00680         int                     sends;          /* Send in progress */
00681         isc_boolean_t           shuttingdown;
00682         const char              *mnemonic;      /* Style of transfer */
00683 } xfrout_ctx_t;
00684 
00685 static isc_result_t
00686 xfrout_ctx_create(isc_mem_t *mctx, ns_client_t *client,
00687                   unsigned int id, dns_name_t *qname, dns_rdatatype_t qtype,
00688                   dns_rdataclass_t qclass, dns_zone_t *zone,
00689                   dns_db_t *db, dns_dbversion_t *ver, isc_quota_t *quota,
00690                   rrstream_t *stream, dns_tsigkey_t *tsigkey,
00691                   isc_buffer_t *lasttsig,
00692                   unsigned int maxtime,
00693                   unsigned int idletime,
00694                   isc_boolean_t many_answers,
00695                   xfrout_ctx_t **xfrp);
00696 
00697 static void
00698 sendstream(xfrout_ctx_t *xfr);
00699 
00700 static void
00701 xfrout_senddone(isc_task_t *task, isc_event_t *event);
00702 
00703 static void
00704 xfrout_fail(xfrout_ctx_t *xfr, isc_result_t result, const char *msg);
00705 
00706 static void
00707 xfrout_maybe_destroy(xfrout_ctx_t *xfr);
00708 
00709 static void
00710 xfrout_ctx_destroy(xfrout_ctx_t **xfrp);
00711 
00712 static void
00713 xfrout_client_shutdown(void *arg, isc_result_t result);
00714 
00715 static void
00716 xfrout_log1(ns_client_t *client, dns_name_t *zonename,
00717             dns_rdataclass_t rdclass, int level,
00718             const char *fmt, ...) ISC_FORMAT_PRINTF(5, 6);
00719 
00720 static void
00721 xfrout_log(xfrout_ctx_t *xfr, int level, const char *fmt, ...)
00722            ISC_FORMAT_PRINTF(3, 4);
00723 
00724 /**************************************************************************/
00725 
00726 void
00727 ns_xfr_start(ns_client_t *client, dns_rdatatype_t reqtype) {
00728         isc_result_t result;
00729         dns_name_t *question_name;
00730         dns_rdataset_t *question_rdataset;
00731         dns_zone_t *zone = NULL, *raw = NULL, *mayberaw;
00732         dns_db_t *db = NULL;
00733         dns_dbversion_t *ver = NULL;
00734         dns_rdataclass_t question_class;
00735         rrstream_t *soa_stream = NULL;
00736         rrstream_t *data_stream = NULL;
00737         rrstream_t *stream = NULL;
00738         dns_difftuple_t *current_soa_tuple = NULL;
00739         dns_name_t *soa_name;
00740         dns_rdataset_t *soa_rdataset;
00741         dns_rdata_t soa_rdata = DNS_RDATA_INIT;
00742         isc_boolean_t have_soa = ISC_FALSE;
00743         const char *mnemonic = NULL;
00744         isc_mem_t *mctx = client->mctx;
00745         dns_message_t *request = client->message;
00746         xfrout_ctx_t *xfr = NULL;
00747         isc_quota_t *quota = NULL;
00748         dns_transfer_format_t format = client->view->transfer_format;
00749         isc_netaddr_t na;
00750         dns_peer_t *peer = NULL;
00751         isc_buffer_t *tsigbuf = NULL;
00752         char *journalfile;
00753         char msg[NS_CLIENT_ACLMSGSIZE("zone transfer")];
00754         char keyname[DNS_NAME_FORMATSIZE];
00755         isc_boolean_t is_poll = ISC_FALSE;
00756         isc_boolean_t is_dlz = ISC_FALSE;
00757         isc_boolean_t is_ixfr = ISC_FALSE;
00758         isc_uint32_t begin_serial = 0, current_serial;
00759 
00760         switch (reqtype) {
00761         case dns_rdatatype_axfr:
00762                 mnemonic = "AXFR";
00763                 break;
00764         case dns_rdatatype_ixfr:
00765                 mnemonic = "IXFR";
00766                 break;
00767         default:
00768                 INSIST(0);
00769                 break;
00770         }
00771 
00772         ns_client_log(client,
00773                       DNS_LOGCATEGORY_XFER_OUT, NS_LOGMODULE_XFER_OUT,
00774                       ISC_LOG_DEBUG(6), "%s request", mnemonic);
00775         /*
00776          * Apply quota.
00777          */
00778         result = isc_quota_attach(&ns_g_server->xfroutquota, &quota);
00779         if (result != ISC_R_SUCCESS) {
00780                 isc_log_write(XFROUT_COMMON_LOGARGS, ISC_LOG_WARNING,
00781                               "%s request denied: %s", mnemonic,
00782                               isc_result_totext(result));
00783                 goto failure;
00784         }
00785 
00786         /*
00787          * Interpret the question section.
00788          */
00789         result = dns_message_firstname(request, DNS_SECTION_QUESTION);
00790         INSIST(result == ISC_R_SUCCESS);
00791 
00792         /*
00793          * The question section must contain exactly one question, and
00794          * it must be for AXFR/IXFR as appropriate.
00795          */
00796         question_name = NULL;
00797         dns_message_currentname(request, DNS_SECTION_QUESTION, &question_name);
00798         question_rdataset = ISC_LIST_HEAD(question_name->list);
00799         question_class = question_rdataset->rdclass;
00800         INSIST(question_rdataset->type == reqtype);
00801         if (ISC_LIST_NEXT(question_rdataset, link) != NULL)
00802                 FAILC(DNS_R_FORMERR, "multiple questions");
00803         result = dns_message_nextname(request, DNS_SECTION_QUESTION);
00804         if (result != ISC_R_NOMORE)
00805                 FAILC(DNS_R_FORMERR, "multiple questions");
00806 
00807         result = dns_zt_find(client->view->zonetable, question_name, 0, NULL,
00808                              &zone);
00809 
00810         if (result != ISC_R_SUCCESS) {
00811                 /*
00812                  * Normal zone table does not have a match.
00813                  * Try the DLZ database
00814                  */
00815                 // Temporary: only searching the first DLZ database
00816                 if (! ISC_LIST_EMPTY(client->view->dlz_searched)) {
00817                         result = dns_dlzallowzonexfr(client->view,
00818                                                      question_name,
00819                                                      &client->peeraddr,
00820                                                      &db);
00821 
00822                         if (result == ISC_R_NOPERM) {
00823                                 char _buf1[DNS_NAME_FORMATSIZE];
00824                                 char _buf2[DNS_RDATACLASS_FORMATSIZE];
00825 
00826                                 result = DNS_R_REFUSED;
00827                                 dns_name_format(question_name, _buf1,
00828                                                 sizeof(_buf1));
00829                                 dns_rdataclass_format(question_class,
00830                                                       _buf2, sizeof(_buf2));
00831                                 ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
00832                                               NS_LOGMODULE_XFER_OUT,
00833                                               ISC_LOG_ERROR,
00834                                               "zone transfer '%s/%s' denied",
00835                                               _buf1, _buf2);
00836                                 goto failure;
00837                         }
00838                         if (result != ISC_R_SUCCESS)
00839                                 FAILQ(DNS_R_NOTAUTH, "non-authoritative zone",
00840                                       question_name, question_class);
00841                         is_dlz = ISC_TRUE;
00842                 } else {
00843                         /*
00844                          * not DLZ and not in normal zone table, we are
00845                          * not authoritative
00846                          */
00847                         FAILQ(DNS_R_NOTAUTH, "non-authoritative zone",
00848                               question_name, question_class);
00849                 }
00850         } else {
00851                 /* zone table has a match */
00852                 switch(dns_zone_gettype(zone)) {
00853                         /* Master and slave zones are OK for transfer. */
00854                         case dns_zone_master:
00855                         case dns_zone_slave:
00856                         case dns_zone_dlz:
00857                                 break;
00858                         default:
00859                                 FAILQ(DNS_R_NOTAUTH, "non-authoritative zone",
00860                                       question_name, question_class);
00861                         }
00862                 CHECK(dns_zone_getdb(zone, &db));
00863                 dns_db_currentversion(db, &ver);
00864         }
00865 
00866         xfrout_log1(client, question_name, question_class, ISC_LOG_DEBUG(6),
00867                     "%s question section OK", mnemonic);
00868 
00869         /*
00870          * Check the authority section.  Look for a SOA record with
00871          * the same name and class as the question.
00872          */
00873         for (result = dns_message_firstname(request, DNS_SECTION_AUTHORITY);
00874              result == ISC_R_SUCCESS;
00875              result = dns_message_nextname(request, DNS_SECTION_AUTHORITY))
00876         {
00877                 soa_name = NULL;
00878                 dns_message_currentname(request, DNS_SECTION_AUTHORITY,
00879                                         &soa_name);
00880 
00881                 /*
00882                  * Ignore data whose owner name is not the zone apex.
00883                  */
00884                 if (! dns_name_equal(soa_name, question_name))
00885                         continue;
00886 
00887                 for (soa_rdataset = ISC_LIST_HEAD(soa_name->list);
00888                      soa_rdataset != NULL;
00889                      soa_rdataset = ISC_LIST_NEXT(soa_rdataset, link))
00890                 {
00891                         /*
00892                          * Ignore non-SOA data.
00893                          */
00894                         if (soa_rdataset->type != dns_rdatatype_soa)
00895                                 continue;
00896                         if (soa_rdataset->rdclass != question_class)
00897                                 continue;
00898 
00899                         CHECK(dns_rdataset_first(soa_rdataset));
00900                         dns_rdataset_current(soa_rdataset, &soa_rdata);
00901                         result = dns_rdataset_next(soa_rdataset);
00902                         if (result == ISC_R_SUCCESS)
00903                                 FAILC(DNS_R_FORMERR,
00904                                       "IXFR authority section "
00905                                       "has multiple SOAs");
00906                         have_soa = ISC_TRUE;
00907                         goto got_soa;
00908                 }
00909         }
00910  got_soa:
00911         if (result != ISC_R_NOMORE)
00912                 CHECK(result);
00913 
00914         xfrout_log1(client, question_name, question_class, ISC_LOG_DEBUG(6),
00915                     "%s authority section OK", mnemonic);
00916 
00917         /*
00918          * If not a DLZ zone, decide whether to allow this transfer.
00919          */
00920         if (!is_dlz) {
00921                 ns_client_aclmsg("zone transfer", question_name, reqtype,
00922                                  client->view->rdclass, msg, sizeof(msg));
00923                 CHECK(ns_client_checkacl(client, NULL, msg,
00924                                          dns_zone_getxfracl(zone),
00925                                          ISC_TRUE, ISC_LOG_ERROR));
00926         }
00927 
00928         /*
00929          * AXFR over UDP is not possible.
00930          */
00931         if (reqtype == dns_rdatatype_axfr &&
00932             (client->attributes & NS_CLIENTATTR_TCP) == 0)
00933                 FAILC(DNS_R_FORMERR, "attempted AXFR over UDP");
00934 
00935         /*
00936          * Look up the requesting server in the peer table.
00937          */
00938         isc_netaddr_fromsockaddr(&na, &client->peeraddr);
00939         (void)dns_peerlist_peerbyaddr(client->view->peers, &na, &peer);
00940 
00941         /*
00942          * Decide on the transfer format (one-answer or many-answers).
00943          */
00944         if (peer != NULL)
00945                 (void)dns_peer_gettransferformat(peer, &format);
00946 
00947         /*
00948          * Get a dynamically allocated copy of the current SOA.
00949          */
00950         if (is_dlz)
00951                 dns_db_currentversion(db, &ver);
00952 
00953         CHECK(dns_db_createsoatuple(db, ver, mctx, DNS_DIFFOP_EXISTS,
00954                                     &current_soa_tuple));
00955 
00956         current_serial = dns_soa_getserial(&current_soa_tuple->rdata);
00957         if (reqtype == dns_rdatatype_ixfr) {
00958                 isc_boolean_t provide_ixfr;
00959 
00960                 /*
00961                  * Outgoing IXFR may have been disabled for this peer
00962                  * or globally.
00963                  */
00964                 provide_ixfr = client->view->provideixfr;
00965                 if (peer != NULL)
00966                         (void) dns_peer_getprovideixfr(peer, &provide_ixfr);
00967                 if (provide_ixfr == ISC_FALSE)
00968                         goto axfr_fallback;
00969 
00970                 if (! have_soa)
00971                         FAILC(DNS_R_FORMERR,
00972                               "IXFR request missing SOA");
00973 
00974                 begin_serial = dns_soa_getserial(&soa_rdata);
00975 
00976                 /*
00977                  * RFC1995 says "If an IXFR query with the same or
00978                  * newer version number than that of the server
00979                  * is received, it is replied to with a single SOA
00980                  * record of the server's current version, just as
00981                  * in AXFR".  The claim about AXFR is incorrect,
00982                  * but other than that, we do as the RFC says.
00983                  *
00984                  * Sending a single SOA record is also how we refuse
00985                  * IXFR over UDP (currently, we always do).
00986                  */
00987                 if (DNS_SERIAL_GE(begin_serial, current_serial) ||
00988                     (client->attributes & NS_CLIENTATTR_TCP) == 0)
00989                 {
00990                         CHECK(soa_rrstream_create(mctx, db, ver, &stream));
00991                         is_poll = ISC_TRUE;
00992                         goto have_stream;
00993                 }
00994                 journalfile = is_dlz ? NULL : dns_zone_getjournal(zone);
00995                 if (journalfile != NULL)
00996                         result = ixfr_rrstream_create(mctx,
00997                                                       journalfile,
00998                                                       begin_serial,
00999                                                       current_serial,
01000                                                       &data_stream);
01001                 else
01002                         result = ISC_R_NOTFOUND;
01003                 if (result == ISC_R_NOTFOUND ||
01004                     result == ISC_R_RANGE) {
01005                         xfrout_log1(client, question_name, question_class,
01006                                     ISC_LOG_DEBUG(4),
01007                                     "IXFR version not in journal, "
01008                                     "falling back to AXFR");
01009                         mnemonic = "AXFR-style IXFR";
01010                         goto axfr_fallback;
01011                 }
01012                 CHECK(result);
01013                 is_ixfr = ISC_TRUE;
01014         } else {
01015         axfr_fallback:
01016                 CHECK(axfr_rrstream_create(mctx, db, ver, &data_stream));
01017         }
01018 
01019         /*
01020          * Bracket the data stream with SOAs.
01021          */
01022         CHECK(soa_rrstream_create(mctx, db, ver, &soa_stream));
01023         CHECK(compound_rrstream_create(mctx, &soa_stream, &data_stream,
01024                                        &stream));
01025         soa_stream = NULL;
01026         data_stream = NULL;
01027 
01028  have_stream:
01029         CHECK(dns_message_getquerytsig(request, mctx, &tsigbuf));
01030         /*
01031          * Create the xfrout context object.  This transfers the ownership
01032          * of "stream", "db", "ver", and "quota" to the xfrout context object.
01033          */
01034 
01035 
01036 
01037         if (is_dlz)
01038                 CHECK(xfrout_ctx_create(mctx, client, request->id,
01039                                         question_name, reqtype, question_class,
01040                                         zone, db, ver, quota, stream,
01041                                         dns_message_gettsigkey(request),
01042                                         tsigbuf,
01043                                         3600,
01044                                         3600,
01045                                         (format == dns_many_answers) ?
01046                                         ISC_TRUE : ISC_FALSE,
01047                                         &xfr));
01048         else
01049                 CHECK(xfrout_ctx_create(mctx, client, request->id,
01050                                         question_name, reqtype, question_class,
01051                                         zone, db, ver, quota, stream,
01052                                         dns_message_gettsigkey(request),
01053                                         tsigbuf,
01054                                         dns_zone_getmaxxfrout(zone),
01055                                         dns_zone_getidleout(zone),
01056                                         (format == dns_many_answers) ?
01057                                         ISC_TRUE : ISC_FALSE,
01058                                         &xfr));
01059 
01060         xfr->mnemonic = mnemonic;
01061         stream = NULL;
01062         quota = NULL;
01063 
01064         CHECK(xfr->stream->methods->first(xfr->stream));
01065 
01066         if (xfr->tsigkey != NULL)
01067                 dns_name_format(&xfr->tsigkey->name, keyname, sizeof(keyname));
01068         else
01069                 keyname[0] = '\0';
01070         if (is_poll)
01071                 xfrout_log1(client, question_name, question_class,
01072                             ISC_LOG_DEBUG(1), "IXFR poll up to date%s%s",
01073                             (xfr->tsigkey != NULL) ? ": TSIG " : "", keyname);
01074         else if (is_ixfr)
01075                 xfrout_log1(client, question_name, question_class,
01076                             ISC_LOG_INFO, "%s started%s%s (serial %u -> %u)",
01077                             mnemonic, (xfr->tsigkey != NULL) ? ": TSIG " : "",
01078                             keyname, begin_serial, current_serial);
01079         else
01080                 xfrout_log1(client, question_name, question_class,
01081                             ISC_LOG_INFO, "%s started%s%s (serial %u)",
01082                             mnemonic, (xfr->tsigkey != NULL) ? ": TSIG " : "",
01083                             keyname, current_serial);
01084 
01085 
01086         if (zone != NULL) {
01087                 dns_zone_getraw(zone, &raw);
01088                 mayberaw = (raw != NULL) ? raw : zone;
01089                 if ((client->attributes & NS_CLIENTATTR_WANTEXPIRE) != 0 &&
01090                     dns_zone_gettype(mayberaw) == dns_zone_slave) {
01091                         isc_time_t expiretime;
01092                         isc_uint32_t secs;
01093                         dns_zone_getexpiretime(zone, &expiretime);
01094                         secs = isc_time_seconds(&expiretime);
01095                         if (secs >= client->now && result == ISC_R_SUCCESS) {
01096                                 client->attributes |= NS_CLIENTATTR_HAVEEXPIRE;
01097                                 client->expire = secs - client->now;
01098                         }
01099                 }
01100                 if (raw != NULL)
01101                         dns_zone_detach(&raw);
01102         }
01103 
01104         /*
01105          * Hand the context over to sendstream().  Set xfr to NULL;
01106          * sendstream() is responsible for either passing the
01107          * context on to a later event handler or destroying it.
01108          */
01109         sendstream(xfr);
01110         xfr = NULL;
01111 
01112         result = ISC_R_SUCCESS;
01113 
01114  failure:
01115         if (result == DNS_R_REFUSED)
01116                 inc_stats(zone, dns_nsstatscounter_xfrrej);
01117         if (quota != NULL)
01118                 isc_quota_detach(&quota);
01119         if (current_soa_tuple != NULL)
01120                 dns_difftuple_free(&current_soa_tuple);
01121         if (stream != NULL)
01122                 stream->methods->destroy(&stream);
01123         if (soa_stream != NULL)
01124                 soa_stream->methods->destroy(&soa_stream);
01125         if (data_stream != NULL)
01126                 data_stream->methods->destroy(&data_stream);
01127         if (ver != NULL)
01128                 dns_db_closeversion(db, &ver, ISC_FALSE);
01129         if (db != NULL)
01130                 dns_db_detach(&db);
01131         if (zone != NULL)
01132                 dns_zone_detach(&zone);
01133         /* XXX kludge */
01134         if (xfr != NULL) {
01135                 xfrout_fail(xfr, result, "setting up zone transfer");
01136         } else if (result != ISC_R_SUCCESS) {
01137                 ns_client_log(client, DNS_LOGCATEGORY_XFER_OUT,
01138                               NS_LOGMODULE_XFER_OUT,
01139                               ISC_LOG_DEBUG(3), "zone transfer setup failed");
01140                 ns_client_error(client, result);
01141         }
01142 }
01143 
01144 static isc_result_t
01145 xfrout_ctx_create(isc_mem_t *mctx, ns_client_t *client, unsigned int id,
01146                   dns_name_t *qname, dns_rdatatype_t qtype,
01147                   dns_rdataclass_t qclass, dns_zone_t *zone,
01148                   dns_db_t *db, dns_dbversion_t *ver, isc_quota_t *quota,
01149                   rrstream_t *stream, dns_tsigkey_t *tsigkey,
01150                   isc_buffer_t *lasttsig, unsigned int maxtime,
01151                   unsigned int idletime, isc_boolean_t many_answers,
01152                   xfrout_ctx_t **xfrp)
01153 {
01154         xfrout_ctx_t *xfr;
01155         isc_result_t result;
01156         unsigned int len;
01157         void *mem;
01158 
01159         INSIST(xfrp != NULL && *xfrp == NULL);
01160         xfr = isc_mem_get(mctx, sizeof(*xfr));
01161         if (xfr == NULL)
01162                 return (ISC_R_NOMEMORY);
01163         xfr->mctx = NULL;
01164         isc_mem_attach(mctx, &xfr->mctx);
01165         xfr->client = NULL;
01166         ns_client_attach(client, &xfr->client);
01167         xfr->id = id;
01168         xfr->qname = qname;
01169         xfr->qtype = qtype;
01170         xfr->qclass = qclass;
01171         xfr->zone = NULL;
01172         xfr->db = NULL;
01173         xfr->ver = NULL;
01174         if (zone != NULL)       /* zone will be NULL if it's DLZ */
01175                 dns_zone_attach(zone, &xfr->zone);
01176         dns_db_attach(db, &xfr->db);
01177         dns_db_attachversion(db, ver, &xfr->ver);
01178         xfr->end_of_stream = ISC_FALSE;
01179         xfr->tsigkey = tsigkey;
01180         xfr->lasttsig = lasttsig;
01181         xfr->txmem = NULL;
01182         xfr->txmemlen = 0;
01183         xfr->nmsg = 0;
01184         xfr->many_answers = many_answers,
01185         xfr->sends = 0;
01186         xfr->shuttingdown = ISC_FALSE;
01187         xfr->mnemonic = NULL;
01188         xfr->buf.base = NULL;
01189         xfr->buf.length = 0;
01190         xfr->txmem = NULL;
01191         xfr->txmemlen = 0;
01192         xfr->stream = NULL;
01193         xfr->quota = NULL;
01194 
01195         /*
01196          * Allocate a temporary buffer for the uncompressed response
01197          * message data.  The size should be no more than 65535 bytes
01198          * so that the compressed data will fit in a TCP message,
01199          * and no less than 65535 bytes so that an almost maximum-sized
01200          * RR will fit.  Note that although 65535-byte RRs are allowed
01201          * in principle, they cannot be zone-transferred (at least not
01202          * if uncompressible), because the message and RR headers would
01203          * push the size of the TCP message over the 65536 byte limit.
01204          */
01205         len = 65535;
01206         mem = isc_mem_get(mctx, len);
01207         if (mem == NULL) {
01208                 result = ISC_R_NOMEMORY;
01209                 goto failure;
01210         }
01211         isc_buffer_init(&xfr->buf, mem, len);
01212 
01213         /*
01214          * Allocate another temporary buffer for the compressed
01215          * response message and its TCP length prefix.
01216          */
01217         len = 2 + 65535;
01218         mem = isc_mem_get(mctx, len);
01219         if (mem == NULL) {
01220                 result = ISC_R_NOMEMORY;
01221                 goto failure;
01222         }
01223         isc_buffer_init(&xfr->txlenbuf, mem, 2);
01224         isc_buffer_init(&xfr->txbuf, (char *) mem + 2, len - 2);
01225         xfr->txmem = mem;
01226         xfr->txmemlen = len;
01227 
01228         CHECK(dns_timer_setidle(xfr->client->timer,
01229                                 maxtime, idletime, ISC_FALSE));
01230 
01231         /*
01232          * Register a shutdown callback with the client, so that we
01233          * can stop the transfer immediately when the client task
01234          * gets a shutdown event.
01235          */
01236         xfr->client->shutdown = xfrout_client_shutdown;
01237         xfr->client->shutdown_arg = xfr;
01238         /*
01239          * These MUST be after the last "goto failure;" / CHECK to
01240          * prevent a double free by the caller.
01241          */
01242         xfr->quota = quota;
01243         xfr->stream = stream;
01244 
01245         *xfrp = xfr;
01246         return (ISC_R_SUCCESS);
01247 
01248 failure:
01249         xfrout_ctx_destroy(&xfr);
01250         return (result);
01251 }
01252 
01253 
01254 /*
01255  * Arrange to send as much as we can of "stream" without blocking.
01256  *
01257  * Requires:
01258  *      The stream iterator is initialized and points at an RR,
01259  *      or possibly at the end of the stream (that is, the
01260  *      _first method of the iterator has been called).
01261  */
01262 static void
01263 sendstream(xfrout_ctx_t *xfr) {
01264         dns_message_t *tcpmsg = NULL;
01265         dns_message_t *msg = NULL; /* Client message if UDP, tcpmsg if TCP */
01266         isc_result_t result;
01267         isc_region_t used;
01268         isc_region_t region;
01269         dns_rdataset_t *qrdataset;
01270         dns_name_t *msgname = NULL;
01271         dns_rdata_t *msgrdata = NULL;
01272         dns_rdatalist_t *msgrdl = NULL;
01273         dns_rdataset_t *msgrds = NULL;
01274         dns_compress_t cctx;
01275         isc_boolean_t cleanup_cctx = ISC_FALSE;
01276 
01277         int n_rrs;
01278 
01279         isc_buffer_clear(&xfr->buf);
01280         isc_buffer_clear(&xfr->txlenbuf);
01281         isc_buffer_clear(&xfr->txbuf);
01282 
01283         if ((xfr->client->attributes & NS_CLIENTATTR_TCP) == 0) {
01284                 /*
01285                  * In the UDP case, we put the response data directly into
01286                  * the client message.
01287                  */
01288                 msg = xfr->client->message;
01289                 CHECK(dns_message_reply(msg, ISC_TRUE));
01290         } else {
01291                 /*
01292                  * TCP. Build a response dns_message_t, temporarily storing
01293                  * the raw, uncompressed owner names and RR data contiguously
01294                  * in xfr->buf.  We know that if the uncompressed data fits
01295                  * in xfr->buf, the compressed data will surely fit in a TCP
01296                  * message.
01297                  */
01298 
01299                 CHECK(dns_message_create(xfr->mctx,
01300                                          DNS_MESSAGE_INTENTRENDER, &tcpmsg));
01301                 msg = tcpmsg;
01302 
01303                 msg->id = xfr->id;
01304                 msg->rcode = dns_rcode_noerror;
01305                 msg->flags = DNS_MESSAGEFLAG_QR | DNS_MESSAGEFLAG_AA;
01306                 if ((xfr->client->attributes & NS_CLIENTATTR_RA) != 0)
01307                         msg->flags |= DNS_MESSAGEFLAG_RA;
01308                 CHECK(dns_message_settsigkey(msg, xfr->tsigkey));
01309                 CHECK(dns_message_setquerytsig(msg, xfr->lasttsig));
01310                 if (xfr->lasttsig != NULL)
01311                         isc_buffer_free(&xfr->lasttsig);
01312 
01313                 /*
01314                  * Add a EDNS option to the message?
01315                  */
01316                 if ((xfr->client->attributes & NS_CLIENTATTR_WANTOPT) != 0) {
01317                         dns_rdataset_t *opt = NULL;
01318 
01319                         CHECK(ns_client_addopt(xfr->client, msg, &opt));
01320                         CHECK(dns_message_setopt(msg, opt));
01321                         /*
01322                          * Add to first message only.
01323                          */
01324                         xfr->client->attributes &= ~NS_CLIENTATTR_WANTNSID;
01325                         xfr->client->attributes &= ~NS_CLIENTATTR_HAVEEXPIRE;
01326                 }
01327 
01328                 /*
01329                  * Account for reserved space.
01330                  */
01331                 if (xfr->tsigkey != NULL)
01332                         INSIST(msg->reserved != 0U);
01333                 isc_buffer_add(&xfr->buf, msg->reserved);
01334 
01335                 /*
01336                  * Include a question section in the first message only.
01337                  * BIND 8.2.1 will not recognize an IXFR if it does not
01338                  * have a question section.
01339                  */
01340                 if (xfr->nmsg == 0) {
01341                         dns_name_t *qname = NULL;
01342                         isc_region_t r;
01343 
01344                         /*
01345                          * Reserve space for the 12-byte message header
01346                          * and 4 bytes of question.
01347                          */
01348                         isc_buffer_add(&xfr->buf, 12 + 4);
01349 
01350                         qrdataset = NULL;
01351                         result = dns_message_gettemprdataset(msg, &qrdataset);
01352                         if (result != ISC_R_SUCCESS)
01353                                 goto failure;
01354                         dns_rdataset_init(qrdataset);
01355                         dns_rdataset_makequestion(qrdataset,
01356                                         xfr->client->message->rdclass,
01357                                         xfr->qtype);
01358 
01359                         result = dns_message_gettempname(msg, &qname);
01360                         if (result != ISC_R_SUCCESS)
01361                                 goto failure;
01362                         dns_name_init(qname, NULL);
01363                         isc_buffer_availableregion(&xfr->buf, &r);
01364                         INSIST(r.length >= xfr->qname->length);
01365                         r.length = xfr->qname->length;
01366                         isc_buffer_putmem(&xfr->buf, xfr->qname->ndata,
01367                                           xfr->qname->length);
01368                         dns_name_fromregion(qname, &r);
01369                         ISC_LIST_INIT(qname->list);
01370                         ISC_LIST_APPEND(qname->list, qrdataset, link);
01371 
01372                         dns_message_addname(msg, qname, DNS_SECTION_QUESTION);
01373                 } else {
01374                         /*
01375                          * Reserve space for the 12-byte message header
01376                          */
01377                         isc_buffer_add(&xfr->buf, 12);
01378                         msg->tcp_continuation = 1;
01379                 }
01380         }
01381 
01382         /*
01383          * Try to fit in as many RRs as possible, unless "one-answer"
01384          * format has been requested.
01385          */
01386         for (n_rrs = 0; ; n_rrs++) {
01387                 dns_name_t *name = NULL;
01388                 isc_uint32_t ttl;
01389                 dns_rdata_t *rdata = NULL;
01390 
01391                 unsigned int size;
01392                 isc_region_t r;
01393 
01394                 msgname = NULL;
01395                 msgrdata = NULL;
01396                 msgrdl = NULL;
01397                 msgrds = NULL;
01398 
01399                 xfr->stream->methods->current(xfr->stream,
01400                                               &name, &ttl, &rdata);
01401                 size = name->length + 10 + rdata->length;
01402                 isc_buffer_availableregion(&xfr->buf, &r);
01403                 if (size >= r.length) {
01404                         /*
01405                          * RR would not fit.  If there are other RRs in the
01406                          * buffer, send them now and leave this RR to the
01407                          * next message.  If this RR overflows the buffer
01408                          * all by itself, fail.
01409                          *
01410                          * In theory some RRs might fit in a TCP message
01411                          * when compressed even if they do not fit when
01412                          * uncompressed, but surely we don't want
01413                          * to send such monstrosities to an unsuspecting
01414                          * slave.
01415                          */
01416                         if (n_rrs == 0) {
01417                                 xfrout_log(xfr, ISC_LOG_WARNING,
01418                                            "RR too large for zone transfer "
01419                                            "(%d bytes)", size);
01420                                 /* XXX DNS_R_RRTOOLARGE? */
01421                                 result = ISC_R_NOSPACE;
01422                                 goto failure;
01423                         }
01424                         break;
01425                 }
01426 
01427                 if (isc_log_wouldlog(ns_g_lctx, XFROUT_RR_LOGLEVEL))
01428                         log_rr(name, rdata, ttl); /* XXX */
01429 
01430                 result = dns_message_gettempname(msg, &msgname);
01431                 if (result != ISC_R_SUCCESS)
01432                         goto failure;
01433                 dns_name_init(msgname, NULL);
01434                 isc_buffer_availableregion(&xfr->buf, &r);
01435                 INSIST(r.length >= name->length);
01436                 r.length = name->length;
01437                 isc_buffer_putmem(&xfr->buf, name->ndata, name->length);
01438                 dns_name_fromregion(msgname, &r);
01439 
01440                 /* Reserve space for RR header. */
01441                 isc_buffer_add(&xfr->buf, 10);
01442 
01443                 result = dns_message_gettemprdata(msg, &msgrdata);
01444                 if (result != ISC_R_SUCCESS)
01445                         goto failure;
01446                 isc_buffer_availableregion(&xfr->buf, &r);
01447                 r.length = rdata->length;
01448                 isc_buffer_putmem(&xfr->buf, rdata->data, rdata->length);
01449                 dns_rdata_init(msgrdata);
01450                 dns_rdata_fromregion(msgrdata,
01451                                      rdata->rdclass, rdata->type, &r);
01452 
01453                 result = dns_message_gettemprdatalist(msg, &msgrdl);
01454                 if (result != ISC_R_SUCCESS)
01455                         goto failure;
01456                 msgrdl->type = rdata->type;
01457                 msgrdl->rdclass = rdata->rdclass;
01458                 msgrdl->ttl = ttl;
01459                 if (rdata->type == dns_rdatatype_sig ||
01460                     rdata->type == dns_rdatatype_rrsig)
01461                         msgrdl->covers = dns_rdata_covers(rdata);
01462                 else
01463                         msgrdl->covers = dns_rdatatype_none;
01464                 ISC_LIST_APPEND(msgrdl->rdata, msgrdata, link);
01465 
01466                 result = dns_message_gettemprdataset(msg, &msgrds);
01467                 if (result != ISC_R_SUCCESS)
01468                         goto failure;
01469                 dns_rdataset_init(msgrds);
01470                 result = dns_rdatalist_tordataset(msgrdl, msgrds);
01471                 INSIST(result == ISC_R_SUCCESS);
01472 
01473                 ISC_LIST_APPEND(msgname->list, msgrds, link);
01474 
01475                 dns_message_addname(msg, msgname, DNS_SECTION_ANSWER);
01476                 msgname = NULL;
01477 
01478                 result = xfr->stream->methods->next(xfr->stream);
01479                 if (result == ISC_R_NOMORE) {
01480                         xfr->end_of_stream = ISC_TRUE;
01481                         break;
01482                 }
01483                 CHECK(result);
01484 
01485                 if (! xfr->many_answers)
01486                         break;
01487         }
01488 
01489         if ((xfr->client->attributes & NS_CLIENTATTR_TCP) != 0) {
01490                 CHECK(dns_compress_init(&cctx, -1, xfr->mctx));
01491                 dns_compress_setsensitive(&cctx, ISC_TRUE);
01492                 cleanup_cctx = ISC_TRUE;
01493                 CHECK(dns_message_renderbegin(msg, &cctx, &xfr->txbuf));
01494                 CHECK(dns_message_rendersection(msg, DNS_SECTION_QUESTION, 0));
01495                 CHECK(dns_message_rendersection(msg, DNS_SECTION_ANSWER, 0));
01496                 CHECK(dns_message_renderend(msg));
01497                 dns_compress_invalidate(&cctx);
01498                 cleanup_cctx = ISC_FALSE;
01499 
01500                 isc_buffer_usedregion(&xfr->txbuf, &used);
01501                 isc_buffer_putuint16(&xfr->txlenbuf,
01502                                      (isc_uint16_t)used.length);
01503                 region.base = xfr->txlenbuf.base;
01504                 region.length = 2 + used.length;
01505                 xfrout_log(xfr, ISC_LOG_DEBUG(8),
01506                            "sending TCP message of %d bytes",
01507                            used.length);
01508                 CHECK(isc_socket_send(xfr->client->tcpsocket, /* XXX */
01509                                       &region, xfr->client->task,
01510                                       xfrout_senddone,
01511                                       xfr));
01512                 xfr->sends++;
01513         } else {
01514                 xfrout_log(xfr, ISC_LOG_DEBUG(8), "sending IXFR UDP response");
01515                 ns_client_send(xfr->client);
01516                 xfr->stream->methods->pause(xfr->stream);
01517                 xfrout_ctx_destroy(&xfr);
01518                 return;
01519         }
01520 
01521         /* Advance lasttsig to be the last TSIG generated */
01522         CHECK(dns_message_getquerytsig(msg, xfr->mctx, &xfr->lasttsig));
01523 
01524         xfr->nmsg++;
01525 
01526  failure:
01527         if (msgname != NULL) {
01528                 if (msgrds != NULL) {
01529                         if (dns_rdataset_isassociated(msgrds))
01530                                 dns_rdataset_disassociate(msgrds);
01531                         dns_message_puttemprdataset(msg, &msgrds);
01532                 }
01533                 if (msgrdl != NULL) {
01534                         ISC_LIST_UNLINK(msgrdl->rdata, msgrdata, link);
01535                         dns_message_puttemprdatalist(msg, &msgrdl);
01536                 }
01537                 if (msgrdata != NULL)
01538                         dns_message_puttemprdata(msg, &msgrdata);
01539                 dns_message_puttempname(msg, &msgname);
01540         }
01541 
01542         if (tcpmsg != NULL)
01543                 dns_message_destroy(&tcpmsg);
01544 
01545         if (cleanup_cctx)
01546                 dns_compress_invalidate(&cctx);
01547         /*
01548          * Make sure to release any locks held by database
01549          * iterators before returning from the event handler.
01550          */
01551         xfr->stream->methods->pause(xfr->stream);
01552 
01553         if (result == ISC_R_SUCCESS)
01554                 return;
01555 
01556         xfrout_fail(xfr, result, "sending zone data");
01557 }
01558 
01559 static void
01560 xfrout_ctx_destroy(xfrout_ctx_t **xfrp) {
01561         xfrout_ctx_t *xfr = *xfrp;
01562         ns_client_t *client = NULL;
01563 
01564         INSIST(xfr->sends == 0);
01565 
01566         xfr->client->shutdown = NULL;
01567         xfr->client->shutdown_arg = NULL;
01568 
01569         if (xfr->stream != NULL)
01570                 xfr->stream->methods->destroy(&xfr->stream);
01571         if (xfr->buf.base != NULL)
01572                 isc_mem_put(xfr->mctx, xfr->buf.base, xfr->buf.length);
01573         if (xfr->txmem != NULL)
01574                 isc_mem_put(xfr->mctx, xfr->txmem, xfr->txmemlen);
01575         if (xfr->lasttsig != NULL)
01576                 isc_buffer_free(&xfr->lasttsig);
01577         if (xfr->quota != NULL)
01578                 isc_quota_detach(&xfr->quota);
01579         if (xfr->ver != NULL)
01580                 dns_db_closeversion(xfr->db, &xfr->ver, ISC_FALSE);
01581         if (xfr->zone != NULL)
01582                 dns_zone_detach(&xfr->zone);
01583         if (xfr->db != NULL)
01584                 dns_db_detach(&xfr->db);
01585 
01586         /*
01587          * We want to detch the client after we have released the memory
01588          * context as ns_client_detach checks the memory reference count.
01589          */
01590         ns_client_attach(xfr->client, &client);
01591         ns_client_detach(&xfr->client);
01592         isc_mem_putanddetach(&xfr->mctx, xfr, sizeof(*xfr));
01593         ns_client_detach(&client);
01594 
01595         *xfrp = NULL;
01596 }
01597 
01598 static void
01599 xfrout_senddone(isc_task_t *task, isc_event_t *event) {
01600         isc_socketevent_t *sev = (isc_socketevent_t *)event;
01601         xfrout_ctx_t *xfr = (xfrout_ctx_t *)event->ev_arg;
01602         isc_result_t evresult = sev->result;
01603 
01604         UNUSED(task);
01605 
01606         INSIST(event->ev_type == ISC_SOCKEVENT_SENDDONE);
01607 
01608         isc_event_free(&event);
01609         xfr->sends--;
01610         INSIST(xfr->sends == 0);
01611 
01612         (void)isc_timer_touch(xfr->client->timer);
01613         if (xfr->shuttingdown == ISC_TRUE) {
01614                 xfrout_maybe_destroy(xfr);
01615         } else if (evresult != ISC_R_SUCCESS) {
01616                 xfrout_fail(xfr, evresult, "send");
01617         } else if (xfr->end_of_stream == ISC_FALSE) {
01618                 sendstream(xfr);
01619         } else {
01620                 /* End of zone transfer stream. */
01621                 inc_stats(xfr->zone, dns_nsstatscounter_xfrdone);
01622                 xfrout_log(xfr, ISC_LOG_INFO, "%s ended", xfr->mnemonic);
01623                 ns_client_next(xfr->client, ISC_R_SUCCESS);
01624                 xfrout_ctx_destroy(&xfr);
01625         }
01626 }
01627 
01628 static void
01629 xfrout_fail(xfrout_ctx_t *xfr, isc_result_t result, const char *msg) {
01630         xfr->shuttingdown = ISC_TRUE;
01631         xfrout_log(xfr, ISC_LOG_ERROR, "%s: %s",
01632                    msg, isc_result_totext(result));
01633         xfrout_maybe_destroy(xfr);
01634 }
01635 
01636 static void
01637 xfrout_maybe_destroy(xfrout_ctx_t *xfr) {
01638         INSIST(xfr->shuttingdown == ISC_TRUE);
01639         if (xfr->sends > 0) {
01640                 /*
01641                  * If we are currently sending, cancel it and wait for
01642                  * cancel event before destroying the context.
01643                  */
01644                 isc_socket_cancel(xfr->client->tcpsocket, xfr->client->task,
01645                                   ISC_SOCKCANCEL_SEND);
01646         } else {
01647                 ns_client_next(xfr->client, ISC_R_CANCELED);
01648                 xfrout_ctx_destroy(&xfr);
01649         }
01650 }
01651 
01652 static void
01653 xfrout_client_shutdown(void *arg, isc_result_t result) {
01654         xfrout_ctx_t *xfr = (xfrout_ctx_t *) arg;
01655         xfrout_fail(xfr, result, "aborted");
01656 }
01657 
01658 /*
01659  * Log outgoing zone transfer messages in a format like
01660  * <client>: transfer of <zone>: <message>
01661  */
01662 
01663 static void
01664 xfrout_logv(ns_client_t *client, dns_name_t *zonename,
01665             dns_rdataclass_t rdclass, int level, const char *fmt, va_list ap)
01666      ISC_FORMAT_PRINTF(5, 0);
01667 
01668 static void
01669 xfrout_logv(ns_client_t *client, dns_name_t *zonename,
01670             dns_rdataclass_t rdclass, int level, const char *fmt, va_list ap)
01671 {
01672         char msgbuf[2048];
01673         char namebuf[DNS_NAME_FORMATSIZE];
01674         char classbuf[DNS_RDATACLASS_FORMATSIZE];
01675 
01676         dns_name_format(zonename, namebuf, sizeof(namebuf));
01677         dns_rdataclass_format(rdclass, classbuf, sizeof(classbuf));
01678         vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
01679         ns_client_log(client, DNS_LOGCATEGORY_XFER_OUT,
01680                       NS_LOGMODULE_XFER_OUT, level,
01681                       "transfer of '%s/%s': %s", namebuf, classbuf, msgbuf);
01682 }
01683 
01684 /*
01685  * Logging function for use when a xfrout_ctx_t has not yet been created.
01686  */
01687 static void
01688 xfrout_log1(ns_client_t *client, dns_name_t *zonename,
01689             dns_rdataclass_t rdclass, int level, const char *fmt, ...) {
01690         va_list ap;
01691         va_start(ap, fmt);
01692         xfrout_logv(client, zonename, rdclass, level, fmt, ap);
01693         va_end(ap);
01694 }
01695 
01696 /*
01697  * Logging function for use when there is a xfrout_ctx_t.
01698  */
01699 static void
01700 xfrout_log(xfrout_ctx_t *xfr, int level, const char *fmt, ...) {
01701         va_list ap;
01702         va_start(ap, fmt);
01703         xfrout_logv(xfr->client, xfr->qname, xfr->qclass, level, fmt, ap);
01704         va_end(ap);
01705 }

Generated on Tue Apr 28 17:40:55 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha