summaryrefslogtreecommitdiff
path: root/usr.sbin/nsd/zonec.c
diff options
context:
space:
mode:
authorStuart Henderson <sthen@cvs.openbsd.org>2013-11-26 12:53:59 +0000
committerStuart Henderson <sthen@cvs.openbsd.org>2013-11-26 12:53:59 +0000
commit2b032a0b5d2a9ce63e42ebe314ff5d91039545e3 (patch)
tree7a88e34592d2253623e877a7b7704b0a6246210c /usr.sbin/nsd/zonec.c
parentb665eb4cb1ea56ccad7fee700f05c85dec76e702 (diff)
merge conflicts
Diffstat (limited to 'usr.sbin/nsd/zonec.c')
-rw-r--r--usr.sbin/nsd/zonec.c497
1 files changed, 170 insertions, 327 deletions
diff --git a/usr.sbin/nsd/zonec.c b/usr.sbin/nsd/zonec.c
index 21d437081cc..ca06832e237 100644
--- a/usr.sbin/nsd/zonec.c
+++ b/usr.sbin/nsd/zonec.c
@@ -1,7 +1,7 @@
/*
* zonec.c -- zone compiler.
*
- * Copyright (c) 2001-2011, NLnet Labs. All rights reserved.
+ * Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
*
* See LICENSE for the license.
*
@@ -22,6 +22,9 @@
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
#include <netinet/in.h>
@@ -37,6 +40,7 @@
#include "rdata.h"
#include "region-allocator.h"
#include "util.h"
+#include "zparser.h"
#include "options.h"
#include "nsec3.h"
@@ -46,16 +50,7 @@
const dname_type *error_dname;
domain_type *error_domain;
-/* The database file... */
-static const char *dbfile = 0;
-
-/* Some global flags... */
-static int vflag = 0;
-/* if -v then print progress each 'progress' RRs */
-static int progress = 10000;
-
-/* Total errors counter */
-static long int totalerrors = 0;
+static time_t startzonec = 0;
static long int totalrrs = 0;
extern uint8_t nsecbits[NSEC_WINDOW_COUNT][NSEC_WINDOW_BITS_SIZE];
@@ -385,6 +380,7 @@ zparser_conv_aaaa(region_type *region, const char *text)
return r;
}
+
uint16_t *
zparser_conv_ilnp64(region_type *region, const char *text)
{
@@ -1151,6 +1147,7 @@ zadd_rdata_txt_clean_wireformat()
if ((tmp_data = (uint16_t *) region_alloc(parser->region,
rd->data[0] + 2)) != NULL) {
memcpy(tmp_data, rd->data, rd->data[0] + 2);
+ /* rd->data of u16+65535 freed when rr_region is freed */
rd->data = tmp_data;
}
else {
@@ -1168,6 +1165,7 @@ zadd_rdata_domain(domain_type *domain)
} else {
parser->current_rr.rdatas[parser->current_rr.rdata_count].domain
= domain;
+ domain->usage ++; /* new reference to domain */
++parser->current_rr.rdata_count;
}
}
@@ -1238,6 +1236,14 @@ zrdatacmp(uint16_t type, rr_type *a, rr_type *b)
{
return 1;
}
+ } else if(rdata_atom_is_literal_domain(type, i)) {
+ if (rdata_atom_size(a->rdatas[i])
+ != rdata_atom_size(b->rdatas[i]))
+ return 1;
+ if (!dname_equal_nocase(rdata_atom_data(a->rdatas[i]),
+ rdata_atom_data(b->rdatas[i]),
+ rdata_atom_size(a->rdatas[i])))
+ return 1;
} else {
if (rdata_atom_size(a->rdatas[i])
!= rdata_atom_size(b->rdatas[i]))
@@ -1279,10 +1285,6 @@ zone_open(const char *filename, uint32_t ttl, uint16_t klass,
return 0;
}
- /* Open the network database */
- setprotoent(1);
- setservent(1);
-
zparser_init(filename, ttl, klass, origin);
return 1;
@@ -1304,13 +1306,15 @@ set_bitnsec(uint8_t bits[NSEC_WINDOW_COUNT][NSEC_WINDOW_BITS_SIZE],
}
-static void
-cleanup_rrset(void *r)
+static int
+has_soa(domain_type* domain)
{
- rrset_type *rrset = (rrset_type *) r;
- if (rrset) {
- free(rrset->rrs);
- }
+ rrset_type* p = NULL;
+ if(!domain) return 0;
+ for(p = domain->rrsets; p; p = p->next)
+ if(rrset_rrtype(p) == TYPE_SOA)
+ return 1;
+ return 0;
}
int
@@ -1326,7 +1330,7 @@ process_rr(void)
/* We only support IN class */
if (rr->klass != CLASS_IN) {
- if(zone->opts && zone->opts->request_xfr)
+ if(zone_is_slave(zone->opts))
zc_warning_prev_line("only class IN is supported");
else
zc_error_prev_line("only class IN is supported");
@@ -1341,48 +1345,27 @@ process_rr(void)
zc_error_prev_line("maximum rdata length exceeds %d octets", MAX_RDLENGTH);
return 0;
}
-
- /* Do we have the zone already? */
- if (!zone)
- {
- zone = (zone_type *) region_alloc(parser->region,
- sizeof(zone_type));
- zone->apex = parser->default_apex;
- zone->soa_rrset = NULL;
- zone->soa_nx_rrset = NULL;
- zone->ns_rrset = NULL;
- zone->opts = NULL;
- zone->is_secure = 0;
- zone->updated = 1;
-
- zone->next = parser->db->zones;
- parser->db->zones = zone;
- parser->current_zone = zone;
- }
-
+ /* we have the zone already */
+ assert(zone);
if (rr->type == TYPE_SOA) {
- /*
- * This is a SOA record, start a new zone or continue
- * an existing one.
- */
- if (rr->owner->is_apex) {
- if(zone->opts && zone->opts->request_xfr)
+ if (rr->owner != zone->apex) {
+ zc_error_prev_line(
+ "SOA record with invalid domain name");
+ return 0;
+ }
+ if(has_soa(rr->owner)) {
+ if(zone_is_slave(zone->opts))
zc_warning_prev_line("this SOA record was already encountered");
else
zc_error_prev_line("this SOA record was already encountered");
- } else if (rr->owner == parser->default_apex) {
- zone->apex = rr->owner;
- rr->owner->is_apex = 1;
+ return 0;
}
-
- /* parser part */
- parser->current_zone = zone;
+ rr->owner->is_apex = 1;
}
- if (!dname_is_subdomain(domain_dname(rr->owner),
- domain_dname(zone->apex)))
+ if (!domain_is_subdomain(rr->owner, zone->apex))
{
- if(zone->opts && zone->opts->request_xfr)
+ if(zone_is_slave(zone->opts))
zc_warning_prev_line("out of zone data");
else
zc_error_prev_line("out of zone data");
@@ -1396,14 +1379,14 @@ process_rr(void)
sizeof(rrset_type));
rrset->zone = zone;
rrset->rr_count = 1;
- rrset->rrs = (rr_type *) xalloc(sizeof(rr_type));
+ rrset->rrs = (rr_type *) region_alloc(parser->region,
+ sizeof(rr_type));
rrset->rrs[0] = *rr;
- region_add_cleanup(parser->region, cleanup_rrset, rrset);
-
/* Add it */
domain_add_rrset(rr->owner, rrset);
} else {
+ rr_type* o;
if (rr->type != TYPE_RRSIG && rrset->rrs[0].ttl != rr->ttl) {
zc_warning_prev_line(
"TTL does not match the TTL of the RRset");
@@ -1422,69 +1405,56 @@ process_rr(void)
}
/* Add it... */
- rrset->rrs = (rr_type *) xrealloc(
- rrset->rrs,
+ o = rrset->rrs;
+ rrset->rrs = (rr_type *) region_alloc(parser->region,
(rrset->rr_count + 1) * sizeof(rr_type));
+ memcpy(rrset->rrs, o, (rrset->rr_count) * sizeof(rr_type));
+ region_recycle(parser->region, o,
+ (rrset->rr_count) * sizeof(rr_type));
rrset->rrs[rrset->rr_count] = *rr;
++rrset->rr_count;
}
if(rr->type == TYPE_DNAME && rrset->rr_count > 1) {
- if(zone->opts && zone->opts->request_xfr)
+ if(zone_is_slave(zone->opts))
zc_warning_prev_line("multiple DNAMEs at the same name");
else
zc_error_prev_line("multiple DNAMEs at the same name");
}
if(rr->type == TYPE_CNAME && rrset->rr_count > 1) {
- if(zone->opts && zone->opts->request_xfr)
+ if(zone_is_slave(zone->opts))
zc_warning_prev_line("multiple CNAMEs at the same name");
else
zc_error_prev_line("multiple CNAMEs at the same name");
}
if((rr->type == TYPE_DNAME && domain_find_rrset(rr->owner, zone, TYPE_CNAME))
||(rr->type == TYPE_CNAME && domain_find_rrset(rr->owner, zone, TYPE_DNAME))) {
- if(zone->opts && zone->opts->request_xfr)
+ if(zone_is_slave(zone->opts))
zc_warning_prev_line("DNAME and CNAME at the same name");
else
zc_error_prev_line("DNAME and CNAME at the same name");
}
if(domain_find_rrset(rr->owner, zone, TYPE_CNAME) &&
domain_find_non_cname_rrset(rr->owner, zone)) {
- if(zone->opts && zone->opts->request_xfr)
+ if(zone_is_slave(zone->opts))
zc_warning_prev_line("CNAME and other data at the same name");
else
zc_error_prev_line("CNAME and other data at the same name");
}
- if (rr->type == TYPE_RRSIG && rr_rrsig_type_covered(rr) == TYPE_DNSKEY) {
- rrset->zone->is_secure = 1;
- }
-
/* Check we have SOA */
- if (zone->soa_rrset == NULL) {
- if (rr->type == TYPE_SOA) {
- if (rr->owner != zone->apex) {
- zc_error_prev_line(
- "SOA record with invalid domain name");
- } else {
- zone->soa_rrset = rrset;
- }
- }
- }
- else if (rr->type == TYPE_SOA) {
- if(zone->opts && zone->opts->request_xfr)
- zc_warning_prev_line("duplicate SOA record discarded");
- else
- zc_error_prev_line("duplicate SOA record discarded");
- --rrset->rr_count;
- }
-
- /* Is this a zone NS? */
- if (rr->type == TYPE_NS && rr->owner == zone->apex) {
- zone->ns_rrset = rrset;
- }
- if (vflag > 1 && totalrrs > 0 && (totalrrs % progress == 0)) {
- fprintf(stdout, "%ld\n", totalrrs);
+ if(rr->owner == zone->apex)
+ apex_rrset_checks(parser->db, rrset, rr->owner);
+
+ if(parser->line % ZONEC_PCT_COUNT == 0 && time(NULL) > startzonec + ZONEC_PCT_TIME) {
+ struct stat buf;
+ startzonec = time(NULL);
+ buf.st_size = 0;
+ fstat(fileno(yyin), &buf);
+ if(buf.st_size == 0) buf.st_size = 1;
+ VERBOSITY(1, (LOG_INFO, "parse %s %d %%",
+ parser->current_zone->opts->name,
+ (int)((uint64_t)ftell(yyin)*(uint64_t)100/(uint64_t)buf.st_size)));
}
++totalrrs;
return 1;
@@ -1510,10 +1480,11 @@ domain_find_rrset_any(domain_type *domain, uint16_t type)
* Check for DNAME type. Nothing is allowed below it
*/
static void
-check_dname(namedb_type* db)
+check_dname(zone_type* zone)
{
domain_type* domain;
- RBTREE_FOR(domain, domain_type*, db->domains->names_to_domains)
+ for(domain = zone->apex; domain && domain_is_subdomain(domain,
+ zone->apex); domain=domain_next(domain))
{
if(domain->is_existing) {
/* there may not be DNAMEs above it */
@@ -1525,11 +1496,11 @@ check_dname(namedb_type* db)
while(parent) {
if(domain_find_rrset_any(parent, TYPE_DNAME)) {
zc_error("While checking node %s,",
- dname_to_string(domain_dname(domain), NULL));
+ domain_to_string(domain));
zc_error("DNAME at %s has data below it. "
"This is not allowed (rfc 2672).",
- dname_to_string(domain_dname(parent), NULL));
- exit(1);
+ domain_to_string(parent));
+ return;
}
parent = parent->parent;
}
@@ -1540,274 +1511,146 @@ check_dname(namedb_type* db)
/*
* Reads the specified zone into the memory
* nsd_options can be NULL if no config file is passed.
- *
*/
-static void
-zone_read(const char *name, const char *zonefile, nsd_options_t* nsd_options)
+unsigned int
+zonec_read(const char* name, const char* zonefile, zone_type* zone)
{
const dname_type *dname;
+ totalrrs = 0;
+ startzonec = time(NULL);
+ parser->errors = 0;
+
dname = dname_parse(parser->region, name);
if (!dname) {
zc_error("incorrect zone name '%s'", name);
- return;
+ return 0;
}
#ifndef ROOT_SERVER
/* Is it a root zone? Are we a root server then? Idiot proof. */
if (dname->label_count == 1) {
zc_error("not configured as a root server");
- return;
+ return 0;
}
#endif
/* Open the zone file */
if (!zone_open(zonefile, 3600, CLASS_IN, dname)) {
- if(nsd_options) {
- /* check for secondary zone, they can start with no zone info */
- zone_options_t* zopt = zone_options_find(nsd_options, dname);
- if(zopt && zone_is_slave(zopt)) {
- zc_warning("slave zone %s with no zonefile '%s'(%s) will "
- "force zone transfer.",
- name, zonefile, strerror(errno));
- return;
- }
- }
- /* cannot happen with stdin - so no fix needed for zonefile */
zc_error("cannot open '%s': %s", zonefile, strerror(errno));
- return;
+ return 0;
}
+ parser->current_zone = zone;
/* Parse and process all RRs. */
yyparse();
+ /* remove origin if it was unused */
+ domain_table_deldomain(parser->db, parser->origin);
+
/* check if zone file contained a correct SOA record */
- if (parser->current_zone && parser->current_zone->soa_rrset
- && parser->current_zone->soa_rrset->rr_count!=0)
- {
- if(dname_compare(domain_dname(
- parser->current_zone->soa_rrset->rrs[0].owner),
- dname) != 0) {
- zc_error("zone configured as '%s', but SOA has owner '%s'.",
- name, dname_to_string(
- domain_dname(parser->current_zone->
- soa_rrset->rrs[0].owner), NULL));
- }
+ if (!parser->current_zone) {
+ zc_error("zone configured as '%s' has no content.", name);
+ } else if(!parser->current_zone->soa_rrset ||
+ parser->current_zone->soa_rrset->rr_count == 0) {
+ zc_error("zone configured as '%s' has no SOA record.", name);
+ } else if(dname_compare(domain_dname(
+ parser->current_zone->soa_rrset->rrs[0].owner), dname) != 0) {
+ zc_error("zone configured as '%s', but SOA has owner '%s'.",
+ name, domain_to_string(
+ parser->current_zone->soa_rrset->rrs[0].owner));
}
fclose(yyin);
+ if(!zone_is_slave(zone->opts))
+ check_dname(zone);
- fflush(stdout);
- totalerrors += parser->errors;
parser->filename = NULL;
+ return parser->errors;
}
-static void
-usage (void)
-{
-#ifndef NDEBUG
- fprintf(stderr, "usage: nsd-zonec [-v|-h|-C|-F|-L] [-c configfile] [-o origin] [-d directory] [-f database] [-z zonefile]\n\n");
-#else
- fprintf(stderr, "usage: nsd-zonec [-v|-h|-C] [-c configfile] [-o origin] [-d directory] [-f database] [-z zonefile]\n\n");
-#endif
- fprintf(stderr, "\tNSD zone compiler, creates database from zone files.\n");
- fprintf(stderr, "\tVersion %s. Report bugs to <%s>.\n\n",
- PACKAGE_VERSION, PACKAGE_BUGREPORT);
- fprintf(stderr, "\t-v\tBe more verbose.\n");
- fprintf(stderr, "\t-h\tPrint this help information.\n");
- fprintf(stderr, "\t-c\tSpecify config file to read instead of default nsd.conf.\n");
- fprintf(stderr, "\t-C\tNo config file is read.\n");
- fprintf(stderr, "\t-d\tSet working directory to open files from.\n");
- fprintf(stderr, "\t-o\tSpecify a zone's origin (only used with -z).\n");
- fprintf(stderr, "\t-f\tSpecify database file to use.\n");
- fprintf(stderr, "\t-z\tSpecify a zonefile to read (read from stdin with \'-\').\n");
-#ifndef NDEBUG
- fprintf(stderr, "\t-F\tSet debug facilities.\n");
- fprintf(stderr, "\t-L\tSet debug level.\n");
-#endif
-}
-
-extern char *optarg;
-extern int optind;
-int
-main (int argc, char **argv)
+/*
+ * setup parse
+ */
+void
+zonec_setup_parser(namedb_type* db)
{
- struct namedb *db;
- char *origin = NULL;
- int c;
- region_type *global_region;
- region_type *rr_region;
- const char* configfile= CONFIGFILE;
- const char* zonesdir = NULL;
- const char* singlefile = NULL;
- nsd_options_t* nsd_options = NULL;
-
- log_init("nsd-zonec");
-
- global_region = region_create(xalloc, free);
- rr_region = region_create(xalloc, free);
- totalerrors = 0;
-
- /* Parse the command line... */
- while ((c = getopt(argc, argv, "d:f:vhCF:L:o:c:z:")) != -1) {
- switch (c) {
- case 'c':
- configfile = optarg;
- break;
- case 'v':
- ++vflag;
- break;
- case 'f':
- dbfile = optarg;
- break;
- case 'd':
- zonesdir = optarg;
- break;
- case 'C':
- configfile = 0;
- break;
-#ifndef NDEBUG
- case 'F':
- sscanf(optarg, "%x", &nsd_debug_facilities);
- break;
- case 'L':
- sscanf(optarg, "%d", &nsd_debug_level);
- break;
-#endif /* NDEBUG */
- case 'o':
- origin = optarg;
- break;
- case 'z':
- singlefile = optarg;
- break;
- case 'h':
- usage();
- exit(0);
- case '?':
- default:
- usage();
- exit(1);
- }
- }
-
- argc -= optind;
- argv += optind;
-
- if (argc != 0) {
- usage();
- exit(1);
- }
-
- /* Read options */
- if(configfile != 0) {
- nsd_options = nsd_options_create(global_region);
- if(!parse_options_file(nsd_options, configfile))
- {
- fprintf(stderr, "nsd-zonec: could not read config: %s\n", configfile);
- exit(1);
- }
- }
- if(nsd_options && zonesdir == 0) zonesdir = nsd_options->zonesdir;
- if(zonesdir && zonesdir[0]) {
- if (chdir(zonesdir)) {
- fprintf(stderr, "nsd-zonec: cannot chdir to %s: %s\n", zonesdir, strerror(errno));
- exit(1);
- }
- }
- if(dbfile == 0) {
- if(nsd_options && nsd_options->database) dbfile = nsd_options->database;
- else dbfile = DBFILE;
- }
-
- /* Create the database */
- if ((db = namedb_new(dbfile)) == NULL) {
- fprintf(stderr, "nsd-zonec: error creating the database (%s): %s\n",
- dbfile, strerror(errno));
- exit(1);
- }
-
- parser = zparser_create(global_region, rr_region, db);
- if (!parser) {
- fprintf(stderr, "nsd-zonec: error creating the parser\n");
- exit(1);
- }
-
+ region_type* rr_region = region_create(xalloc, free);
+ parser = zparser_create(db->region, rr_region, db);
+ assert(parser);
/* Unique pointers used to mark errors. */
- error_dname = (dname_type *) region_alloc(global_region, 0);
- error_domain = (domain_type *) region_alloc(global_region, 0);
-
- if (singlefile || origin) {
- /*
- * Read a single zone file with the specified origin
- */
- if(!singlefile) {
- fprintf(stderr, "nsd-zonec: must have -z zonefile when reading single zone.\n");
- exit(1);
- }
- if(!origin) {
- fprintf(stderr, "nsd-zonec: must have -o origin when reading single zone.\n");
- exit(1);
- }
- if (vflag > 0)
- fprintf(stdout, "nsd-zonec: reading zone \"%s\".\n", origin);
- zone_read(origin, singlefile, nsd_options);
- if (vflag > 0)
- fprintf(stdout, "nsd-zonec: processed %ld RRs in \"%s\".\n", totalrrs, origin);
- } else {
- zone_options_t* zone;
- if(!nsd_options) {
- fprintf(stderr, "nsd-zonec: no zones specified.\n");
- exit(1);
- }
- /* read all zones */
- RBTREE_FOR(zone, zone_options_t*, nsd_options->zone_options)
- {
- if (vflag > 0)
- fprintf(stdout, "nsd-zonec: reading zone \"%s\".\n",
- zone->name);
- zone_read(zone->name, zone->zonefile, nsd_options);
- if (vflag > 0)
- fprintf(stdout,
- "nsd-zonec: processed %ld RRs in \"%s\".\n",
- totalrrs, zone->name);
- totalrrs = 0;
- }
- }
- check_dname(db);
+ error_dname = (dname_type *) region_alloc(db->region, 1);
+ error_domain = (domain_type *) region_alloc(db->region, 1);
+ /* Open the network database */
+ setprotoent(1);
+ setservent(1);
+}
-#ifndef NDEBUG
- if (vflag > 0) {
- fprintf(stdout, "global_region: ");
- region_dump_stats(global_region, stdout);
- fprintf(stdout, "\n");
- fprintf(stdout, "db->region: ");
- region_dump_stats(db->region, stdout);
- fprintf(stdout, "\n");
+/** desetup parse */
+void
+zonec_desetup_parser(void)
+{
+ if(parser) {
+ endservent();
+ endprotoent();
+ region_destroy(parser->rr_region);
+ /* removed when parser->region(=db->region) is destroyed:
+ * region_recycle(parser->region, (void*)error_dname, 1);
+ * region_recycle(parser->region, (void*)error_domain, 1); */
+ /* clear memory for exit, but this is not portable to
+ * other versions of lex. yylex_destroy(); */
}
-#endif /* NDEBUG */
+}
- /* Close the database */
- if (namedb_save(db) != 0) {
- fprintf(stderr, "nsd-zonec: error writing the database (%s): %s\n", db->filename, strerror(errno));
- namedb_discard(db);
- exit(1);
- }
+static domain_table_type* orig_domains = NULL;
+static region_type* orig_region = NULL;
+static region_type* orig_dbregion = NULL;
- /* Print the total number of errors */
- if (vflag > 0 || totalerrors > 0) {
- if (totalerrors > 0) {
- fprintf(stderr, "\nnsd-zonec: done with %ld errors.\n",
- totalerrors);
- } else {
- fprintf(stdout, "\nnsd-zonec: done with no errors.\n");
- }
- }
+/** setup for string parse */
+void
+zonec_setup_string_parser(region_type* region, domain_table_type* domains)
+{
+ assert(parser); /* global parser must be setup */
+ orig_domains = parser->db->domains;
+ orig_region = parser->region;
+ orig_dbregion = parser->db->region;
+ parser->region = region;
+ parser->db->region = region;
+ parser->db->domains = domains;
+ zparser_init("string", 3600, CLASS_IN, domain_dname(domains->root));
+}
- /* Disable this to save some time. */
-#if 0
- region_destroy(global_region);
-#endif
+/** desetup string parse */
+void
+zonec_desetup_string_parser(void)
+{
+ parser->region = orig_region;
+ parser->db->domains = orig_domains;
+ parser->db->region = orig_dbregion;
+}
- return totalerrors ? 1 : 0;
+/** parse a string into temporary storage */
+int
+zonec_parse_string(region_type* region, domain_table_type* domains,
+ zone_type* zone, char* str, domain_type** parsed, int* num_rrs)
+{
+ int errors;
+ zonec_setup_string_parser(region, domains);
+ parser->current_zone = zone;
+ parser->errors = 0;
+ totalrrs = 0;
+ startzonec = time(NULL)+100000; /* disable */
+ parser_push_stringbuf(str);
+ yyparse();
+ parser_pop_stringbuf();
+ errors = parser->errors;
+ *num_rrs = totalrrs;
+ if(*num_rrs == 0)
+ *parsed = NULL;
+ else *parsed = parser->prev_dname;
+ /* remove origin if it was not used during the parse */
+ domain_table_deldomain(parser->db, parser->origin);
+ zonec_desetup_string_parser();
+ return errors;
}