xref: /openbsd/usr.sbin/nsd/configparser.y (revision bf87c3c0)
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);
36*bf87c3c0Sflorian static int parse_catalog_role(const char *str, int *role);
37ac5517e4Sflorian static int parse_expire_expr(const char *str, long long *num, uint8_t *expr);
38308d2509Sflorian static int parse_number(const char *str, long long *num);
39308d2509Sflorian static int parse_range(const char *str, long long *low, long long *high);
403f21e8ccSflorian 
413f21e8ccSflorian struct component {
423f21e8ccSflorian 	struct component *next;
433f21e8ccSflorian 	char *str;
443f21e8ccSflorian };
453f21e8ccSflorian 
4662ac0c33Sjakob %}
475435475dSsthen 
4862ac0c33Sjakob %union {
4962ac0c33Sjakob   char *str;
505435475dSsthen   long long llng;
515435475dSsthen   int bln;
525435475dSsthen   struct ip_address_option *ip;
53308d2509Sflorian   struct range_option *range;
54308d2509Sflorian   struct cpu_option *cpu;
553f21e8ccSflorian   char **strv;
563f21e8ccSflorian   struct component *comp;
57*bf87c3c0Sflorian   int role;
5862ac0c33Sjakob }
5962ac0c33Sjakob 
6062ac0c33Sjakob %token <str> STRING
615435475dSsthen %type <llng> number
625435475dSsthen %type <bln> boolean
635435475dSsthen %type <ip> ip_address
64308d2509Sflorian %type <llng> service_cpu_affinity
65308d2509Sflorian %type <cpu> cpus
663f21e8ccSflorian %type <strv> command
673f21e8ccSflorian %type <comp> arguments
68*bf87c3c0Sflorian %type <role> catalog_role
695435475dSsthen 
705435475dSsthen /* server */
715435475dSsthen %token VAR_SERVER
725435475dSsthen %token VAR_SERVER_COUNT
735435475dSsthen %token VAR_IP_ADDRESS
745435475dSsthen %token VAR_IP_TRANSPARENT
755435475dSsthen %token VAR_IP_FREEBIND
765435475dSsthen %token VAR_REUSEPORT
775435475dSsthen %token VAR_SEND_BUFFER_SIZE
785435475dSsthen %token VAR_RECEIVE_BUFFER_SIZE
795435475dSsthen %token VAR_DEBUG_MODE
805435475dSsthen %token VAR_IP4_ONLY
815435475dSsthen %token VAR_IP6_ONLY
825435475dSsthen %token VAR_DO_IP4
835435475dSsthen %token VAR_DO_IP6
845435475dSsthen %token VAR_PORT
855435475dSsthen %token VAR_USE_SYSTEMD
865435475dSsthen %token VAR_VERBOSITY
875435475dSsthen %token VAR_USERNAME
885435475dSsthen %token VAR_CHROOT
895435475dSsthen %token VAR_ZONESDIR
905435475dSsthen %token VAR_ZONELISTFILE
915435475dSsthen %token VAR_DATABASE
925435475dSsthen %token VAR_LOGFILE
93ac5517e4Sflorian %token VAR_LOG_ONLY_SYSLOG
945435475dSsthen %token VAR_PIDFILE
955435475dSsthen %token VAR_DIFFFILE
965435475dSsthen %token VAR_XFRDFILE
975435475dSsthen %token VAR_XFRDIR
985435475dSsthen %token VAR_HIDE_VERSION
995435475dSsthen %token VAR_HIDE_IDENTITY
1005435475dSsthen %token VAR_VERSION
1015435475dSsthen %token VAR_IDENTITY
1025435475dSsthen %token VAR_NSID
1035435475dSsthen %token VAR_TCP_COUNT
104eab1363eSsthen %token VAR_TCP_REJECT_OVERFLOW
1055435475dSsthen %token VAR_TCP_QUERY_COUNT
1065435475dSsthen %token VAR_TCP_TIMEOUT
1075435475dSsthen %token VAR_TCP_MSS
1085435475dSsthen %token VAR_OUTGOING_TCP_MSS
1095435475dSsthen %token VAR_IPV4_EDNS_SIZE
1105435475dSsthen %token VAR_IPV6_EDNS_SIZE
1115435475dSsthen %token VAR_STATISTICS
1125435475dSsthen %token VAR_XFRD_RELOAD_TIMEOUT
1135435475dSsthen %token VAR_LOG_TIME_ASCII
1145435475dSsthen %token VAR_ROUND_ROBIN
1155435475dSsthen %token VAR_MINIMAL_RESPONSES
1165435475dSsthen %token VAR_CONFINE_TO_ZONE
1175435475dSsthen %token VAR_REFUSE_ANY
1185435475dSsthen %token VAR_ZONEFILES_CHECK
1195435475dSsthen %token VAR_ZONEFILES_WRITE
1205435475dSsthen %token VAR_RRL_SIZE
1215435475dSsthen %token VAR_RRL_RATELIMIT
1225435475dSsthen %token VAR_RRL_SLIP
1235435475dSsthen %token VAR_RRL_IPV4_PREFIX_LENGTH
1245435475dSsthen %token VAR_RRL_IPV6_PREFIX_LENGTH
1255435475dSsthen %token VAR_RRL_WHITELIST_RATELIMIT
1265435475dSsthen %token VAR_TLS_SERVICE_KEY
1275435475dSsthen %token VAR_TLS_SERVICE_PEM
1285435475dSsthen %token VAR_TLS_SERVICE_OCSP
1295435475dSsthen %token VAR_TLS_PORT
130063644e9Sflorian %token VAR_TLS_CERT_BUNDLE
131b71395eaSflorian %token VAR_PROXY_PROTOCOL_PORT
132308d2509Sflorian %token VAR_CPU_AFFINITY
133308d2509Sflorian %token VAR_XFRD_CPU_AFFINITY
134308d2509Sflorian %token <llng> VAR_SERVER_CPU_AFFINITY
135308d2509Sflorian %token VAR_DROP_UPDATES
136bc6311d7Sflorian %token VAR_XFRD_TCP_MAX
137bc6311d7Sflorian %token VAR_XFRD_TCP_PIPELINE
1385435475dSsthen 
1395435475dSsthen /* dnstap */
1405435475dSsthen %token VAR_DNSTAP
1415435475dSsthen %token VAR_DNSTAP_ENABLE
1425435475dSsthen %token VAR_DNSTAP_SOCKET_PATH
1433efee2e1Sflorian %token VAR_DNSTAP_IP
1443efee2e1Sflorian %token VAR_DNSTAP_TLS
1453efee2e1Sflorian %token VAR_DNSTAP_TLS_SERVER_NAME
1463efee2e1Sflorian %token VAR_DNSTAP_TLS_CERT_BUNDLE
1473efee2e1Sflorian %token VAR_DNSTAP_TLS_CLIENT_KEY_FILE
1483efee2e1Sflorian %token VAR_DNSTAP_TLS_CLIENT_CERT_FILE
1495435475dSsthen %token VAR_DNSTAP_SEND_IDENTITY
1505435475dSsthen %token VAR_DNSTAP_SEND_VERSION
1515435475dSsthen %token VAR_DNSTAP_IDENTITY
1525435475dSsthen %token VAR_DNSTAP_VERSION
1535435475dSsthen %token VAR_DNSTAP_LOG_AUTH_QUERY_MESSAGES
1545435475dSsthen %token VAR_DNSTAP_LOG_AUTH_RESPONSE_MESSAGES
1555435475dSsthen 
1565435475dSsthen /* remote-control */
1575435475dSsthen %token VAR_REMOTE_CONTROL
1585435475dSsthen %token VAR_CONTROL_ENABLE
1595435475dSsthen %token VAR_CONTROL_INTERFACE
1605435475dSsthen %token VAR_CONTROL_PORT
1615435475dSsthen %token VAR_SERVER_KEY_FILE
1625435475dSsthen %token VAR_SERVER_CERT_FILE
1635435475dSsthen %token VAR_CONTROL_KEY_FILE
1645435475dSsthen %token VAR_CONTROL_CERT_FILE
1655435475dSsthen 
1665435475dSsthen /* key */
1675435475dSsthen %token VAR_KEY
1685435475dSsthen %token VAR_ALGORITHM
1695435475dSsthen %token VAR_SECRET
1705435475dSsthen 
171063644e9Sflorian /* xot auth */
172063644e9Sflorian %token VAR_TLS_AUTH
173063644e9Sflorian %token VAR_TLS_AUTH_DOMAIN_NAME
174a904e103Sflorian %token VAR_TLS_AUTH_CLIENT_CERT
175a904e103Sflorian %token VAR_TLS_AUTH_CLIENT_KEY
176a904e103Sflorian %token VAR_TLS_AUTH_CLIENT_KEY_PW
177063644e9Sflorian 
1785435475dSsthen /* pattern */
1795435475dSsthen %token VAR_PATTERN
1805435475dSsthen %token VAR_NAME
1815435475dSsthen %token VAR_ZONEFILE
1825435475dSsthen %token VAR_NOTIFY
1835435475dSsthen %token VAR_PROVIDE_XFR
1848d298c9fSsthen %token VAR_ALLOW_QUERY
1855435475dSsthen %token VAR_AXFR
1865435475dSsthen %token VAR_UDP
1875435475dSsthen %token VAR_NOTIFY_RETRY
1885435475dSsthen %token VAR_ALLOW_NOTIFY
1895435475dSsthen %token VAR_REQUEST_XFR
1905435475dSsthen %token VAR_ALLOW_AXFR_FALLBACK
1915435475dSsthen %token VAR_OUTGOING_INTERFACE
192063644e9Sflorian %token VAR_ANSWER_COOKIE
193063644e9Sflorian %token VAR_COOKIE_SECRET
194063644e9Sflorian %token VAR_COOKIE_SECRET_FILE
1955435475dSsthen %token VAR_MAX_REFRESH_TIME
1965435475dSsthen %token VAR_MIN_REFRESH_TIME
1975435475dSsthen %token VAR_MAX_RETRY_TIME
1985435475dSsthen %token VAR_MIN_RETRY_TIME
199ac5517e4Sflorian %token VAR_MIN_EXPIRE_TIME
200*bf87c3c0Sflorian %token VAR_MULTI_PRIMARY_CHECK
2015435475dSsthen %token VAR_SIZE_LIMIT_XFR
2025435475dSsthen %token VAR_ZONESTATS
2035435475dSsthen %token VAR_INCLUDE_PATTERN
2044564029fSflorian %token VAR_STORE_IXFR
2054564029fSflorian %token VAR_IXFR_SIZE
2064564029fSflorian %token VAR_IXFR_NUMBER
2074564029fSflorian %token VAR_CREATE_IXFR
208*bf87c3c0Sflorian %token VAR_CATALOG
209*bf87c3c0Sflorian %token VAR_CATALOG_MEMBER_PATTERN
210*bf87c3c0Sflorian %token VAR_CATALOG_PRODUCER_ZONE
2115435475dSsthen 
2125435475dSsthen /* zone */
2135435475dSsthen %token VAR_ZONE
2145435475dSsthen %token VAR_RRL_WHITELIST
21562ac0c33Sjakob 
216308d2509Sflorian /* socket options */
217308d2509Sflorian %token VAR_SERVERS
218308d2509Sflorian %token VAR_BINDTODEVICE
219308d2509Sflorian %token VAR_SETFIB
220308d2509Sflorian 
2213f21e8ccSflorian /* verify */
2223f21e8ccSflorian %token VAR_VERIFY
2233f21e8ccSflorian %token VAR_ENABLE
2243f21e8ccSflorian %token VAR_VERIFY_ZONE
2253f21e8ccSflorian %token VAR_VERIFY_ZONES
2263f21e8ccSflorian %token VAR_VERIFIER
2273f21e8ccSflorian %token VAR_VERIFIER_COUNT
2283f21e8ccSflorian %token VAR_VERIFIER_FEED_ZONE
2293f21e8ccSflorian %token VAR_VERIFIER_TIMEOUT
2303f21e8ccSflorian 
23162ac0c33Sjakob %%
23262ac0c33Sjakob 
2335435475dSsthen blocks:
2345435475dSsthen     /* may be empty */
2355435475dSsthen   | blocks block ;
2365435475dSsthen 
2375435475dSsthen block:
2385435475dSsthen     server
2395435475dSsthen   | dnstap
2405435475dSsthen   | remote_control
2415435475dSsthen   | key
242063644e9Sflorian   | tls_auth
2435435475dSsthen   | pattern
2443f21e8ccSflorian   | zone
2453f21e8ccSflorian   | verify ;
2465435475dSsthen 
2475435475dSsthen server:
2485435475dSsthen     VAR_SERVER server_block ;
2495435475dSsthen 
2505435475dSsthen server_block:
2515435475dSsthen     server_block server_option | ;
2525435475dSsthen 
2535435475dSsthen server_option:
2545435475dSsthen     VAR_IP_ADDRESS ip_address
25562ac0c33Sjakob       {
2565435475dSsthen         struct ip_address_option *ip = cfg_parser->opt->ip_addresses;
257308d2509Sflorian 
2585435475dSsthen         if(ip == NULL) {
2595435475dSsthen           cfg_parser->opt->ip_addresses = $2;
26062ac0c33Sjakob         } else {
2615435475dSsthen           while(ip->next) { ip = ip->next; }
2625435475dSsthen           ip->next = $2;
26362ac0c33Sjakob         }
264308d2509Sflorian 
265308d2509Sflorian         cfg_parser->ip = $2;
266308d2509Sflorian       }
267308d2509Sflorian     socket_options
268308d2509Sflorian     {
269308d2509Sflorian       cfg_parser->ip = NULL;
27062ac0c33Sjakob     }
2715435475dSsthen   | VAR_SERVER_COUNT number
2729c620270Ssthen     {
2735435475dSsthen       if ($2 > 0) {
2745435475dSsthen         cfg_parser->opt->server_count = (int)$2;
2755435475dSsthen       } else {
2765435475dSsthen         yyerror("expected a number greater than zero");
2779c620270Ssthen       }
2785435475dSsthen     }
2795435475dSsthen   | VAR_IP_TRANSPARENT boolean
280308d2509Sflorian     { cfg_parser->opt->ip_transparent = $2; }
2815435475dSsthen   | VAR_IP_FREEBIND boolean
2825435475dSsthen     { cfg_parser->opt->ip_freebind = $2; }
2835435475dSsthen   | VAR_SEND_BUFFER_SIZE number
2845435475dSsthen     { cfg_parser->opt->send_buffer_size = (int)$2; }
2855435475dSsthen   | VAR_RECEIVE_BUFFER_SIZE number
2865435475dSsthen     { cfg_parser->opt->receive_buffer_size = (int)$2; }
2875435475dSsthen   | VAR_DEBUG_MODE boolean
2885435475dSsthen     { cfg_parser->opt->debug_mode = $2; }
2895435475dSsthen   | VAR_USE_SYSTEMD boolean
290b71395eaSflorian     { /* ignored, obsolete */ }
2915435475dSsthen   | VAR_HIDE_VERSION boolean
2925435475dSsthen     { cfg_parser->opt->hide_version = $2; }
2935435475dSsthen   | VAR_HIDE_IDENTITY boolean
2945435475dSsthen     { cfg_parser->opt->hide_identity = $2; }
295308d2509Sflorian   | VAR_DROP_UPDATES boolean
296308d2509Sflorian     { cfg_parser->opt->drop_updates = $2; }
2975435475dSsthen   | VAR_IP4_ONLY boolean
2985435475dSsthen     { if($2) { cfg_parser->opt->do_ip4 = 1; cfg_parser->opt->do_ip6 = 0; } }
2995435475dSsthen   | VAR_IP6_ONLY boolean
3005435475dSsthen     { if($2) { cfg_parser->opt->do_ip4 = 0; cfg_parser->opt->do_ip6 = 1; } }
3015435475dSsthen   | VAR_DO_IP4 boolean
3025435475dSsthen     { cfg_parser->opt->do_ip4 = $2; }
3035435475dSsthen   | VAR_DO_IP6 boolean
3045435475dSsthen     { cfg_parser->opt->do_ip6 = $2; }
3055435475dSsthen   | VAR_DATABASE STRING
306b71395eaSflorian     { /* ignored, obsolete */ }
3075435475dSsthen   | VAR_IDENTITY STRING
3085435475dSsthen     { cfg_parser->opt->identity = region_strdup(cfg_parser->opt->region, $2); }
3095435475dSsthen   | VAR_VERSION STRING
3105435475dSsthen     { cfg_parser->opt->version = region_strdup(cfg_parser->opt->region, $2); }
3115435475dSsthen   | VAR_NSID STRING
312a8b34139Sjakob     {
313a8b34139Sjakob       unsigned char* nsid = 0;
3145435475dSsthen       size_t nsid_len = strlen($2);
315a8b34139Sjakob 
316a302926fSbrad       if (strncasecmp($2, "ascii_", 6) == 0) {
3175435475dSsthen         nsid_len -= 6; /* discard "ascii_" */
3188d8f1862Ssthen         if(nsid_len < 65535) {
319a302926fSbrad           cfg_parser->opt->nsid = region_alloc(cfg_parser->opt->region, nsid_len*2+1);
320a302926fSbrad           hex_ntop((uint8_t*)$2+6, nsid_len, (char*)cfg_parser->opt->nsid, nsid_len*2+1);
3215435475dSsthen         } else {
3228d8f1862Ssthen           yyerror("NSID too long");
3235435475dSsthen         }
3245435475dSsthen       } else if (nsid_len % 2 != 0) {
325a8b34139Sjakob         yyerror("the NSID must be a hex string of an even length.");
326a8b34139Sjakob       } else {
3275435475dSsthen         nsid_len = nsid_len / 2;
3288d8f1862Ssthen         if(nsid_len < 65535) {
329a8b34139Sjakob           nsid = xalloc(nsid_len);
3305435475dSsthen           if (hex_pton($2, nsid, nsid_len) == -1) {
331a8b34139Sjakob             yyerror("hex string cannot be parsed in NSID.");
3325435475dSsthen           } else {
333a8b34139Sjakob             cfg_parser->opt->nsid = region_strdup(cfg_parser->opt->region, $2);
3345435475dSsthen           }
335a8b34139Sjakob           free(nsid);
3365435475dSsthen         } else {
3378d8f1862Ssthen           yyerror("NSID too long");
338a8b34139Sjakob         }
339a8b34139Sjakob       }
34062ac0c33Sjakob     }
3415435475dSsthen   | VAR_LOGFILE STRING
3425435475dSsthen     { cfg_parser->opt->logfile = region_strdup(cfg_parser->opt->region, $2); }
343ac5517e4Sflorian   | VAR_LOG_ONLY_SYSLOG boolean
344ac5517e4Sflorian     { cfg_parser->opt->log_only_syslog = $2; }
3455435475dSsthen   | VAR_TCP_COUNT number
346533110e2Sbrad     {
3475435475dSsthen       if ($2 > 0) {
3485435475dSsthen         cfg_parser->opt->tcp_count = (int)$2;
3495435475dSsthen       } else {
3505435475dSsthen         yyerror("expected a number greater than zero");
3515435475dSsthen       }
3525435475dSsthen     }
3535435475dSsthen   | VAR_TCP_REJECT_OVERFLOW boolean
3545435475dSsthen     { cfg_parser->opt->tcp_reject_overflow = $2; }
3555435475dSsthen   | VAR_TCP_QUERY_COUNT number
3565435475dSsthen     { cfg_parser->opt->tcp_query_count = (int)$2; }
3575435475dSsthen   | VAR_TCP_TIMEOUT number
3585435475dSsthen     { cfg_parser->opt->tcp_timeout = (int)$2; }
3595435475dSsthen   | VAR_TCP_MSS number
3605435475dSsthen     { cfg_parser->opt->tcp_mss = (int)$2; }
3615435475dSsthen   | VAR_OUTGOING_TCP_MSS number
3625435475dSsthen     { cfg_parser->opt->outgoing_tcp_mss = (int)$2; }
3635435475dSsthen   | VAR_IPV4_EDNS_SIZE number
3645435475dSsthen     { cfg_parser->opt->ipv4_edns_size = (size_t)$2; }
3655435475dSsthen   | VAR_IPV6_EDNS_SIZE number
3665435475dSsthen     { cfg_parser->opt->ipv6_edns_size = (size_t)$2; }
3675435475dSsthen   | VAR_PIDFILE STRING
3685435475dSsthen     { cfg_parser->opt->pidfile = region_strdup(cfg_parser->opt->region, $2); }
3695435475dSsthen   | VAR_PORT number
3705435475dSsthen     {
3715435475dSsthen       /* port number, stored as a string */
3725435475dSsthen       char buf[16];
3735435475dSsthen       (void)snprintf(buf, sizeof(buf), "%lld", $2);
3745435475dSsthen       cfg_parser->opt->port = region_strdup(cfg_parser->opt->region, buf);
3755435475dSsthen     }
3765435475dSsthen   | VAR_REUSEPORT boolean
3775435475dSsthen     { cfg_parser->opt->reuseport = $2; }
3785435475dSsthen   | VAR_STATISTICS number
3795435475dSsthen     { cfg_parser->opt->statistics = (int)$2; }
3805435475dSsthen   | VAR_CHROOT STRING
3815435475dSsthen     { cfg_parser->opt->chroot = region_strdup(cfg_parser->opt->region, $2); }
3825435475dSsthen   | VAR_USERNAME STRING
3835435475dSsthen     { cfg_parser->opt->username = region_strdup(cfg_parser->opt->region, $2); }
3845435475dSsthen   | VAR_ZONESDIR STRING
3855435475dSsthen     { cfg_parser->opt->zonesdir = region_strdup(cfg_parser->opt->region, $2); }
3865435475dSsthen   | VAR_ZONELISTFILE STRING
3875435475dSsthen     { cfg_parser->opt->zonelistfile = region_strdup(cfg_parser->opt->region, $2); }
3885435475dSsthen   | VAR_DIFFFILE STRING
389b71395eaSflorian     { /* ignored, obsolete */ }
3905435475dSsthen   | VAR_XFRDFILE STRING
3915435475dSsthen     { cfg_parser->opt->xfrdfile = region_strdup(cfg_parser->opt->region, $2); }
3925435475dSsthen   | VAR_XFRDIR STRING
3935435475dSsthen     { cfg_parser->opt->xfrdir = region_strdup(cfg_parser->opt->region, $2); }
3945435475dSsthen   | VAR_XFRD_RELOAD_TIMEOUT number
3955435475dSsthen     { cfg_parser->opt->xfrd_reload_timeout = (int)$2; }
3965435475dSsthen   | VAR_VERBOSITY number
3975435475dSsthen     { cfg_parser->opt->verbosity = (int)$2; }
3985435475dSsthen   | VAR_RRL_SIZE number
3995435475dSsthen     {
4005435475dSsthen #ifdef RATELIMIT
4015435475dSsthen       if ($2 > 0) {
4025435475dSsthen         cfg_parser->opt->rrl_size = (size_t)$2;
4035435475dSsthen       } else {
4045435475dSsthen         yyerror("expected a number greater than zero");
4055435475dSsthen       }
4065435475dSsthen #endif
4075435475dSsthen     }
4085435475dSsthen   | VAR_RRL_RATELIMIT number
4095435475dSsthen     {
4105435475dSsthen #ifdef RATELIMIT
4115435475dSsthen       cfg_parser->opt->rrl_ratelimit = (size_t)$2;
4125435475dSsthen #endif
4135435475dSsthen     }
4145435475dSsthen   | VAR_RRL_SLIP number
4155435475dSsthen     {
4165435475dSsthen #ifdef RATELIMIT
4175435475dSsthen       cfg_parser->opt->rrl_slip = (size_t)$2;
4185435475dSsthen #endif
4195435475dSsthen     }
4205435475dSsthen   | VAR_RRL_IPV4_PREFIX_LENGTH number
4215435475dSsthen     {
4225435475dSsthen #ifdef RATELIMIT
4235435475dSsthen       if ($2 > 32) {
4245435475dSsthen         yyerror("invalid IPv4 prefix length");
4255435475dSsthen       } else {
4265435475dSsthen         cfg_parser->opt->rrl_ipv4_prefix_length = (size_t)$2;
4275435475dSsthen       }
4285435475dSsthen #endif
4295435475dSsthen     }
4305435475dSsthen   | VAR_RRL_IPV6_PREFIX_LENGTH number
4315435475dSsthen     {
4325435475dSsthen #ifdef RATELIMIT
4335435475dSsthen       if ($2 > 64) {
4345435475dSsthen         yyerror("invalid IPv6 prefix length");
4355435475dSsthen       } else {
4365435475dSsthen         cfg_parser->opt->rrl_ipv6_prefix_length = (size_t)$2;
4375435475dSsthen       }
4385435475dSsthen #endif
4395435475dSsthen     }
4405435475dSsthen   | VAR_RRL_WHITELIST_RATELIMIT number
4415435475dSsthen     {
4425435475dSsthen #ifdef RATELIMIT
4435435475dSsthen       cfg_parser->opt->rrl_whitelist_ratelimit = (size_t)$2;
4445435475dSsthen #endif
4455435475dSsthen     }
4465435475dSsthen   | VAR_ZONEFILES_CHECK boolean
4475435475dSsthen     { cfg_parser->opt->zonefiles_check = $2; }
4485435475dSsthen   | VAR_ZONEFILES_WRITE number
4495435475dSsthen     { cfg_parser->opt->zonefiles_write = (int)$2; }
4505435475dSsthen   | VAR_LOG_TIME_ASCII boolean
4515435475dSsthen     {
4525435475dSsthen       cfg_parser->opt->log_time_ascii = $2;
453533110e2Sbrad       log_time_asc = cfg_parser->opt->log_time_ascii;
454533110e2Sbrad     }
4555435475dSsthen   | VAR_ROUND_ROBIN boolean
456533110e2Sbrad     {
4575435475dSsthen       cfg_parser->opt->round_robin = $2;
458533110e2Sbrad       round_robin = cfg_parser->opt->round_robin;
459533110e2Sbrad     }
4605435475dSsthen   | VAR_MINIMAL_RESPONSES boolean
461db7d0d02Sflorian     {
4625435475dSsthen       cfg_parser->opt->minimal_responses = $2;
463db7d0d02Sflorian       minimal_responses = cfg_parser->opt->minimal_responses;
464db7d0d02Sflorian     }
4655435475dSsthen   | VAR_CONFINE_TO_ZONE boolean
4665435475dSsthen     { cfg_parser->opt->confine_to_zone = $2; }
4675435475dSsthen   | VAR_REFUSE_ANY boolean
4685435475dSsthen     { cfg_parser->opt->refuse_any = $2; }
4695435475dSsthen   | VAR_TLS_SERVICE_KEY STRING
4705435475dSsthen     { cfg_parser->opt->tls_service_key = region_strdup(cfg_parser->opt->region, $2); }
4715435475dSsthen   | VAR_TLS_SERVICE_OCSP STRING
4725435475dSsthen     { cfg_parser->opt->tls_service_ocsp = region_strdup(cfg_parser->opt->region, $2); }
4735435475dSsthen   | VAR_TLS_SERVICE_PEM STRING
4745435475dSsthen     { cfg_parser->opt->tls_service_pem = region_strdup(cfg_parser->opt->region, $2); }
4755435475dSsthen   | VAR_TLS_PORT number
4765435475dSsthen     {
4775435475dSsthen       /* port number, stored as string */
4785435475dSsthen       char buf[16];
4795435475dSsthen       (void)snprintf(buf, sizeof(buf), "%lld", $2);
4805435475dSsthen       cfg_parser->opt->tls_port = region_strdup(cfg_parser->opt->region, buf);
481db7d0d02Sflorian     }
482063644e9Sflorian   | VAR_TLS_CERT_BUNDLE STRING
483063644e9Sflorian     { cfg_parser->opt->tls_cert_bundle = region_strdup(cfg_parser->opt->region, $2); }
484b71395eaSflorian   | VAR_PROXY_PROTOCOL_PORT number
485b71395eaSflorian     {
486b71395eaSflorian       struct proxy_protocol_port_list* elem = region_alloc_zero(
487b71395eaSflorian 	cfg_parser->opt->region, sizeof(*elem));
488b71395eaSflorian       elem->port = $2;
489b71395eaSflorian       elem->next = cfg_parser->opt->proxy_protocol_port;
490b71395eaSflorian       cfg_parser->opt->proxy_protocol_port = elem;
491b71395eaSflorian     }
492063644e9Sflorian   | VAR_ANSWER_COOKIE boolean
493063644e9Sflorian     { cfg_parser->opt->answer_cookie = $2; }
494063644e9Sflorian   | VAR_COOKIE_SECRET STRING
495063644e9Sflorian     { cfg_parser->opt->cookie_secret = region_strdup(cfg_parser->opt->region, $2); }
496063644e9Sflorian   | VAR_COOKIE_SECRET_FILE STRING
497063644e9Sflorian     { cfg_parser->opt->cookie_secret_file = region_strdup(cfg_parser->opt->region, $2); }
498bc6311d7Sflorian   | VAR_XFRD_TCP_MAX number
499bc6311d7Sflorian     { cfg_parser->opt->xfrd_tcp_max = (int)$2; }
500bc6311d7Sflorian   | VAR_XFRD_TCP_PIPELINE number
501bc6311d7Sflorian     { cfg_parser->opt->xfrd_tcp_pipeline = (int)$2; }
502308d2509Sflorian   | VAR_CPU_AFFINITY cpus
503308d2509Sflorian     {
504308d2509Sflorian       cfg_parser->opt->cpu_affinity = $2;
505308d2509Sflorian     }
506308d2509Sflorian   | service_cpu_affinity number
507308d2509Sflorian     {
508308d2509Sflorian       if($2 < 0) {
509308d2509Sflorian         yyerror("expected a non-negative number");
510308d2509Sflorian         YYABORT;
511308d2509Sflorian       } else {
512308d2509Sflorian         struct cpu_map_option *opt, *tail;
513308d2509Sflorian 
514308d2509Sflorian         opt = cfg_parser->opt->service_cpu_affinity;
515308d2509Sflorian         while(opt && opt->service != $1) { opt = opt->next; }
516308d2509Sflorian 
517308d2509Sflorian         if(opt) {
518308d2509Sflorian           opt->cpu = $2;
519308d2509Sflorian         } else {
520308d2509Sflorian           opt = region_alloc_zero(cfg_parser->opt->region, sizeof(*opt));
521308d2509Sflorian           opt->service = (int)$1;
522308d2509Sflorian           opt->cpu = (int)$2;
523308d2509Sflorian 
524308d2509Sflorian           tail = cfg_parser->opt->service_cpu_affinity;
525308d2509Sflorian           if(tail) {
526308d2509Sflorian             while(tail->next) { tail = tail->next; }
527308d2509Sflorian             tail->next = opt;
528308d2509Sflorian           } else {
529308d2509Sflorian             cfg_parser->opt->service_cpu_affinity = opt;
530308d2509Sflorian           }
531308d2509Sflorian         }
532308d2509Sflorian       }
533308d2509Sflorian     }
534308d2509Sflorian   ;
535308d2509Sflorian 
536308d2509Sflorian socket_options:
537308d2509Sflorian   | socket_options socket_option ;
538308d2509Sflorian 
539308d2509Sflorian socket_option:
540308d2509Sflorian     VAR_SERVERS STRING
541308d2509Sflorian     {
542308d2509Sflorian       char *tok, *ptr, *str;
543308d2509Sflorian       struct range_option *servers = NULL;
544308d2509Sflorian       long long first, last;
545308d2509Sflorian 
546308d2509Sflorian       /* user may specify "0 1", "0" "1", 0 1 or a combination thereof */
547308d2509Sflorian       for(str = $2; (tok = strtok_r(str, " \t", &ptr)); str = NULL) {
548308d2509Sflorian         struct range_option *opt =
549308d2509Sflorian           region_alloc(cfg_parser->opt->region, sizeof(*opt));
550308d2509Sflorian         first = last = 0;
551308d2509Sflorian         if(!parse_range(tok, &first, &last)) {
552308d2509Sflorian           yyerror("invalid server range '%s'", tok);
553308d2509Sflorian           YYABORT;
554308d2509Sflorian         }
555308d2509Sflorian         assert(first >= 0);
556308d2509Sflorian         assert(last >= 0);
557308d2509Sflorian         opt->next = NULL;
558308d2509Sflorian         opt->first = (int)first;
559308d2509Sflorian         opt->last = (int)last;
560308d2509Sflorian         if(servers) {
561308d2509Sflorian           servers = servers->next = opt;
562308d2509Sflorian         } else {
563308d2509Sflorian           servers = cfg_parser->ip->servers = opt;
564308d2509Sflorian         }
565308d2509Sflorian       }
566308d2509Sflorian     }
567308d2509Sflorian   | VAR_BINDTODEVICE boolean
568308d2509Sflorian     { cfg_parser->ip->dev = $2; }
569308d2509Sflorian   | VAR_SETFIB number
570308d2509Sflorian     { cfg_parser->ip->fib = $2; }
571308d2509Sflorian   ;
572308d2509Sflorian 
573308d2509Sflorian cpus:
574308d2509Sflorian     { $$ = NULL; }
575308d2509Sflorian   | cpus STRING
576308d2509Sflorian     {
577308d2509Sflorian       char *tok, *ptr, *str;
578308d2509Sflorian       struct cpu_option *tail;
579308d2509Sflorian       long long cpu;
580308d2509Sflorian 
581308d2509Sflorian       str = $2;
582308d2509Sflorian       $$ = tail = $1;
583308d2509Sflorian       if(tail) {
584308d2509Sflorian         while(tail->next) { tail = tail->next; }
585308d2509Sflorian       }
586308d2509Sflorian 
587308d2509Sflorian       /* Users may specify "0 1", "0" "1", 0 1 or a combination thereof. */
588308d2509Sflorian       for(str = $2; (tok = strtok_r(str, " \t", &ptr)); str = NULL) {
589308d2509Sflorian         struct cpu_option *opt =
590efac4d30Sflorian           region_alloc_zero(cfg_parser->opt->region, sizeof(*opt));
591308d2509Sflorian         cpu = 0;
592efac4d30Sflorian         if(!parse_number(tok, &cpu) || cpu < 0) {
593308d2509Sflorian           yyerror("expected a positive number");
594308d2509Sflorian           YYABORT;
595308d2509Sflorian         }
596308d2509Sflorian         assert(cpu >=0);
597308d2509Sflorian         opt->cpu = (int)cpu;
598308d2509Sflorian         if(tail) {
599308d2509Sflorian           tail->next = opt;
600308d2509Sflorian           tail = opt;
601308d2509Sflorian         } else {
602308d2509Sflorian           $$ = tail = opt;
603308d2509Sflorian         }
604308d2509Sflorian       }
605308d2509Sflorian     }
606308d2509Sflorian   ;
607308d2509Sflorian 
608308d2509Sflorian service_cpu_affinity:
609308d2509Sflorian     VAR_XFRD_CPU_AFFINITY
610308d2509Sflorian     { $$ = -1; }
611308d2509Sflorian   | VAR_SERVER_CPU_AFFINITY
612308d2509Sflorian     {
613308d2509Sflorian       if($1 <= 0) {
614308d2509Sflorian         yyerror("invalid server identifier");
615308d2509Sflorian         YYABORT;
616308d2509Sflorian       }
617308d2509Sflorian       $$ = $1;
618308d2509Sflorian     }
619db7d0d02Sflorian   ;
6205435475dSsthen 
6215435475dSsthen dnstap:
6225435475dSsthen     VAR_DNSTAP dnstap_block ;
6235435475dSsthen 
6245435475dSsthen dnstap_block:
6255435475dSsthen     dnstap_block dnstap_option | ;
6265435475dSsthen 
6275435475dSsthen dnstap_option:
6285435475dSsthen     VAR_DNSTAP_ENABLE boolean
6295435475dSsthen     { cfg_parser->opt->dnstap_enable = $2; }
6305435475dSsthen   | VAR_DNSTAP_SOCKET_PATH STRING
6315435475dSsthen     { cfg_parser->opt->dnstap_socket_path = region_strdup(cfg_parser->opt->region, $2); }
6323efee2e1Sflorian   | VAR_DNSTAP_IP STRING
6333efee2e1Sflorian     { cfg_parser->opt->dnstap_ip = region_strdup(cfg_parser->opt->region, $2); }
6343efee2e1Sflorian   | VAR_DNSTAP_TLS boolean
6353efee2e1Sflorian     { cfg_parser->opt->dnstap_tls = $2; }
6363efee2e1Sflorian   | VAR_DNSTAP_TLS_SERVER_NAME STRING
6373efee2e1Sflorian     { cfg_parser->opt->dnstap_tls_server_name = region_strdup(cfg_parser->opt->region, $2); }
6383efee2e1Sflorian   | VAR_DNSTAP_TLS_CERT_BUNDLE STRING
6393efee2e1Sflorian     { cfg_parser->opt->dnstap_tls_cert_bundle = region_strdup(cfg_parser->opt->region, $2); }
6403efee2e1Sflorian   | VAR_DNSTAP_TLS_CLIENT_KEY_FILE STRING
6413efee2e1Sflorian     { cfg_parser->opt->dnstap_tls_client_key_file = region_strdup(cfg_parser->opt->region, $2); }
6423efee2e1Sflorian   | VAR_DNSTAP_TLS_CLIENT_CERT_FILE STRING
6433efee2e1Sflorian     { cfg_parser->opt->dnstap_tls_client_cert_file = region_strdup(cfg_parser->opt->region, $2); }
6445435475dSsthen   | VAR_DNSTAP_SEND_IDENTITY boolean
6455435475dSsthen     { cfg_parser->opt->dnstap_send_identity = $2; }
6465435475dSsthen   | VAR_DNSTAP_SEND_VERSION boolean
6475435475dSsthen     { cfg_parser->opt->dnstap_send_version = $2; }
6485435475dSsthen   | VAR_DNSTAP_IDENTITY STRING
6495435475dSsthen     { cfg_parser->opt->dnstap_identity = region_strdup(cfg_parser->opt->region, $2); }
6505435475dSsthen   | VAR_DNSTAP_VERSION STRING
6515435475dSsthen     { cfg_parser->opt->dnstap_version = region_strdup(cfg_parser->opt->region, $2); }
6525435475dSsthen   | VAR_DNSTAP_LOG_AUTH_QUERY_MESSAGES boolean
6535435475dSsthen     { cfg_parser->opt->dnstap_log_auth_query_messages = $2; }
6545435475dSsthen   | VAR_DNSTAP_LOG_AUTH_RESPONSE_MESSAGES boolean
6555435475dSsthen     { cfg_parser->opt->dnstap_log_auth_response_messages = $2; }
656bfd0b123Sflorian   ;
6575435475dSsthen 
6585435475dSsthen remote_control:
6595435475dSsthen     VAR_REMOTE_CONTROL remote_control_block ;
6605435475dSsthen 
6615435475dSsthen remote_control_block:
6625435475dSsthen     remote_control_block remote_control_option | ;
6635435475dSsthen 
6645435475dSsthen remote_control_option:
6655435475dSsthen     VAR_CONTROL_ENABLE boolean
6665435475dSsthen     { cfg_parser->opt->control_enable = $2; }
6675435475dSsthen   | VAR_CONTROL_INTERFACE ip_address
66862ac0c33Sjakob     {
6695435475dSsthen       struct ip_address_option *ip = cfg_parser->opt->control_interface;
6705435475dSsthen       if(ip == NULL) {
6715435475dSsthen         cfg_parser->opt->control_interface = $2;
672eab1363eSsthen       } else {
6735435475dSsthen         while(ip->next != NULL) { ip = ip->next; }
6745435475dSsthen         ip->next = $2;
675eab1363eSsthen       }
676eab1363eSsthen     }
6775435475dSsthen   | VAR_CONTROL_PORT number
67862ac0c33Sjakob     {
6795435475dSsthen       if($2 == 0) {
680dd5b221eSsthen         yyerror("control port number expected");
6815435475dSsthen       } else {
6825435475dSsthen         cfg_parser->opt->control_port = (int)$2;
683dd5b221eSsthen       }
684dd5b221eSsthen     }
6855435475dSsthen   | VAR_SERVER_KEY_FILE STRING
6865435475dSsthen     { cfg_parser->opt->server_key_file = region_strdup(cfg_parser->opt->region, $2); }
6875435475dSsthen   | VAR_SERVER_CERT_FILE STRING
6885435475dSsthen     { cfg_parser->opt->server_cert_file = region_strdup(cfg_parser->opt->region, $2); }
6895435475dSsthen   | VAR_CONTROL_KEY_FILE STRING
6905435475dSsthen     { cfg_parser->opt->control_key_file = region_strdup(cfg_parser->opt->region, $2); }
6915435475dSsthen   | VAR_CONTROL_CERT_FILE STRING
6925435475dSsthen     { cfg_parser->opt->control_cert_file = region_strdup(cfg_parser->opt->region, $2); }
693dd5b221eSsthen   ;
694dd5b221eSsthen 
695063644e9Sflorian tls_auth:
696063644e9Sflorian     VAR_TLS_AUTH
697063644e9Sflorian       {
698063644e9Sflorian         tls_auth_options_type *tls_auth = tls_auth_options_create(cfg_parser->opt->region);
699063644e9Sflorian         assert(cfg_parser->tls_auth == NULL);
700063644e9Sflorian         cfg_parser->tls_auth = tls_auth;
701063644e9Sflorian       }
702063644e9Sflorian       tls_auth_block
703063644e9Sflorian     {
704063644e9Sflorian       struct tls_auth_options *tls_auth = cfg_parser->tls_auth;
705063644e9Sflorian       if(tls_auth->name == NULL) {
706063644e9Sflorian         yyerror("tls-auth has no name");
707063644e9Sflorian       } else if(tls_auth->auth_domain_name == NULL) {
708063644e9Sflorian         yyerror("tls-auth %s has no auth-domain-name", tls_auth->name);
709063644e9Sflorian       } else if(tls_auth_options_find(cfg_parser->opt, tls_auth->name)) {
710063644e9Sflorian         yyerror("duplicate tls-auth %s", tls_auth->name);
711063644e9Sflorian       } else {
712063644e9Sflorian       	tls_auth_options_insert(cfg_parser->opt, tls_auth);
713063644e9Sflorian         cfg_parser->tls_auth = NULL;
714063644e9Sflorian       }
715063644e9Sflorian     } ;
716063644e9Sflorian 
717063644e9Sflorian tls_auth_block:
718063644e9Sflorian     tls_auth_block tls_auth_option | ;
719063644e9Sflorian 
720063644e9Sflorian tls_auth_option:
721063644e9Sflorian     VAR_NAME STRING
722063644e9Sflorian     {
723063644e9Sflorian       dname_type *dname;
724063644e9Sflorian       dname = (dname_type *)dname_parse(cfg_parser->opt->region, $2);
725063644e9Sflorian       cfg_parser->tls_auth->name = region_strdup(cfg_parser->opt->region, $2);
726063644e9Sflorian       if(dname == NULL) {
727063644e9Sflorian         yyerror("bad tls-auth name %s", $2);
728063644e9Sflorian       } else {
729063644e9Sflorian         region_recycle(cfg_parser->opt->region, dname, dname_total_size(dname));
730063644e9Sflorian       }
731063644e9Sflorian     }
732063644e9Sflorian   | VAR_TLS_AUTH_DOMAIN_NAME STRING
733063644e9Sflorian     {
734063644e9Sflorian       cfg_parser->tls_auth->auth_domain_name = region_strdup(cfg_parser->opt->region, $2);
735a904e103Sflorian     }
736a904e103Sflorian   | VAR_TLS_AUTH_CLIENT_CERT STRING
737a904e103Sflorian     {
738a904e103Sflorian 	    cfg_parser->tls_auth->client_cert = region_strdup(cfg_parser->opt->region, $2);
739a904e103Sflorian     }
740a904e103Sflorian   | VAR_TLS_AUTH_CLIENT_KEY STRING
741a904e103Sflorian     {
742a904e103Sflorian 	    cfg_parser->tls_auth->client_key = region_strdup(cfg_parser->opt->region, $2);
743a904e103Sflorian     }
744a904e103Sflorian   | VAR_TLS_AUTH_CLIENT_KEY_PW STRING
745a904e103Sflorian     {
746a904e103Sflorian 	    cfg_parser->tls_auth->client_key_pw = region_strdup(cfg_parser->opt->region, $2);
747a904e103Sflorian     }
748a904e103Sflorian   ;
749063644e9Sflorian 
7505435475dSsthen key:
7515435475dSsthen     VAR_KEY
752e02bc0dfSflorian       {
7535435475dSsthen         key_options_type *key = key_options_create(cfg_parser->opt->region);
7545435475dSsthen         key->algorithm = region_strdup(cfg_parser->opt->region, "sha256");
7555435475dSsthen         assert(cfg_parser->key == NULL);
7565435475dSsthen         cfg_parser->key = key;
757e02bc0dfSflorian       }
7585435475dSsthen       key_block
759e02bc0dfSflorian     {
7605435475dSsthen       struct key_options *key = cfg_parser->key;
7615435475dSsthen       if(key->name == NULL) {
7625435475dSsthen         yyerror("tsig key has no name");
7635435475dSsthen       } else if(key->algorithm == NULL) {
7645435475dSsthen         yyerror("tsig key %s has no algorithm", key->name);
7655435475dSsthen       } else if(key->secret == NULL) {
7665435475dSsthen         yyerror("tsig key %s has no secret blob", key->name);
7675435475dSsthen       } else if(key_options_find(cfg_parser->opt, key->name)) {
7685435475dSsthen         yyerror("duplicate tsig key %s", key->name);
7695435475dSsthen       } else {
7705435475dSsthen         key_options_insert(cfg_parser->opt, key);
7715435475dSsthen         cfg_parser->key = NULL;
772e02bc0dfSflorian       }
7735435475dSsthen     } ;
774e02bc0dfSflorian 
7755435475dSsthen key_block:
7765435475dSsthen     key_block key_option | ;
77762ac0c33Sjakob 
7785435475dSsthen key_option:
7795435475dSsthen     VAR_NAME STRING
78062ac0c33Sjakob     {
7815435475dSsthen       dname_type *dname;
78262ac0c33Sjakob 
7835435475dSsthen       dname = (dname_type *)dname_parse(cfg_parser->opt->region, $2);
7845435475dSsthen       cfg_parser->key->name = region_strdup(cfg_parser->opt->region, $2);
7855435475dSsthen       if(dname == NULL) {
7865435475dSsthen         yyerror("bad tsig key name %s", $2);
7875435475dSsthen       } else {
7885435475dSsthen         region_recycle(cfg_parser->opt->region, dname, dname_total_size(dname));
7895435475dSsthen       }
7905435475dSsthen     }
7915435475dSsthen   | VAR_ALGORITHM STRING
79262ac0c33Sjakob     {
7935435475dSsthen       if(tsig_get_algorithm_by_name($2) == NULL) {
7945435475dSsthen         yyerror("bad tsig key algorithm %s", $2);
7955435475dSsthen       } else {
7965435475dSsthen         cfg_parser->key->algorithm = region_strdup(cfg_parser->opt->region, $2);
79762ac0c33Sjakob       }
79862ac0c33Sjakob     }
7995435475dSsthen   | VAR_SECRET STRING
80062ac0c33Sjakob     {
801dd5b221eSsthen       uint8_t data[16384];
802dd5b221eSsthen       int size;
8035435475dSsthen 
8045435475dSsthen       cfg_parser->key->secret = region_strdup(cfg_parser->opt->region, $2);
80572628ec9Ssthen       size = __b64_pton($2, data, sizeof(data));
806dd5b221eSsthen       if(size == -1) {
8075435475dSsthen         yyerror("cannot base64 decode tsig secret %s",
8085435475dSsthen           cfg_parser->key->name?
8095435475dSsthen           cfg_parser->key->name:"");
810dd5b221eSsthen       } else if(size != 0) {
811dd5b221eSsthen         memset(data, 0xdd, size); /* wipe secret */
812dd5b221eSsthen       }
8135435475dSsthen     } ;
8145435475dSsthen 
8155435475dSsthen 
8165435475dSsthen zone:
8175435475dSsthen     VAR_ZONE
8185435475dSsthen       {
8195435475dSsthen         assert(cfg_parser->pattern == NULL);
8205435475dSsthen         assert(cfg_parser->zone == NULL);
8215435475dSsthen         cfg_parser->zone = zone_options_create(cfg_parser->opt->region);
8225435475dSsthen         cfg_parser->zone->part_of_config = 1;
8235435475dSsthen         cfg_parser->zone->pattern = cfg_parser->pattern =
8245435475dSsthen           pattern_options_create(cfg_parser->opt->region);
8255435475dSsthen         cfg_parser->zone->pattern->implicit = 1;
82662ac0c33Sjakob       }
8275435475dSsthen     zone_block
8285435475dSsthen     {
8295435475dSsthen       assert(cfg_parser->zone != NULL);
8305435475dSsthen       if(cfg_parser->zone->name == NULL) {
8315435475dSsthen         yyerror("zone has no name");
8325435475dSsthen       } else if(!nsd_options_insert_zone(cfg_parser->opt, cfg_parser->zone)) {
8335435475dSsthen         yyerror("duplicate zone %s", cfg_parser->zone->name);
8345435475dSsthen       } else if(!nsd_options_insert_pattern(cfg_parser->opt, cfg_parser->zone->pattern)) {
8355435475dSsthen         yyerror("duplicate pattern %s", cfg_parser->zone->pattern->pname);
8365435475dSsthen       }
8375435475dSsthen       cfg_parser->pattern = NULL;
8385435475dSsthen       cfg_parser->zone = NULL;
8395435475dSsthen     } ;
8405435475dSsthen 
8415435475dSsthen zone_block:
8425435475dSsthen     zone_block zone_option | ;
8435435475dSsthen 
8445435475dSsthen zone_option:
8455435475dSsthen     VAR_NAME STRING
8465435475dSsthen     {
8475435475dSsthen       const char *marker = PATTERN_IMPLICIT_MARKER;
8485435475dSsthen       char *pname = region_alloc(cfg_parser->opt->region, strlen($2) + strlen(marker) + 1);
8495435475dSsthen       memmove(pname, marker, strlen(marker));
8505435475dSsthen       memmove(pname + strlen(marker), $2, strlen($2) + 1);
8515435475dSsthen       cfg_parser->zone->pattern->pname = pname;
8525435475dSsthen       cfg_parser->zone->name = region_strdup(cfg_parser->opt->region, $2);
8535435475dSsthen       if(pattern_options_find(cfg_parser->opt, pname)) {
8545435475dSsthen         yyerror("zone %s cannot be created because implicit pattern %s "
8555435475dSsthen                     "already exists", $2, pname);
8565435475dSsthen       }
8575435475dSsthen     }
8585435475dSsthen   | pattern_or_zone_option ;
8595435475dSsthen 
8605435475dSsthen pattern:
8615435475dSsthen     VAR_PATTERN
8625435475dSsthen       {
8635435475dSsthen         assert(cfg_parser->pattern == NULL);
8645435475dSsthen         cfg_parser->pattern = pattern_options_create(cfg_parser->opt->region);
8655435475dSsthen       }
8665435475dSsthen       pattern_block
8675435475dSsthen     {
8685435475dSsthen       pattern_options_type *pattern = cfg_parser->pattern;
8695435475dSsthen       if(pattern->pname == NULL) {
8705435475dSsthen         yyerror("pattern has no name");
8715435475dSsthen       } else if(!nsd_options_insert_pattern(cfg_parser->opt, pattern)) {
8725435475dSsthen         yyerror("duplicate pattern %s", pattern->pname);
8735435475dSsthen       }
8745435475dSsthen       cfg_parser->pattern = NULL;
8755435475dSsthen     } ;
8765435475dSsthen 
8775435475dSsthen pattern_block:
8785435475dSsthen     pattern_block pattern_option | ;
8795435475dSsthen 
8805435475dSsthen pattern_option:
8815435475dSsthen     VAR_NAME STRING
8825435475dSsthen     {
8835435475dSsthen       if(strchr($2, ' ')) {
8845435475dSsthen         yyerror("space is not allowed in pattern name: '%s'", $2);
8855435475dSsthen       }
8865435475dSsthen       cfg_parser->pattern->pname = region_strdup(cfg_parser->opt->region, $2);
8875435475dSsthen     }
8885435475dSsthen   | pattern_or_zone_option ;
8895435475dSsthen 
8905435475dSsthen pattern_or_zone_option:
8915435475dSsthen     VAR_RRL_WHITELIST STRING
8925435475dSsthen     {
8935435475dSsthen #ifdef RATELIMIT
8945435475dSsthen       cfg_parser->pattern->rrl_whitelist |= rrlstr2type($2);
8955435475dSsthen #endif
8965435475dSsthen     }
8975435475dSsthen   | VAR_ZONEFILE STRING
8985435475dSsthen     { cfg_parser->pattern->zonefile = region_strdup(cfg_parser->opt->region, $2); }
8995435475dSsthen   | VAR_ZONESTATS STRING
9005435475dSsthen     { cfg_parser->pattern->zonestats = region_strdup(cfg_parser->opt->region, $2); }
9015435475dSsthen   | VAR_SIZE_LIMIT_XFR number
9025435475dSsthen     {
9035435475dSsthen       if($2 > 0) {
9045435475dSsthen         cfg_parser->pattern->size_limit_xfr = (int)$2;
9055435475dSsthen       } else {
9065435475dSsthen         yyerror("expected a number greater than zero");
9075435475dSsthen       }
9085435475dSsthen     }
909*bf87c3c0Sflorian   | VAR_MULTI_PRIMARY_CHECK boolean
910*bf87c3c0Sflorian     { cfg_parser->pattern->multi_primary_check = (int)$2; }
9115435475dSsthen   | VAR_INCLUDE_PATTERN STRING
9125435475dSsthen     { config_apply_pattern(cfg_parser->pattern, $2); }
9135435475dSsthen   | VAR_REQUEST_XFR STRING STRING
9145435475dSsthen     {
9155435475dSsthen       acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, $2, $3);
916*bf87c3c0Sflorian       if(cfg_parser->pattern->catalog_role == CATALOG_ROLE_PRODUCER)
917*bf87c3c0Sflorian         yyerror("catalog producer zones cannot be secondary zones");
9185435475dSsthen       if(acl->blocked)
9195435475dSsthen         yyerror("blocked address used for request-xfr");
9205435475dSsthen       if(acl->rangetype != acl_range_single)
9215435475dSsthen         yyerror("address range used for request-xfr");
9225435475dSsthen       append_acl(&cfg_parser->pattern->request_xfr, acl);
9235435475dSsthen     }
924063644e9Sflorian 	tlsauth_option
925063644e9Sflorian 	{ }
9265435475dSsthen   | VAR_REQUEST_XFR VAR_AXFR STRING STRING
9275435475dSsthen     {
9285435475dSsthen       acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, $3, $4);
9295435475dSsthen       acl->use_axfr_only = 1;
9305435475dSsthen       if(acl->blocked)
9315435475dSsthen         yyerror("blocked address used for request-xfr");
9325435475dSsthen       if(acl->rangetype != acl_range_single)
9335435475dSsthen         yyerror("address range used for request-xfr");
9345435475dSsthen       append_acl(&cfg_parser->pattern->request_xfr, acl);
9355435475dSsthen     }
936063644e9Sflorian 	tlsauth_option
937063644e9Sflorian 	{ }
9385435475dSsthen   | VAR_REQUEST_XFR VAR_UDP STRING STRING
9395435475dSsthen     {
9405435475dSsthen       acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, $3, $4);
9415435475dSsthen       acl->allow_udp = 1;
9425435475dSsthen       if(acl->blocked)
9435435475dSsthen         yyerror("blocked address used for request-xfr");
9445435475dSsthen       if(acl->rangetype != acl_range_single)
9455435475dSsthen         yyerror("address range used for request-xfr");
9465435475dSsthen       append_acl(&cfg_parser->pattern->request_xfr, acl);
9475435475dSsthen     }
9485435475dSsthen   | VAR_ALLOW_NOTIFY STRING STRING
9495435475dSsthen     {
9505435475dSsthen       acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, $2, $3);
9515435475dSsthen       append_acl(&cfg_parser->pattern->allow_notify, acl);
9525435475dSsthen     }
9535435475dSsthen   | VAR_NOTIFY STRING STRING
9545435475dSsthen     {
9555435475dSsthen       acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, $2, $3);
9565435475dSsthen       if(acl->blocked)
9575435475dSsthen         yyerror("blocked address used for notify");
9585435475dSsthen       if(acl->rangetype != acl_range_single)
9595435475dSsthen         yyerror("address range used for notify");
9605435475dSsthen       append_acl(&cfg_parser->pattern->notify, acl);
9615435475dSsthen     }
9625435475dSsthen   | VAR_PROVIDE_XFR STRING STRING
9635435475dSsthen     {
9645435475dSsthen       acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, $2, $3);
9655435475dSsthen       append_acl(&cfg_parser->pattern->provide_xfr, acl);
9665435475dSsthen     }
9678d298c9fSsthen   | VAR_ALLOW_QUERY STRING STRING
9688d298c9fSsthen     {
9698d298c9fSsthen       acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, $2, $3);
9708d298c9fSsthen       append_acl(&cfg_parser->pattern->allow_query, acl);
9718d298c9fSsthen     }
9725435475dSsthen   | VAR_OUTGOING_INTERFACE STRING
9735435475dSsthen     {
9745435475dSsthen       acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, $2, "NOKEY");
9755435475dSsthen       append_acl(&cfg_parser->pattern->outgoing_interface, acl);
9765435475dSsthen     }
9775435475dSsthen   | VAR_ALLOW_AXFR_FALLBACK boolean
9785435475dSsthen     {
9795435475dSsthen       cfg_parser->pattern->allow_axfr_fallback = $2;
9805435475dSsthen       cfg_parser->pattern->allow_axfr_fallback_is_default = 0;
9815435475dSsthen     }
9825435475dSsthen   | VAR_NOTIFY_RETRY number
9835435475dSsthen     {
9845435475dSsthen       cfg_parser->pattern->notify_retry = $2;
9855435475dSsthen       cfg_parser->pattern->notify_retry_is_default = 0;
9865435475dSsthen     }
9875435475dSsthen   | VAR_MAX_REFRESH_TIME number
9885435475dSsthen     {
9895435475dSsthen       cfg_parser->pattern->max_refresh_time = $2;
9905435475dSsthen       cfg_parser->pattern->max_refresh_time_is_default = 0;
9915435475dSsthen     }
9925435475dSsthen   | VAR_MIN_REFRESH_TIME number
9935435475dSsthen     {
9945435475dSsthen       cfg_parser->pattern->min_refresh_time = $2;
9955435475dSsthen       cfg_parser->pattern->min_refresh_time_is_default = 0;
9965435475dSsthen     }
9975435475dSsthen   | VAR_MAX_RETRY_TIME number
9985435475dSsthen     {
9995435475dSsthen       cfg_parser->pattern->max_retry_time = $2;
10005435475dSsthen       cfg_parser->pattern->max_retry_time_is_default = 0;
10015435475dSsthen     }
10025435475dSsthen   | VAR_MIN_RETRY_TIME number
10035435475dSsthen     {
10045435475dSsthen       cfg_parser->pattern->min_retry_time = $2;
10055435475dSsthen       cfg_parser->pattern->min_retry_time_is_default = 0;
1006ac5517e4Sflorian     }
1007ac5517e4Sflorian   | VAR_MIN_EXPIRE_TIME STRING
1008ac5517e4Sflorian     {
1009ac5517e4Sflorian       long long num;
1010ac5517e4Sflorian       uint8_t expr;
1011ac5517e4Sflorian 
1012ac5517e4Sflorian       if (!parse_expire_expr($2, &num, &expr)) {
1013ac5517e4Sflorian         yyerror("expected an expire time in seconds or \"refresh+retry+1\"");
1014ac5517e4Sflorian         YYABORT; /* trigger a parser error */
1015ac5517e4Sflorian       }
1016ac5517e4Sflorian       cfg_parser->pattern->min_expire_time = num;
1017ac5517e4Sflorian       cfg_parser->pattern->min_expire_time_expr = expr;
10184564029fSflorian     }
10194564029fSflorian   | VAR_STORE_IXFR boolean
10204564029fSflorian     {
10214564029fSflorian       cfg_parser->pattern->store_ixfr = $2;
10224564029fSflorian       cfg_parser->pattern->store_ixfr_is_default = 0;
10234564029fSflorian     }
10244564029fSflorian   | VAR_IXFR_SIZE number
10254564029fSflorian     {
10264564029fSflorian       cfg_parser->pattern->ixfr_size = $2;
10274564029fSflorian       cfg_parser->pattern->ixfr_size_is_default = 0;
10284564029fSflorian     }
10294564029fSflorian   | VAR_IXFR_NUMBER number
10304564029fSflorian     {
10314564029fSflorian       cfg_parser->pattern->ixfr_number = $2;
10324564029fSflorian       cfg_parser->pattern->ixfr_number_is_default = 0;
10334564029fSflorian     }
10344564029fSflorian   | VAR_CREATE_IXFR boolean
10354564029fSflorian     {
10364564029fSflorian       cfg_parser->pattern->create_ixfr = $2;
10374564029fSflorian       cfg_parser->pattern->create_ixfr_is_default = 0;
10383f21e8ccSflorian     }
10393f21e8ccSflorian   | VAR_VERIFY_ZONE boolean
10403f21e8ccSflorian     { cfg_parser->pattern->verify_zone = $2; }
10413f21e8ccSflorian   | VAR_VERIFIER command
10423f21e8ccSflorian     { cfg_parser->pattern->verifier = $2; }
10433f21e8ccSflorian   | VAR_VERIFIER_FEED_ZONE boolean
10443f21e8ccSflorian     { cfg_parser->pattern->verifier_feed_zone = $2; }
10453f21e8ccSflorian   | VAR_VERIFIER_TIMEOUT number
1046*bf87c3c0Sflorian     { cfg_parser->pattern->verifier_timeout = $2; }
1047*bf87c3c0Sflorian   | VAR_CATALOG catalog_role
1048*bf87c3c0Sflorian     {
1049*bf87c3c0Sflorian       if($2 == CATALOG_ROLE_PRODUCER && cfg_parser->pattern->request_xfr)
1050*bf87c3c0Sflorian         yyerror("catalog producer zones cannot be secondary zones");
1051*bf87c3c0Sflorian       cfg_parser->pattern->catalog_role = $2;
1052*bf87c3c0Sflorian       cfg_parser->pattern->catalog_role_is_default = 0;
1053*bf87c3c0Sflorian     }
1054*bf87c3c0Sflorian   | VAR_CATALOG_MEMBER_PATTERN STRING
1055*bf87c3c0Sflorian     {
1056*bf87c3c0Sflorian       cfg_parser->pattern->catalog_member_pattern = region_strdup(cfg_parser->opt->region, $2);
1057*bf87c3c0Sflorian     }
1058*bf87c3c0Sflorian   | VAR_CATALOG_PRODUCER_ZONE STRING
1059*bf87c3c0Sflorian     {
1060*bf87c3c0Sflorian       dname_type *dname;
1061*bf87c3c0Sflorian 
1062*bf87c3c0Sflorian       if(cfg_parser->zone) {
1063*bf87c3c0Sflorian         yyerror("catalog-producer-zone option is for patterns only and cannot "
1064*bf87c3c0Sflorian                 "be used in a zone clause");
1065*bf87c3c0Sflorian       } else if(!(dname = (dname_type *)dname_parse(cfg_parser->opt->region, $2))) {
1066*bf87c3c0Sflorian         yyerror("bad catalog producer name %s", $2);
1067*bf87c3c0Sflorian       } else {
1068*bf87c3c0Sflorian         region_recycle(cfg_parser->opt->region, dname, dname_total_size(dname));
1069*bf87c3c0Sflorian         cfg_parser->pattern->catalog_producer_zone = region_strdup(cfg_parser->opt->region, $2);
1070*bf87c3c0Sflorian       }
1071*bf87c3c0Sflorian     };
10723f21e8ccSflorian 
10733f21e8ccSflorian verify:
10743f21e8ccSflorian     VAR_VERIFY verify_block ;
10753f21e8ccSflorian 
10763f21e8ccSflorian verify_block:
10773f21e8ccSflorian     verify_block verify_option | ;
10783f21e8ccSflorian 
10793f21e8ccSflorian verify_option:
10803f21e8ccSflorian     VAR_ENABLE boolean
10813f21e8ccSflorian     { cfg_parser->opt->verify_enable = $2; }
10823f21e8ccSflorian   | VAR_IP_ADDRESS ip_address
10833f21e8ccSflorian     {
10843f21e8ccSflorian       struct ip_address_option *ip = cfg_parser->opt->verify_ip_addresses;
10853f21e8ccSflorian       if(!ip) {
10863f21e8ccSflorian         cfg_parser->opt->verify_ip_addresses = $2;
10873f21e8ccSflorian       } else {
10883f21e8ccSflorian         while(ip->next) { ip = ip->next; }
10893f21e8ccSflorian         ip->next = $2;
10903f21e8ccSflorian       }
10913f21e8ccSflorian     }
10923f21e8ccSflorian   | VAR_PORT number
10933f21e8ccSflorian     {
10943f21e8ccSflorian       /* port number, stored as a string */
10953f21e8ccSflorian       char buf[16];
10963f21e8ccSflorian       (void)snprintf(buf, sizeof(buf), "%lld", $2);
10973f21e8ccSflorian       cfg_parser->opt->verify_port = region_strdup(cfg_parser->opt->region, buf);
10983f21e8ccSflorian     }
10993f21e8ccSflorian   | VAR_VERIFY_ZONES boolean
11003f21e8ccSflorian     { cfg_parser->opt->verify_zones = $2; }
11013f21e8ccSflorian   | VAR_VERIFIER command
11023f21e8ccSflorian     { cfg_parser->opt->verifier = $2; }
11033f21e8ccSflorian   | VAR_VERIFIER_COUNT number
11043f21e8ccSflorian     { cfg_parser->opt->verifier_count = (int)$2; }
11053f21e8ccSflorian   | VAR_VERIFIER_TIMEOUT number
11063f21e8ccSflorian     { cfg_parser->opt->verifier_timeout = (int)$2; }
11073f21e8ccSflorian   | VAR_VERIFIER_FEED_ZONE boolean
11083f21e8ccSflorian     { cfg_parser->opt->verifier_feed_zone = $2; } ;
11093f21e8ccSflorian 
11103f21e8ccSflorian command:
11113f21e8ccSflorian     STRING arguments
11123f21e8ccSflorian     {
11133f21e8ccSflorian       char **argv;
11143f21e8ccSflorian       size_t argc = 1;
1115de04d855Ssthen       for(struct component *i = $2; i; i = i->next) {
11163f21e8ccSflorian         argc++;
11173f21e8ccSflorian       }
11183f21e8ccSflorian       argv = region_alloc_zero(
11193f21e8ccSflorian         cfg_parser->opt->region, (argc + 1) * sizeof(char *));
11203f21e8ccSflorian       argc = 0;
11213f21e8ccSflorian       argv[argc++] = $1;
1122de04d855Ssthen       for(struct component *j, *i = $2; i; i = j) {
11233f21e8ccSflorian         j = i->next;
11243f21e8ccSflorian         argv[argc++] = i->str;
11253f21e8ccSflorian         region_recycle(cfg_parser->opt->region, i, sizeof(*i));
11263f21e8ccSflorian       }
11273f21e8ccSflorian       $$ = argv;
11283f21e8ccSflorian     } ;
11293f21e8ccSflorian 
11303f21e8ccSflorian arguments:
11313f21e8ccSflorian     { $$ = NULL; }
11323f21e8ccSflorian   | arguments STRING
11333f21e8ccSflorian     {
11343f21e8ccSflorian       struct component *comp = region_alloc_zero(
11353f21e8ccSflorian         cfg_parser->opt->region, sizeof(*comp));
11363f21e8ccSflorian       comp->str = region_strdup(cfg_parser->opt->region, $2);
11373f21e8ccSflorian       if($1) {
11383f21e8ccSflorian         struct component *tail = $1;
11393f21e8ccSflorian         while(tail->next) {
11403f21e8ccSflorian          tail = tail->next;
11413f21e8ccSflorian         }
11423f21e8ccSflorian         tail->next = comp;
11433f21e8ccSflorian         $$ = $1;
11443f21e8ccSflorian       } else {
11453f21e8ccSflorian         $$ = comp;
11463f21e8ccSflorian       }
11475435475dSsthen     } ;
11485435475dSsthen 
11495435475dSsthen ip_address:
11505435475dSsthen     STRING
11515435475dSsthen     {
11525435475dSsthen       struct ip_address_option *ip = region_alloc_zero(
11535435475dSsthen         cfg_parser->opt->region, sizeof(*ip));
11545435475dSsthen       ip->address = region_strdup(cfg_parser->opt->region, $1);
1155308d2509Sflorian       ip->fib = -1;
11565435475dSsthen       $$ = ip;
11575435475dSsthen     } ;
11585435475dSsthen 
11595435475dSsthen number:
11605435475dSsthen     STRING
11615435475dSsthen     {
1162308d2509Sflorian       if(!parse_number($1, &$$)) {
11635435475dSsthen         yyerror("expected a number");
11645435475dSsthen         YYABORT; /* trigger a parser error */
11655435475dSsthen       }
11665435475dSsthen     } ;
11675435475dSsthen 
11685435475dSsthen boolean:
11695435475dSsthen     STRING
11705435475dSsthen     {
1171308d2509Sflorian       if(!parse_boolean($1, &$$)) {
11725435475dSsthen         yyerror("expected yes or no");
11735435475dSsthen         YYABORT; /* trigger a parser error */
11745435475dSsthen       }
11755435475dSsthen     } ;
117662ac0c33Sjakob 
1177063644e9Sflorian tlsauth_option:
1178063644e9Sflorian 	| STRING
1179063644e9Sflorian 	{ char *tls_auth_name = region_strdup(cfg_parser->opt->region, $1);
1180063644e9Sflorian 	  add_to_last_acl(&cfg_parser->pattern->request_xfr, tls_auth_name);} ;
1181063644e9Sflorian 
1182*bf87c3c0Sflorian catalog_role:
1183*bf87c3c0Sflorian     STRING
1184*bf87c3c0Sflorian     {
1185*bf87c3c0Sflorian       if(!parse_catalog_role($1, &$$)) {
1186*bf87c3c0Sflorian         yyerror("expected consumer or producer");
1187*bf87c3c0Sflorian         YYABORT; /* trigger a parser error */
1188*bf87c3c0Sflorian       }
1189*bf87c3c0Sflorian     } ;
1190*bf87c3c0Sflorian 
119162ac0c33Sjakob %%
119262ac0c33Sjakob 
11935435475dSsthen static void
11945435475dSsthen append_acl(struct acl_options **list, struct acl_options *acl)
11955435475dSsthen {
11965435475dSsthen 	assert(list != NULL);
11975435475dSsthen 
11985435475dSsthen 	if(*list == NULL) {
11995435475dSsthen 		*list = acl;
12005435475dSsthen 	} else {
12015435475dSsthen 		struct acl_options *tail = *list;
12025435475dSsthen 		while(tail->next != NULL)
12035435475dSsthen 			tail = tail->next;
12045435475dSsthen 		tail->next = acl;
12055435475dSsthen 	}
12065435475dSsthen }
12075435475dSsthen 
1208063644e9Sflorian static void
add_to_last_acl(struct acl_options ** list,char * tls_auth_name)1209063644e9Sflorian add_to_last_acl(struct acl_options **list, char *tls_auth_name)
1210063644e9Sflorian {
1211063644e9Sflorian 	struct acl_options *tail = *list;
1212063644e9Sflorian 	assert(list != NULL);
1213063644e9Sflorian 	assert(*list != NULL);
1214063644e9Sflorian 	while(tail->next != NULL)
1215063644e9Sflorian 		tail = tail->next;
1216063644e9Sflorian 	tail->tls_auth_name = tls_auth_name;
1217063644e9Sflorian }
1218063644e9Sflorian 
1219308d2509Sflorian static int
parse_boolean(const char * str,int * bln)1220308d2509Sflorian parse_boolean(const char *str, int *bln)
1221308d2509Sflorian {
1222308d2509Sflorian 	if(strcmp(str, "yes") == 0) {
1223308d2509Sflorian 		*bln = 1;
1224308d2509Sflorian 	} else if(strcmp(str, "no") == 0) {
1225308d2509Sflorian 		*bln = 0;
1226308d2509Sflorian 	} else {
1227308d2509Sflorian 		return 0;
1228308d2509Sflorian 	}
1229308d2509Sflorian 
1230308d2509Sflorian 	return 1;
1231308d2509Sflorian }
1232308d2509Sflorian 
1233308d2509Sflorian static int
parse_expire_expr(const char * str,long long * num,uint8_t * expr)1234ac5517e4Sflorian parse_expire_expr(const char *str, long long *num, uint8_t *expr)
1235ac5517e4Sflorian {
1236ac5517e4Sflorian 	if(parse_number(str, num)) {
1237ac5517e4Sflorian 		*expr = EXPIRE_TIME_HAS_VALUE;
1238ac5517e4Sflorian 		return 1;
1239ac5517e4Sflorian 	}
1240ac5517e4Sflorian 	if(strcmp(str, REFRESHPLUSRETRYPLUS1_STR) == 0) {
1241ac5517e4Sflorian 		*num = 0;
1242ac5517e4Sflorian 		*expr = REFRESHPLUSRETRYPLUS1;
1243ac5517e4Sflorian 		return 1;
1244ac5517e4Sflorian 	}
1245ac5517e4Sflorian 	return 0;
1246ac5517e4Sflorian }
1247ac5517e4Sflorian 
1248ac5517e4Sflorian static int
parse_number(const char * str,long long * num)1249308d2509Sflorian parse_number(const char *str, long long *num)
1250308d2509Sflorian {
1251308d2509Sflorian 	/* ensure string consists entirely of digits */
1252308d2509Sflorian 	size_t pos = 0;
1253308d2509Sflorian 	while(str[pos] >= '0' && str[pos] <= '9') {
1254308d2509Sflorian 		pos++;
1255308d2509Sflorian 	}
1256308d2509Sflorian 
1257308d2509Sflorian 	if(pos != 0 && str[pos] == '\0') {
1258308d2509Sflorian 		*num = strtoll(str, NULL, 10);
1259308d2509Sflorian 		return 1;
1260308d2509Sflorian 	}
1261308d2509Sflorian 
1262308d2509Sflorian 	return 0;
1263308d2509Sflorian }
1264308d2509Sflorian 
1265308d2509Sflorian static int
parse_range(const char * str,long long * low,long long * high)1266308d2509Sflorian parse_range(const char *str, long long *low, long long *high)
1267308d2509Sflorian {
1268308d2509Sflorian 	const char *ptr = str;
1269308d2509Sflorian 	long long num[2];
1270308d2509Sflorian 
1271308d2509Sflorian 	/* require range to begin with a number */
1272308d2509Sflorian 	if(*ptr < '0' || *ptr > '9') {
1273308d2509Sflorian 		return 0;
1274308d2509Sflorian 	}
1275308d2509Sflorian 
1276308d2509Sflorian 	num[0] = strtoll(ptr, (char **)&ptr, 10);
1277308d2509Sflorian 
1278308d2509Sflorian 	/* require number to be followed by nothing at all or a dash */
1279308d2509Sflorian 	if(*ptr == '\0') {
1280308d2509Sflorian 		*low = num[0];
1281308d2509Sflorian 		*high = num[0];
1282308d2509Sflorian 		return 1;
1283308d2509Sflorian 	} else if(*ptr != '-') {
1284308d2509Sflorian 		return 0;
1285308d2509Sflorian 	}
1286308d2509Sflorian 
1287308d2509Sflorian 	++ptr;
1288308d2509Sflorian 	/* require dash to be followed by a number */
1289308d2509Sflorian 	if(*ptr < '0' || *ptr > '9') {
1290308d2509Sflorian 		return 0;
1291308d2509Sflorian 	}
1292308d2509Sflorian 
1293308d2509Sflorian 	num[1] = strtoll(ptr, (char **)&ptr, 10);
1294308d2509Sflorian 
1295308d2509Sflorian 	/* require number to be followed by nothing at all */
1296308d2509Sflorian 	if(*ptr == '\0') {
1297308d2509Sflorian 		if(num[0] < num[1]) {
1298308d2509Sflorian 			*low = num[0];
1299308d2509Sflorian 			*high = num[1];
1300308d2509Sflorian 		} else {
1301308d2509Sflorian 			*low = num[1];
1302308d2509Sflorian 			*high = num[0];
1303308d2509Sflorian 		}
1304308d2509Sflorian 		return 1;
1305308d2509Sflorian 	}
1306308d2509Sflorian 
1307308d2509Sflorian 	return 0;
1308308d2509Sflorian }
1309*bf87c3c0Sflorian 
1310*bf87c3c0Sflorian static int
parse_catalog_role(const char * str,int * role)1311*bf87c3c0Sflorian parse_catalog_role(const char *str, int *role)
1312*bf87c3c0Sflorian {
1313*bf87c3c0Sflorian 	if(strcasecmp(str, "consumer") == 0) {
1314*bf87c3c0Sflorian 		*role = CATALOG_ROLE_CONSUMER;
1315*bf87c3c0Sflorian 	} else if(strcmp(str, "producer") == 0) {
1316*bf87c3c0Sflorian 		*role = CATALOG_ROLE_PRODUCER;
1317*bf87c3c0Sflorian 	} else {
1318*bf87c3c0Sflorian 		return 0;
1319*bf87c3c0Sflorian 	}
1320*bf87c3c0Sflorian 	return 1;
1321*bf87c3c0Sflorian }
1322*bf87c3c0Sflorian 
1323*bf87c3c0Sflorian 
1324