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