Bug Summary

File:src/usr.sbin/nsd/options.c
Warning:line 1949, column 25
Null pointer passed as 1st argument to string comparison function

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name options.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.sbin/nsd/obj -resource-dir /usr/local/lib/clang/13.0.0 -I . -I /usr/src/usr.sbin/nsd -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/nsd/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.sbin/nsd/options.c
1/*
2 * options.c -- options functions.
3 *
4 * Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
5 *
6 * See LICENSE for the license.
7 *
8 */
9#include "config.h"
10#include <string.h>
11#include <stdio.h>
12#include <sys/stat.h>
13#include <errno(*__errno()).h>
14#ifdef HAVE_IFADDRS_H1
15#include <ifaddrs.h>
16#endif
17#include "options.h"
18#include "query.h"
19#include "tsig.h"
20#include "difffile.h"
21#include "rrl.h"
22#include "bitset.h"
23
24#include "configparser.h"
25config_parser_state_type* cfg_parser = 0;
26extern FILE* c_in, *c_out;
27int c_parse(void);
28int c_lex(void);
29int c_wrap(void);
30int c_lex_destroy(void);
31extern char* c_text;
32
33static int
34rbtree_strcmp(const void* p1, const void* p2)
35{
36 if(p1 == NULL((void*)0) && p2 == NULL((void*)0)) return 0;
37 if(p1 == NULL((void*)0)) return -1;
38 if(p2 == NULL((void*)0)) return 1;
39 return strcmp((const char*)p1, (const char*)p2);
40}
41
42struct nsd_options*
43nsd_options_create(region_type* region)
44{
45 struct nsd_options* opt;
46 opt = (struct nsd_options*)region_alloc(region, sizeof(
47 struct nsd_options));
48 opt->region = region;
49 opt->zone_options = rbtree_create(region,
50 (int (*)(const void *, const void *)) dname_compare);
51 opt->configfile = NULL((void*)0);
52 opt->zonestatnames = rbtree_create(opt->region, rbtree_strcmp);
53 opt->patterns = rbtree_create(region, rbtree_strcmp);
54 opt->keys = rbtree_create(region, rbtree_strcmp);
55 opt->tls_auths = rbtree_create(region, rbtree_strcmp);
56 opt->ip_addresses = NULL((void*)0);
57 opt->ip_transparent = 0;
58 opt->ip_freebind = 0;
59 opt->send_buffer_size = 0;
60 opt->receive_buffer_size = 0;
61 opt->debug_mode = 0;
62 opt->verbosity = 0;
63 opt->hide_version = 0;
64 opt->hide_identity = 0;
65 opt->drop_updates = 0;
66 opt->do_ip4 = 1;
67 opt->do_ip6 = 1;
68 opt->database = DBFILE"";
69 opt->identity = 0;
70 opt->version = 0;
71 opt->nsid = 0;
72 opt->logfile = 0;
73 opt->log_only_syslog = 0;
74 opt->log_time_ascii = 1;
75 opt->round_robin = 0; /* also packet.h::round_robin */
76 opt->minimal_responses = 1; /* also packet.h::minimal_responses */
77 opt->confine_to_zone = 0;
78 opt->refuse_any = 1;
79 opt->server_count = 1;
80 opt->cpu_affinity = NULL((void*)0);
81 opt->service_cpu_affinity = NULL((void*)0);
82 opt->tcp_count = 100;
83 opt->tcp_reject_overflow = 0;
84 opt->tcp_query_count = 0;
85 opt->tcp_timeout = TCP_TIMEOUT120;
86 opt->tcp_mss = 0;
87 opt->outgoing_tcp_mss = 0;
88 opt->ipv4_edns_size = EDNS_MAX_MESSAGE_LEN1232;
89 opt->ipv6_edns_size = EDNS_MAX_MESSAGE_LEN1232;
90 opt->pidfile = PIDFILE"";
91 opt->port = UDP_PORT"53";
92/* deprecated? opt->port = TCP_PORT; */
93 opt->reuseport = 0;
94 opt->statistics = 0;
95 opt->chroot = 0;
96 opt->username = USER"_nsd";
97 opt->zonesdir = ZONESDIR"/var/nsd/zones";
98 opt->xfrdfile = XFRDFILE"/var/nsd/run/xfrd.state";
99 opt->xfrdir = XFRDIR"/var/nsd/run/xfr";
100 opt->zonelistfile = ZONELISTFILE"/var/nsd/db/zone.list";
101#ifdef RATELIMIT
102 opt->rrl_size = RRL_BUCKETS1000000;
103 opt->rrl_slip = RRL_SLIP2;
104 opt->rrl_ipv4_prefix_length = RRL_IPV4_PREFIX_LENGTH24;
105 opt->rrl_ipv6_prefix_length = RRL_IPV6_PREFIX_LENGTH64;
106# ifdef RATELIMIT_DEFAULT_OFF
107 opt->rrl_ratelimit = 0;
108 opt->rrl_whitelist_ratelimit = 0;
109# else
110 opt->rrl_ratelimit = RRL_LIMIT400/2;
111 opt->rrl_whitelist_ratelimit = RRL_WLIST_LIMIT4000/2;
112# endif
113#endif
114#ifdef USE_DNSTAP
115 opt->dnstap_enable = 0;
116 opt->dnstap_socket_path = DNSTAP_SOCKET_PATH;
117 opt->dnstap_send_identity = 0;
118 opt->dnstap_send_version = 0;
119 opt->dnstap_identity = NULL((void*)0);
120 opt->dnstap_version = NULL((void*)0);
121 opt->dnstap_log_auth_query_messages = 0;
122 opt->dnstap_log_auth_response_messages = 0;
123#endif
124 opt->zonefiles_check = 1;
125 if(opt->database == NULL((void*)0) || opt->database[0] == 0)
126 opt->zonefiles_write = ZONEFILES_WRITE_INTERVAL3600;
127 else opt->zonefiles_write = 0;
128 opt->xfrd_reload_timeout = 1;
129 opt->tls_service_key = NULL((void*)0);
130 opt->tls_service_ocsp = NULL((void*)0);
131 opt->tls_service_pem = NULL((void*)0);
132 opt->tls_port = TLS_PORT"853";
133 opt->tls_cert_bundle = NULL((void*)0);
134 opt->answer_cookie = 1;
135 opt->cookie_secret = NULL((void*)0);
136 opt->cookie_secret_file = CONFIGDIR"/var/nsd/etc""/nsd_cookiesecrets.txt";
137 opt->control_enable = 0;
138 opt->control_interface = NULL((void*)0);
139 opt->control_port = NSD_CONTROL_PORT8952;
140 opt->server_key_file = CONFIGDIR"/var/nsd/etc""/nsd_server.key";
141 opt->server_cert_file = CONFIGDIR"/var/nsd/etc""/nsd_server.pem";
142 opt->control_key_file = CONFIGDIR"/var/nsd/etc""/nsd_control.key";
143 opt->control_cert_file = CONFIGDIR"/var/nsd/etc""/nsd_control.pem";
144 return opt;
145}
146
147int
148nsd_options_insert_zone(struct nsd_options* opt, struct zone_options* zone)
149{
150 /* create dname for lookup */
151 const dname_type* dname = dname_parse(opt->region, zone->name);
152 if(!dname)
153 return 0;
154 zone->node.key = dname;
155 if(!rbtree_insert(opt->zone_options, (rbnode_type*)zone))
156 return 0;
157 return 1;
158}
159
160int
161nsd_options_insert_pattern(struct nsd_options* opt,
162 struct pattern_options* pat)
163{
164 if(!pat->pname)
165 return 0;
166 pat->node.key = pat->pname;
167 if(!rbtree_insert(opt->patterns, (rbnode_type*)pat))
168 return 0;
169 return 1;
170}
171
172void
173warn_if_directory(const char* filetype, FILE* f, const char* fname)
174{
175 if(fileno(f)(!__isthreaded ? ((f)->_file) : (fileno)(f)) != -1) {
176 struct stat st;
177 memset(&st, 0, sizeof(st));
178 if(fstat(fileno(f)(!__isthreaded ? ((f)->_file) : (fileno)(f)), &st) != -1) {
179 if(S_ISDIR(st.st_mode)((st.st_mode & 0170000) == 0040000)) {
180 log_msg(LOG_WARNING4, "trying to read %s but it is a directory: %s", filetype, fname);
181 }
182 }
183 }
184}
185
186int
187parse_options_file(struct nsd_options* opt, const char* file,
188 void (*err)(void*,const char*), void* err_arg)
189{
190 FILE *in = 0;
191 struct pattern_options* pat;
192 struct acl_options* acl;
193
194 if(!cfg_parser) {
195 cfg_parser = (config_parser_state_type*)region_alloc(
196 opt->region, sizeof(config_parser_state_type));
197 cfg_parser->chroot = 0;
198 }
199 cfg_parser->err = err;
200 cfg_parser->err_arg = err_arg;
201 cfg_parser->filename = (char*)file;
202 cfg_parser->line = 1;
203 cfg_parser->errors = 0;
204 cfg_parser->opt = opt;
205 cfg_parser->pattern = NULL((void*)0);
206 cfg_parser->zone = NULL((void*)0);
207 cfg_parser->key = NULL((void*)0);
208 cfg_parser->tls_auth = NULL((void*)0);
209
210 in = fopen(cfg_parser->filename, "r");
211 if(!in) {
212 if(err) {
213 char m[MAXSYSLOGMSGLEN512];
214 snprintf(m, sizeof(m), "Could not open %s: %s\n",
215 file, strerror(errno(*__errno())));
216 err(err_arg, m);
217 } else {
218 fprintf(stderr(&__sF[2]), "Could not open %s: %s\n",
219 file, strerror(errno(*__errno())));
220 }
221 return 0;
222 }
223 warn_if_directory("configfile", in, file);
224 c_in = in;
225 c_parse();
226 fclose(in);
227
228 opt->configfile = region_strdup(opt->region, file);
229
230 RBTREE_FOR(pat, struct pattern_options*, opt->patterns)for(pat=(struct pattern_options*)rbtree_first(opt->patterns
); (rbnode_type*)pat != &rbtree_null_node; pat = (struct pattern_options
*)rbtree_next((rbnode_type*)pat))
231 {
232 /* lookup keys for acls */
233 for(acl=pat->allow_notify; acl; acl=acl->next)
234 {
235 if(acl->nokey || acl->blocked)
236 continue;
237 acl->key_options = key_options_find(opt, acl->key_name);
238 if(!acl->key_options)
239 c_error("key %s in pattern %s could not be found",
240 acl->key_name, pat->pname);
241 }
242 for(acl=pat->notify; acl; acl=acl->next)
243 {
244 if(acl->nokey || acl->blocked)
245 continue;
246 acl->key_options = key_options_find(opt, acl->key_name);
247 if(!acl->key_options)
248 c_error("key %s in pattern %s could not be found",
249 acl->key_name, pat->pname);
250 }
251 for(acl=pat->request_xfr; acl; acl=acl->next)
252 {
253 /* Find tls_auth */
254 if (!acl->tls_auth_name)
255 ; /* pass */
256 else if (!(acl->tls_auth_options =
257 tls_auth_options_find(opt, acl->tls_auth_name)))
258 c_error("tls_auth %s in pattern %s could not be found",
259 acl->tls_auth_name, pat->pname);
260 /* Find key */
261 if(acl->nokey || acl->blocked)
262 continue;
263 acl->key_options = key_options_find(opt, acl->key_name);
264 if(!acl->key_options)
265 c_error("key %s in pattern %s could not be found",
266 acl->key_name, pat->pname);
267 }
268 for(acl=pat->provide_xfr; acl; acl=acl->next)
269 {
270 if(acl->nokey || acl->blocked)
271 continue;
272 acl->key_options = key_options_find(opt, acl->key_name);
273 if(!acl->key_options)
274 c_error("key %s in pattern %s could not be found",
275 acl->key_name, pat->pname);
276 }
277 for(acl=pat->allow_query; acl; acl=acl->next)
278 {
279 if(acl->nokey || acl->blocked)
280 continue;
281 acl->key_options = key_options_find(opt, acl->key_name);
282 if(!acl->key_options)
283 c_error("key %s in pattern %s could not be found",
284 acl->key_name, pat->pname);
285 }
286 }
287
288 if(cfg_parser->errors > 0)
289 {
290 if(err) {
291 char m[MAXSYSLOGMSGLEN512];
292 snprintf(m, sizeof(m), "read %s failed: %d errors in "
293 "configuration file\n", file,
294 cfg_parser->errors);
295 err(err_arg, m);
296 } else {
297 fprintf(stderr(&__sF[2]), "read %s failed: %d errors in "
298 "configuration file\n", file,
299 cfg_parser->errors);
300 }
301 return 0;
302 }
303 return 1;
304}
305
306void options_zonestatnames_create(struct nsd_options* opt)
307{
308 struct zone_options* zopt;
309 /* allocate "" as zonestat 0, for zones without a zonestat */
310 if(!rbtree_search(opt->zonestatnames, "")) {
311 struct zonestatname* n;
312 n = (struct zonestatname*)region_alloc_zero(opt->region,
313 sizeof(*n));
314 n->node.key = region_strdup(opt->region, "");
315 if(!n->node.key) {
316 log_msg(LOG_ERR3, "malloc failed: %s", strerror(errno(*__errno())));
317 exit(1);
318 }
319 n->id = (unsigned)(opt->zonestatnames->count);
320 rbtree_insert(opt->zonestatnames, (rbnode_type*)n);
321 }
322 RBTREE_FOR(zopt, struct zone_options*, opt->zone_options)for(zopt=(struct zone_options*)rbtree_first(opt->zone_options
); (rbnode_type*)zopt != &rbtree_null_node; zopt = (struct
zone_options*)rbtree_next((rbnode_type*)zopt))
{
323 /* insert into tree, so that when read in later id exists */
324 (void)getzonestatid(opt, zopt);
325 }
326}
327
328#define ZONELIST_HEADER"# NSD zone list\n# name pattern\n" "# NSD zone list\n# name pattern\n"
329static int
330comp_zonebucket(const void* a, const void* b)
331{
332 /* the line size is much smaller than max-int, and positive,
333 * so the subtraction works */
334 return *(const int*)b - *(const int*)a;
335}
336
337/* insert free entry into zonelist free buckets */
338static void
339zone_list_free_insert(struct nsd_options* opt, int linesize, off_t off)
340{
341 struct zonelist_free* e;
342 struct zonelist_bucket* b = (struct zonelist_bucket*)rbtree_search(
343 opt->zonefree, &linesize);
344 if(!b) {
345 b = region_alloc_zero(opt->region, sizeof(*b));
346 b->linesize = linesize;
347 b->node = *RBTREE_NULL&rbtree_null_node;
348 b->node.key = &b->linesize;
349 rbtree_insert(opt->zonefree, &b->node);
350 }
351 e = (struct zonelist_free*)region_alloc_zero(opt->region, sizeof(*e));
352 e->next = b->list;
353 b->list = e;
354 e->off = off;
355 opt->zonefree_number++;
356}
357
358struct zone_options*
359zone_list_zone_insert(struct nsd_options* opt, const char* nm,
360 const char* patnm, int linesize, off_t off)
361{
362 struct pattern_options* pat = pattern_options_find(opt, patnm);
363 struct zone_options* zone;
364 if(!pat) {
365 log_msg(LOG_ERR3, "pattern does not exist for zone %s "
366 "pattern %s", nm, patnm);
367 return NULL((void*)0);
368 }
369 zone = zone_options_create(opt->region);
370 zone->part_of_config = 0;
371 zone->name = region_strdup(opt->region, nm);
372 zone->linesize = linesize;
373 zone->off = off;
374 zone->pattern = pat;
375 if(!nsd_options_insert_zone(opt, zone)) {
376 log_msg(LOG_ERR3, "bad domain name or duplicate zone '%s' "
377 "pattern %s", nm, patnm);
378 region_recycle(opt->region, (void*)zone->name, strlen(nm)+1);
379 region_recycle(opt->region, zone, sizeof(*zone));
380 return NULL((void*)0);
381 }
382 return zone;
383}
384
385int
386parse_zone_list_file(struct nsd_options* opt)
387{
388 /* zonelist looks like this:
389 # name pattern
390 add example.com master
391 del example.net slave
392 add foo.bar.nl slave
393 add rutabaga.uk config
394 */
395 char hdr[64];
396 char buf[1024];
397
398 /* create empty data structures */
399 opt->zonefree = rbtree_create(opt->region, comp_zonebucket);
400 opt->zonelist = NULL((void*)0);
401 opt->zonefree_number = 0;
402 opt->zonelist_off = 0;
403
404 /* try to open the zonelist file, an empty or nonexist file is OK */
405 opt->zonelist = fopen(opt->zonelistfile, "r+");
406 if(!opt->zonelist) {
407 if(errno(*__errno()) == ENOENT2)
408 return 1; /* file does not exist, it is created later */
409 log_msg(LOG_ERR3, "could not open zone list %s: %s", opt->zonelistfile,
410 strerror(errno(*__errno())));
411 return 0;
412 }
413 /* read header */
414 hdr[strlen(ZONELIST_HEADER"# NSD zone list\n# name pattern\n")] = 0;
415 if(fread(hdr, 1, strlen(ZONELIST_HEADER"# NSD zone list\n# name pattern\n"), opt->zonelist) !=
416 strlen(ZONELIST_HEADER"# NSD zone list\n# name pattern\n") || strncmp(hdr, ZONELIST_HEADER"# NSD zone list\n# name pattern\n",
417 strlen(ZONELIST_HEADER"# NSD zone list\n# name pattern\n")) != 0) {
418 log_msg(LOG_ERR3, "zone list %s contains bad header\n", opt->zonelistfile);
419 fclose(opt->zonelist);
420 opt->zonelist = NULL((void*)0);
421 return 0;
422 }
423 buf[sizeof(buf)-1]=0;
424
425 /* read entries in file */
426 while(fgets(buf, sizeof(buf), opt->zonelist)) {
427 /* skip comments and empty lines */
428 if(buf[0] == 0 || buf[0] == '\n' || buf[0] == '#')
429 continue;
430 if(strncmp(buf, "add ", 4) == 0) {
431 int linesize = strlen(buf);
432 /* parse the 'add' line */
433 /* pick last space on the line, so that the domain
434 * name can have a space in it (but not the pattern)*/
435 char* space = strrchr(buf+4, ' ');
436 char* nm, *patnm;
437 if(!space) {
438 /* parse error */
439 log_msg(LOG_ERR3, "parse error in %s: '%s'",
440 opt->zonelistfile, buf);
441 continue;
442 }
443 nm = buf+4;
444 *space = 0;
445 patnm = space+1;
446 if(linesize && buf[linesize-1] == '\n')
447 buf[linesize-1] = 0;
448
449 /* store offset and line size for zone entry */
450 /* and create zone entry in zonetree */
451 (void)zone_list_zone_insert(opt, nm, patnm, linesize,
452 ftello(opt->zonelist)-linesize);
453 } else if(strncmp(buf, "del ", 4) == 0) {
454 /* store offset and line size for deleted entry */
455 int linesize = strlen(buf);
456 zone_list_free_insert(opt, linesize,
457 ftello(opt->zonelist)-linesize);
458 } else {
459 log_msg(LOG_WARNING4, "bad data in %s, '%s'", opt->zonelistfile,
460 buf);
461 }
462 }
463 /* store EOF offset */
464 opt->zonelist_off = ftello(opt->zonelist);
465 return 1;
466}
467
468void
469zone_options_delete(struct nsd_options* opt, struct zone_options* zone)
470{
471 rbtree_delete(opt->zone_options, zone->node.key);
472 region_recycle(opt->region, (void*)zone->node.key, dname_total_size(
473 (dname_type*)zone->node.key));
474 region_recycle(opt->region, zone, sizeof(*zone));
475}
476
477/* add a new zone to the zonelist */
478struct zone_options*
479zone_list_add(struct nsd_options* opt, const char* zname, const char* pname)
480{
481 int r;
482 struct zonelist_free* e;
483 struct zonelist_bucket* b;
484 int linesize = 6 + strlen(zname) + strlen(pname);
485 /* create zone entry */
486 struct zone_options* zone = zone_list_zone_insert(opt, zname, pname,
487 linesize, 0);
488 if(!zone)
489 return NULL((void*)0);
490
491 /* use free entry or append to file or create new file */
492 if(!opt->zonelist || opt->zonelist_off == 0) {
493 /* create new file */
494 if(opt->zonelist) fclose(opt->zonelist);
495 opt->zonelist = fopen(opt->zonelistfile, "w+");
496 if(!opt->zonelist) {
497 log_msg(LOG_ERR3, "could not create zone list %s: %s",
498 opt->zonelistfile, strerror(errno(*__errno())));
499 log_msg(LOG_ERR3, "zone %s could not be added", zname);
500 zone_options_delete(opt, zone);
501 return NULL((void*)0);
502 }
503 r = fprintf(opt->zonelist, ZONELIST_HEADER"# NSD zone list\n# name pattern\n");
504 if(r != strlen(ZONELIST_HEADER"# NSD zone list\n# name pattern\n")) {
505 if(r == -1)
506 log_msg(LOG_ERR3, "could not write to %s: %s",
507 opt->zonelistfile, strerror(errno(*__errno())));
508 else log_msg(LOG_ERR3, "partial write to %s: disk full",
509 opt->zonelistfile);
510 log_msg(LOG_ERR3, "zone %s could not be added", zname);
511 zone_options_delete(opt, zone);
512 return NULL((void*)0);
513 }
514 zone->off = ftello(opt->zonelist);
515 if(zone->off == -1)
516 log_msg(LOG_ERR3, "ftello(%s): %s", opt->zonelistfile, strerror(errno(*__errno())));
517 r = fprintf(opt->zonelist, "add %s %s\n", zname, pname);
518 if(r != zone->linesize) {
519 if(r == -1)
520 log_msg(LOG_ERR3, "could not write to %s: %s",
521 opt->zonelistfile, strerror(errno(*__errno())));
522 else log_msg(LOG_ERR3, "partial write to %s: disk full",
523 opt->zonelistfile);
524 log_msg(LOG_ERR3, "zone %s could not be added", zname);
525 zone_options_delete(opt, zone);
526 return NULL((void*)0);
527 }
528 opt->zonelist_off = ftello(opt->zonelist);
529 if(opt->zonelist_off == -1)
530 log_msg(LOG_ERR3, "ftello(%s): %s", opt->zonelistfile, strerror(errno(*__errno())));
531 if(fflush(opt->zonelist) != 0) {
532 log_msg(LOG_ERR3, "fflush %s: %s", opt->zonelistfile, strerror(errno(*__errno())));
533 }
534 return zone;
535 }
536 b = (struct zonelist_bucket*)rbtree_search(opt->zonefree,
537 &zone->linesize);
538 if(!b || b->list == NULL((void*)0)) {
539 /* no empty place, append to file */
540 zone->off = opt->zonelist_off;
541 if(fseeko(opt->zonelist, zone->off, SEEK_SET0) == -1) {
542 log_msg(LOG_ERR3, "fseeko(%s): %s", opt->zonelistfile, strerror(errno(*__errno())));
543 log_msg(LOG_ERR3, "zone %s could not be added", zname);
544 zone_options_delete(opt, zone);
545 return NULL((void*)0);
546 }
547 r = fprintf(opt->zonelist, "add %s %s\n", zname, pname);
548 if(r != zone->linesize) {
549 if(r == -1)
550 log_msg(LOG_ERR3, "could not write to %s: %s",
551 opt->zonelistfile, strerror(errno(*__errno())));
552 else log_msg(LOG_ERR3, "partial write to %s: disk full",
553 opt->zonelistfile);
554 log_msg(LOG_ERR3, "zone %s could not be added", zname);
555 zone_options_delete(opt, zone);
556 return NULL((void*)0);
557 }
558 opt->zonelist_off += linesize;
559 if(fflush(opt->zonelist) != 0) {
560 log_msg(LOG_ERR3, "fflush %s: %s", opt->zonelistfile, strerror(errno(*__errno())));
561 }
562 return zone;
563 }
564 /* reuse empty spot */
565 e = b->list;
566 zone->off = e->off;
567 if(fseeko(opt->zonelist, zone->off, SEEK_SET0) == -1) {
568 log_msg(LOG_ERR3, "fseeko(%s): %s", opt->zonelistfile, strerror(errno(*__errno())));
569 log_msg(LOG_ERR3, "zone %s could not be added", zname);
570 zone_options_delete(opt, zone);
571 return NULL((void*)0);
572 }
573 r = fprintf(opt->zonelist, "add %s %s\n", zname, pname);
574 if(r != zone->linesize) {
575 if(r == -1)
576 log_msg(LOG_ERR3, "could not write to %s: %s",
577 opt->zonelistfile, strerror(errno(*__errno())));
578 else log_msg(LOG_ERR3, "partial write to %s: disk full",
579 opt->zonelistfile);
580 log_msg(LOG_ERR3, "zone %s could not be added", zname);
581 zone_options_delete(opt, zone);
582 return NULL((void*)0);
583 }
584 if(fflush(opt->zonelist) != 0) {
585 log_msg(LOG_ERR3, "fflush %s: %s", opt->zonelistfile, strerror(errno(*__errno())));
586 }
587
588 /* snip off and recycle element */
589 b->list = e->next;
590 region_recycle(opt->region, e, sizeof(*e));
591 if(b->list == NULL((void*)0)) {
592 rbtree_delete(opt->zonefree, &b->linesize);
593 region_recycle(opt->region, b, sizeof(*b));
594 }
595 opt->zonefree_number--;
596 return zone;
597}
598
599/* remove a zone on the zonelist */
600void
601zone_list_del(struct nsd_options* opt, struct zone_options* zone)
602{
603 /* put its space onto the free entry */
604 if(fseeko(opt->zonelist, zone->off, SEEK_SET0) == -1) {
605 log_msg(LOG_ERR3, "fseeko(%s): %s", opt->zonelistfile, strerror(errno(*__errno())));
606 return;
607 }
608 fprintf(opt->zonelist, "del");
609 zone_list_free_insert(opt, zone->linesize, zone->off);
610
611 /* remove zone_options */
612 zone_options_delete(opt, zone);
613
614 /* see if we need to compact: it is going to halve the zonelist */
615 if(opt->zonefree_number > opt->zone_options->count) {
616 zone_list_compact(opt);
617 } else {
618 if(fflush(opt->zonelist) != 0) {
619 log_msg(LOG_ERR3, "fflush %s: %s", opt->zonelistfile, strerror(errno(*__errno())));
620 }
621 }
622}
623/* postorder delete of zonelist free space tree */
624static void
625delbucket(region_type* region, struct zonelist_bucket* b)
626{
627 struct zonelist_free* e, *f;
628 if(!b || (rbnode_type*)b==RBTREE_NULL&rbtree_null_node)
629 return;
630 delbucket(region, (struct zonelist_bucket*)b->node.left);
631 delbucket(region, (struct zonelist_bucket*)b->node.right);
632 e = b->list;
633 while(e) {
634 f = e->next;
635 region_recycle(region, e, sizeof(*e));
636 e = f;
637 }
638 region_recycle(region, b, sizeof(*b));
639}
640
641/* compact zonelist file */
642void
643zone_list_compact(struct nsd_options* opt)
644{
645 char outname[1024];
646 FILE* out;
647 struct zone_options* zone;
648 off_t off;
649 int r;
650 snprintf(outname, sizeof(outname), "%s~", opt->zonelistfile);
651 /* useful, when : count-of-free > count-of-used */
652 /* write zonelist to zonelist~ */
653 out = fopen(outname, "w+");
654 if(!out) {
655 log_msg(LOG_ERR3, "could not open %s: %s", outname, strerror(errno(*__errno())));
656 return;
657 }
658 r = fprintf(out, ZONELIST_HEADER"# NSD zone list\n# name pattern\n");
659 if(r == -1) {
660 log_msg(LOG_ERR3, "write %s failed: %s", outname,
661 strerror(errno(*__errno())));
662 fclose(out);
663 return;
664 } else if(r != strlen(ZONELIST_HEADER"# NSD zone list\n# name pattern\n")) {
665 log_msg(LOG_ERR3, "write %s was partial: disk full",
666 outname);
667 fclose(out);
668 return;
669 }
670 off = ftello(out);
671 if(off == -1) {
672 log_msg(LOG_ERR3, "ftello(%s): %s", outname, strerror(errno(*__errno())));
673 fclose(out);
674 return;
675 }
676 RBTREE_FOR(zone, struct zone_options*, opt->zone_options)for(zone=(struct zone_options*)rbtree_first(opt->zone_options
); (rbnode_type*)zone != &rbtree_null_node; zone = (struct
zone_options*)rbtree_next((rbnode_type*)zone))
{
677 if(zone->part_of_config)
678 continue;
679 r = fprintf(out, "add %s %s\n", zone->name,
680 zone->pattern->pname);
681 if(r < 0) {
682 log_msg(LOG_ERR3, "write %s failed: %s", outname,
683 strerror(errno(*__errno())));
684 fclose(out);
685 return;
686 } else if(r != zone->linesize) {
687 log_msg(LOG_ERR3, "write %s was partial: disk full",
688 outname);
689 fclose(out);
690 return;
691 }
692 }
693 if(fflush(out) != 0) {
694 log_msg(LOG_ERR3, "fflush %s: %s", outname, strerror(errno(*__errno())));
695 }
696
697 /* rename zonelist~ onto zonelist */
698 if(rename(outname, opt->zonelistfile) == -1) {
699 log_msg(LOG_ERR3, "rename(%s to %s) failed: %s",
700 outname, opt->zonelistfile, strerror(errno(*__errno())));
701 fclose(out);
702 return;
703 }
704 fclose(opt->zonelist);
705 /* set offsets */
706 RBTREE_FOR(zone, struct zone_options*, opt->zone_options)for(zone=(struct zone_options*)rbtree_first(opt->zone_options
); (rbnode_type*)zone != &rbtree_null_node; zone = (struct
zone_options*)rbtree_next((rbnode_type*)zone))
{
707 if(zone->part_of_config)
708 continue;
709 zone->off = off;
710 off += zone->linesize;
711 }
712 /* empty the free tree */
713 delbucket(opt->region, (struct zonelist_bucket*)opt->zonefree->root);
714 opt->zonefree->root = RBTREE_NULL&rbtree_null_node;
715 opt->zonefree->count = 0;
716 opt->zonefree_number = 0;
717 /* finish */
718 opt->zonelist = out;
719 opt->zonelist_off = off;
720}
721
722/* close zonelist file */
723void
724zone_list_close(struct nsd_options* opt)
725{
726 if(opt->zonelist) {
727 fclose(opt->zonelist);
728 opt->zonelist = NULL((void*)0);
729 }
730}
731
732static void
733c_error_va_list_pos(int showpos, const char* fmt, va_list args)
734{
735 char* at = NULL((void*)0);
736 cfg_parser->errors++;
737 if(showpos && c_text && c_text[0]!=0) {
738 at = c_text;
739 }
740 if(cfg_parser->err) {
741 char m[MAXSYSLOGMSGLEN512];
742 snprintf(m, sizeof(m), "%s:%d: ", cfg_parser->filename,
743 cfg_parser->line);
744 (*cfg_parser->err)(cfg_parser->err_arg, m);
745 if(at) {
746 snprintf(m, sizeof(m), "at '%s': ", at);
747 (*cfg_parser->err)(cfg_parser->err_arg, m);
748 }
749 (*cfg_parser->err)(cfg_parser->err_arg, "error: ");
750 vsnprintf(m, sizeof(m), fmt, args);
751 (*cfg_parser->err)(cfg_parser->err_arg, m);
752 (*cfg_parser->err)(cfg_parser->err_arg, "\n");
753 return;
754 }
755 fprintf(stderr(&__sF[2]), "%s:%d: ", cfg_parser->filename, cfg_parser->line);
756 if(at) fprintf(stderr(&__sF[2]), "at '%s': ", at);
757 fprintf(stderr(&__sF[2]), "error: ");
758 vfprintf(stderr(&__sF[2]), fmt, args);
759 fprintf(stderr(&__sF[2]), "\n");
760}
761
762void
763c_error(const char *fmt, ...)
764{
765 va_list ap;
766 int showpos = 0;
767
768 if (strcmp(fmt, "syntax error") == 0 || strcmp(fmt, "parse error") == 0) {
769 showpos = 1;
770 }
771
772 va_start(ap, fmt)__builtin_va_start(ap, fmt);
773 c_error_va_list_pos(showpos, fmt, ap);
774 va_end(ap)__builtin_va_end(ap);
775}
776
777int
778c_wrap(void)
779{
780 return 1;
781}
782
783struct zone_options*
784zone_options_create(region_type* region)
785{
786 struct zone_options* zone;
787 zone = (struct zone_options*)region_alloc(region, sizeof(
788 struct zone_options));
789 zone->node = *RBTREE_NULL&rbtree_null_node;
790 zone->name = 0;
791 zone->pattern = 0;
792 zone->part_of_config = 0;
793 return zone;
794}
795
796/* true is booleans are the same truth value */
797#define booleq(x,y)( ((x) && (y)) || (!(x) && !(y)) ) ( ((x) && (y)) || (!(x) && !(y)) )
798
799/* true is min_expire_time_expr has either an equal known value
800 * or none of these known values but booleanally equal
801 */
802#define expire_expr_eq(x,y)( ( (x) == 2 && (y) == 2 ) || ( (x) != 2 && (
y) != 2 && ( (((x)) && ((y))) || (!((x)) &&
!((y))) )))
( ( (x) == REFRESHPLUSRETRYPLUS12 \
803 && (y) == REFRESHPLUSRETRYPLUS12 ) \
804 || ( (x) != REFRESHPLUSRETRYPLUS12 \
805 && (y) != REFRESHPLUSRETRYPLUS12 \
806 && booleq((x), (y))( (((x)) && ((y))) || (!((x)) && !((y))) )))
807
808
809int
810acl_equal(struct acl_options* p, struct acl_options* q)
811{
812 if(!booleq(p->use_axfr_only, q->use_axfr_only)( ((p->use_axfr_only) && (q->use_axfr_only)) ||
(!(p->use_axfr_only) && !(q->use_axfr_only)) )
) return 0;
813 if(!booleq(p->allow_udp, q->allow_udp)( ((p->allow_udp) && (q->allow_udp)) || (!(p->
allow_udp) && !(q->allow_udp)) )
) return 0;
814 if(strcmp(p->ip_address_spec, q->ip_address_spec)!=0) return 0;
815 /* the ip6, port, addr, mask, type: are derived from the ip_address_spec */
816 if(!booleq(p->nokey, q->nokey)( ((p->nokey) && (q->nokey)) || (!(p->nokey)
&& !(q->nokey)) )
) return 0;
817 if(!booleq(p->blocked, q->blocked)( ((p->blocked) && (q->blocked)) || (!(p->blocked
) && !(q->blocked)) )
) return 0;
818 if(p->key_name && q->key_name) {
819 if(strcmp(p->key_name, q->key_name)!=0) return 0;
820 } else if(p->key_name && !q->key_name) return 0;
821 else if(!p->key_name && q->key_name) return 0;
822 /* key_options is derived from key_name */
823 if(p->tls_auth_name && q->tls_auth_name) {
824 if(strcmp(p->tls_auth_name, q->tls_auth_name)!=0) return 0;
825 } else if(p->tls_auth_name && !q->tls_auth_name) return 0;
826 else if(!p->tls_auth_name && q->tls_auth_name) return 0;
827 /* tls_auth_options is derived from tls_auth_name */
828 return 1;
829}
830
831int
832acl_list_equal(struct acl_options* p, struct acl_options* q)
833{
834 /* must be same and in same order */
835 while(p && q) {
836 if(!acl_equal(p, q))
837 return 0;
838 p = p->next;
839 q = q->next;
840 }
841 if(!p && !q) return 1;
842 /* different lengths */
843 return 0;
844}
845
846struct pattern_options*
847pattern_options_create(region_type* region)
848{
849 struct pattern_options* p;
850 p = (struct pattern_options*)region_alloc(region, sizeof(
851 struct pattern_options));
852 p->node = *RBTREE_NULL&rbtree_null_node;
853 p->pname = 0;
854 p->zonefile = 0;
855 p->zonestats = 0;
856 p->allow_notify = 0;
857 p->request_xfr = 0;
858 p->size_limit_xfr = 0;
859 p->notify = 0;
860 p->provide_xfr = 0;
861 p->allow_query = 0;
862 p->outgoing_interface = 0;
863 p->notify_retry = 5;
864 p->notify_retry_is_default = 1;
865 p->allow_axfr_fallback = 1;
866 p->allow_axfr_fallback_is_default = 1;
867 p->implicit = 0;
868 p->xfrd_flags = 0;
869 p->max_refresh_time = 2419200; /* 4 weeks */
870 p->max_refresh_time_is_default = 1;
871 p->min_refresh_time = 0;
872 p->min_refresh_time_is_default = 1;
873 p->max_retry_time = 1209600; /* 2 weeks */
874 p->max_retry_time_is_default = 1;
875 p->min_retry_time = 0;
876 p->min_retry_time_is_default = 1;
877 p->min_expire_time = 0;
878 p->min_expire_time_expr = EXPIRE_TIME_IS_DEFAULT1;
879#ifdef RATELIMIT
880 p->rrl_whitelist = 0;
881#endif
882 p->multi_master_check = 0;
883 return p;
884}
885
886static void
887acl_delete(region_type* region, struct acl_options* acl)
888{
889 if(acl->ip_address_spec)
890 region_recycle(region, (void*)acl->ip_address_spec,
891 strlen(acl->ip_address_spec)+1);
892 if(acl->key_name)
893 region_recycle(region, (void*)acl->key_name,
894 strlen(acl->key_name)+1);
895 if(acl->tls_auth_name)
896 region_recycle(region, (void*)acl->tls_auth_name,
897 strlen(acl->tls_auth_name)+1);
898 /* key_options is a convenience pointer, not owned by the acl */
899 region_recycle(region, acl, sizeof(*acl));
900}
901
902static void
903acl_list_delete(region_type* region, struct acl_options* list)
904{
905 struct acl_options* n;
906 while(list) {
907 n = list->next;
908 acl_delete(region, list);
909 list = n;
910 }
911}
912
913void
914pattern_options_remove(struct nsd_options* opt, const char* name)
915{
916 struct pattern_options* p = (struct pattern_options*)rbtree_delete(
917 opt->patterns, name);
918 /* delete p and its contents */
919 if (!p)
920 return;
921 if(p->pname)
922 region_recycle(opt->region, (void*)p->pname,
923 strlen(p->pname)+1);
924 if(p->zonefile)
925 region_recycle(opt->region, (void*)p->zonefile,
926 strlen(p->zonefile)+1);
927 if(p->zonestats)
928 region_recycle(opt->region, (void*)p->zonestats,
929 strlen(p->zonestats)+1);
930 acl_list_delete(opt->region, p->allow_notify);
931 acl_list_delete(opt->region, p->request_xfr);
932 acl_list_delete(opt->region, p->notify);
933 acl_list_delete(opt->region, p->provide_xfr);
934 acl_list_delete(opt->region, p->allow_query);
935 acl_list_delete(opt->region, p->outgoing_interface);
936
937 region_recycle(opt->region, p, sizeof(struct pattern_options));
938}
939
940static struct acl_options*
941copy_acl(region_type* region, struct acl_options* a)
942{
943 struct acl_options* b;
944 if(!a) return NULL((void*)0);
945 b = (struct acl_options*)region_alloc(region, sizeof(*b));
946 /* copy the whole lot */
947 *b = *a;
948 /* fix the pointers */
949 if(a->ip_address_spec)
950 b->ip_address_spec = region_strdup(region, a->ip_address_spec);
951 if(a->key_name)
952 b->key_name = region_strdup(region, a->key_name);
953 if(a->tls_auth_name)
954 b->tls_auth_name = region_strdup(region, a->tls_auth_name);
955 b->next = NULL((void*)0);
956 b->key_options = NULL((void*)0);
957 b->tls_auth_options = NULL((void*)0);
958 return b;
959}
960
961static struct acl_options*
962copy_acl_list(struct nsd_options* opt, struct acl_options* a)
963{
964 struct acl_options* b, *blast = NULL((void*)0), *blist = NULL((void*)0);
965 while(a) {
966 b = copy_acl(opt->region, a);
967 /* fixup key_options */
968 if(b->key_name)
969 b->key_options = key_options_find(opt, b->key_name);
970 else b->key_options = NULL((void*)0);
971 /* fixup tls_auth_options */
972 if(b->tls_auth_name)
973 b->tls_auth_options = tls_auth_options_find(opt, b->tls_auth_name);
974 else b->tls_auth_options = NULL((void*)0);
975
976 /* link as last into list */
977 b->next = NULL((void*)0);
978 if(!blist) blist = b;
979 else blast->next = b;
980 blast = b;
981
982 a = a->next;
983 }
984 return blist;
985}
986
987static void
988copy_changed_acl(struct nsd_options* opt, struct acl_options** orig,
989 struct acl_options* anew)
990{
991 if(!acl_list_equal(*orig, anew)) {
992 acl_list_delete(opt->region, *orig);
993 *orig = copy_acl_list(opt, anew);
994 }
995}
996
997static void
998copy_pat_fixed(region_type* region, struct pattern_options* orig,
999 struct pattern_options* p)
1000{
1001 orig->allow_axfr_fallback = p->allow_axfr_fallback;
1002 orig->allow_axfr_fallback_is_default =
1003 p->allow_axfr_fallback_is_default;
1004 orig->notify_retry = p->notify_retry;
1005 orig->notify_retry_is_default = p->notify_retry_is_default;
1006 orig->implicit = p->implicit;
1007 if(p->zonefile)
1008 orig->zonefile = region_strdup(region, p->zonefile);
1009 else orig->zonefile = NULL((void*)0);
1010 if(p->zonestats)
1011 orig->zonestats = region_strdup(region, p->zonestats);
1012 else orig->zonestats = NULL((void*)0);
1013 orig->max_refresh_time = p->max_refresh_time;
1014 orig->max_refresh_time_is_default = p->max_refresh_time_is_default;
1015 orig->min_refresh_time = p->min_refresh_time;
1016 orig->min_refresh_time_is_default = p->min_refresh_time_is_default;
1017 orig->max_retry_time = p->max_retry_time;
1018 orig->max_retry_time_is_default = p->max_retry_time_is_default;
1019 orig->min_retry_time = p->min_retry_time;
1020 orig->min_retry_time_is_default = p->min_retry_time_is_default;
1021 orig->min_expire_time = p->min_expire_time;
1022 orig->min_expire_time_expr = p->min_expire_time_expr;
1023#ifdef RATELIMIT
1024 orig->rrl_whitelist = p->rrl_whitelist;
1025#endif
1026 orig->multi_master_check = p->multi_master_check;
1027}
1028
1029void
1030pattern_options_add_modify(struct nsd_options* opt, struct pattern_options* p)
1031{
1032 struct pattern_options* orig = pattern_options_find(opt, p->pname);
1033 if(!orig) {
1034 /* needs to be copied to opt region */
1035 orig = pattern_options_create(opt->region);
1036 orig->pname = region_strdup(opt->region, p->pname);
1037 copy_pat_fixed(opt->region, orig, p);
1038 orig->allow_notify = copy_acl_list(opt, p->allow_notify);
1039 orig->request_xfr = copy_acl_list(opt, p->request_xfr);
1040 orig->notify = copy_acl_list(opt, p->notify);
1041 orig->provide_xfr = copy_acl_list(opt, p->provide_xfr);
1042 orig->allow_query = copy_acl_list(opt, p->allow_query);
1043 orig->outgoing_interface = copy_acl_list(opt,
1044 p->outgoing_interface);
1045 nsd_options_insert_pattern(opt, orig);
1046 } else {
1047 /* modify in place so pointers stay valid (and copy
1048 into region). Do not touch unchanged acls. */
1049 if(orig->zonefile)
1050 region_recycle(opt->region, (char*)orig->zonefile,
1051 strlen(orig->zonefile)+1);
1052 if(orig->zonestats)
1053 region_recycle(opt->region, (char*)orig->zonestats,
1054 strlen(orig->zonestats)+1);
1055 copy_pat_fixed(opt->region, orig, p);
1056 copy_changed_acl(opt, &orig->allow_notify, p->allow_notify);
1057 copy_changed_acl(opt, &orig->request_xfr, p->request_xfr);
1058 copy_changed_acl(opt, &orig->notify, p->notify);
1059 copy_changed_acl(opt, &orig->provide_xfr, p->provide_xfr);
1060 copy_changed_acl(opt, &orig->allow_query, p->allow_query);
1061 copy_changed_acl(opt, &orig->outgoing_interface,
1062 p->outgoing_interface);
1063 }
1064}
1065
1066struct pattern_options*
1067pattern_options_find(struct nsd_options* opt, const char* name)
1068{
1069 return (struct pattern_options*)rbtree_search(opt->patterns, name);
1070}
1071
1072int
1073pattern_options_equal(struct pattern_options* p, struct pattern_options* q)
1074{
1075 if(strcmp(p->pname, q->pname) != 0) return 0;
1076 if(!p->zonefile && q->zonefile) return 0;
1077 else if(p->zonefile && !q->zonefile) return 0;
1078 else if(p->zonefile && q->zonefile) {
1079 if(strcmp(p->zonefile, q->zonefile) != 0) return 0;
1080 }
1081 if(!p->zonestats && q->zonestats) return 0;
1082 else if(p->zonestats && !q->zonestats) return 0;
1083 else if(p->zonestats && q->zonestats) {
1084 if(strcmp(p->zonestats, q->zonestats) != 0) return 0;
1085 }
1086 if(!booleq(p->allow_axfr_fallback, q->allow_axfr_fallback)( ((p->allow_axfr_fallback) && (q->allow_axfr_fallback
)) || (!(p->allow_axfr_fallback) && !(q->allow_axfr_fallback
)) )
) return 0;
1087 if(!booleq(p->allow_axfr_fallback_is_default,( ((p->allow_axfr_fallback_is_default) && (q->allow_axfr_fallback_is_default
)) || (!(p->allow_axfr_fallback_is_default) && !(q
->allow_axfr_fallback_is_default)) )
1088 q->allow_axfr_fallback_is_default)( ((p->allow_axfr_fallback_is_default) && (q->allow_axfr_fallback_is_default
)) || (!(p->allow_axfr_fallback_is_default) && !(q
->allow_axfr_fallback_is_default)) )
) return 0;
1089 if(p->notify_retry != q->notify_retry) return 0;
1090 if(!booleq(p->notify_retry_is_default,( ((p->notify_retry_is_default) && (q->notify_retry_is_default
)) || (!(p->notify_retry_is_default) && !(q->notify_retry_is_default
)) )
1091 q->notify_retry_is_default)( ((p->notify_retry_is_default) && (q->notify_retry_is_default
)) || (!(p->notify_retry_is_default) && !(q->notify_retry_is_default
)) )
) return 0;
1092 if(!booleq(p->implicit, q->implicit)( ((p->implicit) && (q->implicit)) || (!(p->
implicit) && !(q->implicit)) )
) return 0;
1093 if(!acl_list_equal(p->allow_notify, q->allow_notify)) return 0;
1094 if(!acl_list_equal(p->request_xfr, q->request_xfr)) return 0;
1095 if(!acl_list_equal(p->notify, q->notify)) return 0;
1096 if(!acl_list_equal(p->provide_xfr, q->provide_xfr)) return 0;
1097 if(!acl_list_equal(p->allow_query, q->allow_query)) return 0;
1098 if(!acl_list_equal(p->outgoing_interface, q->outgoing_interface))
1099 return 0;
1100 if(p->max_refresh_time != q->max_refresh_time) return 0;
1101 if(!booleq(p->max_refresh_time_is_default,( ((p->max_refresh_time_is_default) && (q->max_refresh_time_is_default
)) || (!(p->max_refresh_time_is_default) && !(q->
max_refresh_time_is_default)) )
1102 q->max_refresh_time_is_default)( ((p->max_refresh_time_is_default) && (q->max_refresh_time_is_default
)) || (!(p->max_refresh_time_is_default) && !(q->
max_refresh_time_is_default)) )
) return 0;
1103 if(p->min_refresh_time != q->min_refresh_time) return 0;
1104 if(!booleq(p->min_refresh_time_is_default,( ((p->min_refresh_time_is_default) && (q->min_refresh_time_is_default
)) || (!(p->min_refresh_time_is_default) && !(q->
min_refresh_time_is_default)) )
1105 q->min_refresh_time_is_default)( ((p->min_refresh_time_is_default) && (q->min_refresh_time_is_default
)) || (!(p->min_refresh_time_is_default) && !(q->
min_refresh_time_is_default)) )
) return 0;
1106 if(p->max_retry_time != q->max_retry_time) return 0;
1107 if(!booleq(p->max_retry_time_is_default,( ((p->max_retry_time_is_default) && (q->max_retry_time_is_default
)) || (!(p->max_retry_time_is_default) && !(q->
max_retry_time_is_default)) )
1108 q->max_retry_time_is_default)( ((p->max_retry_time_is_default) && (q->max_retry_time_is_default
)) || (!(p->max_retry_time_is_default) && !(q->
max_retry_time_is_default)) )
) return 0;
1109 if(p->min_retry_time != q->min_retry_time) return 0;
1110 if(!booleq(p->min_retry_time_is_default,( ((p->min_retry_time_is_default) && (q->min_retry_time_is_default
)) || (!(p->min_retry_time_is_default) && !(q->
min_retry_time_is_default)) )
1111 q->min_retry_time_is_default)( ((p->min_retry_time_is_default) && (q->min_retry_time_is_default
)) || (!(p->min_retry_time_is_default) && !(q->
min_retry_time_is_default)) )
) return 0;
1112 if(p->min_expire_time != q->min_expire_time) return 0;
1113 if(!expire_expr_eq(p->min_expire_time_expr,( ( (p->min_expire_time_expr) == 2 && (q->min_expire_time_expr
) == 2 ) || ( (p->min_expire_time_expr) != 2 && (q
->min_expire_time_expr) != 2 && ( (((p->min_expire_time_expr
)) && ((q->min_expire_time_expr))) || (!((p->min_expire_time_expr
)) && !((q->min_expire_time_expr))) )))
1114 q->min_expire_time_expr)( ( (p->min_expire_time_expr) == 2 && (q->min_expire_time_expr
) == 2 ) || ( (p->min_expire_time_expr) != 2 && (q
->min_expire_time_expr) != 2 && ( (((p->min_expire_time_expr
)) && ((q->min_expire_time_expr))) || (!((p->min_expire_time_expr
)) && !((q->min_expire_time_expr))) )))
) return 0;
1115#ifdef RATELIMIT
1116 if(p->rrl_whitelist != q->rrl_whitelist) return 0;
1117#endif
1118 if(!booleq(p->multi_master_check,q->multi_master_check)( ((p->multi_master_check) && (q->multi_master_check
)) || (!(p->multi_master_check) && !(q->multi_master_check
)) )
) return 0;
1119 if(p->size_limit_xfr != q->size_limit_xfr) return 0;
1120 return 1;
1121}
1122
1123static void
1124marshal_u8(struct buffer* b, uint8_t v)
1125{
1126 buffer_reserve(b, 1);
1127 buffer_write_u8(b, v);
1128}
1129
1130static uint8_t
1131unmarshal_u8(struct buffer* b)
1132{
1133 return buffer_read_u8(b);
1134}
1135
1136static void
1137marshal_u64(struct buffer* b, uint64_t v)
1138{
1139 buffer_reserve(b, 8);
1140 buffer_write_u64(b, v);
1141}
1142
1143static uint64_t
1144unmarshal_u64(struct buffer* b)
1145{
1146 return buffer_read_u64(b);
1147}
1148
1149#ifdef RATELIMIT
1150static void
1151marshal_u16(struct buffer* b, uint16_t v)
1152{
1153 buffer_reserve(b, 2);
1154 buffer_write_u16(b, v);
1155}
1156#endif
1157
1158#ifdef RATELIMIT
1159static uint16_t
1160unmarshal_u16(struct buffer* b)
1161{
1162 return buffer_read_u16(b);
1163}
1164#endif
1165
1166static void
1167marshal_u32(struct buffer* b, uint32_t v)
1168{
1169 buffer_reserve(b, 4);
1170 buffer_write_u32(b, v);
1171}
1172
1173static uint32_t
1174unmarshal_u32(struct buffer* b)
1175{
1176 return buffer_read_u32(b);
1177}
1178
1179static void
1180marshal_str(struct buffer* b, const char* s)
1181{
1182 if(!s) marshal_u8(b, 0);
1183 else {
1184 size_t len = strlen(s);
1185 marshal_u8(b, 1);
1186 buffer_reserve(b, len+1);
1187 buffer_write(b, s, len+1);
1188 }
1189}
1190
1191static char*
1192unmarshal_str(region_type* r, struct buffer* b)
1193{
1194 uint8_t nonnull = unmarshal_u8(b);
1195 if(nonnull) {
1196 char* result = region_strdup(r, (char*)buffer_current(b));
1197 size_t len = strlen((char*)buffer_current(b));
1198 buffer_skip(b, len+1);
1199 return result;
1200 } else return NULL((void*)0);
1201}
1202
1203static void
1204marshal_acl(struct buffer* b, struct acl_options* acl)
1205{
1206 buffer_reserve(b, sizeof(*acl));
1207 buffer_write(b, acl, sizeof(*acl));
1208 marshal_str(b, acl->ip_address_spec);
1209 marshal_str(b, acl->key_name);
1210 marshal_str(b, acl->tls_auth_name);
1211}
1212
1213static struct acl_options*
1214unmarshal_acl(region_type* r, struct buffer* b)
1215{
1216 struct acl_options* acl = (struct acl_options*)region_alloc(r,
1217 sizeof(*acl));
1218 buffer_read(b, acl, sizeof(*acl));
1219 acl->next = NULL((void*)0);
1220 acl->key_options = NULL((void*)0);
1221 acl->tls_auth_options = NULL((void*)0);
1222 acl->ip_address_spec = unmarshal_str(r, b);
1223 acl->key_name = unmarshal_str(r, b);
1224 acl->tls_auth_name = unmarshal_str(r, b);
1225 return acl;
1226}
1227
1228static void
1229marshal_acl_list(struct buffer* b, struct acl_options* list)
1230{
1231 while(list) {
1232 marshal_u8(b, 1); /* is there a next one marker */
1233 marshal_acl(b, list);
1234 list = list->next;
1235 }
1236 marshal_u8(b, 0); /* end of list marker */
1237}
1238
1239static struct acl_options*
1240unmarshal_acl_list(region_type* r, struct buffer* b)
1241{
1242 struct acl_options* a, *last=NULL((void*)0), *list=NULL((void*)0);
1243 while(unmarshal_u8(b)) {
1244 a = unmarshal_acl(r, b);
1245 /* link in */
1246 a->next = NULL((void*)0);
1247 if(!list) list = a;
1248 else last->next = a;
1249 last = a;
1250 }
1251 return list;
1252}
1253
1254void
1255pattern_options_marshal(struct buffer* b, struct pattern_options* p)
1256{
1257 marshal_str(b, p->pname);
1258 marshal_str(b, p->zonefile);
1259 marshal_str(b, p->zonestats);
1260#ifdef RATELIMIT
1261 marshal_u16(b, p->rrl_whitelist);
1262#endif
1263 marshal_u8(b, p->allow_axfr_fallback);
1264 marshal_u8(b, p->allow_axfr_fallback_is_default);
1265 marshal_u8(b, p->notify_retry);
1266 marshal_u8(b, p->notify_retry_is_default);
1267 marshal_u8(b, p->implicit);
1268 marshal_u64(b, p->size_limit_xfr);
1269 marshal_acl_list(b, p->allow_notify);
1270 marshal_acl_list(b, p->request_xfr);
1271 marshal_acl_list(b, p->notify);
1272 marshal_acl_list(b, p->provide_xfr);
1273 marshal_acl_list(b, p->allow_query);
1274 marshal_acl_list(b, p->outgoing_interface);
1275 marshal_u32(b, p->max_refresh_time);
1276 marshal_u8(b, p->max_refresh_time_is_default);
1277 marshal_u32(b, p->min_refresh_time);
1278 marshal_u8(b, p->min_refresh_time_is_default);
1279 marshal_u32(b, p->max_retry_time);
1280 marshal_u8(b, p->max_retry_time_is_default);
1281 marshal_u32(b, p->min_retry_time);
1282 marshal_u8(b, p->min_retry_time_is_default);
1283 marshal_u32(b, p->min_expire_time);
1284 marshal_u8(b, p->min_expire_time_expr);
1285 marshal_u8(b, p->multi_master_check);
1286}
1287
1288struct pattern_options*
1289pattern_options_unmarshal(region_type* r, struct buffer* b)
1290{
1291 struct pattern_options* p = pattern_options_create(r);
1292 p->pname = unmarshal_str(r, b);
1293 p->zonefile = unmarshal_str(r, b);
1294 p->zonestats = unmarshal_str(r, b);
1295#ifdef RATELIMIT
1296 p->rrl_whitelist = unmarshal_u16(b);
1297#endif
1298 p->allow_axfr_fallback = unmarshal_u8(b);
1299 p->allow_axfr_fallback_is_default = unmarshal_u8(b);
1300 p->notify_retry = unmarshal_u8(b);
1301 p->notify_retry_is_default = unmarshal_u8(b);
1302 p->implicit = unmarshal_u8(b);
1303 p->size_limit_xfr = unmarshal_u64(b);
1304 p->allow_notify = unmarshal_acl_list(r, b);
1305 p->request_xfr = unmarshal_acl_list(r, b);
1306 p->notify = unmarshal_acl_list(r, b);
1307 p->provide_xfr = unmarshal_acl_list(r, b);
1308 p->allow_query = unmarshal_acl_list(r, b);
1309 p->outgoing_interface = unmarshal_acl_list(r, b);
1310 p->max_refresh_time = unmarshal_u32(b);
1311 p->max_refresh_time_is_default = unmarshal_u8(b);
1312 p->min_refresh_time = unmarshal_u32(b);
1313 p->min_refresh_time_is_default = unmarshal_u8(b);
1314 p->max_retry_time = unmarshal_u32(b);
1315 p->max_retry_time_is_default = unmarshal_u8(b);
1316 p->min_retry_time = unmarshal_u32(b);
1317 p->min_retry_time_is_default = unmarshal_u8(b);
1318 p->min_expire_time = unmarshal_u32(b);
1319 p->min_expire_time_expr = unmarshal_u8(b);
1320 p->multi_master_check = unmarshal_u8(b);
1321 return p;
1322}
1323
1324struct key_options*
1325key_options_create(region_type* region)
1326{
1327 struct key_options* key;
1328 key = (struct key_options*)region_alloc_zero(region,
1329 sizeof(struct key_options));
1330 return key;
1331}
1332
1333struct tls_auth_options*
1334tls_auth_options_create(region_type* region)
1335{
1336 struct tls_auth_options* tls_auth_options;
1337 tls_auth_options = (struct tls_auth_options*)region_alloc_zero(region, sizeof(struct tls_auth_options));
1338 return tls_auth_options;
1339}
1340
1341void
1342key_options_insert(struct nsd_options* opt, struct key_options* key)
1343{
1344 if(!key->name) return;
1345 key->node.key = key->name;
1346 (void)rbtree_insert(opt->keys, &key->node);
1347}
1348
1349struct key_options*
1350key_options_find(struct nsd_options* opt, const char* name)
1351{
1352 return (struct key_options*)rbtree_search(opt->keys, name);
1353}
1354
1355void
1356tls_auth_options_insert(struct nsd_options* opt, struct tls_auth_options* auth)
1357{
1358 if(!auth->name) return;
1359 auth->node.key = auth->name;
1360 (void)rbtree_insert(opt->tls_auths, &auth->node);
1361}
1362
1363struct tls_auth_options*
1364tls_auth_options_find(struct nsd_options* opt, const char* name)
1365{
1366 return (struct tls_auth_options*)rbtree_search(opt->tls_auths, name);
1367}
1368
1369/** remove tsig_key contents */
1370void
1371key_options_desetup(region_type* region, struct key_options* key)
1372{
1373 /* keep tsig_key pointer so that existing references keep valid */
1374 if(!key->tsig_key)
1375 return;
1376 /* name stays the same */
1377 if(key->tsig_key->data) {
1378 /* wipe secret! */
1379 memset(key->tsig_key->data, 0xdd, key->tsig_key->size);
1380 region_recycle(region, key->tsig_key->data,
1381 key->tsig_key->size);
1382 key->tsig_key->data = NULL((void*)0);
1383 key->tsig_key->size = 0;
1384 }
1385}
1386
1387/** add tsig_key contents */
1388void
1389key_options_setup(region_type* region, struct key_options* key)
1390{
1391 uint8_t data[16384]; /* 16KB */
1392 int size;
1393 if(!key->tsig_key) {
1394 /* create it */
1395 key->tsig_key = (tsig_key_type *) region_alloc(region,
1396 sizeof(tsig_key_type));
1397 /* create name */
1398 key->tsig_key->name = dname_parse(region, key->name);
1399 if(!key->tsig_key->name) {
1400 log_msg(LOG_ERR3, "Failed to parse tsig key name %s",
1401 key->name);
1402 /* key and base64 were checked during syntax parse */
1403 exit(1);
1404 }
1405 key->tsig_key->size = 0;
1406 key->tsig_key->data = NULL((void*)0);
1407 }
1408 size = __b64_pton(key->secret, data, sizeof(data));
1409 if(size == -1) {
1410 log_msg(LOG_ERR3, "Failed to parse tsig key data %s",
1411 key->name);
1412 /* key and base64 were checked during syntax parse */
1413 exit(1);
1414 }
1415 key->tsig_key->size = size;
1416 key->tsig_key->data = (uint8_t *)region_alloc_init(region, data, size);
1417}
1418
1419void
1420key_options_remove(struct nsd_options* opt, const char* name)
1421{
1422 struct key_options* k = key_options_find(opt, name);
1423 if(!k) return;
1424 (void)rbtree_delete(opt->keys, name);
1425 if(k->name)
1426 region_recycle(opt->region, k->name, strlen(k->name)+1);
1427 if(k->algorithm)
1428 region_recycle(opt->region, k->algorithm, strlen(k->algorithm)+1);
1429 if(k->secret) {
1430 memset(k->secret, 0xdd, strlen(k->secret)); /* wipe secret! */
1431 region_recycle(opt->region, k->secret, strlen(k->secret)+1);
1432 }
1433 if(k->tsig_key) {
1434 tsig_del_key(k->tsig_key);
1435 if(k->tsig_key->name)
1436 region_recycle(opt->region, (void*)k->tsig_key->name,
1437 dname_total_size(k->tsig_key->name));
1438 key_options_desetup(opt->region, k);
1439 region_recycle(opt->region, k->tsig_key, sizeof(tsig_key_type));
1440 }
1441 region_recycle(opt->region, k, sizeof(struct key_options));
1442}
1443
1444int
1445key_options_equal(struct key_options* p, struct key_options* q)
1446{
1447 return strcmp(p->name, q->name)==0 && strcmp(p->algorithm,
1448 q->algorithm)==0 && strcmp(p->secret, q->secret)==0;
1449}
1450
1451void
1452key_options_add_modify(struct nsd_options* opt, struct key_options* key)
1453{
1454 struct key_options* orig = key_options_find(opt, key->name);
1455 if(!orig) {
1456 /* needs to be copied to opt region */
1457 orig = key_options_create(opt->region);
1458 orig->name = region_strdup(opt->region, key->name);
1459 orig->algorithm = region_strdup(opt->region, key->algorithm);
1460 orig->secret = region_strdup(opt->region, key->secret);
1461 key_options_setup(opt->region, orig);
1462 tsig_add_key(orig->tsig_key);
1463 key_options_insert(opt, orig);
1464 } else {
1465 /* modify entries in existing key, and copy to opt region */
1466 key_options_desetup(opt->region, orig);
1467 region_recycle(opt->region, orig->algorithm,
1468 strlen(orig->algorithm)+1);
1469 orig->algorithm = region_strdup(opt->region, key->algorithm);
1470 region_recycle(opt->region, orig->secret,
1471 strlen(orig->secret)+1);
1472 orig->secret = region_strdup(opt->region, key->secret);
1473 key_options_setup(opt->region, orig);
1474 }
1475}
1476
1477int
1478acl_check_incoming(struct acl_options* acl, struct query* q,
1479 struct acl_options** reason)
1480{
1481 /* check each acl element.
1482 if 1 blocked element matches - return -1.
1483 if any element matches - return number.
1484 else return -1. */
1485 int found_match = -1;
1486 int number = 0;
1487 struct acl_options* match = 0;
1488
1489 if(reason)
1490 *reason = NULL((void*)0);
1491
1492 while(acl)
1493 {
1494 DEBUG(DEBUG_XFRD,2, (LOG_INFO, "testing acl %s %s",
1495 acl->ip_address_spec, acl->nokey?"NOKEY":
1496 (acl->blocked?"BLOCKED":acl->key_name)));
1497 if(acl_addr_matches(acl, q) && acl_key_matches(acl, q)) {
1498 if(!match)
1499 {
1500 match = acl; /* remember first match */
1501 found_match=number;
1502 }
1503 if(acl->blocked) {
1504 if(reason)
1505 *reason = acl;
1506 return -1;
1507 }
1508 }
1509 number++;
1510 acl = acl->next;
1511 }
1512
1513 if(reason)
1514 *reason = match;
1515 return found_match;
1516}
1517
1518#ifdef INET6
1519int
1520acl_addr_matches_ipv6host(struct acl_options* acl, struct sockaddr_storage* addr_storage, unsigned int port)
1521{
1522 struct sockaddr_in6* addr = (struct sockaddr_in6*)addr_storage;
1523 if(acl->port != 0 && acl->port != port)
1524 return 0;
1525 switch(acl->rangetype) {
1526 case acl_range_mask:
1527 case acl_range_subnet:
1528 if(!acl_addr_match_mask((uint32_t*)&acl->addr.addr6, (uint32_t*)&addr->sin6_addr,
1529 (uint32_t*)&acl->range_mask.addr6, sizeof(struct in6_addr)))
1530 return 0;
1531 break;
1532 case acl_range_minmax:
1533 if(!acl_addr_match_range_v6((uint32_t*)&acl->addr.addr6, (uint32_t*)&addr->sin6_addr,
1534 (uint32_t*)&acl->range_mask.addr6, sizeof(struct in6_addr)))
1535 return 0;
1536 break;
1537 case acl_range_single:
1538 default:
1539 if(memcmp(&addr->sin6_addr, &acl->addr.addr6,
1540 sizeof(struct in6_addr)) != 0)
1541 return 0;
1542 break;
1543 }
1544 return 1;
1545}
1546#endif
1547
1548int
1549acl_addr_matches_ipv4host(struct acl_options* acl, struct sockaddr_in* addr, unsigned int port)
1550{
1551 if(acl->port != 0 && acl->port != port)
1552 return 0;
1553 switch(acl->rangetype) {
1554 case acl_range_mask:
1555 case acl_range_subnet:
1556 if(!acl_addr_match_mask((uint32_t*)&acl->addr.addr, (uint32_t*)&addr->sin_addr,
1557 (uint32_t*)&acl->range_mask.addr, sizeof(struct in_addr)))
1558 return 0;
1559 break;
1560 case acl_range_minmax:
1561 if(!acl_addr_match_range_v4((uint32_t*)&acl->addr.addr, (uint32_t*)&addr->sin_addr,
1562 (uint32_t*)&acl->range_mask.addr, sizeof(struct in_addr)))
1563 return 0;
1564 break;
1565 case acl_range_single:
1566 default:
1567 if(memcmp(&addr->sin_addr, &acl->addr.addr,
1568 sizeof(struct in_addr)) != 0)
1569 return 0;
1570 break;
1571 }
1572 return 1;
1573}
1574
1575int
1576acl_addr_matches_host(struct acl_options* acl, struct acl_options* host)
1577{
1578 if(acl->is_ipv6)
1579 {
1580#ifdef INET6
1581 struct sockaddr_storage* addr = (struct sockaddr_storage*)&host->addr;
1582 if(!host->is_ipv6) return 0;
1583 return acl_addr_matches_ipv6host(acl, addr, host->port);
1584#else
1585 return 0; /* no inet6, no match */
1586#endif
1587 }
1588 else
1589 {
1590 struct sockaddr_in* addr = (struct sockaddr_in*)&host->addr;
1591 if(host->is_ipv6) return 0;
1592 return acl_addr_matches_ipv4host(acl, addr, host->port);
1593 }
1594 /* ENOTREACH */
1595 return 0;
1596}
1597
1598int
1599acl_addr_matches(struct acl_options* acl, struct query* q)
1600{
1601 if(acl->is_ipv6)
1602 {
1603#ifdef INET6
1604 struct sockaddr_storage* addr = (struct sockaddr_storage*)&q->addr;
1605 if(addr->ss_family != AF_INET624)
1606 return 0;
1607 return acl_addr_matches_ipv6host(acl, addr, ntohs(((struct sockaddr_in6*)addr)->sin6_port)(__uint16_t)(__builtin_constant_p(((struct sockaddr_in6*)addr
)->sin6_port) ? (__uint16_t)(((__uint16_t)(((struct sockaddr_in6
*)addr)->sin6_port) & 0xffU) << 8 | ((__uint16_t
)(((struct sockaddr_in6*)addr)->sin6_port) & 0xff00U) >>
8) : __swap16md(((struct sockaddr_in6*)addr)->sin6_port))
);
1608#else
1609 return 0; /* no inet6, no match */
1610#endif
1611 }
1612 else
1613 {
1614 struct sockaddr_in* addr = (struct sockaddr_in*)&q->addr;
1615 if(addr->sin_family != AF_INET2)
1616 return 0;
1617 return acl_addr_matches_ipv4host(acl, addr, ntohs(addr->sin_port)(__uint16_t)(__builtin_constant_p(addr->sin_port) ? (__uint16_t
)(((__uint16_t)(addr->sin_port) & 0xffU) << 8 | (
(__uint16_t)(addr->sin_port) & 0xff00U) >> 8) : __swap16md
(addr->sin_port))
);
1618 }
1619 /* ENOTREACH */
1620 return 0;
1621}
1622
1623int
1624acl_addr_match_mask(uint32_t* a, uint32_t* b, uint32_t* mask, size_t sz)
1625{
1626 size_t i;
1627#ifndef NDEBUG
1628 assert(sz % 4 == 0)((void)0);
1629#endif
1630 sz /= 4;
1631 for(i=0; i<sz; ++i)
1632 {
1633 if(((*a++)&*mask) != ((*b++)&*mask))
1634 return 0;
1635 ++mask;
1636 }
1637 return 1;
1638}
1639
1640int
1641acl_addr_match_range_v4(uint32_t* minval, uint32_t* x, uint32_t* maxval, size_t sz)
1642{
1643 assert(sz == 4)((void)0); (void)sz;
1644 /* check treats x as one huge number */
1645
1646 /* if outside bounds, we are done */
1647 if(*minval > *x)
1648 return 0;
1649 if(*maxval < *x)
1650 return 0;
1651
1652 return 1;
1653}
1654
1655#ifdef INET6
1656int
1657acl_addr_match_range_v6(uint32_t* minval, uint32_t* x, uint32_t* maxval, size_t sz)
1658{
1659 size_t i;
1660 uint8_t checkmin = 1, checkmax = 1;
1661#ifndef NDEBUG
1662 assert(sz % 4 == 0)((void)0);
1663#endif
1664 /* check treats x as one huge number */
1665 sz /= 4;
1666 for(i=0; i<sz; ++i)
1667 {
1668 /* if outside bounds, we are done */
1669 if(checkmin)
1670 if(minval[i] > x[i])
1671 return 0;
1672 if(checkmax)
1673 if(maxval[i] < x[i])
1674 return 0;
1675 /* if x is equal to a bound, that bound needs further checks */
1676 if(checkmin && minval[i]!=x[i])
1677 checkmin = 0;
1678 if(checkmax && maxval[i]!=x[i])
1679 checkmax = 0;
1680 if(!checkmin && !checkmax)
1681 return 1; /* will always match */
1682 }
1683 return 1;
1684}
1685#endif /* INET6 */
1686
1687int
1688acl_key_matches(struct acl_options* acl, struct query* q)
1689{
1690 if(acl->blocked)
1691 return 1;
1692 if(acl->nokey) {
1693 if(q->tsig.status == TSIG_NOT_PRESENT)
1694 return 1;
1695 return 0;
1696 }
1697 /* check name of tsig key */
1698 if(q->tsig.status != TSIG_OK) {
1699 DEBUG(DEBUG_XFRD,2, (LOG_INFO, "keymatch fail query has no TSIG"));
1700 return 0; /* query has no TSIG */
1701 }
1702 if(q->tsig.error_code != TSIG_ERROR_NOERROR0) {
1703 DEBUG(DEBUG_XFRD,2, (LOG_INFO, "keymatch fail, tsig has error"));
1704 return 0; /* some tsig error */
1705 }
1706 if(!acl->key_options->tsig_key) {
1707 DEBUG(DEBUG_XFRD,2, (LOG_INFO, "keymatch fail no config"));
1708 return 0; /* key not properly configured */
1709 }
1710 if(dname_compare(q->tsig.key_name,
1711 acl->key_options->tsig_key->name) != 0) {
1712 DEBUG(DEBUG_XFRD,2, (LOG_INFO, "keymatch fail wrong key name"));
1713 return 0; /* wrong key name */
1714 }
1715 if(tsig_strlowercmp(q->tsig.algorithm->short_name,
1716 acl->key_options->algorithm) != 0 && (
1717 strncmp("hmac-", q->tsig.algorithm->short_name, 5) != 0 ||
1718 tsig_strlowercmp(q->tsig.algorithm->short_name+5,
1719 acl->key_options->algorithm) != 0) ) {
1720 DEBUG(DEBUG_XFRD,2, (LOG_ERR, "query tsig wrong algorithm"));
1721 return 0; /* no such algo */
1722 }
1723 return 1;
1724}
1725
1726int
1727acl_same_host(struct acl_options* a, struct acl_options* b)
1728{
1729 if(a->is_ipv6 && !b->is_ipv6)
1730 return 0;
1731 if(!a->is_ipv6 && b->is_ipv6)
1732 return 0;
1733 if(a->port != b->port)
1734 return 0;
1735 if(a->rangetype != b->rangetype)
1736 return 0;
1737 if(!a->is_ipv6) {
1738 if(memcmp(&a->addr.addr, &b->addr.addr,
1739 sizeof(struct in_addr)) != 0)
1740 return 0;
1741 if(a->rangetype != acl_range_single &&
1742 memcmp(&a->range_mask.addr, &b->range_mask.addr,
1743 sizeof(struct in_addr)) != 0)
1744 return 0;
1745 } else {
1746#ifdef INET6
1747 if(memcmp(&a->addr.addr6, &b->addr.addr6,
1748 sizeof(struct in6_addr)) != 0)
1749 return 0;
1750 if(a->rangetype != acl_range_single &&
1751 memcmp(&a->range_mask.addr6, &b->range_mask.addr6,
1752 sizeof(struct in6_addr)) != 0)
1753 return 0;
1754#else
1755 return 0;
1756#endif
1757 }
1758 return 1;
1759}
1760
1761#if defined(HAVE_SSL)
1762void
1763key_options_tsig_add(struct nsd_options* opt)
1764{
1765 struct key_options* optkey;
1766 RBTREE_FOR(optkey, struct key_options*, opt->keys)for(optkey=(struct key_options*)rbtree_first(opt->keys); (
rbnode_type*)optkey != &rbtree_null_node; optkey = (struct
key_options*)rbtree_next((rbnode_type*)optkey))
{
1767 key_options_setup(opt->region, optkey);
1768 tsig_add_key(optkey->tsig_key);
1769 }
1770}
1771#endif
1772
1773int
1774zone_is_slave(struct zone_options* opt)
1775{
1776 return opt && opt->pattern && opt->pattern->request_xfr != 0;
1777}
1778
1779/* get a character in string (or replacement char if not long enough) */
1780static const char*
1781get_char(const char* str, size_t i)
1782{
1783 static char res[2];
1784 if(i >= strlen(str))
1785 return ".";
1786 res[0] = str[i];
1787 res[1] = 0;
1788 return res;
1789}
1790/* get end label of the zone name (or .) */
1791static const char*
1792get_end_label(struct zone_options* zone, int i)
1793{
1794 const dname_type* d = (const dname_type*)zone->node.key;
1795 if(i >= d->label_count) {
1796 return ".";
1797 }
1798 return wirelabel2str(dname_label(d, i));
1799}
1800/* replace occurrences of one with two */
1801void
1802replace_str(char* str, size_t len, const char* one, const char* two)
1803{
1804 char* pos;
1805 char* at = str;
1806 while( (pos=strstr(at, one)) ) {
1807 if(strlen(str)+strlen(two)-strlen(one) >= len)
1808 return; /* no more space to replace */
1809 /* stuff before pos is fine */
1810 /* move the stuff after pos to make space for two, add
1811 * one to length of remainder to also copy the 0 byte end */
1812 memmove(pos+strlen(two), pos+strlen(one),
1813 strlen(pos+strlen(one))+1);
1814 /* copy in two */
1815 memmove(pos, two, strlen(two));
1816 /* at is end of the newly inserted two (avoids recursion if
1817 * two contains one) */
1818 at = pos+strlen(two);
1819 }
1820}
1821
1822const char*
1823config_cook_string(struct zone_options* zone, const char* input)
1824{
1825 static char f[1024];
1826 /* if not a template, return as-is */
1827 if(!strchr(input, '%')) {
1828 return input;
1829 }
1830 strlcpy(f, input, sizeof(f));
1831 if(strstr(f, "%1"))
1832 replace_str(f, sizeof(f), "%1", get_char(zone->name, 0));
1833 if(strstr(f, "%2"))
1834 replace_str(f, sizeof(f), "%2", get_char(zone->name, 1));
1835 if(strstr(f, "%3"))
1836 replace_str(f, sizeof(f), "%3", get_char(zone->name, 2));
1837 if(strstr(f, "%z"))
1838 replace_str(f, sizeof(f), "%z", get_end_label(zone, 1));
1839 if(strstr(f, "%y"))
1840 replace_str(f, sizeof(f), "%y", get_end_label(zone, 2));
1841 if(strstr(f, "%x"))
1842 replace_str(f, sizeof(f), "%x", get_end_label(zone, 3));
1843 if(strstr(f, "%s"))
1844 replace_str(f, sizeof(f), "%s", zone->name);
1845 return f;
1846}
1847
1848const char*
1849config_make_zonefile(struct zone_options* zone, struct nsd* nsd)
1850{
1851 static char f[1024];
1852 /* if not a template, return as-is */
1853 if(!strchr(zone->pattern->zonefile, '%')) {
1854 if (nsd->chrootdir && nsd->chrootdir[0] &&
1855 zone->pattern->zonefile &&
1856 zone->pattern->zonefile[0] == '/' &&
1857 strncmp(zone->pattern->zonefile, nsd->chrootdir,
1858 strlen(nsd->chrootdir)) == 0)
1859 /* -1 because chrootdir ends in trailing slash */
1860 return zone->pattern->zonefile + strlen(nsd->chrootdir) - 1;
1861 return zone->pattern->zonefile;
1862 }
1863 strlcpy(f, zone->pattern->zonefile, sizeof(f));
1864 if(strstr(f, "%1"))
1865 replace_str(f, sizeof(f), "%1", get_char(zone->name, 0));
1866 if(strstr(f, "%2"))
1867 replace_str(f, sizeof(f), "%2", get_char(zone->name, 1));
1868 if(strstr(f, "%3"))
1869 replace_str(f, sizeof(f), "%3", get_char(zone->name, 2));
1870 if(strstr(f, "%z"))
1871 replace_str(f, sizeof(f), "%z", get_end_label(zone, 1));
1872 if(strstr(f, "%y"))
1873 replace_str(f, sizeof(f), "%y", get_end_label(zone, 2));
1874 if(strstr(f, "%x"))
1875 replace_str(f, sizeof(f), "%x", get_end_label(zone, 3));
1876 if(strstr(f, "%s"))
1877 replace_str(f, sizeof(f), "%s", zone->name);
1878 if (nsd->chrootdir && nsd->chrootdir[0] && f[0] == '/' &&
1879 strncmp(f, nsd->chrootdir, strlen(nsd->chrootdir)) == 0)
1880 /* -1 because chrootdir ends in trailing slash */
1881 return f + strlen(nsd->chrootdir) - 1;
1882 return f;
1883}
1884
1885struct zone_options*
1886zone_options_find(struct nsd_options* opt, const struct dname* apex)
1887{
1888 return (struct zone_options*) rbtree_search(opt->zone_options, apex);
1889}
1890
1891struct acl_options*
1892acl_find_num(struct acl_options* acl, int num)
1893{
1894 int count = num;
1895 if(num < 0)
1896 return 0;
1897 while(acl && count > 0) {
1898 acl = acl->next;
1899 count--;
1900 }
1901 if(count == 0)
1902 return acl;
1903 return 0;
1904}
1905
1906/* true if ipv6 address, false if ipv4 */
1907int
1908parse_acl_is_ipv6(const char* p)
1909{
1910 /* see if addr is ipv6 or ipv4 -- by : and . */
1911 while(*p) {
1912 if(*p == '.') return 0;
1913 if(*p == ':') return 1;
1914 ++p;
1915 }
1916 return 0;
1917}
1918
1919/* returns range type. mask is the 2nd part of the range */
1920int
1921parse_acl_range_type(char* ip, char** mask)
1922{
1923 char *p;
1924 if((p=strchr(ip, '&'))!=0) {
4
Assuming the condition is false
5
Taking false branch
1925 *p = 0;
1926 *mask = p+1;
1927 return acl_range_mask;
1928 }
1929 if((p=strchr(ip, '/'))!=0) {
6
Assuming the condition is false
7
Taking false branch
1930 *p = 0;
1931 *mask = p+1;
1932 return acl_range_subnet;
1933 }
1934 if((p=strchr(ip, '-'))!=0) {
8
Assuming the condition is false
9
Taking false branch
1935 *p = 0;
1936 *mask = p+1;
1937 return acl_range_minmax;
1938 }
1939 *mask = 0;
10
Null pointer value stored to 'p'
1940 return acl_range_single;
1941}
1942
1943/* parses subnet mask, fills 0 mask as well */
1944void
1945parse_acl_range_subnet(char* p, void* addr, int maxbits)
1946{
1947 int subnet_bits = atoi(p);
1948 uint8_t* addr_bytes = (uint8_t*)addr;
1949 if(subnet_bits == 0 && strcmp(p, "0")!=0) {
23
Assuming 'subnet_bits' is equal to 0
24
Null pointer passed as 1st argument to string comparison function
1950 c_error("bad subnet range '%s'", p);
1951 return;
1952 }
1953 if(subnet_bits < 0 || subnet_bits > maxbits) {
1954 c_error("subnet of %d bits out of range [0..%d]", subnet_bits, maxbits);
1955 return;
1956 }
1957 /* fill addr with n bits of 1s (struct has been zeroed) */
1958 while(subnet_bits >= 8) {
1959 *addr_bytes++ = 0xff;
1960 subnet_bits -= 8;
1961 }
1962 if(subnet_bits > 0) {
1963 uint8_t shifts[] = {0x0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff};
1964 *addr_bytes = shifts[subnet_bits];
1965 }
1966}
1967
1968struct acl_options*
1969parse_acl_info(region_type* region, char* ip, const char* key)
1970{
1971 char* p;
1972 struct acl_options* acl = (struct acl_options*)region_alloc(region,
1973 sizeof(struct acl_options));
1974 acl->next = 0;
1975 /* ip */
1976 acl->ip_address_spec = region_strdup(region, ip);
1977 acl->use_axfr_only = 0;
1978 acl->allow_udp = 0;
1979 acl->ixfr_disabled = 0;
1980 acl->bad_xfr_count = 0;
1981 acl->key_options = 0;
1982 acl->tls_auth_options = 0;
1983 acl->tls_auth_name = 0;
1984 acl->is_ipv6 = 0;
1985 acl->port = 0;
1986 memset(&acl->addr, 0, sizeof(union acl_addr_storage));
1987 memset(&acl->range_mask, 0, sizeof(union acl_addr_storage));
1988 if((p=strrchr(ip, '@'))!=0) {
1
Assuming the condition is false
2
Taking false branch
1989 if(atoi(p+1) == 0) c_error("expected port number after '@'");
1990 else acl->port = atoi(p+1);
1991 *p=0;
1992 }
1993 acl->rangetype = parse_acl_range_type(ip, &p);
3
Calling 'parse_acl_range_type'
11
Returning from 'parse_acl_range_type'
1994 if(parse_acl_is_ipv6(ip)) {
12
Assuming the condition is false
13
Taking false branch
1995 acl->is_ipv6 = 1;
1996#ifdef INET6
1997 if(inet_pton(AF_INET624, ip, &acl->addr.addr6) != 1)
1998 c_error("Bad ip6 address '%s'", ip);
1999 if(acl->rangetype==acl_range_mask || acl->rangetype==acl_range_minmax) {
2000 assert(p)((void)0);
2001 if(inet_pton(AF_INET624, p, &acl->range_mask.addr6) != 1)
2002 c_error("Bad ip6 address mask '%s'", p);
2003 }
2004 if(acl->rangetype==acl_range_subnet) {
2005 assert(p)((void)0);
2006 parse_acl_range_subnet(p, &acl->range_mask.addr6, 128);
2007 }
2008#else
2009 c_error("encountered IPv6 address '%s'.", ip);
2010#endif /* INET6 */
2011 } else {
2012 acl->is_ipv6 = 0;
2013 if(inet_pton(AF_INET2, ip, &acl->addr.addr) != 1)
14
Assuming the condition is true
15
Taking true branch
2014 c_error("Bad ip4 address '%s'", ip);
2015 if(acl->rangetype==acl_range_mask || acl->rangetype==acl_range_minmax) {
16
Assuming field 'rangetype' is not equal to acl_range_mask
17
Assuming field 'rangetype' is not equal to acl_range_minmax
18
Taking false branch
2016 assert(p)((void)0);
2017 if(inet_pton(AF_INET2, p, &acl->range_mask.addr) != 1)
2018 c_error("Bad ip4 address mask '%s'", p);
2019 }
2020 if(acl->rangetype==acl_range_subnet) {
19
Assuming field 'rangetype' is equal to acl_range_subnet
20
Taking true branch
2021 assert(p)((void)0);
2022 parse_acl_range_subnet(p, &acl->range_mask.addr, 32);
21
Passing null pointer value via 1st parameter 'p'
22
Calling 'parse_acl_range_subnet'
2023 }
2024 }
2025
2026 /* key */
2027 if(strcmp(key, "NOKEY")==0) {
2028 acl->nokey = 1;
2029 acl->blocked = 0;
2030 acl->key_name = 0;
2031 } else if(strcmp(key, "BLOCKED")==0) {
2032 acl->nokey = 0;
2033 acl->blocked = 1;
2034 acl->key_name = 0;
2035 } else {
2036 acl->nokey = 0;
2037 acl->blocked = 0;
2038 acl->key_name = region_strdup(region, key);
2039 }
2040 return acl;
2041}
2042
2043/* copy acl list at end of parser start, update current */
2044static
2045void copy_and_append_acls(struct acl_options** start, struct acl_options* list)
2046{
2047 struct acl_options *tail = NULL((void*)0);
2048
2049 assert(start != NULL)((void)0);
2050
2051 tail = *start;
2052 if(tail) {
2053 while(tail->next) {
2054 tail = tail->next;
2055 }
2056 }
2057
2058 while(list) {
2059 struct acl_options* acl = copy_acl(cfg_parser->opt->region,
2060 list);
2061 acl->next = NULL((void*)0);
2062 if(tail) {
2063 tail->next = acl;
2064 } else {
2065 *start = acl;
2066 }
2067 tail = acl;
2068 list = list->next;
2069 }
2070}
2071
2072void
2073config_apply_pattern(struct pattern_options *dest, const char* name)
2074{
2075 /* find the pattern */
2076 struct pattern_options* pat = pattern_options_find(cfg_parser->opt,
2077 name);
2078 if(!pat) {
2079 c_error("could not find pattern %s", name);
2080 return;
2081 }
2082
2083 /* apply settings */
2084 if(pat->zonefile)
2085 dest->zonefile = region_strdup(cfg_parser->opt->region,
2086 pat->zonefile);
2087 if(pat->zonestats)
2088 dest->zonestats = region_strdup(cfg_parser->opt->region,
2089 pat->zonestats);
2090 if(!pat->allow_axfr_fallback_is_default) {
2091 dest->allow_axfr_fallback = pat->allow_axfr_fallback;
2092 dest->allow_axfr_fallback_is_default = 0;
2093 }
2094 if(!pat->notify_retry_is_default) {
2095 dest->notify_retry = pat->notify_retry;
2096 dest->notify_retry_is_default = 0;
2097 }
2098 if(!pat->max_refresh_time_is_default) {
2099 dest->max_refresh_time = pat->max_refresh_time;
2100 dest->max_refresh_time_is_default = 0;
2101 }
2102 if(!pat->min_refresh_time_is_default) {
2103 dest->min_refresh_time = pat->min_refresh_time;
2104 dest->min_refresh_time_is_default = 0;
2105 }
2106 if(!pat->max_retry_time_is_default) {
2107 dest->max_retry_time = pat->max_retry_time;
2108 dest->max_retry_time_is_default = 0;
2109 }
2110 if(!pat->min_retry_time_is_default) {
2111 dest->min_retry_time = pat->min_retry_time;
2112 dest->min_retry_time_is_default = 0;
2113 }
2114 if(!expire_time_is_default(pat->min_expire_time_expr)(!( (pat->min_expire_time_expr) == 2 || (pat->min_expire_time_expr
) == 0 ))
) {
2115 dest->min_expire_time = pat->min_expire_time;
2116 dest->min_expire_time_expr = pat->min_expire_time_expr;
2117 }
2118 dest->size_limit_xfr = pat->size_limit_xfr;
2119#ifdef RATELIMIT
2120 dest->rrl_whitelist |= pat->rrl_whitelist;
2121#endif
2122 /* append acl items */
2123 copy_and_append_acls(&dest->allow_notify, pat->allow_notify);
2124 copy_and_append_acls(&dest->request_xfr, pat->request_xfr);
2125 copy_and_append_acls(&dest->notify, pat->notify);
2126 copy_and_append_acls(&dest->provide_xfr, pat->provide_xfr);
2127 copy_and_append_acls(&dest->allow_query, pat->allow_query);
2128 copy_and_append_acls(&dest->outgoing_interface, pat->outgoing_interface);
2129 if(pat->multi_master_check)
2130 dest->multi_master_check = pat->multi_master_check;
2131}
2132
2133void
2134nsd_options_destroy(struct nsd_options* opt)
2135{
2136 region_destroy(opt->region);
2137#ifdef MEMCLEAN /* OS collects memory pages */
2138 c_lex_destroy();
2139#endif
2140}
2141
2142unsigned getzonestatid(struct nsd_options* opt, struct zone_options* zopt)
2143{
2144#ifdef USE_ZONE_STATS
2145 const char* statname;
2146 struct zonestatname* n;
2147 rbnode_type* res;
2148 /* try to find the instantiated zonestat name */
2149 if(!zopt->pattern->zonestats || zopt->pattern->zonestats[0]==0)
2150 return 0; /* no zone stats */
2151 statname = config_cook_string(zopt, zopt->pattern->zonestats);
2152 res = rbtree_search(opt->zonestatnames, statname);
2153 if(res)
2154 return ((struct zonestatname*)res)->id;
2155 /* create it */
2156 n = (struct zonestatname*)region_alloc_zero(opt->region, sizeof(*n));
2157 n->node.key = region_strdup(opt->region, statname);
2158 if(!n->node.key) {
2159 log_msg(LOG_ERR3, "malloc failed: %s", strerror(errno(*__errno())));
2160 exit(1);
2161 }
2162 n->id = (unsigned)(opt->zonestatnames->count);
2163 rbtree_insert(opt->zonestatnames, (rbnode_type*)n);
2164 return n->id;
2165#else /* USE_ZONE_STATS */
2166 (void)opt; (void)zopt;
2167 return 0;
2168#endif /* USE_ZONE_STATS */
2169}
2170
2171/** check if config turns on IP-address interface with certificates or a
2172 * named pipe without certificates. */
2173int
2174options_remote_is_address(struct nsd_options* cfg)
2175{
2176 if(!cfg->control_enable) return 0;
2177 if(!cfg->control_interface) return 1;
2178 if(!cfg->control_interface->address) return 1;
2179 if(cfg->control_interface->address[0] == 0) return 1;
2180 return (cfg->control_interface->address[0] != '/');
2181}
2182
2183#ifdef HAVE_GETIFADDRS1
2184static void
2185resolve_ifa_name(struct ifaddrs *ifas, const char *search_ifa, char ***ip_addresses, size_t *ip_addresses_size)
2186{
2187 struct ifaddrs *ifa;
2188 size_t last_ip_addresses_size = *ip_addresses_size;
2189
2190 for(ifa = ifas; ifa != NULL((void*)0); ifa = ifa->ifa_next) {
2191 sa_family_t family;
2192 const char* atsign;
2193#ifdef INET6 /* | address ip | % | ifa name | @ | port | nul */
2194 char addr_buf[INET6_ADDRSTRLEN46 + 1 + IF_NAMESIZE16 + 1 + 16 + 1];
2195#else
2196 char addr_buf[INET_ADDRSTRLEN16 + 1 + 16 + 1];
2197#endif
2198
2199 if((atsign=strrchr(search_ifa, '@')) != NULL((void*)0)) {
2200 if(strlen(ifa->ifa_name) != (size_t)(atsign-search_ifa)
2201 || strncmp(ifa->ifa_name, search_ifa,
2202 atsign-search_ifa) != 0)
2203 continue;
2204 } else {
2205 if(strcmp(ifa->ifa_name, search_ifa) != 0)
2206 continue;
2207 atsign = "";
2208 }
2209
2210 if(ifa->ifa_addr == NULL((void*)0))
2211 continue;
2212
2213 family = ifa->ifa_addr->sa_family;
2214 if(family == AF_INET2) {
2215 char a4[INET_ADDRSTRLEN16 + 1];
2216 struct sockaddr_in *in4 = (struct sockaddr_in *)
2217 ifa->ifa_addr;
2218 if(!inet_ntop(family, &in4->sin_addr, a4, sizeof(a4)))
2219 error("inet_ntop");
2220 snprintf(addr_buf, sizeof(addr_buf), "%s%s",
2221 a4, atsign);
2222 }
2223#ifdef INET6
2224 else if(family == AF_INET624) {
2225 struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)
2226 ifa->ifa_addr;
2227 char a6[INET6_ADDRSTRLEN46 + 1];
2228 char if_index_name[IF_NAMESIZE16 + 1];
2229 if_index_name[0] = 0;
2230 if(!inet_ntop(family, &in6->sin6_addr, a6, sizeof(a6)))
2231 error("inet_ntop");
2232 if_indextoname(in6->sin6_scope_id,
2233 (char *)if_index_name);
2234 if (strlen(if_index_name) != 0) {
2235 snprintf(addr_buf, sizeof(addr_buf),
2236 "%s%%%s%s", a6, if_index_name, atsign);
2237 } else {
2238 snprintf(addr_buf, sizeof(addr_buf), "%s%s",
2239 a6, atsign);
2240 }
2241 }
2242#endif
2243 else {
2244 continue;
2245 }
2246 VERBOSITY(4, (LOG_INFO, "interface %s has address %s",do { if ((4) <= verbosity) { log_msg (6, "interface %s has address %s"
, search_ifa, addr_buf) ; } } while (0)
2247 search_ifa, addr_buf))do { if ((4) <= verbosity) { log_msg (6, "interface %s has address %s"
, search_ifa, addr_buf) ; } } while (0)
;
2248
2249 *ip_addresses = xrealloc(*ip_addresses, sizeof(char *) * (*ip_addresses_size + 1));
2250 (*ip_addresses)[*ip_addresses_size] = xstrdup(addr_buf);
2251 (*ip_addresses_size)++;
2252 }
2253
2254 if (*ip_addresses_size == last_ip_addresses_size) {
2255 *ip_addresses = xrealloc(*ip_addresses, sizeof(char *) * (*ip_addresses_size + 1));
2256 (*ip_addresses)[*ip_addresses_size] = xstrdup(search_ifa);
2257 (*ip_addresses_size)++;
2258 }
2259}
2260
2261static void
2262resolve_interface_names_for_ref(struct ip_address_option** ip_addresses_ref,
2263 struct ifaddrs *addrs, region_type* region)
2264{
2265 struct ip_address_option *ip_addr;
2266 struct ip_address_option *last = NULL((void*)0);
2267 struct ip_address_option *first = NULL((void*)0);
2268
2269 /* replace the list of ip_adresses with a new list where the
2270 * interface names are replaced with their ip-address strings
2271 * from getifaddrs. An interface can have several addresses. */
2272 for(ip_addr = *ip_addresses_ref; ip_addr; ip_addr = ip_addr->next) {
2273 char **ip_addresses = NULL((void*)0);
2274 size_t ip_addresses_size = 0, i;
2275 resolve_ifa_name(addrs, ip_addr->address, &ip_addresses,
2276 &ip_addresses_size);
2277
2278 for (i = 0; i < ip_addresses_size; i++) {
2279 struct ip_address_option *current;
2280 /* this copies the range_option, dev, and fib from
2281 * the original ip_address option to the new ones
2282 * with the addresses spelled out by resolve_ifa_name*/
2283 current = region_alloc_init(region, ip_addr,
2284 sizeof(*ip_addr));
2285 current->address = region_strdup(region,
2286 ip_addresses[i]);
2287 current->next = NULL((void*)0);
2288 free(ip_addresses[i]);
2289
2290 if(first == NULL((void*)0)) {
2291 first = current;
2292 } else {
2293 last->next = current;
2294 }
2295 last = current;
2296 }
2297 free(ip_addresses);
2298 }
2299 *ip_addresses_ref = first;
2300
2301}
2302#endif /* HAVE_GETIFADDRS */
2303
2304void
2305resolve_interface_names(struct nsd_options* options)
2306{
2307#ifdef HAVE_GETIFADDRS1
2308 struct ifaddrs *addrs;
2309
2310 if(getifaddrs(&addrs) == -1)
2311 error("failed to list interfaces");
2312
2313 resolve_interface_names_for_ref(&options->ip_addresses,
2314 addrs, options->region);
2315 resolve_interface_names_for_ref(&options->control_interface,
2316 addrs, options->region);
2317
2318 freeifaddrs(addrs);
2319#else
2320 (void)options;
2321#endif /* HAVE_GETIFADDRS */
2322}