xref: /openbsd/usr.sbin/nsd/configparser.y (revision bf87c3c0)
1 /*
2  * configparser.y -- yacc grammar for NSD configuration files
3  *
4  * Copyright (c) 2001-2019, NLnet Labs. All rights reserved.
5  *
6  * See LICENSE for the license.
7  *
8  */
9 
10 %{
11 #include "config.h"
12 
13 #include <assert.h>
14 #include <errno.h>
15 #include <stdio.h>
16 #include <string.h>
17 
18 #include "options.h"
19 #include "util.h"
20 #include "dname.h"
21 #include "tsig.h"
22 #include "rrl.h"
23 
24 int yylex(void);
25 
26 #ifdef __cplusplus
27 extern "C"
28 #endif
29 
30 /* these need to be global, otherwise they cannot be used inside yacc */
31 extern config_parser_state_type *cfg_parser;
32 
33 static void append_acl(struct acl_options **list, struct acl_options *acl);
34 static void add_to_last_acl(struct acl_options **list, char *ac);
35 static int parse_boolean(const char *str, int *bln);
36 static int parse_catalog_role(const char *str, int *role);
37 static int parse_expire_expr(const char *str, long long *num, uint8_t *expr);
38 static int parse_number(const char *str, long long *num);
39 static int parse_range(const char *str, long long *low, long long *high);
40 
41 struct component {
42 	struct component *next;
43 	char *str;
44 };
45 
46 %}
47 
48 %union {
49   char *str;
50   long long llng;
51   int bln;
52   struct ip_address_option *ip;
53   struct range_option *range;
54   struct cpu_option *cpu;
55   char **strv;
56   struct component *comp;
57   int role;
58 }
59 
60 %token <str> STRING
61 %type <llng> number
62 %type <bln> boolean
63 %type <ip> ip_address
64 %type <llng> service_cpu_affinity
65 %type <cpu> cpus
66 %type <strv> command
67 %type <comp> arguments
68 %type <role> catalog_role
69 
70 /* server */
71 %token VAR_SERVER
72 %token VAR_SERVER_COUNT
73 %token VAR_IP_ADDRESS
74 %token VAR_IP_TRANSPARENT
75 %token VAR_IP_FREEBIND
76 %token VAR_REUSEPORT
77 %token VAR_SEND_BUFFER_SIZE
78 %token VAR_RECEIVE_BUFFER_SIZE
79 %token VAR_DEBUG_MODE
80 %token VAR_IP4_ONLY
81 %token VAR_IP6_ONLY
82 %token VAR_DO_IP4
83 %token VAR_DO_IP6
84 %token VAR_PORT
85 %token VAR_USE_SYSTEMD
86 %token VAR_VERBOSITY
87 %token VAR_USERNAME
88 %token VAR_CHROOT
89 %token VAR_ZONESDIR
90 %token VAR_ZONELISTFILE
91 %token VAR_DATABASE
92 %token VAR_LOGFILE
93 %token VAR_LOG_ONLY_SYSLOG
94 %token VAR_PIDFILE
95 %token VAR_DIFFFILE
96 %token VAR_XFRDFILE
97 %token VAR_XFRDIR
98 %token VAR_HIDE_VERSION
99 %token VAR_HIDE_IDENTITY
100 %token VAR_VERSION
101 %token VAR_IDENTITY
102 %token VAR_NSID
103 %token VAR_TCP_COUNT
104 %token VAR_TCP_REJECT_OVERFLOW
105 %token VAR_TCP_QUERY_COUNT
106 %token VAR_TCP_TIMEOUT
107 %token VAR_TCP_MSS
108 %token VAR_OUTGOING_TCP_MSS
109 %token VAR_IPV4_EDNS_SIZE
110 %token VAR_IPV6_EDNS_SIZE
111 %token VAR_STATISTICS
112 %token VAR_XFRD_RELOAD_TIMEOUT
113 %token VAR_LOG_TIME_ASCII
114 %token VAR_ROUND_ROBIN
115 %token VAR_MINIMAL_RESPONSES
116 %token VAR_CONFINE_TO_ZONE
117 %token VAR_REFUSE_ANY
118 %token VAR_ZONEFILES_CHECK
119 %token VAR_ZONEFILES_WRITE
120 %token VAR_RRL_SIZE
121 %token VAR_RRL_RATELIMIT
122 %token VAR_RRL_SLIP
123 %token VAR_RRL_IPV4_PREFIX_LENGTH
124 %token VAR_RRL_IPV6_PREFIX_LENGTH
125 %token VAR_RRL_WHITELIST_RATELIMIT
126 %token VAR_TLS_SERVICE_KEY
127 %token VAR_TLS_SERVICE_PEM
128 %token VAR_TLS_SERVICE_OCSP
129 %token VAR_TLS_PORT
130 %token VAR_TLS_CERT_BUNDLE
131 %token VAR_PROXY_PROTOCOL_PORT
132 %token VAR_CPU_AFFINITY
133 %token VAR_XFRD_CPU_AFFINITY
134 %token <llng> VAR_SERVER_CPU_AFFINITY
135 %token VAR_DROP_UPDATES
136 %token VAR_XFRD_TCP_MAX
137 %token VAR_XFRD_TCP_PIPELINE
138 
139 /* dnstap */
140 %token VAR_DNSTAP
141 %token VAR_DNSTAP_ENABLE
142 %token VAR_DNSTAP_SOCKET_PATH
143 %token VAR_DNSTAP_IP
144 %token VAR_DNSTAP_TLS
145 %token VAR_DNSTAP_TLS_SERVER_NAME
146 %token VAR_DNSTAP_TLS_CERT_BUNDLE
147 %token VAR_DNSTAP_TLS_CLIENT_KEY_FILE
148 %token VAR_DNSTAP_TLS_CLIENT_CERT_FILE
149 %token VAR_DNSTAP_SEND_IDENTITY
150 %token VAR_DNSTAP_SEND_VERSION
151 %token VAR_DNSTAP_IDENTITY
152 %token VAR_DNSTAP_VERSION
153 %token VAR_DNSTAP_LOG_AUTH_QUERY_MESSAGES
154 %token VAR_DNSTAP_LOG_AUTH_RESPONSE_MESSAGES
155 
156 /* remote-control */
157 %token VAR_REMOTE_CONTROL
158 %token VAR_CONTROL_ENABLE
159 %token VAR_CONTROL_INTERFACE
160 %token VAR_CONTROL_PORT
161 %token VAR_SERVER_KEY_FILE
162 %token VAR_SERVER_CERT_FILE
163 %token VAR_CONTROL_KEY_FILE
164 %token VAR_CONTROL_CERT_FILE
165 
166 /* key */
167 %token VAR_KEY
168 %token VAR_ALGORITHM
169 %token VAR_SECRET
170 
171 /* xot auth */
172 %token VAR_TLS_AUTH
173 %token VAR_TLS_AUTH_DOMAIN_NAME
174 %token VAR_TLS_AUTH_CLIENT_CERT
175 %token VAR_TLS_AUTH_CLIENT_KEY
176 %token VAR_TLS_AUTH_CLIENT_KEY_PW
177 
178 /* pattern */
179 %token VAR_PATTERN
180 %token VAR_NAME
181 %token VAR_ZONEFILE
182 %token VAR_NOTIFY
183 %token VAR_PROVIDE_XFR
184 %token VAR_ALLOW_QUERY
185 %token VAR_AXFR
186 %token VAR_UDP
187 %token VAR_NOTIFY_RETRY
188 %token VAR_ALLOW_NOTIFY
189 %token VAR_REQUEST_XFR
190 %token VAR_ALLOW_AXFR_FALLBACK
191 %token VAR_OUTGOING_INTERFACE
192 %token VAR_ANSWER_COOKIE
193 %token VAR_COOKIE_SECRET
194 %token VAR_COOKIE_SECRET_FILE
195 %token VAR_MAX_REFRESH_TIME
196 %token VAR_MIN_REFRESH_TIME
197 %token VAR_MAX_RETRY_TIME
198 %token VAR_MIN_RETRY_TIME
199 %token VAR_MIN_EXPIRE_TIME
200 %token VAR_MULTI_PRIMARY_CHECK
201 %token VAR_SIZE_LIMIT_XFR
202 %token VAR_ZONESTATS
203 %token VAR_INCLUDE_PATTERN
204 %token VAR_STORE_IXFR
205 %token VAR_IXFR_SIZE
206 %token VAR_IXFR_NUMBER
207 %token VAR_CREATE_IXFR
208 %token VAR_CATALOG
209 %token VAR_CATALOG_MEMBER_PATTERN
210 %token VAR_CATALOG_PRODUCER_ZONE
211 
212 /* zone */
213 %token VAR_ZONE
214 %token VAR_RRL_WHITELIST
215 
216 /* socket options */
217 %token VAR_SERVERS
218 %token VAR_BINDTODEVICE
219 %token VAR_SETFIB
220 
221 /* verify */
222 %token VAR_VERIFY
223 %token VAR_ENABLE
224 %token VAR_VERIFY_ZONE
225 %token VAR_VERIFY_ZONES
226 %token VAR_VERIFIER
227 %token VAR_VERIFIER_COUNT
228 %token VAR_VERIFIER_FEED_ZONE
229 %token VAR_VERIFIER_TIMEOUT
230 
231 %%
232 
233 blocks:
234     /* may be empty */
235   | blocks block ;
236 
237 block:
238     server
239   | dnstap
240   | remote_control
241   | key
242   | tls_auth
243   | pattern
244   | zone
245   | verify ;
246 
247 server:
248     VAR_SERVER server_block ;
249 
250 server_block:
251     server_block server_option | ;
252 
253 server_option:
254     VAR_IP_ADDRESS ip_address
255       {
256         struct ip_address_option *ip = cfg_parser->opt->ip_addresses;
257 
258         if(ip == NULL) {
259           cfg_parser->opt->ip_addresses = $2;
260         } else {
261           while(ip->next) { ip = ip->next; }
262           ip->next = $2;
263         }
264 
265         cfg_parser->ip = $2;
266       }
267     socket_options
268     {
269       cfg_parser->ip = NULL;
270     }
271   | VAR_SERVER_COUNT number
272     {
273       if ($2 > 0) {
274         cfg_parser->opt->server_count = (int)$2;
275       } else {
276         yyerror("expected a number greater than zero");
277       }
278     }
279   | VAR_IP_TRANSPARENT boolean
280     { cfg_parser->opt->ip_transparent = $2; }
281   | VAR_IP_FREEBIND boolean
282     { cfg_parser->opt->ip_freebind = $2; }
283   | VAR_SEND_BUFFER_SIZE number
284     { cfg_parser->opt->send_buffer_size = (int)$2; }
285   | VAR_RECEIVE_BUFFER_SIZE number
286     { cfg_parser->opt->receive_buffer_size = (int)$2; }
287   | VAR_DEBUG_MODE boolean
288     { cfg_parser->opt->debug_mode = $2; }
289   | VAR_USE_SYSTEMD boolean
290     { /* ignored, obsolete */ }
291   | VAR_HIDE_VERSION boolean
292     { cfg_parser->opt->hide_version = $2; }
293   | VAR_HIDE_IDENTITY boolean
294     { cfg_parser->opt->hide_identity = $2; }
295   | VAR_DROP_UPDATES boolean
296     { cfg_parser->opt->drop_updates = $2; }
297   | VAR_IP4_ONLY boolean
298     { if($2) { cfg_parser->opt->do_ip4 = 1; cfg_parser->opt->do_ip6 = 0; } }
299   | VAR_IP6_ONLY boolean
300     { if($2) { cfg_parser->opt->do_ip4 = 0; cfg_parser->opt->do_ip6 = 1; } }
301   | VAR_DO_IP4 boolean
302     { cfg_parser->opt->do_ip4 = $2; }
303   | VAR_DO_IP6 boolean
304     { cfg_parser->opt->do_ip6 = $2; }
305   | VAR_DATABASE STRING
306     { /* ignored, obsolete */ }
307   | VAR_IDENTITY STRING
308     { cfg_parser->opt->identity = region_strdup(cfg_parser->opt->region, $2); }
309   | VAR_VERSION STRING
310     { cfg_parser->opt->version = region_strdup(cfg_parser->opt->region, $2); }
311   | VAR_NSID STRING
312     {
313       unsigned char* nsid = 0;
314       size_t nsid_len = strlen($2);
315 
316       if (strncasecmp($2, "ascii_", 6) == 0) {
317         nsid_len -= 6; /* discard "ascii_" */
318         if(nsid_len < 65535) {
319           cfg_parser->opt->nsid = region_alloc(cfg_parser->opt->region, nsid_len*2+1);
320           hex_ntop((uint8_t*)$2+6, nsid_len, (char*)cfg_parser->opt->nsid, nsid_len*2+1);
321         } else {
322           yyerror("NSID too long");
323         }
324       } else if (nsid_len % 2 != 0) {
325         yyerror("the NSID must be a hex string of an even length.");
326       } else {
327         nsid_len = nsid_len / 2;
328         if(nsid_len < 65535) {
329           nsid = xalloc(nsid_len);
330           if (hex_pton($2, nsid, nsid_len) == -1) {
331             yyerror("hex string cannot be parsed in NSID.");
332           } else {
333             cfg_parser->opt->nsid = region_strdup(cfg_parser->opt->region, $2);
334           }
335           free(nsid);
336         } else {
337           yyerror("NSID too long");
338         }
339       }
340     }
341   | VAR_LOGFILE STRING
342     { cfg_parser->opt->logfile = region_strdup(cfg_parser->opt->region, $2); }
343   | VAR_LOG_ONLY_SYSLOG boolean
344     { cfg_parser->opt->log_only_syslog = $2; }
345   | VAR_TCP_COUNT number
346     {
347       if ($2 > 0) {
348         cfg_parser->opt->tcp_count = (int)$2;
349       } else {
350         yyerror("expected a number greater than zero");
351       }
352     }
353   | VAR_TCP_REJECT_OVERFLOW boolean
354     { cfg_parser->opt->tcp_reject_overflow = $2; }
355   | VAR_TCP_QUERY_COUNT number
356     { cfg_parser->opt->tcp_query_count = (int)$2; }
357   | VAR_TCP_TIMEOUT number
358     { cfg_parser->opt->tcp_timeout = (int)$2; }
359   | VAR_TCP_MSS number
360     { cfg_parser->opt->tcp_mss = (int)$2; }
361   | VAR_OUTGOING_TCP_MSS number
362     { cfg_parser->opt->outgoing_tcp_mss = (int)$2; }
363   | VAR_IPV4_EDNS_SIZE number
364     { cfg_parser->opt->ipv4_edns_size = (size_t)$2; }
365   | VAR_IPV6_EDNS_SIZE number
366     { cfg_parser->opt->ipv6_edns_size = (size_t)$2; }
367   | VAR_PIDFILE STRING
368     { cfg_parser->opt->pidfile = region_strdup(cfg_parser->opt->region, $2); }
369   | VAR_PORT number
370     {
371       /* port number, stored as a string */
372       char buf[16];
373       (void)snprintf(buf, sizeof(buf), "%lld", $2);
374       cfg_parser->opt->port = region_strdup(cfg_parser->opt->region, buf);
375     }
376   | VAR_REUSEPORT boolean
377     { cfg_parser->opt->reuseport = $2; }
378   | VAR_STATISTICS number
379     { cfg_parser->opt->statistics = (int)$2; }
380   | VAR_CHROOT STRING
381     { cfg_parser->opt->chroot = region_strdup(cfg_parser->opt->region, $2); }
382   | VAR_USERNAME STRING
383     { cfg_parser->opt->username = region_strdup(cfg_parser->opt->region, $2); }
384   | VAR_ZONESDIR STRING
385     { cfg_parser->opt->zonesdir = region_strdup(cfg_parser->opt->region, $2); }
386   | VAR_ZONELISTFILE STRING
387     { cfg_parser->opt->zonelistfile = region_strdup(cfg_parser->opt->region, $2); }
388   | VAR_DIFFFILE STRING
389     { /* ignored, obsolete */ }
390   | VAR_XFRDFILE STRING
391     { cfg_parser->opt->xfrdfile = region_strdup(cfg_parser->opt->region, $2); }
392   | VAR_XFRDIR STRING
393     { cfg_parser->opt->xfrdir = region_strdup(cfg_parser->opt->region, $2); }
394   | VAR_XFRD_RELOAD_TIMEOUT number
395     { cfg_parser->opt->xfrd_reload_timeout = (int)$2; }
396   | VAR_VERBOSITY number
397     { cfg_parser->opt->verbosity = (int)$2; }
398   | VAR_RRL_SIZE number
399     {
400 #ifdef RATELIMIT
401       if ($2 > 0) {
402         cfg_parser->opt->rrl_size = (size_t)$2;
403       } else {
404         yyerror("expected a number greater than zero");
405       }
406 #endif
407     }
408   | VAR_RRL_RATELIMIT number
409     {
410 #ifdef RATELIMIT
411       cfg_parser->opt->rrl_ratelimit = (size_t)$2;
412 #endif
413     }
414   | VAR_RRL_SLIP number
415     {
416 #ifdef RATELIMIT
417       cfg_parser->opt->rrl_slip = (size_t)$2;
418 #endif
419     }
420   | VAR_RRL_IPV4_PREFIX_LENGTH number
421     {
422 #ifdef RATELIMIT
423       if ($2 > 32) {
424         yyerror("invalid IPv4 prefix length");
425       } else {
426         cfg_parser->opt->rrl_ipv4_prefix_length = (size_t)$2;
427       }
428 #endif
429     }
430   | VAR_RRL_IPV6_PREFIX_LENGTH number
431     {
432 #ifdef RATELIMIT
433       if ($2 > 64) {
434         yyerror("invalid IPv6 prefix length");
435       } else {
436         cfg_parser->opt->rrl_ipv6_prefix_length = (size_t)$2;
437       }
438 #endif
439     }
440   | VAR_RRL_WHITELIST_RATELIMIT number
441     {
442 #ifdef RATELIMIT
443       cfg_parser->opt->rrl_whitelist_ratelimit = (size_t)$2;
444 #endif
445     }
446   | VAR_ZONEFILES_CHECK boolean
447     { cfg_parser->opt->zonefiles_check = $2; }
448   | VAR_ZONEFILES_WRITE number
449     { cfg_parser->opt->zonefiles_write = (int)$2; }
450   | VAR_LOG_TIME_ASCII boolean
451     {
452       cfg_parser->opt->log_time_ascii = $2;
453       log_time_asc = cfg_parser->opt->log_time_ascii;
454     }
455   | VAR_ROUND_ROBIN boolean
456     {
457       cfg_parser->opt->round_robin = $2;
458       round_robin = cfg_parser->opt->round_robin;
459     }
460   | VAR_MINIMAL_RESPONSES boolean
461     {
462       cfg_parser->opt->minimal_responses = $2;
463       minimal_responses = cfg_parser->opt->minimal_responses;
464     }
465   | VAR_CONFINE_TO_ZONE boolean
466     { cfg_parser->opt->confine_to_zone = $2; }
467   | VAR_REFUSE_ANY boolean
468     { cfg_parser->opt->refuse_any = $2; }
469   | VAR_TLS_SERVICE_KEY STRING
470     { cfg_parser->opt->tls_service_key = region_strdup(cfg_parser->opt->region, $2); }
471   | VAR_TLS_SERVICE_OCSP STRING
472     { cfg_parser->opt->tls_service_ocsp = region_strdup(cfg_parser->opt->region, $2); }
473   | VAR_TLS_SERVICE_PEM STRING
474     { cfg_parser->opt->tls_service_pem = region_strdup(cfg_parser->opt->region, $2); }
475   | VAR_TLS_PORT number
476     {
477       /* port number, stored as string */
478       char buf[16];
479       (void)snprintf(buf, sizeof(buf), "%lld", $2);
480       cfg_parser->opt->tls_port = region_strdup(cfg_parser->opt->region, buf);
481     }
482   | VAR_TLS_CERT_BUNDLE STRING
483     { cfg_parser->opt->tls_cert_bundle = region_strdup(cfg_parser->opt->region, $2); }
484   | VAR_PROXY_PROTOCOL_PORT number
485     {
486       struct proxy_protocol_port_list* elem = region_alloc_zero(
487 	cfg_parser->opt->region, sizeof(*elem));
488       elem->port = $2;
489       elem->next = cfg_parser->opt->proxy_protocol_port;
490       cfg_parser->opt->proxy_protocol_port = elem;
491     }
492   | VAR_ANSWER_COOKIE boolean
493     { cfg_parser->opt->answer_cookie = $2; }
494   | VAR_COOKIE_SECRET STRING
495     { cfg_parser->opt->cookie_secret = region_strdup(cfg_parser->opt->region, $2); }
496   | VAR_COOKIE_SECRET_FILE STRING
497     { cfg_parser->opt->cookie_secret_file = region_strdup(cfg_parser->opt->region, $2); }
498   | VAR_XFRD_TCP_MAX number
499     { cfg_parser->opt->xfrd_tcp_max = (int)$2; }
500   | VAR_XFRD_TCP_PIPELINE number
501     { cfg_parser->opt->xfrd_tcp_pipeline = (int)$2; }
502   | VAR_CPU_AFFINITY cpus
503     {
504       cfg_parser->opt->cpu_affinity = $2;
505     }
506   | service_cpu_affinity number
507     {
508       if($2 < 0) {
509         yyerror("expected a non-negative number");
510         YYABORT;
511       } else {
512         struct cpu_map_option *opt, *tail;
513 
514         opt = cfg_parser->opt->service_cpu_affinity;
515         while(opt && opt->service != $1) { opt = opt->next; }
516 
517         if(opt) {
518           opt->cpu = $2;
519         } else {
520           opt = region_alloc_zero(cfg_parser->opt->region, sizeof(*opt));
521           opt->service = (int)$1;
522           opt->cpu = (int)$2;
523 
524           tail = cfg_parser->opt->service_cpu_affinity;
525           if(tail) {
526             while(tail->next) { tail = tail->next; }
527             tail->next = opt;
528           } else {
529             cfg_parser->opt->service_cpu_affinity = opt;
530           }
531         }
532       }
533     }
534   ;
535 
536 socket_options:
537   | socket_options socket_option ;
538 
539 socket_option:
540     VAR_SERVERS STRING
541     {
542       char *tok, *ptr, *str;
543       struct range_option *servers = NULL;
544       long long first, last;
545 
546       /* user may specify "0 1", "0" "1", 0 1 or a combination thereof */
547       for(str = $2; (tok = strtok_r(str, " \t", &ptr)); str = NULL) {
548         struct range_option *opt =
549           region_alloc(cfg_parser->opt->region, sizeof(*opt));
550         first = last = 0;
551         if(!parse_range(tok, &first, &last)) {
552           yyerror("invalid server range '%s'", tok);
553           YYABORT;
554         }
555         assert(first >= 0);
556         assert(last >= 0);
557         opt->next = NULL;
558         opt->first = (int)first;
559         opt->last = (int)last;
560         if(servers) {
561           servers = servers->next = opt;
562         } else {
563           servers = cfg_parser->ip->servers = opt;
564         }
565       }
566     }
567   | VAR_BINDTODEVICE boolean
568     { cfg_parser->ip->dev = $2; }
569   | VAR_SETFIB number
570     { cfg_parser->ip->fib = $2; }
571   ;
572 
573 cpus:
574     { $$ = NULL; }
575   | cpus STRING
576     {
577       char *tok, *ptr, *str;
578       struct cpu_option *tail;
579       long long cpu;
580 
581       str = $2;
582       $$ = tail = $1;
583       if(tail) {
584         while(tail->next) { tail = tail->next; }
585       }
586 
587       /* Users may specify "0 1", "0" "1", 0 1 or a combination thereof. */
588       for(str = $2; (tok = strtok_r(str, " \t", &ptr)); str = NULL) {
589         struct cpu_option *opt =
590           region_alloc_zero(cfg_parser->opt->region, sizeof(*opt));
591         cpu = 0;
592         if(!parse_number(tok, &cpu) || cpu < 0) {
593           yyerror("expected a positive number");
594           YYABORT;
595         }
596         assert(cpu >=0);
597         opt->cpu = (int)cpu;
598         if(tail) {
599           tail->next = opt;
600           tail = opt;
601         } else {
602           $$ = tail = opt;
603         }
604       }
605     }
606   ;
607 
608 service_cpu_affinity:
609     VAR_XFRD_CPU_AFFINITY
610     { $$ = -1; }
611   | VAR_SERVER_CPU_AFFINITY
612     {
613       if($1 <= 0) {
614         yyerror("invalid server identifier");
615         YYABORT;
616       }
617       $$ = $1;
618     }
619   ;
620 
621 dnstap:
622     VAR_DNSTAP dnstap_block ;
623 
624 dnstap_block:
625     dnstap_block dnstap_option | ;
626 
627 dnstap_option:
628     VAR_DNSTAP_ENABLE boolean
629     { cfg_parser->opt->dnstap_enable = $2; }
630   | VAR_DNSTAP_SOCKET_PATH STRING
631     { cfg_parser->opt->dnstap_socket_path = region_strdup(cfg_parser->opt->region, $2); }
632   | VAR_DNSTAP_IP STRING
633     { cfg_parser->opt->dnstap_ip = region_strdup(cfg_parser->opt->region, $2); }
634   | VAR_DNSTAP_TLS boolean
635     { cfg_parser->opt->dnstap_tls = $2; }
636   | VAR_DNSTAP_TLS_SERVER_NAME STRING
637     { cfg_parser->opt->dnstap_tls_server_name = region_strdup(cfg_parser->opt->region, $2); }
638   | VAR_DNSTAP_TLS_CERT_BUNDLE STRING
639     { cfg_parser->opt->dnstap_tls_cert_bundle = region_strdup(cfg_parser->opt->region, $2); }
640   | VAR_DNSTAP_TLS_CLIENT_KEY_FILE STRING
641     { cfg_parser->opt->dnstap_tls_client_key_file = region_strdup(cfg_parser->opt->region, $2); }
642   | VAR_DNSTAP_TLS_CLIENT_CERT_FILE STRING
643     { cfg_parser->opt->dnstap_tls_client_cert_file = region_strdup(cfg_parser->opt->region, $2); }
644   | VAR_DNSTAP_SEND_IDENTITY boolean
645     { cfg_parser->opt->dnstap_send_identity = $2; }
646   | VAR_DNSTAP_SEND_VERSION boolean
647     { cfg_parser->opt->dnstap_send_version = $2; }
648   | VAR_DNSTAP_IDENTITY STRING
649     { cfg_parser->opt->dnstap_identity = region_strdup(cfg_parser->opt->region, $2); }
650   | VAR_DNSTAP_VERSION STRING
651     { cfg_parser->opt->dnstap_version = region_strdup(cfg_parser->opt->region, $2); }
652   | VAR_DNSTAP_LOG_AUTH_QUERY_MESSAGES boolean
653     { cfg_parser->opt->dnstap_log_auth_query_messages = $2; }
654   | VAR_DNSTAP_LOG_AUTH_RESPONSE_MESSAGES boolean
655     { cfg_parser->opt->dnstap_log_auth_response_messages = $2; }
656   ;
657 
658 remote_control:
659     VAR_REMOTE_CONTROL remote_control_block ;
660 
661 remote_control_block:
662     remote_control_block remote_control_option | ;
663 
664 remote_control_option:
665     VAR_CONTROL_ENABLE boolean
666     { cfg_parser->opt->control_enable = $2; }
667   | VAR_CONTROL_INTERFACE ip_address
668     {
669       struct ip_address_option *ip = cfg_parser->opt->control_interface;
670       if(ip == NULL) {
671         cfg_parser->opt->control_interface = $2;
672       } else {
673         while(ip->next != NULL) { ip = ip->next; }
674         ip->next = $2;
675       }
676     }
677   | VAR_CONTROL_PORT number
678     {
679       if($2 == 0) {
680         yyerror("control port number expected");
681       } else {
682         cfg_parser->opt->control_port = (int)$2;
683       }
684     }
685   | VAR_SERVER_KEY_FILE STRING
686     { cfg_parser->opt->server_key_file = region_strdup(cfg_parser->opt->region, $2); }
687   | VAR_SERVER_CERT_FILE STRING
688     { cfg_parser->opt->server_cert_file = region_strdup(cfg_parser->opt->region, $2); }
689   | VAR_CONTROL_KEY_FILE STRING
690     { cfg_parser->opt->control_key_file = region_strdup(cfg_parser->opt->region, $2); }
691   | VAR_CONTROL_CERT_FILE STRING
692     { cfg_parser->opt->control_cert_file = region_strdup(cfg_parser->opt->region, $2); }
693   ;
694 
695 tls_auth:
696     VAR_TLS_AUTH
697       {
698         tls_auth_options_type *tls_auth = tls_auth_options_create(cfg_parser->opt->region);
699         assert(cfg_parser->tls_auth == NULL);
700         cfg_parser->tls_auth = tls_auth;
701       }
702       tls_auth_block
703     {
704       struct tls_auth_options *tls_auth = cfg_parser->tls_auth;
705       if(tls_auth->name == NULL) {
706         yyerror("tls-auth has no name");
707       } else if(tls_auth->auth_domain_name == NULL) {
708         yyerror("tls-auth %s has no auth-domain-name", tls_auth->name);
709       } else if(tls_auth_options_find(cfg_parser->opt, tls_auth->name)) {
710         yyerror("duplicate tls-auth %s", tls_auth->name);
711       } else {
712       	tls_auth_options_insert(cfg_parser->opt, tls_auth);
713         cfg_parser->tls_auth = NULL;
714       }
715     } ;
716 
717 tls_auth_block:
718     tls_auth_block tls_auth_option | ;
719 
720 tls_auth_option:
721     VAR_NAME STRING
722     {
723       dname_type *dname;
724       dname = (dname_type *)dname_parse(cfg_parser->opt->region, $2);
725       cfg_parser->tls_auth->name = region_strdup(cfg_parser->opt->region, $2);
726       if(dname == NULL) {
727         yyerror("bad tls-auth name %s", $2);
728       } else {
729         region_recycle(cfg_parser->opt->region, dname, dname_total_size(dname));
730       }
731     }
732   | VAR_TLS_AUTH_DOMAIN_NAME STRING
733     {
734       cfg_parser->tls_auth->auth_domain_name = region_strdup(cfg_parser->opt->region, $2);
735     }
736   | VAR_TLS_AUTH_CLIENT_CERT STRING
737     {
738 	    cfg_parser->tls_auth->client_cert = region_strdup(cfg_parser->opt->region, $2);
739     }
740   | VAR_TLS_AUTH_CLIENT_KEY STRING
741     {
742 	    cfg_parser->tls_auth->client_key = region_strdup(cfg_parser->opt->region, $2);
743     }
744   | VAR_TLS_AUTH_CLIENT_KEY_PW STRING
745     {
746 	    cfg_parser->tls_auth->client_key_pw = region_strdup(cfg_parser->opt->region, $2);
747     }
748   ;
749 
750 key:
751     VAR_KEY
752       {
753         key_options_type *key = key_options_create(cfg_parser->opt->region);
754         key->algorithm = region_strdup(cfg_parser->opt->region, "sha256");
755         assert(cfg_parser->key == NULL);
756         cfg_parser->key = key;
757       }
758       key_block
759     {
760       struct key_options *key = cfg_parser->key;
761       if(key->name == NULL) {
762         yyerror("tsig key has no name");
763       } else if(key->algorithm == NULL) {
764         yyerror("tsig key %s has no algorithm", key->name);
765       } else if(key->secret == NULL) {
766         yyerror("tsig key %s has no secret blob", key->name);
767       } else if(key_options_find(cfg_parser->opt, key->name)) {
768         yyerror("duplicate tsig key %s", key->name);
769       } else {
770         key_options_insert(cfg_parser->opt, key);
771         cfg_parser->key = NULL;
772       }
773     } ;
774 
775 key_block:
776     key_block key_option | ;
777 
778 key_option:
779     VAR_NAME STRING
780     {
781       dname_type *dname;
782 
783       dname = (dname_type *)dname_parse(cfg_parser->opt->region, $2);
784       cfg_parser->key->name = region_strdup(cfg_parser->opt->region, $2);
785       if(dname == NULL) {
786         yyerror("bad tsig key name %s", $2);
787       } else {
788         region_recycle(cfg_parser->opt->region, dname, dname_total_size(dname));
789       }
790     }
791   | VAR_ALGORITHM STRING
792     {
793       if(tsig_get_algorithm_by_name($2) == NULL) {
794         yyerror("bad tsig key algorithm %s", $2);
795       } else {
796         cfg_parser->key->algorithm = region_strdup(cfg_parser->opt->region, $2);
797       }
798     }
799   | VAR_SECRET STRING
800     {
801       uint8_t data[16384];
802       int size;
803 
804       cfg_parser->key->secret = region_strdup(cfg_parser->opt->region, $2);
805       size = __b64_pton($2, data, sizeof(data));
806       if(size == -1) {
807         yyerror("cannot base64 decode tsig secret %s",
808           cfg_parser->key->name?
809           cfg_parser->key->name:"");
810       } else if(size != 0) {
811         memset(data, 0xdd, size); /* wipe secret */
812       }
813     } ;
814 
815 
816 zone:
817     VAR_ZONE
818       {
819         assert(cfg_parser->pattern == NULL);
820         assert(cfg_parser->zone == NULL);
821         cfg_parser->zone = zone_options_create(cfg_parser->opt->region);
822         cfg_parser->zone->part_of_config = 1;
823         cfg_parser->zone->pattern = cfg_parser->pattern =
824           pattern_options_create(cfg_parser->opt->region);
825         cfg_parser->zone->pattern->implicit = 1;
826       }
827     zone_block
828     {
829       assert(cfg_parser->zone != NULL);
830       if(cfg_parser->zone->name == NULL) {
831         yyerror("zone has no name");
832       } else if(!nsd_options_insert_zone(cfg_parser->opt, cfg_parser->zone)) {
833         yyerror("duplicate zone %s", cfg_parser->zone->name);
834       } else if(!nsd_options_insert_pattern(cfg_parser->opt, cfg_parser->zone->pattern)) {
835         yyerror("duplicate pattern %s", cfg_parser->zone->pattern->pname);
836       }
837       cfg_parser->pattern = NULL;
838       cfg_parser->zone = NULL;
839     } ;
840 
841 zone_block:
842     zone_block zone_option | ;
843 
844 zone_option:
845     VAR_NAME STRING
846     {
847       const char *marker = PATTERN_IMPLICIT_MARKER;
848       char *pname = region_alloc(cfg_parser->opt->region, strlen($2) + strlen(marker) + 1);
849       memmove(pname, marker, strlen(marker));
850       memmove(pname + strlen(marker), $2, strlen($2) + 1);
851       cfg_parser->zone->pattern->pname = pname;
852       cfg_parser->zone->name = region_strdup(cfg_parser->opt->region, $2);
853       if(pattern_options_find(cfg_parser->opt, pname)) {
854         yyerror("zone %s cannot be created because implicit pattern %s "
855                     "already exists", $2, pname);
856       }
857     }
858   | pattern_or_zone_option ;
859 
860 pattern:
861     VAR_PATTERN
862       {
863         assert(cfg_parser->pattern == NULL);
864         cfg_parser->pattern = pattern_options_create(cfg_parser->opt->region);
865       }
866       pattern_block
867     {
868       pattern_options_type *pattern = cfg_parser->pattern;
869       if(pattern->pname == NULL) {
870         yyerror("pattern has no name");
871       } else if(!nsd_options_insert_pattern(cfg_parser->opt, pattern)) {
872         yyerror("duplicate pattern %s", pattern->pname);
873       }
874       cfg_parser->pattern = NULL;
875     } ;
876 
877 pattern_block:
878     pattern_block pattern_option | ;
879 
880 pattern_option:
881     VAR_NAME STRING
882     {
883       if(strchr($2, ' ')) {
884         yyerror("space is not allowed in pattern name: '%s'", $2);
885       }
886       cfg_parser->pattern->pname = region_strdup(cfg_parser->opt->region, $2);
887     }
888   | pattern_or_zone_option ;
889 
890 pattern_or_zone_option:
891     VAR_RRL_WHITELIST STRING
892     {
893 #ifdef RATELIMIT
894       cfg_parser->pattern->rrl_whitelist |= rrlstr2type($2);
895 #endif
896     }
897   | VAR_ZONEFILE STRING
898     { cfg_parser->pattern->zonefile = region_strdup(cfg_parser->opt->region, $2); }
899   | VAR_ZONESTATS STRING
900     { cfg_parser->pattern->zonestats = region_strdup(cfg_parser->opt->region, $2); }
901   | VAR_SIZE_LIMIT_XFR number
902     {
903       if($2 > 0) {
904         cfg_parser->pattern->size_limit_xfr = (int)$2;
905       } else {
906         yyerror("expected a number greater than zero");
907       }
908     }
909   | VAR_MULTI_PRIMARY_CHECK boolean
910     { cfg_parser->pattern->multi_primary_check = (int)$2; }
911   | VAR_INCLUDE_PATTERN STRING
912     { config_apply_pattern(cfg_parser->pattern, $2); }
913   | VAR_REQUEST_XFR STRING STRING
914     {
915       acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, $2, $3);
916       if(cfg_parser->pattern->catalog_role == CATALOG_ROLE_PRODUCER)
917         yyerror("catalog producer zones cannot be secondary zones");
918       if(acl->blocked)
919         yyerror("blocked address used for request-xfr");
920       if(acl->rangetype != acl_range_single)
921         yyerror("address range used for request-xfr");
922       append_acl(&cfg_parser->pattern->request_xfr, acl);
923     }
924 	tlsauth_option
925 	{ }
926   | VAR_REQUEST_XFR VAR_AXFR STRING STRING
927     {
928       acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, $3, $4);
929       acl->use_axfr_only = 1;
930       if(acl->blocked)
931         yyerror("blocked address used for request-xfr");
932       if(acl->rangetype != acl_range_single)
933         yyerror("address range used for request-xfr");
934       append_acl(&cfg_parser->pattern->request_xfr, acl);
935     }
936 	tlsauth_option
937 	{ }
938   | VAR_REQUEST_XFR VAR_UDP STRING STRING
939     {
940       acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, $3, $4);
941       acl->allow_udp = 1;
942       if(acl->blocked)
943         yyerror("blocked address used for request-xfr");
944       if(acl->rangetype != acl_range_single)
945         yyerror("address range used for request-xfr");
946       append_acl(&cfg_parser->pattern->request_xfr, acl);
947     }
948   | VAR_ALLOW_NOTIFY STRING STRING
949     {
950       acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, $2, $3);
951       append_acl(&cfg_parser->pattern->allow_notify, acl);
952     }
953   | VAR_NOTIFY STRING STRING
954     {
955       acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, $2, $3);
956       if(acl->blocked)
957         yyerror("blocked address used for notify");
958       if(acl->rangetype != acl_range_single)
959         yyerror("address range used for notify");
960       append_acl(&cfg_parser->pattern->notify, acl);
961     }
962   | VAR_PROVIDE_XFR STRING STRING
963     {
964       acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, $2, $3);
965       append_acl(&cfg_parser->pattern->provide_xfr, acl);
966     }
967   | VAR_ALLOW_QUERY STRING STRING
968     {
969       acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, $2, $3);
970       append_acl(&cfg_parser->pattern->allow_query, acl);
971     }
972   | VAR_OUTGOING_INTERFACE STRING
973     {
974       acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, $2, "NOKEY");
975       append_acl(&cfg_parser->pattern->outgoing_interface, acl);
976     }
977   | VAR_ALLOW_AXFR_FALLBACK boolean
978     {
979       cfg_parser->pattern->allow_axfr_fallback = $2;
980       cfg_parser->pattern->allow_axfr_fallback_is_default = 0;
981     }
982   | VAR_NOTIFY_RETRY number
983     {
984       cfg_parser->pattern->notify_retry = $2;
985       cfg_parser->pattern->notify_retry_is_default = 0;
986     }
987   | VAR_MAX_REFRESH_TIME number
988     {
989       cfg_parser->pattern->max_refresh_time = $2;
990       cfg_parser->pattern->max_refresh_time_is_default = 0;
991     }
992   | VAR_MIN_REFRESH_TIME number
993     {
994       cfg_parser->pattern->min_refresh_time = $2;
995       cfg_parser->pattern->min_refresh_time_is_default = 0;
996     }
997   | VAR_MAX_RETRY_TIME number
998     {
999       cfg_parser->pattern->max_retry_time = $2;
1000       cfg_parser->pattern->max_retry_time_is_default = 0;
1001     }
1002   | VAR_MIN_RETRY_TIME number
1003     {
1004       cfg_parser->pattern->min_retry_time = $2;
1005       cfg_parser->pattern->min_retry_time_is_default = 0;
1006     }
1007   | VAR_MIN_EXPIRE_TIME STRING
1008     {
1009       long long num;
1010       uint8_t expr;
1011 
1012       if (!parse_expire_expr($2, &num, &expr)) {
1013         yyerror("expected an expire time in seconds or \"refresh+retry+1\"");
1014         YYABORT; /* trigger a parser error */
1015       }
1016       cfg_parser->pattern->min_expire_time = num;
1017       cfg_parser->pattern->min_expire_time_expr = expr;
1018     }
1019   | VAR_STORE_IXFR boolean
1020     {
1021       cfg_parser->pattern->store_ixfr = $2;
1022       cfg_parser->pattern->store_ixfr_is_default = 0;
1023     }
1024   | VAR_IXFR_SIZE number
1025     {
1026       cfg_parser->pattern->ixfr_size = $2;
1027       cfg_parser->pattern->ixfr_size_is_default = 0;
1028     }
1029   | VAR_IXFR_NUMBER number
1030     {
1031       cfg_parser->pattern->ixfr_number = $2;
1032       cfg_parser->pattern->ixfr_number_is_default = 0;
1033     }
1034   | VAR_CREATE_IXFR boolean
1035     {
1036       cfg_parser->pattern->create_ixfr = $2;
1037       cfg_parser->pattern->create_ixfr_is_default = 0;
1038     }
1039   | VAR_VERIFY_ZONE boolean
1040     { cfg_parser->pattern->verify_zone = $2; }
1041   | VAR_VERIFIER command
1042     { cfg_parser->pattern->verifier = $2; }
1043   | VAR_VERIFIER_FEED_ZONE boolean
1044     { cfg_parser->pattern->verifier_feed_zone = $2; }
1045   | VAR_VERIFIER_TIMEOUT number
1046     { cfg_parser->pattern->verifier_timeout = $2; }
1047   | VAR_CATALOG catalog_role
1048     {
1049       if($2 == CATALOG_ROLE_PRODUCER && cfg_parser->pattern->request_xfr)
1050         yyerror("catalog producer zones cannot be secondary zones");
1051       cfg_parser->pattern->catalog_role = $2;
1052       cfg_parser->pattern->catalog_role_is_default = 0;
1053     }
1054   | VAR_CATALOG_MEMBER_PATTERN STRING
1055     {
1056       cfg_parser->pattern->catalog_member_pattern = region_strdup(cfg_parser->opt->region, $2);
1057     }
1058   | VAR_CATALOG_PRODUCER_ZONE STRING
1059     {
1060       dname_type *dname;
1061 
1062       if(cfg_parser->zone) {
1063         yyerror("catalog-producer-zone option is for patterns only and cannot "
1064                 "be used in a zone clause");
1065       } else if(!(dname = (dname_type *)dname_parse(cfg_parser->opt->region, $2))) {
1066         yyerror("bad catalog producer name %s", $2);
1067       } else {
1068         region_recycle(cfg_parser->opt->region, dname, dname_total_size(dname));
1069         cfg_parser->pattern->catalog_producer_zone = region_strdup(cfg_parser->opt->region, $2);
1070       }
1071     };
1072 
1073 verify:
1074     VAR_VERIFY verify_block ;
1075 
1076 verify_block:
1077     verify_block verify_option | ;
1078 
1079 verify_option:
1080     VAR_ENABLE boolean
1081     { cfg_parser->opt->verify_enable = $2; }
1082   | VAR_IP_ADDRESS ip_address
1083     {
1084       struct ip_address_option *ip = cfg_parser->opt->verify_ip_addresses;
1085       if(!ip) {
1086         cfg_parser->opt->verify_ip_addresses = $2;
1087       } else {
1088         while(ip->next) { ip = ip->next; }
1089         ip->next = $2;
1090       }
1091     }
1092   | VAR_PORT number
1093     {
1094       /* port number, stored as a string */
1095       char buf[16];
1096       (void)snprintf(buf, sizeof(buf), "%lld", $2);
1097       cfg_parser->opt->verify_port = region_strdup(cfg_parser->opt->region, buf);
1098     }
1099   | VAR_VERIFY_ZONES boolean
1100     { cfg_parser->opt->verify_zones = $2; }
1101   | VAR_VERIFIER command
1102     { cfg_parser->opt->verifier = $2; }
1103   | VAR_VERIFIER_COUNT number
1104     { cfg_parser->opt->verifier_count = (int)$2; }
1105   | VAR_VERIFIER_TIMEOUT number
1106     { cfg_parser->opt->verifier_timeout = (int)$2; }
1107   | VAR_VERIFIER_FEED_ZONE boolean
1108     { cfg_parser->opt->verifier_feed_zone = $2; } ;
1109 
1110 command:
1111     STRING arguments
1112     {
1113       char **argv;
1114       size_t argc = 1;
1115       for(struct component *i = $2; i; i = i->next) {
1116         argc++;
1117       }
1118       argv = region_alloc_zero(
1119         cfg_parser->opt->region, (argc + 1) * sizeof(char *));
1120       argc = 0;
1121       argv[argc++] = $1;
1122       for(struct component *j, *i = $2; i; i = j) {
1123         j = i->next;
1124         argv[argc++] = i->str;
1125         region_recycle(cfg_parser->opt->region, i, sizeof(*i));
1126       }
1127       $$ = argv;
1128     } ;
1129 
1130 arguments:
1131     { $$ = NULL; }
1132   | arguments STRING
1133     {
1134       struct component *comp = region_alloc_zero(
1135         cfg_parser->opt->region, sizeof(*comp));
1136       comp->str = region_strdup(cfg_parser->opt->region, $2);
1137       if($1) {
1138         struct component *tail = $1;
1139         while(tail->next) {
1140          tail = tail->next;
1141         }
1142         tail->next = comp;
1143         $$ = $1;
1144       } else {
1145         $$ = comp;
1146       }
1147     } ;
1148 
1149 ip_address:
1150     STRING
1151     {
1152       struct ip_address_option *ip = region_alloc_zero(
1153         cfg_parser->opt->region, sizeof(*ip));
1154       ip->address = region_strdup(cfg_parser->opt->region, $1);
1155       ip->fib = -1;
1156       $$ = ip;
1157     } ;
1158 
1159 number:
1160     STRING
1161     {
1162       if(!parse_number($1, &$$)) {
1163         yyerror("expected a number");
1164         YYABORT; /* trigger a parser error */
1165       }
1166     } ;
1167 
1168 boolean:
1169     STRING
1170     {
1171       if(!parse_boolean($1, &$$)) {
1172         yyerror("expected yes or no");
1173         YYABORT; /* trigger a parser error */
1174       }
1175     } ;
1176 
1177 tlsauth_option:
1178 	| STRING
1179 	{ char *tls_auth_name = region_strdup(cfg_parser->opt->region, $1);
1180 	  add_to_last_acl(&cfg_parser->pattern->request_xfr, tls_auth_name);} ;
1181 
1182 catalog_role:
1183     STRING
1184     {
1185       if(!parse_catalog_role($1, &$$)) {
1186         yyerror("expected consumer or producer");
1187         YYABORT; /* trigger a parser error */
1188       }
1189     } ;
1190 
1191 %%
1192 
1193 static void
1194 append_acl(struct acl_options **list, struct acl_options *acl)
1195 {
1196 	assert(list != NULL);
1197 
1198 	if(*list == NULL) {
1199 		*list = acl;
1200 	} else {
1201 		struct acl_options *tail = *list;
1202 		while(tail->next != NULL)
1203 			tail = tail->next;
1204 		tail->next = acl;
1205 	}
1206 }
1207 
1208 static void
add_to_last_acl(struct acl_options ** list,char * tls_auth_name)1209 add_to_last_acl(struct acl_options **list, char *tls_auth_name)
1210 {
1211 	struct acl_options *tail = *list;
1212 	assert(list != NULL);
1213 	assert(*list != NULL);
1214 	while(tail->next != NULL)
1215 		tail = tail->next;
1216 	tail->tls_auth_name = tls_auth_name;
1217 }
1218 
1219 static int
parse_boolean(const char * str,int * bln)1220 parse_boolean(const char *str, int *bln)
1221 {
1222 	if(strcmp(str, "yes") == 0) {
1223 		*bln = 1;
1224 	} else if(strcmp(str, "no") == 0) {
1225 		*bln = 0;
1226 	} else {
1227 		return 0;
1228 	}
1229 
1230 	return 1;
1231 }
1232 
1233 static int
parse_expire_expr(const char * str,long long * num,uint8_t * expr)1234 parse_expire_expr(const char *str, long long *num, uint8_t *expr)
1235 {
1236 	if(parse_number(str, num)) {
1237 		*expr = EXPIRE_TIME_HAS_VALUE;
1238 		return 1;
1239 	}
1240 	if(strcmp(str, REFRESHPLUSRETRYPLUS1_STR) == 0) {
1241 		*num = 0;
1242 		*expr = REFRESHPLUSRETRYPLUS1;
1243 		return 1;
1244 	}
1245 	return 0;
1246 }
1247 
1248 static int
parse_number(const char * str,long long * num)1249 parse_number(const char *str, long long *num)
1250 {
1251 	/* ensure string consists entirely of digits */
1252 	size_t pos = 0;
1253 	while(str[pos] >= '0' && str[pos] <= '9') {
1254 		pos++;
1255 	}
1256 
1257 	if(pos != 0 && str[pos] == '\0') {
1258 		*num = strtoll(str, NULL, 10);
1259 		return 1;
1260 	}
1261 
1262 	return 0;
1263 }
1264 
1265 static int
parse_range(const char * str,long long * low,long long * high)1266 parse_range(const char *str, long long *low, long long *high)
1267 {
1268 	const char *ptr = str;
1269 	long long num[2];
1270 
1271 	/* require range to begin with a number */
1272 	if(*ptr < '0' || *ptr > '9') {
1273 		return 0;
1274 	}
1275 
1276 	num[0] = strtoll(ptr, (char **)&ptr, 10);
1277 
1278 	/* require number to be followed by nothing at all or a dash */
1279 	if(*ptr == '\0') {
1280 		*low = num[0];
1281 		*high = num[0];
1282 		return 1;
1283 	} else if(*ptr != '-') {
1284 		return 0;
1285 	}
1286 
1287 	++ptr;
1288 	/* require dash to be followed by a number */
1289 	if(*ptr < '0' || *ptr > '9') {
1290 		return 0;
1291 	}
1292 
1293 	num[1] = strtoll(ptr, (char **)&ptr, 10);
1294 
1295 	/* require number to be followed by nothing at all */
1296 	if(*ptr == '\0') {
1297 		if(num[0] < num[1]) {
1298 			*low = num[0];
1299 			*high = num[1];
1300 		} else {
1301 			*low = num[1];
1302 			*high = num[0];
1303 		}
1304 		return 1;
1305 	}
1306 
1307 	return 0;
1308 }
1309 
1310 static int
parse_catalog_role(const char * str,int * role)1311 parse_catalog_role(const char *str, int *role)
1312 {
1313 	if(strcasecmp(str, "consumer") == 0) {
1314 		*role = CATALOG_ROLE_CONSUMER;
1315 	} else if(strcmp(str, "producer") == 0) {
1316 		*role = CATALOG_ROLE_PRODUCER;
1317 	} else {
1318 		return 0;
1319 	}
1320 	return 1;
1321 }
1322 
1323 
1324