xref: /openbsd/usr.sbin/nsd/configparser.y (revision 5a38ef86)
1 /*
2  * configparser.y -- yacc grammar for NSD configuration files
3  *
4  * Copyright (c) 2001-2019, NLnet Labs. All rights reserved.
5  *
6  * See LICENSE for the license.
7  *
8  */
9 
10 %{
11 #include "config.h"
12 
13 #include <assert.h>
14 #include <errno.h>
15 #include <stdio.h>
16 #include <string.h>
17 
18 #include "options.h"
19 #include "util.h"
20 #include "dname.h"
21 #include "tsig.h"
22 #include "rrl.h"
23 
24 int yylex(void);
25 
26 #ifdef __cplusplus
27 extern "C"
28 #endif
29 
30 /* these need to be global, otherwise they cannot be used inside yacc */
31 extern config_parser_state_type *cfg_parser;
32 
33 static void append_acl(struct acl_options **list, struct acl_options *acl);
34 static void add_to_last_acl(struct acl_options **list, char *ac);
35 static int parse_boolean(const char *str, int *bln);
36 static int parse_expire_expr(const char *str, long long *num, uint8_t *expr);
37 static int parse_number(const char *str, long long *num);
38 static int parse_range(const char *str, long long *low, long long *high);
39 %}
40 
41 %union {
42   char *str;
43   long long llng;
44   int bln;
45   struct ip_address_option *ip;
46   struct range_option *range;
47   struct cpu_option *cpu;
48 }
49 
50 %token <str> STRING
51 %type <llng> number
52 %type <bln> boolean
53 %type <ip> ip_address
54 %type <llng> service_cpu_affinity
55 %type <cpu> cpus
56 
57 /* server */
58 %token VAR_SERVER
59 %token VAR_SERVER_COUNT
60 %token VAR_IP_ADDRESS
61 %token VAR_IP_TRANSPARENT
62 %token VAR_IP_FREEBIND
63 %token VAR_REUSEPORT
64 %token VAR_SEND_BUFFER_SIZE
65 %token VAR_RECEIVE_BUFFER_SIZE
66 %token VAR_DEBUG_MODE
67 %token VAR_IP4_ONLY
68 %token VAR_IP6_ONLY
69 %token VAR_DO_IP4
70 %token VAR_DO_IP6
71 %token VAR_PORT
72 %token VAR_USE_SYSTEMD
73 %token VAR_VERBOSITY
74 %token VAR_USERNAME
75 %token VAR_CHROOT
76 %token VAR_ZONESDIR
77 %token VAR_ZONELISTFILE
78 %token VAR_DATABASE
79 %token VAR_LOGFILE
80 %token VAR_LOG_ONLY_SYSLOG
81 %token VAR_PIDFILE
82 %token VAR_DIFFFILE
83 %token VAR_XFRDFILE
84 %token VAR_XFRDIR
85 %token VAR_HIDE_VERSION
86 %token VAR_HIDE_IDENTITY
87 %token VAR_VERSION
88 %token VAR_IDENTITY
89 %token VAR_NSID
90 %token VAR_TCP_COUNT
91 %token VAR_TCP_REJECT_OVERFLOW
92 %token VAR_TCP_QUERY_COUNT
93 %token VAR_TCP_TIMEOUT
94 %token VAR_TCP_MSS
95 %token VAR_OUTGOING_TCP_MSS
96 %token VAR_IPV4_EDNS_SIZE
97 %token VAR_IPV6_EDNS_SIZE
98 %token VAR_STATISTICS
99 %token VAR_XFRD_RELOAD_TIMEOUT
100 %token VAR_LOG_TIME_ASCII
101 %token VAR_ROUND_ROBIN
102 %token VAR_MINIMAL_RESPONSES
103 %token VAR_CONFINE_TO_ZONE
104 %token VAR_REFUSE_ANY
105 %token VAR_ZONEFILES_CHECK
106 %token VAR_ZONEFILES_WRITE
107 %token VAR_RRL_SIZE
108 %token VAR_RRL_RATELIMIT
109 %token VAR_RRL_SLIP
110 %token VAR_RRL_IPV4_PREFIX_LENGTH
111 %token VAR_RRL_IPV6_PREFIX_LENGTH
112 %token VAR_RRL_WHITELIST_RATELIMIT
113 %token VAR_TLS_SERVICE_KEY
114 %token VAR_TLS_SERVICE_PEM
115 %token VAR_TLS_SERVICE_OCSP
116 %token VAR_TLS_PORT
117 %token VAR_TLS_CERT_BUNDLE
118 %token VAR_CPU_AFFINITY
119 %token VAR_XFRD_CPU_AFFINITY
120 %token <llng> VAR_SERVER_CPU_AFFINITY
121 %token VAR_DROP_UPDATES
122 
123 /* dnstap */
124 %token VAR_DNSTAP
125 %token VAR_DNSTAP_ENABLE
126 %token VAR_DNSTAP_SOCKET_PATH
127 %token VAR_DNSTAP_SEND_IDENTITY
128 %token VAR_DNSTAP_SEND_VERSION
129 %token VAR_DNSTAP_IDENTITY
130 %token VAR_DNSTAP_VERSION
131 %token VAR_DNSTAP_LOG_AUTH_QUERY_MESSAGES
132 %token VAR_DNSTAP_LOG_AUTH_RESPONSE_MESSAGES
133 
134 /* remote-control */
135 %token VAR_REMOTE_CONTROL
136 %token VAR_CONTROL_ENABLE
137 %token VAR_CONTROL_INTERFACE
138 %token VAR_CONTROL_PORT
139 %token VAR_SERVER_KEY_FILE
140 %token VAR_SERVER_CERT_FILE
141 %token VAR_CONTROL_KEY_FILE
142 %token VAR_CONTROL_CERT_FILE
143 
144 /* key */
145 %token VAR_KEY
146 %token VAR_ALGORITHM
147 %token VAR_SECRET
148 
149 /* xot auth */
150 %token VAR_TLS_AUTH
151 %token VAR_TLS_AUTH_DOMAIN_NAME
152 %token VAR_TLS_AUTH_CLIENT_CERT
153 %token VAR_TLS_AUTH_CLIENT_KEY
154 %token VAR_TLS_AUTH_CLIENT_KEY_PW
155 
156 /* pattern */
157 %token VAR_PATTERN
158 %token VAR_NAME
159 %token VAR_ZONEFILE
160 %token VAR_NOTIFY
161 %token VAR_PROVIDE_XFR
162 %token VAR_ALLOW_QUERY
163 %token VAR_AXFR
164 %token VAR_UDP
165 %token VAR_NOTIFY_RETRY
166 %token VAR_ALLOW_NOTIFY
167 %token VAR_REQUEST_XFR
168 %token VAR_ALLOW_AXFR_FALLBACK
169 %token VAR_OUTGOING_INTERFACE
170 %token VAR_ANSWER_COOKIE
171 %token VAR_COOKIE_SECRET
172 %token VAR_COOKIE_SECRET_FILE
173 %token VAR_MAX_REFRESH_TIME
174 %token VAR_MIN_REFRESH_TIME
175 %token VAR_MAX_RETRY_TIME
176 %token VAR_MIN_RETRY_TIME
177 %token VAR_MIN_EXPIRE_TIME
178 %token VAR_MULTI_MASTER_CHECK
179 %token VAR_SIZE_LIMIT_XFR
180 %token VAR_ZONESTATS
181 %token VAR_INCLUDE_PATTERN
182 
183 /* zone */
184 %token VAR_ZONE
185 %token VAR_RRL_WHITELIST
186 
187 /* socket options */
188 %token VAR_SERVERS
189 %token VAR_BINDTODEVICE
190 %token VAR_SETFIB
191 
192 %%
193 
194 blocks:
195     /* may be empty */
196   | blocks block ;
197 
198 block:
199     server
200   | dnstap
201   | remote_control
202   | key
203   | tls_auth
204   | pattern
205   | zone ;
206 
207 server:
208     VAR_SERVER server_block ;
209 
210 server_block:
211     server_block server_option | ;
212 
213 server_option:
214     VAR_IP_ADDRESS ip_address
215       {
216         struct ip_address_option *ip = cfg_parser->opt->ip_addresses;
217 
218         if(ip == NULL) {
219           cfg_parser->opt->ip_addresses = $2;
220         } else {
221           while(ip->next) { ip = ip->next; }
222           ip->next = $2;
223         }
224 
225         cfg_parser->ip = $2;
226       }
227     socket_options
228     {
229       cfg_parser->ip = NULL;
230     }
231   | VAR_SERVER_COUNT number
232     {
233       if ($2 > 0) {
234         cfg_parser->opt->server_count = (int)$2;
235       } else {
236         yyerror("expected a number greater than zero");
237       }
238     }
239   | VAR_IP_TRANSPARENT boolean
240     { cfg_parser->opt->ip_transparent = $2; }
241   | VAR_IP_FREEBIND boolean
242     { cfg_parser->opt->ip_freebind = $2; }
243   | VAR_SEND_BUFFER_SIZE number
244     { cfg_parser->opt->send_buffer_size = (int)$2; }
245   | VAR_RECEIVE_BUFFER_SIZE number
246     { cfg_parser->opt->receive_buffer_size = (int)$2; }
247   | VAR_DEBUG_MODE boolean
248     { cfg_parser->opt->debug_mode = $2; }
249   | VAR_USE_SYSTEMD boolean
250     { /* ignored, deprecated */ }
251   | VAR_HIDE_VERSION boolean
252     { cfg_parser->opt->hide_version = $2; }
253   | VAR_HIDE_IDENTITY boolean
254     { cfg_parser->opt->hide_identity = $2; }
255   | VAR_DROP_UPDATES boolean
256     { cfg_parser->opt->drop_updates = $2; }
257   | VAR_IP4_ONLY boolean
258     { if($2) { cfg_parser->opt->do_ip4 = 1; cfg_parser->opt->do_ip6 = 0; } }
259   | VAR_IP6_ONLY boolean
260     { if($2) { cfg_parser->opt->do_ip4 = 0; cfg_parser->opt->do_ip6 = 1; } }
261   | VAR_DO_IP4 boolean
262     { cfg_parser->opt->do_ip4 = $2; }
263   | VAR_DO_IP6 boolean
264     { cfg_parser->opt->do_ip6 = $2; }
265   | VAR_DATABASE STRING
266     {
267       cfg_parser->opt->database = region_strdup(cfg_parser->opt->region, $2);
268       if(cfg_parser->opt->database[0] == 0 &&
269          cfg_parser->opt->zonefiles_write == 0)
270       {
271         cfg_parser->opt->zonefiles_write = ZONEFILES_WRITE_INTERVAL;
272       }
273     }
274   | VAR_IDENTITY STRING
275     { cfg_parser->opt->identity = region_strdup(cfg_parser->opt->region, $2); }
276   | VAR_VERSION STRING
277     { cfg_parser->opt->version = region_strdup(cfg_parser->opt->region, $2); }
278   | VAR_NSID STRING
279     {
280       unsigned char* nsid = 0;
281       size_t nsid_len = strlen($2);
282 
283       if (strncasecmp($2, "ascii_", 6) == 0) {
284         nsid_len -= 6; /* discard "ascii_" */
285         if(nsid_len < 65535) {
286           cfg_parser->opt->nsid = region_alloc(cfg_parser->opt->region, nsid_len*2+1);
287           hex_ntop((uint8_t*)$2+6, nsid_len, (char*)cfg_parser->opt->nsid, nsid_len*2+1);
288         } else {
289           yyerror("NSID too long");
290         }
291       } else if (nsid_len % 2 != 0) {
292         yyerror("the NSID must be a hex string of an even length.");
293       } else {
294         nsid_len = nsid_len / 2;
295         if(nsid_len < 65535) {
296           nsid = xalloc(nsid_len);
297           if (hex_pton($2, nsid, nsid_len) == -1) {
298             yyerror("hex string cannot be parsed in NSID.");
299           } else {
300             cfg_parser->opt->nsid = region_strdup(cfg_parser->opt->region, $2);
301           }
302           free(nsid);
303         } else {
304           yyerror("NSID too long");
305         }
306       }
307     }
308   | VAR_LOGFILE STRING
309     { cfg_parser->opt->logfile = region_strdup(cfg_parser->opt->region, $2); }
310   | VAR_LOG_ONLY_SYSLOG boolean
311     { cfg_parser->opt->log_only_syslog = $2; }
312   | VAR_TCP_COUNT number
313     {
314       if ($2 > 0) {
315         cfg_parser->opt->tcp_count = (int)$2;
316       } else {
317         yyerror("expected a number greater than zero");
318       }
319     }
320   | VAR_TCP_REJECT_OVERFLOW boolean
321     { cfg_parser->opt->tcp_reject_overflow = $2; }
322   | VAR_TCP_QUERY_COUNT number
323     { cfg_parser->opt->tcp_query_count = (int)$2; }
324   | VAR_TCP_TIMEOUT number
325     { cfg_parser->opt->tcp_timeout = (int)$2; }
326   | VAR_TCP_MSS number
327     { cfg_parser->opt->tcp_mss = (int)$2; }
328   | VAR_OUTGOING_TCP_MSS number
329     { cfg_parser->opt->outgoing_tcp_mss = (int)$2; }
330   | VAR_IPV4_EDNS_SIZE number
331     { cfg_parser->opt->ipv4_edns_size = (size_t)$2; }
332   | VAR_IPV6_EDNS_SIZE number
333     { cfg_parser->opt->ipv6_edns_size = (size_t)$2; }
334   | VAR_PIDFILE STRING
335     { cfg_parser->opt->pidfile = region_strdup(cfg_parser->opt->region, $2); }
336   | VAR_PORT number
337     {
338       /* port number, stored as a string */
339       char buf[16];
340       (void)snprintf(buf, sizeof(buf), "%lld", $2);
341       cfg_parser->opt->port = region_strdup(cfg_parser->opt->region, buf);
342     }
343   | VAR_REUSEPORT boolean
344     { cfg_parser->opt->reuseport = $2; }
345   | VAR_STATISTICS number
346     { cfg_parser->opt->statistics = (int)$2; }
347   | VAR_CHROOT STRING
348     { cfg_parser->opt->chroot = region_strdup(cfg_parser->opt->region, $2); }
349   | VAR_USERNAME STRING
350     { cfg_parser->opt->username = region_strdup(cfg_parser->opt->region, $2); }
351   | VAR_ZONESDIR STRING
352     { cfg_parser->opt->zonesdir = region_strdup(cfg_parser->opt->region, $2); }
353   | VAR_ZONELISTFILE STRING
354     { cfg_parser->opt->zonelistfile = region_strdup(cfg_parser->opt->region, $2); }
355   | VAR_DIFFFILE STRING
356     { /* ignored, deprecated */ }
357   | VAR_XFRDFILE STRING
358     { cfg_parser->opt->xfrdfile = region_strdup(cfg_parser->opt->region, $2); }
359   | VAR_XFRDIR STRING
360     { cfg_parser->opt->xfrdir = region_strdup(cfg_parser->opt->region, $2); }
361   | VAR_XFRD_RELOAD_TIMEOUT number
362     { cfg_parser->opt->xfrd_reload_timeout = (int)$2; }
363   | VAR_VERBOSITY number
364     { cfg_parser->opt->verbosity = (int)$2; }
365   | VAR_RRL_SIZE number
366     {
367 #ifdef RATELIMIT
368       if ($2 > 0) {
369         cfg_parser->opt->rrl_size = (size_t)$2;
370       } else {
371         yyerror("expected a number greater than zero");
372       }
373 #endif
374     }
375   | VAR_RRL_RATELIMIT number
376     {
377 #ifdef RATELIMIT
378       cfg_parser->opt->rrl_ratelimit = (size_t)$2;
379 #endif
380     }
381   | VAR_RRL_SLIP number
382     {
383 #ifdef RATELIMIT
384       cfg_parser->opt->rrl_slip = (size_t)$2;
385 #endif
386     }
387   | VAR_RRL_IPV4_PREFIX_LENGTH number
388     {
389 #ifdef RATELIMIT
390       if ($2 > 32) {
391         yyerror("invalid IPv4 prefix length");
392       } else {
393         cfg_parser->opt->rrl_ipv4_prefix_length = (size_t)$2;
394       }
395 #endif
396     }
397   | VAR_RRL_IPV6_PREFIX_LENGTH number
398     {
399 #ifdef RATELIMIT
400       if ($2 > 64) {
401         yyerror("invalid IPv6 prefix length");
402       } else {
403         cfg_parser->opt->rrl_ipv6_prefix_length = (size_t)$2;
404       }
405 #endif
406     }
407   | VAR_RRL_WHITELIST_RATELIMIT number
408     {
409 #ifdef RATELIMIT
410       cfg_parser->opt->rrl_whitelist_ratelimit = (size_t)$2;
411 #endif
412     }
413   | VAR_ZONEFILES_CHECK boolean
414     { cfg_parser->opt->zonefiles_check = $2; }
415   | VAR_ZONEFILES_WRITE number
416     { cfg_parser->opt->zonefiles_write = (int)$2; }
417   | VAR_LOG_TIME_ASCII boolean
418     {
419       cfg_parser->opt->log_time_ascii = $2;
420       log_time_asc = cfg_parser->opt->log_time_ascii;
421     }
422   | VAR_ROUND_ROBIN boolean
423     {
424       cfg_parser->opt->round_robin = $2;
425       round_robin = cfg_parser->opt->round_robin;
426     }
427   | VAR_MINIMAL_RESPONSES boolean
428     {
429       cfg_parser->opt->minimal_responses = $2;
430       minimal_responses = cfg_parser->opt->minimal_responses;
431     }
432   | VAR_CONFINE_TO_ZONE boolean
433     { cfg_parser->opt->confine_to_zone = $2; }
434   | VAR_REFUSE_ANY boolean
435     { cfg_parser->opt->refuse_any = $2; }
436   | VAR_TLS_SERVICE_KEY STRING
437     { cfg_parser->opt->tls_service_key = region_strdup(cfg_parser->opt->region, $2); }
438   | VAR_TLS_SERVICE_OCSP STRING
439     { cfg_parser->opt->tls_service_ocsp = region_strdup(cfg_parser->opt->region, $2); }
440   | VAR_TLS_SERVICE_PEM STRING
441     { cfg_parser->opt->tls_service_pem = region_strdup(cfg_parser->opt->region, $2); }
442   | VAR_TLS_PORT number
443     {
444       /* port number, stored as string */
445       char buf[16];
446       (void)snprintf(buf, sizeof(buf), "%lld", $2);
447       cfg_parser->opt->tls_port = region_strdup(cfg_parser->opt->region, buf);
448     }
449   | VAR_TLS_CERT_BUNDLE STRING
450     { cfg_parser->opt->tls_cert_bundle = region_strdup(cfg_parser->opt->region, $2); }
451   | VAR_ANSWER_COOKIE boolean
452     { cfg_parser->opt->answer_cookie = $2; }
453   | VAR_COOKIE_SECRET STRING
454     { cfg_parser->opt->cookie_secret = region_strdup(cfg_parser->opt->region, $2); }
455   | VAR_COOKIE_SECRET_FILE STRING
456     { cfg_parser->opt->cookie_secret_file = region_strdup(cfg_parser->opt->region, $2); }
457   | VAR_CPU_AFFINITY cpus
458     {
459       cfg_parser->opt->cpu_affinity = $2;
460     }
461   | service_cpu_affinity number
462     {
463       if($2 < 0) {
464         yyerror("expected a non-negative number");
465         YYABORT;
466       } else {
467         struct cpu_map_option *opt, *tail;
468 
469         opt = cfg_parser->opt->service_cpu_affinity;
470         while(opt && opt->service != $1) { opt = opt->next; }
471 
472         if(opt) {
473           opt->cpu = $2;
474         } else {
475           opt = region_alloc_zero(cfg_parser->opt->region, sizeof(*opt));
476           opt->service = (int)$1;
477           opt->cpu = (int)$2;
478 
479           tail = cfg_parser->opt->service_cpu_affinity;
480           if(tail) {
481             while(tail->next) { tail = tail->next; }
482             tail->next = opt;
483           } else {
484             cfg_parser->opt->service_cpu_affinity = opt;
485           }
486         }
487       }
488     }
489   ;
490 
491 socket_options:
492   | socket_options socket_option ;
493 
494 socket_option:
495     VAR_SERVERS STRING
496     {
497       char *tok, *ptr, *str;
498       struct range_option *servers = NULL;
499       long long first, last;
500 
501       /* user may specify "0 1", "0" "1", 0 1 or a combination thereof */
502       for(str = $2; (tok = strtok_r(str, " \t", &ptr)); str = NULL) {
503         struct range_option *opt =
504           region_alloc(cfg_parser->opt->region, sizeof(*opt));
505         first = last = 0;
506         if(!parse_range(tok, &first, &last)) {
507           yyerror("invalid server range '%s'", tok);
508           YYABORT;
509         }
510         assert(first >= 0);
511         assert(last >= 0);
512         opt->next = NULL;
513         opt->first = (int)first;
514         opt->last = (int)last;
515         if(servers) {
516           servers = servers->next = opt;
517         } else {
518           servers = cfg_parser->ip->servers = opt;
519         }
520       }
521     }
522   | VAR_BINDTODEVICE boolean
523     { cfg_parser->ip->dev = $2; }
524   | VAR_SETFIB number
525     { cfg_parser->ip->fib = $2; }
526   ;
527 
528 cpus:
529     { $$ = NULL; }
530   | cpus STRING
531     {
532       char *tok, *ptr, *str;
533       struct cpu_option *tail;
534       long long cpu;
535 
536       str = $2;
537       $$ = tail = $1;
538       if(tail) {
539         while(tail->next) { tail = tail->next; }
540       }
541 
542       /* Users may specify "0 1", "0" "1", 0 1 or a combination thereof. */
543       for(str = $2; (tok = strtok_r(str, " \t", &ptr)); str = NULL) {
544         struct cpu_option *opt =
545           region_alloc(cfg_parser->opt->region, sizeof(*opt));
546         cpu = 0;
547         if(!parse_number(tok, &cpu) || opt->cpu < 0) {
548           yyerror("expected a positive number");
549           YYABORT;
550         }
551         assert(cpu >=0);
552         opt->cpu = (int)cpu;
553         if(tail) {
554           tail->next = opt;
555           tail = opt;
556         } else {
557           $$ = tail = opt;
558         }
559       }
560     }
561   ;
562 
563 service_cpu_affinity:
564     VAR_XFRD_CPU_AFFINITY
565     { $$ = -1; }
566   | VAR_SERVER_CPU_AFFINITY
567     {
568       if($1 <= 0) {
569         yyerror("invalid server identifier");
570         YYABORT;
571       }
572       $$ = $1;
573     }
574   ;
575 
576 dnstap:
577     VAR_DNSTAP dnstap_block ;
578 
579 dnstap_block:
580     dnstap_block dnstap_option | ;
581 
582 dnstap_option:
583     VAR_DNSTAP_ENABLE boolean
584     { cfg_parser->opt->dnstap_enable = $2; }
585   | VAR_DNSTAP_SOCKET_PATH STRING
586     { cfg_parser->opt->dnstap_socket_path = region_strdup(cfg_parser->opt->region, $2); }
587   | VAR_DNSTAP_SEND_IDENTITY boolean
588     { cfg_parser->opt->dnstap_send_identity = $2; }
589   | VAR_DNSTAP_SEND_VERSION boolean
590     { cfg_parser->opt->dnstap_send_version = $2; }
591   | VAR_DNSTAP_IDENTITY STRING
592     { cfg_parser->opt->dnstap_identity = region_strdup(cfg_parser->opt->region, $2); }
593   | VAR_DNSTAP_VERSION STRING
594     { cfg_parser->opt->dnstap_version = region_strdup(cfg_parser->opt->region, $2); }
595   | VAR_DNSTAP_LOG_AUTH_QUERY_MESSAGES boolean
596     { cfg_parser->opt->dnstap_log_auth_query_messages = $2; }
597   | VAR_DNSTAP_LOG_AUTH_RESPONSE_MESSAGES boolean
598     { cfg_parser->opt->dnstap_log_auth_response_messages = $2; }
599   ;
600 
601 remote_control:
602     VAR_REMOTE_CONTROL remote_control_block ;
603 
604 remote_control_block:
605     remote_control_block remote_control_option | ;
606 
607 remote_control_option:
608     VAR_CONTROL_ENABLE boolean
609     { cfg_parser->opt->control_enable = $2; }
610   | VAR_CONTROL_INTERFACE ip_address
611     {
612       struct ip_address_option *ip = cfg_parser->opt->control_interface;
613       if(ip == NULL) {
614         cfg_parser->opt->control_interface = $2;
615       } else {
616         while(ip->next != NULL) { ip = ip->next; }
617         ip->next = $2;
618       }
619     }
620   | VAR_CONTROL_PORT number
621     {
622       if($2 == 0) {
623         yyerror("control port number expected");
624       } else {
625         cfg_parser->opt->control_port = (int)$2;
626       }
627     }
628   | VAR_SERVER_KEY_FILE STRING
629     { cfg_parser->opt->server_key_file = region_strdup(cfg_parser->opt->region, $2); }
630   | VAR_SERVER_CERT_FILE STRING
631     { cfg_parser->opt->server_cert_file = region_strdup(cfg_parser->opt->region, $2); }
632   | VAR_CONTROL_KEY_FILE STRING
633     { cfg_parser->opt->control_key_file = region_strdup(cfg_parser->opt->region, $2); }
634   | VAR_CONTROL_CERT_FILE STRING
635     { cfg_parser->opt->control_cert_file = region_strdup(cfg_parser->opt->region, $2); }
636   ;
637 
638 tls_auth:
639     VAR_TLS_AUTH
640       {
641         tls_auth_options_type *tls_auth = tls_auth_options_create(cfg_parser->opt->region);
642         assert(cfg_parser->tls_auth == NULL);
643         cfg_parser->tls_auth = tls_auth;
644       }
645       tls_auth_block
646     {
647       struct tls_auth_options *tls_auth = cfg_parser->tls_auth;
648       if(tls_auth->name == NULL) {
649         yyerror("tls-auth has no name");
650       } else if(tls_auth->auth_domain_name == NULL) {
651         yyerror("tls-auth %s has no auth-domain-name", tls_auth->name);
652       } else if(tls_auth_options_find(cfg_parser->opt, tls_auth->name)) {
653         yyerror("duplicate tls-auth %s", tls_auth->name);
654       } else {
655       	tls_auth_options_insert(cfg_parser->opt, tls_auth);
656         cfg_parser->tls_auth = NULL;
657       }
658     } ;
659 
660 tls_auth_block:
661     tls_auth_block tls_auth_option | ;
662 
663 tls_auth_option:
664     VAR_NAME STRING
665     {
666       dname_type *dname;
667       dname = (dname_type *)dname_parse(cfg_parser->opt->region, $2);
668       cfg_parser->tls_auth->name = region_strdup(cfg_parser->opt->region, $2);
669       if(dname == NULL) {
670         yyerror("bad tls-auth name %s", $2);
671       } else {
672         region_recycle(cfg_parser->opt->region, dname, dname_total_size(dname));
673       }
674     }
675   | VAR_TLS_AUTH_DOMAIN_NAME STRING
676     {
677       cfg_parser->tls_auth->auth_domain_name = region_strdup(cfg_parser->opt->region, $2);
678     }
679   | VAR_TLS_AUTH_CLIENT_CERT STRING
680     {
681 	    cfg_parser->tls_auth->client_cert = region_strdup(cfg_parser->opt->region, $2);
682     }
683   | VAR_TLS_AUTH_CLIENT_KEY STRING
684     {
685 	    cfg_parser->tls_auth->client_key = region_strdup(cfg_parser->opt->region, $2);
686     }
687   | VAR_TLS_AUTH_CLIENT_KEY_PW STRING
688     {
689 	    cfg_parser->tls_auth->client_key_pw = region_strdup(cfg_parser->opt->region, $2);
690     }
691   ;
692 
693 key:
694     VAR_KEY
695       {
696         key_options_type *key = key_options_create(cfg_parser->opt->region);
697         key->algorithm = region_strdup(cfg_parser->opt->region, "sha256");
698         assert(cfg_parser->key == NULL);
699         cfg_parser->key = key;
700       }
701       key_block
702     {
703       struct key_options *key = cfg_parser->key;
704       if(key->name == NULL) {
705         yyerror("tsig key has no name");
706       } else if(key->algorithm == NULL) {
707         yyerror("tsig key %s has no algorithm", key->name);
708       } else if(key->secret == NULL) {
709         yyerror("tsig key %s has no secret blob", key->name);
710       } else if(key_options_find(cfg_parser->opt, key->name)) {
711         yyerror("duplicate tsig key %s", key->name);
712       } else {
713         key_options_insert(cfg_parser->opt, key);
714         cfg_parser->key = NULL;
715       }
716     } ;
717 
718 key_block:
719     key_block key_option | ;
720 
721 key_option:
722     VAR_NAME STRING
723     {
724       dname_type *dname;
725 
726       dname = (dname_type *)dname_parse(cfg_parser->opt->region, $2);
727       cfg_parser->key->name = region_strdup(cfg_parser->opt->region, $2);
728       if(dname == NULL) {
729         yyerror("bad tsig key name %s", $2);
730       } else {
731         region_recycle(cfg_parser->opt->region, dname, dname_total_size(dname));
732       }
733     }
734   | VAR_ALGORITHM STRING
735     {
736       if(tsig_get_algorithm_by_name($2) == NULL) {
737         yyerror("bad tsig key algorithm %s", $2);
738       } else {
739         cfg_parser->key->algorithm = region_strdup(cfg_parser->opt->region, $2);
740       }
741     }
742   | VAR_SECRET STRING
743     {
744       uint8_t data[16384];
745       int size;
746 
747       cfg_parser->key->secret = region_strdup(cfg_parser->opt->region, $2);
748       size = __b64_pton($2, data, sizeof(data));
749       if(size == -1) {
750         yyerror("cannot base64 decode tsig secret %s",
751           cfg_parser->key->name?
752           cfg_parser->key->name:"");
753       } else if(size != 0) {
754         memset(data, 0xdd, size); /* wipe secret */
755       }
756     } ;
757 
758 
759 zone:
760     VAR_ZONE
761       {
762         assert(cfg_parser->pattern == NULL);
763         assert(cfg_parser->zone == NULL);
764         cfg_parser->zone = zone_options_create(cfg_parser->opt->region);
765         cfg_parser->zone->part_of_config = 1;
766         cfg_parser->zone->pattern = cfg_parser->pattern =
767           pattern_options_create(cfg_parser->opt->region);
768         cfg_parser->zone->pattern->implicit = 1;
769       }
770     zone_block
771     {
772       assert(cfg_parser->zone != NULL);
773       if(cfg_parser->zone->name == NULL) {
774         yyerror("zone has no name");
775       } else if(!nsd_options_insert_zone(cfg_parser->opt, cfg_parser->zone)) {
776         yyerror("duplicate zone %s", cfg_parser->zone->name);
777       } else if(!nsd_options_insert_pattern(cfg_parser->opt, cfg_parser->zone->pattern)) {
778         yyerror("duplicate pattern %s", cfg_parser->zone->pattern->pname);
779       }
780       cfg_parser->pattern = NULL;
781       cfg_parser->zone = NULL;
782     } ;
783 
784 zone_block:
785     zone_block zone_option | ;
786 
787 zone_option:
788     VAR_NAME STRING
789     {
790       const char *marker = PATTERN_IMPLICIT_MARKER;
791       char *pname = region_alloc(cfg_parser->opt->region, strlen($2) + strlen(marker) + 1);
792       memmove(pname, marker, strlen(marker));
793       memmove(pname + strlen(marker), $2, strlen($2) + 1);
794       cfg_parser->zone->pattern->pname = pname;
795       cfg_parser->zone->name = region_strdup(cfg_parser->opt->region, $2);
796       if(pattern_options_find(cfg_parser->opt, pname)) {
797         yyerror("zone %s cannot be created because implicit pattern %s "
798                     "already exists", $2, pname);
799       }
800     }
801   | pattern_or_zone_option ;
802 
803 pattern:
804     VAR_PATTERN
805       {
806         assert(cfg_parser->pattern == NULL);
807         cfg_parser->pattern = pattern_options_create(cfg_parser->opt->region);
808       }
809       pattern_block
810     {
811       pattern_options_type *pattern = cfg_parser->pattern;
812       if(pattern->pname == NULL) {
813         yyerror("pattern has no name");
814       } else if(!nsd_options_insert_pattern(cfg_parser->opt, pattern)) {
815         yyerror("duplicate pattern %s", pattern->pname);
816       }
817       cfg_parser->pattern = NULL;
818     } ;
819 
820 pattern_block:
821     pattern_block pattern_option | ;
822 
823 pattern_option:
824     VAR_NAME STRING
825     {
826       if(strchr($2, ' ')) {
827         yyerror("space is not allowed in pattern name: '%s'", $2);
828       }
829       cfg_parser->pattern->pname = region_strdup(cfg_parser->opt->region, $2);
830     }
831   | pattern_or_zone_option ;
832 
833 pattern_or_zone_option:
834     VAR_RRL_WHITELIST STRING
835     {
836 #ifdef RATELIMIT
837       cfg_parser->pattern->rrl_whitelist |= rrlstr2type($2);
838 #endif
839     }
840   | VAR_ZONEFILE STRING
841     { cfg_parser->pattern->zonefile = region_strdup(cfg_parser->opt->region, $2); }
842   | VAR_ZONESTATS STRING
843     { cfg_parser->pattern->zonestats = region_strdup(cfg_parser->opt->region, $2); }
844   | VAR_SIZE_LIMIT_XFR number
845     {
846       if($2 > 0) {
847         cfg_parser->pattern->size_limit_xfr = (int)$2;
848       } else {
849         yyerror("expected a number greater than zero");
850       }
851     }
852   | VAR_MULTI_MASTER_CHECK boolean
853     { cfg_parser->pattern->multi_master_check = (int)$2; }
854   | VAR_INCLUDE_PATTERN STRING
855     { config_apply_pattern(cfg_parser->pattern, $2); }
856   | VAR_REQUEST_XFR STRING STRING
857     {
858       acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, $2, $3);
859       if(acl->blocked)
860         yyerror("blocked address used for request-xfr");
861       if(acl->rangetype != acl_range_single)
862         yyerror("address range used for request-xfr");
863       append_acl(&cfg_parser->pattern->request_xfr, acl);
864     }
865 	tlsauth_option
866 	{ }
867   | VAR_REQUEST_XFR VAR_AXFR STRING STRING
868     {
869       acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, $3, $4);
870       acl->use_axfr_only = 1;
871       if(acl->blocked)
872         yyerror("blocked address used for request-xfr");
873       if(acl->rangetype != acl_range_single)
874         yyerror("address range used for request-xfr");
875       append_acl(&cfg_parser->pattern->request_xfr, acl);
876     }
877 	tlsauth_option
878 	{ }
879   | VAR_REQUEST_XFR VAR_UDP STRING STRING
880     {
881       acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, $3, $4);
882       acl->allow_udp = 1;
883       if(acl->blocked)
884         yyerror("blocked address used for request-xfr");
885       if(acl->rangetype != acl_range_single)
886         yyerror("address range used for request-xfr");
887       append_acl(&cfg_parser->pattern->request_xfr, acl);
888     }
889   | VAR_ALLOW_NOTIFY STRING STRING
890     {
891       acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, $2, $3);
892       append_acl(&cfg_parser->pattern->allow_notify, acl);
893     }
894   | VAR_NOTIFY STRING STRING
895     {
896       acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, $2, $3);
897       if(acl->blocked)
898         yyerror("blocked address used for notify");
899       if(acl->rangetype != acl_range_single)
900         yyerror("address range used for notify");
901       append_acl(&cfg_parser->pattern->notify, acl);
902     }
903   | VAR_PROVIDE_XFR STRING STRING
904     {
905       acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, $2, $3);
906       append_acl(&cfg_parser->pattern->provide_xfr, acl);
907     }
908   | VAR_ALLOW_QUERY STRING STRING
909     {
910       acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, $2, $3);
911       append_acl(&cfg_parser->pattern->allow_query, acl);
912     }
913   | VAR_OUTGOING_INTERFACE STRING
914     {
915       acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, $2, "NOKEY");
916       append_acl(&cfg_parser->pattern->outgoing_interface, acl);
917     }
918   | VAR_ALLOW_AXFR_FALLBACK boolean
919     {
920       cfg_parser->pattern->allow_axfr_fallback = $2;
921       cfg_parser->pattern->allow_axfr_fallback_is_default = 0;
922     }
923   | VAR_NOTIFY_RETRY number
924     {
925       cfg_parser->pattern->notify_retry = $2;
926       cfg_parser->pattern->notify_retry_is_default = 0;
927     }
928   | VAR_MAX_REFRESH_TIME number
929     {
930       cfg_parser->pattern->max_refresh_time = $2;
931       cfg_parser->pattern->max_refresh_time_is_default = 0;
932     }
933   | VAR_MIN_REFRESH_TIME number
934     {
935       cfg_parser->pattern->min_refresh_time = $2;
936       cfg_parser->pattern->min_refresh_time_is_default = 0;
937     }
938   | VAR_MAX_RETRY_TIME number
939     {
940       cfg_parser->pattern->max_retry_time = $2;
941       cfg_parser->pattern->max_retry_time_is_default = 0;
942     }
943   | VAR_MIN_RETRY_TIME number
944     {
945       cfg_parser->pattern->min_retry_time = $2;
946       cfg_parser->pattern->min_retry_time_is_default = 0;
947     }
948   | VAR_MIN_EXPIRE_TIME STRING
949     {
950       long long num;
951       uint8_t expr;
952 
953       if (!parse_expire_expr($2, &num, &expr)) {
954         yyerror("expected an expire time in seconds or \"refresh+retry+1\"");
955         YYABORT; /* trigger a parser error */
956       }
957       cfg_parser->pattern->min_expire_time = num;
958       cfg_parser->pattern->min_expire_time_expr = expr;
959     };
960 
961 ip_address:
962     STRING
963     {
964       struct ip_address_option *ip = region_alloc_zero(
965         cfg_parser->opt->region, sizeof(*ip));
966       ip->address = region_strdup(cfg_parser->opt->region, $1);
967       ip->fib = -1;
968       $$ = ip;
969     } ;
970 
971 number:
972     STRING
973     {
974       if(!parse_number($1, &$$)) {
975         yyerror("expected a number");
976         YYABORT; /* trigger a parser error */
977       }
978     } ;
979 
980 boolean:
981     STRING
982     {
983       if(!parse_boolean($1, &$$)) {
984         yyerror("expected yes or no");
985         YYABORT; /* trigger a parser error */
986       }
987     } ;
988 
989 tlsauth_option:
990 	| STRING
991 	{ char *tls_auth_name = region_strdup(cfg_parser->opt->region, $1);
992 	  add_to_last_acl(&cfg_parser->pattern->request_xfr, tls_auth_name);} ;
993 
994 %%
995 
996 static void
997 append_acl(struct acl_options **list, struct acl_options *acl)
998 {
999 	assert(list != NULL);
1000 
1001 	if(*list == NULL) {
1002 		*list = acl;
1003 	} else {
1004 		struct acl_options *tail = *list;
1005 		while(tail->next != NULL)
1006 			tail = tail->next;
1007 		tail->next = acl;
1008 	}
1009 }
1010 
1011 static void
1012 add_to_last_acl(struct acl_options **list, char *tls_auth_name)
1013 {
1014 	struct acl_options *tail = *list;
1015 	assert(list != NULL);
1016 	assert(*list != NULL);
1017 	while(tail->next != NULL)
1018 		tail = tail->next;
1019 	tail->tls_auth_name = tls_auth_name;
1020 }
1021 
1022 static int
1023 parse_boolean(const char *str, int *bln)
1024 {
1025 	if(strcmp(str, "yes") == 0) {
1026 		*bln = 1;
1027 	} else if(strcmp(str, "no") == 0) {
1028 		*bln = 0;
1029 	} else {
1030 		return 0;
1031 	}
1032 
1033 	return 1;
1034 }
1035 
1036 static int
1037 parse_expire_expr(const char *str, long long *num, uint8_t *expr)
1038 {
1039 	if(parse_number(str, num)) {
1040 		*expr = EXPIRE_TIME_HAS_VALUE;
1041 		return 1;
1042 	}
1043 	if(strcmp(str, REFRESHPLUSRETRYPLUS1_STR) == 0) {
1044 		*num = 0;
1045 		*expr = REFRESHPLUSRETRYPLUS1;
1046 		return 1;
1047 	}
1048 	return 0;
1049 }
1050 
1051 static int
1052 parse_number(const char *str, long long *num)
1053 {
1054 	/* ensure string consists entirely of digits */
1055 	size_t pos = 0;
1056 	while(str[pos] >= '0' && str[pos] <= '9') {
1057 		pos++;
1058 	}
1059 
1060 	if(pos != 0 && str[pos] == '\0') {
1061 		*num = strtoll(str, NULL, 10);
1062 		return 1;
1063 	}
1064 
1065 	return 0;
1066 }
1067 
1068 static int
1069 parse_range(const char *str, long long *low, long long *high)
1070 {
1071 	const char *ptr = str;
1072 	long long num[2];
1073 
1074 	/* require range to begin with a number */
1075 	if(*ptr < '0' || *ptr > '9') {
1076 		return 0;
1077 	}
1078 
1079 	num[0] = strtoll(ptr, (char **)&ptr, 10);
1080 
1081 	/* require number to be followed by nothing at all or a dash */
1082 	if(*ptr == '\0') {
1083 		*low = num[0];
1084 		*high = num[0];
1085 		return 1;
1086 	} else if(*ptr != '-') {
1087 		return 0;
1088 	}
1089 
1090 	++ptr;
1091 	/* require dash to be followed by a number */
1092 	if(*ptr < '0' || *ptr > '9') {
1093 		return 0;
1094 	}
1095 
1096 	num[1] = strtoll(ptr, (char **)&ptr, 10);
1097 
1098 	/* require number to be followed by nothing at all */
1099 	if(*ptr == '\0') {
1100 		if(num[0] < num[1]) {
1101 			*low = num[0];
1102 			*high = num[1];
1103 		} else {
1104 			*low = num[1];
1105 			*high = num[0];
1106 		}
1107 		return 1;
1108 	}
1109 
1110 	return 0;
1111 }
1112