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