xref: /netbsd-src/external/bsd/nsd/dist/configlexer.lex (revision b5c47949a45ac972130c38cf13dfd8afb1f09285)
1 %{
2 /*
3  * configlexer.lex - lexical analyzer for NSD config file
4  *
5  * Copyright (c) 2001-2006, NLnet Labs. All rights reserved
6  *
7  * See LICENSE for the license.
8  *
9  */
10 /* because flex keeps having sign-unsigned compare problems that are unfixed*/
11 #if defined(__clang__)||(defined(__GNUC__)&&((__GNUC__ >4)||(defined(__GNUC_MINOR__)&&(__GNUC__ ==4)&&(__GNUC_MINOR__ >=2))))
12 #pragma GCC diagnostic ignored "-Wsign-compare"
13 #endif
14 
15 #include "config.h"
16 
17 #include <ctype.h>
18 #include <errno.h>
19 #include <string.h>
20 #include <strings.h>
21 #ifdef HAVE_GLOB_H
22 # include <glob.h>
23 #endif
24 
25 #include "options.h"
26 #include "configyyrename.h"
27 #include "configparser.h"
28 
29 #if 0
30 #define LEXOUT(s)  printf s /* used ONLY when debugging */
31 #else
32 #define LEXOUT(s)
33 #endif
34 
35 struct inc_state {
36 	char* filename;
37 	int line;
38 	YY_BUFFER_STATE buffer;
39 	struct inc_state* next;
40 };
41 static struct inc_state* config_include_stack = NULL;
42 static int inc_depth = 0;
43 
44 static void config_start_include(const char* filename)
45 {
46 	FILE *input;
47 	struct inc_state* s;
48 	char* nm;
49 	if(inc_depth++ > 10000000) {
50 		yyerror("too many include files");
51 		return;
52 	}
53 	if(strlen(filename) == 0) {
54 		yyerror("empty include file name");
55 		return;
56 	}
57 	s = (struct inc_state*)malloc(sizeof(*s));
58 	if(!s) {
59 		yyerror("include %s: malloc failure", filename);
60 		return;
61 	}
62 	nm = strdup(filename);
63 	if(!nm) {
64 		yyerror("include %s: strdup failure", filename);
65 		free(s);
66 		return;
67 	}
68 	input = fopen(filename, "r");
69 	if(!input) {
70 		yyerror("cannot open include file '%s': %s",
71 			filename, strerror(errno));
72 		free(s);
73 		free(nm);
74 		return;
75 	}
76 	LEXOUT(("switch_to_include_file(%s) ", filename));
77 	s->filename = cfg_parser->filename;
78 	s->line = cfg_parser->line;
79 	s->buffer = YY_CURRENT_BUFFER;
80 	s->next = config_include_stack;
81 	config_include_stack = s;
82 
83 	cfg_parser->filename = nm;
84 	cfg_parser->line = 1;
85 	yy_switch_to_buffer(yy_create_buffer(input, YY_BUF_SIZE));
86 }
87 
88 static void config_start_include_glob(const char* filename)
89 {
90 	/* check for wildcards */
91 #ifdef HAVE_GLOB
92 	glob_t g;
93 	int i, r, flags;
94 #endif /* HAVE_GLOB */
95 	if (cfg_parser->chroot) {
96 		int l = strlen(cfg_parser->chroot); /* chroot has trailing slash */
97 		if (strncmp(cfg_parser->chroot, filename, l) != 0) {
98 			yyerror("include file '%s' is not relative to chroot '%s'",
99 				filename, cfg_parser->chroot);
100 			return;
101 		}
102 		filename += l - 1; /* strip chroot without trailing slash */
103 	}
104 #ifdef HAVE_GLOB
105 	if(!(!strchr(filename, '*') && !strchr(filename, '?') &&
106 		 !strchr(filename, '[') && !strchr(filename, '{') &&
107 		 !strchr(filename, '~'))) {
108 		 flags = 0
109 #ifdef GLOB_ERR
110 		 	 | GLOB_ERR
111 #endif
112 			 /* do not set GLOB_NOSORT so the results are sorted
113 			    and in a predictable order. */
114 #ifdef GLOB_BRACE
115 			 | GLOB_BRACE
116 #endif
117 #ifdef GLOB_TILDE
118 			 | GLOB_TILDE
119 #endif
120 		;
121 		memset(&g, 0, sizeof(g));
122 		r = glob(filename, flags, NULL, &g);
123 		if(r) {
124 			/* some error */
125 			globfree(&g);
126 			if(r == GLOB_NOMATCH)
127 				return; /* no matches for pattern */
128 			config_start_include(filename); /* let original deal with it */
129 			return;
130 		}
131 		/* process files found, if any */
132 		for(i=(int)g.gl_pathc-1; i>=0; i--) {
133 			config_start_include(g.gl_pathv[i]);
134 		}
135 		globfree(&g);
136 		return;
137 	}
138 #endif /* HAVE_GLOB */
139 	config_start_include(filename);
140 }
141 
142 static void config_end_include(void)
143 {
144 	struct inc_state* s = config_include_stack;
145 	--inc_depth;
146 	if(!s) return;
147 	free(cfg_parser->filename);
148 	cfg_parser->filename = s->filename;
149 	cfg_parser->line = s->line;
150 	yy_delete_buffer(YY_CURRENT_BUFFER);
151 	yy_switch_to_buffer(s->buffer);
152 	config_include_stack = s->next;
153 	free(s);
154 }
155 
156 #ifndef yy_set_bol /* compat definition, for flex 2.4.6 */
157 #define yy_set_bol(at_bol) \
158         { \
159 	        if ( ! yy_current_buffer ) \
160 	                yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
161 	        yy_current_buffer->yy_ch_buf[0] = ((at_bol)?'\n':' '); \
162         }
163 #endif
164 
165 %}
166 %option noinput
167 %option nounput
168 %{
169 #ifndef YY_NO_UNPUT
170 #define YY_NO_UNPUT 1
171 #endif
172 #ifndef YY_NO_INPUT
173 #define YY_NO_INPUT 1
174 #endif
175 %}
176 
177 SPACE   [ \t]
178 LETTER  [a-zA-Z]
179 UNQUOTEDLETTER [^\"\n\r \t\\]|\\.
180 NEWLINE [\r\n]
181 COMMENT \#
182 COLON 	\:
183 ANY     [^\"\n\r\\]|\\.
184 
185 %x	quotedstring include include_quoted
186 
187 %%
188 {SPACE}* 		{ LEXOUT(("SP ")); /* ignore */ }
189 {SPACE}*{COMMENT}.* 	{ LEXOUT(("comment(%s) ", yytext)); /* ignore */ }
190 server{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_SERVER;}
191 name{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_NAME;}
192 ip-address{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_IP_ADDRESS;}
193 interface{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_IP_ADDRESS;}
194 ip-transparent{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_IP_TRANSPARENT;}
195 ip-freebind{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_IP_FREEBIND;}
196 send-buffer-size{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_SEND_BUFFER_SIZE;}
197 receive-buffer-size{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_RECEIVE_BUFFER_SIZE;}
198 debug-mode{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_DEBUG_MODE;}
199 use-systemd{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_USE_SYSTEMD;}
200 hide-version{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_HIDE_VERSION;}
201 hide-identity{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_HIDE_IDENTITY;}
202 drop-updates{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_DROP_UPDATES; }
203 ip4-only{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_IP4_ONLY;}
204 ip6-only{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_IP6_ONLY;}
205 do-ip4{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_DO_IP4;}
206 do-ip6{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_DO_IP6;}
207 database{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_DATABASE;}
208 identity{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_IDENTITY;}
209 version{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_VERSION;}
210 nsid{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_NSID;}
211 logfile{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_LOGFILE;}
212 log-only-syslog{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_LOG_ONLY_SYSLOG;}
213 server-count{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_SERVER_COUNT;}
214 tcp-count{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_TCP_COUNT;}
215 tcp-reject-overflow{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_TCP_REJECT_OVERFLOW;}
216 tcp-query-count{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_TCP_QUERY_COUNT;}
217 tcp-timeout{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_TCP_TIMEOUT;}
218 tcp-mss{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_TCP_MSS;}
219 outgoing-tcp-mss{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_OUTGOING_TCP_MSS;}
220 ipv4-edns-size{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_IPV4_EDNS_SIZE;}
221 ipv6-edns-size{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_IPV6_EDNS_SIZE;}
222 pidfile{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_PIDFILE;}
223 port{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_PORT;}
224 reuseport{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_REUSEPORT;}
225 statistics{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_STATISTICS;}
226 chroot{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_CHROOT;}
227 username{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_USERNAME;}
228 zonesdir{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_ZONESDIR;}
229 zonelistfile{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_ZONELISTFILE;}
230 difffile{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_DIFFFILE;}
231 xfrdfile{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_XFRDFILE;}
232 xfrdir{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_XFRDIR;}
233 xfrd-reload-timeout{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_XFRD_RELOAD_TIMEOUT;}
234 verbosity{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_VERBOSITY;}
235 zone{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_ZONE;}
236 zonefile{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_ZONEFILE;}
237 zonestats{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_ZONESTATS;}
238 allow-notify{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_ALLOW_NOTIFY;}
239 size-limit-xfr{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_SIZE_LIMIT_XFR;}
240 request-xfr{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_REQUEST_XFR;}
241 notify{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_NOTIFY;}
242 notify-retry{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_NOTIFY_RETRY;}
243 provide-xfr{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_PROVIDE_XFR;}
244 outgoing-interface{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_OUTGOING_INTERFACE;}
245 allow-axfr-fallback{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_ALLOW_AXFR_FALLBACK;}
246 key{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_KEY;}
247 algorithm{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_ALGORITHM;}
248 secret{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_SECRET;}
249 pattern{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_PATTERN;}
250 include-pattern{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_INCLUDE_PATTERN;}
251 remote-control{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_REMOTE_CONTROL;}
252 control-enable{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_CONTROL_ENABLE;}
253 control-interface{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_CONTROL_INTERFACE;}
254 control-port{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_CONTROL_PORT;}
255 server-key-file{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_SERVER_KEY_FILE;}
256 server-cert-file{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_SERVER_CERT_FILE;}
257 control-key-file{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_CONTROL_KEY_FILE;}
258 control-cert-file{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_CONTROL_CERT_FILE;}
259 AXFR			{ LEXOUT(("v(%s) ", yytext)); return VAR_AXFR;}
260 UDP			{ LEXOUT(("v(%s) ", yytext)); return VAR_UDP;}
261 rrl-size{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_RRL_SIZE;}
262 rrl-ratelimit{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_RRL_RATELIMIT;}
263 rrl-slip{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_RRL_SLIP;}
264 rrl-ipv4-prefix-length{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_RRL_IPV4_PREFIX_LENGTH;}
265 rrl-ipv6-prefix-length{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_RRL_IPV6_PREFIX_LENGTH;}
266 rrl-whitelist-ratelimit{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_RRL_WHITELIST_RATELIMIT;}
267 rrl-whitelist{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_RRL_WHITELIST;}
268 zonefiles-check{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_ZONEFILES_CHECK;}
269 zonefiles-write{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_ZONEFILES_WRITE;}
270 dnstap{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP;}
271 dnstap-enable{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_ENABLE;}
272 dnstap-socket-path{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_SOCKET_PATH; }
273 dnstap-send-identity{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_SEND_IDENTITY; }
274 dnstap-send-version{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_SEND_VERSION; }
275 dnstap-identity{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_IDENTITY; }
276 dnstap-version{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_VERSION; }
277 dnstap-log-auth-query-messages{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_LOG_AUTH_QUERY_MESSAGES; }
278 dnstap-log-auth-response-messages{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_LOG_AUTH_RESPONSE_MESSAGES; }
279 log-time-ascii{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_LOG_TIME_ASCII;}
280 round-robin{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_ROUND_ROBIN;}
281 minimal-responses{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_MINIMAL_RESPONSES;}
282 confine-to-zone{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_CONFINE_TO_ZONE;}
283 refuse-any{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_REFUSE_ANY;}
284 max-refresh-time{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_MAX_REFRESH_TIME;}
285 min-refresh-time{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_MIN_REFRESH_TIME;}
286 max-retry-time{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_MAX_RETRY_TIME;}
287 min-retry-time{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_MIN_RETRY_TIME;}
288 min-expire-time{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_MIN_EXPIRE_TIME;}
289 multi-master-check{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_MULTI_MASTER_CHECK;}
290 tls-service-key{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_TLS_SERVICE_KEY;}
291 tls-service-ocsp{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_TLS_SERVICE_OCSP;}
292 tls-service-pem{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_TLS_SERVICE_PEM;}
293 tls-port{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_TLS_PORT;}
294 {NEWLINE}		{ LEXOUT(("NL\n")); cfg_parser->line++;}
295 
296 servers={UNQUOTEDLETTER}*	{
297 	yyless(yyleng - (yyleng - 8));
298 	LEXOUT(("v(%s) ", yytext));
299 	return VAR_SERVERS;
300 }
301 bindtodevice={UNQUOTEDLETTER}*	{
302 	yyless(yyleng - (yyleng - 13));
303 	LEXOUT(("v(%s) ", yytext));
304 	return VAR_BINDTODEVICE;
305 }
306 setfib={UNQUOTEDLETTER}*	{
307 	yyless(yyleng - (yyleng - 7));
308 	LEXOUT(("v(%s) ", yytext));
309 	return VAR_SETFIB;
310 }
311 
312 cpu-affinity{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_CPU_AFFINITY; }
313 xfrd-cpu-affinity{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_XFRD_CPU_AFFINITY; }
314 server-[1-9][0-9]*-cpu-affinity{COLON}	{
315 		char *str = yytext;
316 		LEXOUT(("v(%s) ", yytext));
317 		/* Skip server- */
318 		while (*str != '\0' && (*str < '0' || *str > '9')) {
319 			str++;
320 		}
321 		yylval.llng = strtoll(str, NULL, 10);
322 		return VAR_SERVER_CPU_AFFINITY;
323 	}
324 
325 	/* Quoted strings. Strip leading and ending quotes */
326 \"			{ BEGIN(quotedstring); LEXOUT(("QS ")); }
327 <quotedstring><<EOF>>   {
328         yyerror("EOF inside quoted string");
329         BEGIN(INITIAL);
330 }
331 <quotedstring>{ANY}*    { LEXOUT(("STR(%s) ", yytext)); yymore(); }
332 <quotedstring>\n        { cfg_parser->line++; yymore(); }
333 <quotedstring>\" {
334         LEXOUT(("QE "));
335         BEGIN(INITIAL);
336         yytext[yyleng - 1] = '\0';
337 	yylval.str = region_strdup(cfg_parser->opt->region, yytext);
338         return STRING;
339 }
340 
341 	/* include: directive */
342 include{COLON}		{ LEXOUT(("v(%s) ", yytext)); BEGIN(include); }
343 <include><<EOF>>	{
344         yyerror("EOF inside include directive");
345         BEGIN(INITIAL);
346 }
347 <include>{SPACE}*	{ LEXOUT(("ISP ")); /* ignore */ }
348 <include>{NEWLINE}	{ LEXOUT(("NL\n")); cfg_parser->line++;}
349 <include>\"		{ LEXOUT(("IQS ")); BEGIN(include_quoted); }
350 <include>{UNQUOTEDLETTER}*	{
351 	LEXOUT(("Iunquotedstr(%s) ", yytext));
352 	config_start_include_glob(yytext);
353 	BEGIN(INITIAL);
354 }
355 <include_quoted><<EOF>>	{
356         yyerror("EOF inside quoted string");
357         BEGIN(INITIAL);
358 }
359 <include_quoted>{ANY}*	{ LEXOUT(("ISTR(%s) ", yytext)); yymore(); }
360 <include_quoted>{NEWLINE}	{ cfg_parser->line++; yymore(); }
361 <include_quoted>\"	{
362 	LEXOUT(("IQE "));
363 	yytext[yyleng - 1] = '\0';
364 	config_start_include_glob(yytext);
365 	BEGIN(INITIAL);
366 }
367 <INITIAL><<EOF>>	{
368 	yy_set_bol(1); /* Set beginning of line, so "^" rules match.  */
369 	if (!config_include_stack) {
370 		yyterminate();
371 	} else {
372 		fclose(yyin);
373 		config_end_include();
374 	}
375 }
376 
377 {UNQUOTEDLETTER}*	{ LEXOUT(("unquotedstr(%s) ", yytext));
378 			yylval.str = region_strdup(cfg_parser->opt->region, yytext); return STRING; }
379 
380 %%
381