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