xref: /netbsd-src/external/bsd/nsd/dist/configparser.y (revision 479d8f7d843cc1b22d497efdf1f27a50ee8418d4)
1 /*
2  * configparser.y -- yacc grammar for NSD configuration files
3  *
4  * Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
5  *
6  * See LICENSE for the license.
7  *
8  */
9 
10 %{
11 #include "config.h"
12 
13 #include <stdarg.h>
14 #include <stdio.h>
15 #include <string.h>
16 #include <stdlib.h>
17 #include <assert.h>
18 
19 #include "options.h"
20 #include "util.h"
21 #include "dname.h"
22 #include "tsig.h"
23 #include "rrl.h"
24 #include "configyyrename.h"
25 int c_lex(void);
26 void c_error(const char *message);
27 
28 #ifdef __cplusplus
29 extern "C"
30 #endif /* __cplusplus */
31 
32 /* these need to be global, otherwise they cannot be used inside yacc */
33 extern config_parser_state_t* cfg_parser;
34 
35 #if 0
36 #define OUTYY(s) printf s /* used ONLY when debugging */
37 #else
38 #define OUTYY(s)
39 #endif
40 
41 %}
42 %union {
43 	char*	str;
44 }
45 
46 %token SPACE LETTER NEWLINE COMMENT COLON ANY ZONESTR
47 %token <str> STRING
48 %token VAR_SERVER VAR_NAME VAR_IP_ADDRESS VAR_IP_TRANSPARENT VAR_DEBUG_MODE
49 %token VAR_IP4_ONLY VAR_IP6_ONLY VAR_DATABASE VAR_IDENTITY VAR_NSID VAR_LOGFILE
50 %token VAR_SERVER_COUNT VAR_TCP_COUNT VAR_PIDFILE VAR_PORT VAR_STATISTICS
51 %token VAR_CHROOT VAR_USERNAME VAR_ZONESDIR VAR_XFRDFILE VAR_DIFFFILE
52 %token VAR_XFRD_RELOAD_TIMEOUT VAR_TCP_QUERY_COUNT VAR_TCP_TIMEOUT
53 %token VAR_IPV4_EDNS_SIZE VAR_IPV6_EDNS_SIZE VAR_DO_IP4 VAR_DO_IP6
54 %token VAR_TCP_MSS VAR_OUTGOING_TCP_MSS VAR_IP_FREEBIND
55 %token VAR_ZONEFILE
56 %token VAR_ZONE
57 %token VAR_ALLOW_NOTIFY VAR_REQUEST_XFR VAR_NOTIFY VAR_PROVIDE_XFR VAR_SIZE_LIMIT_XFR
58 %token VAR_NOTIFY_RETRY VAR_OUTGOING_INTERFACE VAR_ALLOW_AXFR_FALLBACK
59 %token VAR_KEY
60 %token VAR_ALGORITHM VAR_SECRET
61 %token VAR_AXFR VAR_UDP
62 %token VAR_VERBOSITY VAR_HIDE_VERSION
63 %token VAR_PATTERN VAR_INCLUDEPATTERN VAR_ZONELISTFILE
64 %token VAR_REMOTE_CONTROL VAR_CONTROL_ENABLE VAR_CONTROL_INTERFACE
65 %token VAR_CONTROL_PORT VAR_SERVER_KEY_FILE VAR_SERVER_CERT_FILE
66 %token VAR_CONTROL_KEY_FILE VAR_CONTROL_CERT_FILE VAR_XFRDIR
67 %token VAR_RRL_SIZE VAR_RRL_RATELIMIT VAR_RRL_SLIP
68 %token VAR_RRL_IPV4_PREFIX_LENGTH VAR_RRL_IPV6_PREFIX_LENGTH
69 %token VAR_RRL_WHITELIST_RATELIMIT VAR_RRL_WHITELIST
70 %token VAR_ZONEFILES_CHECK VAR_ZONEFILES_WRITE VAR_LOG_TIME_ASCII
71 %token VAR_ROUND_ROBIN VAR_ZONESTATS VAR_REUSEPORT VAR_VERSION
72 %token VAR_MAX_REFRESH_TIME VAR_MIN_REFRESH_TIME
73 %token VAR_MAX_RETRY_TIME VAR_MIN_RETRY_TIME
74 %token VAR_MULTI_MASTER_CHECK
75 
76 %%
77 toplevelvars: /* empty */ | toplevelvars toplevelvar ;
78 toplevelvar: serverstart contents_server | zonestart contents_zone |
79 	keystart contents_key | patternstart contents_pattern |
80 	rcstart contents_rc;
81 
82 /* server: declaration */
83 serverstart: VAR_SERVER
84 	{ OUTYY(("\nP(server:)\n"));
85 		if(cfg_parser->server_settings_seen) {
86 			yyerror("duplicate server: element.");
87 		}
88 		cfg_parser->server_settings_seen = 1;
89 	}
90 	;
91 contents_server: contents_server content_server | ;
92 content_server: server_ip_address | server_ip_transparent | server_debug_mode | server_ip4_only |
93 	server_ip6_only | server_database | server_identity | server_nsid | server_logfile |
94 	server_server_count | server_tcp_count | server_pidfile | server_port |
95 	server_statistics | server_chroot | server_username | server_zonesdir |
96 	server_difffile | server_xfrdfile | server_xfrd_reload_timeout |
97 	server_tcp_query_count | server_tcp_timeout | server_ipv4_edns_size |
98 	server_ipv6_edns_size | server_verbosity | server_hide_version |
99 	server_zonelistfile | server_xfrdir |
100 	server_tcp_mss | server_outgoing_tcp_mss |
101 	server_rrl_size | server_rrl_ratelimit | server_rrl_slip |
102 	server_rrl_ipv4_prefix_length | server_rrl_ipv6_prefix_length | server_rrl_whitelist_ratelimit |
103 	server_zonefiles_check | server_do_ip4 | server_do_ip6 |
104 	server_zonefiles_write | server_log_time_ascii | server_round_robin |
105 	server_reuseport | server_version | server_ip_freebind;
106 server_ip_address: VAR_IP_ADDRESS STRING
107 	{
108 		OUTYY(("P(server_ip_address:%s)\n", $2));
109 		if(cfg_parser->current_ip_address_option) {
110 			cfg_parser->current_ip_address_option->next =
111 				(ip_address_option_t*)region_alloc(
112 				cfg_parser->opt->region, sizeof(ip_address_option_t));
113 			cfg_parser->current_ip_address_option =
114 				cfg_parser->current_ip_address_option->next;
115 			cfg_parser->current_ip_address_option->next=0;
116 		} else {
117 			cfg_parser->current_ip_address_option =
118 				(ip_address_option_t*)region_alloc(
119 				cfg_parser->opt->region, sizeof(ip_address_option_t));
120 			cfg_parser->current_ip_address_option->next=0;
121 			cfg_parser->opt->ip_addresses = cfg_parser->current_ip_address_option;
122 		}
123 
124 		cfg_parser->current_ip_address_option->address =
125 			region_strdup(cfg_parser->opt->region, $2);
126 	}
127 	;
128 server_ip_transparent: VAR_IP_TRANSPARENT STRING
129 	{
130 		OUTYY(("P(server_ip_transparent:%s)\n", $2));
131 		if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
132 			yyerror("expected yes or no.");
133 		else cfg_parser->opt->ip_transparent = (strcmp($2, "yes")==0);
134 	}
135 	;
136 server_ip_freebind: VAR_IP_FREEBIND STRING
137 	{
138 		OUTYY(("P(server_ip_freebind:%s)\n", $2));
139 		if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
140 			yyerror("expected yes or no.");
141 		else cfg_parser->opt->ip_freebind = (strcmp($2, "yes")==0);
142 	}
143 	;
144 server_debug_mode: VAR_DEBUG_MODE STRING
145 	{
146 		OUTYY(("P(server_debug_mode:%s)\n", $2));
147 		if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
148 			yyerror("expected yes or no.");
149 		else cfg_parser->opt->debug_mode = (strcmp($2, "yes")==0);
150 	}
151 	;
152 server_verbosity: VAR_VERBOSITY STRING
153 	{
154 		OUTYY(("P(server_verbosity:%s)\n", $2));
155 		if(atoi($2) == 0 && strcmp($2, "0") != 0)
156 			yyerror("number expected");
157 		else cfg_parser->opt->verbosity = atoi($2);
158 	}
159 	;
160 server_hide_version: VAR_HIDE_VERSION STRING
161 	{
162 		OUTYY(("P(server_hide_version:%s)\n", $2));
163 		if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
164 			yyerror("expected yes or no.");
165 		else cfg_parser->opt->hide_version = (strcmp($2, "yes")==0);
166 	}
167 	;
168 server_ip4_only: VAR_IP4_ONLY STRING
169 	{
170 		/* for backwards compatibility in config file with NSD3 */
171 		OUTYY(("P(server_ip4_only:%s)\n", $2));
172 		if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
173 			yyerror("expected yes or no.");
174 		else if(strcmp($2, "yes")==0) {
175 			cfg_parser->opt->do_ip4 = 1;
176 			cfg_parser->opt->do_ip6 = 0;
177 		}
178 	}
179 	;
180 server_ip6_only: VAR_IP6_ONLY STRING
181 	{
182 		/* for backwards compatibility in config file with NSD3 */
183 		OUTYY(("P(server_ip6_only:%s)\n", $2));
184 		if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
185 			yyerror("expected yes or no.");
186 		else if(strcmp($2, "yes")==0) {
187 			cfg_parser->opt->do_ip6 = 1;
188 			cfg_parser->opt->do_ip4 = 0;
189 		}
190 	}
191 	;
192 server_do_ip4: VAR_DO_IP4 STRING
193 	{
194 		OUTYY(("P(server_do_ip4:%s)\n", $2));
195 		if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
196 			yyerror("expected yes or no.");
197 		else cfg_parser->opt->do_ip4 = (strcmp($2, "yes")==0);
198 	}
199 	;
200 server_do_ip6: VAR_DO_IP6 STRING
201 	{
202 		OUTYY(("P(server_do_ip6:%s)\n", $2));
203 		if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
204 			yyerror("expected yes or no.");
205 		else cfg_parser->opt->do_ip6 = (strcmp($2, "yes")==0);
206 	}
207 	;
208 server_reuseport: VAR_REUSEPORT STRING
209 	{
210 		OUTYY(("P(server_reuseport:%s)\n", $2));
211 		if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
212 			yyerror("expected yes or no.");
213 		else cfg_parser->opt->reuseport = (strcmp($2, "yes")==0);
214 	}
215 	;
216 server_database: VAR_DATABASE STRING
217 	{
218 		OUTYY(("P(server_database:%s)\n", $2));
219 		cfg_parser->opt->database = region_strdup(cfg_parser->opt->region, $2);
220 		if(cfg_parser->opt->database[0] == 0 &&
221 			cfg_parser->opt->zonefiles_write == 0)
222 			cfg_parser->opt->zonefiles_write = ZONEFILES_WRITE_INTERVAL;
223 	}
224 	;
225 server_identity: VAR_IDENTITY STRING
226 	{
227 		OUTYY(("P(server_identity:%s)\n", $2));
228 		cfg_parser->opt->identity = region_strdup(cfg_parser->opt->region, $2);
229 	}
230 	;
231 server_version: VAR_VERSION STRING
232 	{
233 		OUTYY(("P(server_version:%s)\n", $2));
234 		cfg_parser->opt->version = region_strdup(cfg_parser->opt->region, $2);
235 	}
236 	;
237 server_nsid: VAR_NSID STRING
238 	{
239 		unsigned char* nsid = 0;
240 		size_t nsid_len = 0;
241 
242 		OUTYY(("P(server_nsid:%s)\n", $2));
243 
244 		if (strncasecmp($2, "ascii_", 6) == 0) {
245 			nsid_len = strlen($2+6);
246 			if(nsid_len < 65535) {
247 				cfg_parser->opt->nsid = region_alloc(cfg_parser->opt->region, nsid_len*2+1);
248 				hex_ntop((uint8_t*)$2+6, nsid_len, (char*)cfg_parser->opt->nsid, nsid_len*2+1);
249 			} else
250 				yyerror("NSID too long");
251 		} else if (strlen($2) % 2 != 0) {
252 			yyerror("the NSID must be a hex string of an even length.");
253 		} else {
254 			nsid_len = strlen($2) / 2;
255 			if(nsid_len < 65535) {
256 				nsid = xalloc(nsid_len);
257 				if (hex_pton($2, nsid, nsid_len) == -1)
258 					yyerror("hex string cannot be parsed in NSID.");
259 				else
260 					cfg_parser->opt->nsid = region_strdup(cfg_parser->opt->region, $2);
261 				free(nsid);
262 			} else
263 				yyerror("NSID too long");
264 		}
265 	}
266 	;
267 server_logfile: VAR_LOGFILE STRING
268 	{
269 		OUTYY(("P(server_logfile:%s)\n", $2));
270 		cfg_parser->opt->logfile = region_strdup(cfg_parser->opt->region, $2);
271 	}
272 	;
273 server_log_time_ascii: VAR_LOG_TIME_ASCII STRING
274 	{
275 		OUTYY(("P(server_log_time_ascii:%s)\n", $2));
276 		if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
277 			yyerror("expected yes or no.");
278 		else {
279 			cfg_parser->opt->log_time_ascii = (strcmp($2, "yes")==0);
280 			log_time_asc = cfg_parser->opt->log_time_ascii;
281 		}
282 	}
283 	;
284 server_round_robin: VAR_ROUND_ROBIN STRING
285 	{
286 		OUTYY(("P(server_round_robin:%s)\n", $2));
287 		if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
288 			yyerror("expected yes or no.");
289 		else {
290 			cfg_parser->opt->round_robin = (strcmp($2, "yes")==0);
291 			round_robin = cfg_parser->opt->round_robin;
292 		}
293 	}
294 	;
295 server_server_count: VAR_SERVER_COUNT STRING
296 	{
297 		OUTYY(("P(server_server_count:%s)\n", $2));
298 		if(atoi($2) <= 0)
299 			yyerror("number greater than zero expected");
300 		else cfg_parser->opt->server_count = atoi($2);
301 	}
302 	;
303 server_tcp_count: VAR_TCP_COUNT STRING
304 	{
305 		OUTYY(("P(server_tcp_count:%s)\n", $2));
306 		if(atoi($2) <= 0)
307 			yyerror("number greater than zero expected");
308 		else cfg_parser->opt->tcp_count = atoi($2);
309 	}
310 	;
311 server_pidfile: VAR_PIDFILE STRING
312 	{
313 		OUTYY(("P(server_pidfile:%s)\n", $2));
314 		cfg_parser->opt->pidfile = region_strdup(cfg_parser->opt->region, $2);
315 	}
316 	;
317 server_port: VAR_PORT STRING
318 	{
319 		OUTYY(("P(server_port:%s)\n", $2));
320 		cfg_parser->opt->port = region_strdup(cfg_parser->opt->region, $2);
321 	}
322 	;
323 server_statistics: VAR_STATISTICS STRING
324 	{
325 		OUTYY(("P(server_statistics:%s)\n", $2));
326 		if(atoi($2) == 0 && strcmp($2, "0") != 0)
327 			yyerror("number expected");
328 		else cfg_parser->opt->statistics = atoi($2);
329 	}
330 	;
331 server_chroot: VAR_CHROOT STRING
332 	{
333 		OUTYY(("P(server_chroot:%s)\n", $2));
334 		cfg_parser->opt->chroot = region_strdup(cfg_parser->opt->region, $2);
335 	}
336 	;
337 server_username: VAR_USERNAME STRING
338 	{
339 		OUTYY(("P(server_username:%s)\n", $2));
340 		cfg_parser->opt->username = region_strdup(cfg_parser->opt->region, $2);
341 	}
342 	;
343 server_zonesdir: VAR_ZONESDIR STRING
344 	{
345 		OUTYY(("P(server_zonesdir:%s)\n", $2));
346 		cfg_parser->opt->zonesdir = region_strdup(cfg_parser->opt->region, $2);
347 	}
348 	;
349 server_zonelistfile: VAR_ZONELISTFILE STRING
350 	{
351 		OUTYY(("P(server_zonelistfile:%s)\n", $2));
352 		cfg_parser->opt->zonelistfile = region_strdup(cfg_parser->opt->region, $2);
353 	}
354 	;
355 server_xfrdir: VAR_XFRDIR STRING
356 	{
357 		OUTYY(("P(server_xfrdir:%s)\n", $2));
358 		cfg_parser->opt->xfrdir = region_strdup(cfg_parser->opt->region, $2);
359 	}
360 	;
361 server_difffile: VAR_DIFFFILE STRING
362 	{
363 		OUTYY(("P(server_difffile:%s)\n", $2));
364 		/* ignore the value for backwards compatibility in config file*/
365 	}
366 	;
367 server_xfrdfile: VAR_XFRDFILE STRING
368 	{
369 		OUTYY(("P(server_xfrdfile:%s)\n", $2));
370 		cfg_parser->opt->xfrdfile = region_strdup(cfg_parser->opt->region, $2);
371 	}
372 	;
373 server_xfrd_reload_timeout: VAR_XFRD_RELOAD_TIMEOUT STRING
374 	{
375 		OUTYY(("P(server_xfrd_reload_timeout:%s)\n", $2));
376 		if(atoi($2) == 0 && strcmp($2, "0") != 0)
377 			yyerror("number expected");
378 		cfg_parser->opt->xfrd_reload_timeout = atoi($2);
379 	}
380 	;
381 server_tcp_query_count: VAR_TCP_QUERY_COUNT STRING
382 	{
383 		OUTYY(("P(server_tcp_query_count:%s)\n", $2));
384 		if(atoi($2) == 0 && strcmp($2, "0") != 0)
385 			yyerror("number expected");
386 		cfg_parser->opt->tcp_query_count = atoi($2);
387 	}
388 	;
389 server_tcp_timeout: VAR_TCP_TIMEOUT STRING
390 	{
391 		OUTYY(("P(server_tcp_timeout:%s)\n", $2));
392 		if(atoi($2) == 0 && strcmp($2, "0") != 0)
393 			yyerror("number expected");
394 		cfg_parser->opt->tcp_timeout = atoi($2);
395 	}
396 	;
397 server_tcp_mss: VAR_TCP_MSS STRING
398 	{
399 		OUTYY(("P(server_tcp_mss:%s)\n", $2));
400 		if(atoi($2) == 0 && strcmp($2, "0") != 0)
401 			yyerror("number expected");
402 		cfg_parser->opt->tcp_mss = atoi($2);
403 	}
404 	;
405 server_outgoing_tcp_mss: VAR_OUTGOING_TCP_MSS STRING
406 	{
407 		OUTYY(("P(server_outgoing_tcp_mss:%s)\n", $2));
408 		if(atoi($2) == 0 && strcmp($2, "0") != 0)
409 			yyerror("number expected");
410 		cfg_parser->opt->outgoing_tcp_mss = atoi($2);
411 	}
412 	;
413 server_ipv4_edns_size: VAR_IPV4_EDNS_SIZE STRING
414 	{
415 		OUTYY(("P(server_ipv4_edns_size:%s)\n", $2));
416 		if(atoi($2) == 0 && strcmp($2, "0") != 0)
417 			yyerror("number expected");
418 		cfg_parser->opt->ipv4_edns_size = atoi($2);
419 	}
420 	;
421 server_ipv6_edns_size: VAR_IPV6_EDNS_SIZE STRING
422 	{
423 		OUTYY(("P(server_ipv6_edns_size:%s)\n", $2));
424 		if(atoi($2) == 0 && strcmp($2, "0") != 0)
425 			yyerror("number expected");
426 		cfg_parser->opt->ipv6_edns_size = atoi($2);
427 	}
428 	;
429 server_rrl_size: VAR_RRL_SIZE STRING
430 	{
431 		OUTYY(("P(server_rrl_size:%s)\n", $2));
432 #ifdef RATELIMIT
433 		if(atoi($2) <= 0)
434 			yyerror("number greater than zero expected");
435 		cfg_parser->opt->rrl_size = atoi($2);
436 #endif
437 	}
438 	;
439 server_rrl_ratelimit: VAR_RRL_RATELIMIT STRING
440 	{
441 		OUTYY(("P(server_rrl_ratelimit:%s)\n", $2));
442 #ifdef RATELIMIT
443 		cfg_parser->opt->rrl_ratelimit = atoi($2);
444 #endif
445 	}
446 	;
447 server_rrl_slip: VAR_RRL_SLIP STRING
448 	{
449 		OUTYY(("P(server_rrl_slip:%s)\n", $2));
450 #ifdef RATELIMIT
451 		if(atoi($2) < 0)
452 			yyerror("number equal or greater than zero expected");
453 		cfg_parser->opt->rrl_slip = atoi($2);
454 #endif
455 	}
456 	;
457 server_rrl_ipv4_prefix_length: VAR_RRL_IPV4_PREFIX_LENGTH STRING
458 	{
459 		OUTYY(("P(server_rrl_ipv4_prefix_length:%s)\n", $2));
460 #ifdef RATELIMIT
461 		if(atoi($2) < 0 || atoi($2) > 32)
462 			yyerror("invalid IPv4 prefix length");
463 		cfg_parser->opt->rrl_ipv4_prefix_length = atoi($2);
464 #endif
465 	}
466 	;
467 server_rrl_ipv6_prefix_length: VAR_RRL_IPV6_PREFIX_LENGTH STRING
468 	{
469 		OUTYY(("P(server_rrl_ipv6_prefix_length:%s)\n", $2));
470 #ifdef RATELIMIT
471 		if(atoi($2) < 0 || atoi($2) > 64)
472 			yyerror("invalid IPv6 prefix length");
473 		cfg_parser->opt->rrl_ipv6_prefix_length = atoi($2);
474 #endif
475 	}
476 	;
477 server_rrl_whitelist_ratelimit: VAR_RRL_WHITELIST_RATELIMIT STRING
478 	{
479 		OUTYY(("P(server_rrl_whitelist_ratelimit:%s)\n", $2));
480 #ifdef RATELIMIT
481 		cfg_parser->opt->rrl_whitelist_ratelimit = atoi($2);
482 #endif
483 	}
484 	;
485 server_zonefiles_check: VAR_ZONEFILES_CHECK STRING
486 	{
487 		OUTYY(("P(server_zonefiles_check:%s)\n", $2));
488 		if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
489 			yyerror("expected yes or no.");
490 		else cfg_parser->opt->zonefiles_check = (strcmp($2, "yes")==0);
491 	}
492 	;
493 server_zonefiles_write: VAR_ZONEFILES_WRITE STRING
494 	{
495 		OUTYY(("P(server_zonefiles_write:%s)\n", $2));
496 		if(atoi($2) == 0 && strcmp($2, "0") != 0)
497 			yyerror("number expected");
498 		else cfg_parser->opt->zonefiles_write = atoi($2);
499 	}
500 	;
501 
502 rcstart: VAR_REMOTE_CONTROL
503 	{
504 		OUTYY(("\nP(remote-control:)\n"));
505 	}
506 	;
507 contents_rc: contents_rc content_rc
508 	| ;
509 content_rc: rc_control_enable | rc_control_interface | rc_control_port |
510 	rc_server_key_file | rc_server_cert_file | rc_control_key_file |
511 	rc_control_cert_file
512 	;
513 rc_control_enable: VAR_CONTROL_ENABLE STRING
514 	{
515 		OUTYY(("P(control_enable:%s)\n", $2));
516 		if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
517 			yyerror("expected yes or no.");
518 		else cfg_parser->opt->control_enable = (strcmp($2, "yes")==0);
519 	}
520 	;
521 rc_control_port: VAR_CONTROL_PORT STRING
522 	{
523 		OUTYY(("P(control_port:%s)\n", $2));
524 		if(atoi($2) == 0)
525 			yyerror("control port number expected");
526 		else cfg_parser->opt->control_port = atoi($2);
527 	}
528 	;
529 rc_control_interface: VAR_CONTROL_INTERFACE STRING
530 	{
531 		ip_address_option_t* o = (ip_address_option_t*)region_alloc(
532 			cfg_parser->opt->region, sizeof(ip_address_option_t));
533 		OUTYY(("P(control_interface:%s)\n", $2));
534 		o->next = cfg_parser->opt->control_interface;
535 		cfg_parser->opt->control_interface = o;
536 		o->address = region_strdup(cfg_parser->opt->region, $2);
537 	}
538 	;
539 rc_server_key_file: VAR_SERVER_KEY_FILE STRING
540 	{
541 	OUTYY(("P(rc_server_key_file:%s)\n", $2));
542 	cfg_parser->opt->server_key_file = region_strdup(cfg_parser->opt->region, $2);
543 	}
544 	;
545 rc_server_cert_file: VAR_SERVER_CERT_FILE STRING
546 	{
547 	OUTYY(("P(rc_server_cert_file:%s)\n", $2));
548 	cfg_parser->opt->server_cert_file = region_strdup(cfg_parser->opt->region, $2);
549 	}
550 	;
551 rc_control_key_file: VAR_CONTROL_KEY_FILE STRING
552 	{
553 	OUTYY(("P(rc_control_key_file:%s)\n", $2));
554 	cfg_parser->opt->control_key_file = region_strdup(cfg_parser->opt->region, $2);
555 	}
556 	;
557 rc_control_cert_file: VAR_CONTROL_CERT_FILE STRING
558 	{
559 	OUTYY(("P(rc_control_cert_file:%s)\n", $2));
560 	cfg_parser->opt->control_cert_file = region_strdup(cfg_parser->opt->region, $2);
561 	}
562 	;
563 
564 /* pattern: declaration */
565 patternstart: VAR_PATTERN
566 	{
567 		OUTYY(("\nP(pattern:)\n"));
568 		if(cfg_parser->current_zone) {
569 			if(!cfg_parser->current_zone->name)
570 				c_error("previous zone has no name");
571 			else {
572 				if(!nsd_options_insert_zone(cfg_parser->opt,
573 					cfg_parser->current_zone))
574 					c_error("duplicate zone");
575 			}
576 			if(!cfg_parser->current_zone->pattern)
577 				c_error("previous zone has no pattern");
578 			cfg_parser->current_zone = NULL;
579 		}
580 		if(cfg_parser->current_pattern) {
581 			if(!cfg_parser->current_pattern->pname)
582 				c_error("previous pattern has no name");
583 			else {
584 				if(!nsd_options_insert_pattern(cfg_parser->opt,
585 					cfg_parser->current_pattern))
586 					c_error_msg("duplicate pattern %s",
587 						cfg_parser->current_pattern->pname);
588 			}
589 		}
590 		cfg_parser->current_pattern = pattern_options_create(
591 			cfg_parser->opt->region);
592 		cfg_parser->current_allow_notify = 0;
593 		cfg_parser->current_request_xfr = 0;
594 		cfg_parser->current_notify = 0;
595 		cfg_parser->current_provide_xfr = 0;
596 		cfg_parser->current_outgoing_interface = 0;
597 	}
598 	;
599 contents_pattern: contents_pattern content_pattern | content_pattern;
600 content_pattern: pattern_name | zone_config_item;
601 zone_config_item: zone_zonefile | zone_allow_notify | zone_request_xfr |
602 	zone_notify | zone_notify_retry | zone_provide_xfr |
603 	zone_outgoing_interface | zone_allow_axfr_fallback | include_pattern |
604 	zone_rrl_whitelist | zone_zonestats | zone_max_refresh_time |
605 	zone_min_refresh_time | zone_max_retry_time | zone_min_retry_time |
606        zone_size_limit_xfr | zone_multi_master_check;
607 pattern_name: VAR_NAME STRING
608 	{
609 		OUTYY(("P(pattern_name:%s)\n", $2));
610 #ifndef NDEBUG
611 		assert(cfg_parser->current_pattern);
612 #endif
613 		if(strchr($2, ' '))
614 			c_error_msg("space is not allowed in pattern name: "
615 				"'%s'", $2);
616 		cfg_parser->current_pattern->pname = region_strdup(cfg_parser->opt->region, $2);
617 	}
618 	;
619 include_pattern: VAR_INCLUDEPATTERN STRING
620 	{
621 		OUTYY(("P(include-pattern:%s)\n", $2));
622 #ifndef NDEBUG
623 		assert(cfg_parser->current_pattern);
624 #endif
625 		config_apply_pattern($2);
626 	}
627 	;
628 
629 /* zone: declaration */
630 zonestart: VAR_ZONE
631 	{
632 		OUTYY(("\nP(zone:)\n"));
633 		if(cfg_parser->current_zone) {
634 			if(!cfg_parser->current_zone->name)
635 				c_error("previous zone has no name");
636 			else {
637 				if(!nsd_options_insert_zone(cfg_parser->opt,
638 					cfg_parser->current_zone))
639 					c_error("duplicate zone");
640 			}
641 			if(!cfg_parser->current_zone->pattern)
642 				c_error("previous zone has no pattern");
643 		}
644 		if(cfg_parser->current_pattern) {
645 			if(!cfg_parser->current_pattern->pname)
646 				c_error("previous pattern has no name");
647 			else {
648 				if(!nsd_options_insert_pattern(cfg_parser->opt,
649 					cfg_parser->current_pattern))
650 					c_error_msg("duplicate pattern %s",
651 						cfg_parser->current_pattern->pname);
652 			}
653 		}
654 		cfg_parser->current_zone = zone_options_create(cfg_parser->opt->region);
655 		cfg_parser->current_zone->part_of_config = 1;
656 		cfg_parser->current_pattern = pattern_options_create(
657 			cfg_parser->opt->region);
658 		cfg_parser->current_pattern->implicit = 1;
659 		cfg_parser->current_zone->pattern = cfg_parser->current_pattern;
660 		cfg_parser->current_allow_notify = 0;
661 		cfg_parser->current_request_xfr = 0;
662 		cfg_parser->current_notify = 0;
663 		cfg_parser->current_provide_xfr = 0;
664 		cfg_parser->current_outgoing_interface = 0;
665 	}
666 	;
667 contents_zone: contents_zone content_zone | content_zone;
668 content_zone: zone_name | zone_config_item;
669 zone_name: VAR_NAME STRING
670 	{
671 		char* s;
672 		OUTYY(("P(zone_name:%s)\n", $2));
673 #ifndef NDEBUG
674 		assert(cfg_parser->current_zone);
675 		assert(cfg_parser->current_pattern);
676 #endif
677 		cfg_parser->current_zone->name = region_strdup(cfg_parser->opt->region, $2);
678 		s = (char*)region_alloc(cfg_parser->opt->region,
679 			strlen($2)+strlen(PATTERN_IMPLICIT_MARKER)+1);
680 		memmove(s, PATTERN_IMPLICIT_MARKER,
681 			strlen(PATTERN_IMPLICIT_MARKER));
682 		memmove(s+strlen(PATTERN_IMPLICIT_MARKER), $2, strlen($2)+1);
683 		if(pattern_options_find(cfg_parser->opt, s))
684 			c_error_msg("zone %s cannot be created because "
685 				"implicit pattern %s already exists", $2, s);
686 		cfg_parser->current_pattern->pname = s;
687 	}
688 	;
689 zone_zonefile: VAR_ZONEFILE STRING
690 	{
691 		OUTYY(("P(zonefile:%s)\n", $2));
692 #ifndef NDEBUG
693 		assert(cfg_parser->current_pattern);
694 #endif
695 		cfg_parser->current_pattern->zonefile = region_strdup(cfg_parser->opt->region, $2);
696 	}
697 	;
698 zone_zonestats: VAR_ZONESTATS STRING
699 	{
700 		OUTYY(("P(zonestats:%s)\n", $2));
701 #ifndef NDEBUG
702 		assert(cfg_parser->current_pattern);
703 #endif
704 		cfg_parser->current_pattern->zonestats = region_strdup(cfg_parser->opt->region, $2);
705 	}
706 	;
707 zone_allow_notify: VAR_ALLOW_NOTIFY STRING STRING
708 	{
709 		acl_options_t* acl = parse_acl_info(cfg_parser->opt->region, $2, $3);
710 		OUTYY(("P(allow_notify:%s %s)\n", $2, $3));
711 		if(cfg_parser->current_allow_notify)
712 			cfg_parser->current_allow_notify->next = acl;
713 		else
714 			cfg_parser->current_pattern->allow_notify = acl;
715 		cfg_parser->current_allow_notify = acl;
716 	}
717 	;
718 zone_request_xfr: VAR_REQUEST_XFR zone_request_xfr_data
719 	{
720 	}
721 	;
722 zone_size_limit_xfr: VAR_SIZE_LIMIT_XFR STRING
723 	{
724 		OUTYY(("P(size_limit_xfr:%s)\n", $2));
725 		if(atoll($2) < 0)
726 			yyerror("number >= 0 expected");
727 		else cfg_parser->current_pattern->size_limit_xfr = atoll($2);
728 	}
729 	;
730 zone_request_xfr_data: STRING STRING
731 	{
732 		acl_options_t* acl = parse_acl_info(cfg_parser->opt->region, $1, $2);
733 		OUTYY(("P(request_xfr:%s %s)\n", $1, $2));
734 		if(acl->blocked) c_error("blocked address used for request-xfr");
735 		if(acl->rangetype!=acl_range_single) c_error("address range used for request-xfr");
736 		if(cfg_parser->current_request_xfr)
737 			cfg_parser->current_request_xfr->next = acl;
738 		else
739 			cfg_parser->current_pattern->request_xfr = acl;
740 		cfg_parser->current_request_xfr = acl;
741 	}
742 	| VAR_AXFR STRING STRING
743 	{
744 		acl_options_t* acl = parse_acl_info(cfg_parser->opt->region, $2, $3);
745 		acl->use_axfr_only = 1;
746 		OUTYY(("P(request_xfr:%s %s)\n", $2, $3));
747 		if(acl->blocked) c_error("blocked address used for request-xfr");
748 		if(acl->rangetype!=acl_range_single) c_error("address range used for request-xfr");
749 		if(cfg_parser->current_request_xfr)
750 			cfg_parser->current_request_xfr->next = acl;
751 		else
752 			cfg_parser->current_pattern->request_xfr = acl;
753 		cfg_parser->current_request_xfr = acl;
754 	}
755 	| VAR_UDP STRING STRING
756 	{
757 		acl_options_t* acl = parse_acl_info(cfg_parser->opt->region, $2, $3);
758 		acl->allow_udp = 1;
759 		OUTYY(("P(request_xfr:%s %s)\n", $2, $3));
760 		if(acl->blocked) c_error("blocked address used for request-xfr");
761 		if(acl->rangetype!=acl_range_single) c_error("address range used for request-xfr");
762 		if(cfg_parser->current_request_xfr)
763 			cfg_parser->current_request_xfr->next = acl;
764 		else
765 			cfg_parser->current_pattern->request_xfr = acl;
766 		cfg_parser->current_request_xfr = acl;
767 	}
768 	;
769 zone_notify: VAR_NOTIFY STRING STRING
770 	{
771 		acl_options_t* acl = parse_acl_info(cfg_parser->opt->region, $2, $3);
772 		OUTYY(("P(notify:%s %s)\n", $2, $3));
773 		if(acl->blocked) c_error("blocked address used for notify");
774 		if(acl->rangetype!=acl_range_single) c_error("address range used for notify");
775 		if(cfg_parser->current_notify)
776 			cfg_parser->current_notify->next = acl;
777 		else
778 			cfg_parser->current_pattern->notify = acl;
779 		cfg_parser->current_notify = acl;
780 	}
781 	;
782 zone_notify_retry: VAR_NOTIFY_RETRY STRING
783 	{
784 		OUTYY(("P(notify_retry:%s)\n", $2));
785 		if(atoi($2) == 0 && strcmp($2, "0") != 0)
786 			yyerror("number expected");
787 		else {
788 			cfg_parser->current_pattern->notify_retry = atoi($2);
789 			cfg_parser->current_pattern->notify_retry_is_default=0;
790 		}
791 	}
792 	;
793 zone_provide_xfr: VAR_PROVIDE_XFR STRING STRING
794 	{
795 		acl_options_t* acl = parse_acl_info(cfg_parser->opt->region, $2, $3);
796 		OUTYY(("P(provide_xfr:%s %s)\n", $2, $3));
797 		if(cfg_parser->current_provide_xfr)
798 			cfg_parser->current_provide_xfr->next = acl;
799 		else
800 			cfg_parser->current_pattern->provide_xfr = acl;
801 		cfg_parser->current_provide_xfr = acl;
802 	}
803 	;
804 zone_outgoing_interface: VAR_OUTGOING_INTERFACE STRING
805 	{
806 		acl_options_t* acl = parse_acl_info(cfg_parser->opt->region, $2, "NOKEY");
807 		OUTYY(("P(outgoing_interface:%s)\n", $2));
808 		if(acl->rangetype!=acl_range_single) c_error("address range used for outgoing interface");
809 		if(cfg_parser->current_outgoing_interface)
810 			cfg_parser->current_outgoing_interface->next = acl;
811 		else
812 			cfg_parser->current_pattern->outgoing_interface = acl;
813 		cfg_parser->current_outgoing_interface = acl;
814 	}
815 	;
816 zone_allow_axfr_fallback: VAR_ALLOW_AXFR_FALLBACK STRING
817 	{
818 		OUTYY(("P(allow_axfr_fallback:%s)\n", $2));
819 		if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
820 			yyerror("expected yes or no.");
821 		else {
822 			cfg_parser->current_pattern->allow_axfr_fallback = (strcmp($2, "yes")==0);
823 			cfg_parser->current_pattern->allow_axfr_fallback_is_default = 0;
824 		}
825 	}
826 	;
827 zone_rrl_whitelist: VAR_RRL_WHITELIST STRING
828 	{
829 		OUTYY(("P(zone_rrl_whitelist:%s)\n", $2));
830 #ifdef RATELIMIT
831 		cfg_parser->current_pattern->rrl_whitelist |= rrlstr2type($2);
832 #endif
833 	}
834 	;
835 zone_max_refresh_time: VAR_MAX_REFRESH_TIME STRING
836 {
837 	OUTYY(("P(zone_max_refresh_time:%s)\n", $2));
838 	if(atoi($2) == 0 && strcmp($2, "0") != 0)
839 		yyerror("number expected");
840 	else {
841 		cfg_parser->current_pattern->max_refresh_time = atoi($2);
842 		cfg_parser->current_pattern->max_refresh_time_is_default = 0;
843 	}
844 };
845 zone_min_refresh_time: VAR_MIN_REFRESH_TIME STRING
846 {
847 	OUTYY(("P(zone_min_refresh_time:%s)\n", $2));
848 	if(atoi($2) == 0 && strcmp($2, "0") != 0)
849 		yyerror("number expected");
850 	else {
851 		cfg_parser->current_pattern->min_refresh_time = atoi($2);
852 		cfg_parser->current_pattern->min_refresh_time_is_default = 0;
853 	}
854 };
855 zone_max_retry_time: VAR_MAX_RETRY_TIME STRING
856 {
857 	OUTYY(("P(zone_max_retry_time:%s)\n", $2));
858 	if(atoi($2) == 0 && strcmp($2, "0") != 0)
859 		yyerror("number expected");
860 	else {
861 		cfg_parser->current_pattern->max_retry_time = atoi($2);
862 		cfg_parser->current_pattern->max_retry_time_is_default = 0;
863 	}
864 };
865 zone_min_retry_time: VAR_MIN_RETRY_TIME STRING
866 {
867 	OUTYY(("P(zone_min_retry_time:%s)\n", $2));
868 	if(atoi($2) == 0 && strcmp($2, "0") != 0)
869 		yyerror("number expected");
870 	else {
871 		cfg_parser->current_pattern->min_retry_time = atoi($2);
872 		cfg_parser->current_pattern->min_retry_time_is_default = 0;
873 	}
874 };
875 zone_multi_master_check: VAR_MULTI_MASTER_CHECK STRING
876 	{
877 		OUTYY(("P(zone_multi_master_check:%s)\n", $2));
878 		if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
879 			yyerror("expected yes or no.");
880 		else cfg_parser->current_pattern->multi_master_check = (strcmp($2, "yes")==0);
881 	}
882 
883 /* key: declaration */
884 keystart: VAR_KEY
885 	{
886 		OUTYY(("\nP(key:)\n"));
887 		if(cfg_parser->current_key) {
888 			if(!cfg_parser->current_key->name) c_error("previous key has no name");
889 			if(!cfg_parser->current_key->algorithm) c_error("previous key has no algorithm");
890 			if(!cfg_parser->current_key->secret) c_error("previous key has no secret blob");
891 			key_options_insert(cfg_parser->opt, cfg_parser->current_key);
892 		}
893 		cfg_parser->current_key = key_options_create(cfg_parser->opt->region);
894 		cfg_parser->current_key->algorithm = region_strdup(cfg_parser->opt->region, "sha256");
895 	}
896 	;
897 contents_key: contents_key content_key | content_key;
898 content_key: key_name | key_algorithm | key_secret;
899 key_name: VAR_NAME STRING
900 	{
901 		const dname_type* d;
902 		OUTYY(("P(key_name:%s)\n", $2));
903 #ifndef NDEBUG
904 		assert(cfg_parser->current_key);
905 #endif
906 		cfg_parser->current_key->name = region_strdup(cfg_parser->opt->region, $2);
907 		d = dname_parse(cfg_parser->opt->region, $2);
908 		if(!d)	c_error_msg("Failed to parse tsig key name %s", $2);
909 		else	region_recycle(cfg_parser->opt->region, (void*)d,
910 				dname_total_size(d));
911 	}
912 	;
913 key_algorithm: VAR_ALGORITHM STRING
914 	{
915 		OUTYY(("P(key_algorithm:%s)\n", $2));
916 #ifndef NDEBUG
917 		assert(cfg_parser->current_key);
918 #endif
919 		if(cfg_parser->current_key->algorithm)
920 			region_recycle(cfg_parser->opt->region, cfg_parser->current_key->algorithm, strlen(cfg_parser->current_key->algorithm)+1);
921 		cfg_parser->current_key->algorithm = region_strdup(cfg_parser->opt->region, $2);
922 		if(tsig_get_algorithm_by_name($2) == NULL)
923 			c_error_msg("Bad tsig algorithm %s", $2);
924 	}
925 	;
926 key_secret: VAR_SECRET STRING
927 	{
928 		uint8_t data[16384];
929 		int size;
930 		OUTYY(("key_secret:%s)\n", $2));
931 #ifndef NDEBUG
932 		assert(cfg_parser->current_key);
933 #endif
934 		cfg_parser->current_key->secret = region_strdup(cfg_parser->opt->region, $2);
935 		size = b64_pton($2, data, sizeof(data));
936 		if(size == -1) {
937 			c_error_msg("Cannot base64 decode tsig secret %s",
938 				cfg_parser->current_key->name?
939 				cfg_parser->current_key->name:"");
940 		} else if(size != 0) {
941 			memset(data, 0xdd, size); /* wipe secret */
942 		}
943 	}
944 	;
945 
946 %%
947 
948 /* parse helper routines could be here */
949