📄 masterdump.c
字号:
UNEXPECTED_ERROR(__FILE__, __LINE__, "could not set master file style"); return (ISC_R_UNEXPECTED); } /* * The caller might want to give us an empty owner * name (e.g. if they are outputting into a master * file and this rdataset has the same name as the * previous one.) */ if (dns_name_countlabels(owner_name) == 0) owner_name = NULL; if (question) return (question_totext(rdataset, owner_name, &ctx, omit_final_dot, target)); else return (rdataset_totext(rdataset, owner_name, &ctx, omit_final_dot, target));}isc_result_tdns_master_rdatasettotext(dns_name_t *owner_name, dns_rdataset_t *rdataset, const dns_master_style_t *style, isc_buffer_t *target){ dns_totext_ctx_t ctx; isc_result_t result; result = totext_ctx_init(style, &ctx); if (result != ISC_R_SUCCESS) { UNEXPECTED_ERROR(__FILE__, __LINE__, "could not set master file style"); return (ISC_R_UNEXPECTED); } return (rdataset_totext(rdataset, owner_name, &ctx, ISC_FALSE, target));}isc_result_tdns_master_questiontotext(dns_name_t *owner_name, dns_rdataset_t *rdataset, const dns_master_style_t *style, isc_buffer_t *target){ dns_totext_ctx_t ctx; isc_result_t result; result = totext_ctx_init(style, &ctx); if (result != ISC_R_SUCCESS) { UNEXPECTED_ERROR(__FILE__, __LINE__, "could not set master file style"); return (ISC_R_UNEXPECTED); } return (question_totext(rdataset, owner_name, &ctx, ISC_FALSE, target));}/* * Print an rdataset. 'buffer' is a scratch buffer, which must have been * dynamically allocated by the caller. It must be large enough to * hold the result from dns_ttl_totext(). If more than that is needed, * the buffer will be grown automatically. */static isc_result_tdump_rdataset(isc_mem_t *mctx, dns_name_t *name, dns_rdataset_t *rdataset, dns_totext_ctx_t *ctx, isc_buffer_t *buffer, FILE *f){ isc_region_t r; isc_result_t result; REQUIRE(buffer->length > 0); /* * Output a $TTL directive if needed. */ if ((ctx->style.flags & DNS_STYLEFLAG_TTL) != 0) { if (ctx->current_ttl_valid == ISC_FALSE || ctx->current_ttl != rdataset->ttl) { if ((ctx->style.flags & DNS_STYLEFLAG_COMMENT) != 0) { isc_buffer_clear(buffer); result = dns_ttl_totext(rdataset->ttl, ISC_TRUE, buffer); INSIST(result == ISC_R_SUCCESS); isc_buffer_usedregion(buffer, &r); fprintf(f, "$TTL %u\t; %.*s\n", rdataset->ttl, (int) r.length, (char *) r.base); } else { fprintf(f, "$TTL %u\n", rdataset->ttl); } ctx->current_ttl = rdataset->ttl; ctx->current_ttl_valid = ISC_TRUE; } } isc_buffer_clear(buffer); /* * Generate the text representation of the rdataset into * the buffer. If the buffer is too small, grow it. */ for (;;) { int newlength; void *newmem; result = rdataset_totext(rdataset, name, ctx, ISC_FALSE, buffer); if (result != ISC_R_NOSPACE) break; 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); } if (result != ISC_R_SUCCESS) return (result); /* * Write the buffer contents to the master file. */ isc_buffer_usedregion(buffer, &r); result = isc_stdio_write(r.base, 1, (size_t)r.length, f, NULL); if (result != ISC_R_SUCCESS) { UNEXPECTED_ERROR(__FILE__, __LINE__, "master file write failed: %s", isc_result_totext(result)); return (result); } return (ISC_R_SUCCESS);}/* * Define the order in which rdatasets should be printed in zone * files. We will print SOA and NS records before others, SIGs * immediately following the things they sign, and order everything * else by RR number. This is all just for aesthetics and * compatibility with buggy software that expects the SOA to be first; * the DNS specifications allow any order. */static intdump_order(const dns_rdataset_t *rds) { int t; int sig; if (rds->type == dns_rdatatype_rrsig) { t = rds->covers; sig = 1; } else { t = rds->type; sig = 0; } switch (t) { case dns_rdatatype_soa: t = 0; break; case dns_rdatatype_ns: t = 1; break; default: t += 2; break; } return (t << 1) + sig;}static intdump_order_compare(const void *a, const void *b) { return (dump_order(*((const dns_rdataset_t * const *) a)) - dump_order(*((const dns_rdataset_t * const *) b)));}/* * Dump all the rdatasets of a domain name to a master file. We make * a "best effort" attempt to sort the RRsets in a nice order, but if * there are more than MAXSORT RRsets, we punt and only sort them in * groups of MAXSORT. This is not expected to ever happen in practice * since much less than 64 RR types have been registered with the * IANA, so far, and the output will be correct (though not * aesthetically pleasing) even if it does happen. */#define MAXSORT 64static const char *trustnames[] = { "none", "pending", "additional", "glue", "answer", "authauthority", "authanswer", "secure", "local" /* aka ultimate */};static isc_result_tdump_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; dns_rdataset_t rdatasets[MAXSORT]; dns_rdataset_t *sorted[MAXSORT]; int i, n; itresult = dns_rdatasetiter_first(rdsiter); dumpresult = ISC_R_SUCCESS; if (itresult == ISC_R_SUCCESS && ctx->neworigin != NULL) { isc_buffer_clear(buffer); itresult = dns_name_totext(ctx->neworigin, ISC_FALSE, buffer); RUNTIME_CHECK(itresult == ISC_R_SUCCESS); isc_buffer_usedregion(buffer, &r); fprintf(f, "$ORIGIN %.*s\n", (int) r.length, (char *) r.base); ctx->neworigin = NULL; } again: for (i = 0; itresult == ISC_R_SUCCESS && i < MAXSORT; itresult = dns_rdatasetiter_next(rdsiter), i++) { dns_rdataset_init(&rdatasets[i]); dns_rdatasetiter_current(rdsiter, &rdatasets[i]); sorted[i] = &rdatasets[i]; } n = i; INSIST(n <= MAXSORT); qsort(sorted, n, sizeof(sorted[0]), dump_order_compare); for (i = 0; i < n; i++) { dns_rdataset_t *rds = sorted[i]; if (ctx->style.flags & DNS_STYLEFLAG_TRUST) { unsigned int trust = rds->trust; INSIST(trust < (sizeof(trustnames) / sizeof(trustnames[0]))); fprintf(f, "; %s\n", trustnames[trust]); } if (rds->type == 0 && (ctx->style.flags & DNS_STYLEFLAG_NCACHE) == 0) { /* Omit negative cache entries */ } else { isc_result_t result = dump_rdataset(mctx, name, rds, ctx, buffer, f); if (result != ISC_R_SUCCESS) dumpresult = result; if ((ctx->style.flags & DNS_STYLEFLAG_OMIT_OWNER) != 0) name = NULL; } dns_rdataset_disassociate(rds); } if (dumpresult != ISC_R_SUCCESS) return (dumpresult); /* * If we got more data than could be sorted at once, * go handle the rest. */ if (itresult == ISC_R_SUCCESS) goto again; if (itresult == ISC_R_NOMORE) itresult = ISC_R_SUCCESS; return (itresult);}/* * Dump given RRsets in the "raw" format. */static isc_result_tdump_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_tdump_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 * for several purposes: converting origin names, rdatasets, * $DATE timestamps, and comment strings for $TTL directives. * * 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 * text representation of any domain name (for $ORIGIN). */static const int initial_buffer_length = 1200;static isc_result_tdumptostreaminc(dns_dumpctx_t *dctx);static voiddumpctx_destroy(dns_dumpctx_t *dctx) { dctx->magic = 0; DESTROYLOCK(&dctx->lock); if (dctx->version != NULL) dns_db_closeversion(dctx->db, &dctx->version, ISC_FALSE); dns_dbiterator_destroy(&dctx->dbiter); dns_db_detach(&dctx->db); if (dctx->task != NULL) isc_task_detach(&dctx->task); if (dctx->file != NULL) isc_mem_free(dctx->mctx, dctx->file); if (dctx->tmpfile != NULL) isc_mem_free(dctx->mctx, dctx->tmpfile); isc_mem_putanddetach(&dctx->mctx, dctx, sizeof(*dctx));}voiddns_dumpctx_attach(dns_dumpctx_t *source, dns_dumpctx_t **target) { REQUIRE(DNS_DCTX_VALID(source)); REQUIRE(target != NULL && *target == NULL); LOCK(&source->lock); INSIST(source->references > 0); source->references++; INSIST(source->references != 0); /* Overflow? */ UNLOCK(&source->lock); *target = source;}voiddns_dumpctx_detach(dns_dumpctx_t **dctxp) { dns_dumpctx_t *dctx; isc_boolean_t need_destroy = ISC_FALSE; REQUIRE(dctxp != NULL); dctx = *dctxp; REQUIRE(DNS_DCTX_VALID(dctx)); *dctxp = NULL; LOCK(&dctx->lock); INSIST(dctx->references != 0); dctx->references--; if (dctx->references == 0) need_destroy = ISC_TRUE; UNLOCK(&dctx->lock); if (need_destroy) dumpctx_destroy(dctx);}dns_dbversion_t *dns_dumpctx_version(dns_dumpctx_t *dctx) { REQUIRE(DNS_DCTX_VALID(dctx)); return (dctx->version);}dns_db_t *dns_dumpctx_db(dns_dumpctx_t *dctx) { REQUIRE(DNS_DCTX_VALID(dctx)); return (dctx->db);}voiddns_dumpctx_cancel(dns_dumpctx_t *dctx) { REQUIRE(DNS_DCTX_VALID(dctx)); LOCK(&dctx->lock); dctx->canceled = ISC_TRUE; UNLOCK(&dctx->lock);}static isc_result_tcloseandrename(FILE *f, isc_result_t result, const char *temp, const char *file){ isc_result_t tresult; isc_boolean_t logit = ISC_TF(result == ISC_R_SUCCESS); if (result == ISC_R_SUCCESS) result = isc_stdio_sync(f); if (result != ISC_R_SUCCESS && logit) { isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL, DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR, "dumping master file: %s: fsync: %s", temp, isc_result_totext(result)); logit = ISC_FALSE; } tresult = isc_stdio_close(f); if (result == ISC_R_SUCCESS) result = tresult; if (result != ISC_R_SUCCESS && logit) { isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL, DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR, "dumping master file: %s: fclose: %s", temp, isc_result_totext(result)); logit = ISC_FALSE; } if (result == ISC_R_SUCCESS) result = isc_file_rename(temp, file); else (void)isc_file_remove(temp); if (result != ISC_R_SUCCESS && logit) { isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL, DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR, "dumping master file: rename: %s: %s", file, isc_result_totext(result)); } return (result);}static voiddump_quantum(isc_task_t *task, isc_event_t *event) { isc_result_t result; isc_result_t tresult; dns_dumpctx_t *dctx; REQUIRE(event != NULL); dctx = event->ev_arg; REQUIRE(DNS_DCTX_VALID(dctx)); if (dctx->canceled) result = ISC_R_CANCELED; else result = dumptostreaminc(dctx); if (result == DNS_R_CONTINUE) { event->ev_arg = dctx; isc_task_send(task, &event); return; } if (dctx->file != NULL) { tresult = closeandrename(dctx->f, result, dctx->tmpfile, dctx->file); if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS) result = tresult; } (dctx->done)(dctx->done_arg, result); isc_event_free(&event); dns_dumpctx_detach(&dctx);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -