diff options
Diffstat (limited to 'src/knot/zone/zone-dump.c')
-rw-r--r-- | src/knot/zone/zone-dump.c | 236 |
1 files changed, 236 insertions, 0 deletions
diff --git a/src/knot/zone/zone-dump.c b/src/knot/zone/zone-dump.c new file mode 100644 index 0000000..41ec925 --- /dev/null +++ b/src/knot/zone/zone-dump.c @@ -0,0 +1,236 @@ +/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <inttypes.h> + +#include "knot/dnssec/zone-nsec.h" +#include "knot/zone/zone-dump.h" +#include "libknot/libknot.h" + +/*! \brief Size of auxiliary buffer. */ +#define DUMP_BUF_LEN (70 * 1024) + +/*! \brief Dump parameters. */ +typedef struct { + FILE *file; + char *buf; + size_t buflen; + uint64_t rr_count; + bool dump_rrsig; + bool dump_nsec; + const knot_dname_t *origin; + const knot_dump_style_t *style; + const char *first_comment; +} dump_params_t; + +static int apex_node_dump_text(zone_node_t *node, dump_params_t *params) +{ + knot_rrset_t soa = node_rrset(node, KNOT_RRTYPE_SOA); + + // Dump SOA record as a first. + if (!params->dump_nsec) { + int ret = knot_rrset_txt_dump(&soa, ¶ms->buf, ¶ms->buflen, + params->style); + if (ret < 0) { + return ret; + } + params->rr_count += soa.rrs.count; + fprintf(params->file, "%s", params->buf); + params->buf[0] = '\0'; + } + + // Dump other records. + for (uint16_t i = 0; i < node->rrset_count; i++) { + knot_rrset_t rrset = node_rrset_at(node, i); + switch (rrset.type) { + case KNOT_RRTYPE_NSEC: + continue; + case KNOT_RRTYPE_RRSIG: + continue; + case KNOT_RRTYPE_SOA: + continue; + default: + break; + } + + int ret = knot_rrset_txt_dump(&rrset, ¶ms->buf, ¶ms->buflen, + params->style); + if (ret < 0) { + return ret; + } + params->rr_count += rrset.rrs.count; + fprintf(params->file, "%s", params->buf); + params->buf[0] = '\0'; + } + + return KNOT_EOK; +} + +static int node_dump_text(zone_node_t *node, void *data) +{ + dump_params_t *params = (dump_params_t *)data; + + // Zone apex rrsets. + if (node->owner == params->origin && !params->dump_rrsig && + !params->dump_nsec) { + apex_node_dump_text(node, params); + return KNOT_EOK; + } + + // Dump non-apex rrsets. + for (uint16_t i = 0; i < node->rrset_count; i++) { + knot_rrset_t rrset = node_rrset_at(node, i); + switch (rrset.type) { + case KNOT_RRTYPE_RRSIG: + if (params->dump_rrsig) { + break; + } + continue; + case KNOT_RRTYPE_NSEC: + if (params->dump_nsec) { + break; + } + continue; + case KNOT_RRTYPE_NSEC3: + if (params->dump_nsec) { + break; + } + continue; + default: + if (params->dump_nsec || params->dump_rrsig) { + continue; + } + break; + } + + // Dump block comment if available. + if (params->first_comment != NULL) { + fprintf(params->file, "%s", params->first_comment); + params->first_comment = NULL; + } + + int ret = knot_rrset_txt_dump(&rrset, ¶ms->buf, ¶ms->buflen, + params->style); + if (ret < 0) { + return ret; + } + params->rr_count += rrset.rrs.count; + fprintf(params->file, "%s", params->buf); + params->buf[0] = '\0'; + } + + return KNOT_EOK; +} + +int zone_dump_text(zone_contents_t *zone, FILE *file, bool comments, const char *color) +{ + if (file == NULL) { + return KNOT_EINVAL; + } + + if (zone == NULL) { + return KNOT_EEMPTYZONE; + } + + // Allocate auxiliary buffer for dumping operations. + char *buf = malloc(DUMP_BUF_LEN); + if (buf == NULL) { + return KNOT_ENOMEM; + } + + if (comments) { + fprintf(file, ";; Zone dump (Knot DNS %s)\n", PACKAGE_VERSION); + } + + // Set structure with parameters. + knot_dump_style_t style = KNOT_DUMP_STYLE_DEFAULT; + style.color = color; + style.now = knot_time(); + dump_params_t params = { + .file = file, + .buf = buf, + .buflen = DUMP_BUF_LEN, + .rr_count = 0, + .origin = zone->apex->owner, + .style = &style, + .dump_rrsig = false, + .dump_nsec = false + }; + + // Dump standard zone records without RRSIGS. + int ret = zone_contents_apply(zone, node_dump_text, ¶ms); + if (ret != KNOT_EOK) { + free(params.buf); + return ret; + } + + // Dump RRSIG records if available. + params.dump_rrsig = true; + params.dump_nsec = false; + params.first_comment = comments ? ";; DNSSEC signatures\n" : NULL; + ret = zone_contents_apply(zone, node_dump_text, ¶ms); + if (ret != KNOT_EOK) { + free(params.buf); + return ret; + } + + // Dump NSEC chain if available. + params.dump_rrsig = false; + params.dump_nsec = true; + params.first_comment = comments ? ";; DNSSEC NSEC chain\n" : NULL; + ret = zone_contents_apply(zone, node_dump_text, ¶ms); + if (ret != KNOT_EOK) { + free(params.buf); + return ret; + } + + // Dump NSEC3 chain if available. + params.dump_rrsig = false; + params.dump_nsec = true; + params.first_comment = comments ? ";; DNSSEC NSEC3 chain\n" : NULL; + ret = zone_contents_nsec3_apply(zone, node_dump_text, ¶ms); + if (ret != KNOT_EOK) { + free(params.buf); + return ret; + } + + params.dump_rrsig = true; + params.dump_nsec = false; + params.first_comment = comments ? ";; DNSSEC NSEC3 signatures\n" : NULL; + ret = zone_contents_nsec3_apply(zone, node_dump_text, ¶ms); + if (ret != KNOT_EOK) { + free(params.buf); + return ret; + } + + if (comments) { + // Create formatted date-time string. + time_t now = time(NULL); + struct tm tm; + localtime_r(&now, &tm); + char date[64]; + strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S %Z", &tm); + + // Dump trailing statistics. + fprintf(file, ";; Written %"PRIu64" records\n" + ";; Time %s\n", + params.rr_count, date); + } + + free(params.buf); // params.buf may be != buf because of knot_rrset_txt_dump_dynamic() + + return KNOT_EOK; +} |