xref: /openbsd-src/usr.sbin/nsd/options.c (revision bf87c3c07c3ad89262e2b8cae09f17e70aa9e1ee)
162ac0c33Sjakob /*
262ac0c33Sjakob  * options.c -- options functions.
362ac0c33Sjakob  *
4d3fecca9Ssthen  * Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
562ac0c33Sjakob  *
662ac0c33Sjakob  * See LICENSE for the license.
762ac0c33Sjakob  *
862ac0c33Sjakob  */
92c1ae072Ssthen #include "config.h"
1062ac0c33Sjakob #include <string.h>
1162ac0c33Sjakob #include <stdio.h>
123b24e79eSsthen #include <sys/stat.h>
1362ac0c33Sjakob #include <errno.h>
148d298c9fSsthen #ifdef HAVE_IFADDRS_H
158d298c9fSsthen #include <ifaddrs.h>
168d298c9fSsthen #endif
1762ac0c33Sjakob #include "options.h"
1862ac0c33Sjakob #include "query.h"
1962ac0c33Sjakob #include "tsig.h"
204564029fSflorian #include "ixfr.h"
21d3fecca9Ssthen #include "difffile.h"
222c1ae072Ssthen #include "rrl.h"
23308d2509Sflorian #include "bitset.h"
24*bf87c3c0Sflorian #include "xfrd.h"
2562ac0c33Sjakob 
26d3fecca9Ssthen #include "configparser.h"
27fe5fe5f6Sflorian config_parser_state_type* cfg_parser = 0;
2862ac0c33Sjakob extern FILE* c_in, *c_out;
2962ac0c33Sjakob int c_parse(void);
3062ac0c33Sjakob int c_lex(void);
3162ac0c33Sjakob int c_wrap(void);
32b90bb40eSsthen int c_lex_destroy(void);
33e3d8a0a5Ssthen extern char* c_text;
3462ac0c33Sjakob 
35d3fecca9Ssthen static int
rbtree_strcmp(const void * p1,const void * p2)36d3fecca9Ssthen rbtree_strcmp(const void* p1, const void* p2)
37d3fecca9Ssthen {
389e506f0aSbrad 	if(p1 == NULL && p2 == NULL) return 0;
399e506f0aSbrad 	if(p1 == NULL) return -1;
409e506f0aSbrad 	if(p2 == NULL) return 1;
41d3fecca9Ssthen 	return strcmp((const char*)p1, (const char*)p2);
42d3fecca9Ssthen }
43d3fecca9Ssthen 
44fe5fe5f6Sflorian struct nsd_options*
nsd_options_create(region_type * region)45d3fecca9Ssthen nsd_options_create(region_type* region)
4662ac0c33Sjakob {
47fe5fe5f6Sflorian 	struct nsd_options* opt;
48fe5fe5f6Sflorian 	opt = (struct nsd_options*)region_alloc(region, sizeof(
49fe5fe5f6Sflorian 		struct nsd_options));
5062ac0c33Sjakob 	opt->region = region;
5162ac0c33Sjakob 	opt->zone_options = rbtree_create(region,
5262ac0c33Sjakob 		(int (*)(const void *, const void *)) dname_compare);
53d3fecca9Ssthen 	opt->configfile = NULL;
549e506f0aSbrad 	opt->zonestatnames = rbtree_create(opt->region, rbtree_strcmp);
55d3fecca9Ssthen 	opt->patterns = rbtree_create(region, rbtree_strcmp);
56d3fecca9Ssthen 	opt->keys = rbtree_create(region, rbtree_strcmp);
57063644e9Sflorian 	opt->tls_auths = rbtree_create(region, rbtree_strcmp);
5862ac0c33Sjakob 	opt->ip_addresses = NULL;
5912455795Ssthen 	opt->ip_transparent = 0;
60275a8d89Sflorian 	opt->ip_freebind = 0;
61eab1363eSsthen 	opt->send_buffer_size = 0;
62eab1363eSsthen 	opt->receive_buffer_size = 0;
6362ac0c33Sjakob 	opt->debug_mode = 0;
6462ac0c33Sjakob 	opt->verbosity = 0;
6562ac0c33Sjakob 	opt->hide_version = 0;
66eab1363eSsthen 	opt->hide_identity = 0;
67308d2509Sflorian 	opt->drop_updates = 0;
68d3fecca9Ssthen 	opt->do_ip4 = 1;
69d3fecca9Ssthen 	opt->do_ip6 = 1;
7062ac0c33Sjakob 	opt->identity = 0;
713126abd5Ssthen 	opt->version = 0;
72a8b34139Sjakob 	opt->nsid = 0;
7362ac0c33Sjakob 	opt->logfile = 0;
74ac5517e4Sflorian 	opt->log_only_syslog = 0;
7515ed76cbSbrad 	opt->log_time_ascii = 1;
7615ed76cbSbrad 	opt->round_robin = 0; /* also packet.h::round_robin */
77eaa9872aSflorian 	opt->minimal_responses = 1; /* also packet.h::minimal_responses */
785435475dSsthen 	opt->confine_to_zone = 0;
79eaa9872aSflorian 	opt->refuse_any = 1;
8062ac0c33Sjakob 	opt->server_count = 1;
81308d2509Sflorian 	opt->cpu_affinity = NULL;
82308d2509Sflorian 	opt->service_cpu_affinity = NULL;
83d3fecca9Ssthen 	opt->tcp_count = 100;
84eab1363eSsthen 	opt->tcp_reject_overflow = 0;
8562ac0c33Sjakob 	opt->tcp_query_count = 0;
8662ac0c33Sjakob 	opt->tcp_timeout = TCP_TIMEOUT;
87275a8d89Sflorian 	opt->tcp_mss = 0;
88275a8d89Sflorian 	opt->outgoing_tcp_mss = 0;
8962ac0c33Sjakob 	opt->ipv4_edns_size = EDNS_MAX_MESSAGE_LEN;
9062ac0c33Sjakob 	opt->ipv6_edns_size = EDNS_MAX_MESSAGE_LEN;
9162ac0c33Sjakob 	opt->pidfile = PIDFILE;
9262ac0c33Sjakob 	opt->port = UDP_PORT;
9362ac0c33Sjakob /* deprecated?	opt->port = TCP_PORT; */
94e3d8a0a5Ssthen 	opt->reuseport = 0;
95bc6311d7Sflorian 	opt->xfrd_tcp_max = 128;
96bc6311d7Sflorian 	opt->xfrd_tcp_pipeline = 128;
9762ac0c33Sjakob 	opt->statistics = 0;
9862ac0c33Sjakob 	opt->chroot = 0;
9962ac0c33Sjakob 	opt->username = USER;
10062ac0c33Sjakob 	opt->zonesdir = ZONESDIR;
10162ac0c33Sjakob 	opt->xfrdfile = XFRDFILE;
102d3fecca9Ssthen 	opt->xfrdir = XFRDIR;
103d3fecca9Ssthen 	opt->zonelistfile = ZONELISTFILE;
1042c1ae072Ssthen #ifdef RATELIMIT
1052c1ae072Ssthen 	opt->rrl_size = RRL_BUCKETS;
10612455795Ssthen 	opt->rrl_slip = RRL_SLIP;
10712455795Ssthen 	opt->rrl_ipv4_prefix_length = RRL_IPV4_PREFIX_LENGTH;
10812455795Ssthen 	opt->rrl_ipv6_prefix_length = RRL_IPV6_PREFIX_LENGTH;
1093126abd5Ssthen #  ifdef RATELIMIT_DEFAULT_OFF
1103126abd5Ssthen 	opt->rrl_ratelimit = 0;
1113126abd5Ssthen 	opt->rrl_whitelist_ratelimit = 0;
1123126abd5Ssthen #  else
1133126abd5Ssthen 	opt->rrl_ratelimit = RRL_LIMIT/2;
1142c1ae072Ssthen 	opt->rrl_whitelist_ratelimit = RRL_WLIST_LIMIT/2;
1152c1ae072Ssthen #  endif
1163126abd5Ssthen #endif
117e02bc0dfSflorian #ifdef USE_DNSTAP
118e02bc0dfSflorian 	opt->dnstap_enable = 0;
119e02bc0dfSflorian 	opt->dnstap_socket_path = DNSTAP_SOCKET_PATH;
1203efee2e1Sflorian 	opt->dnstap_ip = "";
1213efee2e1Sflorian 	opt->dnstap_tls = 1;
1223efee2e1Sflorian 	opt->dnstap_tls_server_name = NULL;
1233efee2e1Sflorian 	opt->dnstap_tls_cert_bundle = NULL;
1243efee2e1Sflorian 	opt->dnstap_tls_client_key_file = NULL;
1253efee2e1Sflorian 	opt->dnstap_tls_client_cert_file = NULL;
126e02bc0dfSflorian 	opt->dnstap_send_identity = 0;
127e02bc0dfSflorian 	opt->dnstap_send_version = 0;
128e02bc0dfSflorian 	opt->dnstap_identity = NULL;
129e02bc0dfSflorian 	opt->dnstap_version = NULL;
130e02bc0dfSflorian 	opt->dnstap_log_auth_query_messages = 0;
131e02bc0dfSflorian 	opt->dnstap_log_auth_response_messages = 0;
132e02bc0dfSflorian #endif
133d3fecca9Ssthen 	opt->zonefiles_check = 1;
13415ed76cbSbrad 	opt->zonefiles_write = ZONEFILES_WRITE_INTERVAL;
135d3fecca9Ssthen 	opt->xfrd_reload_timeout = 1;
136eab1363eSsthen 	opt->tls_service_key = NULL;
137eab1363eSsthen 	opt->tls_service_ocsp = NULL;
138eab1363eSsthen 	opt->tls_service_pem = NULL;
139eab1363eSsthen 	opt->tls_port = TLS_PORT;
140063644e9Sflorian 	opt->tls_cert_bundle = NULL;
141b71395eaSflorian 	opt->proxy_protocol_port = NULL;
142214d9bc0Sflorian 	opt->answer_cookie = 1;
143063644e9Sflorian 	opt->cookie_secret = NULL;
144063644e9Sflorian 	opt->cookie_secret_file = CONFIGDIR"/nsd_cookiesecrets.txt";
145d3fecca9Ssthen 	opt->control_enable = 0;
146d3fecca9Ssthen 	opt->control_interface = NULL;
147d3fecca9Ssthen 	opt->control_port = NSD_CONTROL_PORT;
148d3fecca9Ssthen 	opt->server_key_file = CONFIGDIR"/nsd_server.key";
149d3fecca9Ssthen 	opt->server_cert_file = CONFIGDIR"/nsd_server.pem";
150d3fecca9Ssthen 	opt->control_key_file = CONFIGDIR"/nsd_control.key";
151d3fecca9Ssthen 	opt->control_cert_file = CONFIGDIR"/nsd_control.pem";
1523f21e8ccSflorian 
1533f21e8ccSflorian 	opt->verify_enable = 0;
1543f21e8ccSflorian 	opt->verify_ip_addresses = NULL;
1553f21e8ccSflorian 	opt->verify_port = VERIFY_PORT;
1563f21e8ccSflorian 	opt->verify_zones = 1;
1573f21e8ccSflorian 	opt->verifier = NULL;
1583f21e8ccSflorian 	opt->verifier_count = 1;
1593f21e8ccSflorian 	opt->verifier_feed_zone = 1;
1603f21e8ccSflorian 	opt->verifier_timeout = 0;
1613f21e8ccSflorian 
16262ac0c33Sjakob 	return opt;
16362ac0c33Sjakob }
16462ac0c33Sjakob 
165d3fecca9Ssthen int
nsd_options_insert_zone(struct nsd_options * opt,struct zone_options * zone)166fe5fe5f6Sflorian nsd_options_insert_zone(struct nsd_options* opt, struct zone_options* zone)
16762ac0c33Sjakob {
16862ac0c33Sjakob 	/* create dname for lookup */
16962ac0c33Sjakob 	const dname_type* dname = dname_parse(opt->region, zone->name);
17062ac0c33Sjakob 	if(!dname)
17162ac0c33Sjakob 		return 0;
17262ac0c33Sjakob 	zone->node.key = dname;
173fe5fe5f6Sflorian 	if(!rbtree_insert(opt->zone_options, (rbnode_type*)zone))
17462ac0c33Sjakob 		return 0;
17562ac0c33Sjakob 	return 1;
17662ac0c33Sjakob }
17762ac0c33Sjakob 
178d3fecca9Ssthen int
nsd_options_insert_pattern(struct nsd_options * opt,struct pattern_options * pat)179fe5fe5f6Sflorian nsd_options_insert_pattern(struct nsd_options* opt,
180fe5fe5f6Sflorian 	struct pattern_options* pat)
181d3fecca9Ssthen {
182d3fecca9Ssthen 	if(!pat->pname)
183d3fecca9Ssthen 		return 0;
184d3fecca9Ssthen 	pat->node.key = pat->pname;
185fe5fe5f6Sflorian 	if(!rbtree_insert(opt->patterns, (rbnode_type*)pat))
186d3fecca9Ssthen 		return 0;
187d3fecca9Ssthen 	return 1;
188d3fecca9Ssthen }
189d3fecca9Ssthen 
1903b24e79eSsthen void
warn_if_directory(const char * filetype,FILE * f,const char * fname)1913b24e79eSsthen warn_if_directory(const char* filetype, FILE* f, const char* fname)
1923b24e79eSsthen {
1933b24e79eSsthen 	if(fileno(f) != -1) {
1943b24e79eSsthen 		struct stat st;
1953b24e79eSsthen 		memset(&st, 0, sizeof(st));
1963b24e79eSsthen 		if(fstat(fileno(f), &st) != -1) {
1973b24e79eSsthen 			if(S_ISDIR(st.st_mode)) {
1983b24e79eSsthen 				log_msg(LOG_WARNING, "trying to read %s but it is a directory: %s", filetype, fname);
1993b24e79eSsthen 			}
2003b24e79eSsthen 		}
2013b24e79eSsthen 	}
2023b24e79eSsthen }
2033b24e79eSsthen 
204d3fecca9Ssthen int
parse_options_file(struct nsd_options * opt,const char * file,void (* err)(void *,const char *),void * err_arg,struct nsd_options * old_opts)205fe5fe5f6Sflorian parse_options_file(struct nsd_options* opt, const char* file,
206*bf87c3c0Sflorian 	void (*err)(void*,const char*), void* err_arg,
207*bf87c3c0Sflorian 	struct nsd_options* old_opts)
20862ac0c33Sjakob {
20962ac0c33Sjakob 	FILE *in = 0;
210fe5fe5f6Sflorian 	struct pattern_options* pat;
211fe5fe5f6Sflorian 	struct acl_options* acl;
21262ac0c33Sjakob 
213d3fecca9Ssthen 	if(!cfg_parser) {
214fe5fe5f6Sflorian 		cfg_parser = (config_parser_state_type*)region_alloc(
215fe5fe5f6Sflorian 			opt->region, sizeof(config_parser_state_type));
216d3fecca9Ssthen 		cfg_parser->chroot = 0;
217d3fecca9Ssthen 	}
218d3fecca9Ssthen 	cfg_parser->err = err;
219d3fecca9Ssthen 	cfg_parser->err_arg = err_arg;
22015ed76cbSbrad 	cfg_parser->filename = (char*)file;
22162ac0c33Sjakob 	cfg_parser->line = 1;
22262ac0c33Sjakob 	cfg_parser->errors = 0;
22362ac0c33Sjakob 	cfg_parser->opt = opt;
2245435475dSsthen 	cfg_parser->pattern = NULL;
2255435475dSsthen 	cfg_parser->zone = NULL;
2265435475dSsthen 	cfg_parser->key = NULL;
227063644e9Sflorian 	cfg_parser->tls_auth = NULL;
22862ac0c33Sjakob 
22962ac0c33Sjakob 	in = fopen(cfg_parser->filename, "r");
23062ac0c33Sjakob 	if(!in) {
231d3fecca9Ssthen 		if(err) {
232d3fecca9Ssthen 			char m[MAXSYSLOGMSGLEN];
233d3fecca9Ssthen 			snprintf(m, sizeof(m), "Could not open %s: %s\n",
234d3fecca9Ssthen 				file, strerror(errno));
235d3fecca9Ssthen 			err(err_arg, m);
236d3fecca9Ssthen 		} else {
237d3fecca9Ssthen 			fprintf(stderr, "Could not open %s: %s\n",
238d3fecca9Ssthen 				file, strerror(errno));
239d3fecca9Ssthen 		}
24062ac0c33Sjakob 		return 0;
24162ac0c33Sjakob 	}
2423b24e79eSsthen 	warn_if_directory("configfile", in, file);
24362ac0c33Sjakob 	c_in = in;
24462ac0c33Sjakob 	c_parse();
24562ac0c33Sjakob 	fclose(in);
24662ac0c33Sjakob 
247d3fecca9Ssthen 	opt->configfile = region_strdup(opt->region, file);
2485435475dSsthen 
249fe5fe5f6Sflorian 	RBTREE_FOR(pat, struct pattern_options*, opt->patterns)
25062ac0c33Sjakob 	{
251*bf87c3c0Sflorian 		struct pattern_options* old_pat =
252*bf87c3c0Sflorian 			old_opts ? pattern_options_find(old_opts, pat->pname)
253*bf87c3c0Sflorian 			         : NULL;
254*bf87c3c0Sflorian 
25562ac0c33Sjakob 		/* lookup keys for acls */
256d3fecca9Ssthen 		for(acl=pat->allow_notify; acl; acl=acl->next)
25762ac0c33Sjakob 		{
25862ac0c33Sjakob 			if(acl->nokey || acl->blocked)
25962ac0c33Sjakob 				continue;
26062ac0c33Sjakob 			acl->key_options = key_options_find(opt, acl->key_name);
26162ac0c33Sjakob 			if(!acl->key_options)
2625435475dSsthen 				c_error("key %s in pattern %s could not be found",
263d3fecca9Ssthen 					acl->key_name, pat->pname);
26462ac0c33Sjakob 		}
265d3fecca9Ssthen 		for(acl=pat->notify; acl; acl=acl->next)
26662ac0c33Sjakob 		{
26762ac0c33Sjakob 			if(acl->nokey || acl->blocked)
26862ac0c33Sjakob 				continue;
26962ac0c33Sjakob 			acl->key_options = key_options_find(opt, acl->key_name);
27062ac0c33Sjakob 			if(!acl->key_options)
2715435475dSsthen 				c_error("key %s in pattern %s could not be found",
272d3fecca9Ssthen 					acl->key_name, pat->pname);
27362ac0c33Sjakob 		}
274d3fecca9Ssthen 		for(acl=pat->request_xfr; acl; acl=acl->next)
27562ac0c33Sjakob 		{
276063644e9Sflorian 			/* Find tls_auth */
277063644e9Sflorian 			if (!acl->tls_auth_name)
278063644e9Sflorian 				; /* pass */
279063644e9Sflorian 			else if (!(acl->tls_auth_options =
280063644e9Sflorian 			                tls_auth_options_find(opt, acl->tls_auth_name)))
281063644e9Sflorian 				c_error("tls_auth %s in pattern %s could not be found",
282063644e9Sflorian 						acl->tls_auth_name, pat->pname);
283063644e9Sflorian 			/* Find key */
28462ac0c33Sjakob 			if(acl->nokey || acl->blocked)
28562ac0c33Sjakob 				continue;
28662ac0c33Sjakob 			acl->key_options = key_options_find(opt, acl->key_name);
28762ac0c33Sjakob 			if(!acl->key_options)
2885435475dSsthen 				c_error("key %s in pattern %s could not be found",
289d3fecca9Ssthen 					acl->key_name, pat->pname);
29062ac0c33Sjakob 		}
291d3fecca9Ssthen 		for(acl=pat->provide_xfr; acl; acl=acl->next)
29262ac0c33Sjakob 		{
29362ac0c33Sjakob 			if(acl->nokey || acl->blocked)
29462ac0c33Sjakob 				continue;
29562ac0c33Sjakob 			acl->key_options = key_options_find(opt, acl->key_name);
29662ac0c33Sjakob 			if(!acl->key_options)
2975435475dSsthen 				c_error("key %s in pattern %s could not be found",
298d3fecca9Ssthen 					acl->key_name, pat->pname);
29962ac0c33Sjakob 		}
3008d298c9fSsthen 		for(acl=pat->allow_query; acl; acl=acl->next)
3018d298c9fSsthen 		{
3028d298c9fSsthen 			if(acl->nokey || acl->blocked)
3038d298c9fSsthen 				continue;
3048d298c9fSsthen 			acl->key_options = key_options_find(opt, acl->key_name);
3058d298c9fSsthen 			if(!acl->key_options)
3068d298c9fSsthen 				c_error("key %s in pattern %s could not be found",
3078d298c9fSsthen 					acl->key_name, pat->pname);
3088d298c9fSsthen 		}
309*bf87c3c0Sflorian 		/* lookup zones for catalog-producer-zone options */
310*bf87c3c0Sflorian 		if(pat->catalog_producer_zone) {
311*bf87c3c0Sflorian 			struct zone_options* zopt;
312*bf87c3c0Sflorian 			const dname_type *dname = dname_parse(opt->region,
313*bf87c3c0Sflorian 					pat->catalog_producer_zone);
314*bf87c3c0Sflorian 			if(dname == NULL) {
315*bf87c3c0Sflorian 				; /* pass; already erred during parsing */
316*bf87c3c0Sflorian 
317*bf87c3c0Sflorian 			} else if (!(zopt = zone_options_find(opt, dname))) {
318*bf87c3c0Sflorian 				c_error("catalog producer zone %s in pattern "
319*bf87c3c0Sflorian 					"%s could not be found",
320*bf87c3c0Sflorian 					pat->catalog_producer_zone,
321*bf87c3c0Sflorian 					pat->pname);
322*bf87c3c0Sflorian 
323*bf87c3c0Sflorian 			} else if (!zone_is_catalog_producer(zopt)) {
324*bf87c3c0Sflorian 				c_error("catalog-producer-zone %s in pattern "
325*bf87c3c0Sflorian 					"%s is not configered as a "
326*bf87c3c0Sflorian 					"catalog: producer",
327*bf87c3c0Sflorian 					pat->catalog_producer_zone,
328*bf87c3c0Sflorian 					pat->pname);
329*bf87c3c0Sflorian 			}
330*bf87c3c0Sflorian 		}
331*bf87c3c0Sflorian 		if( !old_opts /* Okay to add a cat producer member zone pat */
332*bf87c3c0Sflorian 		|| (!old_pat) /* But not to add, change or del an existing */
333*bf87c3c0Sflorian 		|| ( old_pat && !old_pat->catalog_producer_zone
334*bf87c3c0Sflorian 		             &&     !pat->catalog_producer_zone)
335*bf87c3c0Sflorian 		|| ( old_pat &&  old_pat->catalog_producer_zone
336*bf87c3c0Sflorian 		             &&      pat->catalog_producer_zone
337*bf87c3c0Sflorian 		             && strcmp( old_pat->catalog_producer_zone
338*bf87c3c0Sflorian 		                      ,     pat->catalog_producer_zone) == 0)){
339*bf87c3c0Sflorian 			; /* No existing catalog producer member zone added
340*bf87c3c0Sflorian 			   * or changed. Everyting is fine: pass */
341*bf87c3c0Sflorian 		} else {
342*bf87c3c0Sflorian 			c_error("catalog-producer-zone in pattern %s cannot "
343*bf87c3c0Sflorian 				"be removed or changed on a running NSD",
344*bf87c3c0Sflorian 				pat->pname);
345*bf87c3c0Sflorian 		}
34662ac0c33Sjakob 	}
34762ac0c33Sjakob 
34862ac0c33Sjakob 	if(cfg_parser->errors > 0)
34962ac0c33Sjakob 	{
350d3fecca9Ssthen 		if(err) {
351d3fecca9Ssthen 			char m[MAXSYSLOGMSGLEN];
352d3fecca9Ssthen 			snprintf(m, sizeof(m), "read %s failed: %d errors in "
35315ed76cbSbrad 				"configuration file\n", file,
35462ac0c33Sjakob 				cfg_parser->errors);
355d3fecca9Ssthen 			err(err_arg, m);
356d3fecca9Ssthen 		} else {
357d3fecca9Ssthen 			fprintf(stderr, "read %s failed: %d errors in "
35815ed76cbSbrad 				"configuration file\n", file,
359d3fecca9Ssthen 				cfg_parser->errors);
360d3fecca9Ssthen 		}
36162ac0c33Sjakob 		return 0;
36262ac0c33Sjakob 	}
36362ac0c33Sjakob 	return 1;
36462ac0c33Sjakob }
36562ac0c33Sjakob 
options_zonestatnames_create(struct nsd_options * opt)366fe5fe5f6Sflorian void options_zonestatnames_create(struct nsd_options* opt)
3679e506f0aSbrad {
368fe5fe5f6Sflorian 	struct zone_options* zopt;
3699e506f0aSbrad 	/* allocate "" as zonestat 0, for zones without a zonestat */
3709e506f0aSbrad 	if(!rbtree_search(opt->zonestatnames, "")) {
3719e506f0aSbrad 		struct zonestatname* n;
372b90bb40eSsthen 		n = (struct zonestatname*)region_alloc_zero(opt->region,
373b90bb40eSsthen 			sizeof(*n));
374b90bb40eSsthen 		n->node.key = region_strdup(opt->region, "");
3759e506f0aSbrad 		if(!n->node.key) {
3769e506f0aSbrad 			log_msg(LOG_ERR, "malloc failed: %s", strerror(errno));
3779e506f0aSbrad 			exit(1);
3789e506f0aSbrad 		}
3799e506f0aSbrad 		n->id = (unsigned)(opt->zonestatnames->count);
380fe5fe5f6Sflorian 		rbtree_insert(opt->zonestatnames, (rbnode_type*)n);
3819e506f0aSbrad 	}
382fe5fe5f6Sflorian 	RBTREE_FOR(zopt, struct zone_options*, opt->zone_options) {
3839e506f0aSbrad 		/* insert into tree, so that when read in later id exists */
3849e506f0aSbrad 		(void)getzonestatid(opt, zopt);
3859e506f0aSbrad 	}
3869e506f0aSbrad }
3879e506f0aSbrad 
388d3fecca9Ssthen #define ZONELIST_HEADER "# NSD zone list\n# name pattern\n"
389d3fecca9Ssthen static int
comp_zonebucket(const void * a,const void * b)390d3fecca9Ssthen comp_zonebucket(const void* a, const void* b)
391d3fecca9Ssthen {
3929e506f0aSbrad 	/* the line size is much smaller than max-int, and positive,
3939e506f0aSbrad 	 * so the subtraction works */
394d3fecca9Ssthen 	return *(const int*)b - *(const int*)a;
395d3fecca9Ssthen }
396d3fecca9Ssthen 
397d3fecca9Ssthen /* insert free entry into zonelist free buckets */
398d3fecca9Ssthen static void
zone_list_free_insert(struct nsd_options * opt,int linesize,off_t off)399fe5fe5f6Sflorian zone_list_free_insert(struct nsd_options* opt, int linesize, off_t off)
400d3fecca9Ssthen {
401d3fecca9Ssthen 	struct zonelist_free* e;
402d3fecca9Ssthen 	struct zonelist_bucket* b = (struct zonelist_bucket*)rbtree_search(
403d3fecca9Ssthen 		opt->zonefree, &linesize);
404d3fecca9Ssthen 	if(!b) {
405d3fecca9Ssthen 		b = region_alloc_zero(opt->region, sizeof(*b));
406d3fecca9Ssthen 		b->linesize = linesize;
407d3fecca9Ssthen 		b->node = *RBTREE_NULL;
408d3fecca9Ssthen 		b->node.key = &b->linesize;
409d3fecca9Ssthen 		rbtree_insert(opt->zonefree, &b->node);
410d3fecca9Ssthen 	}
411d3fecca9Ssthen 	e = (struct zonelist_free*)region_alloc_zero(opt->region, sizeof(*e));
412d3fecca9Ssthen 	e->next = b->list;
413d3fecca9Ssthen 	b->list = e;
414d3fecca9Ssthen 	e->off = off;
415d3fecca9Ssthen 	opt->zonefree_number++;
416d3fecca9Ssthen }
417d3fecca9Ssthen 
418*bf87c3c0Sflorian static struct zone_options*
zone_list_member_zone_insert(struct nsd_options * opt,const char * nm,const char * patnm,int linesize,off_t off,const char * mem_idnm,new_member_id_type new_member_id)419*bf87c3c0Sflorian zone_list_member_zone_insert(struct nsd_options* opt, const char* nm,
420*bf87c3c0Sflorian 	const char* patnm, int linesize, off_t off, const char* mem_idnm,
421*bf87c3c0Sflorian 	new_member_id_type new_member_id)
422d3fecca9Ssthen {
423fe5fe5f6Sflorian 	struct pattern_options* pat = pattern_options_find(opt, patnm);
424*bf87c3c0Sflorian 	struct catalog_member_zone* cmz = NULL;
425fe5fe5f6Sflorian 	struct zone_options* zone;
426*bf87c3c0Sflorian 	char member_id_str[MAXDOMAINLEN * 5 + 3] = "ERROR!";
427*bf87c3c0Sflorian 	DEBUG(DEBUG_XFRD, 2, (LOG_INFO, "zone_list_zone_insert(\"%s\", \"%s\""
428*bf87c3c0Sflorian 	        ", %d, \"%s\")", nm, patnm, linesize,
429*bf87c3c0Sflorian 		(mem_idnm ? mem_idnm : "<NULL>")));
430d3fecca9Ssthen 	if(!pat) {
431d3fecca9Ssthen 		log_msg(LOG_ERR, "pattern does not exist for zone %s "
432d3fecca9Ssthen 			"pattern %s", nm, patnm);
433d3fecca9Ssthen 		return NULL;
434d3fecca9Ssthen 	}
435*bf87c3c0Sflorian 	zone = pat->catalog_producer_zone
436*bf87c3c0Sflorian 	     ? &(cmz = catalog_member_zone_create(opt->region))->options
437*bf87c3c0Sflorian 	     : zone_options_create(opt->region);
438d3fecca9Ssthen 	zone->part_of_config = 0;
439d3fecca9Ssthen 	zone->name = region_strdup(opt->region, nm);
440d3fecca9Ssthen 	zone->linesize = linesize;
441d3fecca9Ssthen 	zone->off = off;
442d3fecca9Ssthen 	zone->pattern = pat;
443d3fecca9Ssthen 	if(!nsd_options_insert_zone(opt, zone)) {
444d3fecca9Ssthen 		log_msg(LOG_ERR, "bad domain name or duplicate zone '%s' "
445d3fecca9Ssthen 			"pattern %s", nm, patnm);
446d3fecca9Ssthen 		region_recycle(opt->region, (void*)zone->name, strlen(nm)+1);
447d3fecca9Ssthen 		region_recycle(opt->region, zone, sizeof(*zone));
448d3fecca9Ssthen 		return NULL;
449d3fecca9Ssthen 	}
450*bf87c3c0Sflorian 	if(!mem_idnm) {
451*bf87c3c0Sflorian 		if(cmz && new_member_id)
452*bf87c3c0Sflorian 			new_member_id(cmz);
453*bf87c3c0Sflorian 		if(cmz && cmz->member_id) {
454*bf87c3c0Sflorian 			/* Assume all bytes of member_id are printable.
455*bf87c3c0Sflorian 			 * plus 1 for space
456*bf87c3c0Sflorian 			 */
457*bf87c3c0Sflorian 			zone->linesize += label_length(dname_name(cmz->member_id)) + 1;
458*bf87c3c0Sflorian 			DEBUG(DEBUG_XFRD, 2, (LOG_INFO, "new linesize: %d",
459*bf87c3c0Sflorian 				(int)zone->linesize));
460*bf87c3c0Sflorian 		}
461*bf87c3c0Sflorian 	} else if(!cmz)
462*bf87c3c0Sflorian 		log_msg(LOG_ERR, "member ID '%s' given, but no catalog-producer-"
463*bf87c3c0Sflorian 			"zone value provided in zone '%s' or pattern '%s'",
464*bf87c3c0Sflorian 			mem_idnm, nm, patnm);
465*bf87c3c0Sflorian 
466*bf87c3c0Sflorian 	else if(snprintf(member_id_str, sizeof(member_id_str),
467*bf87c3c0Sflorian 	    "%s.zones.%s", mem_idnm, pat->catalog_producer_zone) >=
468*bf87c3c0Sflorian 	    (int)sizeof(member_id_str))
469*bf87c3c0Sflorian 		log_msg(LOG_ERR, "syntax error in member ID '%s.zones.%s' for "
470*bf87c3c0Sflorian 			"zone '%s'", mem_idnm, pat->catalog_producer_zone, nm);
471*bf87c3c0Sflorian 
472*bf87c3c0Sflorian 	else if(!(cmz->member_id = dname_parse(opt->region, member_id_str)))
473*bf87c3c0Sflorian 		log_msg(LOG_ERR, "parse error in member ID '%s' for "
474*bf87c3c0Sflorian 			"zone '%s'", member_id_str, nm);
475d3fecca9Ssthen 	return zone;
476d3fecca9Ssthen }
477d3fecca9Ssthen 
478*bf87c3c0Sflorian struct zone_options*
zone_list_zone_insert(struct nsd_options * opt,const char * nm,const char * patnm)479*bf87c3c0Sflorian zone_list_zone_insert(struct nsd_options* opt,const char* nm,const char* patnm)
480*bf87c3c0Sflorian {
481*bf87c3c0Sflorian 	return zone_list_member_zone_insert(opt, nm, patnm, 0, 0, NULL, NULL);
482*bf87c3c0Sflorian }
483*bf87c3c0Sflorian 
484d3fecca9Ssthen int
parse_zone_list_file(struct nsd_options * opt)485fe5fe5f6Sflorian parse_zone_list_file(struct nsd_options* opt)
486d3fecca9Ssthen {
487d3fecca9Ssthen 	/* zonelist looks like this:
488d3fecca9Ssthen 	# name pattern
489d3fecca9Ssthen 	add example.com master
490d3fecca9Ssthen 	del example.net slave
491d3fecca9Ssthen 	add foo.bar.nl slave
492d3fecca9Ssthen 	add rutabaga.uk config
493d3fecca9Ssthen 	*/
494308d2509Sflorian 	char hdr[64];
495d3fecca9Ssthen 	char buf[1024];
496d3fecca9Ssthen 
497d3fecca9Ssthen 	/* create empty data structures */
498d3fecca9Ssthen 	opt->zonefree = rbtree_create(opt->region, comp_zonebucket);
499d3fecca9Ssthen 	opt->zonelist = NULL;
500d3fecca9Ssthen 	opt->zonefree_number = 0;
501d3fecca9Ssthen 	opt->zonelist_off = 0;
502d3fecca9Ssthen 
503d3fecca9Ssthen 	/* try to open the zonelist file, an empty or nonexist file is OK */
504d3fecca9Ssthen 	opt->zonelist = fopen(opt->zonelistfile, "r+");
505d3fecca9Ssthen 	if(!opt->zonelist) {
506d3fecca9Ssthen 		if(errno == ENOENT)
507d3fecca9Ssthen 			return 1; /* file does not exist, it is created later */
508d3fecca9Ssthen 		log_msg(LOG_ERR, "could not open zone list %s: %s", opt->zonelistfile,
509d3fecca9Ssthen 			strerror(errno));
510d3fecca9Ssthen 		return 0;
511d3fecca9Ssthen 	}
512d3fecca9Ssthen 	/* read header */
513308d2509Sflorian 	hdr[strlen(ZONELIST_HEADER)] = 0;
514308d2509Sflorian 	if(fread(hdr, 1, strlen(ZONELIST_HEADER), opt->zonelist) !=
515308d2509Sflorian 		strlen(ZONELIST_HEADER) || strncmp(hdr, ZONELIST_HEADER,
516d3fecca9Ssthen 		strlen(ZONELIST_HEADER)) != 0) {
517d3fecca9Ssthen 		log_msg(LOG_ERR, "zone list %s contains bad header\n", opt->zonelistfile);
518d3fecca9Ssthen 		fclose(opt->zonelist);
519d3fecca9Ssthen 		opt->zonelist = NULL;
520d3fecca9Ssthen 		return 0;
521d3fecca9Ssthen 	}
522308d2509Sflorian 	buf[sizeof(buf)-1]=0;
523d3fecca9Ssthen 
524d3fecca9Ssthen 	/* read entries in file */
525d3fecca9Ssthen 	while(fgets(buf, sizeof(buf), opt->zonelist)) {
526d3fecca9Ssthen 		/* skip comments and empty lines */
527d3fecca9Ssthen 		if(buf[0] == 0 || buf[0] == '\n' || buf[0] == '#')
528d3fecca9Ssthen 			continue;
529d3fecca9Ssthen 		if(strncmp(buf, "add ", 4) == 0) {
530d3fecca9Ssthen 			int linesize = strlen(buf);
531d3fecca9Ssthen 			/* parse the 'add' line */
532d3fecca9Ssthen 			/* pick last space on the line, so that the domain
533d3fecca9Ssthen 			 * name can have a space in it (but not the pattern)*/
534d3fecca9Ssthen 			char* space = strrchr(buf+4, ' ');
535d3fecca9Ssthen 			char* nm, *patnm;
536d3fecca9Ssthen 			if(!space) {
537d3fecca9Ssthen 				/* parse error */
538d3fecca9Ssthen 				log_msg(LOG_ERR, "parse error in %s: '%s'",
539d3fecca9Ssthen 					opt->zonelistfile, buf);
540d3fecca9Ssthen 				continue;
541d3fecca9Ssthen 			}
542d3fecca9Ssthen 			nm = buf+4;
543d3fecca9Ssthen 			*space = 0;
544d3fecca9Ssthen 			patnm = space+1;
545d3fecca9Ssthen 			if(linesize && buf[linesize-1] == '\n')
546d3fecca9Ssthen 				buf[linesize-1] = 0;
547d3fecca9Ssthen 
548d3fecca9Ssthen 			/* store offset and line size for zone entry */
549d3fecca9Ssthen 			/* and create zone entry in zonetree */
550*bf87c3c0Sflorian 			(void)zone_list_member_zone_insert(opt, nm, patnm,
551*bf87c3c0Sflorian 				linesize, ftello(opt->zonelist)-linesize,
552*bf87c3c0Sflorian 				NULL, NULL);
553*bf87c3c0Sflorian 
554*bf87c3c0Sflorian 		} else if(strncmp(buf, "cat ", 4) == 0) {
555*bf87c3c0Sflorian 			int linesize = strlen(buf);
556*bf87c3c0Sflorian 			/* parse the 'add' line */
557*bf87c3c0Sflorian 			/* pick last space on the line, so that the domain
558*bf87c3c0Sflorian 			 * name can have a space in it (but not the pattern)*/
559*bf87c3c0Sflorian 			char* nm = buf + 4;
560*bf87c3c0Sflorian 			char* mem_idnm = strrchr(nm, ' '), *patnm;
561*bf87c3c0Sflorian 			if(!mem_idnm) {
562*bf87c3c0Sflorian 				/* parse error */
563*bf87c3c0Sflorian 				log_msg(LOG_ERR, "parse error in %s: '%s'",
564*bf87c3c0Sflorian 					opt->zonelistfile, buf);
565*bf87c3c0Sflorian 				continue;
566*bf87c3c0Sflorian 			}
567*bf87c3c0Sflorian 			*mem_idnm++ = 0;
568*bf87c3c0Sflorian 			patnm = strrchr(nm, ' ');
569*bf87c3c0Sflorian 			if(!patnm) {
570*bf87c3c0Sflorian 				*--mem_idnm = ' ';
571*bf87c3c0Sflorian 				/* parse error */
572*bf87c3c0Sflorian 				log_msg(LOG_ERR, "parse error in %s: '%s'",
573*bf87c3c0Sflorian 					opt->zonelistfile, buf);
574*bf87c3c0Sflorian 				continue;
575*bf87c3c0Sflorian 			}
576*bf87c3c0Sflorian 			*patnm++ = 0;
577*bf87c3c0Sflorian 			if(linesize && buf[linesize-1] == '\n')
578*bf87c3c0Sflorian 				buf[linesize-1] = 0;
579*bf87c3c0Sflorian 
580*bf87c3c0Sflorian 			/* store offset and line size for zone entry */
581*bf87c3c0Sflorian 			/* and create zone entry in zonetree */
582*bf87c3c0Sflorian 			(void)zone_list_member_zone_insert(opt, nm, patnm,
583*bf87c3c0Sflorian 				linesize, ftello(opt->zonelist)-linesize,
584*bf87c3c0Sflorian 				mem_idnm, NULL);
585*bf87c3c0Sflorian 
586d3fecca9Ssthen 		} else if(strncmp(buf, "del ", 4) == 0) {
587d3fecca9Ssthen 			/* store offset and line size for deleted entry */
588d3fecca9Ssthen 			int linesize = strlen(buf);
589d3fecca9Ssthen 			zone_list_free_insert(opt, linesize,
590d3fecca9Ssthen 				ftello(opt->zonelist)-linesize);
591d3fecca9Ssthen 		} else {
592d3fecca9Ssthen 			log_msg(LOG_WARNING, "bad data in %s, '%s'", opt->zonelistfile,
593d3fecca9Ssthen 				buf);
594d3fecca9Ssthen 		}
595d3fecca9Ssthen 	}
596d3fecca9Ssthen 	/* store EOF offset */
597d3fecca9Ssthen 	opt->zonelist_off = ftello(opt->zonelist);
598d3fecca9Ssthen 	return 1;
599d3fecca9Ssthen }
600d3fecca9Ssthen 
601d3fecca9Ssthen void
zone_options_delete(struct nsd_options * opt,struct zone_options * zone)602fe5fe5f6Sflorian zone_options_delete(struct nsd_options* opt, struct zone_options* zone)
603d3fecca9Ssthen {
604*bf87c3c0Sflorian 	struct catalog_member_zone* member_zone = as_catalog_member_zone(zone);
605*bf87c3c0Sflorian 
606d3fecca9Ssthen 	rbtree_delete(opt->zone_options, zone->node.key);
607d3fecca9Ssthen 	region_recycle(opt->region, (void*)zone->node.key, dname_total_size(
608d3fecca9Ssthen 		(dname_type*)zone->node.key));
609*bf87c3c0Sflorian 	if(!member_zone) {
610d3fecca9Ssthen 		region_recycle(opt->region, zone, sizeof(*zone));
611*bf87c3c0Sflorian 		return;
612d3fecca9Ssthen 	}
613*bf87c3c0Sflorian 	/* Because catalog member zones are in xfrd only deleted through
614*bf87c3c0Sflorian 	 * catalog_del_consumer_member_zone() or through
615*bf87c3c0Sflorian 	 * xfrd_del_catalog_producer_member(), which both clear the node,
616*bf87c3c0Sflorian 	 * and because member zones in the main and serve processes are not
617*bf87c3c0Sflorian 	 * indexed, *member_zone->node == *RBTREE_NULL.
618*bf87c3c0Sflorian 	 * member_id is cleared too by those delete function, but there may be
619*bf87c3c0Sflorian 	 * leftover member_id's from the initial zone.list processing, which
620*bf87c3c0Sflorian 	 * made it to the main and serve processes.
621*bf87c3c0Sflorian 	 */
622*bf87c3c0Sflorian 	assert(!memcmp(&member_zone->node, RBTREE_NULL, sizeof(*RBTREE_NULL)));
623*bf87c3c0Sflorian 	if(member_zone->member_id) {
624*bf87c3c0Sflorian 		region_recycle(opt->region, (void*)member_zone->member_id,
625*bf87c3c0Sflorian 				dname_total_size(member_zone->member_id));
626*bf87c3c0Sflorian 	}
627*bf87c3c0Sflorian 	region_recycle(opt->region, member_zone, sizeof(*member_zone));
628*bf87c3c0Sflorian }
629*bf87c3c0Sflorian 
630d3fecca9Ssthen 
631d3fecca9Ssthen /* add a new zone to the zonelist */
632fe5fe5f6Sflorian struct zone_options*
zone_list_add_or_cat(struct nsd_options * opt,const char * zname,const char * pname,new_member_id_type new_member_id)633*bf87c3c0Sflorian zone_list_add_or_cat(struct nsd_options* opt, const char* zname,
634*bf87c3c0Sflorian 		const char* pname, new_member_id_type new_member_id)
635d3fecca9Ssthen {
636d3fecca9Ssthen 	int r;
637d3fecca9Ssthen 	struct zonelist_free* e;
638d3fecca9Ssthen 	struct zonelist_bucket* b;
639*bf87c3c0Sflorian 	char zone_list_line[6 + 5 * MAXDOMAINLEN + 2024 + 65];
640*bf87c3c0Sflorian 	struct catalog_member_zone* cmz;
641*bf87c3c0Sflorian 
642d3fecca9Ssthen 	/* create zone entry */
643*bf87c3c0Sflorian 	struct zone_options* zone = zone_list_member_zone_insert(
644*bf87c3c0Sflorian 		opt, zname, pname, 6 + strlen(zname) + strlen(pname),
645*bf87c3c0Sflorian 		0, NULL, new_member_id);
646d3fecca9Ssthen 	if(!zone)
647d3fecca9Ssthen 		return NULL;
648d3fecca9Ssthen 
649*bf87c3c0Sflorian 	if(zone_is_catalog_producer_member(zone)
650*bf87c3c0Sflorian 	&& (cmz = as_catalog_member_zone(zone))
651*bf87c3c0Sflorian 	&& cmz->member_id) {
652*bf87c3c0Sflorian 		snprintf(zone_list_line, sizeof(zone_list_line),
653*bf87c3c0Sflorian 			"cat %s %s %.*s\n", zname, pname,
654*bf87c3c0Sflorian 			(int)label_length(dname_name(cmz->member_id)),
655*bf87c3c0Sflorian 			(const char*)dname_name(cmz->member_id) + 1);
656*bf87c3c0Sflorian 	} else {
657*bf87c3c0Sflorian 		snprintf(zone_list_line, sizeof(zone_list_line),
658*bf87c3c0Sflorian 			"add %s %s\n", zname, pname);
659*bf87c3c0Sflorian 	}
660d3fecca9Ssthen 	/* use free entry or append to file or create new file */
661d3fecca9Ssthen 	if(!opt->zonelist || opt->zonelist_off == 0) {
662d3fecca9Ssthen 		/* create new file */
663d3fecca9Ssthen 		if(opt->zonelist) fclose(opt->zonelist);
664d3fecca9Ssthen 		opt->zonelist = fopen(opt->zonelistfile, "w+");
665d3fecca9Ssthen 		if(!opt->zonelist) {
666d3fecca9Ssthen 			log_msg(LOG_ERR, "could not create zone list %s: %s",
667d3fecca9Ssthen 				opt->zonelistfile, strerror(errno));
668d3fecca9Ssthen 			log_msg(LOG_ERR, "zone %s could not be added", zname);
669d3fecca9Ssthen 			zone_options_delete(opt, zone);
670d3fecca9Ssthen 			return NULL;
671d3fecca9Ssthen 		}
672d3fecca9Ssthen 		r = fprintf(opt->zonelist, ZONELIST_HEADER);
673d3fecca9Ssthen 		if(r != strlen(ZONELIST_HEADER)) {
674d3fecca9Ssthen 			if(r == -1)
675d3fecca9Ssthen 				log_msg(LOG_ERR, "could not write to %s: %s",
676d3fecca9Ssthen 					opt->zonelistfile, strerror(errno));
677d3fecca9Ssthen 			else log_msg(LOG_ERR, "partial write to %s: disk full",
678d3fecca9Ssthen 				opt->zonelistfile);
679d3fecca9Ssthen 			log_msg(LOG_ERR, "zone %s could not be added", zname);
680d3fecca9Ssthen 			zone_options_delete(opt, zone);
681d3fecca9Ssthen 			return NULL;
682d3fecca9Ssthen 		}
683d3fecca9Ssthen 		zone->off = ftello(opt->zonelist);
684d3fecca9Ssthen 		if(zone->off == -1)
685d3fecca9Ssthen 			log_msg(LOG_ERR, "ftello(%s): %s", opt->zonelistfile, strerror(errno));
686*bf87c3c0Sflorian 		r = fprintf(opt->zonelist, "%s", zone_list_line);
687d3fecca9Ssthen 		if(r != zone->linesize) {
688d3fecca9Ssthen 			if(r == -1)
689d3fecca9Ssthen 				log_msg(LOG_ERR, "could not write to %s: %s",
690d3fecca9Ssthen 					opt->zonelistfile, strerror(errno));
691d3fecca9Ssthen 			else log_msg(LOG_ERR, "partial write to %s: disk full",
692d3fecca9Ssthen 				opt->zonelistfile);
693d3fecca9Ssthen 			log_msg(LOG_ERR, "zone %s could not be added", zname);
694d3fecca9Ssthen 			zone_options_delete(opt, zone);
695d3fecca9Ssthen 			return NULL;
696d3fecca9Ssthen 		}
697d3fecca9Ssthen 		opt->zonelist_off = ftello(opt->zonelist);
698d3fecca9Ssthen 		if(opt->zonelist_off == -1)
699d3fecca9Ssthen 			log_msg(LOG_ERR, "ftello(%s): %s", opt->zonelistfile, strerror(errno));
700d3fecca9Ssthen 		if(fflush(opt->zonelist) != 0) {
701d3fecca9Ssthen 			log_msg(LOG_ERR, "fflush %s: %s", opt->zonelistfile, strerror(errno));
702d3fecca9Ssthen 		}
703d3fecca9Ssthen 		return zone;
704d3fecca9Ssthen 	}
705d3fecca9Ssthen 	b = (struct zonelist_bucket*)rbtree_search(opt->zonefree,
706d3fecca9Ssthen 		&zone->linesize);
707d3fecca9Ssthen 	if(!b || b->list == NULL) {
708d3fecca9Ssthen 		/* no empty place, append to file */
709d3fecca9Ssthen 		zone->off = opt->zonelist_off;
710d3fecca9Ssthen 		if(fseeko(opt->zonelist, zone->off, SEEK_SET) == -1) {
711d3fecca9Ssthen 			log_msg(LOG_ERR, "fseeko(%s): %s", opt->zonelistfile, strerror(errno));
712d3fecca9Ssthen 			log_msg(LOG_ERR, "zone %s could not be added", zname);
713d3fecca9Ssthen 			zone_options_delete(opt, zone);
714d3fecca9Ssthen 			return NULL;
715d3fecca9Ssthen 		}
716*bf87c3c0Sflorian 		r = fprintf(opt->zonelist, "%s", zone_list_line);
717d3fecca9Ssthen 		if(r != zone->linesize) {
718d3fecca9Ssthen 			if(r == -1)
719d3fecca9Ssthen 				log_msg(LOG_ERR, "could not write to %s: %s",
720d3fecca9Ssthen 					opt->zonelistfile, strerror(errno));
721d3fecca9Ssthen 			else log_msg(LOG_ERR, "partial write to %s: disk full",
722d3fecca9Ssthen 				opt->zonelistfile);
723d3fecca9Ssthen 			log_msg(LOG_ERR, "zone %s could not be added", zname);
724d3fecca9Ssthen 			zone_options_delete(opt, zone);
725d3fecca9Ssthen 			return NULL;
726d3fecca9Ssthen 		}
727*bf87c3c0Sflorian 		opt->zonelist_off += zone->linesize;
728d3fecca9Ssthen 		if(fflush(opt->zonelist) != 0) {
729d3fecca9Ssthen 			log_msg(LOG_ERR, "fflush %s: %s", opt->zonelistfile, strerror(errno));
730d3fecca9Ssthen 		}
731d3fecca9Ssthen 		return zone;
732d3fecca9Ssthen 	}
733d3fecca9Ssthen 	/* reuse empty spot */
734d3fecca9Ssthen 	e = b->list;
735d3fecca9Ssthen 	zone->off = e->off;
736d3fecca9Ssthen 	if(fseeko(opt->zonelist, zone->off, SEEK_SET) == -1) {
737d3fecca9Ssthen 		log_msg(LOG_ERR, "fseeko(%s): %s", opt->zonelistfile, strerror(errno));
738d3fecca9Ssthen 		log_msg(LOG_ERR, "zone %s could not be added", zname);
739d3fecca9Ssthen 		zone_options_delete(opt, zone);
740d3fecca9Ssthen 		return NULL;
741d3fecca9Ssthen 	}
742*bf87c3c0Sflorian 	r = fprintf(opt->zonelist, "%s", zone_list_line);
743d3fecca9Ssthen 	if(r != zone->linesize) {
744d3fecca9Ssthen 		if(r == -1)
745d3fecca9Ssthen 			log_msg(LOG_ERR, "could not write to %s: %s",
746d3fecca9Ssthen 				opt->zonelistfile, strerror(errno));
747d3fecca9Ssthen 		else log_msg(LOG_ERR, "partial write to %s: disk full",
748d3fecca9Ssthen 			opt->zonelistfile);
749d3fecca9Ssthen 		log_msg(LOG_ERR, "zone %s could not be added", zname);
750d3fecca9Ssthen 		zone_options_delete(opt, zone);
751d3fecca9Ssthen 		return NULL;
752d3fecca9Ssthen 	}
753d3fecca9Ssthen 	if(fflush(opt->zonelist) != 0) {
754d3fecca9Ssthen 		log_msg(LOG_ERR, "fflush %s: %s", opt->zonelistfile, strerror(errno));
755d3fecca9Ssthen 	}
756d3fecca9Ssthen 
757d3fecca9Ssthen 	/* snip off and recycle element */
758d3fecca9Ssthen 	b->list = e->next;
759d3fecca9Ssthen 	region_recycle(opt->region, e, sizeof(*e));
760d3fecca9Ssthen 	if(b->list == NULL) {
761d3fecca9Ssthen 		rbtree_delete(opt->zonefree, &b->linesize);
762d3fecca9Ssthen 		region_recycle(opt->region, b, sizeof(*b));
763d3fecca9Ssthen 	}
764d3fecca9Ssthen 	opt->zonefree_number--;
765d3fecca9Ssthen 	return zone;
766d3fecca9Ssthen }
767d3fecca9Ssthen 
768d3fecca9Ssthen /* remove a zone on the zonelist */
769d3fecca9Ssthen void
zone_list_del(struct nsd_options * opt,struct zone_options * zone)770fe5fe5f6Sflorian zone_list_del(struct nsd_options* opt, struct zone_options* zone)
771d3fecca9Ssthen {
772*bf87c3c0Sflorian 	if (zone_is_catalog_consumer_member(zone)) {
773*bf87c3c0Sflorian 		/* catalog consumer member zones are not in the zones.list file */
774*bf87c3c0Sflorian 		zone_options_delete(opt, zone);
775*bf87c3c0Sflorian 		return;
776*bf87c3c0Sflorian 	}
777d3fecca9Ssthen 	/* put its space onto the free entry */
778d3fecca9Ssthen 	if(fseeko(opt->zonelist, zone->off, SEEK_SET) == -1) {
779d3fecca9Ssthen 		log_msg(LOG_ERR, "fseeko(%s): %s", opt->zonelistfile, strerror(errno));
780d3fecca9Ssthen 		return;
781d3fecca9Ssthen 	}
782d3fecca9Ssthen 	fprintf(opt->zonelist, "del");
783d3fecca9Ssthen 	zone_list_free_insert(opt, zone->linesize, zone->off);
784d3fecca9Ssthen 
785fe5fe5f6Sflorian 	/* remove zone_options */
786d3fecca9Ssthen 	zone_options_delete(opt, zone);
787d3fecca9Ssthen 
788d3fecca9Ssthen 	/* see if we need to compact: it is going to halve the zonelist */
789d3fecca9Ssthen 	if(opt->zonefree_number > opt->zone_options->count) {
790d3fecca9Ssthen 		zone_list_compact(opt);
791d3fecca9Ssthen 	} else {
792d3fecca9Ssthen 		if(fflush(opt->zonelist) != 0) {
793d3fecca9Ssthen 			log_msg(LOG_ERR, "fflush %s: %s", opt->zonelistfile, strerror(errno));
794d3fecca9Ssthen 		}
795d3fecca9Ssthen 	}
796d3fecca9Ssthen }
797d3fecca9Ssthen /* postorder delete of zonelist free space tree */
798d3fecca9Ssthen static void
delbucket(region_type * region,struct zonelist_bucket * b)799d3fecca9Ssthen delbucket(region_type* region, struct zonelist_bucket* b)
800d3fecca9Ssthen {
801d3fecca9Ssthen 	struct zonelist_free* e, *f;
802fe5fe5f6Sflorian 	if(!b || (rbnode_type*)b==RBTREE_NULL)
803d3fecca9Ssthen 		return;
804d3fecca9Ssthen 	delbucket(region, (struct zonelist_bucket*)b->node.left);
805d3fecca9Ssthen 	delbucket(region, (struct zonelist_bucket*)b->node.right);
806d3fecca9Ssthen 	e = b->list;
807d3fecca9Ssthen 	while(e) {
808d3fecca9Ssthen 		f = e->next;
809d3fecca9Ssthen 		region_recycle(region, e, sizeof(*e));
810d3fecca9Ssthen 		e = f;
811d3fecca9Ssthen 	}
812d3fecca9Ssthen 	region_recycle(region, b, sizeof(*b));
813d3fecca9Ssthen }
814d3fecca9Ssthen 
815d3fecca9Ssthen /* compact zonelist file */
816d3fecca9Ssthen void
zone_list_compact(struct nsd_options * opt)817fe5fe5f6Sflorian zone_list_compact(struct nsd_options* opt)
818d3fecca9Ssthen {
819d3fecca9Ssthen 	char outname[1024];
820d3fecca9Ssthen 	FILE* out;
821fe5fe5f6Sflorian 	struct zone_options* zone;
822d3fecca9Ssthen 	off_t off;
823d3fecca9Ssthen 	int r;
824d3fecca9Ssthen 	snprintf(outname, sizeof(outname), "%s~", opt->zonelistfile);
825d3fecca9Ssthen 	/* useful, when : count-of-free > count-of-used */
826d3fecca9Ssthen 	/* write zonelist to zonelist~ */
827d3fecca9Ssthen 	out = fopen(outname, "w+");
828d3fecca9Ssthen 	if(!out) {
829d3fecca9Ssthen 		log_msg(LOG_ERR, "could not open %s: %s", outname, strerror(errno));
830d3fecca9Ssthen 		return;
831d3fecca9Ssthen 	}
832d3fecca9Ssthen 	r = fprintf(out, ZONELIST_HEADER);
833d3fecca9Ssthen 	if(r == -1) {
834d3fecca9Ssthen 		log_msg(LOG_ERR, "write %s failed: %s", outname,
835d3fecca9Ssthen 			strerror(errno));
836d3fecca9Ssthen 		fclose(out);
837d3fecca9Ssthen 		return;
838d3fecca9Ssthen 	} else if(r != strlen(ZONELIST_HEADER)) {
839d3fecca9Ssthen 		log_msg(LOG_ERR, "write %s was partial: disk full",
840d3fecca9Ssthen 			outname);
841d3fecca9Ssthen 		fclose(out);
842d3fecca9Ssthen 		return;
843d3fecca9Ssthen 	}
844d3fecca9Ssthen 	off = ftello(out);
845d3fecca9Ssthen 	if(off == -1) {
846d3fecca9Ssthen 		log_msg(LOG_ERR, "ftello(%s): %s", outname, strerror(errno));
847d3fecca9Ssthen 		fclose(out);
848d3fecca9Ssthen 		return;
849d3fecca9Ssthen 	}
850fe5fe5f6Sflorian 	RBTREE_FOR(zone, struct zone_options*, opt->zone_options) {
851*bf87c3c0Sflorian 		struct catalog_member_zone* cmz;
852*bf87c3c0Sflorian 
853d3fecca9Ssthen 		if(zone->part_of_config)
854d3fecca9Ssthen 			continue;
855*bf87c3c0Sflorian 		if(zone_is_catalog_producer_member(zone)
856*bf87c3c0Sflorian 		&& (cmz = as_catalog_member_zone(zone))
857*bf87c3c0Sflorian 		&& cmz->member_id) {
858*bf87c3c0Sflorian 			r = fprintf(out, "cat %s %s %.*s\n", zone->name,
859*bf87c3c0Sflorian 				zone->pattern->pname,
860*bf87c3c0Sflorian 				(int)label_length(dname_name(cmz->member_id)),
861*bf87c3c0Sflorian 				(const char*)dname_name(cmz->member_id) + 1);
862*bf87c3c0Sflorian 		} else {
863d3fecca9Ssthen 			r = fprintf(out, "add %s %s\n", zone->name,
864d3fecca9Ssthen 					zone->pattern->pname);
865*bf87c3c0Sflorian 		}
866d3fecca9Ssthen 		if(r < 0) {
867d3fecca9Ssthen 			log_msg(LOG_ERR, "write %s failed: %s", outname,
868d3fecca9Ssthen 				strerror(errno));
869d3fecca9Ssthen 			fclose(out);
870d3fecca9Ssthen 			return;
871d3fecca9Ssthen 		} else if(r != zone->linesize) {
872d3fecca9Ssthen 			log_msg(LOG_ERR, "write %s was partial: disk full",
873d3fecca9Ssthen 				outname);
874d3fecca9Ssthen 			fclose(out);
875d3fecca9Ssthen 			return;
876d3fecca9Ssthen 		}
877d3fecca9Ssthen 	}
878d3fecca9Ssthen 	if(fflush(out) != 0) {
879d3fecca9Ssthen 		log_msg(LOG_ERR, "fflush %s: %s", outname, strerror(errno));
880d3fecca9Ssthen 	}
881d3fecca9Ssthen 
882d3fecca9Ssthen 	/* rename zonelist~ onto zonelist */
883d3fecca9Ssthen 	if(rename(outname, opt->zonelistfile) == -1) {
884d3fecca9Ssthen 		log_msg(LOG_ERR, "rename(%s to %s) failed: %s",
885d3fecca9Ssthen 			outname, opt->zonelistfile, strerror(errno));
886d3fecca9Ssthen 		fclose(out);
887d3fecca9Ssthen 		return;
888d3fecca9Ssthen 	}
889d3fecca9Ssthen 	fclose(opt->zonelist);
890d3fecca9Ssthen 	/* set offsets */
891fe5fe5f6Sflorian 	RBTREE_FOR(zone, struct zone_options*, opt->zone_options) {
892d3fecca9Ssthen 		if(zone->part_of_config)
893d3fecca9Ssthen 			continue;
894d3fecca9Ssthen 		zone->off = off;
895d3fecca9Ssthen 		off += zone->linesize;
896d3fecca9Ssthen 	}
897d3fecca9Ssthen 	/* empty the free tree */
898d3fecca9Ssthen 	delbucket(opt->region, (struct zonelist_bucket*)opt->zonefree->root);
899d3fecca9Ssthen 	opt->zonefree->root = RBTREE_NULL;
900d3fecca9Ssthen 	opt->zonefree->count = 0;
901d3fecca9Ssthen 	opt->zonefree_number = 0;
902d3fecca9Ssthen 	/* finish */
903d3fecca9Ssthen 	opt->zonelist = out;
904d3fecca9Ssthen 	opt->zonelist_off = off;
905d3fecca9Ssthen }
906d3fecca9Ssthen 
907d3fecca9Ssthen /* close zonelist file */
908d3fecca9Ssthen void
zone_list_close(struct nsd_options * opt)909fe5fe5f6Sflorian zone_list_close(struct nsd_options* opt)
910d3fecca9Ssthen {
911b90bb40eSsthen 	if(opt->zonelist) {
912d3fecca9Ssthen 		fclose(opt->zonelist);
913d3fecca9Ssthen 		opt->zonelist = NULL;
914d3fecca9Ssthen 	}
915b90bb40eSsthen }
916d3fecca9Ssthen 
9175435475dSsthen static void
c_error_va_list_pos(int showpos,const char * fmt,va_list args)918e3d8a0a5Ssthen c_error_va_list_pos(int showpos, const char* fmt, va_list args)
91962ac0c33Sjakob {
920e3d8a0a5Ssthen 	char* at = NULL;
92162ac0c33Sjakob 	cfg_parser->errors++;
922e3d8a0a5Ssthen 	if(showpos && c_text && c_text[0]!=0) {
923e3d8a0a5Ssthen 		at = c_text;
924e3d8a0a5Ssthen 	}
925d3fecca9Ssthen 	if(cfg_parser->err) {
926d3fecca9Ssthen 		char m[MAXSYSLOGMSGLEN];
927e3d8a0a5Ssthen 		snprintf(m, sizeof(m), "%s:%d: ", cfg_parser->filename,
928d3fecca9Ssthen 			cfg_parser->line);
929d3fecca9Ssthen 		(*cfg_parser->err)(cfg_parser->err_arg, m);
930e3d8a0a5Ssthen 		if(at) {
931e3d8a0a5Ssthen 			snprintf(m, sizeof(m), "at '%s': ", at);
932e3d8a0a5Ssthen 			(*cfg_parser->err)(cfg_parser->err_arg, m);
933e3d8a0a5Ssthen 		}
934e3d8a0a5Ssthen 		(*cfg_parser->err)(cfg_parser->err_arg, "error: ");
935d3fecca9Ssthen 		vsnprintf(m, sizeof(m), fmt, args);
936d3fecca9Ssthen 		(*cfg_parser->err)(cfg_parser->err_arg, m);
937d3fecca9Ssthen 		(*cfg_parser->err)(cfg_parser->err_arg, "\n");
938d3fecca9Ssthen 		return;
939d3fecca9Ssthen 	}
940e3d8a0a5Ssthen         fprintf(stderr, "%s:%d: ", cfg_parser->filename, cfg_parser->line);
941e3d8a0a5Ssthen 	if(at) fprintf(stderr, "at '%s': ", at);
942e3d8a0a5Ssthen 	fprintf(stderr, "error: ");
94362ac0c33Sjakob 	vfprintf(stderr, fmt, args);
94462ac0c33Sjakob 	fprintf(stderr, "\n");
94562ac0c33Sjakob }
94662ac0c33Sjakob 
947d3fecca9Ssthen void
c_error(const char * fmt,...)9485435475dSsthen c_error(const char *fmt, ...)
949e3d8a0a5Ssthen {
9505435475dSsthen 	va_list ap;
9515435475dSsthen 	int showpos = 0;
9525435475dSsthen 
9535435475dSsthen 	if (strcmp(fmt, "syntax error") == 0 || strcmp(fmt, "parse error") == 0) {
9545435475dSsthen 		showpos = 1;
955e3d8a0a5Ssthen 	}
956e3d8a0a5Ssthen 
9575435475dSsthen 	va_start(ap, fmt);
9585435475dSsthen 	c_error_va_list_pos(showpos, fmt, ap);
9595435475dSsthen 	va_end(ap);
96062ac0c33Sjakob }
96162ac0c33Sjakob 
962d3fecca9Ssthen int
c_wrap(void)9635435475dSsthen c_wrap(void)
96462ac0c33Sjakob {
96562ac0c33Sjakob 	return 1;
96662ac0c33Sjakob }
96762ac0c33Sjakob 
968fe5fe5f6Sflorian struct zone_options*
zone_options_create(region_type * region)969d3fecca9Ssthen zone_options_create(region_type* region)
97062ac0c33Sjakob {
971fe5fe5f6Sflorian 	struct zone_options* zone;
972fe5fe5f6Sflorian 	zone = (struct zone_options*)region_alloc(region, sizeof(
973fe5fe5f6Sflorian 		struct zone_options));
97462ac0c33Sjakob 	zone->node = *RBTREE_NULL;
97562ac0c33Sjakob 	zone->name = 0;
976d3fecca9Ssthen 	zone->pattern = 0;
977d3fecca9Ssthen 	zone->part_of_config = 0;
978*bf87c3c0Sflorian 	zone->is_catalog_member_zone = 0;
97962ac0c33Sjakob 	return zone;
98062ac0c33Sjakob }
98162ac0c33Sjakob 
982*bf87c3c0Sflorian struct catalog_member_zone*
catalog_member_zone_create(region_type * region)983*bf87c3c0Sflorian catalog_member_zone_create(region_type* region)
984*bf87c3c0Sflorian {
985*bf87c3c0Sflorian 	struct catalog_member_zone* member_zone;
986*bf87c3c0Sflorian 	member_zone = (struct catalog_member_zone*)region_alloc(region,
987*bf87c3c0Sflorian 			sizeof(struct catalog_member_zone));
988*bf87c3c0Sflorian 	member_zone->options.node = *RBTREE_NULL;
989*bf87c3c0Sflorian 	member_zone->options.name = 0;
990*bf87c3c0Sflorian 	member_zone->options.pattern = 0;
991*bf87c3c0Sflorian 	member_zone->options.part_of_config = 0;
992*bf87c3c0Sflorian 	member_zone->options.is_catalog_member_zone = 1;
993*bf87c3c0Sflorian 	member_zone->member_id = NULL;
994*bf87c3c0Sflorian 	member_zone->node = *RBTREE_NULL;
995*bf87c3c0Sflorian 	return member_zone;
996*bf87c3c0Sflorian }
997*bf87c3c0Sflorian 
998d3fecca9Ssthen /* true is booleans are the same truth value */
999d3fecca9Ssthen #define booleq(x,y) ( ((x) && (y)) || (!(x) && !(y)) )
1000d3fecca9Ssthen 
1001ac5517e4Sflorian /* true is min_expire_time_expr has either an equal known value
1002ac5517e4Sflorian  * or none of these known values but booleanally equal
1003ac5517e4Sflorian  */
1004ac5517e4Sflorian #define expire_expr_eq(x,y) (  (  (x) == REFRESHPLUSRETRYPLUS1 \
1005ac5517e4Sflorian                                && (y) == REFRESHPLUSRETRYPLUS1 ) \
1006ac5517e4Sflorian                             || (  (x) != REFRESHPLUSRETRYPLUS1 \
1007ac5517e4Sflorian                                && (y) != REFRESHPLUSRETRYPLUS1 \
1008ac5517e4Sflorian                                && booleq((x), (y))))
1009ac5517e4Sflorian 
1010ac5517e4Sflorian 
1011d3fecca9Ssthen int
acl_equal(struct acl_options * p,struct acl_options * q)1012fe5fe5f6Sflorian acl_equal(struct acl_options* p, struct acl_options* q)
101362ac0c33Sjakob {
1014d3fecca9Ssthen 	if(!booleq(p->use_axfr_only, q->use_axfr_only)) return 0;
1015d3fecca9Ssthen 	if(!booleq(p->allow_udp, q->allow_udp)) return 0;
1016d3fecca9Ssthen 	if(strcmp(p->ip_address_spec, q->ip_address_spec)!=0) return 0;
1017d3fecca9Ssthen 	/* the ip6, port, addr, mask, type: are derived from the ip_address_spec */
1018d3fecca9Ssthen 	if(!booleq(p->nokey, q->nokey)) return 0;
1019d3fecca9Ssthen 	if(!booleq(p->blocked, q->blocked)) return 0;
1020d3fecca9Ssthen 	if(p->key_name && q->key_name) {
1021d3fecca9Ssthen 		if(strcmp(p->key_name, q->key_name)!=0) return 0;
1022d3fecca9Ssthen 	} else if(p->key_name && !q->key_name) return 0;
1023d3fecca9Ssthen 	else if(!p->key_name && q->key_name) return 0;
1024d3fecca9Ssthen 	/* key_options is derived from key_name */
1025063644e9Sflorian 	if(p->tls_auth_name && q->tls_auth_name) {
1026063644e9Sflorian 		if(strcmp(p->tls_auth_name, q->tls_auth_name)!=0) return 0;
1027063644e9Sflorian 	} else if(p->tls_auth_name && !q->tls_auth_name) return 0;
1028063644e9Sflorian 	else if(!p->tls_auth_name && q->tls_auth_name) return 0;
1029063644e9Sflorian 	/* tls_auth_options is derived from tls_auth_name */
1030d3fecca9Ssthen 	return 1;
103162ac0c33Sjakob }
103262ac0c33Sjakob 
1033d3fecca9Ssthen int
acl_list_equal(struct acl_options * p,struct acl_options * q)1034fe5fe5f6Sflorian acl_list_equal(struct acl_options* p, struct acl_options* q)
103562ac0c33Sjakob {
1036d3fecca9Ssthen 	/* must be same and in same order */
1037d3fecca9Ssthen 	while(p && q) {
1038d3fecca9Ssthen 		if(!acl_equal(p, q))
1039d3fecca9Ssthen 			return 0;
1040d3fecca9Ssthen 		p = p->next;
1041d3fecca9Ssthen 		q = q->next;
104262ac0c33Sjakob 	}
1043d3fecca9Ssthen 	if(!p && !q) return 1;
1044d3fecca9Ssthen 	/* different lengths */
104562ac0c33Sjakob 	return 0;
104662ac0c33Sjakob }
104762ac0c33Sjakob 
1048fe5fe5f6Sflorian struct pattern_options*
pattern_options_create(region_type * region)1049d3fecca9Ssthen pattern_options_create(region_type* region)
1050d3fecca9Ssthen {
1051fe5fe5f6Sflorian 	struct pattern_options* p;
1052fe5fe5f6Sflorian 	p = (struct pattern_options*)region_alloc(region, sizeof(
1053fe5fe5f6Sflorian 		struct pattern_options));
1054d3fecca9Ssthen 	p->node = *RBTREE_NULL;
1055d3fecca9Ssthen 	p->pname = 0;
1056d3fecca9Ssthen 	p->zonefile = 0;
10579e506f0aSbrad 	p->zonestats = 0;
1058d3fecca9Ssthen 	p->allow_notify = 0;
1059d3fecca9Ssthen 	p->request_xfr = 0;
10606e9bf1eeSflorian 	p->size_limit_xfr = 0;
1061d3fecca9Ssthen 	p->notify = 0;
1062d3fecca9Ssthen 	p->provide_xfr = 0;
10638d298c9fSsthen 	p->allow_query = 0;
1064d3fecca9Ssthen 	p->outgoing_interface = 0;
1065d3fecca9Ssthen 	p->notify_retry = 5;
1066d3fecca9Ssthen 	p->notify_retry_is_default = 1;
1067d3fecca9Ssthen 	p->allow_axfr_fallback = 1;
1068d3fecca9Ssthen 	p->allow_axfr_fallback_is_default = 1;
1069d3fecca9Ssthen 	p->implicit = 0;
1070d3fecca9Ssthen 	p->xfrd_flags = 0;
10716e9bf1eeSflorian 	p->max_refresh_time = 2419200;	/* 4 weeks */
10726e9bf1eeSflorian 	p->max_refresh_time_is_default = 1;
10736e9bf1eeSflorian 	p->min_refresh_time = 0;
10746e9bf1eeSflorian 	p->min_refresh_time_is_default = 1;
10756e9bf1eeSflorian 	p->max_retry_time = 1209600;	/* 2 weeks */
10766e9bf1eeSflorian 	p->max_retry_time_is_default = 1;
10776e9bf1eeSflorian 	p->min_retry_time = 0;
10786e9bf1eeSflorian 	p->min_retry_time_is_default = 1;
1079ac5517e4Sflorian 	p->min_expire_time = 0;
1080ac5517e4Sflorian 	p->min_expire_time_expr = EXPIRE_TIME_IS_DEFAULT;
1081d3fecca9Ssthen #ifdef RATELIMIT
1082d3fecca9Ssthen 	p->rrl_whitelist = 0;
1083d3fecca9Ssthen #endif
1084*bf87c3c0Sflorian 	p->multi_primary_check = 0;
10854564029fSflorian 	p->store_ixfr = 0;
10864564029fSflorian 	p->store_ixfr_is_default = 1;
10874564029fSflorian 	p->ixfr_size = IXFR_SIZE_DEFAULT;
10884564029fSflorian 	p->ixfr_size_is_default = 1;
10894564029fSflorian 	p->ixfr_number = IXFR_NUMBER_DEFAULT;
10904564029fSflorian 	p->ixfr_number_is_default = 1;
10914564029fSflorian 	p->create_ixfr = 0;
10924564029fSflorian 	p->create_ixfr_is_default = 1;
10933f21e8ccSflorian 	p->verify_zone = VERIFY_ZONE_INHERIT;
10943f21e8ccSflorian 	p->verify_zone_is_default = 1;
10953f21e8ccSflorian 	p->verifier = NULL;
10963f21e8ccSflorian 	p->verifier_feed_zone = VERIFIER_FEED_ZONE_INHERIT;
10973f21e8ccSflorian 	p->verifier_feed_zone_is_default = 1;
10983f21e8ccSflorian 	p->verifier_timeout = VERIFIER_TIMEOUT_INHERIT;
10993f21e8ccSflorian 	p->verifier_timeout_is_default = 1;
1100*bf87c3c0Sflorian 	p->catalog_role = CATALOG_ROLE_INHERIT;
1101*bf87c3c0Sflorian 	p->catalog_role_is_default = 1;
1102*bf87c3c0Sflorian 	p->catalog_member_pattern = NULL;
1103*bf87c3c0Sflorian 	p->catalog_producer_zone = NULL;
1104d3fecca9Ssthen 	return p;
1105d3fecca9Ssthen }
1106d3fecca9Ssthen 
1107d3fecca9Ssthen static void
acl_delete(region_type * region,struct acl_options * acl)1108fe5fe5f6Sflorian acl_delete(region_type* region, struct acl_options* acl)
1109d3fecca9Ssthen {
1110d3fecca9Ssthen 	if(acl->ip_address_spec)
1111d3fecca9Ssthen 		region_recycle(region, (void*)acl->ip_address_spec,
1112d3fecca9Ssthen 			strlen(acl->ip_address_spec)+1);
1113d3fecca9Ssthen 	if(acl->key_name)
1114d3fecca9Ssthen 		region_recycle(region, (void*)acl->key_name,
1115d3fecca9Ssthen 			strlen(acl->key_name)+1);
1116063644e9Sflorian 	if(acl->tls_auth_name)
1117063644e9Sflorian 		region_recycle(region, (void*)acl->tls_auth_name,
1118063644e9Sflorian 			strlen(acl->tls_auth_name)+1);
1119d3fecca9Ssthen 	/* key_options is a convenience pointer, not owned by the acl */
1120d3fecca9Ssthen 	region_recycle(region, acl, sizeof(*acl));
1121d3fecca9Ssthen }
1122d3fecca9Ssthen 
1123d3fecca9Ssthen static void
acl_list_delete(region_type * region,struct acl_options * list)1124fe5fe5f6Sflorian acl_list_delete(region_type* region, struct acl_options* list)
1125d3fecca9Ssthen {
1126fe5fe5f6Sflorian 	struct acl_options* n;
1127d3fecca9Ssthen 	while(list) {
1128d3fecca9Ssthen 		n = list->next;
1129d3fecca9Ssthen 		acl_delete(region, list);
1130d3fecca9Ssthen 		list = n;
1131d3fecca9Ssthen 	}
1132d3fecca9Ssthen }
1133d3fecca9Ssthen 
11343f21e8ccSflorian static void
verifier_delete(region_type * region,char ** v)11353f21e8ccSflorian verifier_delete(region_type* region, char **v)
11363f21e8ccSflorian {
11373f21e8ccSflorian 	if(v != NULL) {
11383f21e8ccSflorian 		size_t vc = 0;
11393f21e8ccSflorian 		for(vc = 0; v[vc] != NULL; vc++)
11403f21e8ccSflorian 			region_recycle(region, v[vc], strlen(v[vc]) + 1);
11413f21e8ccSflorian 		region_recycle(region, v, (vc + 1) * sizeof(char *));
11423f21e8ccSflorian 	}
11433f21e8ccSflorian }
11443f21e8ccSflorian 
1145d3fecca9Ssthen void
pattern_options_remove(struct nsd_options * opt,const char * name)1146fe5fe5f6Sflorian pattern_options_remove(struct nsd_options* opt, const char* name)
1147d3fecca9Ssthen {
1148fe5fe5f6Sflorian 	struct pattern_options* p = (struct pattern_options*)rbtree_delete(
1149d3fecca9Ssthen 		opt->patterns, name);
1150d3fecca9Ssthen 	/* delete p and its contents */
1151d3fecca9Ssthen 	if (!p)
1152d3fecca9Ssthen 		return;
1153d3fecca9Ssthen 	if(p->pname)
1154d3fecca9Ssthen 		region_recycle(opt->region, (void*)p->pname,
1155d3fecca9Ssthen 			strlen(p->pname)+1);
1156d3fecca9Ssthen 	if(p->zonefile)
1157d3fecca9Ssthen 		region_recycle(opt->region, (void*)p->zonefile,
1158d3fecca9Ssthen 			strlen(p->zonefile)+1);
11599e506f0aSbrad 	if(p->zonestats)
11609e506f0aSbrad 		region_recycle(opt->region, (void*)p->zonestats,
11619e506f0aSbrad 			strlen(p->zonestats)+1);
1162d3fecca9Ssthen 	acl_list_delete(opt->region, p->allow_notify);
1163d3fecca9Ssthen 	acl_list_delete(opt->region, p->request_xfr);
1164d3fecca9Ssthen 	acl_list_delete(opt->region, p->notify);
1165d3fecca9Ssthen 	acl_list_delete(opt->region, p->provide_xfr);
11668d298c9fSsthen 	acl_list_delete(opt->region, p->allow_query);
1167d3fecca9Ssthen 	acl_list_delete(opt->region, p->outgoing_interface);
11683f21e8ccSflorian 	verifier_delete(opt->region, p->verifier);
1169d3fecca9Ssthen 
1170fe5fe5f6Sflorian 	region_recycle(opt->region, p, sizeof(struct pattern_options));
1171d3fecca9Ssthen }
1172d3fecca9Ssthen 
1173fe5fe5f6Sflorian static struct acl_options*
copy_acl(region_type * region,struct acl_options * a)1174fe5fe5f6Sflorian copy_acl(region_type* region, struct acl_options* a)
1175d3fecca9Ssthen {
1176fe5fe5f6Sflorian 	struct acl_options* b;
1177d3fecca9Ssthen 	if(!a) return NULL;
1178fe5fe5f6Sflorian 	b = (struct acl_options*)region_alloc(region, sizeof(*b));
1179d3fecca9Ssthen 	/* copy the whole lot */
1180d3fecca9Ssthen 	*b = *a;
1181d3fecca9Ssthen 	/* fix the pointers */
1182d3fecca9Ssthen 	if(a->ip_address_spec)
1183d3fecca9Ssthen 		b->ip_address_spec = region_strdup(region, a->ip_address_spec);
1184d3fecca9Ssthen 	if(a->key_name)
1185d3fecca9Ssthen 		b->key_name = region_strdup(region, a->key_name);
1186063644e9Sflorian 	if(a->tls_auth_name)
1187063644e9Sflorian 		b->tls_auth_name = region_strdup(region, a->tls_auth_name);
1188d3fecca9Ssthen 	b->next = NULL;
1189d3fecca9Ssthen 	b->key_options = NULL;
1190063644e9Sflorian 	b->tls_auth_options = NULL;
1191d3fecca9Ssthen 	return b;
1192d3fecca9Ssthen }
1193d3fecca9Ssthen 
1194fe5fe5f6Sflorian static struct acl_options*
copy_acl_list(struct nsd_options * opt,struct acl_options * a)1195fe5fe5f6Sflorian copy_acl_list(struct nsd_options* opt, struct acl_options* a)
1196d3fecca9Ssthen {
1197fe5fe5f6Sflorian 	struct acl_options* b, *blast = NULL, *blist = NULL;
1198d3fecca9Ssthen 	while(a) {
1199d3fecca9Ssthen 		b = copy_acl(opt->region, a);
1200d3fecca9Ssthen 		/* fixup key_options */
1201d3fecca9Ssthen 		if(b->key_name)
1202d3fecca9Ssthen 			b->key_options = key_options_find(opt, b->key_name);
1203d3fecca9Ssthen 		else	b->key_options = NULL;
1204063644e9Sflorian 		/* fixup tls_auth_options */
1205063644e9Sflorian 		if(b->tls_auth_name)
1206063644e9Sflorian 			b->tls_auth_options = tls_auth_options_find(opt, b->tls_auth_name);
1207063644e9Sflorian 		else	b->tls_auth_options = NULL;
1208d3fecca9Ssthen 
1209d3fecca9Ssthen 		/* link as last into list */
1210d3fecca9Ssthen 		b->next = NULL;
1211d3fecca9Ssthen 		if(!blist) blist = b;
1212d3fecca9Ssthen 		else blast->next = b;
1213d3fecca9Ssthen 		blast = b;
1214d3fecca9Ssthen 
1215d3fecca9Ssthen 		a = a->next;
1216d3fecca9Ssthen 	}
1217d3fecca9Ssthen 	return blist;
1218d3fecca9Ssthen }
1219d3fecca9Ssthen 
1220d3fecca9Ssthen static void
copy_changed_acl(struct nsd_options * opt,struct acl_options ** orig,struct acl_options * anew)1221fe5fe5f6Sflorian copy_changed_acl(struct nsd_options* opt, struct acl_options** orig,
1222fe5fe5f6Sflorian 	struct acl_options* anew)
1223d3fecca9Ssthen {
1224d3fecca9Ssthen 	if(!acl_list_equal(*orig, anew)) {
1225d3fecca9Ssthen 		acl_list_delete(opt->region, *orig);
1226d3fecca9Ssthen 		*orig = copy_acl_list(opt, anew);
1227d3fecca9Ssthen 	}
1228d3fecca9Ssthen }
1229d3fecca9Ssthen 
1230d3fecca9Ssthen static void
copy_changed_verifier(struct nsd_options * opt,char *** ov,char ** nv)12313f21e8ccSflorian copy_changed_verifier(struct nsd_options* opt, char ***ov, char **nv)
12323f21e8ccSflorian {
12333f21e8ccSflorian 	size_t ovc, nvc;
12343f21e8ccSflorian 	assert(ov != NULL);
12353f21e8ccSflorian 	ovc = nvc = 0;
12363f21e8ccSflorian 	if(nv != NULL) {
12373f21e8ccSflorian 		for(; nv[nvc] != NULL; nvc++) ;
12383f21e8ccSflorian 	} else {
12393f21e8ccSflorian 		verifier_delete(opt->region, *ov);
12403f21e8ccSflorian 		*ov = NULL;
12413f21e8ccSflorian 		return;
12423f21e8ccSflorian 	}
12433f21e8ccSflorian 	if(*ov != NULL) {
12443f21e8ccSflorian 		for(; (*ov)[ovc] != NULL; ovc++) {
12453f21e8ccSflorian 			if(ovc < nvc && strcmp((*ov)[ovc], nv[ovc]) != 0)
12463f21e8ccSflorian 				break;
12473f21e8ccSflorian 		}
12483f21e8ccSflorian 		if(ovc == nvc)
12493f21e8ccSflorian 			return;
12503f21e8ccSflorian 		verifier_delete(opt->region, *ov);
12513f21e8ccSflorian 		*ov = NULL;
12523f21e8ccSflorian 	}
12533f21e8ccSflorian 	*ov = region_alloc(opt->region, (nvc + 1) * sizeof(*nv));
12543f21e8ccSflorian 	for(ovc = 0; nv[ovc] != NULL; ovc++) {
12553f21e8ccSflorian 		(*ov)[ovc] = region_strdup(opt->region, nv[ovc]);
12563f21e8ccSflorian 	}
12573f21e8ccSflorian 	(*ov)[ovc] = NULL;
12583f21e8ccSflorian 	assert(ovc == nvc);
12593f21e8ccSflorian }
12603f21e8ccSflorian 
12613f21e8ccSflorian static void
copy_pat_fixed(region_type * region,struct pattern_options * orig,struct pattern_options * p)1262fe5fe5f6Sflorian copy_pat_fixed(region_type* region, struct pattern_options* orig,
1263fe5fe5f6Sflorian 	struct pattern_options* p)
1264d3fecca9Ssthen {
1265d3fecca9Ssthen 	orig->allow_axfr_fallback = p->allow_axfr_fallback;
1266d3fecca9Ssthen 	orig->allow_axfr_fallback_is_default =
1267d3fecca9Ssthen 		p->allow_axfr_fallback_is_default;
1268d3fecca9Ssthen 	orig->notify_retry = p->notify_retry;
1269d3fecca9Ssthen 	orig->notify_retry_is_default = p->notify_retry_is_default;
1270d3fecca9Ssthen 	orig->implicit = p->implicit;
1271d3fecca9Ssthen 	if(p->zonefile)
1272d3fecca9Ssthen 		orig->zonefile = region_strdup(region, p->zonefile);
1273d3fecca9Ssthen 	else orig->zonefile = NULL;
12749e506f0aSbrad 	if(p->zonestats)
12759e506f0aSbrad 		orig->zonestats = region_strdup(region, p->zonestats);
12769e506f0aSbrad 	else orig->zonestats = NULL;
12776e9bf1eeSflorian 	orig->max_refresh_time = p->max_refresh_time;
12786e9bf1eeSflorian 	orig->max_refresh_time_is_default = p->max_refresh_time_is_default;
12796e9bf1eeSflorian 	orig->min_refresh_time = p->min_refresh_time;
12806e9bf1eeSflorian 	orig->min_refresh_time_is_default = p->min_refresh_time_is_default;
12816e9bf1eeSflorian 	orig->max_retry_time = p->max_retry_time;
12826e9bf1eeSflorian 	orig->max_retry_time_is_default = p->max_retry_time_is_default;
12836e9bf1eeSflorian 	orig->min_retry_time = p->min_retry_time;
12846e9bf1eeSflorian 	orig->min_retry_time_is_default = p->min_retry_time_is_default;
1285ac5517e4Sflorian 	orig->min_expire_time = p->min_expire_time;
1286ac5517e4Sflorian 	orig->min_expire_time_expr = p->min_expire_time_expr;
1287d3fecca9Ssthen #ifdef RATELIMIT
1288d3fecca9Ssthen 	orig->rrl_whitelist = p->rrl_whitelist;
1289d3fecca9Ssthen #endif
1290*bf87c3c0Sflorian 	orig->multi_primary_check = p->multi_primary_check;
12914564029fSflorian 	orig->store_ixfr = p->store_ixfr;
12924564029fSflorian 	orig->store_ixfr_is_default = p->store_ixfr_is_default;
12934564029fSflorian 	orig->ixfr_size = p->ixfr_size;
12944564029fSflorian 	orig->ixfr_size_is_default = p->ixfr_size_is_default;
12954564029fSflorian 	orig->ixfr_number = p->ixfr_number;
12964564029fSflorian 	orig->ixfr_number_is_default = p->ixfr_number_is_default;
12974564029fSflorian 	orig->create_ixfr = p->create_ixfr;
12984564029fSflorian 	orig->create_ixfr_is_default = p->create_ixfr_is_default;
12993f21e8ccSflorian 	orig->verify_zone = p->verify_zone;
13003f21e8ccSflorian 	orig->verify_zone_is_default = p->verify_zone_is_default;
13013f21e8ccSflorian 	orig->verifier_timeout = p->verifier_timeout;
13023f21e8ccSflorian 	orig->verifier_timeout_is_default = p->verifier_timeout_is_default;
13033f21e8ccSflorian 	orig->verifier_feed_zone = p->verifier_feed_zone;
13043f21e8ccSflorian 	orig->verifier_feed_zone_is_default = p->verifier_feed_zone_is_default;
1305*bf87c3c0Sflorian 	orig->catalog_role = p->catalog_role;
1306*bf87c3c0Sflorian 	orig->catalog_role_is_default = p->catalog_role_is_default;
1307*bf87c3c0Sflorian 	if(p->catalog_member_pattern)
1308*bf87c3c0Sflorian 		orig->catalog_member_pattern =
1309*bf87c3c0Sflorian 			region_strdup(region, p->catalog_member_pattern);
1310*bf87c3c0Sflorian 	else orig->catalog_member_pattern = NULL;
1311*bf87c3c0Sflorian 	if(p->catalog_producer_zone)
1312*bf87c3c0Sflorian 		orig->catalog_producer_zone =
1313*bf87c3c0Sflorian 			region_strdup(region, p->catalog_producer_zone);
1314*bf87c3c0Sflorian 	else orig->catalog_producer_zone = NULL;
1315d3fecca9Ssthen }
1316d3fecca9Ssthen 
1317d3fecca9Ssthen void
pattern_options_add_modify(struct nsd_options * opt,struct pattern_options * p)1318fe5fe5f6Sflorian pattern_options_add_modify(struct nsd_options* opt, struct pattern_options* p)
1319d3fecca9Ssthen {
1320fe5fe5f6Sflorian 	struct pattern_options* orig = pattern_options_find(opt, p->pname);
1321d3fecca9Ssthen 	if(!orig) {
1322d3fecca9Ssthen 		/* needs to be copied to opt region */
1323d3fecca9Ssthen 		orig = pattern_options_create(opt->region);
1324d3fecca9Ssthen 		orig->pname = region_strdup(opt->region, p->pname);
1325d3fecca9Ssthen 		copy_pat_fixed(opt->region, orig, p);
1326d3fecca9Ssthen 		orig->allow_notify = copy_acl_list(opt, p->allow_notify);
1327d3fecca9Ssthen 		orig->request_xfr = copy_acl_list(opt, p->request_xfr);
1328d3fecca9Ssthen 		orig->notify = copy_acl_list(opt, p->notify);
1329d3fecca9Ssthen 		orig->provide_xfr = copy_acl_list(opt, p->provide_xfr);
13308d298c9fSsthen 		orig->allow_query = copy_acl_list(opt, p->allow_query);
1331d3fecca9Ssthen 		orig->outgoing_interface = copy_acl_list(opt,
1332d3fecca9Ssthen 			p->outgoing_interface);
13333f21e8ccSflorian 		copy_changed_verifier(opt, &orig->verifier, p->verifier);
1334d3fecca9Ssthen 		nsd_options_insert_pattern(opt, orig);
1335d3fecca9Ssthen 	} else {
1336d3fecca9Ssthen 		/* modify in place so pointers stay valid (and copy
1337d3fecca9Ssthen 		   into region). Do not touch unchanged acls. */
1338d3fecca9Ssthen 		if(orig->zonefile)
1339d3fecca9Ssthen 			region_recycle(opt->region, (char*)orig->zonefile,
1340d3fecca9Ssthen 				strlen(orig->zonefile)+1);
13419e506f0aSbrad 		if(orig->zonestats)
13429e506f0aSbrad 			region_recycle(opt->region, (char*)orig->zonestats,
13439e506f0aSbrad 				strlen(orig->zonestats)+1);
1344d3fecca9Ssthen 		copy_pat_fixed(opt->region, orig, p);
1345d3fecca9Ssthen 		copy_changed_acl(opt, &orig->allow_notify, p->allow_notify);
1346d3fecca9Ssthen 		copy_changed_acl(opt, &orig->request_xfr, p->request_xfr);
1347d3fecca9Ssthen 		copy_changed_acl(opt, &orig->notify, p->notify);
1348d3fecca9Ssthen 		copy_changed_acl(opt, &orig->provide_xfr, p->provide_xfr);
13498d298c9fSsthen 		copy_changed_acl(opt, &orig->allow_query, p->allow_query);
1350d3fecca9Ssthen 		copy_changed_acl(opt, &orig->outgoing_interface,
1351d3fecca9Ssthen 			p->outgoing_interface);
13523f21e8ccSflorian 		copy_changed_verifier(opt, &orig->verifier, p->verifier);
1353d3fecca9Ssthen 	}
1354d3fecca9Ssthen }
1355d3fecca9Ssthen 
1356fe5fe5f6Sflorian struct pattern_options*
pattern_options_find(struct nsd_options * opt,const char * name)1357fe5fe5f6Sflorian pattern_options_find(struct nsd_options* opt, const char* name)
1358d3fecca9Ssthen {
1359fe5fe5f6Sflorian 	return (struct pattern_options*)rbtree_search(opt->patterns, name);
1360d3fecca9Ssthen }
1361d3fecca9Ssthen 
13623f21e8ccSflorian static int
pattern_verifiers_equal(const char ** vp,const char ** vq)13633f21e8ccSflorian pattern_verifiers_equal(const char **vp, const char **vq)
13643f21e8ccSflorian {
13653f21e8ccSflorian 	size_t vpc, vqc;
13663f21e8ccSflorian 	if(vp == NULL)
13673f21e8ccSflorian 		return vq == NULL;
13683f21e8ccSflorian 	if(vq == NULL)
13693f21e8ccSflorian 		return 0;
13703f21e8ccSflorian 	for(vpc = 0; vp[vpc] != NULL; vpc++) ;
13713f21e8ccSflorian 	for(vqc = 0; vq[vqc] != NULL; vqc++) ;
13723f21e8ccSflorian 	if(vpc != vqc)
13733f21e8ccSflorian 		return 0;
13743f21e8ccSflorian 	for(vpc = 0; vp[vpc] != NULL; vpc++) {
13753f21e8ccSflorian 		assert(vq[vpc] != NULL);
13763f21e8ccSflorian 		if (strcmp(vp[vpc], vq[vpc]) != 0)
13773f21e8ccSflorian 			return 0;
13783f21e8ccSflorian 	}
13793f21e8ccSflorian 	return 1;
13803f21e8ccSflorian }
13813f21e8ccSflorian 
1382d3fecca9Ssthen int
pattern_options_equal(struct pattern_options * p,struct pattern_options * q)1383fe5fe5f6Sflorian pattern_options_equal(struct pattern_options* p, struct pattern_options* q)
1384d3fecca9Ssthen {
1385d3fecca9Ssthen 	if(strcmp(p->pname, q->pname) != 0) return 0;
1386d3fecca9Ssthen 	if(!p->zonefile && q->zonefile) return 0;
1387d3fecca9Ssthen 	else if(p->zonefile && !q->zonefile) return 0;
1388d3fecca9Ssthen 	else if(p->zonefile && q->zonefile) {
1389d3fecca9Ssthen 		if(strcmp(p->zonefile, q->zonefile) != 0) return 0;
1390d3fecca9Ssthen 	}
13919e506f0aSbrad 	if(!p->zonestats && q->zonestats) return 0;
13929e506f0aSbrad 	else if(p->zonestats && !q->zonestats) return 0;
13939e506f0aSbrad 	else if(p->zonestats && q->zonestats) {
13949e506f0aSbrad 		if(strcmp(p->zonestats, q->zonestats) != 0) return 0;
13959e506f0aSbrad 	}
1396d3fecca9Ssthen 	if(!booleq(p->allow_axfr_fallback, q->allow_axfr_fallback)) return 0;
1397d3fecca9Ssthen 	if(!booleq(p->allow_axfr_fallback_is_default,
1398d3fecca9Ssthen 		q->allow_axfr_fallback_is_default)) return 0;
1399d3fecca9Ssthen 	if(p->notify_retry != q->notify_retry) return 0;
1400d3fecca9Ssthen 	if(!booleq(p->notify_retry_is_default,
1401d3fecca9Ssthen 		q->notify_retry_is_default)) return 0;
1402d3fecca9Ssthen 	if(!booleq(p->implicit, q->implicit)) return 0;
1403d3fecca9Ssthen 	if(!acl_list_equal(p->allow_notify, q->allow_notify)) return 0;
1404d3fecca9Ssthen 	if(!acl_list_equal(p->request_xfr, q->request_xfr)) return 0;
1405d3fecca9Ssthen 	if(!acl_list_equal(p->notify, q->notify)) return 0;
1406d3fecca9Ssthen 	if(!acl_list_equal(p->provide_xfr, q->provide_xfr)) return 0;
14078d298c9fSsthen 	if(!acl_list_equal(p->allow_query, q->allow_query)) return 0;
1408d3fecca9Ssthen 	if(!acl_list_equal(p->outgoing_interface, q->outgoing_interface))
1409d3fecca9Ssthen 		return 0;
14106e9bf1eeSflorian 	if(p->max_refresh_time != q->max_refresh_time) return 0;
14116e9bf1eeSflorian 	if(!booleq(p->max_refresh_time_is_default,
14126e9bf1eeSflorian 		q->max_refresh_time_is_default)) return 0;
14136e9bf1eeSflorian 	if(p->min_refresh_time != q->min_refresh_time) return 0;
14146e9bf1eeSflorian 	if(!booleq(p->min_refresh_time_is_default,
14156e9bf1eeSflorian 		q->min_refresh_time_is_default)) return 0;
14166e9bf1eeSflorian 	if(p->max_retry_time != q->max_retry_time) return 0;
14176e9bf1eeSflorian 	if(!booleq(p->max_retry_time_is_default,
14186e9bf1eeSflorian 		q->max_retry_time_is_default)) return 0;
14196e9bf1eeSflorian 	if(p->min_retry_time != q->min_retry_time) return 0;
14206e9bf1eeSflorian 	if(!booleq(p->min_retry_time_is_default,
14216e9bf1eeSflorian 		q->min_retry_time_is_default)) return 0;
1422ac5517e4Sflorian 	if(p->min_expire_time != q->min_expire_time) return 0;
1423ac5517e4Sflorian 	if(!expire_expr_eq(p->min_expire_time_expr,
1424ac5517e4Sflorian 		q->min_expire_time_expr)) return 0;
1425d3fecca9Ssthen #ifdef RATELIMIT
1426d3fecca9Ssthen 	if(p->rrl_whitelist != q->rrl_whitelist) return 0;
1427d3fecca9Ssthen #endif
1428*bf87c3c0Sflorian 	if(!booleq(p->multi_primary_check,q->multi_primary_check)) return 0;
14296e9bf1eeSflorian 	if(p->size_limit_xfr != q->size_limit_xfr) return 0;
14304564029fSflorian 	if(!booleq(p->store_ixfr,q->store_ixfr)) return 0;
14314564029fSflorian 	if(!booleq(p->store_ixfr_is_default,q->store_ixfr_is_default)) return 0;
14324564029fSflorian 	if(p->ixfr_size != q->ixfr_size) return 0;
14334564029fSflorian 	if(!booleq(p->ixfr_size_is_default,q->ixfr_size_is_default)) return 0;
14344564029fSflorian 	if(p->ixfr_number != q->ixfr_number) return 0;
14354564029fSflorian 	if(!booleq(p->ixfr_number_is_default,q->ixfr_number_is_default)) return 0;
14364564029fSflorian 	if(!booleq(p->create_ixfr,q->create_ixfr)) return 0;
14374564029fSflorian 	if(!booleq(p->create_ixfr_is_default,q->create_ixfr_is_default)) return 0;
14383f21e8ccSflorian 	if(p->verify_zone != q->verify_zone) return 0;
14393f21e8ccSflorian 	if(!booleq(p->verify_zone_is_default,
14403f21e8ccSflorian 		q->verify_zone_is_default)) return 0;
14413f21e8ccSflorian 	if(!pattern_verifiers_equal((const char **)p->verifier,
14423f21e8ccSflorian 		(const char **)q->verifier)) return 0;
14433f21e8ccSflorian 	if(p->verifier_feed_zone != q->verifier_feed_zone) return 0;
14443f21e8ccSflorian 	if(!booleq(p->verifier_feed_zone_is_default,
14453f21e8ccSflorian 		q->verifier_feed_zone_is_default)) return 0;
14463f21e8ccSflorian 	if(p->verifier_timeout != q->verifier_timeout) return 0;
14473f21e8ccSflorian 	if(!booleq(p->verifier_timeout_is_default,
14483f21e8ccSflorian 		q->verifier_timeout_is_default)) return 0;
1449*bf87c3c0Sflorian 	if(p->catalog_role != q->catalog_role) return 0;
1450*bf87c3c0Sflorian 	if(!booleq(p->catalog_role_is_default,
1451*bf87c3c0Sflorian 		q->catalog_role_is_default)) return 0;
1452*bf87c3c0Sflorian 	if(!p->catalog_member_pattern && q->catalog_member_pattern) return 0;
1453*bf87c3c0Sflorian 	else if(p->catalog_member_pattern && !q->catalog_member_pattern) return 0;
1454*bf87c3c0Sflorian 	else if(p->catalog_member_pattern && q->catalog_member_pattern) {
1455*bf87c3c0Sflorian 		if(strcmp(p->catalog_member_pattern, q->catalog_member_pattern) != 0) return 0;
1456*bf87c3c0Sflorian 	}
1457*bf87c3c0Sflorian 	if(!p->catalog_producer_zone && q->catalog_producer_zone) return 0;
1458*bf87c3c0Sflorian 	else if(p->catalog_producer_zone && !q->catalog_producer_zone) return 0;
1459*bf87c3c0Sflorian 	else if(p->catalog_producer_zone && q->catalog_producer_zone) {
1460*bf87c3c0Sflorian 		if(strcmp(p->catalog_producer_zone, q->catalog_producer_zone) != 0) return 0;
1461*bf87c3c0Sflorian 	}
1462d3fecca9Ssthen 	return 1;
1463d3fecca9Ssthen }
1464d3fecca9Ssthen 
1465d3fecca9Ssthen static void
marshal_u8(struct buffer * b,uint8_t v)1466d3fecca9Ssthen marshal_u8(struct buffer* b, uint8_t v)
1467d3fecca9Ssthen {
1468d3fecca9Ssthen 	buffer_reserve(b, 1);
1469d3fecca9Ssthen 	buffer_write_u8(b, v);
1470d3fecca9Ssthen }
1471d3fecca9Ssthen 
1472d3fecca9Ssthen static uint8_t
unmarshal_u8(struct buffer * b)1473d3fecca9Ssthen unmarshal_u8(struct buffer* b)
1474d3fecca9Ssthen {
1475d3fecca9Ssthen 	return buffer_read_u8(b);
1476d3fecca9Ssthen }
1477d3fecca9Ssthen 
14786e9bf1eeSflorian static void
marshal_u64(struct buffer * b,uint64_t v)14796e9bf1eeSflorian marshal_u64(struct buffer* b, uint64_t v)
14806e9bf1eeSflorian {
14816e9bf1eeSflorian 	buffer_reserve(b, 8);
14826e9bf1eeSflorian 	buffer_write_u64(b, v);
14836e9bf1eeSflorian }
14846e9bf1eeSflorian 
14856e9bf1eeSflorian static uint64_t
unmarshal_u64(struct buffer * b)14866e9bf1eeSflorian unmarshal_u64(struct buffer* b)
14876e9bf1eeSflorian {
14886e9bf1eeSflorian 	return buffer_read_u64(b);
14896e9bf1eeSflorian }
14906e9bf1eeSflorian 
1491d3fecca9Ssthen #ifdef RATELIMIT
1492d3fecca9Ssthen static void
marshal_u16(struct buffer * b,uint16_t v)1493d3fecca9Ssthen marshal_u16(struct buffer* b, uint16_t v)
1494d3fecca9Ssthen {
1495d3fecca9Ssthen 	buffer_reserve(b, 2);
1496d3fecca9Ssthen 	buffer_write_u16(b, v);
1497d3fecca9Ssthen }
1498d3fecca9Ssthen #endif
1499d3fecca9Ssthen 
1500d3fecca9Ssthen #ifdef RATELIMIT
1501d3fecca9Ssthen static uint16_t
unmarshal_u16(struct buffer * b)1502d3fecca9Ssthen unmarshal_u16(struct buffer* b)
1503d3fecca9Ssthen {
1504d3fecca9Ssthen 	return buffer_read_u16(b);
1505d3fecca9Ssthen }
1506d3fecca9Ssthen #endif
1507d3fecca9Ssthen 
1508d3fecca9Ssthen static void
marshal_u32(struct buffer * b,uint32_t v)15096e9bf1eeSflorian marshal_u32(struct buffer* b, uint32_t v)
15106e9bf1eeSflorian {
15116e9bf1eeSflorian 	buffer_reserve(b, 4);
15126e9bf1eeSflorian 	buffer_write_u32(b, v);
15136e9bf1eeSflorian }
15146e9bf1eeSflorian 
15156e9bf1eeSflorian static uint32_t
unmarshal_u32(struct buffer * b)15166e9bf1eeSflorian unmarshal_u32(struct buffer* b)
15176e9bf1eeSflorian {
15186e9bf1eeSflorian 	return buffer_read_u32(b);
15196e9bf1eeSflorian }
15206e9bf1eeSflorian 
15216e9bf1eeSflorian static void
marshal_str(struct buffer * b,const char * s)1522d3fecca9Ssthen marshal_str(struct buffer* b, const char* s)
1523d3fecca9Ssthen {
1524d3fecca9Ssthen 	if(!s) marshal_u8(b, 0);
1525d3fecca9Ssthen 	else {
1526d3fecca9Ssthen 		size_t len = strlen(s);
1527d3fecca9Ssthen 		marshal_u8(b, 1);
1528d3fecca9Ssthen 		buffer_reserve(b, len+1);
1529d3fecca9Ssthen 		buffer_write(b, s, len+1);
1530d3fecca9Ssthen 	}
1531d3fecca9Ssthen }
1532d3fecca9Ssthen 
1533d3fecca9Ssthen static char*
unmarshal_str(region_type * r,struct buffer * b)1534d3fecca9Ssthen unmarshal_str(region_type* r, struct buffer* b)
1535d3fecca9Ssthen {
1536d3fecca9Ssthen 	uint8_t nonnull = unmarshal_u8(b);
1537d3fecca9Ssthen 	if(nonnull) {
1538d3fecca9Ssthen 		char* result = region_strdup(r, (char*)buffer_current(b));
1539d3fecca9Ssthen 		size_t len = strlen((char*)buffer_current(b));
1540d3fecca9Ssthen 		buffer_skip(b, len+1);
1541d3fecca9Ssthen 		return result;
1542d3fecca9Ssthen 	} else return NULL;
1543d3fecca9Ssthen }
1544d3fecca9Ssthen 
1545d3fecca9Ssthen static void
marshal_acl(struct buffer * b,struct acl_options * acl)1546fe5fe5f6Sflorian marshal_acl(struct buffer* b, struct acl_options* acl)
1547d3fecca9Ssthen {
1548d3fecca9Ssthen 	buffer_reserve(b, sizeof(*acl));
1549d3fecca9Ssthen 	buffer_write(b, acl, sizeof(*acl));
1550d3fecca9Ssthen 	marshal_str(b, acl->ip_address_spec);
1551d3fecca9Ssthen 	marshal_str(b, acl->key_name);
1552063644e9Sflorian 	marshal_str(b, acl->tls_auth_name);
1553d3fecca9Ssthen }
1554d3fecca9Ssthen 
1555fe5fe5f6Sflorian static struct acl_options*
unmarshal_acl(region_type * r,struct buffer * b)1556d3fecca9Ssthen unmarshal_acl(region_type* r, struct buffer* b)
1557d3fecca9Ssthen {
1558fe5fe5f6Sflorian 	struct acl_options* acl = (struct acl_options*)region_alloc(r,
1559fe5fe5f6Sflorian 		sizeof(*acl));
1560d3fecca9Ssthen 	buffer_read(b, acl, sizeof(*acl));
1561d3fecca9Ssthen 	acl->next = NULL;
1562d3fecca9Ssthen 	acl->key_options = NULL;
1563063644e9Sflorian 	acl->tls_auth_options = NULL;
1564d3fecca9Ssthen 	acl->ip_address_spec = unmarshal_str(r, b);
1565d3fecca9Ssthen 	acl->key_name = unmarshal_str(r, b);
1566063644e9Sflorian 	acl->tls_auth_name = unmarshal_str(r, b);
1567d3fecca9Ssthen 	return acl;
1568d3fecca9Ssthen }
1569d3fecca9Ssthen 
1570d3fecca9Ssthen static void
marshal_acl_list(struct buffer * b,struct acl_options * list)1571fe5fe5f6Sflorian marshal_acl_list(struct buffer* b, struct acl_options* list)
1572d3fecca9Ssthen {
1573d3fecca9Ssthen 	while(list) {
1574d3fecca9Ssthen 		marshal_u8(b, 1); /* is there a next one marker */
1575d3fecca9Ssthen 		marshal_acl(b, list);
1576d3fecca9Ssthen 		list = list->next;
1577d3fecca9Ssthen 	}
1578d3fecca9Ssthen 	marshal_u8(b, 0); /* end of list marker */
1579d3fecca9Ssthen }
1580d3fecca9Ssthen 
1581fe5fe5f6Sflorian static struct acl_options*
unmarshal_acl_list(region_type * r,struct buffer * b)1582d3fecca9Ssthen unmarshal_acl_list(region_type* r, struct buffer* b)
1583d3fecca9Ssthen {
1584fe5fe5f6Sflorian 	struct acl_options* a, *last=NULL, *list=NULL;
1585d3fecca9Ssthen 	while(unmarshal_u8(b)) {
1586d3fecca9Ssthen 		a = unmarshal_acl(r, b);
1587d3fecca9Ssthen 		/* link in */
1588d3fecca9Ssthen 		a->next = NULL;
1589d3fecca9Ssthen 		if(!list) list = a;
1590d3fecca9Ssthen 		else last->next = a;
1591d3fecca9Ssthen 		last = a;
1592d3fecca9Ssthen 	}
1593d3fecca9Ssthen 	return list;
1594d3fecca9Ssthen }
1595d3fecca9Ssthen 
15963f21e8ccSflorian static void
marshal_strv(struct buffer * b,char ** strv)15973f21e8ccSflorian marshal_strv(struct buffer* b, char **strv)
15983f21e8ccSflorian {
15993f21e8ccSflorian 	uint32_t i, n;
16003f21e8ccSflorian 
16013f21e8ccSflorian 	assert(b != NULL);
16023f21e8ccSflorian 
16033f21e8ccSflorian 	if (strv == NULL) {
16043f21e8ccSflorian 		marshal_u32(b, 0);
16053f21e8ccSflorian 		return;
16063f21e8ccSflorian 	}
16073f21e8ccSflorian 	for(n = 0; strv[n]; n++) {
16083f21e8ccSflorian 		/* do nothing */
16093f21e8ccSflorian 	}
16103f21e8ccSflorian 	marshal_u32(b, n);
16113f21e8ccSflorian 	for(i = 0; strv[i] != NULL; i++) {
16123f21e8ccSflorian 		marshal_str(b, strv[i]);
16133f21e8ccSflorian 	}
16143f21e8ccSflorian 	marshal_u8(b, 0);
16153f21e8ccSflorian }
16163f21e8ccSflorian 
16173f21e8ccSflorian static char **
unmarshal_strv(region_type * r,struct buffer * b)16183f21e8ccSflorian unmarshal_strv(region_type* r, struct buffer* b)
16193f21e8ccSflorian {
16203f21e8ccSflorian 	uint32_t i, n;
16213f21e8ccSflorian 	char **strv;
16223f21e8ccSflorian 
16233f21e8ccSflorian 	assert(r != NULL);
16243f21e8ccSflorian 	assert(b != NULL);
16253f21e8ccSflorian 
16263f21e8ccSflorian 	if ((n = unmarshal_u32(b)) == 0) {
16273f21e8ccSflorian 		return NULL;
16283f21e8ccSflorian 	}
16293f21e8ccSflorian 	strv = region_alloc_zero(r, (n + 1) * sizeof(char *));
16303f21e8ccSflorian 	for(i = 0; i <= n; i++) {
16313f21e8ccSflorian 		strv[i] = unmarshal_str(r, b);
16323f21e8ccSflorian 	}
16333f21e8ccSflorian 	assert(i == (n + 1));
16343f21e8ccSflorian 	assert(strv[i - 1] == NULL);
16353f21e8ccSflorian 
16363f21e8ccSflorian 	return strv;
16373f21e8ccSflorian }
16383f21e8ccSflorian 
1639d3fecca9Ssthen void
pattern_options_marshal(struct buffer * b,struct pattern_options * p)1640fe5fe5f6Sflorian pattern_options_marshal(struct buffer* b, struct pattern_options* p)
1641d3fecca9Ssthen {
1642d3fecca9Ssthen 	marshal_str(b, p->pname);
1643d3fecca9Ssthen 	marshal_str(b, p->zonefile);
16449e506f0aSbrad 	marshal_str(b, p->zonestats);
1645d3fecca9Ssthen #ifdef RATELIMIT
1646d3fecca9Ssthen 	marshal_u16(b, p->rrl_whitelist);
1647d3fecca9Ssthen #endif
1648d3fecca9Ssthen 	marshal_u8(b, p->allow_axfr_fallback);
1649d3fecca9Ssthen 	marshal_u8(b, p->allow_axfr_fallback_is_default);
1650d3fecca9Ssthen 	marshal_u8(b, p->notify_retry);
1651d3fecca9Ssthen 	marshal_u8(b, p->notify_retry_is_default);
1652d3fecca9Ssthen 	marshal_u8(b, p->implicit);
16536e9bf1eeSflorian 	marshal_u64(b, p->size_limit_xfr);
1654d3fecca9Ssthen 	marshal_acl_list(b, p->allow_notify);
1655d3fecca9Ssthen 	marshal_acl_list(b, p->request_xfr);
1656d3fecca9Ssthen 	marshal_acl_list(b, p->notify);
1657d3fecca9Ssthen 	marshal_acl_list(b, p->provide_xfr);
16588d298c9fSsthen 	marshal_acl_list(b, p->allow_query);
1659d3fecca9Ssthen 	marshal_acl_list(b, p->outgoing_interface);
16606e9bf1eeSflorian 	marshal_u32(b, p->max_refresh_time);
16616e9bf1eeSflorian 	marshal_u8(b, p->max_refresh_time_is_default);
16626e9bf1eeSflorian 	marshal_u32(b, p->min_refresh_time);
16636e9bf1eeSflorian 	marshal_u8(b, p->min_refresh_time_is_default);
16646e9bf1eeSflorian 	marshal_u32(b, p->max_retry_time);
16656e9bf1eeSflorian 	marshal_u8(b, p->max_retry_time_is_default);
16666e9bf1eeSflorian 	marshal_u32(b, p->min_retry_time);
16676e9bf1eeSflorian 	marshal_u8(b, p->min_retry_time_is_default);
1668ac5517e4Sflorian 	marshal_u32(b, p->min_expire_time);
1669ac5517e4Sflorian 	marshal_u8(b, p->min_expire_time_expr);
1670*bf87c3c0Sflorian 	marshal_u8(b, p->multi_primary_check);
16714564029fSflorian 	marshal_u8(b, p->store_ixfr);
16724564029fSflorian 	marshal_u8(b, p->store_ixfr_is_default);
16734564029fSflorian 	marshal_u64(b, p->ixfr_size);
16744564029fSflorian 	marshal_u8(b, p->ixfr_size_is_default);
16754564029fSflorian 	marshal_u32(b, p->ixfr_number);
16764564029fSflorian 	marshal_u8(b, p->ixfr_number_is_default);
16774564029fSflorian 	marshal_u8(b, p->create_ixfr);
16784564029fSflorian 	marshal_u8(b, p->create_ixfr_is_default);
16793f21e8ccSflorian 	marshal_u8(b, p->verify_zone);
16803f21e8ccSflorian 	marshal_u8(b, p->verify_zone_is_default);
16813f21e8ccSflorian 	marshal_strv(b, p->verifier);
16823f21e8ccSflorian 	marshal_u8(b, p->verifier_feed_zone);
16833f21e8ccSflorian 	marshal_u8(b, p->verifier_feed_zone_is_default);
16843f21e8ccSflorian 	marshal_u32(b, p->verifier_timeout);
16853f21e8ccSflorian 	marshal_u8(b, p->verifier_timeout_is_default);
1686*bf87c3c0Sflorian 	marshal_u8(b, p->catalog_role);
1687*bf87c3c0Sflorian 	marshal_u8(b, p->catalog_role_is_default);
1688*bf87c3c0Sflorian 	marshal_str(b, p->catalog_member_pattern);
1689*bf87c3c0Sflorian 	marshal_str(b, p->catalog_producer_zone);
1690d3fecca9Ssthen }
1691d3fecca9Ssthen 
1692fe5fe5f6Sflorian struct pattern_options*
pattern_options_unmarshal(region_type * r,struct buffer * b)1693d3fecca9Ssthen pattern_options_unmarshal(region_type* r, struct buffer* b)
1694d3fecca9Ssthen {
1695fe5fe5f6Sflorian 	struct pattern_options* p = pattern_options_create(r);
1696d3fecca9Ssthen 	p->pname = unmarshal_str(r, b);
1697d3fecca9Ssthen 	p->zonefile = unmarshal_str(r, b);
16989e506f0aSbrad 	p->zonestats = unmarshal_str(r, b);
1699d3fecca9Ssthen #ifdef RATELIMIT
1700d3fecca9Ssthen 	p->rrl_whitelist = unmarshal_u16(b);
1701d3fecca9Ssthen #endif
1702d3fecca9Ssthen 	p->allow_axfr_fallback = unmarshal_u8(b);
1703d3fecca9Ssthen 	p->allow_axfr_fallback_is_default = unmarshal_u8(b);
1704d3fecca9Ssthen 	p->notify_retry = unmarshal_u8(b);
1705d3fecca9Ssthen 	p->notify_retry_is_default = unmarshal_u8(b);
1706d3fecca9Ssthen 	p->implicit = unmarshal_u8(b);
17076e9bf1eeSflorian 	p->size_limit_xfr = unmarshal_u64(b);
1708d3fecca9Ssthen 	p->allow_notify = unmarshal_acl_list(r, b);
1709d3fecca9Ssthen 	p->request_xfr = unmarshal_acl_list(r, b);
1710d3fecca9Ssthen 	p->notify = unmarshal_acl_list(r, b);
1711d3fecca9Ssthen 	p->provide_xfr = unmarshal_acl_list(r, b);
17128d298c9fSsthen 	p->allow_query = unmarshal_acl_list(r, b);
1713d3fecca9Ssthen 	p->outgoing_interface = unmarshal_acl_list(r, b);
17146e9bf1eeSflorian 	p->max_refresh_time = unmarshal_u32(b);
17156e9bf1eeSflorian 	p->max_refresh_time_is_default = unmarshal_u8(b);
17166e9bf1eeSflorian 	p->min_refresh_time = unmarshal_u32(b);
17176e9bf1eeSflorian 	p->min_refresh_time_is_default = unmarshal_u8(b);
17186e9bf1eeSflorian 	p->max_retry_time = unmarshal_u32(b);
17196e9bf1eeSflorian 	p->max_retry_time_is_default = unmarshal_u8(b);
17206e9bf1eeSflorian 	p->min_retry_time = unmarshal_u32(b);
17216e9bf1eeSflorian 	p->min_retry_time_is_default = unmarshal_u8(b);
1722ac5517e4Sflorian 	p->min_expire_time = unmarshal_u32(b);
1723ac5517e4Sflorian 	p->min_expire_time_expr = unmarshal_u8(b);
1724*bf87c3c0Sflorian 	p->multi_primary_check = unmarshal_u8(b);
17254564029fSflorian 	p->store_ixfr = unmarshal_u8(b);
17264564029fSflorian 	p->store_ixfr_is_default = unmarshal_u8(b);
17274564029fSflorian 	p->ixfr_size = unmarshal_u64(b);
17284564029fSflorian 	p->ixfr_size_is_default = unmarshal_u8(b);
17294564029fSflorian 	p->ixfr_number = unmarshal_u32(b);
17304564029fSflorian 	p->ixfr_number_is_default = unmarshal_u8(b);
17314564029fSflorian 	p->create_ixfr = unmarshal_u8(b);
17324564029fSflorian 	p->create_ixfr_is_default = unmarshal_u8(b);
17333f21e8ccSflorian 	p->verify_zone = unmarshal_u8(b);
17343f21e8ccSflorian 	p->verify_zone_is_default = unmarshal_u8(b);
17353f21e8ccSflorian 	p->verifier = unmarshal_strv(r, b);
17363f21e8ccSflorian 	p->verifier_feed_zone = unmarshal_u8(b);
17373f21e8ccSflorian 	p->verifier_feed_zone_is_default = unmarshal_u8(b);
17383f21e8ccSflorian 	p->verifier_timeout = unmarshal_u32(b);
17393f21e8ccSflorian 	p->verifier_timeout_is_default = unmarshal_u8(b);
1740*bf87c3c0Sflorian 	p->catalog_role = unmarshal_u8(b);
1741*bf87c3c0Sflorian 	p->catalog_role_is_default = unmarshal_u8(b);
1742*bf87c3c0Sflorian 	p->catalog_member_pattern = unmarshal_str(r, b);
1743*bf87c3c0Sflorian 	p->catalog_producer_zone = unmarshal_str(r, b);
1744d3fecca9Ssthen 	return p;
1745d3fecca9Ssthen }
1746d3fecca9Ssthen 
1747fe5fe5f6Sflorian struct key_options*
key_options_create(region_type * region)1748d3fecca9Ssthen key_options_create(region_type* region)
1749d3fecca9Ssthen {
1750fe5fe5f6Sflorian 	struct key_options* key;
1751fe5fe5f6Sflorian 	key = (struct key_options*)region_alloc_zero(region,
1752fe5fe5f6Sflorian 		sizeof(struct key_options));
1753d3fecca9Ssthen 	return key;
1754d3fecca9Ssthen }
1755d3fecca9Ssthen 
1756063644e9Sflorian struct tls_auth_options*
tls_auth_options_create(region_type * region)1757063644e9Sflorian tls_auth_options_create(region_type* region)
1758063644e9Sflorian {
1759063644e9Sflorian 	struct tls_auth_options* tls_auth_options;
1760063644e9Sflorian 	tls_auth_options = (struct tls_auth_options*)region_alloc_zero(region, sizeof(struct tls_auth_options));
1761063644e9Sflorian 	return tls_auth_options;
1762063644e9Sflorian }
1763063644e9Sflorian 
1764d3fecca9Ssthen void
key_options_insert(struct nsd_options * opt,struct key_options * key)1765fe5fe5f6Sflorian key_options_insert(struct nsd_options* opt, struct key_options* key)
1766d3fecca9Ssthen {
1767d3fecca9Ssthen 	if(!key->name) return;
1768d3fecca9Ssthen 	key->node.key = key->name;
1769d3fecca9Ssthen 	(void)rbtree_insert(opt->keys, &key->node);
1770d3fecca9Ssthen }
1771d3fecca9Ssthen 
1772fe5fe5f6Sflorian struct key_options*
key_options_find(struct nsd_options * opt,const char * name)1773fe5fe5f6Sflorian key_options_find(struct nsd_options* opt, const char* name)
1774d3fecca9Ssthen {
1775fe5fe5f6Sflorian 	return (struct key_options*)rbtree_search(opt->keys, name);
1776d3fecca9Ssthen }
1777d3fecca9Ssthen 
1778063644e9Sflorian void
tls_auth_options_insert(struct nsd_options * opt,struct tls_auth_options * auth)1779063644e9Sflorian tls_auth_options_insert(struct nsd_options* opt, struct tls_auth_options* auth)
1780063644e9Sflorian {
1781063644e9Sflorian 	if(!auth->name) return;
1782063644e9Sflorian 	auth->node.key = auth->name;
1783063644e9Sflorian 	(void)rbtree_insert(opt->tls_auths, &auth->node);
1784063644e9Sflorian }
1785063644e9Sflorian 
1786063644e9Sflorian struct tls_auth_options*
tls_auth_options_find(struct nsd_options * opt,const char * name)1787063644e9Sflorian tls_auth_options_find(struct nsd_options* opt, const char* name)
1788063644e9Sflorian {
1789063644e9Sflorian 	return (struct tls_auth_options*)rbtree_search(opt->tls_auths, name);
1790063644e9Sflorian }
1791063644e9Sflorian 
1792d3fecca9Ssthen /** remove tsig_key contents */
1793d3fecca9Ssthen void
key_options_desetup(region_type * region,struct key_options * key)1794fe5fe5f6Sflorian key_options_desetup(region_type* region, struct key_options* key)
1795d3fecca9Ssthen {
1796d3fecca9Ssthen 	/* keep tsig_key pointer so that existing references keep valid */
1797d3fecca9Ssthen 	if(!key->tsig_key)
1798d3fecca9Ssthen 		return;
1799d3fecca9Ssthen 	/* name stays the same */
1800d3fecca9Ssthen 	if(key->tsig_key->data) {
1801d3fecca9Ssthen 		/* wipe secret! */
1802d3fecca9Ssthen 		memset(key->tsig_key->data, 0xdd, key->tsig_key->size);
1803d3fecca9Ssthen 		region_recycle(region, key->tsig_key->data,
1804d3fecca9Ssthen 			key->tsig_key->size);
1805d3fecca9Ssthen 		key->tsig_key->data = NULL;
1806d3fecca9Ssthen 		key->tsig_key->size = 0;
1807d3fecca9Ssthen 	}
1808d3fecca9Ssthen }
1809d3fecca9Ssthen 
1810d3fecca9Ssthen /** add tsig_key contents */
1811d3fecca9Ssthen void
key_options_setup(region_type * region,struct key_options * key)1812fe5fe5f6Sflorian key_options_setup(region_type* region, struct key_options* key)
1813d3fecca9Ssthen {
1814d3fecca9Ssthen 	uint8_t data[16384]; /* 16KB */
1815d3fecca9Ssthen 	int size;
1816d3fecca9Ssthen 	if(!key->tsig_key) {
1817d3fecca9Ssthen 		/* create it */
1818d3fecca9Ssthen 		key->tsig_key = (tsig_key_type *) region_alloc(region,
1819d3fecca9Ssthen 			sizeof(tsig_key_type));
1820d3fecca9Ssthen 		/* create name */
1821d3fecca9Ssthen 		key->tsig_key->name = dname_parse(region, key->name);
1822d3fecca9Ssthen 		if(!key->tsig_key->name) {
1823d3fecca9Ssthen 			log_msg(LOG_ERR, "Failed to parse tsig key name %s",
1824d3fecca9Ssthen 				key->name);
1825d3fecca9Ssthen 			/* key and base64 were checked during syntax parse */
1826d3fecca9Ssthen 			exit(1);
1827d3fecca9Ssthen 		}
1828d3fecca9Ssthen 		key->tsig_key->size = 0;
1829d3fecca9Ssthen 		key->tsig_key->data = NULL;
1830d3fecca9Ssthen 	}
183172628ec9Ssthen 	size = __b64_pton(key->secret, data, sizeof(data));
1832d3fecca9Ssthen 	if(size == -1) {
1833d3fecca9Ssthen 		log_msg(LOG_ERR, "Failed to parse tsig key data %s",
1834d3fecca9Ssthen 			key->name);
1835d3fecca9Ssthen 		/* key and base64 were checked during syntax parse */
1836d3fecca9Ssthen 		exit(1);
1837d3fecca9Ssthen 	}
1838d3fecca9Ssthen 	key->tsig_key->size = size;
1839d3fecca9Ssthen 	key->tsig_key->data = (uint8_t *)region_alloc_init(region, data, size);
1840d3fecca9Ssthen }
1841d3fecca9Ssthen 
1842d3fecca9Ssthen void
key_options_remove(struct nsd_options * opt,const char * name)1843fe5fe5f6Sflorian key_options_remove(struct nsd_options* opt, const char* name)
1844d3fecca9Ssthen {
1845fe5fe5f6Sflorian 	struct key_options* k = key_options_find(opt, name);
1846d3fecca9Ssthen 	if(!k) return;
1847d3fecca9Ssthen 	(void)rbtree_delete(opt->keys, name);
1848d3fecca9Ssthen 	if(k->name)
1849d3fecca9Ssthen 		region_recycle(opt->region, k->name, strlen(k->name)+1);
1850d3fecca9Ssthen 	if(k->algorithm)
1851d3fecca9Ssthen 		region_recycle(opt->region, k->algorithm, strlen(k->algorithm)+1);
1852d3fecca9Ssthen 	if(k->secret) {
1853d3fecca9Ssthen 		memset(k->secret, 0xdd, strlen(k->secret)); /* wipe secret! */
1854d3fecca9Ssthen 		region_recycle(opt->region, k->secret, strlen(k->secret)+1);
1855d3fecca9Ssthen 	}
1856d3fecca9Ssthen 	if(k->tsig_key) {
1857d3fecca9Ssthen 		tsig_del_key(k->tsig_key);
1858d3fecca9Ssthen 		if(k->tsig_key->name)
1859d3fecca9Ssthen 			region_recycle(opt->region, (void*)k->tsig_key->name,
1860d3fecca9Ssthen 				dname_total_size(k->tsig_key->name));
1861d3fecca9Ssthen 		key_options_desetup(opt->region, k);
1862d3fecca9Ssthen 		region_recycle(opt->region, k->tsig_key, sizeof(tsig_key_type));
1863d3fecca9Ssthen 	}
1864fe5fe5f6Sflorian 	region_recycle(opt->region, k, sizeof(struct key_options));
1865d3fecca9Ssthen }
1866d3fecca9Ssthen 
1867d3fecca9Ssthen int
key_options_equal(struct key_options * p,struct key_options * q)1868fe5fe5f6Sflorian key_options_equal(struct key_options* p, struct key_options* q)
1869d3fecca9Ssthen {
1870d3fecca9Ssthen 	return strcmp(p->name, q->name)==0 && strcmp(p->algorithm,
1871d3fecca9Ssthen 		q->algorithm)==0 && strcmp(p->secret, q->secret)==0;
1872d3fecca9Ssthen }
1873d3fecca9Ssthen 
1874d3fecca9Ssthen void
key_options_add_modify(struct nsd_options * opt,struct key_options * key)1875fe5fe5f6Sflorian key_options_add_modify(struct nsd_options* opt, struct key_options* key)
1876d3fecca9Ssthen {
1877fe5fe5f6Sflorian 	struct key_options* orig = key_options_find(opt, key->name);
1878d3fecca9Ssthen 	if(!orig) {
1879d3fecca9Ssthen 		/* needs to be copied to opt region */
1880d3fecca9Ssthen 		orig = key_options_create(opt->region);
1881d3fecca9Ssthen 		orig->name = region_strdup(opt->region, key->name);
1882d3fecca9Ssthen 		orig->algorithm = region_strdup(opt->region, key->algorithm);
1883d3fecca9Ssthen 		orig->secret = region_strdup(opt->region, key->secret);
1884d3fecca9Ssthen 		key_options_setup(opt->region, orig);
1885d3fecca9Ssthen 		tsig_add_key(orig->tsig_key);
1886d3fecca9Ssthen 		key_options_insert(opt, orig);
1887d3fecca9Ssthen 	} else {
1888d3fecca9Ssthen 		/* modify entries in existing key, and copy to opt region */
1889d3fecca9Ssthen 		key_options_desetup(opt->region, orig);
1890d3fecca9Ssthen 		region_recycle(opt->region, orig->algorithm,
1891d3fecca9Ssthen 			strlen(orig->algorithm)+1);
1892d3fecca9Ssthen 		orig->algorithm = region_strdup(opt->region, key->algorithm);
1893d3fecca9Ssthen 		region_recycle(opt->region, orig->secret,
1894d3fecca9Ssthen 			strlen(orig->secret)+1);
1895d3fecca9Ssthen 		orig->secret = region_strdup(opt->region, key->secret);
1896d3fecca9Ssthen 		key_options_setup(opt->region, orig);
1897d3fecca9Ssthen 	}
1898d3fecca9Ssthen }
1899d3fecca9Ssthen 
1900d3fecca9Ssthen int
acl_check_incoming_block_proxy(struct acl_options * acl,struct query * q,struct acl_options ** reason)1901b71395eaSflorian acl_check_incoming_block_proxy(struct acl_options* acl, struct query* q,
1902b71395eaSflorian 	struct acl_options** reason)
1903b71395eaSflorian {
1904b71395eaSflorian 	/* check each acl element.
1905b71395eaSflorian 	 * if it is blocked, return -1.
1906b71395eaSflorian 	 * return false if no matches for blocked elements. */
1907b71395eaSflorian 	if(reason)
1908b71395eaSflorian 		*reason = NULL;
1909b71395eaSflorian 
1910b71395eaSflorian 	while(acl)
1911b71395eaSflorian 	{
1912b71395eaSflorian 		DEBUG(DEBUG_XFRD,2, (LOG_INFO, "proxy testing acl %s %s",
1913b71395eaSflorian 			acl->ip_address_spec, acl->nokey?"NOKEY":
1914b71395eaSflorian 			(acl->blocked?"BLOCKED":acl->key_name)));
1915b71395eaSflorian 		if(acl_addr_matches_proxy(acl, q) && acl->blocked) {
1916b71395eaSflorian 			if(reason)
1917b71395eaSflorian 				*reason = acl;
1918b71395eaSflorian 			return -1;
1919b71395eaSflorian 		}
1920b71395eaSflorian 		acl = acl->next;
1921b71395eaSflorian 	}
1922b71395eaSflorian 
1923b71395eaSflorian 	return 0;
1924b71395eaSflorian }
1925b71395eaSflorian 
1926b71395eaSflorian int
acl_check_incoming(struct acl_options * acl,struct query * q,struct acl_options ** reason)1927fe5fe5f6Sflorian acl_check_incoming(struct acl_options* acl, struct query* q,
1928fe5fe5f6Sflorian 	struct acl_options** reason)
192962ac0c33Sjakob {
193062ac0c33Sjakob 	/* check each acl element.
193162ac0c33Sjakob 	   if 1 blocked element matches - return -1.
193262ac0c33Sjakob 	   if any element matches - return number.
193362ac0c33Sjakob 	   else return -1. */
193462ac0c33Sjakob 	int found_match = -1;
193562ac0c33Sjakob 	int number = 0;
1936fe5fe5f6Sflorian 	struct acl_options* match = 0;
193762ac0c33Sjakob 
193862ac0c33Sjakob 	if(reason)
193962ac0c33Sjakob 		*reason = NULL;
194062ac0c33Sjakob 
194162ac0c33Sjakob 	while(acl)
194262ac0c33Sjakob 	{
194362ac0c33Sjakob 		DEBUG(DEBUG_XFRD,2, (LOG_INFO, "testing acl %s %s",
194462ac0c33Sjakob 			acl->ip_address_spec, acl->nokey?"NOKEY":
194562ac0c33Sjakob 			(acl->blocked?"BLOCKED":acl->key_name)));
194662ac0c33Sjakob 		if(acl_addr_matches(acl, q) && acl_key_matches(acl, q)) {
194762ac0c33Sjakob 			if(!match)
194862ac0c33Sjakob 			{
194962ac0c33Sjakob 				match = acl; /* remember first match */
195062ac0c33Sjakob 				found_match=number;
195162ac0c33Sjakob 			}
195262ac0c33Sjakob 			if(acl->blocked) {
195362ac0c33Sjakob 				if(reason)
195462ac0c33Sjakob 					*reason = acl;
195562ac0c33Sjakob 				return -1;
195662ac0c33Sjakob 			}
195762ac0c33Sjakob 		}
195862ac0c33Sjakob 		number++;
195962ac0c33Sjakob 		acl = acl->next;
196062ac0c33Sjakob 	}
196162ac0c33Sjakob 
196262ac0c33Sjakob 	if(reason)
196362ac0c33Sjakob 		*reason = match;
196462ac0c33Sjakob 	return found_match;
196562ac0c33Sjakob }
196662ac0c33Sjakob 
196762ac0c33Sjakob #ifdef INET6
1968d3fecca9Ssthen int
acl_addr_matches_ipv6host(struct acl_options * acl,struct sockaddr_storage * addr_storage,unsigned int port)1969fe5fe5f6Sflorian acl_addr_matches_ipv6host(struct acl_options* acl, struct sockaddr_storage* addr_storage, unsigned int port)
19707b21d3ddSsthen {
19717b21d3ddSsthen 	struct sockaddr_in6* addr = (struct sockaddr_in6*)addr_storage;
19727b21d3ddSsthen 	if(acl->port != 0 && acl->port != port)
197362ac0c33Sjakob 		return 0;
197462ac0c33Sjakob 	switch(acl->rangetype) {
197562ac0c33Sjakob 	case acl_range_mask:
197662ac0c33Sjakob 	case acl_range_subnet:
197762ac0c33Sjakob 		if(!acl_addr_match_mask((uint32_t*)&acl->addr.addr6, (uint32_t*)&addr->sin6_addr,
197862ac0c33Sjakob 			(uint32_t*)&acl->range_mask.addr6, sizeof(struct in6_addr)))
197962ac0c33Sjakob 			return 0;
198062ac0c33Sjakob 		break;
198162ac0c33Sjakob 	case acl_range_minmax:
1982308d2509Sflorian 		if(!acl_addr_match_range_v6((uint32_t*)&acl->addr.addr6, (uint32_t*)&addr->sin6_addr,
198362ac0c33Sjakob 			(uint32_t*)&acl->range_mask.addr6, sizeof(struct in6_addr)))
198462ac0c33Sjakob 			return 0;
198562ac0c33Sjakob 		break;
198662ac0c33Sjakob 	case acl_range_single:
198762ac0c33Sjakob 	default:
198862ac0c33Sjakob 		if(memcmp(&addr->sin6_addr, &acl->addr.addr6,
198962ac0c33Sjakob 			sizeof(struct in6_addr)) != 0)
199062ac0c33Sjakob 			return 0;
199162ac0c33Sjakob 		break;
199262ac0c33Sjakob 	}
199362ac0c33Sjakob 	return 1;
199462ac0c33Sjakob }
19957b21d3ddSsthen #endif
19967b21d3ddSsthen 
1997d3fecca9Ssthen int
acl_addr_matches_ipv4host(struct acl_options * acl,struct sockaddr_in * addr,unsigned int port)1998fe5fe5f6Sflorian acl_addr_matches_ipv4host(struct acl_options* acl, struct sockaddr_in* addr, unsigned int port)
199962ac0c33Sjakob {
20007b21d3ddSsthen 	if(acl->port != 0 && acl->port != port)
200162ac0c33Sjakob 		return 0;
200262ac0c33Sjakob 	switch(acl->rangetype) {
200362ac0c33Sjakob 	case acl_range_mask:
200462ac0c33Sjakob 	case acl_range_subnet:
200562ac0c33Sjakob 		if(!acl_addr_match_mask((uint32_t*)&acl->addr.addr, (uint32_t*)&addr->sin_addr,
200662ac0c33Sjakob 			(uint32_t*)&acl->range_mask.addr, sizeof(struct in_addr)))
200762ac0c33Sjakob 			return 0;
200862ac0c33Sjakob 		break;
200962ac0c33Sjakob 	case acl_range_minmax:
2010308d2509Sflorian 		if(!acl_addr_match_range_v4((uint32_t*)&acl->addr.addr, (uint32_t*)&addr->sin_addr,
201162ac0c33Sjakob 			(uint32_t*)&acl->range_mask.addr, sizeof(struct in_addr)))
201262ac0c33Sjakob 			return 0;
201362ac0c33Sjakob 		break;
201462ac0c33Sjakob 	case acl_range_single:
201562ac0c33Sjakob 	default:
201662ac0c33Sjakob 		if(memcmp(&addr->sin_addr, &acl->addr.addr,
201762ac0c33Sjakob 			sizeof(struct in_addr)) != 0)
201862ac0c33Sjakob 			return 0;
201962ac0c33Sjakob 		break;
202062ac0c33Sjakob 	}
202162ac0c33Sjakob 	return 1;
202262ac0c33Sjakob }
20237b21d3ddSsthen 
2024d3fecca9Ssthen int
acl_addr_matches_host(struct acl_options * acl,struct acl_options * host)2025fe5fe5f6Sflorian acl_addr_matches_host(struct acl_options* acl, struct acl_options* host)
20267b21d3ddSsthen {
20277b21d3ddSsthen 	if(acl->is_ipv6)
20287b21d3ddSsthen 	{
20297b21d3ddSsthen #ifdef INET6
20307b21d3ddSsthen 		struct sockaddr_storage* addr = (struct sockaddr_storage*)&host->addr;
20317b21d3ddSsthen 		if(!host->is_ipv6) return 0;
20327b21d3ddSsthen 		return acl_addr_matches_ipv6host(acl, addr, host->port);
20337b21d3ddSsthen #else
20347b21d3ddSsthen 		return 0; /* no inet6, no match */
20357b21d3ddSsthen #endif
20367b21d3ddSsthen 	}
20377b21d3ddSsthen 	else
20387b21d3ddSsthen 	{
20397b21d3ddSsthen 		struct sockaddr_in* addr = (struct sockaddr_in*)&host->addr;
20407b21d3ddSsthen 		if(host->is_ipv6) return 0;
20417b21d3ddSsthen 		return acl_addr_matches_ipv4host(acl, addr, host->port);
20427b21d3ddSsthen 	}
20437b21d3ddSsthen 	/* ENOTREACH */
20447b21d3ddSsthen 	return 0;
20457b21d3ddSsthen }
20467b21d3ddSsthen 
2047d3fecca9Ssthen int
acl_addr_matches(struct acl_options * acl,struct query * q)2048fe5fe5f6Sflorian acl_addr_matches(struct acl_options* acl, struct query* q)
20497b21d3ddSsthen {
20507b21d3ddSsthen 	if(acl->is_ipv6)
20517b21d3ddSsthen 	{
20527b21d3ddSsthen #ifdef INET6
2053b71395eaSflorian 		struct sockaddr_storage* addr = (struct sockaddr_storage*)&q->client_addr;
20547b21d3ddSsthen 		if(addr->ss_family != AF_INET6)
20557b21d3ddSsthen 			return 0;
20567b21d3ddSsthen 		return acl_addr_matches_ipv6host(acl, addr, ntohs(((struct sockaddr_in6*)addr)->sin6_port));
20577b21d3ddSsthen #else
20587b21d3ddSsthen 		return 0; /* no inet6, no match */
20597b21d3ddSsthen #endif
20607b21d3ddSsthen 	}
20617b21d3ddSsthen 	else
20627b21d3ddSsthen 	{
2063b71395eaSflorian 		struct sockaddr_in* addr = (struct sockaddr_in*)&q->client_addr;
2064b71395eaSflorian 		if(addr->sin_family != AF_INET)
2065b71395eaSflorian 			return 0;
2066b71395eaSflorian 		return acl_addr_matches_ipv4host(acl, addr, ntohs(addr->sin_port));
2067b71395eaSflorian 	}
2068b71395eaSflorian 	/* ENOTREACH */
2069b71395eaSflorian 	return 0;
2070b71395eaSflorian }
2071b71395eaSflorian 
2072b71395eaSflorian int
acl_addr_matches_proxy(struct acl_options * acl,struct query * q)2073b71395eaSflorian acl_addr_matches_proxy(struct acl_options* acl, struct query* q)
2074b71395eaSflorian {
2075b71395eaSflorian 	if(acl->is_ipv6)
2076b71395eaSflorian 	{
2077b71395eaSflorian #ifdef INET6
2078b71395eaSflorian 		struct sockaddr_storage* addr = (struct sockaddr_storage*)&q->remote_addr;
2079b71395eaSflorian 		if(addr->ss_family != AF_INET6)
2080b71395eaSflorian 			return 0;
2081b71395eaSflorian 		return acl_addr_matches_ipv6host(acl, addr, ntohs(((struct sockaddr_in6*)addr)->sin6_port));
2082b71395eaSflorian #else
2083b71395eaSflorian 		return 0; /* no inet6, no match */
2084b71395eaSflorian #endif
2085b71395eaSflorian 	}
2086b71395eaSflorian 	else
2087b71395eaSflorian 	{
2088b71395eaSflorian 		struct sockaddr_in* addr = (struct sockaddr_in*)&q->remote_addr;
20897b21d3ddSsthen 		if(addr->sin_family != AF_INET)
20907b21d3ddSsthen 			return 0;
20917b21d3ddSsthen 		return acl_addr_matches_ipv4host(acl, addr, ntohs(addr->sin_port));
20927b21d3ddSsthen 	}
209362ac0c33Sjakob 	/* ENOTREACH */
209462ac0c33Sjakob 	return 0;
209562ac0c33Sjakob }
209662ac0c33Sjakob 
2097d3fecca9Ssthen int
acl_addr_match_mask(uint32_t * a,uint32_t * b,uint32_t * mask,size_t sz)2098d3fecca9Ssthen acl_addr_match_mask(uint32_t* a, uint32_t* b, uint32_t* mask, size_t sz)
209962ac0c33Sjakob {
210062ac0c33Sjakob 	size_t i;
210162ac0c33Sjakob #ifndef NDEBUG
210262ac0c33Sjakob 	assert(sz % 4 == 0);
210362ac0c33Sjakob #endif
210462ac0c33Sjakob 	sz /= 4;
210562ac0c33Sjakob 	for(i=0; i<sz; ++i)
210662ac0c33Sjakob 	{
210762ac0c33Sjakob 		if(((*a++)&*mask) != ((*b++)&*mask))
210862ac0c33Sjakob 			return 0;
210962ac0c33Sjakob 		++mask;
211062ac0c33Sjakob 	}
211162ac0c33Sjakob 	return 1;
211262ac0c33Sjakob }
211362ac0c33Sjakob 
2114d3fecca9Ssthen int
acl_addr_match_range_v4(uint32_t * minval,uint32_t * x,uint32_t * maxval,size_t sz)2115308d2509Sflorian acl_addr_match_range_v4(uint32_t* minval, uint32_t* x, uint32_t* maxval, size_t sz)
2116308d2509Sflorian {
2117308d2509Sflorian 	assert(sz == 4); (void)sz;
2118308d2509Sflorian 	/* check treats x as one huge number */
2119308d2509Sflorian 
2120308d2509Sflorian 	/* if outside bounds, we are done */
2121308d2509Sflorian 	if(*minval > *x)
2122308d2509Sflorian 		return 0;
2123308d2509Sflorian 	if(*maxval < *x)
2124308d2509Sflorian 		return 0;
2125308d2509Sflorian 
2126308d2509Sflorian 	return 1;
2127308d2509Sflorian }
2128308d2509Sflorian 
2129308d2509Sflorian #ifdef INET6
2130308d2509Sflorian int
acl_addr_match_range_v6(uint32_t * minval,uint32_t * x,uint32_t * maxval,size_t sz)2131308d2509Sflorian acl_addr_match_range_v6(uint32_t* minval, uint32_t* x, uint32_t* maxval, size_t sz)
213262ac0c33Sjakob {
213362ac0c33Sjakob 	size_t i;
213462ac0c33Sjakob 	uint8_t checkmin = 1, checkmax = 1;
213562ac0c33Sjakob #ifndef NDEBUG
213662ac0c33Sjakob 	assert(sz % 4 == 0);
213762ac0c33Sjakob #endif
213862ac0c33Sjakob 	/* check treats x as one huge number */
213962ac0c33Sjakob 	sz /= 4;
214062ac0c33Sjakob 	for(i=0; i<sz; ++i)
214162ac0c33Sjakob 	{
214262ac0c33Sjakob 		/* if outside bounds, we are done */
214362ac0c33Sjakob 		if(checkmin)
214462ac0c33Sjakob 			if(minval[i] > x[i])
214562ac0c33Sjakob 				return 0;
214662ac0c33Sjakob 		if(checkmax)
214762ac0c33Sjakob 			if(maxval[i] < x[i])
214862ac0c33Sjakob 				return 0;
214962ac0c33Sjakob 		/* if x is equal to a bound, that bound needs further checks */
215062ac0c33Sjakob 		if(checkmin && minval[i]!=x[i])
215162ac0c33Sjakob 			checkmin = 0;
215262ac0c33Sjakob 		if(checkmax && maxval[i]!=x[i])
215362ac0c33Sjakob 			checkmax = 0;
215462ac0c33Sjakob 		if(!checkmin && !checkmax)
215562ac0c33Sjakob 			return 1; /* will always match */
215662ac0c33Sjakob 	}
215762ac0c33Sjakob 	return 1;
215862ac0c33Sjakob }
2159308d2509Sflorian #endif /* INET6 */
216062ac0c33Sjakob 
2161d3fecca9Ssthen int
acl_key_matches(struct acl_options * acl,struct query * q)2162fe5fe5f6Sflorian acl_key_matches(struct acl_options* acl, struct query* q)
216362ac0c33Sjakob {
216462ac0c33Sjakob 	if(acl->blocked)
216562ac0c33Sjakob 		return 1;
216662ac0c33Sjakob 	if(acl->nokey) {
216762ac0c33Sjakob 		if(q->tsig.status == TSIG_NOT_PRESENT)
216862ac0c33Sjakob 			return 1;
216962ac0c33Sjakob 		return 0;
217062ac0c33Sjakob 	}
217162ac0c33Sjakob 	/* check name of tsig key */
217262ac0c33Sjakob 	if(q->tsig.status != TSIG_OK) {
217362ac0c33Sjakob 		DEBUG(DEBUG_XFRD,2, (LOG_INFO, "keymatch fail query has no TSIG"));
217462ac0c33Sjakob 		return 0; /* query has no TSIG */
217562ac0c33Sjakob 	}
217662ac0c33Sjakob 	if(q->tsig.error_code != TSIG_ERROR_NOERROR) {
217762ac0c33Sjakob 		DEBUG(DEBUG_XFRD,2, (LOG_INFO, "keymatch fail, tsig has error"));
217862ac0c33Sjakob 		return 0; /* some tsig error */
217962ac0c33Sjakob 	}
218062ac0c33Sjakob 	if(!acl->key_options->tsig_key) {
218162ac0c33Sjakob 		DEBUG(DEBUG_XFRD,2, (LOG_INFO, "keymatch fail no config"));
21823126abd5Ssthen 		return 0; /* key not properly configured */
218362ac0c33Sjakob 	}
218462ac0c33Sjakob 	if(dname_compare(q->tsig.key_name,
218562ac0c33Sjakob 		acl->key_options->tsig_key->name) != 0) {
218662ac0c33Sjakob 		DEBUG(DEBUG_XFRD,2, (LOG_INFO, "keymatch fail wrong key name"));
218762ac0c33Sjakob 		return 0; /* wrong key name */
218862ac0c33Sjakob 	}
218962ac0c33Sjakob 	if(tsig_strlowercmp(q->tsig.algorithm->short_name,
2190c1e73312Sflorian 		acl->key_options->algorithm) != 0 && (
2191c1e73312Sflorian 		strncmp("hmac-", q->tsig.algorithm->short_name, 5) != 0 ||
2192c1e73312Sflorian 		tsig_strlowercmp(q->tsig.algorithm->short_name+5,
2193c1e73312Sflorian 		acl->key_options->algorithm) != 0) ) {
219462ac0c33Sjakob 		DEBUG(DEBUG_XFRD,2, (LOG_ERR, "query tsig wrong algorithm"));
219562ac0c33Sjakob 		return 0; /* no such algo */
219662ac0c33Sjakob 	}
219762ac0c33Sjakob 	return 1;
219862ac0c33Sjakob }
219962ac0c33Sjakob 
220062ac0c33Sjakob int
acl_same_host(struct acl_options * a,struct acl_options * b)2201fe5fe5f6Sflorian acl_same_host(struct acl_options* a, struct acl_options* b)
220262ac0c33Sjakob {
220362ac0c33Sjakob 	if(a->is_ipv6 && !b->is_ipv6)
220462ac0c33Sjakob 		return 0;
220562ac0c33Sjakob 	if(!a->is_ipv6 && b->is_ipv6)
220662ac0c33Sjakob 		return 0;
220762ac0c33Sjakob 	if(a->port != b->port)
220862ac0c33Sjakob 		return 0;
220962ac0c33Sjakob 	if(a->rangetype != b->rangetype)
221062ac0c33Sjakob 		return 0;
221162ac0c33Sjakob 	if(!a->is_ipv6) {
221262ac0c33Sjakob 		if(memcmp(&a->addr.addr, &b->addr.addr,
221362ac0c33Sjakob 		   sizeof(struct in_addr)) != 0)
221462ac0c33Sjakob 			return 0;
221562ac0c33Sjakob 		if(a->rangetype != acl_range_single &&
221662ac0c33Sjakob 		   memcmp(&a->range_mask.addr, &b->range_mask.addr,
221762ac0c33Sjakob 		   sizeof(struct in_addr)) != 0)
221862ac0c33Sjakob 			return 0;
221962ac0c33Sjakob 	} else {
222062ac0c33Sjakob #ifdef INET6
222162ac0c33Sjakob 		if(memcmp(&a->addr.addr6, &b->addr.addr6,
222262ac0c33Sjakob 		   sizeof(struct in6_addr)) != 0)
222362ac0c33Sjakob 			return 0;
222462ac0c33Sjakob 		if(a->rangetype != acl_range_single &&
222562ac0c33Sjakob 		   memcmp(&a->range_mask.addr6, &b->range_mask.addr6,
222662ac0c33Sjakob 		   sizeof(struct in6_addr)) != 0)
222762ac0c33Sjakob 			return 0;
222862ac0c33Sjakob #else
222962ac0c33Sjakob 		return 0;
223062ac0c33Sjakob #endif
223162ac0c33Sjakob 	}
223262ac0c33Sjakob 	return 1;
223362ac0c33Sjakob }
223462ac0c33Sjakob 
2235d65f3523Sjakob #if defined(HAVE_SSL)
2236d3fecca9Ssthen void
key_options_tsig_add(struct nsd_options * opt)2237fe5fe5f6Sflorian key_options_tsig_add(struct nsd_options* opt)
223862ac0c33Sjakob {
2239fe5fe5f6Sflorian 	struct key_options* optkey;
2240fe5fe5f6Sflorian 	RBTREE_FOR(optkey, struct key_options*, opt->keys) {
2241d3fecca9Ssthen 		key_options_setup(opt->region, optkey);
2242d3fecca9Ssthen 		tsig_add_key(optkey->tsig_key);
224362ac0c33Sjakob 	}
224462ac0c33Sjakob }
2245d65f3523Sjakob #endif
224662ac0c33Sjakob 
2247d3fecca9Ssthen int
zone_is_slave(struct zone_options * opt)2248fe5fe5f6Sflorian zone_is_slave(struct zone_options* opt)
224962ac0c33Sjakob {
2250d3fecca9Ssthen 	return opt && opt->pattern && opt->pattern->request_xfr != 0;
225162ac0c33Sjakob }
225262ac0c33Sjakob 
2253d3fecca9Ssthen /* get a character in string (or replacement char if not long enough) */
2254d3fecca9Ssthen static const char*
get_char(const char * str,size_t i)2255d3fecca9Ssthen get_char(const char* str, size_t i)
2256d3fecca9Ssthen {
2257d3fecca9Ssthen 	static char res[2];
2258d3fecca9Ssthen 	if(i >= strlen(str))
2259d3fecca9Ssthen 		return ".";
2260d3fecca9Ssthen 	res[0] = str[i];
2261d3fecca9Ssthen 	res[1] = 0;
2262d3fecca9Ssthen 	return res;
2263d3fecca9Ssthen }
2264d3fecca9Ssthen /* get end label of the zone name (or .) */
2265d3fecca9Ssthen static const char*
get_end_label(struct zone_options * zone,int i)2266fe5fe5f6Sflorian get_end_label(struct zone_options* zone, int i)
2267d3fecca9Ssthen {
2268d3fecca9Ssthen 	const dname_type* d = (const dname_type*)zone->node.key;
2269d3fecca9Ssthen 	if(i >= d->label_count) {
2270d3fecca9Ssthen 		return ".";
2271d3fecca9Ssthen 	}
2272d3fecca9Ssthen 	return wirelabel2str(dname_label(d, i));
2273d3fecca9Ssthen }
2274d3fecca9Ssthen /* replace occurrences of one with two */
2275d3fecca9Ssthen void
replace_str(char * str,size_t len,const char * one,const char * two)2276d3fecca9Ssthen replace_str(char* str, size_t len, const char* one, const char* two)
2277d3fecca9Ssthen {
2278d3fecca9Ssthen 	char* pos;
2279d3fecca9Ssthen 	char* at = str;
2280d3fecca9Ssthen 	while( (pos=strstr(at, one)) ) {
2281d3fecca9Ssthen 		if(strlen(str)+strlen(two)-strlen(one) >= len)
2282d3fecca9Ssthen 			return; /* no more space to replace */
2283d3fecca9Ssthen 		/* stuff before pos is fine */
2284d3fecca9Ssthen 		/* move the stuff after pos to make space for two, add
2285d3fecca9Ssthen 		 * one to length of remainder to also copy the 0 byte end */
2286d3fecca9Ssthen 		memmove(pos+strlen(two), pos+strlen(one),
2287d3fecca9Ssthen 			strlen(pos+strlen(one))+1);
2288d3fecca9Ssthen 		/* copy in two */
2289d3fecca9Ssthen 		memmove(pos, two, strlen(two));
2290d3fecca9Ssthen 		/* at is end of the newly inserted two (avoids recursion if
2291d3fecca9Ssthen 		 * two contains one) */
2292d3fecca9Ssthen 		at = pos+strlen(two);
2293d3fecca9Ssthen 	}
2294d3fecca9Ssthen }
2295d3fecca9Ssthen 
2296d3fecca9Ssthen const char*
config_cook_string(struct zone_options * zone,const char * input)2297fe5fe5f6Sflorian config_cook_string(struct zone_options* zone, const char* input)
22989e506f0aSbrad {
22999e506f0aSbrad 	static char f[1024];
23009e506f0aSbrad 	/* if not a template, return as-is */
23019e506f0aSbrad 	if(!strchr(input, '%')) {
23029e506f0aSbrad 		return input;
23039e506f0aSbrad 	}
23049e506f0aSbrad 	strlcpy(f, input, sizeof(f));
23059e506f0aSbrad 	if(strstr(f, "%1"))
23069e506f0aSbrad 		replace_str(f, sizeof(f), "%1", get_char(zone->name, 0));
23079e506f0aSbrad 	if(strstr(f, "%2"))
23089e506f0aSbrad 		replace_str(f, sizeof(f), "%2", get_char(zone->name, 1));
23099e506f0aSbrad 	if(strstr(f, "%3"))
23109e506f0aSbrad 		replace_str(f, sizeof(f), "%3", get_char(zone->name, 2));
23119e506f0aSbrad 	if(strstr(f, "%z"))
23129e506f0aSbrad 		replace_str(f, sizeof(f), "%z", get_end_label(zone, 1));
23139e506f0aSbrad 	if(strstr(f, "%y"))
23149e506f0aSbrad 		replace_str(f, sizeof(f), "%y", get_end_label(zone, 2));
23159e506f0aSbrad 	if(strstr(f, "%x"))
23169e506f0aSbrad 		replace_str(f, sizeof(f), "%x", get_end_label(zone, 3));
23179e506f0aSbrad 	if(strstr(f, "%s"))
23189e506f0aSbrad 		replace_str(f, sizeof(f), "%s", zone->name);
23199e506f0aSbrad 	return f;
23209e506f0aSbrad }
23219e506f0aSbrad 
23229e506f0aSbrad const char*
config_make_zonefile(struct zone_options * zone,struct nsd * nsd)2323fe5fe5f6Sflorian config_make_zonefile(struct zone_options* zone, struct nsd* nsd)
2324d3fecca9Ssthen {
2325d3fecca9Ssthen 	static char f[1024];
2326d3fecca9Ssthen 	/* if not a template, return as-is */
2327cdb6bbddSbrad 	if(!strchr(zone->pattern->zonefile, '%')) {
2328cdb6bbddSbrad 		if (nsd->chrootdir && nsd->chrootdir[0] &&
2329cdb6bbddSbrad 			zone->pattern->zonefile &&
2330cdb6bbddSbrad 			zone->pattern->zonefile[0] == '/' &&
2331cdb6bbddSbrad 			strncmp(zone->pattern->zonefile, nsd->chrootdir,
2332cdb6bbddSbrad 			strlen(nsd->chrootdir)) == 0)
2333cdb6bbddSbrad 			/* -1 because chrootdir ends in trailing slash */
2334cdb6bbddSbrad 			return zone->pattern->zonefile + strlen(nsd->chrootdir) - 1;
2335d3fecca9Ssthen 		return zone->pattern->zonefile;
2336cdb6bbddSbrad 	}
2337d3fecca9Ssthen 	strlcpy(f, zone->pattern->zonefile, sizeof(f));
2338d3fecca9Ssthen 	if(strstr(f, "%1"))
2339d3fecca9Ssthen 		replace_str(f, sizeof(f), "%1", get_char(zone->name, 0));
2340d3fecca9Ssthen 	if(strstr(f, "%2"))
2341d3fecca9Ssthen 		replace_str(f, sizeof(f), "%2", get_char(zone->name, 1));
2342d3fecca9Ssthen 	if(strstr(f, "%3"))
2343d3fecca9Ssthen 		replace_str(f, sizeof(f), "%3", get_char(zone->name, 2));
2344d3fecca9Ssthen 	if(strstr(f, "%z"))
2345d3fecca9Ssthen 		replace_str(f, sizeof(f), "%z", get_end_label(zone, 1));
2346d3fecca9Ssthen 	if(strstr(f, "%y"))
2347d3fecca9Ssthen 		replace_str(f, sizeof(f), "%y", get_end_label(zone, 2));
2348d3fecca9Ssthen 	if(strstr(f, "%x"))
2349d3fecca9Ssthen 		replace_str(f, sizeof(f), "%x", get_end_label(zone, 3));
2350d3fecca9Ssthen 	if(strstr(f, "%s"))
2351d3fecca9Ssthen 		replace_str(f, sizeof(f), "%s", zone->name);
2352cdb6bbddSbrad 	if (nsd->chrootdir && nsd->chrootdir[0] && f[0] == '/' &&
2353cdb6bbddSbrad 		strncmp(f, nsd->chrootdir, strlen(nsd->chrootdir)) == 0)
2354cdb6bbddSbrad 		/* -1 because chrootdir ends in trailing slash */
2355cdb6bbddSbrad 		return f + strlen(nsd->chrootdir) - 1;
2356d3fecca9Ssthen 	return f;
2357d3fecca9Ssthen }
2358d3fecca9Ssthen 
2359fe5fe5f6Sflorian struct zone_options*
zone_options_find(struct nsd_options * opt,const struct dname * apex)2360fe5fe5f6Sflorian zone_options_find(struct nsd_options* opt, const struct dname* apex)
236162ac0c33Sjakob {
2362fe5fe5f6Sflorian 	return (struct zone_options*) rbtree_search(opt->zone_options, apex);
236362ac0c33Sjakob }
236462ac0c33Sjakob 
2365fe5fe5f6Sflorian struct acl_options*
acl_find_num(struct acl_options * acl,int num)2366fe5fe5f6Sflorian acl_find_num(struct acl_options* acl, int num)
236762ac0c33Sjakob {
236862ac0c33Sjakob 	int count = num;
236962ac0c33Sjakob 	if(num < 0)
237062ac0c33Sjakob 		return 0;
237162ac0c33Sjakob 	while(acl && count > 0) {
237262ac0c33Sjakob 		acl = acl->next;
237362ac0c33Sjakob 		count--;
237462ac0c33Sjakob 	}
237562ac0c33Sjakob 	if(count == 0)
237662ac0c33Sjakob 		return acl;
237762ac0c33Sjakob 	return 0;
237862ac0c33Sjakob }
237962ac0c33Sjakob 
238062ac0c33Sjakob /* true if ipv6 address, false if ipv4 */
2381d3fecca9Ssthen int
parse_acl_is_ipv6(const char * p)2382d3fecca9Ssthen parse_acl_is_ipv6(const char* p)
238362ac0c33Sjakob {
238462ac0c33Sjakob 	/* see if addr is ipv6 or ipv4 -- by : and . */
238562ac0c33Sjakob 	while(*p) {
238662ac0c33Sjakob 		if(*p == '.') return 0;
238762ac0c33Sjakob 		if(*p == ':') return 1;
238862ac0c33Sjakob 		++p;
238962ac0c33Sjakob 	}
239062ac0c33Sjakob 	return 0;
239162ac0c33Sjakob }
239262ac0c33Sjakob 
239362ac0c33Sjakob /* returns range type. mask is the 2nd part of the range */
2394d3fecca9Ssthen int
parse_acl_range_type(char * ip,char ** mask)2395d3fecca9Ssthen parse_acl_range_type(char* ip, char** mask)
239662ac0c33Sjakob {
239762ac0c33Sjakob 	char *p;
239862ac0c33Sjakob 	if((p=strchr(ip, '&'))!=0) {
239962ac0c33Sjakob 		*p = 0;
240062ac0c33Sjakob 		*mask = p+1;
240162ac0c33Sjakob 		return acl_range_mask;
240262ac0c33Sjakob 	}
240362ac0c33Sjakob 	if((p=strchr(ip, '/'))!=0) {
240462ac0c33Sjakob 		*p = 0;
240562ac0c33Sjakob 		*mask = p+1;
240662ac0c33Sjakob 		return acl_range_subnet;
240762ac0c33Sjakob 	}
240862ac0c33Sjakob 	if((p=strchr(ip, '-'))!=0) {
240962ac0c33Sjakob 		*p = 0;
241062ac0c33Sjakob 		*mask = p+1;
241162ac0c33Sjakob 		return acl_range_minmax;
241262ac0c33Sjakob 	}
241362ac0c33Sjakob 	*mask = 0;
241462ac0c33Sjakob 	return acl_range_single;
241562ac0c33Sjakob }
241662ac0c33Sjakob 
241762ac0c33Sjakob /* parses subnet mask, fills 0 mask as well */
2418d3fecca9Ssthen void
parse_acl_range_subnet(char * p,void * addr,int maxbits)2419d3fecca9Ssthen parse_acl_range_subnet(char* p, void* addr, int maxbits)
242062ac0c33Sjakob {
242162ac0c33Sjakob 	int subnet_bits = atoi(p);
242262ac0c33Sjakob 	uint8_t* addr_bytes = (uint8_t*)addr;
242362ac0c33Sjakob 	if(subnet_bits == 0 && strcmp(p, "0")!=0) {
24245435475dSsthen 		c_error("bad subnet range '%s'", p);
242562ac0c33Sjakob 		return;
242662ac0c33Sjakob 	}
242762ac0c33Sjakob 	if(subnet_bits < 0 || subnet_bits > maxbits) {
24285435475dSsthen 		c_error("subnet of %d bits out of range [0..%d]", subnet_bits, maxbits);
242962ac0c33Sjakob 		return;
243062ac0c33Sjakob 	}
243162ac0c33Sjakob 	/* fill addr with n bits of 1s (struct has been zeroed) */
243262ac0c33Sjakob 	while(subnet_bits >= 8) {
243362ac0c33Sjakob 		*addr_bytes++ = 0xff;
243462ac0c33Sjakob 		subnet_bits -= 8;
243562ac0c33Sjakob 	}
243662ac0c33Sjakob 	if(subnet_bits > 0) {
243762ac0c33Sjakob 		uint8_t shifts[] = {0x0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff};
243862ac0c33Sjakob 		*addr_bytes = shifts[subnet_bits];
243962ac0c33Sjakob 	}
244062ac0c33Sjakob }
244162ac0c33Sjakob 
2442fe5fe5f6Sflorian struct acl_options*
parse_acl_info(region_type * region,char * ip,const char * key)2443d3fecca9Ssthen parse_acl_info(region_type* region, char* ip, const char* key)
244462ac0c33Sjakob {
244562ac0c33Sjakob 	char* p;
2446fe5fe5f6Sflorian 	struct acl_options* acl = (struct acl_options*)region_alloc(region,
2447fe5fe5f6Sflorian 		sizeof(struct acl_options));
244862ac0c33Sjakob 	acl->next = 0;
244962ac0c33Sjakob 	/* ip */
245062ac0c33Sjakob 	acl->ip_address_spec = region_strdup(region, ip);
245162ac0c33Sjakob 	acl->use_axfr_only = 0;
245262ac0c33Sjakob 	acl->allow_udp = 0;
245362ac0c33Sjakob 	acl->ixfr_disabled = 0;
245412455795Ssthen 	acl->bad_xfr_count = 0;
245562ac0c33Sjakob 	acl->key_options = 0;
2456063644e9Sflorian 	acl->tls_auth_options = 0;
2457063644e9Sflorian 	acl->tls_auth_name = 0;
245862ac0c33Sjakob 	acl->is_ipv6 = 0;
245962ac0c33Sjakob 	acl->port = 0;
246062ac0c33Sjakob 	memset(&acl->addr, 0, sizeof(union acl_addr_storage));
246162ac0c33Sjakob 	memset(&acl->range_mask, 0, sizeof(union acl_addr_storage));
246262ac0c33Sjakob 	if((p=strrchr(ip, '@'))!=0) {
246362ac0c33Sjakob 		if(atoi(p+1) == 0) c_error("expected port number after '@'");
246462ac0c33Sjakob 		else acl->port = atoi(p+1);
246562ac0c33Sjakob 		*p=0;
246662ac0c33Sjakob 	}
246762ac0c33Sjakob 	acl->rangetype = parse_acl_range_type(ip, &p);
246862ac0c33Sjakob 	if(parse_acl_is_ipv6(ip)) {
246962ac0c33Sjakob 		acl->is_ipv6 = 1;
247062ac0c33Sjakob #ifdef INET6
247162ac0c33Sjakob 		if(inet_pton(AF_INET6, ip, &acl->addr.addr6) != 1)
24725435475dSsthen 			c_error("Bad ip6 address '%s'", ip);
2473b90bb40eSsthen 		if(acl->rangetype==acl_range_mask || acl->rangetype==acl_range_minmax) {
2474b90bb40eSsthen 			assert(p);
247562ac0c33Sjakob 			if(inet_pton(AF_INET6, p, &acl->range_mask.addr6) != 1)
24765435475dSsthen 				c_error("Bad ip6 address mask '%s'", p);
2477b90bb40eSsthen 		}
2478b90bb40eSsthen 		if(acl->rangetype==acl_range_subnet) {
2479b90bb40eSsthen 			assert(p);
248062ac0c33Sjakob 			parse_acl_range_subnet(p, &acl->range_mask.addr6, 128);
2481b90bb40eSsthen 		}
248262ac0c33Sjakob #else
24835435475dSsthen 		c_error("encountered IPv6 address '%s'.", ip);
248462ac0c33Sjakob #endif /* INET6 */
248562ac0c33Sjakob 	} else {
248662ac0c33Sjakob 		acl->is_ipv6 = 0;
248762ac0c33Sjakob 		if(inet_pton(AF_INET, ip, &acl->addr.addr) != 1)
24885435475dSsthen 			c_error("Bad ip4 address '%s'", ip);
2489b90bb40eSsthen 		if(acl->rangetype==acl_range_mask || acl->rangetype==acl_range_minmax) {
2490b90bb40eSsthen 			assert(p);
249162ac0c33Sjakob 			if(inet_pton(AF_INET, p, &acl->range_mask.addr) != 1)
24925435475dSsthen 				c_error("Bad ip4 address mask '%s'", p);
2493b90bb40eSsthen 		}
2494b90bb40eSsthen 		if(acl->rangetype==acl_range_subnet) {
2495b90bb40eSsthen 			assert(p);
249662ac0c33Sjakob 			parse_acl_range_subnet(p, &acl->range_mask.addr, 32);
249762ac0c33Sjakob 		}
2498b90bb40eSsthen 	}
249962ac0c33Sjakob 
250062ac0c33Sjakob 	/* key */
250162ac0c33Sjakob 	if(strcmp(key, "NOKEY")==0) {
250262ac0c33Sjakob 		acl->nokey = 1;
250362ac0c33Sjakob 		acl->blocked = 0;
250462ac0c33Sjakob 		acl->key_name = 0;
250562ac0c33Sjakob 	} else if(strcmp(key, "BLOCKED")==0) {
250662ac0c33Sjakob 		acl->nokey = 0;
250762ac0c33Sjakob 		acl->blocked = 1;
250862ac0c33Sjakob 		acl->key_name = 0;
250962ac0c33Sjakob 	} else {
251062ac0c33Sjakob 		acl->nokey = 0;
251162ac0c33Sjakob 		acl->blocked = 0;
251262ac0c33Sjakob 		acl->key_name = region_strdup(region, key);
251362ac0c33Sjakob 	}
251462ac0c33Sjakob 	return acl;
251562ac0c33Sjakob }
251662ac0c33Sjakob 
2517d3fecca9Ssthen /* copy acl list at end of parser start, update current */
2518d3fecca9Ssthen static
copy_and_append_acls(struct acl_options ** start,struct acl_options * list)25195435475dSsthen void copy_and_append_acls(struct acl_options** start, struct acl_options* list)
2520d3fecca9Ssthen {
25215435475dSsthen 	struct acl_options *tail = NULL;
25225435475dSsthen 
25235435475dSsthen 	assert(start != NULL);
25245435475dSsthen 
25255435475dSsthen 	tail = *start;
25265435475dSsthen 	if(tail) {
25275435475dSsthen 		while(tail->next) {
25285435475dSsthen 			tail = tail->next;
25295435475dSsthen 		}
25305435475dSsthen 	}
25315435475dSsthen 
2532d3fecca9Ssthen 	while(list) {
2533fe5fe5f6Sflorian 		struct acl_options* acl = copy_acl(cfg_parser->opt->region,
2534fe5fe5f6Sflorian 			list);
2535d3fecca9Ssthen 		acl->next = NULL;
25365435475dSsthen 		if(tail) {
25375435475dSsthen 			tail->next = acl;
25385435475dSsthen 		} else {
25395435475dSsthen 			*start = acl;
25405435475dSsthen 		}
25415435475dSsthen 		tail = acl;
2542d3fecca9Ssthen 		list = list->next;
2543d3fecca9Ssthen 	}
2544d3fecca9Ssthen }
2545d3fecca9Ssthen 
2546d3fecca9Ssthen void
config_apply_pattern(struct pattern_options * dest,const char * name)25475435475dSsthen config_apply_pattern(struct pattern_options *dest, const char* name)
2548d3fecca9Ssthen {
2549d3fecca9Ssthen 	/* find the pattern */
2550fe5fe5f6Sflorian 	struct pattern_options* pat = pattern_options_find(cfg_parser->opt,
2551fe5fe5f6Sflorian 		name);
2552d3fecca9Ssthen 	if(!pat) {
25535435475dSsthen 		c_error("could not find pattern %s", name);
2554d3fecca9Ssthen 		return;
2555d3fecca9Ssthen 	}
2556*bf87c3c0Sflorian 	if(strncmp(dest->pname, PATTERN_IMPLICIT_MARKER,
2557*bf87c3c0Sflorian 				strlen(PATTERN_IMPLICIT_MARKER)) == 0
2558*bf87c3c0Sflorian 	&& pat->catalog_producer_zone) {
2559*bf87c3c0Sflorian 		c_error("patterns with an catalog-producer-zone option are to "
2560*bf87c3c0Sflorian 		        "be used with \"nsd-control addzone\" only and cannot "
2561*bf87c3c0Sflorian 			"be included from zone clauses in the config file");
2562*bf87c3c0Sflorian 		return;
2563*bf87c3c0Sflorian 	}
2564*bf87c3c0Sflorian 	if((dest->catalog_role == CATALOG_ROLE_PRODUCER &&  pat->request_xfr)
2565*bf87c3c0Sflorian 	|| ( pat->catalog_role == CATALOG_ROLE_PRODUCER && dest->request_xfr)){
2566*bf87c3c0Sflorian 		c_error("catalog producer zones cannot be secondary zones");
2567*bf87c3c0Sflorian 	}
2568d3fecca9Ssthen 
2569d3fecca9Ssthen 	/* apply settings */
2570d3fecca9Ssthen 	if(pat->zonefile)
25715435475dSsthen 		dest->zonefile = region_strdup(cfg_parser->opt->region,
2572d3fecca9Ssthen 			pat->zonefile);
25739e506f0aSbrad 	if(pat->zonestats)
25745435475dSsthen 		dest->zonestats = region_strdup(cfg_parser->opt->region,
25759e506f0aSbrad 			pat->zonestats);
2576d3fecca9Ssthen 	if(!pat->allow_axfr_fallback_is_default) {
25775435475dSsthen 		dest->allow_axfr_fallback = pat->allow_axfr_fallback;
25785435475dSsthen 		dest->allow_axfr_fallback_is_default = 0;
2579d3fecca9Ssthen 	}
2580d3fecca9Ssthen 	if(!pat->notify_retry_is_default) {
25815435475dSsthen 		dest->notify_retry = pat->notify_retry;
25825435475dSsthen 		dest->notify_retry_is_default = 0;
2583d3fecca9Ssthen 	}
25846e9bf1eeSflorian 	if(!pat->max_refresh_time_is_default) {
25855435475dSsthen 		dest->max_refresh_time = pat->max_refresh_time;
25865435475dSsthen 		dest->max_refresh_time_is_default = 0;
25876e9bf1eeSflorian 	}
25886e9bf1eeSflorian 	if(!pat->min_refresh_time_is_default) {
25895435475dSsthen 		dest->min_refresh_time = pat->min_refresh_time;
25905435475dSsthen 		dest->min_refresh_time_is_default = 0;
25916e9bf1eeSflorian 	}
25926e9bf1eeSflorian 	if(!pat->max_retry_time_is_default) {
25935435475dSsthen 		dest->max_retry_time = pat->max_retry_time;
25945435475dSsthen 		dest->max_retry_time_is_default = 0;
25956e9bf1eeSflorian 	}
25966e9bf1eeSflorian 	if(!pat->min_retry_time_is_default) {
25975435475dSsthen 		dest->min_retry_time = pat->min_retry_time;
25985435475dSsthen 		dest->min_retry_time_is_default = 0;
25996e9bf1eeSflorian 	}
2600ac5517e4Sflorian 	if(!expire_time_is_default(pat->min_expire_time_expr)) {
2601ac5517e4Sflorian 		dest->min_expire_time = pat->min_expire_time;
2602ac5517e4Sflorian 		dest->min_expire_time_expr = pat->min_expire_time_expr;
2603ac5517e4Sflorian 	}
26044564029fSflorian 	if(!pat->store_ixfr_is_default) {
26054564029fSflorian 		dest->store_ixfr = pat->store_ixfr;
26064564029fSflorian 		dest->store_ixfr_is_default = 0;
26074564029fSflorian 	}
26084564029fSflorian 	if(!pat->ixfr_size_is_default) {
26094564029fSflorian 		dest->ixfr_size = pat->ixfr_size;
26104564029fSflorian 		dest->ixfr_size_is_default = 0;
26114564029fSflorian 	}
26124564029fSflorian 	if(!pat->ixfr_number_is_default) {
26134564029fSflorian 		dest->ixfr_number = pat->ixfr_number;
26144564029fSflorian 		dest->ixfr_number_is_default = 0;
26154564029fSflorian 	}
26164564029fSflorian 	if(!pat->create_ixfr_is_default) {
26174564029fSflorian 		dest->create_ixfr = pat->create_ixfr;
26184564029fSflorian 		dest->create_ixfr_is_default = 0;
26194564029fSflorian 	}
26205435475dSsthen 	dest->size_limit_xfr = pat->size_limit_xfr;
2621d3fecca9Ssthen #ifdef RATELIMIT
26225435475dSsthen 	dest->rrl_whitelist |= pat->rrl_whitelist;
2623d3fecca9Ssthen #endif
2624d3fecca9Ssthen 	/* append acl items */
26255435475dSsthen 	copy_and_append_acls(&dest->allow_notify, pat->allow_notify);
26265435475dSsthen 	copy_and_append_acls(&dest->request_xfr, pat->request_xfr);
26275435475dSsthen 	copy_and_append_acls(&dest->notify, pat->notify);
26285435475dSsthen 	copy_and_append_acls(&dest->provide_xfr, pat->provide_xfr);
26298d298c9fSsthen 	copy_and_append_acls(&dest->allow_query, pat->allow_query);
26305435475dSsthen 	copy_and_append_acls(&dest->outgoing_interface, pat->outgoing_interface);
2631*bf87c3c0Sflorian 	if(pat->multi_primary_check)
2632*bf87c3c0Sflorian 		dest->multi_primary_check = pat->multi_primary_check;
26333f21e8ccSflorian 
26343f21e8ccSflorian 	if(!pat->verify_zone_is_default) {
26353f21e8ccSflorian 		dest->verify_zone = pat->verify_zone;
26363f21e8ccSflorian 		dest->verify_zone_is_default = 0;
26373f21e8ccSflorian 	}
26383f21e8ccSflorian 	if(!pat->verifier_timeout_is_default) {
26393f21e8ccSflorian 		dest->verifier_timeout = pat->verifier_timeout;
26403f21e8ccSflorian 		dest->verifier_timeout_is_default = 0;
26413f21e8ccSflorian 	}
26423f21e8ccSflorian 	if(!pat->verifier_feed_zone_is_default) {
26433f21e8ccSflorian 		dest->verifier_feed_zone = pat->verifier_feed_zone;
26443f21e8ccSflorian 		dest->verifier_feed_zone_is_default = 0;
26453f21e8ccSflorian 	}
26463f21e8ccSflorian 	if(pat->verifier != NULL) {
26473f21e8ccSflorian 		size_t cnt;
26483f21e8ccSflorian 		char **vec;
26493f21e8ccSflorian 		region_type *region = cfg_parser->opt->region;
26503f21e8ccSflorian 
26513f21e8ccSflorian 		for(cnt = 0; pat->verifier[cnt] != NULL; cnt++) ;
26523f21e8ccSflorian 		vec = region_alloc(region, (cnt + 1) * sizeof(char *));
26533f21e8ccSflorian 		for(cnt = 0; pat->verifier[cnt] != NULL; cnt++) {
26543f21e8ccSflorian 			vec[cnt] = region_strdup(region, pat->verifier[cnt]);
26553f21e8ccSflorian 		}
26563f21e8ccSflorian 		vec[cnt] = NULL;
26573f21e8ccSflorian 		if(dest->verifier != NULL) {
26583f21e8ccSflorian 			size_t size;
26593f21e8ccSflorian 			for(cnt = 0; dest->verifier[cnt] != NULL; cnt++) {
26603f21e8ccSflorian 				size = strlen(dest->verifier[cnt]) + 1;
26613f21e8ccSflorian 				region_recycle(
26623f21e8ccSflorian 					region, dest->verifier[cnt], size);
26633f21e8ccSflorian 			}
26643f21e8ccSflorian 			size = (cnt + 1) * sizeof(char *);
26653f21e8ccSflorian 			region_recycle(region, dest->verifier, size);
26663f21e8ccSflorian 		}
26673f21e8ccSflorian 		dest->verifier = vec;
26683f21e8ccSflorian 	}
2669*bf87c3c0Sflorian 	if(!pat->catalog_role_is_default) {
2670*bf87c3c0Sflorian 		dest->catalog_role = pat->catalog_role;
2671*bf87c3c0Sflorian 		dest->catalog_role_is_default = 0;
2672*bf87c3c0Sflorian 	}
2673*bf87c3c0Sflorian 	if(pat->catalog_member_pattern)
2674*bf87c3c0Sflorian 		dest->catalog_member_pattern = region_strdup(
2675*bf87c3c0Sflorian 			cfg_parser->opt->region, pat->catalog_member_pattern);
2676*bf87c3c0Sflorian 	if(pat->catalog_producer_zone)
2677*bf87c3c0Sflorian 		dest->catalog_producer_zone = region_strdup(
2678*bf87c3c0Sflorian 			cfg_parser->opt->region, pat->catalog_producer_zone);
2679d3fecca9Ssthen }
2680d3fecca9Ssthen 
2681d3fecca9Ssthen void
nsd_options_destroy(struct nsd_options * opt)2682fe5fe5f6Sflorian nsd_options_destroy(struct nsd_options* opt)
268362ac0c33Sjakob {
268462ac0c33Sjakob 	region_destroy(opt->region);
2685b90bb40eSsthen #ifdef MEMCLEAN /* OS collects memory pages */
2686b90bb40eSsthen 	c_lex_destroy();
2687b90bb40eSsthen #endif
268862ac0c33Sjakob }
26899e506f0aSbrad 
getzonestatid(struct nsd_options * opt,struct zone_options * zopt)2690fe5fe5f6Sflorian unsigned getzonestatid(struct nsd_options* opt, struct zone_options* zopt)
26919e506f0aSbrad {
26929e506f0aSbrad #ifdef USE_ZONE_STATS
26939e506f0aSbrad 	const char* statname;
26949e506f0aSbrad 	struct zonestatname* n;
2695fe5fe5f6Sflorian 	rbnode_type* res;
26969e506f0aSbrad 	/* try to find the instantiated zonestat name */
26979e506f0aSbrad 	if(!zopt->pattern->zonestats || zopt->pattern->zonestats[0]==0)
26989e506f0aSbrad 		return 0; /* no zone stats */
26999e506f0aSbrad 	statname = config_cook_string(zopt, zopt->pattern->zonestats);
27009e506f0aSbrad 	res = rbtree_search(opt->zonestatnames, statname);
27019e506f0aSbrad 	if(res)
27029e506f0aSbrad 		return ((struct zonestatname*)res)->id;
27039e506f0aSbrad 	/* create it */
2704b90bb40eSsthen 	n = (struct zonestatname*)region_alloc_zero(opt->region, sizeof(*n));
2705b90bb40eSsthen 	n->node.key = region_strdup(opt->region, statname);
27069e506f0aSbrad 	if(!n->node.key) {
27079e506f0aSbrad 		log_msg(LOG_ERR, "malloc failed: %s", strerror(errno));
27089e506f0aSbrad 		exit(1);
27099e506f0aSbrad 	}
27109e506f0aSbrad 	n->id = (unsigned)(opt->zonestatnames->count);
2711fe5fe5f6Sflorian 	rbtree_insert(opt->zonestatnames, (rbnode_type*)n);
27129e506f0aSbrad 	return n->id;
27139e506f0aSbrad #else /* USE_ZONE_STATS */
27149e506f0aSbrad 	(void)opt; (void)zopt;
27159e506f0aSbrad 	return 0;
27169e506f0aSbrad #endif /* USE_ZONE_STATS */
27179e506f0aSbrad }
271818e77612Sflorian 
271918e77612Sflorian /** check if config turns on IP-address interface with certificates or a
272018e77612Sflorian  * named pipe without certificates. */
272118e77612Sflorian int
options_remote_is_address(struct nsd_options * cfg)272218e77612Sflorian options_remote_is_address(struct nsd_options* cfg)
272318e77612Sflorian {
272418e77612Sflorian 	if(!cfg->control_enable) return 0;
272518e77612Sflorian 	if(!cfg->control_interface) return 1;
272618e77612Sflorian 	if(!cfg->control_interface->address) return 1;
272718e77612Sflorian 	if(cfg->control_interface->address[0] == 0) return 1;
272818e77612Sflorian 	return (cfg->control_interface->address[0] != '/');
272918e77612Sflorian }
27308d298c9fSsthen 
27318d298c9fSsthen #ifdef HAVE_GETIFADDRS
27328d298c9fSsthen static void
resolve_ifa_name(struct ifaddrs * ifas,const char * search_ifa,char *** ip_addresses,size_t * ip_addresses_size)27338d298c9fSsthen resolve_ifa_name(struct ifaddrs *ifas, const char *search_ifa, char ***ip_addresses, size_t *ip_addresses_size)
27348d298c9fSsthen {
27358d298c9fSsthen 	struct ifaddrs *ifa;
27368d298c9fSsthen 	size_t last_ip_addresses_size = *ip_addresses_size;
27378d298c9fSsthen 
27388d298c9fSsthen 	for(ifa = ifas; ifa != NULL; ifa = ifa->ifa_next) {
27398d298c9fSsthen 		sa_family_t family;
27408d298c9fSsthen 		const char* atsign;
27418d298c9fSsthen #ifdef INET6      /* |   address ip    | % |  ifa name  | @ |  port  | nul */
27428d298c9fSsthen 		char addr_buf[INET6_ADDRSTRLEN + 1 + IF_NAMESIZE + 1 + 16 + 1];
27438d298c9fSsthen #else
27448d298c9fSsthen 		char addr_buf[INET_ADDRSTRLEN + 1 + 16 + 1];
27458d298c9fSsthen #endif
27468d298c9fSsthen 
27478d298c9fSsthen 		if((atsign=strrchr(search_ifa, '@')) != NULL) {
27488d298c9fSsthen 			if(strlen(ifa->ifa_name) != (size_t)(atsign-search_ifa)
27498d298c9fSsthen 			   || strncmp(ifa->ifa_name, search_ifa,
27508d298c9fSsthen 			   atsign-search_ifa) != 0)
27518d298c9fSsthen 				continue;
27528d298c9fSsthen 		} else {
27538d298c9fSsthen 			if(strcmp(ifa->ifa_name, search_ifa) != 0)
27548d298c9fSsthen 				continue;
27558d298c9fSsthen 			atsign = "";
27568d298c9fSsthen 		}
27578d298c9fSsthen 
27588d298c9fSsthen 		if(ifa->ifa_addr == NULL)
27598d298c9fSsthen 			continue;
27608d298c9fSsthen 
27618d298c9fSsthen 		family = ifa->ifa_addr->sa_family;
27628d298c9fSsthen 		if(family == AF_INET) {
27638d298c9fSsthen 			char a4[INET_ADDRSTRLEN + 1];
27648d298c9fSsthen 			struct sockaddr_in *in4 = (struct sockaddr_in *)
27658d298c9fSsthen 				ifa->ifa_addr;
27668d298c9fSsthen 			if(!inet_ntop(family, &in4->sin_addr, a4, sizeof(a4)))
27678d298c9fSsthen 				error("inet_ntop");
27688d298c9fSsthen 			snprintf(addr_buf, sizeof(addr_buf), "%s%s",
27698d298c9fSsthen 				a4, atsign);
27708d298c9fSsthen 		}
27718d298c9fSsthen #ifdef INET6
27728d298c9fSsthen 		else if(family == AF_INET6) {
27738d298c9fSsthen 			struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)
27748d298c9fSsthen 				ifa->ifa_addr;
27758d298c9fSsthen 			char a6[INET6_ADDRSTRLEN + 1];
27768d298c9fSsthen 			char if_index_name[IF_NAMESIZE + 1];
27778d298c9fSsthen 			if_index_name[0] = 0;
27788d298c9fSsthen 			if(!inet_ntop(family, &in6->sin6_addr, a6, sizeof(a6)))
27798d298c9fSsthen 				error("inet_ntop");
27808d298c9fSsthen 			if_indextoname(in6->sin6_scope_id,
27818d298c9fSsthen 				(char *)if_index_name);
27828d298c9fSsthen 			if (strlen(if_index_name) != 0) {
27838d298c9fSsthen 				snprintf(addr_buf, sizeof(addr_buf),
27848d298c9fSsthen 					"%s%%%s%s", a6, if_index_name, atsign);
27858d298c9fSsthen 			} else {
27868d298c9fSsthen 				snprintf(addr_buf, sizeof(addr_buf), "%s%s",
27878d298c9fSsthen 					a6, atsign);
27888d298c9fSsthen 			}
27898d298c9fSsthen 		}
27908d298c9fSsthen #endif
27918d298c9fSsthen 		else {
27928d298c9fSsthen 			continue;
27938d298c9fSsthen 		}
27948d298c9fSsthen 		VERBOSITY(4, (LOG_INFO, "interface %s has address %s",
27958d298c9fSsthen 			search_ifa, addr_buf));
27968d298c9fSsthen 
27978d298c9fSsthen 		*ip_addresses = xrealloc(*ip_addresses, sizeof(char *) * (*ip_addresses_size + 1));
27988d298c9fSsthen 		(*ip_addresses)[*ip_addresses_size] = xstrdup(addr_buf);
27998d298c9fSsthen 		(*ip_addresses_size)++;
28008d298c9fSsthen 	}
28018d298c9fSsthen 
28028d298c9fSsthen 	if (*ip_addresses_size == last_ip_addresses_size) {
28038d298c9fSsthen 		*ip_addresses = xrealloc(*ip_addresses, sizeof(char *) * (*ip_addresses_size + 1));
28048d298c9fSsthen 		(*ip_addresses)[*ip_addresses_size] = xstrdup(search_ifa);
28058d298c9fSsthen 		(*ip_addresses_size)++;
28068d298c9fSsthen 	}
28078d298c9fSsthen }
28088d298c9fSsthen 
28098d298c9fSsthen static void
resolve_interface_names_for_ref(struct ip_address_option ** ip_addresses_ref,struct ifaddrs * addrs,region_type * region)28108d298c9fSsthen resolve_interface_names_for_ref(struct ip_address_option** ip_addresses_ref,
28118d298c9fSsthen 		struct ifaddrs *addrs, region_type* region)
28128d298c9fSsthen {
28138d298c9fSsthen 	struct ip_address_option *ip_addr;
28148d298c9fSsthen 	struct ip_address_option *last = NULL;
28158d298c9fSsthen 	struct ip_address_option *first = NULL;
28168d298c9fSsthen 
28178d298c9fSsthen 	/* replace the list of ip_adresses with a new list where the
28188d298c9fSsthen 	 * interface names are replaced with their ip-address strings
28198d298c9fSsthen 	 * from getifaddrs.  An interface can have several addresses. */
28208d298c9fSsthen 	for(ip_addr = *ip_addresses_ref; ip_addr; ip_addr = ip_addr->next) {
28218d298c9fSsthen 		char **ip_addresses = NULL;
28228d298c9fSsthen 		size_t ip_addresses_size = 0, i;
28238d298c9fSsthen 		resolve_ifa_name(addrs, ip_addr->address, &ip_addresses,
28248d298c9fSsthen 			&ip_addresses_size);
28258d298c9fSsthen 
28268d298c9fSsthen 		for (i = 0; i < ip_addresses_size; i++) {
28278d298c9fSsthen 			struct ip_address_option *current;
28288d298c9fSsthen 			/* this copies the range_option, dev, and fib from
28298d298c9fSsthen 			 * the original ip_address option to the new ones
28308d298c9fSsthen 			 * with the addresses spelled out by resolve_ifa_name*/
28318d298c9fSsthen 			current = region_alloc_init(region, ip_addr,
28328d298c9fSsthen 				sizeof(*ip_addr));
28338d298c9fSsthen 			current->address = region_strdup(region,
28348d298c9fSsthen 				ip_addresses[i]);
28358d298c9fSsthen 			current->next = NULL;
28368d298c9fSsthen 			free(ip_addresses[i]);
28378d298c9fSsthen 
28388d298c9fSsthen 			if(first == NULL) {
28398d298c9fSsthen 				first = current;
28408d298c9fSsthen 			} else {
28418d298c9fSsthen 				last->next = current;
28428d298c9fSsthen 			}
28438d298c9fSsthen 			last = current;
28448d298c9fSsthen 		}
28458d298c9fSsthen 		free(ip_addresses);
28468d298c9fSsthen 	}
28478d298c9fSsthen 	*ip_addresses_ref = first;
28488d298c9fSsthen 
28498d298c9fSsthen }
28508d298c9fSsthen #endif /* HAVE_GETIFADDRS */
28518d298c9fSsthen 
28528d298c9fSsthen void
resolve_interface_names(struct nsd_options * options)28538d298c9fSsthen resolve_interface_names(struct nsd_options* options)
28548d298c9fSsthen {
28558d298c9fSsthen #ifdef HAVE_GETIFADDRS
28568d298c9fSsthen 	struct ifaddrs *addrs;
28578d298c9fSsthen 
28588d298c9fSsthen 	if(getifaddrs(&addrs) == -1)
28598d298c9fSsthen 		  error("failed to list interfaces");
28608d298c9fSsthen 
28618d298c9fSsthen 	resolve_interface_names_for_ref(&options->ip_addresses,
28628d298c9fSsthen 			addrs, options->region);
28638d298c9fSsthen 	resolve_interface_names_for_ref(&options->control_interface,
28648d298c9fSsthen 			addrs, options->region);
28658d298c9fSsthen 
28668d298c9fSsthen 	freeifaddrs(addrs);
28678d298c9fSsthen #else
28688d298c9fSsthen 	(void)options;
28698d298c9fSsthen #endif /* HAVE_GETIFADDRS */
28708d298c9fSsthen }
2871b71395eaSflorian 
2872b71395eaSflorian int
sockaddr_uses_proxy_protocol_port(struct nsd_options * options,struct sockaddr * addr)2873b71395eaSflorian sockaddr_uses_proxy_protocol_port(struct nsd_options* options,
2874b71395eaSflorian 	struct sockaddr* addr)
2875b71395eaSflorian {
2876b71395eaSflorian 	struct proxy_protocol_port_list* p;
2877b71395eaSflorian 	int port;
2878b71395eaSflorian #ifdef INET6
2879b71395eaSflorian 	struct sockaddr_storage* ss = (struct sockaddr_storage*)addr;
2880b71395eaSflorian 	if(ss->ss_family == AF_INET6) {
2881b71395eaSflorian 		struct sockaddr_in6* a6 = (struct sockaddr_in6*)addr;
2882b71395eaSflorian 		port = ntohs(a6->sin6_port);
2883b71395eaSflorian 	} else if(ss->ss_family == AF_INET) {
2884b71395eaSflorian #endif
2885b71395eaSflorian 		struct sockaddr_in* a = (struct sockaddr_in*)addr;
2886b71395eaSflorian #ifndef INET6
2887b71395eaSflorian 		if(a->sin_family != AF_INET)
2888b71395eaSflorian 			return 0; /* unknown family */
2889b71395eaSflorian #endif
2890b71395eaSflorian 		port = ntohs(a->sin_port);
2891b71395eaSflorian #ifdef INET6
2892b71395eaSflorian 	} else {
2893b71395eaSflorian 		return 0; /* unknown family */
2894b71395eaSflorian 	}
2895b71395eaSflorian #endif
2896b71395eaSflorian 	p = options->proxy_protocol_port;
2897b71395eaSflorian 	while(p) {
2898b71395eaSflorian 		if(p->port == port)
2899b71395eaSflorian 			return 1;
2900b71395eaSflorian 		p = p->next;
2901b71395eaSflorian 	}
2902b71395eaSflorian 	return 0;
2903b71395eaSflorian }
2904