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