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