diff options
author | Jakob Schlyter <jakob@cvs.openbsd.org> | 2010-01-15 19:25:09 +0000 |
---|---|---|
committer | Jakob Schlyter <jakob@cvs.openbsd.org> | 2010-01-15 19:25:09 +0000 |
commit | 9eaa04b41a0d6eae92712b72760a0be533d8d31a (patch) | |
tree | 9516390fdd3c033f5cec70e75015e186fe513311 /usr.sbin | |
parent | 991ba55f366ee9f2e6d1d5050e11642b2bad5e83 (diff) |
NSD v3.2.4
Diffstat (limited to 'usr.sbin')
-rw-r--r-- | usr.sbin/nsd/options.c | 1570 |
1 files changed, 170 insertions, 1400 deletions
diff --git a/usr.sbin/nsd/options.c b/usr.sbin/nsd/options.c index 8b8f3f5352e..9ce47f398bf 100644 --- a/usr.sbin/nsd/options.c +++ b/usr.sbin/nsd/options.c @@ -6,7 +6,7 @@ * See LICENSE for the license. * */ -#include "config.h" +#include <config.h> #include <string.h> #include <stdio.h> #include <errno.h> @@ -14,10 +14,10 @@ #include "query.h" #include "tsig.h" #include "difffile.h" -#include "rrl.h" #include "configyyrename.h" #include "configparser.h" +nsd_options_t* nsd_options = 0; config_parser_state_t* cfg_parser = 0; extern FILE* c_in, *c_out; int c_parse(void); @@ -25,42 +25,26 @@ int c_lex(void); int c_wrap(void); void c_error(const char *message); -static int -rbtree_strcmp(const void* p1, const void* p2) -{ - if(p1 == NULL && p2 == NULL) return 0; - if(p1 == NULL) return -1; - if(p2 == NULL) return 1; - return strcmp((const char*)p1, (const char*)p2); -} - -nsd_options_t* -nsd_options_create(region_type* region) +nsd_options_t* nsd_options_create(region_type* region) { nsd_options_t* opt; opt = (nsd_options_t*)region_alloc(region, sizeof(nsd_options_t)); opt->region = region; opt->zone_options = rbtree_create(region, (int (*)(const void *, const void *)) dname_compare); - opt->configfile = NULL; - opt->zonestatnames = rbtree_create(opt->region, rbtree_strcmp); - opt->patterns = rbtree_create(region, rbtree_strcmp); - opt->keys = rbtree_create(region, rbtree_strcmp); + opt->keys = NULL; + opt->numkeys = 0; opt->ip_addresses = NULL; - opt->ip_transparent = 0; opt->debug_mode = 0; opt->verbosity = 0; opt->hide_version = 0; - opt->do_ip4 = 1; - opt->do_ip6 = 1; + opt->ip4_only = 0; + opt->ip6_only = 0; opt->database = DBFILE; opt->identity = 0; - opt->nsid = 0; opt->logfile = 0; - opt->log_time_ascii = 1; - opt->round_robin = 0; /* also packet.h::round_robin */ opt->server_count = 1; - opt->tcp_count = 100; + opt->tcp_count = 10; opt->tcp_query_count = 0; opt->tcp_timeout = TCP_TIMEOUT; opt->ipv4_edns_size = EDNS_MAX_MESSAGE_LEN; @@ -72,34 +56,14 @@ nsd_options_create(region_type* region) opt->chroot = 0; opt->username = USER; opt->zonesdir = ZONESDIR; + opt->difffile = DIFFFILE; opt->xfrdfile = XFRDFILE; - opt->xfrdir = XFRDIR; - opt->zonelistfile = ZONELISTFILE; -#ifdef RATELIMIT - opt->rrl_size = RRL_BUCKETS; - opt->rrl_ratelimit = RRL_LIMIT/2; - opt->rrl_slip = RRL_SLIP; - opt->rrl_ipv4_prefix_length = RRL_IPV4_PREFIX_LENGTH; - opt->rrl_ipv6_prefix_length = RRL_IPV6_PREFIX_LENGTH; - opt->rrl_whitelist_ratelimit = RRL_WLIST_LIMIT/2; -#endif - opt->zonefiles_check = 1; - if(opt->database == NULL || opt->database[0] == 0) - opt->zonefiles_write = ZONEFILES_WRITE_INTERVAL; - else opt->zonefiles_write = 0; - opt->xfrd_reload_timeout = 1; - opt->control_enable = 0; - opt->control_interface = NULL; - opt->control_port = NSD_CONTROL_PORT; - opt->server_key_file = CONFIGDIR"/nsd_server.key"; - opt->server_cert_file = CONFIGDIR"/nsd_server.pem"; - opt->control_key_file = CONFIGDIR"/nsd_control.key"; - opt->control_cert_file = CONFIGDIR"/nsd_control.pem"; + opt->xfrd_reload_timeout = 10; + nsd_options = opt; return opt; } -int -nsd_options_insert_zone(nsd_options_t* opt, zone_options_t* zone) +int nsd_options_insert_zone(nsd_options_t* opt, zone_options_t* zone) { /* create dname for lookup */ const dname_type* dname = dname_parse(opt->region, zone->name); @@ -111,40 +75,23 @@ nsd_options_insert_zone(nsd_options_t* opt, zone_options_t* zone) return 1; } -int -nsd_options_insert_pattern(nsd_options_t* opt, pattern_options_t* pat) -{ - if(!pat->pname) - return 0; - pat->node.key = pat->pname; - if(!rbtree_insert(opt->patterns, (rbnode_t*)pat)) - return 0; - return 1; -} - -int -parse_options_file(nsd_options_t* opt, const char* file, - void (*err)(void*,const char*), void* err_arg) +int parse_options_file(nsd_options_t* opt, const char* file) { FILE *in = 0; - pattern_options_t* pat; + zone_options_t* zone; acl_options_t* acl; - if(!cfg_parser) { + if(!cfg_parser) cfg_parser = (config_parser_state_t*)region_alloc( opt->region, sizeof(config_parser_state_t)); - cfg_parser->chroot = 0; - } - cfg_parser->err = err; - cfg_parser->err_arg = err_arg; - cfg_parser->filename = (char*)file; + cfg_parser->filename = file; cfg_parser->line = 1; cfg_parser->errors = 0; - cfg_parser->server_settings_seen = 0; cfg_parser->opt = opt; - cfg_parser->current_pattern = 0; cfg_parser->current_zone = 0; - cfg_parser->current_key = 0; + cfg_parser->current_key = opt->keys; + while(cfg_parser->current_key && cfg_parser->current_key->next) + cfg_parser->current_key = cfg_parser->current_key->next; cfg_parser->current_ip_address_option = opt->ip_addresses; while(cfg_parser->current_ip_address_option && cfg_parser->current_ip_address_option->next) cfg_parser->current_ip_address_option = cfg_parser->current_ip_address_option->next; @@ -152,34 +99,16 @@ parse_options_file(nsd_options_t* opt, const char* file, cfg_parser->current_request_xfr = 0; cfg_parser->current_notify = 0; cfg_parser->current_provide_xfr = 0; - + in = fopen(cfg_parser->filename, "r"); if(!in) { - if(err) { - char m[MAXSYSLOGMSGLEN]; - snprintf(m, sizeof(m), "Could not open %s: %s\n", - file, strerror(errno)); - err(err_arg, m); - } else { - fprintf(stderr, "Could not open %s: %s\n", - file, strerror(errno)); - } + fprintf(stderr, "Could not open %s: %s\n", file, strerror(errno)); return 0; } c_in = in; c_parse(); fclose(in); - opt->configfile = region_strdup(opt->region, file); - if(cfg_parser->current_pattern) { - if(!cfg_parser->current_pattern->pname) - c_error("last pattern has no name"); - else { - if(!nsd_options_insert_pattern(cfg_parser->opt, - cfg_parser->current_pattern)) - c_error("duplicate pattern"); - } - } if(cfg_parser->current_zone) { if(!cfg_parser->current_zone->name) c_error("last zone has no name"); @@ -188,523 +117,83 @@ parse_options_file(nsd_options_t* opt, const char* file, cfg_parser->current_zone)) c_error("duplicate zone"); } - if(!cfg_parser->current_zone->pattern) - c_error("last zone has no pattern"); + if(!cfg_parser->current_zone->zonefile) + c_error("last zone has no zonefile"); } - if(cfg_parser->current_key) + if(opt->keys) { - if(!cfg_parser->current_key->name) + if(!opt->keys->name) c_error("last key has no name"); - if(!cfg_parser->current_key->algorithm) + if(!opt->keys->algorithm) c_error("last key has no algorithm"); - if(!cfg_parser->current_key->secret) + if(!opt->keys->secret) c_error("last key has no secret blob"); - key_options_insert(opt, cfg_parser->current_key); } - RBTREE_FOR(pat, pattern_options_t*, opt->patterns) + RBTREE_FOR(zone, zone_options_t*, opt->zone_options) { + if(!zone->name) + continue; + if(!zone->zonefile) + continue; /* lookup keys for acls */ - for(acl=pat->allow_notify; acl; acl=acl->next) + for(acl=zone->allow_notify; acl; acl=acl->next) { if(acl->nokey || acl->blocked) continue; acl->key_options = key_options_find(opt, acl->key_name); if(!acl->key_options) - c_error_msg("key %s in pattern %s could not be found", - acl->key_name, pat->pname); + c_error_msg("key %s in zone %s could not be found", + acl->key_name, zone->name); } - for(acl=pat->notify; acl; acl=acl->next) + for(acl=zone->notify; acl; acl=acl->next) { if(acl->nokey || acl->blocked) continue; acl->key_options = key_options_find(opt, acl->key_name); if(!acl->key_options) - c_error_msg("key %s in pattern %s could not be found", - acl->key_name, pat->pname); + c_error_msg("key %s in zone %s could not be found", + acl->key_name, zone->name); } - for(acl=pat->request_xfr; acl; acl=acl->next) + for(acl=zone->request_xfr; acl; acl=acl->next) { if(acl->nokey || acl->blocked) continue; acl->key_options = key_options_find(opt, acl->key_name); if(!acl->key_options) - c_error_msg("key %s in pattern %s could not be found", - acl->key_name, pat->pname); + c_error_msg("key %s in zone %s could not be found", + acl->key_name, zone->name); } - for(acl=pat->provide_xfr; acl; acl=acl->next) + for(acl=zone->provide_xfr; acl; acl=acl->next) { if(acl->nokey || acl->blocked) continue; acl->key_options = key_options_find(opt, acl->key_name); if(!acl->key_options) - c_error_msg("key %s in pattern %s could not be found", - acl->key_name, pat->pname); + c_error_msg("key %s in zone %s could not be found", + acl->key_name, zone->name); } } if(cfg_parser->errors > 0) { - if(err) { - char m[MAXSYSLOGMSGLEN]; - snprintf(m, sizeof(m), "read %s failed: %d errors in " - "configuration file\n", file, - cfg_parser->errors); - err(err_arg, m); - } else { - fprintf(stderr, "read %s failed: %d errors in " - "configuration file\n", file, - cfg_parser->errors); - } - return 0; - } - return 1; -} - -void options_zonestatnames_create(nsd_options_t* opt) -{ - zone_options_t* zopt; - /* allocate "" as zonestat 0, for zones without a zonestat */ - if(!rbtree_search(opt->zonestatnames, "")) { - struct zonestatname* n; - n = (struct zonestatname*)xalloc(sizeof(*n)); - memset(n, 0, sizeof(*n)); - n->node.key = strdup(""); - if(!n->node.key) { - log_msg(LOG_ERR, "malloc failed: %s", strerror(errno)); - exit(1); - } - n->id = (unsigned)(opt->zonestatnames->count); - rbtree_insert(opt->zonestatnames, (rbnode_t*)n); - } - RBTREE_FOR(zopt, zone_options_t*, opt->zone_options) { - /* insert into tree, so that when read in later id exists */ - (void)getzonestatid(opt, zopt); - } -} - -#define ZONELIST_HEADER "# NSD zone list\n# name pattern\n" -static int -comp_zonebucket(const void* a, const void* b) -{ - /* the line size is much smaller than max-int, and positive, - * so the subtraction works */ - return *(const int*)b - *(const int*)a; -} - -/* insert free entry into zonelist free buckets */ -static void -zone_list_free_insert(nsd_options_t* opt, int linesize, off_t off) -{ - struct zonelist_free* e; - struct zonelist_bucket* b = (struct zonelist_bucket*)rbtree_search( - opt->zonefree, &linesize); - if(!b) { - b = region_alloc_zero(opt->region, sizeof(*b)); - b->linesize = linesize; - b->node = *RBTREE_NULL; - b->node.key = &b->linesize; - rbtree_insert(opt->zonefree, &b->node); - } - e = (struct zonelist_free*)region_alloc_zero(opt->region, sizeof(*e)); - e->next = b->list; - b->list = e; - e->off = off; - opt->zonefree_number++; -} - -zone_options_t* -zone_list_zone_insert(nsd_options_t* opt, const char* nm, const char* patnm, - int linesize, off_t off) -{ - pattern_options_t* pat = pattern_options_find(opt, patnm); - zone_options_t* zone; - if(!pat) { - log_msg(LOG_ERR, "pattern does not exist for zone %s " - "pattern %s", nm, patnm); - return NULL; - } - zone = zone_options_create(opt->region); - zone->part_of_config = 0; - zone->name = region_strdup(opt->region, nm); - zone->linesize = linesize; - zone->off = off; - zone->pattern = pat; - if(!nsd_options_insert_zone(opt, zone)) { - log_msg(LOG_ERR, "bad domain name or duplicate zone '%s' " - "pattern %s", nm, patnm); - region_recycle(opt->region, (void*)zone->name, strlen(nm)+1); - region_recycle(opt->region, zone, sizeof(*zone)); - return NULL; - } - return zone; -} - -int -parse_zone_list_file(nsd_options_t* opt) -{ - /* zonelist looks like this: - # name pattern - add example.com master - del example.net slave - add foo.bar.nl slave - add rutabaga.uk config - */ - char buf[1024]; - - /* create empty data structures */ - opt->zonefree = rbtree_create(opt->region, comp_zonebucket); - opt->zonelist = NULL; - opt->zonefree_number = 0; - opt->zonelist_off = 0; - - /* try to open the zonelist file, an empty or nonexist file is OK */ - opt->zonelist = fopen(opt->zonelistfile, "r+"); - if(!opt->zonelist) { - if(errno == ENOENT) - return 1; /* file does not exist, it is created later */ - log_msg(LOG_ERR, "could not open zone list %s: %s", opt->zonelistfile, - strerror(errno)); - return 0; - } - /* read header */ - buf[strlen(ZONELIST_HEADER)] = 0; - if(fread(buf, 1, strlen(ZONELIST_HEADER), opt->zonelist) != - strlen(ZONELIST_HEADER) || strncmp(buf, ZONELIST_HEADER, - strlen(ZONELIST_HEADER)) != 0) { - log_msg(LOG_ERR, "zone list %s contains bad header\n", opt->zonelistfile); - fclose(opt->zonelist); - opt->zonelist = NULL; + fprintf(stderr, "read %s failed: %d errors in configuration file\n", + cfg_parser->filename, + cfg_parser->errors); return 0; } - - /* read entries in file */ - while(fgets(buf, sizeof(buf), opt->zonelist)) { - /* skip comments and empty lines */ - if(buf[0] == 0 || buf[0] == '\n' || buf[0] == '#') - continue; - if(strncmp(buf, "add ", 4) == 0) { - int linesize = strlen(buf); - /* parse the 'add' line */ - /* pick last space on the line, so that the domain - * name can have a space in it (but not the pattern)*/ - char* space = strrchr(buf+4, ' '); - char* nm, *patnm; - if(!space) { - /* parse error */ - log_msg(LOG_ERR, "parse error in %s: '%s'", - opt->zonelistfile, buf); - continue; - } - nm = buf+4; - *space = 0; - patnm = space+1; - if(linesize && buf[linesize-1] == '\n') - buf[linesize-1] = 0; - - /* store offset and line size for zone entry */ - /* and create zone entry in zonetree */ - (void)zone_list_zone_insert(opt, nm, patnm, linesize, - ftello(opt->zonelist)-linesize); - } else if(strncmp(buf, "del ", 4) == 0) { - /* store offset and line size for deleted entry */ - int linesize = strlen(buf); - zone_list_free_insert(opt, linesize, - ftello(opt->zonelist)-linesize); - } else { - log_msg(LOG_WARNING, "bad data in %s, '%s'", opt->zonelistfile, - buf); - } - } - /* store EOF offset */ - opt->zonelist_off = ftello(opt->zonelist); return 1; } -void -zone_options_delete(nsd_options_t* opt, zone_options_t* zone) -{ - rbtree_delete(opt->zone_options, zone->node.key); - region_recycle(opt->region, (void*)zone->node.key, dname_total_size( - (dname_type*)zone->node.key)); - region_recycle(opt->region, zone, sizeof(*zone)); -} - -/* add a new zone to the zonelist */ -zone_options_t* -zone_list_add(nsd_options_t* opt, const char* zname, const char* pname) -{ - int r; - struct zonelist_free* e; - struct zonelist_bucket* b; - int linesize = 6 + strlen(zname) + strlen(pname); - /* create zone entry */ - zone_options_t* zone = zone_list_zone_insert(opt, zname, pname, - linesize, 0); - if(!zone) - return NULL; - - /* use free entry or append to file or create new file */ - if(!opt->zonelist || opt->zonelist_off == 0) { - /* create new file */ - if(opt->zonelist) fclose(opt->zonelist); - opt->zonelist = fopen(opt->zonelistfile, "w+"); - if(!opt->zonelist) { - log_msg(LOG_ERR, "could not create zone list %s: %s", - opt->zonelistfile, strerror(errno)); - log_msg(LOG_ERR, "zone %s could not be added", zname); - zone_options_delete(opt, zone); - return NULL; - } - r = fprintf(opt->zonelist, ZONELIST_HEADER); - if(r != strlen(ZONELIST_HEADER)) { - if(r == -1) - log_msg(LOG_ERR, "could not write to %s: %s", - opt->zonelistfile, strerror(errno)); - else log_msg(LOG_ERR, "partial write to %s: disk full", - opt->zonelistfile); - log_msg(LOG_ERR, "zone %s could not be added", zname); - zone_options_delete(opt, zone); - return NULL; - } - zone->off = ftello(opt->zonelist); - if(zone->off == -1) - log_msg(LOG_ERR, "ftello(%s): %s", opt->zonelistfile, strerror(errno)); - r = fprintf(opt->zonelist, "add %s %s\n", zname, pname); - if(r != zone->linesize) { - if(r == -1) - log_msg(LOG_ERR, "could not write to %s: %s", - opt->zonelistfile, strerror(errno)); - else log_msg(LOG_ERR, "partial write to %s: disk full", - opt->zonelistfile); - log_msg(LOG_ERR, "zone %s could not be added", zname); - zone_options_delete(opt, zone); - return NULL; - } - opt->zonelist_off = ftello(opt->zonelist); - if(opt->zonelist_off == -1) - log_msg(LOG_ERR, "ftello(%s): %s", opt->zonelistfile, strerror(errno)); - if(fflush(opt->zonelist) != 0) { - log_msg(LOG_ERR, "fflush %s: %s", opt->zonelistfile, strerror(errno)); - } - return zone; - } - b = (struct zonelist_bucket*)rbtree_search(opt->zonefree, - &zone->linesize); - if(!b || b->list == NULL) { - /* no empty place, append to file */ - zone->off = opt->zonelist_off; - if(fseeko(opt->zonelist, zone->off, SEEK_SET) == -1) { - log_msg(LOG_ERR, "fseeko(%s): %s", opt->zonelistfile, strerror(errno)); - log_msg(LOG_ERR, "zone %s could not be added", zname); - zone_options_delete(opt, zone); - return NULL; - } - r = fprintf(opt->zonelist, "add %s %s\n", zname, pname); - if(r != zone->linesize) { - if(r == -1) - log_msg(LOG_ERR, "could not write to %s: %s", - opt->zonelistfile, strerror(errno)); - else log_msg(LOG_ERR, "partial write to %s: disk full", - opt->zonelistfile); - log_msg(LOG_ERR, "zone %s could not be added", zname); - zone_options_delete(opt, zone); - return NULL; - } - opt->zonelist_off += linesize; - if(fflush(opt->zonelist) != 0) { - log_msg(LOG_ERR, "fflush %s: %s", opt->zonelistfile, strerror(errno)); - } - return zone; - } - /* reuse empty spot */ - e = b->list; - zone->off = e->off; - if(fseeko(opt->zonelist, zone->off, SEEK_SET) == -1) { - log_msg(LOG_ERR, "fseeko(%s): %s", opt->zonelistfile, strerror(errno)); - log_msg(LOG_ERR, "zone %s could not be added", zname); - zone_options_delete(opt, zone); - return NULL; - } - r = fprintf(opt->zonelist, "add %s %s\n", zname, pname); - if(r != zone->linesize) { - if(r == -1) - log_msg(LOG_ERR, "could not write to %s: %s", - opt->zonelistfile, strerror(errno)); - else log_msg(LOG_ERR, "partial write to %s: disk full", - opt->zonelistfile); - log_msg(LOG_ERR, "zone %s could not be added", zname); - zone_options_delete(opt, zone); - return NULL; - } - if(fflush(opt->zonelist) != 0) { - log_msg(LOG_ERR, "fflush %s: %s", opt->zonelistfile, strerror(errno)); - } - - /* snip off and recycle element */ - b->list = e->next; - region_recycle(opt->region, e, sizeof(*e)); - if(b->list == NULL) { - rbtree_delete(opt->zonefree, &b->linesize); - region_recycle(opt->region, b, sizeof(*b)); - } - opt->zonefree_number--; - return zone; -} - -/* remove a zone on the zonelist */ -void -zone_list_del(nsd_options_t* opt, zone_options_t* zone) -{ - /* put its space onto the free entry */ - if(fseeko(opt->zonelist, zone->off, SEEK_SET) == -1) { - log_msg(LOG_ERR, "fseeko(%s): %s", opt->zonelistfile, strerror(errno)); - return; - } - fprintf(opt->zonelist, "del"); - zone_list_free_insert(opt, zone->linesize, zone->off); - - /* remove zone_options_t */ - zone_options_delete(opt, zone); - - /* see if we need to compact: it is going to halve the zonelist */ - if(opt->zonefree_number > opt->zone_options->count) { - zone_list_compact(opt); - } else { - if(fflush(opt->zonelist) != 0) { - log_msg(LOG_ERR, "fflush %s: %s", opt->zonelistfile, strerror(errno)); - } - } -} -/* postorder delete of zonelist free space tree */ -static void -delbucket(region_type* region, struct zonelist_bucket* b) -{ - struct zonelist_free* e, *f; - if(!b || (rbnode_t*)b==RBTREE_NULL) - return; - delbucket(region, (struct zonelist_bucket*)b->node.left); - delbucket(region, (struct zonelist_bucket*)b->node.right); - e = b->list; - while(e) { - f = e->next; - region_recycle(region, e, sizeof(*e)); - e = f; - } - region_recycle(region, b, sizeof(*b)); -} - -/* compact zonelist file */ -void -zone_list_compact(nsd_options_t* opt) -{ - char outname[1024]; - FILE* out; - zone_options_t* zone; - off_t off; - int r; - snprintf(outname, sizeof(outname), "%s~", opt->zonelistfile); - /* useful, when : count-of-free > count-of-used */ - /* write zonelist to zonelist~ */ - out = fopen(outname, "w+"); - if(!out) { - log_msg(LOG_ERR, "could not open %s: %s", outname, strerror(errno)); - return; - } - r = fprintf(out, ZONELIST_HEADER); - if(r == -1) { - log_msg(LOG_ERR, "write %s failed: %s", outname, - strerror(errno)); - fclose(out); - return; - } else if(r != strlen(ZONELIST_HEADER)) { - log_msg(LOG_ERR, "write %s was partial: disk full", - outname); - fclose(out); - return; - } - off = ftello(out); - if(off == -1) { - log_msg(LOG_ERR, "ftello(%s): %s", outname, strerror(errno)); - fclose(out); - return; - } - RBTREE_FOR(zone, zone_options_t*, opt->zone_options) { - if(zone->part_of_config) - continue; - r = fprintf(out, "add %s %s\n", zone->name, - zone->pattern->pname); - if(r < 0) { - log_msg(LOG_ERR, "write %s failed: %s", outname, - strerror(errno)); - fclose(out); - return; - } else if(r != zone->linesize) { - log_msg(LOG_ERR, "write %s was partial: disk full", - outname); - fclose(out); - return; - } - } - if(fflush(out) != 0) { - log_msg(LOG_ERR, "fflush %s: %s", outname, strerror(errno)); - } - - /* rename zonelist~ onto zonelist */ - if(rename(outname, opt->zonelistfile) == -1) { - log_msg(LOG_ERR, "rename(%s to %s) failed: %s", - outname, opt->zonelistfile, strerror(errno)); - fclose(out); - return; - } - fclose(opt->zonelist); - /* set offsets */ - RBTREE_FOR(zone, zone_options_t*, opt->zone_options) { - if(zone->part_of_config) - continue; - zone->off = off; - off += zone->linesize; - } - /* empty the free tree */ - delbucket(opt->region, (struct zonelist_bucket*)opt->zonefree->root); - opt->zonefree->root = RBTREE_NULL; - opt->zonefree->count = 0; - opt->zonefree_number = 0; - /* finish */ - opt->zonelist = out; - opt->zonelist_off = off; -} - -/* close zonelist file */ -void -zone_list_close(nsd_options_t* opt) -{ - fclose(opt->zonelist); - opt->zonelist = NULL; -} - - -void -c_error_va_list(const char* fmt, va_list args) +void c_error_va_list(const char *fmt, va_list args) { cfg_parser->errors++; - if(cfg_parser->err) { - char m[MAXSYSLOGMSGLEN]; - snprintf(m, sizeof(m), "%s:%d: error: ", cfg_parser->filename, - cfg_parser->line); - (*cfg_parser->err)(cfg_parser->err_arg, m); - vsnprintf(m, sizeof(m), fmt, args); - (*cfg_parser->err)(cfg_parser->err_arg, m); - (*cfg_parser->err)(cfg_parser->err_arg, "\n"); - return; - } fprintf(stderr, "%s:%d: error: ", cfg_parser->filename, cfg_parser->line); vfprintf(stderr, fmt, args); fprintf(stderr, "\n"); } -void -c_error_msg(const char* fmt, ...) +void c_error_msg(const char* fmt, ...) { va_list args; va_start(args, fmt); @@ -712,563 +201,61 @@ c_error_msg(const char* fmt, ...) va_end(args); } -void -c_error(const char* str) +void c_error(const char *str) { - c_error_msg("%s", str); + cfg_parser->errors++; + fprintf(stderr, "%s:%d: error: %s\n", cfg_parser->filename, + cfg_parser->line, str); } -int -c_wrap() +int c_wrap() { return 1; } -zone_options_t* -zone_options_create(region_type* region) +zone_options_t* zone_options_create(region_type* region) { zone_options_t* zone; zone = (zone_options_t*)region_alloc(region, sizeof(zone_options_t)); zone->node = *RBTREE_NULL; zone->name = 0; - zone->pattern = 0; - zone->part_of_config = 0; + zone->zonefile = 0; + zone->allow_notify = 0; + zone->request_xfr = 0; + zone->notify = 0; + zone->notify_retry = 5; + zone->provide_xfr = 0; + zone->outgoing_interface = 0; + zone->allow_axfr_fallback = 1; return zone; } -/* true is booleans are the same truth value */ -#define booleq(x,y) ( ((x) && (y)) || (!(x) && !(y)) ) - -int -acl_equal(acl_options_t* p, acl_options_t* q) -{ - if(!booleq(p->use_axfr_only, q->use_axfr_only)) return 0; - if(!booleq(p->allow_udp, q->allow_udp)) return 0; - if(strcmp(p->ip_address_spec, q->ip_address_spec)!=0) return 0; - /* the ip6, port, addr, mask, type: are derived from the ip_address_spec */ - if(!booleq(p->nokey, q->nokey)) return 0; - if(!booleq(p->blocked, q->blocked)) return 0; - if(p->key_name && q->key_name) { - if(strcmp(p->key_name, q->key_name)!=0) return 0; - } else if(p->key_name && !q->key_name) return 0; - else if(!p->key_name && q->key_name) return 0; - /* key_options is derived from key_name */ - return 1; -} - -int -acl_list_equal(acl_options_t* p, acl_options_t* q) -{ - /* must be same and in same order */ - while(p && q) { - if(!acl_equal(p, q)) - return 0; - p = p->next; - q = q->next; - } - if(!p && !q) return 1; - /* different lengths */ - return 0; -} - -pattern_options_t* -pattern_options_create(region_type* region) -{ - pattern_options_t* p; - p = (pattern_options_t*)region_alloc(region, sizeof(pattern_options_t)); - p->node = *RBTREE_NULL; - p->pname = 0; - p->zonefile = 0; - p->zonestats = 0; - p->allow_notify = 0; - p->request_xfr = 0; - p->notify = 0; - p->provide_xfr = 0; - p->outgoing_interface = 0; - p->notify_retry = 5; - p->notify_retry_is_default = 1; - p->allow_axfr_fallback = 1; - p->allow_axfr_fallback_is_default = 1; - p->implicit = 0; - p->xfrd_flags = 0; -#ifdef RATELIMIT - p->rrl_whitelist = 0; -#endif - return p; -} - -static void -acl_delete(region_type* region, acl_options_t* acl) -{ - if(acl->ip_address_spec) - region_recycle(region, (void*)acl->ip_address_spec, - strlen(acl->ip_address_spec)+1); - if(acl->key_name) - region_recycle(region, (void*)acl->key_name, - strlen(acl->key_name)+1); - /* key_options is a convenience pointer, not owned by the acl */ - region_recycle(region, acl, sizeof(*acl)); -} - -static void -acl_list_delete(region_type* region, acl_options_t* list) -{ - acl_options_t* n; - while(list) { - n = list->next; - acl_delete(region, list); - list = n; - } -} - -void -pattern_options_remove(nsd_options_t* opt, const char* name) -{ - pattern_options_t* p = (pattern_options_t*)rbtree_delete( - opt->patterns, name); - /* delete p and its contents */ - if (!p) - return; - if(p->pname) - region_recycle(opt->region, (void*)p->pname, - strlen(p->pname)+1); - if(p->zonefile) - region_recycle(opt->region, (void*)p->zonefile, - strlen(p->zonefile)+1); - if(p->zonestats) - region_recycle(opt->region, (void*)p->zonestats, - strlen(p->zonestats)+1); - acl_list_delete(opt->region, p->allow_notify); - acl_list_delete(opt->region, p->request_xfr); - acl_list_delete(opt->region, p->notify); - acl_list_delete(opt->region, p->provide_xfr); - acl_list_delete(opt->region, p->outgoing_interface); - - region_recycle(opt->region, p, sizeof(pattern_options_t)); -} - -static acl_options_t* -copy_acl(region_type* region, acl_options_t* a) -{ - acl_options_t* b; - if(!a) return NULL; - b = (acl_options_t*)region_alloc(region, sizeof(*b)); - /* copy the whole lot */ - *b = *a; - /* fix the pointers */ - if(a->ip_address_spec) - b->ip_address_spec = region_strdup(region, a->ip_address_spec); - if(a->key_name) - b->key_name = region_strdup(region, a->key_name); - b->next = NULL; - b->key_options = NULL; - return b; -} - -static acl_options_t* -copy_acl_list(nsd_options_t* opt, acl_options_t* a) -{ - acl_options_t* b, *blast = NULL, *blist = NULL; - while(a) { - b = copy_acl(opt->region, a); - /* fixup key_options */ - if(b->key_name) - b->key_options = key_options_find(opt, b->key_name); - else b->key_options = NULL; - - /* link as last into list */ - b->next = NULL; - if(!blist) blist = b; - else blast->next = b; - blast = b; - - a = a->next; - } - return blist; -} - -static void -copy_changed_acl(nsd_options_t* opt, acl_options_t** orig, - acl_options_t* anew) -{ - if(!acl_list_equal(*orig, anew)) { - acl_list_delete(opt->region, *orig); - *orig = copy_acl_list(opt, anew); - } -} - -static void -copy_pat_fixed(region_type* region, pattern_options_t* orig, - pattern_options_t* p) -{ - orig->allow_axfr_fallback = p->allow_axfr_fallback; - orig->allow_axfr_fallback_is_default = - p->allow_axfr_fallback_is_default; - orig->notify_retry = p->notify_retry; - orig->notify_retry_is_default = p->notify_retry_is_default; - orig->implicit = p->implicit; - if(p->zonefile) - orig->zonefile = region_strdup(region, p->zonefile); - else orig->zonefile = NULL; - if(p->zonestats) - orig->zonestats = region_strdup(region, p->zonestats); - else orig->zonestats = NULL; -#ifdef RATELIMIT - orig->rrl_whitelist = p->rrl_whitelist; -#endif -} - -void -pattern_options_add_modify(nsd_options_t* opt, pattern_options_t* p) -{ - pattern_options_t* orig = pattern_options_find(opt, p->pname); - if(!orig) { - /* needs to be copied to opt region */ - orig = pattern_options_create(opt->region); - orig->pname = region_strdup(opt->region, p->pname); - copy_pat_fixed(opt->region, orig, p); - orig->allow_notify = copy_acl_list(opt, p->allow_notify); - orig->request_xfr = copy_acl_list(opt, p->request_xfr); - orig->notify = copy_acl_list(opt, p->notify); - orig->provide_xfr = copy_acl_list(opt, p->provide_xfr); - orig->outgoing_interface = copy_acl_list(opt, - p->outgoing_interface); - nsd_options_insert_pattern(opt, orig); - } else { - /* modify in place so pointers stay valid (and copy - into region). Do not touch unchanged acls. */ - if(orig->zonefile) - region_recycle(opt->region, (char*)orig->zonefile, - strlen(orig->zonefile)+1); - if(orig->zonestats) - region_recycle(opt->region, (char*)orig->zonestats, - strlen(orig->zonestats)+1); - copy_pat_fixed(opt->region, orig, p); - copy_changed_acl(opt, &orig->allow_notify, p->allow_notify); - copy_changed_acl(opt, &orig->request_xfr, p->request_xfr); - copy_changed_acl(opt, &orig->notify, p->notify); - copy_changed_acl(opt, &orig->provide_xfr, p->provide_xfr); - copy_changed_acl(opt, &orig->outgoing_interface, - p->outgoing_interface); - } -} - -pattern_options_t* -pattern_options_find(nsd_options_t* opt, const char* name) -{ - return (pattern_options_t*)rbtree_search(opt->patterns, name); -} - -int -pattern_options_equal(pattern_options_t* p, pattern_options_t* q) -{ - if(strcmp(p->pname, q->pname) != 0) return 0; - if(!p->zonefile && q->zonefile) return 0; - else if(p->zonefile && !q->zonefile) return 0; - else if(p->zonefile && q->zonefile) { - if(strcmp(p->zonefile, q->zonefile) != 0) return 0; - } - if(!p->zonestats && q->zonestats) return 0; - else if(p->zonestats && !q->zonestats) return 0; - else if(p->zonestats && q->zonestats) { - if(strcmp(p->zonestats, q->zonestats) != 0) return 0; - } - if(!booleq(p->allow_axfr_fallback, q->allow_axfr_fallback)) return 0; - if(!booleq(p->allow_axfr_fallback_is_default, - q->allow_axfr_fallback_is_default)) return 0; - if(p->notify_retry != q->notify_retry) return 0; - if(!booleq(p->notify_retry_is_default, - q->notify_retry_is_default)) return 0; - if(!booleq(p->implicit, q->implicit)) return 0; - if(!acl_list_equal(p->allow_notify, q->allow_notify)) return 0; - if(!acl_list_equal(p->request_xfr, q->request_xfr)) return 0; - if(!acl_list_equal(p->notify, q->notify)) return 0; - if(!acl_list_equal(p->provide_xfr, q->provide_xfr)) return 0; - if(!acl_list_equal(p->outgoing_interface, q->outgoing_interface)) - return 0; -#ifdef RATELIMIT - if(p->rrl_whitelist != q->rrl_whitelist) return 0; -#endif - return 1; -} - -static void -marshal_u8(struct buffer* b, uint8_t v) -{ - buffer_reserve(b, 1); - buffer_write_u8(b, v); -} - -static uint8_t -unmarshal_u8(struct buffer* b) -{ - return buffer_read_u8(b); -} - -#ifdef RATELIMIT -static void -marshal_u16(struct buffer* b, uint16_t v) -{ - buffer_reserve(b, 2); - buffer_write_u16(b, v); -} -#endif - -#ifdef RATELIMIT -static uint16_t -unmarshal_u16(struct buffer* b) -{ - return buffer_read_u16(b); -} -#endif - -static void -marshal_str(struct buffer* b, const char* s) -{ - if(!s) marshal_u8(b, 0); - else { - size_t len = strlen(s); - marshal_u8(b, 1); - buffer_reserve(b, len+1); - buffer_write(b, s, len+1); - } -} - -static char* -unmarshal_str(region_type* r, struct buffer* b) -{ - uint8_t nonnull = unmarshal_u8(b); - if(nonnull) { - char* result = region_strdup(r, (char*)buffer_current(b)); - size_t len = strlen((char*)buffer_current(b)); - buffer_skip(b, len+1); - return result; - } else return NULL; -} - -static void -marshal_acl(struct buffer* b, acl_options_t* acl) -{ - buffer_reserve(b, sizeof(*acl)); - buffer_write(b, acl, sizeof(*acl)); - marshal_str(b, acl->ip_address_spec); - marshal_str(b, acl->key_name); -} - -static acl_options_t* -unmarshal_acl(region_type* r, struct buffer* b) -{ - acl_options_t* acl = (acl_options_t*)region_alloc(r, sizeof(*acl)); - buffer_read(b, acl, sizeof(*acl)); - acl->next = NULL; - acl->key_options = NULL; - acl->ip_address_spec = unmarshal_str(r, b); - acl->key_name = unmarshal_str(r, b); - return acl; -} - -static void -marshal_acl_list(struct buffer* b, acl_options_t* list) -{ - while(list) { - marshal_u8(b, 1); /* is there a next one marker */ - marshal_acl(b, list); - list = list->next; - } - marshal_u8(b, 0); /* end of list marker */ -} - -static acl_options_t* -unmarshal_acl_list(region_type* r, struct buffer* b) -{ - acl_options_t* a, *last=NULL, *list=NULL; - while(unmarshal_u8(b)) { - a = unmarshal_acl(r, b); - /* link in */ - a->next = NULL; - if(!list) list = a; - else last->next = a; - last = a; - } - return list; -} - -void -pattern_options_marshal(struct buffer* b, pattern_options_t* p) -{ - marshal_str(b, p->pname); - marshal_str(b, p->zonefile); - marshal_str(b, p->zonestats); -#ifdef RATELIMIT - marshal_u16(b, p->rrl_whitelist); -#endif - marshal_u8(b, p->allow_axfr_fallback); - marshal_u8(b, p->allow_axfr_fallback_is_default); - marshal_u8(b, p->notify_retry); - marshal_u8(b, p->notify_retry_is_default); - marshal_u8(b, p->implicit); - marshal_acl_list(b, p->allow_notify); - marshal_acl_list(b, p->request_xfr); - marshal_acl_list(b, p->notify); - marshal_acl_list(b, p->provide_xfr); - marshal_acl_list(b, p->outgoing_interface); -} - -pattern_options_t* -pattern_options_unmarshal(region_type* r, struct buffer* b) -{ - pattern_options_t* p = pattern_options_create(r); - p->pname = unmarshal_str(r, b); - p->zonefile = unmarshal_str(r, b); - p->zonestats = unmarshal_str(r, b); -#ifdef RATELIMIT - p->rrl_whitelist = unmarshal_u16(b); -#endif - p->allow_axfr_fallback = unmarshal_u8(b); - p->allow_axfr_fallback_is_default = unmarshal_u8(b); - p->notify_retry = unmarshal_u8(b); - p->notify_retry_is_default = unmarshal_u8(b); - p->implicit = unmarshal_u8(b); - p->allow_notify = unmarshal_acl_list(r, b); - p->request_xfr = unmarshal_acl_list(r, b); - p->notify = unmarshal_acl_list(r, b); - p->provide_xfr = unmarshal_acl_list(r, b); - p->outgoing_interface = unmarshal_acl_list(r, b); - return p; -} - -key_options_t* -key_options_create(region_type* region) +key_options_t* key_options_create(region_type* region) { key_options_t* key; - key = (key_options_t*)region_alloc_zero(region, sizeof(key_options_t)); + key = (key_options_t*)region_alloc(region, sizeof(key_options_t)); + key->name = 0; + key->next = 0; + key->algorithm = 0; + key->secret = 0; +#ifdef TSIG + key->tsig_key = 0; +#endif return key; } -void -key_options_insert(nsd_options_t* opt, key_options_t* key) -{ - if(!key->name) return; - key->node.key = key->name; - (void)rbtree_insert(opt->keys, &key->node); -} - -key_options_t* -key_options_find(nsd_options_t* opt, const char* name) -{ - return (key_options_t*)rbtree_search(opt->keys, name); -} - -/** remove tsig_key contents */ -void -key_options_desetup(region_type* region, key_options_t* key) +key_options_t* key_options_find(nsd_options_t* opt, const char* name) { - /* keep tsig_key pointer so that existing references keep valid */ - if(!key->tsig_key) - return; - /* name stays the same */ - if(key->tsig_key->data) { - /* wipe secret! */ - memset(key->tsig_key->data, 0xdd, key->tsig_key->size); - region_recycle(region, key->tsig_key->data, - key->tsig_key->size); - key->tsig_key->data = NULL; - key->tsig_key->size = 0; - } -} - -/** add tsig_key contents */ -void -key_options_setup(region_type* region, key_options_t* key) -{ - uint8_t data[16384]; /* 16KB */ - int size; - if(!key->tsig_key) { - /* create it */ - key->tsig_key = (tsig_key_type *) region_alloc(region, - sizeof(tsig_key_type)); - /* create name */ - key->tsig_key->name = dname_parse(region, key->name); - if(!key->tsig_key->name) { - log_msg(LOG_ERR, "Failed to parse tsig key name %s", - key->name); - /* key and base64 were checked during syntax parse */ - exit(1); - } - key->tsig_key->size = 0; - key->tsig_key->data = NULL; - } - size = b64_pton(key->secret, data, sizeof(data)); - if(size == -1) { - log_msg(LOG_ERR, "Failed to parse tsig key data %s", - key->name); - /* key and base64 were checked during syntax parse */ - exit(1); - } - key->tsig_key->size = size; - key->tsig_key->data = (uint8_t *)region_alloc_init(region, data, size); -} - -void -key_options_remove(nsd_options_t* opt, const char* name) -{ - key_options_t* k = key_options_find(opt, name); - if(!k) return; - (void)rbtree_delete(opt->keys, name); - if(k->name) - region_recycle(opt->region, k->name, strlen(k->name)+1); - if(k->algorithm) - region_recycle(opt->region, k->algorithm, strlen(k->algorithm)+1); - if(k->secret) { - memset(k->secret, 0xdd, strlen(k->secret)); /* wipe secret! */ - region_recycle(opt->region, k->secret, strlen(k->secret)+1); - } - if(k->tsig_key) { - tsig_del_key(k->tsig_key); - if(k->tsig_key->name) - region_recycle(opt->region, (void*)k->tsig_key->name, - dname_total_size(k->tsig_key->name)); - key_options_desetup(opt->region, k); - region_recycle(opt->region, k->tsig_key, sizeof(tsig_key_type)); - } - region_recycle(opt->region, k, sizeof(key_options_t)); -} - -int -key_options_equal(key_options_t* p, key_options_t* q) -{ - return strcmp(p->name, q->name)==0 && strcmp(p->algorithm, - q->algorithm)==0 && strcmp(p->secret, q->secret)==0; -} - -void -key_options_add_modify(nsd_options_t* opt, key_options_t* key) -{ - key_options_t* orig = key_options_find(opt, key->name); - if(!orig) { - /* needs to be copied to opt region */ - orig = key_options_create(opt->region); - orig->name = region_strdup(opt->region, key->name); - orig->algorithm = region_strdup(opt->region, key->algorithm); - orig->secret = region_strdup(opt->region, key->secret); - key_options_setup(opt->region, orig); - tsig_add_key(orig->tsig_key); - key_options_insert(opt, orig); - } else { - /* modify entries in existing key, and copy to opt region */ - key_options_desetup(opt->region, orig); - region_recycle(opt->region, orig->algorithm, - strlen(orig->algorithm)+1); - orig->algorithm = region_strdup(opt->region, key->algorithm); - region_recycle(opt->region, orig->secret, - strlen(orig->secret)+1); - orig->secret = region_strdup(opt->region, key->secret); - key_options_setup(opt->region, orig); + key_options_t* key = opt->keys; + while(key) { + if(strcmp(key->name, name)==0) + return key; + key = key->next; } + return 0; } -int -acl_check_incoming(acl_options_t* acl, struct query* q, +int acl_check_incoming(acl_options_t* acl, struct query* q, acl_options_t** reason) { /* check each acl element. @@ -1308,96 +295,37 @@ acl_check_incoming(acl_options_t* acl, struct query* q, return found_match; } -#ifdef INET6 -int -acl_addr_matches_ipv6host(acl_options_t* acl, struct sockaddr_storage* addr_storage, unsigned int port) -{ - struct sockaddr_in6* addr = (struct sockaddr_in6*)addr_storage; - if(acl->port != 0 && acl->port != port) - return 0; - switch(acl->rangetype) { - case acl_range_mask: - case acl_range_subnet: - if(!acl_addr_match_mask((uint32_t*)&acl->addr.addr6, (uint32_t*)&addr->sin6_addr, - (uint32_t*)&acl->range_mask.addr6, sizeof(struct in6_addr))) - return 0; - break; - case acl_range_minmax: - if(!acl_addr_match_range((uint32_t*)&acl->addr.addr6, (uint32_t*)&addr->sin6_addr, - (uint32_t*)&acl->range_mask.addr6, sizeof(struct in6_addr))) - return 0; - break; - case acl_range_single: - default: - if(memcmp(&addr->sin6_addr, &acl->addr.addr6, - sizeof(struct in6_addr)) != 0) - return 0; - break; - } - return 1; -} -#endif - -int -acl_addr_matches_ipv4host(acl_options_t* acl, struct sockaddr_in* addr, unsigned int port) -{ - if(acl->port != 0 && acl->port != port) - return 0; - switch(acl->rangetype) { - case acl_range_mask: - case acl_range_subnet: - if(!acl_addr_match_mask((uint32_t*)&acl->addr.addr, (uint32_t*)&addr->sin_addr, - (uint32_t*)&acl->range_mask.addr, sizeof(struct in_addr))) - return 0; - break; - case acl_range_minmax: - if(!acl_addr_match_range((uint32_t*)&acl->addr.addr, (uint32_t*)&addr->sin_addr, - (uint32_t*)&acl->range_mask.addr, sizeof(struct in_addr))) - return 0; - break; - case acl_range_single: - default: - if(memcmp(&addr->sin_addr, &acl->addr.addr, - sizeof(struct in_addr)) != 0) - return 0; - break; - } - return 1; -} - -int -acl_addr_matches_host(acl_options_t* acl, acl_options_t* host) -{ - if(acl->is_ipv6) - { -#ifdef INET6 - struct sockaddr_storage* addr = (struct sockaddr_storage*)&host->addr; - if(!host->is_ipv6) return 0; - return acl_addr_matches_ipv6host(acl, addr, host->port); -#else - return 0; /* no inet6, no match */ -#endif - } - else - { - struct sockaddr_in* addr = (struct sockaddr_in*)&host->addr; - if(host->is_ipv6) return 0; - return acl_addr_matches_ipv4host(acl, addr, host->port); - } - /* ENOTREACH */ - return 0; -} - -int -acl_addr_matches(acl_options_t* acl, struct query* q) +int acl_addr_matches(acl_options_t* acl, struct query* q) { if(acl->is_ipv6) { #ifdef INET6 - struct sockaddr_storage* addr = (struct sockaddr_storage*)&q->addr; - if(addr->ss_family != AF_INET6) + struct sockaddr_storage* addr_storage = (struct sockaddr_storage*)&q->addr; + struct sockaddr_in6* addr = (struct sockaddr_in6*)&q->addr; + if(addr_storage->ss_family != AF_INET6) return 0; - return acl_addr_matches_ipv6host(acl, addr, ntohs(((struct sockaddr_in6*)addr)->sin6_port)); + if(acl->port != 0 && acl->port != ntohs(addr->sin6_port)) + return 0; + switch(acl->rangetype) { + case acl_range_mask: + case acl_range_subnet: + if(!acl_addr_match_mask((uint32_t*)&acl->addr.addr6, (uint32_t*)&addr->sin6_addr, + (uint32_t*)&acl->range_mask.addr6, sizeof(struct in6_addr))) + return 0; + break; + case acl_range_minmax: + if(!acl_addr_match_range((uint32_t*)&acl->addr.addr6, (uint32_t*)&addr->sin6_addr, + (uint32_t*)&acl->range_mask.addr6, sizeof(struct in6_addr))) + return 0; + break; + case acl_range_single: + default: + if(memcmp(&addr->sin6_addr, &acl->addr.addr6, + sizeof(struct in6_addr)) != 0) + return 0; + break; + } + return 1; #else return 0; /* no inet6, no match */ #endif @@ -1407,14 +335,34 @@ acl_addr_matches(acl_options_t* acl, struct query* q) struct sockaddr_in* addr = (struct sockaddr_in*)&q->addr; if(addr->sin_family != AF_INET) return 0; - return acl_addr_matches_ipv4host(acl, addr, ntohs(addr->sin_port)); + if(acl->port != 0 && acl->port != ntohs(addr->sin_port)) + return 0; + switch(acl->rangetype) { + case acl_range_mask: + case acl_range_subnet: + if(!acl_addr_match_mask((uint32_t*)&acl->addr.addr, (uint32_t*)&addr->sin_addr, + (uint32_t*)&acl->range_mask.addr, sizeof(struct in_addr))) + return 0; + break; + case acl_range_minmax: + if(!acl_addr_match_range((uint32_t*)&acl->addr.addr, (uint32_t*)&addr->sin_addr, + (uint32_t*)&acl->range_mask.addr, sizeof(struct in_addr))) + return 0; + break; + case acl_range_single: + default: + if(memcmp(&addr->sin_addr, &acl->addr.addr, + sizeof(struct in_addr)) != 0) + return 0; + break; + } + return 1; } /* ENOTREACH */ return 0; } -int -acl_addr_match_mask(uint32_t* a, uint32_t* b, uint32_t* mask, size_t sz) +int acl_addr_match_mask(uint32_t* a, uint32_t* b, uint32_t* mask, size_t sz) { size_t i; #ifndef NDEBUG @@ -1430,8 +378,7 @@ acl_addr_match_mask(uint32_t* a, uint32_t* b, uint32_t* mask, size_t sz) return 1; } -int -acl_addr_match_range(uint32_t* minval, uint32_t* x, uint32_t* maxval, size_t sz) +int acl_addr_match_range(uint32_t* minval, uint32_t* x, uint32_t* maxval, size_t sz) { size_t i; uint8_t checkmin = 1, checkmax = 1; @@ -1460,11 +407,11 @@ acl_addr_match_range(uint32_t* minval, uint32_t* x, uint32_t* maxval, size_t sz) return 1; } -int -acl_key_matches(acl_options_t* acl, struct query* q) +int acl_key_matches(acl_options_t* acl, struct query* q) { if(acl->blocked) return 1; +#ifdef TSIG if(acl->nokey) { if(q->tsig.status == TSIG_NOT_PRESENT) return 1; @@ -1494,6 +441,11 @@ acl_key_matches(acl_options_t* acl, struct query* q) return 0; /* no such algo */ } return 1; +#else + if(acl->nokey) + return 1; + return 0; +#endif } int @@ -1531,132 +483,43 @@ acl_same_host(acl_options_t* a, acl_options_t* b) return 1; } -#if defined(HAVE_SSL) -void -key_options_tsig_add(nsd_options_t* opt) +void key_options_tsig_add(nsd_options_t* opt) { +#if defined(TSIG) && defined(HAVE_SSL) key_options_t* optkey; - RBTREE_FOR(optkey, key_options_t*, opt->keys) { - key_options_setup(opt->region, optkey); - tsig_add_key(optkey->tsig_key); - } -} -#endif - -int -zone_is_slave(zone_options_t* opt) -{ - return opt && opt->pattern && opt->pattern->request_xfr != 0; -} + uint8_t data[4000]; + tsig_key_type* tsigkey; + const dname_type* dname; + int size; -/* get a character in string (or replacement char if not long enough) */ -static const char* -get_char(const char* str, size_t i) -{ - static char res[2]; - if(i >= strlen(str)) - return "."; - res[0] = str[i]; - res[1] = 0; - return res; -} -/* get end label of the zone name (or .) */ -static const char* -get_end_label(zone_options_t* zone, int i) -{ - const dname_type* d = (const dname_type*)zone->node.key; - if(i >= d->label_count) { - return "."; - } - return wirelabel2str(dname_label(d, i)); -} -/* replace occurrences of one with two */ -void -replace_str(char* str, size_t len, const char* one, const char* two) -{ - char* pos; - char* at = str; - while( (pos=strstr(at, one)) ) { - if(strlen(str)+strlen(two)-strlen(one) >= len) - return; /* no more space to replace */ - /* stuff before pos is fine */ - /* move the stuff after pos to make space for two, add - * one to length of remainder to also copy the 0 byte end */ - memmove(pos+strlen(two), pos+strlen(one), - strlen(pos+strlen(one))+1); - /* copy in two */ - memmove(pos, two, strlen(two)); - /* at is end of the newly inserted two (avoids recursion if - * two contains one) */ - at = pos+strlen(two); + for(optkey = opt->keys; optkey; optkey = optkey->next) + { + dname = dname_parse(opt->region, optkey->name); + if(!dname) { + log_msg(LOG_ERR, "Failed to parse tsig key name %s", optkey->name); + continue; + } + size = b64_pton(optkey->secret, data, sizeof(data)); + if(size == -1) { + log_msg(LOG_ERR, "Failed to parse tsig key data %s", optkey->name); + continue; + } + tsigkey = (tsig_key_type *) region_alloc(opt->region, sizeof(tsig_key_type)); + tsigkey->name = dname; + tsigkey->size = size; + tsigkey->data = (uint8_t *) region_alloc_init(opt->region, data, tsigkey->size); + tsig_add_key(tsigkey); + optkey->tsig_key = tsigkey; } +#endif } -const char* -config_cook_string(zone_options_t* zone, const char* input) +int zone_is_slave(zone_options_t* opt) { - static char f[1024]; - /* if not a template, return as-is */ - if(!strchr(input, '%')) { - return input; - } - strlcpy(f, input, sizeof(f)); - if(strstr(f, "%1")) - replace_str(f, sizeof(f), "%1", get_char(zone->name, 0)); - if(strstr(f, "%2")) - replace_str(f, sizeof(f), "%2", get_char(zone->name, 1)); - if(strstr(f, "%3")) - replace_str(f, sizeof(f), "%3", get_char(zone->name, 2)); - if(strstr(f, "%z")) - replace_str(f, sizeof(f), "%z", get_end_label(zone, 1)); - if(strstr(f, "%y")) - replace_str(f, sizeof(f), "%y", get_end_label(zone, 2)); - if(strstr(f, "%x")) - replace_str(f, sizeof(f), "%x", get_end_label(zone, 3)); - if(strstr(f, "%s")) - replace_str(f, sizeof(f), "%s", zone->name); - return f; + return opt->request_xfr != 0; } -const char* -config_make_zonefile(zone_options_t* zone, struct nsd* nsd) -{ - static char f[1024]; - /* if not a template, return as-is */ - if(!strchr(zone->pattern->zonefile, '%')) { - if (nsd->chrootdir && nsd->chrootdir[0] && - zone->pattern->zonefile && - zone->pattern->zonefile[0] == '/' && - strncmp(zone->pattern->zonefile, nsd->chrootdir, - strlen(nsd->chrootdir)) == 0) - /* -1 because chrootdir ends in trailing slash */ - return zone->pattern->zonefile + strlen(nsd->chrootdir) - 1; - return zone->pattern->zonefile; - } - strlcpy(f, zone->pattern->zonefile, sizeof(f)); - if(strstr(f, "%1")) - replace_str(f, sizeof(f), "%1", get_char(zone->name, 0)); - if(strstr(f, "%2")) - replace_str(f, sizeof(f), "%2", get_char(zone->name, 1)); - if(strstr(f, "%3")) - replace_str(f, sizeof(f), "%3", get_char(zone->name, 2)); - if(strstr(f, "%z")) - replace_str(f, sizeof(f), "%z", get_end_label(zone, 1)); - if(strstr(f, "%y")) - replace_str(f, sizeof(f), "%y", get_end_label(zone, 2)); - if(strstr(f, "%x")) - replace_str(f, sizeof(f), "%x", get_end_label(zone, 3)); - if(strstr(f, "%s")) - replace_str(f, sizeof(f), "%s", zone->name); - if (nsd->chrootdir && nsd->chrootdir[0] && f[0] == '/' && - strncmp(f, nsd->chrootdir, strlen(nsd->chrootdir)) == 0) - /* -1 because chrootdir ends in trailing slash */ - return f + strlen(nsd->chrootdir) - 1; - return f; -} - -zone_options_t* -zone_options_find(nsd_options_t* opt, const struct dname* apex) +zone_options_t* zone_options_find(nsd_options_t* opt, const struct dname* apex) { return (zone_options_t*) rbtree_search(opt->zone_options, apex); } @@ -1677,8 +540,7 @@ acl_find_num(acl_options_t* acl, int num) } /* true if ipv6 address, false if ipv4 */ -int -parse_acl_is_ipv6(const char* p) +int parse_acl_is_ipv6(const char* p) { /* see if addr is ipv6 or ipv4 -- by : and . */ while(*p) { @@ -1690,8 +552,7 @@ parse_acl_is_ipv6(const char* p) } /* returns range type. mask is the 2nd part of the range */ -int -parse_acl_range_type(char* ip, char** mask) +int parse_acl_range_type(char* ip, char** mask) { char *p; if((p=strchr(ip, '&'))!=0) { @@ -1714,8 +575,7 @@ parse_acl_range_type(char* ip, char** mask) } /* parses subnet mask, fills 0 mask as well */ -void -parse_acl_range_subnet(char* p, void* addr, int maxbits) +void parse_acl_range_subnet(char* p, void* addr, int maxbits) { int subnet_bits = atoi(p); uint8_t* addr_bytes = (uint8_t*)addr; @@ -1738,8 +598,7 @@ parse_acl_range_subnet(char* p, void* addr, int maxbits) } } -acl_options_t* -parse_acl_info(region_type* region, char* ip, const char* key) +acl_options_t* parse_acl_info(region_type* region, char* ip, const char* key) { char* p; acl_options_t* acl = (acl_options_t*)region_alloc(region, sizeof(acl_options_t)); @@ -1749,7 +608,6 @@ parse_acl_info(region_type* region, char* ip, const char* key) acl->use_axfr_only = 0; acl->allow_udp = 0; acl->ixfr_disabled = 0; - acl->bad_xfr_count = 0; acl->key_options = 0; acl->is_ipv6 = 0; acl->port = 0; @@ -1802,95 +660,7 @@ parse_acl_info(region_type* region, char* ip, const char* key) return acl; } -/* copy acl list at end of parser start, update current */ -static -void append_acl(acl_options_t** start, acl_options_t** cur, - acl_options_t* list) -{ - while(list) { - acl_options_t* acl = copy_acl(cfg_parser->opt->region, list); - acl->next = NULL; - if(*cur) - (*cur)->next = acl; - else *start = acl; - *cur = acl; - list = list->next; - } -} - -void -config_apply_pattern(const char* name) -{ - /* find the pattern */ - pattern_options_t* pat = pattern_options_find(cfg_parser->opt, name); - pattern_options_t* a = cfg_parser->current_pattern; - if(!pat) { - c_error_msg("could not find pattern %s", name); - return; - } - - /* apply settings */ - if(pat->zonefile) - a->zonefile = region_strdup(cfg_parser->opt->region, - pat->zonefile); - if(pat->zonestats) - a->zonestats = region_strdup(cfg_parser->opt->region, - pat->zonestats); - if(!pat->allow_axfr_fallback_is_default) { - a->allow_axfr_fallback = pat->allow_axfr_fallback; - a->allow_axfr_fallback_is_default = 0; - } - if(!pat->notify_retry_is_default) { - a->notify_retry = pat->notify_retry; - a->notify_retry_is_default = 0; - } -#ifdef RATELIMIT - a->rrl_whitelist |= pat->rrl_whitelist; -#endif - /* append acl items */ - append_acl(&a->allow_notify, &cfg_parser->current_allow_notify, - pat->allow_notify); - append_acl(&a->request_xfr, &cfg_parser->current_request_xfr, - pat->request_xfr); - append_acl(&a->notify, &cfg_parser->current_notify, pat->notify); - append_acl(&a->provide_xfr, &cfg_parser->current_provide_xfr, - pat->provide_xfr); - append_acl(&a->outgoing_interface, &cfg_parser-> - current_outgoing_interface, pat->outgoing_interface); -} - -void -nsd_options_destroy(nsd_options_t* opt) +void nsd_options_destroy(nsd_options_t* opt) { region_destroy(opt->region); } - -unsigned getzonestatid(nsd_options_t* opt, zone_options_t* zopt) -{ -#ifdef USE_ZONE_STATS - const char* statname; - struct zonestatname* n; - rbnode_t* res; - /* try to find the instantiated zonestat name */ - if(!zopt->pattern->zonestats || zopt->pattern->zonestats[0]==0) - return 0; /* no zone stats */ - statname = config_cook_string(zopt, zopt->pattern->zonestats); - res = rbtree_search(opt->zonestatnames, statname); - if(res) - return ((struct zonestatname*)res)->id; - /* create it */ - n = (struct zonestatname*)xalloc(sizeof(*n)); - memset(n, 0, sizeof(*n)); - n->node.key = strdup(statname); - if(!n->node.key) { - log_msg(LOG_ERR, "malloc failed: %s", strerror(errno)); - exit(1); - } - n->id = (unsigned)(opt->zonestatnames->count); - rbtree_insert(opt->zonestatnames, (rbnode_t*)n); - return n->id; -#else /* USE_ZONE_STATS */ - (void)opt; (void)zopt; - return 0; -#endif /* USE_ZONE_STATS */ -} |