From 63c88f4a04154c00b7f63a3a3e7274b9cfcfd160 Mon Sep 17 00:00:00 2001 From: Diego Fronza Date: Thu, 7 Nov 2019 15:28:42 -0300 Subject: [PATCH 1/2] Enable named-checkzone and named-compilezone to take input from stdin If a filename (the last argument) is not provided for named-checkzone or named-compilezone, or if it is a single dash "-" character, zone data will be read from stdin. Example of invocation: cat /etc/zone_name.db | named-compilezone -f text -F raw \ -o zone_name.raw zone_name --- bin/check/check-tool.c | 9 +++++-- bin/check/named-checkzone.c | 20 +++++++++++--- lib/dns/include/dns/zone.h | 17 ++++++++++++ lib/dns/win32/libdns.def.in | 1 + lib/dns/zone.c | 52 +++++++++++++++++++++++++++++++------ 5 files changed, 85 insertions(+), 14 deletions(-) diff --git a/bin/check/check-tool.c b/bin/check/check-tool.c index 5f00121d26..38387b172b 100644 --- a/bin/check/check-tool.c +++ b/bin/check/check-tool.c @@ -695,8 +695,13 @@ load_zone(isc_mem_t *mctx, const char *zonename, const char *filename, CHECK(dns_name_fromtext(origin, &buffer, dns_rootname, 0, NULL)); CHECK(dns_zone_setorigin(zone, origin)); dns_zone_setdbtype(zone, 1, (const char *const *)dbtype); - CHECK(dns_zone_setfile(zone, filename, fileformat, - &dns_master_style_default)); + if (strcmp(filename, "-") == 0) { + CHECK(dns_zone_setstream(zone, stdin, fileformat, + &dns_master_style_default)); + } else { + CHECK(dns_zone_setfile(zone, filename, fileformat, + &dns_master_style_default)); + } if (journal != NULL) { CHECK(dns_zone_setjournal(zone, journal)); } diff --git a/bin/check/named-checkzone.c b/bin/check/named-checkzone.c index e50f84e0d2..4b15bd02b2 100644 --- a/bin/check/named-checkzone.c +++ b/bin/check/named-checkzone.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -76,7 +77,7 @@ usage(void) { "[-i (full|full-sibling|local|local-sibling|none)] " "[-M (ignore|warn|fail)] [-S (ignore|warn|fail)] " "[-W (ignore|warn)] " - "%s zonename filename\n", + "%s zonename [ (filename|-) ]\n", prog_name, progmode == progmode_check ? "[-o filename]" : "-o filename"); exit(1); @@ -94,7 +95,7 @@ int main(int argc, char **argv) { int c; char *origin = NULL; - char *filename = NULL; + const char *filename = NULL; isc_log_t *lctx = NULL; isc_result_t result; char classname_in[] = "IN"; @@ -512,7 +513,8 @@ main(int argc, char **argv) { logdump = false; } - if (isc_commandline_index + 2 != argc) { + if (argc - isc_commandline_index < 1 || + argc - isc_commandline_index > 2) { usage(); } @@ -529,7 +531,16 @@ main(int argc, char **argv) { dns_result_register(); origin = argv[isc_commandline_index++]; - filename = argv[isc_commandline_index++]; + + if (isc_commandline_index == argc) { + /* "-" will be interpreted as stdin */ + filename = "-"; + } else { + filename = argv[isc_commandline_index]; + } + + isc_commandline_index++; + result = load_zone(mctx, origin, filename, inputformat, classname, maxttl, &zone); @@ -563,5 +574,6 @@ main(int argc, char **argv) { #ifdef _WIN32 DestroySockets(); #endif /* ifdef _WIN32 */ + return ((result == ISC_R_SUCCESS) ? 0 : 1); } diff --git a/lib/dns/include/dns/zone.h b/lib/dns/include/dns/zone.h index f209e95bf0..80ccb22979 100644 --- a/lib/dns/include/dns/zone.h +++ b/lib/dns/include/dns/zone.h @@ -295,6 +295,23 @@ dns_zone_getfile(dns_zone_t *zone); *\li Pointer to null-terminated file name, or NULL. */ +isc_result_t +dns_zone_setstream(dns_zone_t *zone, const FILE *stream, + dns_masterformat_t format, const dns_master_style_t *style); +/*%< + * Sets the source stream from which the zone will load its database. + * + * Requires: + *\li 'zone' to be a valid zone. + *\li 'stream' to be a valid and open FILE *. + *\li 'zone->masterfile' to be NULL, since we should load data either from + * 'stream' or from a master file, but not both. + * + * Returns: + *\li #ISC_R_NOMEMORY + *\li #ISC_R_SUCCESS + */ + void dns_zone_setmaxrecords(dns_zone_t *zone, uint32_t records); /*%< diff --git a/lib/dns/win32/libdns.def.in b/lib/dns/win32/libdns.def.in index 83d750cb03..38ee1a123a 100644 --- a/lib/dns/win32/libdns.def.in +++ b/lib/dns/win32/libdns.def.in @@ -1351,6 +1351,7 @@ dns_zone_setssutable dns_zone_setstatistics dns_zone_setstatlevel dns_zone_setstats +dns_zone_setstream dns_zone_settask dns_zone_settype dns_zone_setupdateacl diff --git a/lib/dns/zone.c b/lib/dns/zone.c index a7d11e8192..b0161c3311 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -214,6 +214,7 @@ struct dns_zone { isc_refcount_t irefs; dns_name_t origin; char *masterfile; + const FILE *stream; /* loading from a stream? */ ISC_LIST(dns_include_t) includes; /* Include files */ ISC_LIST(dns_include_t) newincludes; /* Loading */ unsigned int nincludes; @@ -986,6 +987,7 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) { zone->strrdclass = NULL; zone->strviewname = NULL; zone->masterfile = NULL; + zone->stream = NULL; ISC_LIST_INIT(zone->includes); ISC_LIST_INIT(zone->newincludes); zone->nincludes = 0; @@ -1672,6 +1674,7 @@ dns_zone_setfile(dns_zone_t *zone, const char *file, dns_masterformat_t format, isc_result_t result = ISC_R_SUCCESS; REQUIRE(DNS_ZONE_VALID(zone)); + REQUIRE(zone->stream == NULL); LOCK_ZONE(zone); result = dns_zone_setstring(zone, &zone->masterfile, file); @@ -1694,6 +1697,27 @@ dns_zone_getfile(dns_zone_t *zone) { return (zone->masterfile); } +isc_result_t +dns_zone_setstream(dns_zone_t *zone, const FILE *stream, + dns_masterformat_t format, const dns_master_style_t *style) { + isc_result_t result = ISC_R_SUCCESS; + + REQUIRE(DNS_ZONE_VALID(zone)); + REQUIRE(stream != NULL); + REQUIRE(zone->masterfile == NULL); + + LOCK_ZONE(zone); + zone->stream = stream; + zone->masterformat = format; + if (format == dns_masterformat_text) { + zone->masterstyle = style; + } + result = default_journal(zone); + UNLOCK_ZONE(zone); + + return (result); +} + dns_ttl_t dns_zone_getmaxttl(dns_zone_t *zone) { REQUIRE(DNS_ZONE_VALID(zone)); @@ -2175,8 +2199,10 @@ zone_load(dns_zone_t *zone, unsigned int flags, bool locked) { (zone->type == dns_zone_redirect && zone->masters != NULL)) && rbt) { - if (zone->masterfile == NULL || - !isc_file_exists(zone->masterfile)) { + if (zone->stream == NULL && + (zone->masterfile == NULL || + !isc_file_exists(zone->masterfile))) + { if (zone->masterfile != NULL) { dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD, ISC_LOG_DEBUG(1), @@ -2221,7 +2247,7 @@ zone_load(dns_zone_t *zone, unsigned int flags, bool locked) { } if (!dns_db_ispersistent(db)) { - if (zone->masterfile != NULL) { + if (zone->masterfile != NULL || zone->stream != NULL) { result = zone_startload(db, zone, loadtime); } else { result = DNS_R_NOMASTERFILE; @@ -2643,11 +2669,21 @@ zone_startload(dns_db_t *db, dns_zone_t *zone, isc_time_t loadtime) { zone_idetach(&callbacks.zone); return (result); } - result = dns_master_loadfile( - zone->masterfile, &zone->origin, &zone->origin, - zone->rdclass, options, 0, &callbacks, - zone_registerinclude, zone, zone->mctx, - zone->masterformat, zone->maxttl); + + if (zone->stream != NULL) { + FILE *stream = NULL; + DE_CONST(zone->stream, stream); + result = dns_master_loadstream( + stream, &zone->origin, &zone->origin, + zone->rdclass, options, &callbacks, zone->mctx); + } else { + result = dns_master_loadfile( + zone->masterfile, &zone->origin, &zone->origin, + zone->rdclass, options, 0, &callbacks, + zone_registerinclude, zone, zone->mctx, + zone->masterformat, zone->maxttl); + } + tresult = dns_db_endload(db, &callbacks); if (result == ISC_R_SUCCESS) { result = tresult; From a3453c257b884f56ce32acc9a1290449d18399af Mon Sep 17 00:00:00 2001 From: Diego Fronza Date: Fri, 31 Jan 2020 16:52:43 -0300 Subject: [PATCH 2/2] Added system test Added a system test which ensures that named-checkzone works when taking input data from stdin. --- bin/tests/system/checkzone/clean.sh | 1 + bin/tests/system/checkzone/tests.sh | 22 ++++++++++++++++++++++ bin/tests/system/checkzone/zones/zone1.db | 10 ++++++++++ 3 files changed, 33 insertions(+) create mode 100644 bin/tests/system/checkzone/zones/zone1.db diff --git a/bin/tests/system/checkzone/clean.sh b/bin/tests/system/checkzone/clean.sh index 95d3caaaae..8b50fdba5c 100644 --- a/bin/tests/system/checkzone/clean.sh +++ b/bin/tests/system/checkzone/clean.sh @@ -9,3 +9,4 @@ rm -f test.* good1.db.map good1.db.raw named-compilezone rm -f ns*/named.lock +rm -f zones/zone1_*.txt diff --git a/bin/tests/system/checkzone/tests.sh b/bin/tests/system/checkzone/tests.sh index 022c3111cd..0ba9d5dc46 100644 --- a/bin/tests/system/checkzone/tests.sh +++ b/bin/tests/system/checkzone/tests.sh @@ -182,5 +182,27 @@ n=`expr $n + 1` if [ $ret != 0 ]; then echo_i "failed"; fi status=`expr $status + $ret` +n=`expr $n + 1` +echo_i "checking that named-compilezone works when reading input from stdin ($n)" +ret=0 +# Step 1: take raw input from stdin and convert it to text/relative format. +# Last argument "-" is optional, but it says more explicitly that we're reading from stdin. +cat zones/zone1.db | ./named-compilezone -f text -F text -s relative \ + -o zones/zone1_stdin.txt zone1.com - > /dev/null || ret=1 +status=`expr $status + $ret` + +ret=0 +# Step 2: take raw input from file and convert it to text format. +./named-compilezone -f text -F text -s relative -o zones/zone1_file.txt \ + zone1.com zones/zone1.db > /dev/null || ret=1 +status=`expr $status + $ret` + +ret=0 +# Step 3: Ensure that output conversion from stdin is the same as the output conversion from a file. +$DIFF zones/zone1_file.txt zones/zone1_stdin.txt >/dev/null 2>&1 || ret=1 +status=`expr $status + $ret` + +if [ $ret != 0 ]; then echo_i "failed"; fi + echo_i "exit status: $status" [ $status -eq 0 ] || exit 1 diff --git a/bin/tests/system/checkzone/zones/zone1.db b/bin/tests/system/checkzone/zones/zone1.db new file mode 100644 index 0000000000..df9a018b36 --- /dev/null +++ b/bin/tests/system/checkzone/zones/zone1.db @@ -0,0 +1,10 @@ +zone1.com. 86400 IN SOA dns1.zone1.com. hostmaster.zone1.com. 2001062501 21600 3600 604800 86400 +zone1.com. 86400 IN NS dns1.zone1.com. +zone1.com. 86400 IN NS dns2.zone1.com. +zone1.com. 86400 IN A 10.53.0.1 +zone1.com. 86400 IN MX 10 mail1.zone1.com. +zone1.com. 86400 IN MX 20 mail2.zone1.com. +dns1.zone1.com. 86400 IN A 10.53.0.1 +dns2.zone1.com. 86400 IN A 10.53.0.2 +mail1.zone1.com. 86400 IN A 10.53.0.1 +mail2.zone1.com. 86400 IN A 10.53.0.2