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