xref: /openbsd/usr.sbin/nsd/configparser.y (revision efac4d30)
162ac0c33Sjakob /*
262ac0c33Sjakob  * configparser.y -- yacc grammar for NSD configuration files
362ac0c33Sjakob  *
45435475dSsthen  * Copyright (c) 2001-2019, NLnet Labs. All rights reserved.
562ac0c33Sjakob  *
662ac0c33Sjakob  * See LICENSE for the license.
762ac0c33Sjakob  *
862ac0c33Sjakob  */
962ac0c33Sjakob 
1062ac0c33Sjakob %{
11d11a62c8Ssthen #include "config.h"
1262ac0c33Sjakob 
135435475dSsthen #include <assert.h>
145435475dSsthen #include <errno.h>
1562ac0c33Sjakob #include <stdio.h>
1662ac0c33Sjakob #include <string.h>
1762ac0c33Sjakob 
1862ac0c33Sjakob #include "options.h"
19a8b34139Sjakob #include "util.h"
20dd5b221eSsthen #include "dname.h"
21dd5b221eSsthen #include "tsig.h"
2275343be4Ssthen #include "rrl.h"
235435475dSsthen 
245435475dSsthen int yylex(void);
2562ac0c33Sjakob 
2662ac0c33Sjakob #ifdef __cplusplus
2762ac0c33Sjakob extern "C"
285435475dSsthen #endif
2962ac0c33Sjakob 
3062ac0c33Sjakob /* these need to be global, otherwise they cannot be used inside yacc */
31fe5fe5f6Sflorian extern config_parser_state_type *cfg_parser;
3262ac0c33Sjakob 
335435475dSsthen static void append_acl(struct acl_options **list, struct acl_options *acl);
34063644e9Sflorian static void add_to_last_acl(struct acl_options **list, char *ac);
35308d2509Sflorian static int parse_boolean(const char *str, int *bln);
36ac5517e4Sflorian static int parse_expire_expr(const char *str, long long *num, uint8_t *expr);
37308d2509Sflorian static int parse_number(const char *str, long long *num);
38308d2509Sflorian static int parse_range(const char *str, long long *low, long long *high);
3962ac0c33Sjakob %}
405435475dSsthen 
4162ac0c33Sjakob %union {
4262ac0c33Sjakob   char *str;
435435475dSsthen   long long llng;
445435475dSsthen   int bln;
455435475dSsthen   struct ip_address_option *ip;
46308d2509Sflorian   struct range_option *range;
47308d2509Sflorian   struct cpu_option *cpu;
4862ac0c33Sjakob }
4962ac0c33Sjakob 
5062ac0c33Sjakob %token <str> STRING
515435475dSsthen %type <llng> number
525435475dSsthen %type <bln> boolean
535435475dSsthen %type <ip> ip_address
54308d2509Sflorian %type <llng> service_cpu_affinity
55308d2509Sflorian %type <cpu> cpus
565435475dSsthen 
575435475dSsthen /* server */
585435475dSsthen %token VAR_SERVER
595435475dSsthen %token VAR_SERVER_COUNT
605435475dSsthen %token VAR_IP_ADDRESS
615435475dSsthen %token VAR_IP_TRANSPARENT
625435475dSsthen %token VAR_IP_FREEBIND
635435475dSsthen %token VAR_REUSEPORT
645435475dSsthen %token VAR_SEND_BUFFER_SIZE
655435475dSsthen %token VAR_RECEIVE_BUFFER_SIZE
665435475dSsthen %token VAR_DEBUG_MODE
675435475dSsthen %token VAR_IP4_ONLY
685435475dSsthen %token VAR_IP6_ONLY
695435475dSsthen %token VAR_DO_IP4
705435475dSsthen %token VAR_DO_IP6
715435475dSsthen %token VAR_PORT
725435475dSsthen %token VAR_USE_SYSTEMD
735435475dSsthen %token VAR_VERBOSITY
745435475dSsthen %token VAR_USERNAME
755435475dSsthen %token VAR_CHROOT
765435475dSsthen %token VAR_ZONESDIR
775435475dSsthen %token VAR_ZONELISTFILE
785435475dSsthen %token VAR_DATABASE
795435475dSsthen %token VAR_LOGFILE
80ac5517e4Sflorian %token VAR_LOG_ONLY_SYSLOG
815435475dSsthen %token VAR_PIDFILE
825435475dSsthen %token VAR_DIFFFILE
835435475dSsthen %token VAR_XFRDFILE
845435475dSsthen %token VAR_XFRDIR
855435475dSsthen %token VAR_HIDE_VERSION
865435475dSsthen %token VAR_HIDE_IDENTITY
875435475dSsthen %token VAR_VERSION
885435475dSsthen %token VAR_IDENTITY
895435475dSsthen %token VAR_NSID
905435475dSsthen %token VAR_TCP_COUNT
91eab1363eSsthen %token VAR_TCP_REJECT_OVERFLOW
925435475dSsthen %token VAR_TCP_QUERY_COUNT
935435475dSsthen %token VAR_TCP_TIMEOUT
945435475dSsthen %token VAR_TCP_MSS
955435475dSsthen %token VAR_OUTGOING_TCP_MSS
965435475dSsthen %token VAR_IPV4_EDNS_SIZE
975435475dSsthen %token VAR_IPV6_EDNS_SIZE
985435475dSsthen %token VAR_STATISTICS
995435475dSsthen %token VAR_XFRD_RELOAD_TIMEOUT
1005435475dSsthen %token VAR_LOG_TIME_ASCII
1015435475dSsthen %token VAR_ROUND_ROBIN
1025435475dSsthen %token VAR_MINIMAL_RESPONSES
1035435475dSsthen %token VAR_CONFINE_TO_ZONE
1045435475dSsthen %token VAR_REFUSE_ANY
1055435475dSsthen %token VAR_ZONEFILES_CHECK
1065435475dSsthen %token VAR_ZONEFILES_WRITE
1075435475dSsthen %token VAR_RRL_SIZE
1085435475dSsthen %token VAR_RRL_RATELIMIT
1095435475dSsthen %token VAR_RRL_SLIP
1105435475dSsthen %token VAR_RRL_IPV4_PREFIX_LENGTH
1115435475dSsthen %token VAR_RRL_IPV6_PREFIX_LENGTH
1125435475dSsthen %token VAR_RRL_WHITELIST_RATELIMIT
1135435475dSsthen %token VAR_TLS_SERVICE_KEY
1145435475dSsthen %token VAR_TLS_SERVICE_PEM
1155435475dSsthen %token VAR_TLS_SERVICE_OCSP
1165435475dSsthen %token VAR_TLS_PORT
117063644e9Sflorian %token VAR_TLS_CERT_BUNDLE
118308d2509Sflorian %token VAR_CPU_AFFINITY
119308d2509Sflorian %token VAR_XFRD_CPU_AFFINITY
120308d2509Sflorian %token <llng> VAR_SERVER_CPU_AFFINITY
121308d2509Sflorian %token VAR_DROP_UPDATES
1225435475dSsthen 
1235435475dSsthen /* dnstap */
1245435475dSsthen %token VAR_DNSTAP
1255435475dSsthen %token VAR_DNSTAP_ENABLE
1265435475dSsthen %token VAR_DNSTAP_SOCKET_PATH
1275435475dSsthen %token VAR_DNSTAP_SEND_IDENTITY
1285435475dSsthen %token VAR_DNSTAP_SEND_VERSION
1295435475dSsthen %token VAR_DNSTAP_IDENTITY
1305435475dSsthen %token VAR_DNSTAP_VERSION
1315435475dSsthen %token VAR_DNSTAP_LOG_AUTH_QUERY_MESSAGES
1325435475dSsthen %token VAR_DNSTAP_LOG_AUTH_RESPONSE_MESSAGES
1335435475dSsthen 
1345435475dSsthen /* remote-control */
1355435475dSsthen %token VAR_REMOTE_CONTROL
1365435475dSsthen %token VAR_CONTROL_ENABLE
1375435475dSsthen %token VAR_CONTROL_INTERFACE
1385435475dSsthen %token VAR_CONTROL_PORT
1395435475dSsthen %token VAR_SERVER_KEY_FILE
1405435475dSsthen %token VAR_SERVER_CERT_FILE
1415435475dSsthen %token VAR_CONTROL_KEY_FILE
1425435475dSsthen %token VAR_CONTROL_CERT_FILE
1435435475dSsthen 
1445435475dSsthen /* key */
1455435475dSsthen %token VAR_KEY
1465435475dSsthen %token VAR_ALGORITHM
1475435475dSsthen %token VAR_SECRET
1485435475dSsthen 
149063644e9Sflorian /* xot auth */
150063644e9Sflorian %token VAR_TLS_AUTH
151063644e9Sflorian %token VAR_TLS_AUTH_DOMAIN_NAME
152a904e103Sflorian %token VAR_TLS_AUTH_CLIENT_CERT
153a904e103Sflorian %token VAR_TLS_AUTH_CLIENT_KEY
154a904e103Sflorian %token VAR_TLS_AUTH_CLIENT_KEY_PW
155063644e9Sflorian 
1565435475dSsthen /* pattern */
1575435475dSsthen %token VAR_PATTERN
1585435475dSsthen %token VAR_NAME
1595435475dSsthen %token VAR_ZONEFILE
1605435475dSsthen %token VAR_NOTIFY
1615435475dSsthen %token VAR_PROVIDE_XFR
1628d298c9fSsthen %token VAR_ALLOW_QUERY
1635435475dSsthen %token VAR_AXFR
1645435475dSsthen %token VAR_UDP
1655435475dSsthen %token VAR_NOTIFY_RETRY
1665435475dSsthen %token VAR_ALLOW_NOTIFY
1675435475dSsthen %token VAR_REQUEST_XFR
1685435475dSsthen %token VAR_ALLOW_AXFR_FALLBACK
1695435475dSsthen %token VAR_OUTGOING_INTERFACE
170063644e9Sflorian %token VAR_ANSWER_COOKIE
171063644e9Sflorian %token VAR_COOKIE_SECRET
172063644e9Sflorian %token VAR_COOKIE_SECRET_FILE
1735435475dSsthen %token VAR_MAX_REFRESH_TIME
1745435475dSsthen %token VAR_MIN_REFRESH_TIME
1755435475dSsthen %token VAR_MAX_RETRY_TIME
1765435475dSsthen %token VAR_MIN_RETRY_TIME
177ac5517e4Sflorian %token VAR_MIN_EXPIRE_TIME
1785435475dSsthen %token VAR_MULTI_MASTER_CHECK
1795435475dSsthen %token VAR_SIZE_LIMIT_XFR
1805435475dSsthen %token VAR_ZONESTATS
1815435475dSsthen %token VAR_INCLUDE_PATTERN
1825435475dSsthen 
1835435475dSsthen /* zone */
1845435475dSsthen %token VAR_ZONE
1855435475dSsthen %token VAR_RRL_WHITELIST
18662ac0c33Sjakob 
187308d2509Sflorian /* socket options */
188308d2509Sflorian %token VAR_SERVERS
189308d2509Sflorian %token VAR_BINDTODEVICE
190308d2509Sflorian %token VAR_SETFIB
191308d2509Sflorian 
19262ac0c33Sjakob %%
19362ac0c33Sjakob 
1945435475dSsthen blocks:
1955435475dSsthen     /* may be empty */
1965435475dSsthen   | blocks block ;
1975435475dSsthen 
1985435475dSsthen block:
1995435475dSsthen     server
2005435475dSsthen   | dnstap
2015435475dSsthen   | remote_control
2025435475dSsthen   | key
203063644e9Sflorian   | tls_auth
2045435475dSsthen   | pattern
2055435475dSsthen   | zone ;
2065435475dSsthen 
2075435475dSsthen server:
2085435475dSsthen     VAR_SERVER server_block ;
2095435475dSsthen 
2105435475dSsthen server_block:
2115435475dSsthen     server_block server_option | ;
2125435475dSsthen 
2135435475dSsthen server_option:
2145435475dSsthen     VAR_IP_ADDRESS ip_address
21562ac0c33Sjakob       {
2165435475dSsthen         struct ip_address_option *ip = cfg_parser->opt->ip_addresses;
217308d2509Sflorian 
2185435475dSsthen         if(ip == NULL) {
2195435475dSsthen           cfg_parser->opt->ip_addresses = $2;
22062ac0c33Sjakob         } else {
2215435475dSsthen           while(ip->next) { ip = ip->next; }
2225435475dSsthen           ip->next = $2;
22362ac0c33Sjakob         }
224308d2509Sflorian 
225308d2509Sflorian         cfg_parser->ip = $2;
226308d2509Sflorian       }
227308d2509Sflorian     socket_options
228308d2509Sflorian     {
229308d2509Sflorian       cfg_parser->ip = NULL;
23062ac0c33Sjakob     }
2315435475dSsthen   | VAR_SERVER_COUNT number
2329c620270Ssthen     {
2335435475dSsthen       if ($2 > 0) {
2345435475dSsthen         cfg_parser->opt->server_count = (int)$2;
2355435475dSsthen       } else {
2365435475dSsthen         yyerror("expected a number greater than zero");
2379c620270Ssthen       }
2385435475dSsthen     }
2395435475dSsthen   | VAR_IP_TRANSPARENT boolean
240308d2509Sflorian     { cfg_parser->opt->ip_transparent = $2; }
2415435475dSsthen   | VAR_IP_FREEBIND boolean
2425435475dSsthen     { cfg_parser->opt->ip_freebind = $2; }
2435435475dSsthen   | VAR_SEND_BUFFER_SIZE number
2445435475dSsthen     { cfg_parser->opt->send_buffer_size = (int)$2; }
2455435475dSsthen   | VAR_RECEIVE_BUFFER_SIZE number
2465435475dSsthen     { cfg_parser->opt->receive_buffer_size = (int)$2; }
2475435475dSsthen   | VAR_DEBUG_MODE boolean
2485435475dSsthen     { cfg_parser->opt->debug_mode = $2; }
2495435475dSsthen   | VAR_USE_SYSTEMD boolean
2505435475dSsthen     { /* ignored, deprecated */ }
2515435475dSsthen   | VAR_HIDE_VERSION boolean
2525435475dSsthen     { cfg_parser->opt->hide_version = $2; }
2535435475dSsthen   | VAR_HIDE_IDENTITY boolean
2545435475dSsthen     { cfg_parser->opt->hide_identity = $2; }
255308d2509Sflorian   | VAR_DROP_UPDATES boolean
256308d2509Sflorian     { cfg_parser->opt->drop_updates = $2; }
2575435475dSsthen   | VAR_IP4_ONLY boolean
2585435475dSsthen     { if($2) { cfg_parser->opt->do_ip4 = 1; cfg_parser->opt->do_ip6 = 0; } }
2595435475dSsthen   | VAR_IP6_ONLY boolean
2605435475dSsthen     { if($2) { cfg_parser->opt->do_ip4 = 0; cfg_parser->opt->do_ip6 = 1; } }
2615435475dSsthen   | VAR_DO_IP4 boolean
2625435475dSsthen     { cfg_parser->opt->do_ip4 = $2; }
2635435475dSsthen   | VAR_DO_IP6 boolean
2645435475dSsthen     { cfg_parser->opt->do_ip6 = $2; }
2655435475dSsthen   | VAR_DATABASE STRING
266275a8d89Sflorian     {
26762ac0c33Sjakob       cfg_parser->opt->database = region_strdup(cfg_parser->opt->region, $2);
268533110e2Sbrad       if(cfg_parser->opt->database[0] == 0 &&
269533110e2Sbrad          cfg_parser->opt->zonefiles_write == 0)
2705435475dSsthen       {
271533110e2Sbrad         cfg_parser->opt->zonefiles_write = ZONEFILES_WRITE_INTERVAL;
27262ac0c33Sjakob       }
27362ac0c33Sjakob     }
2745435475dSsthen   | VAR_IDENTITY STRING
2755435475dSsthen     { cfg_parser->opt->identity = region_strdup(cfg_parser->opt->region, $2); }
2765435475dSsthen   | VAR_VERSION STRING
2775435475dSsthen     { cfg_parser->opt->version = region_strdup(cfg_parser->opt->region, $2); }
2785435475dSsthen   | VAR_NSID STRING
279a8b34139Sjakob     {
280a8b34139Sjakob       unsigned char* nsid = 0;
2815435475dSsthen       size_t nsid_len = strlen($2);
282a8b34139Sjakob 
283a302926fSbrad       if (strncasecmp($2, "ascii_", 6) == 0) {
2845435475dSsthen         nsid_len -= 6; /* discard "ascii_" */
2858d8f1862Ssthen         if(nsid_len < 65535) {
286a302926fSbrad           cfg_parser->opt->nsid = region_alloc(cfg_parser->opt->region, nsid_len*2+1);
287a302926fSbrad           hex_ntop((uint8_t*)$2+6, nsid_len, (char*)cfg_parser->opt->nsid, nsid_len*2+1);
2885435475dSsthen         } else {
2898d8f1862Ssthen           yyerror("NSID too long");
2905435475dSsthen         }
2915435475dSsthen       } else if (nsid_len % 2 != 0) {
292a8b34139Sjakob         yyerror("the NSID must be a hex string of an even length.");
293a8b34139Sjakob       } else {
2945435475dSsthen         nsid_len = nsid_len / 2;
2958d8f1862Ssthen         if(nsid_len < 65535) {
296a8b34139Sjakob           nsid = xalloc(nsid_len);
2975435475dSsthen           if (hex_pton($2, nsid, nsid_len) == -1) {
298a8b34139Sjakob             yyerror("hex string cannot be parsed in NSID.");
2995435475dSsthen           } else {
300a8b34139Sjakob             cfg_parser->opt->nsid = region_strdup(cfg_parser->opt->region, $2);
3015435475dSsthen           }
302a8b34139Sjakob           free(nsid);
3035435475dSsthen         } else {
3048d8f1862Ssthen           yyerror("NSID too long");
305a8b34139Sjakob         }
306a8b34139Sjakob       }
30762ac0c33Sjakob     }
3085435475dSsthen   | VAR_LOGFILE STRING
3095435475dSsthen     { cfg_parser->opt->logfile = region_strdup(cfg_parser->opt->region, $2); }
310ac5517e4Sflorian   | VAR_LOG_ONLY_SYSLOG boolean
311ac5517e4Sflorian     { cfg_parser->opt->log_only_syslog = $2; }
3125435475dSsthen   | VAR_TCP_COUNT number
313533110e2Sbrad     {
3145435475dSsthen       if ($2 > 0) {
3155435475dSsthen         cfg_parser->opt->tcp_count = (int)$2;
3165435475dSsthen       } else {
3175435475dSsthen         yyerror("expected a number greater than zero");
3185435475dSsthen       }
3195435475dSsthen     }
3205435475dSsthen   | VAR_TCP_REJECT_OVERFLOW boolean
3215435475dSsthen     { cfg_parser->opt->tcp_reject_overflow = $2; }
3225435475dSsthen   | VAR_TCP_QUERY_COUNT number
3235435475dSsthen     { cfg_parser->opt->tcp_query_count = (int)$2; }
3245435475dSsthen   | VAR_TCP_TIMEOUT number
3255435475dSsthen     { cfg_parser->opt->tcp_timeout = (int)$2; }
3265435475dSsthen   | VAR_TCP_MSS number
3275435475dSsthen     { cfg_parser->opt->tcp_mss = (int)$2; }
3285435475dSsthen   | VAR_OUTGOING_TCP_MSS number
3295435475dSsthen     { cfg_parser->opt->outgoing_tcp_mss = (int)$2; }
3305435475dSsthen   | VAR_IPV4_EDNS_SIZE number
3315435475dSsthen     { cfg_parser->opt->ipv4_edns_size = (size_t)$2; }
3325435475dSsthen   | VAR_IPV6_EDNS_SIZE number
3335435475dSsthen     { cfg_parser->opt->ipv6_edns_size = (size_t)$2; }
3345435475dSsthen   | VAR_PIDFILE STRING
3355435475dSsthen     { cfg_parser->opt->pidfile = region_strdup(cfg_parser->opt->region, $2); }
3365435475dSsthen   | VAR_PORT number
3375435475dSsthen     {
3385435475dSsthen       /* port number, stored as a string */
3395435475dSsthen       char buf[16];
3405435475dSsthen       (void)snprintf(buf, sizeof(buf), "%lld", $2);
3415435475dSsthen       cfg_parser->opt->port = region_strdup(cfg_parser->opt->region, buf);
3425435475dSsthen     }
3435435475dSsthen   | VAR_REUSEPORT boolean
3445435475dSsthen     { cfg_parser->opt->reuseport = $2; }
3455435475dSsthen   | VAR_STATISTICS number
3465435475dSsthen     { cfg_parser->opt->statistics = (int)$2; }
3475435475dSsthen   | VAR_CHROOT STRING
3485435475dSsthen     { cfg_parser->opt->chroot = region_strdup(cfg_parser->opt->region, $2); }
3495435475dSsthen   | VAR_USERNAME STRING
3505435475dSsthen     { cfg_parser->opt->username = region_strdup(cfg_parser->opt->region, $2); }
3515435475dSsthen   | VAR_ZONESDIR STRING
3525435475dSsthen     { cfg_parser->opt->zonesdir = region_strdup(cfg_parser->opt->region, $2); }
3535435475dSsthen   | VAR_ZONELISTFILE STRING
3545435475dSsthen     { cfg_parser->opt->zonelistfile = region_strdup(cfg_parser->opt->region, $2); }
3555435475dSsthen   | VAR_DIFFFILE STRING
3565435475dSsthen     { /* ignored, deprecated */ }
3575435475dSsthen   | VAR_XFRDFILE STRING
3585435475dSsthen     { cfg_parser->opt->xfrdfile = region_strdup(cfg_parser->opt->region, $2); }
3595435475dSsthen   | VAR_XFRDIR STRING
3605435475dSsthen     { cfg_parser->opt->xfrdir = region_strdup(cfg_parser->opt->region, $2); }
3615435475dSsthen   | VAR_XFRD_RELOAD_TIMEOUT number
3625435475dSsthen     { cfg_parser->opt->xfrd_reload_timeout = (int)$2; }
3635435475dSsthen   | VAR_VERBOSITY number
3645435475dSsthen     { cfg_parser->opt->verbosity = (int)$2; }
3655435475dSsthen   | VAR_RRL_SIZE number
3665435475dSsthen     {
3675435475dSsthen #ifdef RATELIMIT
3685435475dSsthen       if ($2 > 0) {
3695435475dSsthen         cfg_parser->opt->rrl_size = (size_t)$2;
3705435475dSsthen       } else {
3715435475dSsthen         yyerror("expected a number greater than zero");
3725435475dSsthen       }
3735435475dSsthen #endif
3745435475dSsthen     }
3755435475dSsthen   | VAR_RRL_RATELIMIT number
3765435475dSsthen     {
3775435475dSsthen #ifdef RATELIMIT
3785435475dSsthen       cfg_parser->opt->rrl_ratelimit = (size_t)$2;
3795435475dSsthen #endif
3805435475dSsthen     }
3815435475dSsthen   | VAR_RRL_SLIP number
3825435475dSsthen     {
3835435475dSsthen #ifdef RATELIMIT
3845435475dSsthen       cfg_parser->opt->rrl_slip = (size_t)$2;
3855435475dSsthen #endif
3865435475dSsthen     }
3875435475dSsthen   | VAR_RRL_IPV4_PREFIX_LENGTH number
3885435475dSsthen     {
3895435475dSsthen #ifdef RATELIMIT
3905435475dSsthen       if ($2 > 32) {
3915435475dSsthen         yyerror("invalid IPv4 prefix length");
3925435475dSsthen       } else {
3935435475dSsthen         cfg_parser->opt->rrl_ipv4_prefix_length = (size_t)$2;
3945435475dSsthen       }
3955435475dSsthen #endif
3965435475dSsthen     }
3975435475dSsthen   | VAR_RRL_IPV6_PREFIX_LENGTH number
3985435475dSsthen     {
3995435475dSsthen #ifdef RATELIMIT
4005435475dSsthen       if ($2 > 64) {
4015435475dSsthen         yyerror("invalid IPv6 prefix length");
4025435475dSsthen       } else {
4035435475dSsthen         cfg_parser->opt->rrl_ipv6_prefix_length = (size_t)$2;
4045435475dSsthen       }
4055435475dSsthen #endif
4065435475dSsthen     }
4075435475dSsthen   | VAR_RRL_WHITELIST_RATELIMIT number
4085435475dSsthen     {
4095435475dSsthen #ifdef RATELIMIT
4105435475dSsthen       cfg_parser->opt->rrl_whitelist_ratelimit = (size_t)$2;
4115435475dSsthen #endif
4125435475dSsthen     }
4135435475dSsthen   | VAR_ZONEFILES_CHECK boolean
4145435475dSsthen     { cfg_parser->opt->zonefiles_check = $2; }
4155435475dSsthen   | VAR_ZONEFILES_WRITE number
4165435475dSsthen     { cfg_parser->opt->zonefiles_write = (int)$2; }
4175435475dSsthen   | VAR_LOG_TIME_ASCII boolean
4185435475dSsthen     {
4195435475dSsthen       cfg_parser->opt->log_time_ascii = $2;
420533110e2Sbrad       log_time_asc = cfg_parser->opt->log_time_ascii;
421533110e2Sbrad     }
4225435475dSsthen   | VAR_ROUND_ROBIN boolean
423533110e2Sbrad     {
4245435475dSsthen       cfg_parser->opt->round_robin = $2;
425533110e2Sbrad       round_robin = cfg_parser->opt->round_robin;
426533110e2Sbrad     }
4275435475dSsthen   | VAR_MINIMAL_RESPONSES boolean
428db7d0d02Sflorian     {
4295435475dSsthen       cfg_parser->opt->minimal_responses = $2;
430db7d0d02Sflorian       minimal_responses = cfg_parser->opt->minimal_responses;
431db7d0d02Sflorian     }
4325435475dSsthen   | VAR_CONFINE_TO_ZONE boolean
4335435475dSsthen     { cfg_parser->opt->confine_to_zone = $2; }
4345435475dSsthen   | VAR_REFUSE_ANY boolean
4355435475dSsthen     { cfg_parser->opt->refuse_any = $2; }
4365435475dSsthen   | VAR_TLS_SERVICE_KEY STRING
4375435475dSsthen     { cfg_parser->opt->tls_service_key = region_strdup(cfg_parser->opt->region, $2); }
4385435475dSsthen   | VAR_TLS_SERVICE_OCSP STRING
4395435475dSsthen     { cfg_parser->opt->tls_service_ocsp = region_strdup(cfg_parser->opt->region, $2); }
4405435475dSsthen   | VAR_TLS_SERVICE_PEM STRING
4415435475dSsthen     { cfg_parser->opt->tls_service_pem = region_strdup(cfg_parser->opt->region, $2); }
4425435475dSsthen   | VAR_TLS_PORT number
4435435475dSsthen     {
4445435475dSsthen       /* port number, stored as string */
4455435475dSsthen       char buf[16];
4465435475dSsthen       (void)snprintf(buf, sizeof(buf), "%lld", $2);
4475435475dSsthen       cfg_parser->opt->tls_port = region_strdup(cfg_parser->opt->region, buf);
448db7d0d02Sflorian     }
449063644e9Sflorian   | VAR_TLS_CERT_BUNDLE STRING
450063644e9Sflorian     { cfg_parser->opt->tls_cert_bundle = region_strdup(cfg_parser->opt->region, $2); }
451063644e9Sflorian   | VAR_ANSWER_COOKIE boolean
452063644e9Sflorian     { cfg_parser->opt->answer_cookie = $2; }
453063644e9Sflorian   | VAR_COOKIE_SECRET STRING
454063644e9Sflorian     { cfg_parser->opt->cookie_secret = region_strdup(cfg_parser->opt->region, $2); }
455063644e9Sflorian   | VAR_COOKIE_SECRET_FILE STRING
456063644e9Sflorian     { cfg_parser->opt->cookie_secret_file = region_strdup(cfg_parser->opt->region, $2); }
457308d2509Sflorian   | VAR_CPU_AFFINITY cpus
458308d2509Sflorian     {
459308d2509Sflorian       cfg_parser->opt->cpu_affinity = $2;
460308d2509Sflorian     }
461308d2509Sflorian   | service_cpu_affinity number
462308d2509Sflorian     {
463308d2509Sflorian       if($2 < 0) {
464308d2509Sflorian         yyerror("expected a non-negative number");
465308d2509Sflorian         YYABORT;
466308d2509Sflorian       } else {
467308d2509Sflorian         struct cpu_map_option *opt, *tail;
468308d2509Sflorian 
469308d2509Sflorian         opt = cfg_parser->opt->service_cpu_affinity;
470308d2509Sflorian         while(opt && opt->service != $1) { opt = opt->next; }
471308d2509Sflorian 
472308d2509Sflorian         if(opt) {
473308d2509Sflorian           opt->cpu = $2;
474308d2509Sflorian         } else {
475308d2509Sflorian           opt = region_alloc_zero(cfg_parser->opt->region, sizeof(*opt));
476308d2509Sflorian           opt->service = (int)$1;
477308d2509Sflorian           opt->cpu = (int)$2;
478308d2509Sflorian 
479308d2509Sflorian           tail = cfg_parser->opt->service_cpu_affinity;
480308d2509Sflorian           if(tail) {
481308d2509Sflorian             while(tail->next) { tail = tail->next; }
482308d2509Sflorian             tail->next = opt;
483308d2509Sflorian           } else {
484308d2509Sflorian             cfg_parser->opt->service_cpu_affinity = opt;
485308d2509Sflorian           }
486308d2509Sflorian         }
487308d2509Sflorian       }
488308d2509Sflorian     }
489308d2509Sflorian   ;
490308d2509Sflorian 
491308d2509Sflorian socket_options:
492308d2509Sflorian   | socket_options socket_option ;
493308d2509Sflorian 
494308d2509Sflorian socket_option:
495308d2509Sflorian     VAR_SERVERS STRING
496308d2509Sflorian     {
497308d2509Sflorian       char *tok, *ptr, *str;
498308d2509Sflorian       struct range_option *servers = NULL;
499308d2509Sflorian       long long first, last;
500308d2509Sflorian 
501308d2509Sflorian       /* user may specify "0 1", "0" "1", 0 1 or a combination thereof */
502308d2509Sflorian       for(str = $2; (tok = strtok_r(str, " \t", &ptr)); str = NULL) {
503308d2509Sflorian         struct range_option *opt =
504308d2509Sflorian           region_alloc(cfg_parser->opt->region, sizeof(*opt));
505308d2509Sflorian         first = last = 0;
506308d2509Sflorian         if(!parse_range(tok, &first, &last)) {
507308d2509Sflorian           yyerror("invalid server range '%s'", tok);
508308d2509Sflorian           YYABORT;
509308d2509Sflorian         }
510308d2509Sflorian         assert(first >= 0);
511308d2509Sflorian         assert(last >= 0);
512308d2509Sflorian         opt->next = NULL;
513308d2509Sflorian         opt->first = (int)first;
514308d2509Sflorian         opt->last = (int)last;
515308d2509Sflorian         if(servers) {
516308d2509Sflorian           servers = servers->next = opt;
517308d2509Sflorian         } else {
518308d2509Sflorian           servers = cfg_parser->ip->servers = opt;
519308d2509Sflorian         }
520308d2509Sflorian       }
521308d2509Sflorian     }
522308d2509Sflorian   | VAR_BINDTODEVICE boolean
523308d2509Sflorian     { cfg_parser->ip->dev = $2; }
524308d2509Sflorian   | VAR_SETFIB number
525308d2509Sflorian     { cfg_parser->ip->fib = $2; }
526308d2509Sflorian   ;
527308d2509Sflorian 
528308d2509Sflorian cpus:
529308d2509Sflorian     { $$ = NULL; }
530308d2509Sflorian   | cpus STRING
531308d2509Sflorian     {
532308d2509Sflorian       char *tok, *ptr, *str;
533308d2509Sflorian       struct cpu_option *tail;
534308d2509Sflorian       long long cpu;
535308d2509Sflorian 
536308d2509Sflorian       str = $2;
537308d2509Sflorian       $$ = tail = $1;
538308d2509Sflorian       if(tail) {
539308d2509Sflorian         while(tail->next) { tail = tail->next; }
540308d2509Sflorian       }
541308d2509Sflorian 
542308d2509Sflorian       /* Users may specify "0 1", "0" "1", 0 1 or a combination thereof. */
543308d2509Sflorian       for(str = $2; (tok = strtok_r(str, " \t", &ptr)); str = NULL) {
544308d2509Sflorian         struct cpu_option *opt =
545*efac4d30Sflorian           region_alloc_zero(cfg_parser->opt->region, sizeof(*opt));
546308d2509Sflorian         cpu = 0;
547*efac4d30Sflorian         if(!parse_number(tok, &cpu) || cpu < 0) {
548308d2509Sflorian           yyerror("expected a positive number");
549308d2509Sflorian           YYABORT;
550308d2509Sflorian         }
551308d2509Sflorian         assert(cpu >=0);
552308d2509Sflorian         opt->cpu = (int)cpu;
553308d2509Sflorian         if(tail) {
554308d2509Sflorian           tail->next = opt;
555308d2509Sflorian           tail = opt;
556308d2509Sflorian         } else {
557308d2509Sflorian           $$ = tail = opt;
558308d2509Sflorian         }
559308d2509Sflorian       }
560308d2509Sflorian     }
561308d2509Sflorian   ;
562308d2509Sflorian 
563308d2509Sflorian service_cpu_affinity:
564308d2509Sflorian     VAR_XFRD_CPU_AFFINITY
565308d2509Sflorian     { $$ = -1; }
566308d2509Sflorian   | VAR_SERVER_CPU_AFFINITY
567308d2509Sflorian     {
568308d2509Sflorian       if($1 <= 0) {
569308d2509Sflorian         yyerror("invalid server identifier");
570308d2509Sflorian         YYABORT;
571308d2509Sflorian       }
572308d2509Sflorian       $$ = $1;
573308d2509Sflorian     }
574db7d0d02Sflorian   ;
5755435475dSsthen 
5765435475dSsthen dnstap:
5775435475dSsthen     VAR_DNSTAP dnstap_block ;
5785435475dSsthen 
5795435475dSsthen dnstap_block:
5805435475dSsthen     dnstap_block dnstap_option | ;
5815435475dSsthen 
5825435475dSsthen dnstap_option:
5835435475dSsthen     VAR_DNSTAP_ENABLE boolean
5845435475dSsthen     { cfg_parser->opt->dnstap_enable = $2; }
5855435475dSsthen   | VAR_DNSTAP_SOCKET_PATH STRING
5865435475dSsthen     { cfg_parser->opt->dnstap_socket_path = region_strdup(cfg_parser->opt->region, $2); }
5875435475dSsthen   | VAR_DNSTAP_SEND_IDENTITY boolean
5885435475dSsthen     { cfg_parser->opt->dnstap_send_identity = $2; }
5895435475dSsthen   | VAR_DNSTAP_SEND_VERSION boolean
5905435475dSsthen     { cfg_parser->opt->dnstap_send_version = $2; }
5915435475dSsthen   | VAR_DNSTAP_IDENTITY STRING
5925435475dSsthen     { cfg_parser->opt->dnstap_identity = region_strdup(cfg_parser->opt->region, $2); }
5935435475dSsthen   | VAR_DNSTAP_VERSION STRING
5945435475dSsthen     { cfg_parser->opt->dnstap_version = region_strdup(cfg_parser->opt->region, $2); }
5955435475dSsthen   | VAR_DNSTAP_LOG_AUTH_QUERY_MESSAGES boolean
5965435475dSsthen     { cfg_parser->opt->dnstap_log_auth_query_messages = $2; }
5975435475dSsthen   | VAR_DNSTAP_LOG_AUTH_RESPONSE_MESSAGES boolean
5985435475dSsthen     { cfg_parser->opt->dnstap_log_auth_response_messages = $2; }
599bfd0b123Sflorian   ;
6005435475dSsthen 
6015435475dSsthen remote_control:
6025435475dSsthen     VAR_REMOTE_CONTROL remote_control_block ;
6035435475dSsthen 
6045435475dSsthen remote_control_block:
6055435475dSsthen     remote_control_block remote_control_option | ;
6065435475dSsthen 
6075435475dSsthen remote_control_option:
6085435475dSsthen     VAR_CONTROL_ENABLE boolean
6095435475dSsthen     { cfg_parser->opt->control_enable = $2; }
6105435475dSsthen   | VAR_CONTROL_INTERFACE ip_address
61162ac0c33Sjakob     {
6125435475dSsthen       struct ip_address_option *ip = cfg_parser->opt->control_interface;
6135435475dSsthen       if(ip == NULL) {
6145435475dSsthen         cfg_parser->opt->control_interface = $2;
615eab1363eSsthen       } else {
6165435475dSsthen         while(ip->next != NULL) { ip = ip->next; }
6175435475dSsthen         ip->next = $2;
618eab1363eSsthen       }
619eab1363eSsthen     }
6205435475dSsthen   | VAR_CONTROL_PORT number
62162ac0c33Sjakob     {
6225435475dSsthen       if($2 == 0) {
623dd5b221eSsthen         yyerror("control port number expected");
6245435475dSsthen       } else {
6255435475dSsthen         cfg_parser->opt->control_port = (int)$2;
626dd5b221eSsthen       }
627dd5b221eSsthen     }
6285435475dSsthen   | VAR_SERVER_KEY_FILE STRING
6295435475dSsthen     { cfg_parser->opt->server_key_file = region_strdup(cfg_parser->opt->region, $2); }
6305435475dSsthen   | VAR_SERVER_CERT_FILE STRING
6315435475dSsthen     { cfg_parser->opt->server_cert_file = region_strdup(cfg_parser->opt->region, $2); }
6325435475dSsthen   | VAR_CONTROL_KEY_FILE STRING
6335435475dSsthen     { cfg_parser->opt->control_key_file = region_strdup(cfg_parser->opt->region, $2); }
6345435475dSsthen   | VAR_CONTROL_CERT_FILE STRING
6355435475dSsthen     { cfg_parser->opt->control_cert_file = region_strdup(cfg_parser->opt->region, $2); }
636dd5b221eSsthen   ;
637dd5b221eSsthen 
638063644e9Sflorian tls_auth:
639063644e9Sflorian     VAR_TLS_AUTH
640063644e9Sflorian       {
641063644e9Sflorian         tls_auth_options_type *tls_auth = tls_auth_options_create(cfg_parser->opt->region);
642063644e9Sflorian         assert(cfg_parser->tls_auth == NULL);
643063644e9Sflorian         cfg_parser->tls_auth = tls_auth;
644063644e9Sflorian       }
645063644e9Sflorian       tls_auth_block
646063644e9Sflorian     {
647063644e9Sflorian       struct tls_auth_options *tls_auth = cfg_parser->tls_auth;
648063644e9Sflorian       if(tls_auth->name == NULL) {
649063644e9Sflorian         yyerror("tls-auth has no name");
650063644e9Sflorian       } else if(tls_auth->auth_domain_name == NULL) {
651063644e9Sflorian         yyerror("tls-auth %s has no auth-domain-name", tls_auth->name);
652063644e9Sflorian       } else if(tls_auth_options_find(cfg_parser->opt, tls_auth->name)) {
653063644e9Sflorian         yyerror("duplicate tls-auth %s", tls_auth->name);
654063644e9Sflorian       } else {
655063644e9Sflorian       	tls_auth_options_insert(cfg_parser->opt, tls_auth);
656063644e9Sflorian         cfg_parser->tls_auth = NULL;
657063644e9Sflorian       }
658063644e9Sflorian     } ;
659063644e9Sflorian 
660063644e9Sflorian tls_auth_block:
661063644e9Sflorian     tls_auth_block tls_auth_option | ;
662063644e9Sflorian 
663063644e9Sflorian tls_auth_option:
664063644e9Sflorian     VAR_NAME STRING
665063644e9Sflorian     {
666063644e9Sflorian       dname_type *dname;
667063644e9Sflorian       dname = (dname_type *)dname_parse(cfg_parser->opt->region, $2);
668063644e9Sflorian       cfg_parser->tls_auth->name = region_strdup(cfg_parser->opt->region, $2);
669063644e9Sflorian       if(dname == NULL) {
670063644e9Sflorian         yyerror("bad tls-auth name %s", $2);
671063644e9Sflorian       } else {
672063644e9Sflorian         region_recycle(cfg_parser->opt->region, dname, dname_total_size(dname));
673063644e9Sflorian       }
674063644e9Sflorian     }
675063644e9Sflorian   | VAR_TLS_AUTH_DOMAIN_NAME STRING
676063644e9Sflorian     {
677063644e9Sflorian       cfg_parser->tls_auth->auth_domain_name = region_strdup(cfg_parser->opt->region, $2);
678a904e103Sflorian     }
679a904e103Sflorian   | VAR_TLS_AUTH_CLIENT_CERT STRING
680a904e103Sflorian     {
681a904e103Sflorian 	    cfg_parser->tls_auth->client_cert = region_strdup(cfg_parser->opt->region, $2);
682a904e103Sflorian     }
683a904e103Sflorian   | VAR_TLS_AUTH_CLIENT_KEY STRING
684a904e103Sflorian     {
685a904e103Sflorian 	    cfg_parser->tls_auth->client_key = region_strdup(cfg_parser->opt->region, $2);
686a904e103Sflorian     }
687a904e103Sflorian   | VAR_TLS_AUTH_CLIENT_KEY_PW STRING
688a904e103Sflorian     {
689a904e103Sflorian 	    cfg_parser->tls_auth->client_key_pw = region_strdup(cfg_parser->opt->region, $2);
690a904e103Sflorian     }
691a904e103Sflorian   ;
692063644e9Sflorian 
6935435475dSsthen key:
6945435475dSsthen     VAR_KEY
695e02bc0dfSflorian       {
6965435475dSsthen         key_options_type *key = key_options_create(cfg_parser->opt->region);
6975435475dSsthen         key->algorithm = region_strdup(cfg_parser->opt->region, "sha256");
6985435475dSsthen         assert(cfg_parser->key == NULL);
6995435475dSsthen         cfg_parser->key = key;
700e02bc0dfSflorian       }
7015435475dSsthen       key_block
702e02bc0dfSflorian     {
7035435475dSsthen       struct key_options *key = cfg_parser->key;
7045435475dSsthen       if(key->name == NULL) {
7055435475dSsthen         yyerror("tsig key has no name");
7065435475dSsthen       } else if(key->algorithm == NULL) {
7075435475dSsthen         yyerror("tsig key %s has no algorithm", key->name);
7085435475dSsthen       } else if(key->secret == NULL) {
7095435475dSsthen         yyerror("tsig key %s has no secret blob", key->name);
7105435475dSsthen       } else if(key_options_find(cfg_parser->opt, key->name)) {
7115435475dSsthen         yyerror("duplicate tsig key %s", key->name);
7125435475dSsthen       } else {
7135435475dSsthen         key_options_insert(cfg_parser->opt, key);
7145435475dSsthen         cfg_parser->key = NULL;
715e02bc0dfSflorian       }
7165435475dSsthen     } ;
717e02bc0dfSflorian 
7185435475dSsthen key_block:
7195435475dSsthen     key_block key_option | ;
72062ac0c33Sjakob 
7215435475dSsthen key_option:
7225435475dSsthen     VAR_NAME STRING
72362ac0c33Sjakob     {
7245435475dSsthen       dname_type *dname;
72562ac0c33Sjakob 
7265435475dSsthen       dname = (dname_type *)dname_parse(cfg_parser->opt->region, $2);
7275435475dSsthen       cfg_parser->key->name = region_strdup(cfg_parser->opt->region, $2);
7285435475dSsthen       if(dname == NULL) {
7295435475dSsthen         yyerror("bad tsig key name %s", $2);
7305435475dSsthen       } else {
7315435475dSsthen         region_recycle(cfg_parser->opt->region, dname, dname_total_size(dname));
7325435475dSsthen       }
7335435475dSsthen     }
7345435475dSsthen   | VAR_ALGORITHM STRING
73562ac0c33Sjakob     {
7365435475dSsthen       if(tsig_get_algorithm_by_name($2) == NULL) {
7375435475dSsthen         yyerror("bad tsig key algorithm %s", $2);
7385435475dSsthen       } else {
7395435475dSsthen         cfg_parser->key->algorithm = region_strdup(cfg_parser->opt->region, $2);
74062ac0c33Sjakob       }
74162ac0c33Sjakob     }
7425435475dSsthen   | VAR_SECRET STRING
74362ac0c33Sjakob     {
744dd5b221eSsthen       uint8_t data[16384];
745dd5b221eSsthen       int size;
7465435475dSsthen 
7475435475dSsthen       cfg_parser->key->secret = region_strdup(cfg_parser->opt->region, $2);
74872628ec9Ssthen       size = __b64_pton($2, data, sizeof(data));
749dd5b221eSsthen       if(size == -1) {
7505435475dSsthen         yyerror("cannot base64 decode tsig secret %s",
7515435475dSsthen           cfg_parser->key->name?
7525435475dSsthen           cfg_parser->key->name:"");
753dd5b221eSsthen       } else if(size != 0) {
754dd5b221eSsthen         memset(data, 0xdd, size); /* wipe secret */
755dd5b221eSsthen       }
7565435475dSsthen     } ;
7575435475dSsthen 
7585435475dSsthen 
7595435475dSsthen zone:
7605435475dSsthen     VAR_ZONE
7615435475dSsthen       {
7625435475dSsthen         assert(cfg_parser->pattern == NULL);
7635435475dSsthen         assert(cfg_parser->zone == NULL);
7645435475dSsthen         cfg_parser->zone = zone_options_create(cfg_parser->opt->region);
7655435475dSsthen         cfg_parser->zone->part_of_config = 1;
7665435475dSsthen         cfg_parser->zone->pattern = cfg_parser->pattern =
7675435475dSsthen           pattern_options_create(cfg_parser->opt->region);
7685435475dSsthen         cfg_parser->zone->pattern->implicit = 1;
76962ac0c33Sjakob       }
7705435475dSsthen     zone_block
7715435475dSsthen     {
7725435475dSsthen       assert(cfg_parser->zone != NULL);
7735435475dSsthen       if(cfg_parser->zone->name == NULL) {
7745435475dSsthen         yyerror("zone has no name");
7755435475dSsthen       } else if(!nsd_options_insert_zone(cfg_parser->opt, cfg_parser->zone)) {
7765435475dSsthen         yyerror("duplicate zone %s", cfg_parser->zone->name);
7775435475dSsthen       } else if(!nsd_options_insert_pattern(cfg_parser->opt, cfg_parser->zone->pattern)) {
7785435475dSsthen         yyerror("duplicate pattern %s", cfg_parser->zone->pattern->pname);
7795435475dSsthen       }
7805435475dSsthen       cfg_parser->pattern = NULL;
7815435475dSsthen       cfg_parser->zone = NULL;
7825435475dSsthen     } ;
7835435475dSsthen 
7845435475dSsthen zone_block:
7855435475dSsthen     zone_block zone_option | ;
7865435475dSsthen 
7875435475dSsthen zone_option:
7885435475dSsthen     VAR_NAME STRING
7895435475dSsthen     {
7905435475dSsthen       const char *marker = PATTERN_IMPLICIT_MARKER;
7915435475dSsthen       char *pname = region_alloc(cfg_parser->opt->region, strlen($2) + strlen(marker) + 1);
7925435475dSsthen       memmove(pname, marker, strlen(marker));
7935435475dSsthen       memmove(pname + strlen(marker), $2, strlen($2) + 1);
7945435475dSsthen       cfg_parser->zone->pattern->pname = pname;
7955435475dSsthen       cfg_parser->zone->name = region_strdup(cfg_parser->opt->region, $2);
7965435475dSsthen       if(pattern_options_find(cfg_parser->opt, pname)) {
7975435475dSsthen         yyerror("zone %s cannot be created because implicit pattern %s "
7985435475dSsthen                     "already exists", $2, pname);
7995435475dSsthen       }
8005435475dSsthen     }
8015435475dSsthen   | pattern_or_zone_option ;
8025435475dSsthen 
8035435475dSsthen pattern:
8045435475dSsthen     VAR_PATTERN
8055435475dSsthen       {
8065435475dSsthen         assert(cfg_parser->pattern == NULL);
8075435475dSsthen         cfg_parser->pattern = pattern_options_create(cfg_parser->opt->region);
8085435475dSsthen       }
8095435475dSsthen       pattern_block
8105435475dSsthen     {
8115435475dSsthen       pattern_options_type *pattern = cfg_parser->pattern;
8125435475dSsthen       if(pattern->pname == NULL) {
8135435475dSsthen         yyerror("pattern has no name");
8145435475dSsthen       } else if(!nsd_options_insert_pattern(cfg_parser->opt, pattern)) {
8155435475dSsthen         yyerror("duplicate pattern %s", pattern->pname);
8165435475dSsthen       }
8175435475dSsthen       cfg_parser->pattern = NULL;
8185435475dSsthen     } ;
8195435475dSsthen 
8205435475dSsthen pattern_block:
8215435475dSsthen     pattern_block pattern_option | ;
8225435475dSsthen 
8235435475dSsthen pattern_option:
8245435475dSsthen     VAR_NAME STRING
8255435475dSsthen     {
8265435475dSsthen       if(strchr($2, ' ')) {
8275435475dSsthen         yyerror("space is not allowed in pattern name: '%s'", $2);
8285435475dSsthen       }
8295435475dSsthen       cfg_parser->pattern->pname = region_strdup(cfg_parser->opt->region, $2);
8305435475dSsthen     }
8315435475dSsthen   | pattern_or_zone_option ;
8325435475dSsthen 
8335435475dSsthen pattern_or_zone_option:
8345435475dSsthen     VAR_RRL_WHITELIST STRING
8355435475dSsthen     {
8365435475dSsthen #ifdef RATELIMIT
8375435475dSsthen       cfg_parser->pattern->rrl_whitelist |= rrlstr2type($2);
8385435475dSsthen #endif
8395435475dSsthen     }
8405435475dSsthen   | VAR_ZONEFILE STRING
8415435475dSsthen     { cfg_parser->pattern->zonefile = region_strdup(cfg_parser->opt->region, $2); }
8425435475dSsthen   | VAR_ZONESTATS STRING
8435435475dSsthen     { cfg_parser->pattern->zonestats = region_strdup(cfg_parser->opt->region, $2); }
8445435475dSsthen   | VAR_SIZE_LIMIT_XFR number
8455435475dSsthen     {
8465435475dSsthen       if($2 > 0) {
8475435475dSsthen         cfg_parser->pattern->size_limit_xfr = (int)$2;
8485435475dSsthen       } else {
8495435475dSsthen         yyerror("expected a number greater than zero");
8505435475dSsthen       }
8515435475dSsthen     }
8525435475dSsthen   | VAR_MULTI_MASTER_CHECK boolean
8535435475dSsthen     { cfg_parser->pattern->multi_master_check = (int)$2; }
8545435475dSsthen   | VAR_INCLUDE_PATTERN STRING
8555435475dSsthen     { config_apply_pattern(cfg_parser->pattern, $2); }
8565435475dSsthen   | VAR_REQUEST_XFR STRING STRING
8575435475dSsthen     {
8585435475dSsthen       acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, $2, $3);
8595435475dSsthen       if(acl->blocked)
8605435475dSsthen         yyerror("blocked address used for request-xfr");
8615435475dSsthen       if(acl->rangetype != acl_range_single)
8625435475dSsthen         yyerror("address range used for request-xfr");
8635435475dSsthen       append_acl(&cfg_parser->pattern->request_xfr, acl);
8645435475dSsthen     }
865063644e9Sflorian 	tlsauth_option
866063644e9Sflorian 	{ }
8675435475dSsthen   | VAR_REQUEST_XFR VAR_AXFR STRING STRING
8685435475dSsthen     {
8695435475dSsthen       acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, $3, $4);
8705435475dSsthen       acl->use_axfr_only = 1;
8715435475dSsthen       if(acl->blocked)
8725435475dSsthen         yyerror("blocked address used for request-xfr");
8735435475dSsthen       if(acl->rangetype != acl_range_single)
8745435475dSsthen         yyerror("address range used for request-xfr");
8755435475dSsthen       append_acl(&cfg_parser->pattern->request_xfr, acl);
8765435475dSsthen     }
877063644e9Sflorian 	tlsauth_option
878063644e9Sflorian 	{ }
8795435475dSsthen   | VAR_REQUEST_XFR VAR_UDP STRING STRING
8805435475dSsthen     {
8815435475dSsthen       acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, $3, $4);
8825435475dSsthen       acl->allow_udp = 1;
8835435475dSsthen       if(acl->blocked)
8845435475dSsthen         yyerror("blocked address used for request-xfr");
8855435475dSsthen       if(acl->rangetype != acl_range_single)
8865435475dSsthen         yyerror("address range used for request-xfr");
8875435475dSsthen       append_acl(&cfg_parser->pattern->request_xfr, acl);
8885435475dSsthen     }
8895435475dSsthen   | VAR_ALLOW_NOTIFY STRING STRING
8905435475dSsthen     {
8915435475dSsthen       acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, $2, $3);
8925435475dSsthen       append_acl(&cfg_parser->pattern->allow_notify, acl);
8935435475dSsthen     }
8945435475dSsthen   | VAR_NOTIFY STRING STRING
8955435475dSsthen     {
8965435475dSsthen       acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, $2, $3);
8975435475dSsthen       if(acl->blocked)
8985435475dSsthen         yyerror("blocked address used for notify");
8995435475dSsthen       if(acl->rangetype != acl_range_single)
9005435475dSsthen         yyerror("address range used for notify");
9015435475dSsthen       append_acl(&cfg_parser->pattern->notify, acl);
9025435475dSsthen     }
9035435475dSsthen   | VAR_PROVIDE_XFR STRING STRING
9045435475dSsthen     {
9055435475dSsthen       acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, $2, $3);
9065435475dSsthen       append_acl(&cfg_parser->pattern->provide_xfr, acl);
9075435475dSsthen     }
9088d298c9fSsthen   | VAR_ALLOW_QUERY STRING STRING
9098d298c9fSsthen     {
9108d298c9fSsthen       acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, $2, $3);
9118d298c9fSsthen       append_acl(&cfg_parser->pattern->allow_query, acl);
9128d298c9fSsthen     }
9135435475dSsthen   | VAR_OUTGOING_INTERFACE STRING
9145435475dSsthen     {
9155435475dSsthen       acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, $2, "NOKEY");
9165435475dSsthen       append_acl(&cfg_parser->pattern->outgoing_interface, acl);
9175435475dSsthen     }
9185435475dSsthen   | VAR_ALLOW_AXFR_FALLBACK boolean
9195435475dSsthen     {
9205435475dSsthen       cfg_parser->pattern->allow_axfr_fallback = $2;
9215435475dSsthen       cfg_parser->pattern->allow_axfr_fallback_is_default = 0;
9225435475dSsthen     }
9235435475dSsthen   | VAR_NOTIFY_RETRY number
9245435475dSsthen     {
9255435475dSsthen       cfg_parser->pattern->notify_retry = $2;
9265435475dSsthen       cfg_parser->pattern->notify_retry_is_default = 0;
9275435475dSsthen     }
9285435475dSsthen   | VAR_MAX_REFRESH_TIME number
9295435475dSsthen     {
9305435475dSsthen       cfg_parser->pattern->max_refresh_time = $2;
9315435475dSsthen       cfg_parser->pattern->max_refresh_time_is_default = 0;
9325435475dSsthen     }
9335435475dSsthen   | VAR_MIN_REFRESH_TIME number
9345435475dSsthen     {
9355435475dSsthen       cfg_parser->pattern->min_refresh_time = $2;
9365435475dSsthen       cfg_parser->pattern->min_refresh_time_is_default = 0;
9375435475dSsthen     }
9385435475dSsthen   | VAR_MAX_RETRY_TIME number
9395435475dSsthen     {
9405435475dSsthen       cfg_parser->pattern->max_retry_time = $2;
9415435475dSsthen       cfg_parser->pattern->max_retry_time_is_default = 0;
9425435475dSsthen     }
9435435475dSsthen   | VAR_MIN_RETRY_TIME number
9445435475dSsthen     {
9455435475dSsthen       cfg_parser->pattern->min_retry_time = $2;
9465435475dSsthen       cfg_parser->pattern->min_retry_time_is_default = 0;
947ac5517e4Sflorian     }
948ac5517e4Sflorian   | VAR_MIN_EXPIRE_TIME STRING
949ac5517e4Sflorian     {
950ac5517e4Sflorian       long long num;
951ac5517e4Sflorian       uint8_t expr;
952ac5517e4Sflorian 
953ac5517e4Sflorian       if (!parse_expire_expr($2, &num, &expr)) {
954ac5517e4Sflorian         yyerror("expected an expire time in seconds or \"refresh+retry+1\"");
955ac5517e4Sflorian         YYABORT; /* trigger a parser error */
956ac5517e4Sflorian       }
957ac5517e4Sflorian       cfg_parser->pattern->min_expire_time = num;
958ac5517e4Sflorian       cfg_parser->pattern->min_expire_time_expr = expr;
9595435475dSsthen     };
9605435475dSsthen 
9615435475dSsthen ip_address:
9625435475dSsthen     STRING
9635435475dSsthen     {
9645435475dSsthen       struct ip_address_option *ip = region_alloc_zero(
9655435475dSsthen         cfg_parser->opt->region, sizeof(*ip));
9665435475dSsthen       ip->address = region_strdup(cfg_parser->opt->region, $1);
967308d2509Sflorian       ip->fib = -1;
9685435475dSsthen       $$ = ip;
9695435475dSsthen     } ;
9705435475dSsthen 
9715435475dSsthen number:
9725435475dSsthen     STRING
9735435475dSsthen     {
974308d2509Sflorian       if(!parse_number($1, &$$)) {
9755435475dSsthen         yyerror("expected a number");
9765435475dSsthen         YYABORT; /* trigger a parser error */
9775435475dSsthen       }
9785435475dSsthen     } ;
9795435475dSsthen 
9805435475dSsthen boolean:
9815435475dSsthen     STRING
9825435475dSsthen     {
983308d2509Sflorian       if(!parse_boolean($1, &$$)) {
9845435475dSsthen         yyerror("expected yes or no");
9855435475dSsthen         YYABORT; /* trigger a parser error */
9865435475dSsthen       }
9875435475dSsthen     } ;
98862ac0c33Sjakob 
989063644e9Sflorian tlsauth_option:
990063644e9Sflorian 	| STRING
991063644e9Sflorian 	{ char *tls_auth_name = region_strdup(cfg_parser->opt->region, $1);
992063644e9Sflorian 	  add_to_last_acl(&cfg_parser->pattern->request_xfr, tls_auth_name);} ;
993063644e9Sflorian 
99462ac0c33Sjakob %%
99562ac0c33Sjakob 
9965435475dSsthen static void
9975435475dSsthen append_acl(struct acl_options **list, struct acl_options *acl)
9985435475dSsthen {
9995435475dSsthen 	assert(list != NULL);
10005435475dSsthen 
10015435475dSsthen 	if(*list == NULL) {
10025435475dSsthen 		*list = acl;
10035435475dSsthen 	} else {
10045435475dSsthen 		struct acl_options *tail = *list;
10055435475dSsthen 		while(tail->next != NULL)
10065435475dSsthen 			tail = tail->next;
10075435475dSsthen 		tail->next = acl;
10085435475dSsthen 	}
10095435475dSsthen }
10105435475dSsthen 
1011063644e9Sflorian static void
1012063644e9Sflorian add_to_last_acl(struct acl_options **list, char *tls_auth_name)
1013063644e9Sflorian {
1014063644e9Sflorian 	struct acl_options *tail = *list;
1015063644e9Sflorian 	assert(list != NULL);
1016063644e9Sflorian 	assert(*list != NULL);
1017063644e9Sflorian 	while(tail->next != NULL)
1018063644e9Sflorian 		tail = tail->next;
1019063644e9Sflorian 	tail->tls_auth_name = tls_auth_name;
1020063644e9Sflorian }
1021063644e9Sflorian 
1022308d2509Sflorian static int
1023308d2509Sflorian parse_boolean(const char *str, int *bln)
1024308d2509Sflorian {
1025308d2509Sflorian 	if(strcmp(str, "yes") == 0) {
1026308d2509Sflorian 		*bln = 1;
1027308d2509Sflorian 	} else if(strcmp(str, "no") == 0) {
1028308d2509Sflorian 		*bln = 0;
1029308d2509Sflorian 	} else {
1030308d2509Sflorian 		return 0;
1031308d2509Sflorian 	}
1032308d2509Sflorian 
1033308d2509Sflorian 	return 1;
1034308d2509Sflorian }
1035308d2509Sflorian 
1036308d2509Sflorian static int
1037ac5517e4Sflorian parse_expire_expr(const char *str, long long *num, uint8_t *expr)
1038ac5517e4Sflorian {
1039ac5517e4Sflorian 	if(parse_number(str, num)) {
1040ac5517e4Sflorian 		*expr = EXPIRE_TIME_HAS_VALUE;
1041ac5517e4Sflorian 		return 1;
1042ac5517e4Sflorian 	}
1043ac5517e4Sflorian 	if(strcmp(str, REFRESHPLUSRETRYPLUS1_STR) == 0) {
1044ac5517e4Sflorian 		*num = 0;
1045ac5517e4Sflorian 		*expr = REFRESHPLUSRETRYPLUS1;
1046ac5517e4Sflorian 		return 1;
1047ac5517e4Sflorian 	}
1048ac5517e4Sflorian 	return 0;
1049ac5517e4Sflorian }
1050ac5517e4Sflorian 
1051ac5517e4Sflorian static int
1052308d2509Sflorian parse_number(const char *str, long long *num)
1053308d2509Sflorian {
1054308d2509Sflorian 	/* ensure string consists entirely of digits */
1055308d2509Sflorian 	size_t pos = 0;
1056308d2509Sflorian 	while(str[pos] >= '0' && str[pos] <= '9') {
1057308d2509Sflorian 		pos++;
1058308d2509Sflorian 	}
1059308d2509Sflorian 
1060308d2509Sflorian 	if(pos != 0 && str[pos] == '\0') {
1061308d2509Sflorian 		*num = strtoll(str, NULL, 10);
1062308d2509Sflorian 		return 1;
1063308d2509Sflorian 	}
1064308d2509Sflorian 
1065308d2509Sflorian 	return 0;
1066308d2509Sflorian }
1067308d2509Sflorian 
1068308d2509Sflorian static int
1069308d2509Sflorian parse_range(const char *str, long long *low, long long *high)
1070308d2509Sflorian {
1071308d2509Sflorian 	const char *ptr = str;
1072308d2509Sflorian 	long long num[2];
1073308d2509Sflorian 
1074308d2509Sflorian 	/* require range to begin with a number */
1075308d2509Sflorian 	if(*ptr < '0' || *ptr > '9') {
1076308d2509Sflorian 		return 0;
1077308d2509Sflorian 	}
1078308d2509Sflorian 
1079308d2509Sflorian 	num[0] = strtoll(ptr, (char **)&ptr, 10);
1080308d2509Sflorian 
1081308d2509Sflorian 	/* require number to be followed by nothing at all or a dash */
1082308d2509Sflorian 	if(*ptr == '\0') {
1083308d2509Sflorian 		*low = num[0];
1084308d2509Sflorian 		*high = num[0];
1085308d2509Sflorian 		return 1;
1086308d2509Sflorian 	} else if(*ptr != '-') {
1087308d2509Sflorian 		return 0;
1088308d2509Sflorian 	}
1089308d2509Sflorian 
1090308d2509Sflorian 	++ptr;
1091308d2509Sflorian 	/* require dash to be followed by a number */
1092308d2509Sflorian 	if(*ptr < '0' || *ptr > '9') {
1093308d2509Sflorian 		return 0;
1094308d2509Sflorian 	}
1095308d2509Sflorian 
1096308d2509Sflorian 	num[1] = strtoll(ptr, (char **)&ptr, 10);
1097308d2509Sflorian 
1098308d2509Sflorian 	/* require number to be followed by nothing at all */
1099308d2509Sflorian 	if(*ptr == '\0') {
1100308d2509Sflorian 		if(num[0] < num[1]) {
1101308d2509Sflorian 			*low = num[0];
1102308d2509Sflorian 			*high = num[1];
1103308d2509Sflorian 		} else {
1104308d2509Sflorian 			*low = num[1];
1105308d2509Sflorian 			*high = num[0];
1106308d2509Sflorian 		}
1107308d2509Sflorian 		return 1;
1108308d2509Sflorian 	}
1109308d2509Sflorian 
1110308d2509Sflorian 	return 0;
1111308d2509Sflorian }
1112