diff options
Diffstat (limited to 'contrib/bind9/lib/dns/masterdump.c')
-rw-r--r-- | contrib/bind9/lib/dns/masterdump.c | 351 |
1 files changed, 317 insertions, 34 deletions
diff --git a/contrib/bind9/lib/dns/masterdump.c b/contrib/bind9/lib/dns/masterdump.c index 0f4716d..03716e2 100644 --- a/contrib/bind9/lib/dns/masterdump.c +++ b/contrib/bind9/lib/dns/masterdump.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2006 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any @@ -15,7 +15,9 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: masterdump.c,v 1.56.2.5.2.15 2006/03/10 00:17:21 marka Exp $ */ +/* $Id: masterdump.c,v 1.73.18.14 2006/08/08 06:39:36 marka Exp $ */ + +/*! \file */ #include <config.h> @@ -29,13 +31,16 @@ #include <isc/stdio.h> #include <isc/string.h> #include <isc/task.h> +#include <isc/time.h> #include <isc/util.h> #include <dns/db.h> #include <dns/dbiterator.h> #include <dns/events.h> #include <dns/fixedname.h> +#include <dns/lib.h> #include <dns/log.h> +#include <dns/master.h> #include <dns/masterdump.h> #include <dns/rdata.h> #include <dns/rdataclass.h> @@ -65,7 +70,7 @@ struct dns_master_style { unsigned int tab_width; }; -/* +/*% * The maximum length of the newline+indentation that is output * when inserting a line break in an RR. This effectively puts an * upper limits on the value of "rdata_column", because if it is @@ -73,7 +78,7 @@ struct dns_master_style { */ #define DNS_TOTEXT_LINEBREAK_MAXLEN 100 -/* +/*% * Context structure for a masterfile dump in progress. */ typedef struct dns_totext_ctx { @@ -134,7 +139,7 @@ dns_master_style_simple = { 24, 32, 32, 40, 80, 8 }; -/* +/*% * A style suitable for dns_rdataset_totext(). */ LIBDNS_EXTERNAL_DATA const dns_master_style_t @@ -171,11 +176,16 @@ struct dns_dumpctx { /* dns_master_dumpinc() */ char *file; char *tmpfile; + dns_masterformat_t format; + isc_result_t (*dumpsets)(isc_mem_t *mctx, dns_name_t *name, + dns_rdatasetiter_t *rdsiter, + dns_totext_ctx_t *ctx, + isc_buffer_t *buffer, FILE *f); }; #define NXDOMAIN(x) (((x)->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0) -/* +/*% * Output tabs and spaces to go from column '*current' to * column 'to', and update '*current' to reflect the new * current column. @@ -348,6 +358,7 @@ rdataset_totext(dns_rdataset_t *rdataset, REQUIRE(DNS_RDATASET_VALID(rdataset)); + rdataset->attributes |= DNS_RDATASETATTR_LOADORDER; result = dns_rdataset_first(rdataset); REQUIRE(result == ISC_R_SUCCESS); @@ -774,9 +785,9 @@ static const char *trustnames[] = { }; static isc_result_t -dump_rdatasets(isc_mem_t *mctx, dns_name_t *name, dns_rdatasetiter_t *rdsiter, - dns_totext_ctx_t *ctx, - isc_buffer_t *buffer, FILE *f) +dump_rdatasets_text(isc_mem_t *mctx, dns_name_t *name, + dns_rdatasetiter_t *rdsiter, dns_totext_ctx_t *ctx, + isc_buffer_t *buffer, FILE *f) { isc_result_t itresult, dumpresult; isc_region_t r; @@ -848,6 +859,146 @@ dump_rdatasets(isc_mem_t *mctx, dns_name_t *name, dns_rdatasetiter_t *rdsiter, return (itresult); } +/* + * Dump given RRsets in the "raw" format. + */ +static isc_result_t +dump_rdataset_raw(isc_mem_t *mctx, dns_name_t *name, dns_rdataset_t *rdataset, + isc_buffer_t *buffer, FILE *f) +{ + isc_result_t result; + isc_uint32_t totallen; + isc_uint16_t dlen; + isc_region_t r, r_hdr; + + REQUIRE(buffer->length > 0); + REQUIRE(DNS_RDATASET_VALID(rdataset)); + + restart: + totallen = 0; + result = dns_rdataset_first(rdataset); + REQUIRE(result == ISC_R_SUCCESS); + + isc_buffer_clear(buffer); + + /* + * Common header and owner name (length followed by name) + * These fields should be in a moderate length, so we assume we + * can store all of them in the initial buffer. + */ + isc_buffer_availableregion(buffer, &r_hdr); + INSIST(r_hdr.length >= sizeof(dns_masterrawrdataset_t)); + isc_buffer_putuint32(buffer, totallen); /* XXX: leave space */ + isc_buffer_putuint16(buffer, rdataset->rdclass); /* 16-bit class */ + isc_buffer_putuint16(buffer, rdataset->type); /* 16-bit type */ + isc_buffer_putuint16(buffer, rdataset->covers); /* same as type */ + isc_buffer_putuint32(buffer, rdataset->ttl); /* 32-bit TTL */ + isc_buffer_putuint32(buffer, dns_rdataset_count(rdataset)); + totallen = isc_buffer_usedlength(buffer); + INSIST(totallen <= sizeof(dns_masterrawrdataset_t)); + + dns_name_toregion(name, &r); + INSIST(isc_buffer_availablelength(buffer) >= + (sizeof(dlen) + r.length)); + dlen = (isc_uint16_t)r.length; + isc_buffer_putuint16(buffer, dlen); + isc_buffer_copyregion(buffer, &r); + totallen += sizeof(dlen) + r.length; + + do { + dns_rdata_t rdata = DNS_RDATA_INIT; + isc_region_t r; + + dns_rdataset_current(rdataset, &rdata); + dns_rdata_toregion(&rdata, &r); + INSIST(r.length <= 0xffffU); + dlen = (isc_uint16_t)r.length; + + /* + * Copy the rdata into the buffer. If the buffer is too small, + * grow it. This should be rare, so we'll simply restart the + * entire procedure (or should we copy the old data and + * continue?). + */ + if (isc_buffer_availablelength(buffer) < + sizeof(dlen) + r.length) { + int newlength; + void *newmem; + + newlength = buffer->length * 2; + newmem = isc_mem_get(mctx, newlength); + if (newmem == NULL) + return (ISC_R_NOMEMORY); + isc_mem_put(mctx, buffer->base, buffer->length); + isc_buffer_init(buffer, newmem, newlength); + goto restart; + } + isc_buffer_putuint16(buffer, dlen); + isc_buffer_copyregion(buffer, &r); + totallen += sizeof(dlen) + r.length; + + result = dns_rdataset_next(rdataset); + } while (result == ISC_R_SUCCESS); + + if (result != ISC_R_NOMORE) + return (result); + + /* + * Fill in the total length field. + * XXX: this is a bit tricky. Since we have already "used" the space + * for the total length in the buffer, we first remember the entire + * buffer length in the region, "rewind", and then write the value. + */ + isc_buffer_usedregion(buffer, &r); + isc_buffer_clear(buffer); + isc_buffer_putuint32(buffer, totallen); + INSIST(isc_buffer_usedlength(buffer) < totallen); + + /* + * Write the buffer contents to the raw master file. + */ + result = isc_stdio_write(r.base, 1, (size_t)r.length, f, NULL); + + if (result != ISC_R_SUCCESS) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "raw master file write failed: %s", + isc_result_totext(result)); + return (result); + } + + return (result); +} + +static isc_result_t +dump_rdatasets_raw(isc_mem_t *mctx, dns_name_t *name, + dns_rdatasetiter_t *rdsiter, dns_totext_ctx_t *ctx, + isc_buffer_t *buffer, FILE *f) +{ + isc_result_t result; + dns_rdataset_t rdataset; + + for (result = dns_rdatasetiter_first(rdsiter); + result == ISC_R_SUCCESS; + result = dns_rdatasetiter_next(rdsiter)) { + + dns_rdataset_init(&rdataset); + dns_rdatasetiter_current(rdsiter, &rdataset); + + if (rdataset.type == 0 && + (ctx->style.flags & DNS_STYLEFLAG_NCACHE) == 0) { + /* Omit negative cache entries */ + } else { + result = dump_rdataset_raw(mctx, name, &rdataset, + buffer, f); + } + dns_rdataset_disassociate(&rdataset); + } + + if (result == ISC_R_NOMORE) + result = ISC_R_SUCCESS; + + return (result); +} /* * Initial size of text conversion buffer. The buffer is used @@ -856,7 +1007,7 @@ dump_rdatasets(isc_mem_t *mctx, dns_name_t *name, dns_rdatasetiter_t *rdsiter, * * When converting rdatasets, it is dynamically resized, but * when converting origins, timestamps, etc it is not. Therefore, - * the initial size must large enough to hold the longest possible + * the initial size must large enough to hold the longest possible * text representation of any domain name (for $ORIGIN). */ static const int initial_buffer_length = 1200; @@ -1021,7 +1172,8 @@ task_send(dns_dumpctx_t *dctx) { static isc_result_t dumpctx_create(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version, - const dns_master_style_t *style, FILE *f, dns_dumpctx_t **dctxp) + const dns_master_style_t *style, FILE *f, dns_dumpctx_t **dctxp, + dns_masterformat_t format) { dns_dumpctx_t *dctx; isc_result_t result; @@ -1044,6 +1196,19 @@ dumpctx_create(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version, dctx->canceled = ISC_FALSE; dctx->file = NULL; dctx->tmpfile = NULL; + dctx->format = format; + + switch (format) { + case dns_masterformat_text: + dctx->dumpsets = dump_rdatasets_text; + break; + case dns_masterformat_raw: + dctx->dumpsets = dump_rdatasets_raw; + break; + default: + INSIST(0); + break; + } result = totext_ctx_init(style, &dctx->tctx); if (result != ISC_R_SUCCESS) { @@ -1057,8 +1222,11 @@ dumpctx_create(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version, dctx->do_date = dns_db_iscache(dctx->db); - relative = ((dctx->tctx.style.flags & DNS_STYLEFLAG_REL_OWNER) != 0) ? - ISC_TRUE : ISC_FALSE; + if (dctx->format == dns_masterformat_text && + (dctx->tctx.style.flags & DNS_STYLEFLAG_REL_OWNER) != 0) { + relative = ISC_TRUE; + } else + relative = ISC_FALSE; result = dns_db_createiterator(dctx->db, relative, &dctx->dbiter); if (result != ISC_R_SUCCESS) goto cleanup; @@ -1095,6 +1263,9 @@ dumptostreaminc(dns_dumpctx_t *dctx) { dns_name_t *name; dns_fixedname_t fixname; unsigned int nodes; + dns_masterrawheader_t rawheader; + isc_uint32_t now32; + isc_time_t start; bufmem = isc_mem_get(dctx->mctx, initial_buffer_length); if (bufmem == NULL) @@ -1106,26 +1277,68 @@ dumptostreaminc(dns_dumpctx_t *dctx) { name = dns_fixedname_name(&fixname); if (dctx->first) { - /* - * If the database has cache semantics, output an RFC2540 - * $DATE directive so that the TTLs can be adjusted when - * it is reloaded. For zones it is not really needed, and - * it would make the file incompatible with pre-RFC2540 - * software, so we omit it in the zone case. - */ - if (dctx->do_date) { - result = dns_time32_totext(dctx->now, &buffer); - RUNTIME_CHECK(result == ISC_R_SUCCESS); - isc_buffer_usedregion(&buffer, &r); - fprintf(dctx->f, "$DATE %.*s\n", - (int) r.length, (char *) r.base); + switch (dctx->format) { + case dns_masterformat_text: + /* + * If the database has cache semantics, output an + * RFC2540 $DATE directive so that the TTLs can be + * adjusted when it is reloaded. For zones it is not + * really needed, and it would make the file + * incompatible with pre-RFC2540 software, so we omit + * it in the zone case. + */ + if (dctx->do_date) { + result = dns_time32_totext(dctx->now, &buffer); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + isc_buffer_usedregion(&buffer, &r); + fprintf(dctx->f, "$DATE %.*s\n", + (int) r.length, (char *) r.base); + } + break; + case dns_masterformat_raw: + r.base = (unsigned char *)&rawheader; + r.length = sizeof(rawheader); + isc_buffer_region(&buffer, &r); + isc_buffer_putuint32(&buffer, dns_masterformat_raw); + isc_buffer_putuint32(&buffer, DNS_RAWFORMAT_VERSION); + if (sizeof(now32) != sizeof(dctx->now)) { + /* + * We assume isc_stdtime_t is a 32-bit integer, + * which should be the case on most cases. + * If it turns out to be uncommon, we'll need + * to bump the version number and revise the + * header format. + */ + isc_log_write(dns_lctx, + ISC_LOGCATEGORY_GENERAL, + DNS_LOGMODULE_MASTERDUMP, + ISC_LOG_INFO, + "dumping master file in raw " + "format: stdtime is not 32bits"); + now32 = 0; + } else + now32 = dctx->now; + isc_buffer_putuint32(&buffer, now32); + INSIST(isc_buffer_usedlength(&buffer) <= + sizeof(rawheader)); + result = isc_stdio_write(buffer.base, 1, + isc_buffer_usedlength(&buffer), + dctx->f, NULL); + if (result != ISC_R_SUCCESS) + return (result); + isc_buffer_clear(&buffer); + break; + default: + INSIST(0); } + result = dns_dbiterator_first(dctx->dbiter); dctx->first = ISC_FALSE; } else result = ISC_R_SUCCESS; nodes = dctx->nodes; + isc_time_now(&start); while (result == ISC_R_SUCCESS && (dctx->nodes == 0 || nodes--)) { dns_rdatasetiter_t *rdsiter = NULL; dns_dbnode_t *node = NULL; @@ -1148,8 +1361,8 @@ dumptostreaminc(dns_dumpctx_t *dctx) { dns_db_detachnode(dctx->db, &node); goto fail; } - result = dump_rdatasets(dctx->mctx, name, rdsiter, &dctx->tctx, - &buffer, dctx->f); + result = (dctx->dumpsets)(dctx->mctx, name, rdsiter, + &dctx->tctx, &buffer, dctx->f); dns_rdatasetiter_destroy(&rdsiter); if (result != ISC_R_SUCCESS) { dns_db_detachnode(dctx->db, &node); @@ -1159,7 +1372,46 @@ dumptostreaminc(dns_dumpctx_t *dctx) { result = dns_dbiterator_next(dctx->dbiter); } + /* + * Work out how many nodes can be written in the time between + * two requests to the nameserver. Smooth the resulting number and + * use it as a estimate for the number of nodes to be written in the + * next iteration. + */ if (dctx->nodes != 0 && result == ISC_R_SUCCESS) { + unsigned int pps = dns_pps; /* packets per second */ + unsigned int interval; + isc_uint64_t usecs; + isc_time_t end; + + isc_time_now(&end); + if (pps < 100) + pps = 100; + interval = 1000000 / pps; /* interval in usecs */ + if (interval == 0) + interval = 1; + usecs = isc_time_microdiff(&end, &start); + if (usecs == 0) { + dctx->nodes = dctx->nodes * 2; + if (dctx->nodes > 1000) + dctx->nodes = 1000; + } else { + nodes = dctx->nodes * interval; + nodes /= (unsigned int)usecs; + if (nodes == 0) + nodes = 1; + else if (nodes > 1000) + nodes = 1000; + + /* Smooth and assign. */ + dctx->nodes = (nodes + dctx->nodes * 7) / 8; + + isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL, + DNS_LOGMODULE_MASTERDUMP, + ISC_LOG_DEBUG(1), + "dumptostreaminc(%p) new nodes -> %d\n", + dctx, dctx->nodes); + } result = dns_dbiterator_pause(dctx->dbiter); RUNTIME_CHECK(result == ISC_R_SUCCESS); result = DNS_R_CONTINUE; @@ -1185,7 +1437,8 @@ dns_master_dumptostreaminc(isc_mem_t *mctx, dns_db_t *db, REQUIRE(f != NULL); REQUIRE(done != NULL); - result = dumpctx_create(mctx, db, version, style, f, &dctx); + result = dumpctx_create(mctx, db, version, style, f, &dctx, + dns_masterformat_text); if (result != ISC_R_SUCCESS) return (result); isc_task_attach(task, &dctx->task); @@ -1212,10 +1465,20 @@ dns_master_dumptostream(isc_mem_t *mctx, dns_db_t *db, const dns_master_style_t *style, FILE *f) { + return (dns_master_dumptostream2(mctx, db, version, style, + dns_masterformat_text, f)); +} + +isc_result_t +dns_master_dumptostream2(isc_mem_t *mctx, dns_db_t *db, + dns_dbversion_t *version, + const dns_master_style_t *style, + dns_masterformat_t format, FILE *f) +{ dns_dumpctx_t *dctx = NULL; isc_result_t result; - result = dumpctx_create(mctx, db, version, style, f, &dctx); + result = dumpctx_create(mctx, db, version, style, f, &dctx, format); if (result != ISC_R_SUCCESS) return (result); @@ -1264,6 +1527,17 @@ dns_master_dumpinc(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version, isc_task_t *task, dns_dumpdonefunc_t done, void *done_arg, dns_dumpctx_t **dctxp) { + return (dns_master_dumpinc2(mctx, db, version, style, filename, task, + done, done_arg, dctxp, + dns_masterformat_text)); +} + +isc_result_t +dns_master_dumpinc2(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version, + const dns_master_style_t *style, const char *filename, + isc_task_t *task, dns_dumpdonefunc_t done, void *done_arg, + dns_dumpctx_t **dctxp, dns_masterformat_t format) +{ FILE *f = NULL; isc_result_t result; char *tempname = NULL; @@ -1278,7 +1552,7 @@ dns_master_dumpinc(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version, if (result != ISC_R_SUCCESS) goto cleanup; - result = dumpctx_create(mctx, db, version, style, f, &dctx); + result = dumpctx_create(mctx, db, version, style, f, &dctx, format); if (result != ISC_R_SUCCESS) { (void)isc_stdio_close(f); (void)isc_file_remove(tempname); @@ -1314,6 +1588,15 @@ isc_result_t dns_master_dump(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version, const dns_master_style_t *style, const char *filename) { + return (dns_master_dump2(mctx, db, version, style, filename, + dns_masterformat_text)); +} + +isc_result_t +dns_master_dump2(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version, + const dns_master_style_t *style, const char *filename, + dns_masterformat_t format) +{ FILE *f = NULL; isc_result_t result; char *tempname; @@ -1323,7 +1606,7 @@ dns_master_dump(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version, if (result != ISC_R_SUCCESS) return (result); - result = dumpctx_create(mctx, db, version, style, f, &dctx); + result = dumpctx_create(mctx, db, version, style, f, &dctx, format); if (result != ISC_R_SUCCESS) goto cleanup; @@ -1340,6 +1623,7 @@ dns_master_dump(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version, /* * Dump a database node into a master file. + * XXX: this function assumes the text format. */ isc_result_t dns_master_dumpnodetostream(isc_mem_t *mctx, dns_db_t *db, @@ -1373,7 +1657,7 @@ dns_master_dumpnodetostream(isc_mem_t *mctx, dns_db_t *db, result = dns_db_allrdatasets(db, node, version, now, &rdsiter); if (result != ISC_R_SUCCESS) goto failure; - result = dump_rdatasets(mctx, name, rdsiter, &ctx, &buffer, f); + result = dump_rdatasets_text(mctx, name, rdsiter, &ctx, &buffer, f); if (result != ISC_R_SUCCESS) goto failure; dns_rdatasetiter_destroy(&rdsiter); @@ -1452,4 +1736,3 @@ dns_master_styledestroy(dns_master_style_t **stylep, isc_mem_t *mctx) { *stylep = NULL; isc_mem_put(mctx, style, sizeof(*style)); } - |