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