configlexer.lex revision 1.1.1.6
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
35struct inc_state {
36	char* filename;
37	int line;
38	YY_BUFFER_STATE buffer;
39	struct inc_state* next;
40};
41static struct inc_state* config_include_stack = NULL;
42static int inc_depth = 0;
43
44static 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
88static 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
142static 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
177SPACE   [ \t]
178LETTER  [a-zA-Z]
179UNQUOTEDLETTER [^\"\n\r \t\\]|\\.
180NEWLINE [\r\n]
181COMMENT \#
182COLON 	\:
183ANY     [^\"\n\r\\]|\\.
184
185%x	quotedstring include include_quoted
186
187%%
188{SPACE}* 		{ LEXOUT(("SP ")); /* ignore */ }
189{SPACE}*{COMMENT}.* 	{ LEXOUT(("comment(%s) ", yytext)); /* ignore */ }
190server{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_SERVER;}
191name{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_NAME;}
192ip-address{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_IP_ADDRESS;}
193interface{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_IP_ADDRESS;}
194ip-transparent{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_IP_TRANSPARENT;}
195ip-freebind{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_IP_FREEBIND;}
196send-buffer-size{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_SEND_BUFFER_SIZE;}
197receive-buffer-size{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_RECEIVE_BUFFER_SIZE;}
198debug-mode{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_DEBUG_MODE;}
199use-systemd{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_USE_SYSTEMD;}
200hide-version{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_HIDE_VERSION;}
201hide-identity{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_HIDE_IDENTITY;}
202drop-updates{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_DROP_UPDATES; }
203ip4-only{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_IP4_ONLY;}
204ip6-only{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_IP6_ONLY;}
205do-ip4{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_DO_IP4;}
206do-ip6{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_DO_IP6;}
207database{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_DATABASE;}
208identity{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_IDENTITY;}
209version{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_VERSION;}
210nsid{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_NSID;}
211logfile{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_LOGFILE;}
212log-only-syslog{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_LOG_ONLY_SYSLOG;}
213server-count{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_SERVER_COUNT;}
214tcp-count{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_TCP_COUNT;}
215tcp-reject-overflow{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_TCP_REJECT_OVERFLOW;}
216tcp-query-count{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_TCP_QUERY_COUNT;}
217tcp-timeout{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_TCP_TIMEOUT;}
218tcp-mss{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_TCP_MSS;}
219outgoing-tcp-mss{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_OUTGOING_TCP_MSS;}
220ipv4-edns-size{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_IPV4_EDNS_SIZE;}
221ipv6-edns-size{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_IPV6_EDNS_SIZE;}
222pidfile{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_PIDFILE;}
223port{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_PORT;}
224reuseport{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_REUSEPORT;}
225statistics{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_STATISTICS;}
226chroot{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_CHROOT;}
227username{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_USERNAME;}
228zonesdir{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_ZONESDIR;}
229zonelistfile{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_ZONELISTFILE;}
230difffile{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_DIFFFILE;}
231xfrdfile{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_XFRDFILE;}
232xfrdir{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_XFRDIR;}
233xfrd-reload-timeout{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_XFRD_RELOAD_TIMEOUT;}
234verbosity{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_VERBOSITY;}
235zone{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_ZONE;}
236zonefile{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_ZONEFILE;}
237zonestats{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_ZONESTATS;}
238allow-notify{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_ALLOW_NOTIFY;}
239size-limit-xfr{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_SIZE_LIMIT_XFR;}
240request-xfr{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_REQUEST_XFR;}
241notify{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_NOTIFY;}
242notify-retry{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_NOTIFY_RETRY;}
243provide-xfr{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_PROVIDE_XFR;}
244outgoing-interface{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_OUTGOING_INTERFACE;}
245allow-axfr-fallback{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_ALLOW_AXFR_FALLBACK;}
246key{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_KEY;}
247algorithm{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_ALGORITHM;}
248secret{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_SECRET;}
249pattern{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_PATTERN;}
250include-pattern{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_INCLUDE_PATTERN;}
251remote-control{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_REMOTE_CONTROL;}
252control-enable{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_CONTROL_ENABLE;}
253control-interface{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_CONTROL_INTERFACE;}
254control-port{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_CONTROL_PORT;}
255server-key-file{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_SERVER_KEY_FILE;}
256server-cert-file{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_SERVER_CERT_FILE;}
257control-key-file{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_CONTROL_KEY_FILE;}
258control-cert-file{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_CONTROL_CERT_FILE;}
259AXFR			{ LEXOUT(("v(%s) ", yytext)); return VAR_AXFR;}
260UDP			{ LEXOUT(("v(%s) ", yytext)); return VAR_UDP;}
261rrl-size{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_RRL_SIZE;}
262rrl-ratelimit{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_RRL_RATELIMIT;}
263rrl-slip{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_RRL_SLIP;}
264rrl-ipv4-prefix-length{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_RRL_IPV4_PREFIX_LENGTH;}
265rrl-ipv6-prefix-length{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_RRL_IPV6_PREFIX_LENGTH;}
266rrl-whitelist-ratelimit{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_RRL_WHITELIST_RATELIMIT;}
267rrl-whitelist{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_RRL_WHITELIST;}
268zonefiles-check{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_ZONEFILES_CHECK;}
269zonefiles-write{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_ZONEFILES_WRITE;}
270dnstap{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP;}
271dnstap-enable{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_ENABLE;}
272dnstap-socket-path{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_SOCKET_PATH; }
273dnstap-send-identity{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_SEND_IDENTITY; }
274dnstap-send-version{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_SEND_VERSION; }
275dnstap-identity{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_IDENTITY; }
276dnstap-version{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_VERSION; }
277dnstap-log-auth-query-messages{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_LOG_AUTH_QUERY_MESSAGES; }
278dnstap-log-auth-response-messages{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_DNSTAP_LOG_AUTH_RESPONSE_MESSAGES; }
279log-time-ascii{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_LOG_TIME_ASCII;}
280round-robin{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_ROUND_ROBIN;}
281minimal-responses{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_MINIMAL_RESPONSES;}
282confine-to-zone{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_CONFINE_TO_ZONE;}
283refuse-any{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_REFUSE_ANY;}
284max-refresh-time{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_MAX_REFRESH_TIME;}
285min-refresh-time{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_MIN_REFRESH_TIME;}
286max-retry-time{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_MAX_RETRY_TIME;}
287min-retry-time{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_MIN_RETRY_TIME;}
288min-expire-time{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_MIN_EXPIRE_TIME;}
289multi-master-check{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_MULTI_MASTER_CHECK;}
290tls-service-key{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_TLS_SERVICE_KEY;}
291tls-service-ocsp{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_TLS_SERVICE_OCSP;}
292tls-service-pem{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_TLS_SERVICE_PEM;}
293tls-port{COLON}		{ LEXOUT(("v(%s) ", yytext)); return VAR_TLS_PORT;}
294{NEWLINE}		{ LEXOUT(("NL\n")); cfg_parser->line++;}
295
296servers={UNQUOTEDLETTER}*	{
297	yyless(yyleng - (yyleng - 8));
298	LEXOUT(("v(%s) ", yytext));
299	return VAR_SERVERS;
300}
301bindtodevice={UNQUOTEDLETTER}*	{
302	yyless(yyleng - (yyleng - 13));
303	LEXOUT(("v(%s) ", yytext));
304	return VAR_BINDTODEVICE;
305}
306setfib={UNQUOTEDLETTER}*	{
307	yyless(yyleng - (yyleng - 7));
308	LEXOUT(("v(%s) ", yytext));
309	return VAR_SETFIB;
310}
311
312cpu-affinity{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_CPU_AFFINITY; }
313xfrd-cpu-affinity{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_XFRD_CPU_AFFINITY; }
314server-[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 */
342include{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