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