summaryrefslogtreecommitdiffstats
path: root/src/scanner.l
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-09 13:08:37 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-09 13:08:37 +0000
commit971e619d8602fa52b1bfcb3ea65b7ab96be85318 (patch)
tree26feb2498c72b796e07b86349d17f544046de279 /src/scanner.l
parentInitial commit. (diff)
downloadnftables-upstream.tar.xz
nftables-upstream.zip
Adding upstream version 1.0.9.upstream/1.0.9upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/scanner.l')
-rw-r--r--src/scanner.l1326
1 files changed, 1326 insertions, 0 deletions
diff --git a/src/scanner.l b/src/scanner.l
new file mode 100644
index 0000000..88376b7
--- /dev/null
+++ b/src/scanner.l
@@ -0,0 +1,1326 @@
+/*
+ * Copyright (c) 2007-2008 Patrick McHardy <kaber@trash.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Development of this code funded by Astaro AG (http://www.astaro.com/)
+ */
+
+%{
+
+#include <nft.h>
+
+#include <limits.h>
+#include <glob.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <linux/types.h>
+#include <linux/netfilter.h>
+#include <sys/stat.h>
+
+#include <nftables.h>
+#include <erec.h>
+#include <rule.h>
+#include <parser.h>
+#include "parser_bison.h"
+
+#define YY_NO_INPUT
+
+/*
+ * Work around flex behaviour when reaching the end of buffer: normally, flex
+ * regexes are greedy, when reaching the end of buffer however it tries to
+ * match whatever is left in the buffer and only backs up in case it doesn't
+ * match *any* pattern. Since we accept unquoted strings, this means any partial
+ * token will be recognized as string.
+ *
+ * Make sure to only pass input to flex linewise to avoid this.
+ */
+#define YY_INPUT(buf,result,max_size) \
+{ \
+ result = 0; \
+ errno = 0; \
+ \
+ while (result < max_size) { \
+ int chr = fgetc(yyin); \
+ \
+ if (chr != EOF) { \
+ buf[result++] = chr; \
+ if (chr == '\n' || chr == ' ') \
+ break; \
+ continue; \
+ } \
+ \
+ if (ferror(yyin)) { \
+ if (errno != EINTR) { \
+ YY_FATAL_ERROR("input in flex scanner failed"); \
+ break; \
+ } \
+ errno = 0; \
+ clearerr(yyin); \
+ } \
+ break; \
+ } \
+}
+
+static void scanner_pop_buffer(yyscan_t scanner);
+
+
+static void init_pos(struct input_descriptor *indesc)
+{
+ indesc->lineno = 1;
+ indesc->column = 1;
+ indesc->token_offset = 0;
+ indesc->line_offset = 0;
+}
+
+static void update_pos(struct parser_state *state, struct location *loc,
+ int len)
+{
+ loc->indesc = state->indesc;
+ loc->first_line = state->indesc->lineno;
+ loc->last_line = state->indesc->lineno;
+ loc->first_column = state->indesc->column;
+ loc->last_column = state->indesc->column + len - 1;
+ state->indesc->column += len;
+}
+
+static void update_offset(struct parser_state *state, struct location *loc,
+ unsigned int len)
+{
+ state->indesc->token_offset += len;
+ loc->token_offset = state->indesc->token_offset;
+ loc->line_offset = state->indesc->line_offset;
+}
+
+static void reset_pos(struct parser_state *state, struct location *loc)
+{
+ state->indesc->line_offset = state->indesc->token_offset;
+ state->indesc->lineno += 1;
+ state->indesc->column = 1;
+}
+
+static void scanner_push_start_cond(void *scanner, enum startcond_type type);
+
+#define YY_USER_ACTION { \
+ update_pos(yyget_extra(yyscanner), yylloc, yyleng); \
+ update_offset(yyget_extra(yyscanner), yylloc, yyleng); \
+}
+
+/* avoid warnings with -Wmissing-prototypes */
+extern int yyget_column(yyscan_t);
+extern void yyset_column(int, yyscan_t);
+
+%}
+
+space [ ]
+tab \t
+newline \n
+digit [0-9]
+hexdigit [0-9a-fA-F]
+decstring {digit}+
+hexstring 0[xX]{hexdigit}+
+letter [a-zA-Z]
+string ({letter}|[_.])({letter}|{digit}|[/\-_\.])*
+quotedstring \"[^"]*\"
+asteriskstring ({string}\*|{string}\\\*|\\\*|{string}\\\*{string})
+comment #.*$
+comment_line ^[ \t]*#.*\n
+slash \/
+
+timestring ([0-9]+d)?([0-9]+h)?([0-9]+m)?([0-9]+s)?([0-9]+ms)?
+
+hex4 ([[:xdigit:]]{1,4})
+v680 (({hex4}:){7}{hex4})
+v670 ((:)((:{hex4}){7}))
+v671 ((({hex4}:){1})((:{hex4}){6}))
+v672 ((({hex4}:){2})((:{hex4}){5}))
+v673 ((({hex4}:){3})((:{hex4}){4}))
+v674 ((({hex4}:){4})((:{hex4}){3}))
+v675 ((({hex4}:){5})((:{hex4}){2}))
+v676 ((({hex4}:){6})(:{hex4}{1}))
+v677 ((({hex4}:){7})(:))
+v67 ({v670}|{v671}|{v672}|{v673}|{v674}|{v675}|{v676}|{v677})
+v660 ((:)((:{hex4}){6}))
+v661 ((({hex4}:){1})((:{hex4}){5}))
+v662 ((({hex4}:){2})((:{hex4}){4}))
+v663 ((({hex4}:){3})((:{hex4}){3}))
+v664 ((({hex4}:){4})((:{hex4}){2}))
+v665 ((({hex4}:){5})((:{hex4}){1}))
+v666 ((({hex4}:){6})(:))
+v66 ({v660}|{v661}|{v662}|{v663}|{v664}|{v665}|{v666})
+v650 ((:)((:{hex4}){5}))
+v651 ((({hex4}:){1})((:{hex4}){4}))
+v652 ((({hex4}:){2})((:{hex4}){3}))
+v653 ((({hex4}:){3})((:{hex4}){2}))
+v654 ((({hex4}:){4})(:{hex4}{1}))
+v655 ((({hex4}:){5})(:))
+v65 ({v650}|{v651}|{v652}|{v653}|{v654}|{v655})
+v640 ((:)((:{hex4}){4}))
+v641 ((({hex4}:){1})((:{hex4}){3}))
+v642 ((({hex4}:){2})((:{hex4}){2}))
+v643 ((({hex4}:){3})((:{hex4}){1}))
+v644 ((({hex4}:){4})(:))
+v64 ({v640}|{v641}|{v642}|{v643}|{v644})
+v630 ((:)((:{hex4}){3}))
+v631 ((({hex4}:){1})((:{hex4}){2}))
+v632 ((({hex4}:){2})((:{hex4}){1}))
+v633 ((({hex4}:){3})(:))
+v63 ({v630}|{v631}|{v632}|{v633})
+v620 ((:)((:{hex4}){2}))
+v620_rfc4291 ((:)(:{ip4addr}))
+v621 ((({hex4}:){1})((:{hex4}){1}))
+v622 ((({hex4}:){2})(:))
+v62_rfc4291 ((:)(:[fF]{4})(:{ip4addr}))
+v62 ({v620}|{v621}|{v622}|{v62_rfc4291}|{v620_rfc4291})
+v610 ((:)(:{hex4}{1}))
+v611 ((({hex4}:){1})(:))
+v61 ({v610}|{v611})
+v60 (::)
+
+macaddr (([[:xdigit:]]{1,2}:){5}[[:xdigit:]]{1,2})
+ip4addr (([[:digit:]]{1,3}"."){3}([[:digit:]]{1,3}))
+ip6addr ({v680}|{v67}|{v66}|{v65}|{v64}|{v63}|{v62}|{v61}|{v60})
+ip6addr_rfc2732 (\[{ip6addr}\])
+
+classid ({hexdigit}{1,4}:{hexdigit}{1,4})
+addrstring ({macaddr}|{ip4addr}|{ip6addr})
+
+%option prefix="nft_"
+%option outfile="lex.yy.c"
+%option reentrant
+%option noyywrap
+%option nounput
+%option bison-bridge
+%option bison-locations
+%option debug
+%option yylineno
+%option nodefault
+%option warn
+%option stack
+%s SCANSTATE_ARP
+%s SCANSTATE_AT
+%s SCANSTATE_CT
+%s SCANSTATE_COUNTER
+%s SCANSTATE_ETH
+%s SCANSTATE_GRE
+%s SCANSTATE_ICMP
+%s SCANSTATE_IGMP
+%s SCANSTATE_IP
+%s SCANSTATE_IP6
+%s SCANSTATE_LAST
+%s SCANSTATE_LIMIT
+%s SCANSTATE_META
+%s SCANSTATE_POLICY
+%s SCANSTATE_QUOTA
+%s SCANSTATE_SCTP
+%s SCANSTATE_SECMARK
+%s SCANSTATE_TCP
+%s SCANSTATE_TYPE
+%s SCANSTATE_VLAN
+%s SCANSTATE_XT
+%s SCANSTATE_CMD_DESTROY
+%s SCANSTATE_CMD_EXPORT
+%s SCANSTATE_CMD_IMPORT
+%s SCANSTATE_CMD_LIST
+%s SCANSTATE_CMD_MONITOR
+%s SCANSTATE_CMD_RESET
+%s SCANSTATE_EXPR_AH
+%s SCANSTATE_EXPR_COMP
+%s SCANSTATE_EXPR_DCCP
+%s SCANSTATE_EXPR_DST
+%s SCANSTATE_EXPR_ESP
+%s SCANSTATE_EXPR_FIB
+%s SCANSTATE_EXPR_FRAG
+%s SCANSTATE_EXPR_HASH
+%s SCANSTATE_EXPR_HBH
+%s SCANSTATE_EXPR_IPSEC
+%s SCANSTATE_EXPR_MH
+%s SCANSTATE_EXPR_NUMGEN
+%s SCANSTATE_EXPR_OSF
+%s SCANSTATE_EXPR_QUEUE
+%s SCANSTATE_EXPR_RT
+%s SCANSTATE_EXPR_SCTP_CHUNK
+%s SCANSTATE_EXPR_SOCKET
+%s SCANSTATE_EXPR_TH
+%s SCANSTATE_EXPR_UDP
+%s SCANSTATE_EXPR_UDPLITE
+
+%s SCANSTATE_STMT_DUP
+%s SCANSTATE_STMT_FWD
+%s SCANSTATE_STMT_LOG
+%s SCANSTATE_STMT_NAT
+%s SCANSTATE_STMT_REJECT
+%s SCANSTATE_STMT_SYNPROXY
+%s SCANSTATE_STMT_TPROXY
+
+%%
+
+"==" { return EQ; }
+"eq" { return EQ; }
+"!=" { return NEQ; }
+"ne" { return NEQ; }
+"<=" { return LTE; }
+"le" { return LTE; }
+"<" { return LT; }
+"lt" { return LT; }
+">=" { return GTE; }
+"ge" { return GTE; }
+">" { return GT; }
+"gt" { return GT; }
+"," { return COMMA; }
+"." { return DOT; }
+":" { return COLON; }
+";" { return SEMICOLON; }
+"{" { return '{'; }
+"}" { return '}'; }
+"[" { return '['; }
+"]" { return ']'; }
+"(" { return '('; }
+")" { return ')'; }
+"<<" { return LSHIFT; }
+"lshift" { return LSHIFT; }
+">>" { return RSHIFT; }
+"rshift" { return RSHIFT; }
+"^" { return CARET; }
+"xor" { return CARET; }
+"&" { return AMPERSAND; }
+"and" { return AMPERSAND; }
+"|" { return '|'; }
+"or" { return '|'; }
+"!" { return NOT; }
+"not" { return NOT; }
+"/" { return SLASH; }
+"-" { return DASH; }
+"*" { return ASTERISK; }
+"@" { scanner_push_start_cond(yyscanner, SCANSTATE_AT); return AT; }
+"$" { return '$'; }
+"=" { return '='; }
+"vmap" { return VMAP; }
+
+"+" { return PLUS; }
+
+"include" { return INCLUDE; }
+"define" { return DEFINE; }
+"redefine" { return REDEFINE; }
+"undefine" { return UNDEFINE; }
+
+"describe" { return DESCRIBE; }
+
+<SCANSTATE_CMD_LIST,SCANSTATE_CMD_MONITOR>{
+ "chains" { return CHAINS; }
+ "sets" { return SETS; }
+ "tables" { return TABLES; }
+}
+<SCANSTATE_CMD_MONITOR>{
+ "rules" { return RULES; }
+ "trace" { return TRACE; }
+}
+"hook" { return HOOK; }
+"device" { return DEVICE; }
+"devices" { return DEVICES; }
+"table" { return TABLE; }
+"chain" { return CHAIN; }
+"rule" { return RULE; }
+"set" { return SET; }
+"element" { return ELEMENT; }
+"map" { return MAP; }
+"flowtable" { return FLOWTABLE; }
+"handle" { return HANDLE; }
+"ruleset" { return RULESET; }
+
+"socket" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_SOCKET); return SOCKET; }
+<SCANSTATE_EXPR_SOCKET>{
+ "transparent" { return TRANSPARENT; }
+ "wildcard" { return WILDCARD; }
+ "cgroupv2" { return CGROUPV2; }
+ "level" { return LEVEL; }
+}
+"tproxy" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_TPROXY); return TPROXY; }
+
+"accept" { return ACCEPT; }
+"drop" { return DROP; }
+"continue" { return CONTINUE; }
+"jump" { return JUMP; }
+"goto" { return GOTO; }
+"return" { return RETURN; }
+<SCANSTATE_EXPR_QUEUE,SCANSTATE_STMT_DUP,SCANSTATE_STMT_FWD,SCANSTATE_STMT_NAT,SCANSTATE_STMT_TPROXY,SCANSTATE_IP,SCANSTATE_IP6>"to" { return TO; } /* XXX: SCANSTATE_IP is a workaround */
+
+"inet" { return INET; }
+"netdev" { return NETDEV; }
+
+"add" { return ADD; }
+"replace" { return REPLACE; }
+"update" { return UPDATE; }
+"create" { return CREATE; }
+"insert" { return INSERT; }
+"delete" { return DELETE; }
+"get" { return GET; }
+"list" { scanner_push_start_cond(yyscanner, SCANSTATE_CMD_LIST); return LIST; }
+"reset" { scanner_push_start_cond(yyscanner, SCANSTATE_CMD_RESET); return RESET; }
+"flush" { return FLUSH; }
+"rename" { return RENAME; }
+"import" { scanner_push_start_cond(yyscanner, SCANSTATE_CMD_IMPORT); return IMPORT; }
+"export" { scanner_push_start_cond(yyscanner, SCANSTATE_CMD_EXPORT); return EXPORT; }
+"monitor" { scanner_push_start_cond(yyscanner, SCANSTATE_CMD_MONITOR); return MONITOR; }
+"destroy" { scanner_push_start_cond(yyscanner, SCANSTATE_CMD_DESTROY); return DESTROY; }
+
+
+"position" { return POSITION; }
+"index" { return INDEX; }
+"comment" { return COMMENT; }
+
+"constant" { return CONSTANT; }
+"interval" { return INTERVAL; }
+"dynamic" { return DYNAMIC; }
+"auto-merge" { return AUTOMERGE; }
+"timeout" { return TIMEOUT; }
+"gc-interval" { return GC_INTERVAL; }
+"elements" { return ELEMENTS; }
+"expires" { return EXPIRES; }
+
+"policy" { scanner_push_start_cond(yyscanner, SCANSTATE_POLICY); return POLICY; }
+"size" { return SIZE; }
+<SCANSTATE_POLICY>{
+ "performance" { return PERFORMANCE; }
+ "memory" { return MEMORY; }
+}
+
+"flow" { return FLOW; }
+"offload" { return OFFLOAD; }
+"meter" { return METER; }
+
+<SCANSTATE_CMD_LIST>{
+ "meters" { return METERS; }
+ "flowtables" { return FLOWTABLES; }
+ "limits" { return LIMITS; }
+ "maps" { return MAPS; }
+ "secmarks" { return SECMARKS; }
+ "synproxys" { return SYNPROXYS; }
+ "hooks" { return HOOKS; }
+}
+
+"counter" { scanner_push_start_cond(yyscanner, SCANSTATE_COUNTER); return COUNTER; }
+<SCANSTATE_COUNTER,SCANSTATE_LIMIT,SCANSTATE_QUOTA,SCANSTATE_STMT_SYNPROXY,SCANSTATE_EXPR_OSF>"name" { return NAME; }
+<SCANSTATE_COUNTER,SCANSTATE_CT,SCANSTATE_LIMIT>"packets" { return PACKETS; }
+<SCANSTATE_COUNTER,SCANSTATE_CT,SCANSTATE_LIMIT,SCANSTATE_QUOTA>"bytes" { return BYTES; }
+
+"last" { scanner_push_start_cond(yyscanner, SCANSTATE_LAST); return LAST; }
+<SCANSTATE_LAST>{
+ "never" { return NEVER; }
+}
+
+<SCANSTATE_CMD_LIST,SCANSTATE_CMD_RESET>{
+ "counters" { return COUNTERS; }
+ "quotas" { return QUOTAS; }
+ "rules" { return RULES; }
+}
+
+"log" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_LOG); return LOG; }
+<SCANSTATE_STMT_LOG,SCANSTATE_STMT_NAT,SCANSTATE_IP,SCANSTATE_IP6>"prefix" { return PREFIX; }
+<SCANSTATE_STMT_LOG>{
+ "snaplen" { return SNAPLEN; }
+ "queue-threshold" { return QUEUE_THRESHOLD; }
+ "level" { return LEVEL; }
+ "group" { return GROUP; }
+}
+
+"queue" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_QUEUE); return QUEUE;}
+<SCANSTATE_EXPR_QUEUE>{
+ "num" { return QUEUENUM;}
+ "bypass" { return BYPASS;}
+ "fanout" { return FANOUT;}
+}
+"limit" { scanner_push_start_cond(yyscanner, SCANSTATE_LIMIT); return LIMIT; }
+<SCANSTATE_LIMIT>{
+ "rate" { return RATE; }
+ "burst" { return BURST; }
+
+ /* time_unit */
+ "second" { return SECOND; }
+ "minute" { return MINUTE; }
+ "week" { return WEEK; }
+}
+<SCANSTATE_CT,SCANSTATE_LIMIT,SCANSTATE_QUOTA>"over" { return OVER; }
+
+"quota" { scanner_push_start_cond(yyscanner, SCANSTATE_QUOTA); return QUOTA; }
+<SCANSTATE_QUOTA>{
+ "until" { return UNTIL; }
+}
+
+<SCANSTATE_QUOTA,SCANSTATE_LAST>"used" { return USED; }
+
+"hour" { return HOUR; }
+"day" { return DAY; }
+
+"reject" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_REJECT); return _REJECT; }
+<SCANSTATE_STMT_REJECT>{
+ "with" { return WITH; }
+ "icmpx" { return ICMPX; }
+}
+
+"snat" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_NAT); return SNAT; }
+"dnat" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_NAT); return DNAT; }
+"masquerade" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_NAT); return MASQUERADE; }
+"redirect" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_NAT); return REDIRECT; }
+"random" { return RANDOM; }
+<SCANSTATE_STMT_NAT>{
+ "fully-random" { return FULLY_RANDOM; }
+ "persistent" { return PERSISTENT; }
+ "port" { return PORT; }
+}
+
+<SCANSTATE_AT>{
+ "ll" { return LL_HDR; }
+ "nh" { return NETWORK_HDR; }
+}
+"th" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_TH); return TRANSPORT_HDR; }
+
+"bridge" { return BRIDGE; }
+
+"ether" { scanner_push_start_cond(yyscanner, SCANSTATE_ETH); return ETHER; }
+<SCANSTATE_ARP,SCANSTATE_CT,SCANSTATE_ETH,SCANSTATE_IP,SCANSTATE_IP6,SCANSTATE_EXPR_FIB,SCANSTATE_EXPR_IPSEC>{
+ "saddr" { return SADDR; }
+ "daddr" { return DADDR; }
+}
+"type" { scanner_push_start_cond(yyscanner, SCANSTATE_TYPE); return TYPE; }
+"typeof" { return TYPEOF; }
+
+"vlan" { scanner_push_start_cond(yyscanner, SCANSTATE_VLAN); return VLAN; }
+<SCANSTATE_CT,SCANSTATE_EXPR_FRAG,SCANSTATE_VLAN,SCANSTATE_IP,SCANSTATE_ICMP>"id" { return ID; }
+<SCANSTATE_VLAN>{
+ "cfi" { return CFI; }
+ "dei" { return DEI; }
+ "pcp" { return PCP; }
+}
+"8021ad" { yylval->string = xstrdup(yytext); return STRING; }
+"8021q" { yylval->string = xstrdup(yytext); return STRING; }
+
+"arp" { scanner_push_start_cond(yyscanner, SCANSTATE_ARP); return ARP; }
+<SCANSTATE_ARP>{
+ "htype" { return HTYPE; }
+ "ptype" { return PTYPE; }
+ "hlen" { return HLEN; }
+ "plen" { return PLEN; }
+ "operation" { return OPERATION; }
+}
+
+"ip" { scanner_push_start_cond(yyscanner, SCANSTATE_IP); return IP; }
+<SCANSTATE_IP,SCANSTATE_IP6,SCANSTATE_EXPR_OSF,SCANSTATE_GRE>{
+ "version" { return HDRVERSION; }
+}
+<SCANSTATE_EXPR_AH,SCANSTATE_EXPR_DST,SCANSTATE_EXPR_HBH,SCANSTATE_EXPR_MH,SCANSTATE_EXPR_RT,SCANSTATE_IP>{
+ "hdrlength" { return HDRLENGTH; }
+}
+<SCANSTATE_IP,SCANSTATE_IP6,SCANSTATE_TYPE>{
+ "dscp" { return DSCP; }
+}
+"ecn" { return ECN; }
+<SCANSTATE_EXPR_UDP,SCANSTATE_IP,SCANSTATE_IP6,SCANSTATE_META,SCANSTATE_TCP,SCANSTATE_SCTP,SCANSTATE_EXPR_SCTP_CHUNK>"length" { return LENGTH; }
+<SCANSTATE_EXPR_FRAG,SCANSTATE_IP>{
+ "frag-off" { return FRAG_OFF; }
+}
+<SCANSTATE_EXPR_OSF,SCANSTATE_IP>{
+ "ttl" { return TTL; }
+}
+<SCANSTATE_CT,SCANSTATE_IP,SCANSTATE_META,SCANSTATE_TYPE,SCANSTATE_GRE>"protocol" { return PROTOCOL; }
+<SCANSTATE_EXPR_MH,SCANSTATE_EXPR_UDP,SCANSTATE_EXPR_UDPLITE,SCANSTATE_ICMP,SCANSTATE_IGMP,SCANSTATE_IP,SCANSTATE_SCTP,SCANSTATE_TCP>{
+ "checksum" { return CHECKSUM; }
+}
+
+<SCANSTATE_IP>{
+ "lsrr" { return LSRR; }
+ "rr" { return RR; }
+ "ssrr" { return SSRR; }
+ "ra" { return RA; }
+
+ "ptr" { return PTR; }
+ "value" { return VALUE; }
+
+ "option" { return OPTION; }
+ "options" { return OPTIONS; }
+}
+
+<SCANSTATE_TCP>{
+ /* tcp header fields */
+ "ackseq" { return ACKSEQ; }
+ "doff" { return DOFF; }
+ "window" { return WINDOW; }
+ "urgptr" { return URGPTR; }
+
+ /* tcp option types */
+ "echo" { return ECHO; }
+ "eol" { return EOL; }
+ "maxseg" { return MSS; }
+ "mss" { return MSS; }
+ "nop" { return NOP; }
+ "noop" { return NOP; }
+ "sack" { return SACK; }
+ "sack0" { return SACK0; }
+ "sack1" { return SACK1; }
+ "sack2" { return SACK2; }
+ "sack3" { return SACK3; }
+ "sack-permitted" { return SACK_PERM; }
+ "sack-perm" { return SACK_PERM; }
+ "timestamp" { return TIMESTAMP; }
+ "fastopen" { return FASTOPEN; }
+ "mptcp" { return MPTCP; }
+ "md5sig" { return MD5SIG; }
+
+ /* tcp option fields */
+ "left" { return LEFT; }
+ "right" { return RIGHT; }
+ "count" { return COUNT; }
+ "tsval" { return TSVAL; }
+ "tsecr" { return TSECR; }
+ "subtype" { return SUBTYPE; }
+
+ "options" { return OPTIONS; }
+ "option" { return OPTION; }
+}
+"time" { return TIME; }
+
+"icmp" { scanner_push_start_cond(yyscanner, SCANSTATE_ICMP); return ICMP; }
+"icmpv6" { scanner_push_start_cond(yyscanner, SCANSTATE_ICMP); return ICMP6; }
+<SCANSTATE_ICMP>{
+ "gateway" { return GATEWAY; }
+ "code" { return CODE; }
+ "param-problem" { return PPTR; }
+ "max-delay" { return MAXDELAY; }
+ "mtu" { return MTU; }
+ "taddr" { return TADDR; }
+ "daddr" { return DADDR; }
+}
+<SCANSTATE_EXPR_AH,SCANSTATE_EXPR_ESP,SCANSTATE_ICMP,SCANSTATE_TCP>{
+ "sequence" { return SEQUENCE; }
+}
+
+"igmp" { scanner_push_start_cond(yyscanner, SCANSTATE_IGMP); return IGMP; }
+<SCANSTATE_IGMP>{
+ "mrt" { return MRT; }
+ "group" { return GROUP; }
+}
+
+"ip6" { scanner_push_start_cond(yyscanner, SCANSTATE_IP6); return IP6; }
+"priority" { return PRIORITY; }
+<SCANSTATE_IP6>{
+ "flowlabel" { return FLOWLABEL; }
+ "hoplimit" { return HOPLIMIT; }
+}
+<SCANSTATE_EXPR_AH,SCANSTATE_EXPR_COMP,SCANSTATE_EXPR_DST,SCANSTATE_EXPR_FRAG,SCANSTATE_EXPR_HBH,SCANSTATE_EXPR_MH,SCANSTATE_EXPR_RT,SCANSTATE_IP6>{
+ "nexthdr" { return NEXTHDR; }
+}
+
+"ah" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_AH); return AH; }
+<SCANSTATE_EXPR_AH,SCANSTATE_EXPR_FRAG,SCANSTATE_EXPR_MH,SCANSTATE_TCP>{
+ "reserved" { return RESERVED; }
+}
+<SCANSTATE_EXPR_AH,SCANSTATE_EXPR_ESP,SCANSTATE_EXPR_IPSEC>"spi" { return SPI; }
+
+"esp" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_ESP); return ESP; }
+
+"comp" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_COMP); return COMP; }
+<SCANSTATE_EXPR_COMP>{
+ "cpi" { return CPI; }
+}
+"flags" { return FLAGS; }
+
+"udp" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_UDP); return UDP; }
+"udplite" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_UDPLITE); return UDPLITE; }
+<SCANSTATE_EXPR_UDPLITE>{
+ "csumcov" { return CSUMCOV; }
+}
+<SCANSTATE_EXPR_DCCP,SCANSTATE_SCTP,SCANSTATE_TCP,SCANSTATE_EXPR_TH,SCANSTATE_EXPR_UDP,SCANSTATE_EXPR_UDPLITE>{
+ "sport" { return SPORT; }
+}
+<SCANSTATE_CT,SCANSTATE_EXPR_DCCP,SCANSTATE_SCTP,SCANSTATE_TCP,SCANSTATE_EXPR_TH,SCANSTATE_EXPR_UDP,SCANSTATE_EXPR_UDPLITE>{
+ "dport" { return DPORT; }
+}
+<SCANSTATE_EXPR_DCCP>{
+ "option" { return OPTION; }
+}
+
+"vxlan" { return VXLAN; }
+"vni" { return VNI; }
+
+"geneve" { return GENEVE; }
+
+"gre" { scanner_push_start_cond(yyscanner, SCANSTATE_GRE); return GRE; }
+"gretap" { scanner_push_start_cond(yyscanner, SCANSTATE_GRE); return GRETAP; }
+
+"tcp" { scanner_push_start_cond(yyscanner, SCANSTATE_TCP); return TCP; }
+
+"dccp" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_DCCP); return DCCP; }
+
+"sctp" { scanner_push_start_cond(yyscanner, SCANSTATE_SCTP); return SCTP; }
+
+<SCANSTATE_SCTP>{
+ "chunk" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_SCTP_CHUNK); return CHUNK; }
+ "vtag" { return VTAG; }
+}
+
+<SCANSTATE_EXPR_SCTP_CHUNK>{
+ "data" { return DATA; }
+ "init" { return INIT; }
+ "init-ack" { return INIT_ACK; }
+ "heartbeat" { return HEARTBEAT; }
+ "heartbeat-ack" { return HEARTBEAT_ACK; }
+ "abort" { return ABORT; }
+ "shutdown" { return SHUTDOWN; }
+ "shutdown-ack" { return SHUTDOWN_ACK; }
+ "error" { return ERROR; }
+ "cookie-echo" { return COOKIE_ECHO; }
+ "cookie-ack" { return COOKIE_ACK; }
+ "ecne" { return ECNE; }
+ "cwr" { return CWR; }
+ "shutdown-complete" { return SHUTDOWN_COMPLETE; }
+ "asconf-ack" { return ASCONF_ACK; }
+ "forward-tsn" { return FORWARD_TSN; }
+ "asconf" { return ASCONF; }
+
+ "tsn" { return TSN; }
+ "sack" { return SACK; }
+ "stream" { return STREAM; }
+ "ssn" { return SSN; }
+ "ppid" { return PPID; }
+ "init-tag" { return INIT_TAG; }
+ "a-rwnd" { return A_RWND; }
+ "num-outbound-streams" { return NUM_OSTREAMS; }
+ "num-inbound-streams" { return NUM_ISTREAMS; }
+ "initial-tsn" { return INIT_TSN; }
+ "cum-tsn-ack" { return CUM_TSN_ACK; }
+ "num-gap-ack-blocks" { return NUM_GACK_BLOCKS; }
+ "num-dup-tsns" { return NUM_DUP_TSNS; }
+ "lowest-tsn" { return LOWEST_TSN; }
+ "seqno" { return SEQNO; }
+ "new-cum-tsn" { return NEW_CUM_TSN; }
+}
+
+"rt" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_RT); return RT; }
+"rt0" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_RT); return RT0; }
+"rt2" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_RT); return RT2; }
+"srh" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_RT); return RT4; }
+<SCANSTATE_EXPR_RT,SCANSTATE_STMT_NAT,SCANSTATE_IP,SCANSTATE_IP6>"addr" { return ADDR; }
+
+"hbh" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_HBH); return HBH; }
+
+"frag" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_FRAG); return FRAG; }
+<SCANSTATE_EXPR_FRAG>{
+ "reserved2" { return RESERVED2; }
+ "more-fragments" { return MORE_FRAGMENTS; }
+}
+
+"dst" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_DST); return DST; }
+
+"mh" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_MH); return MH; }
+
+"meta" { scanner_push_start_cond(yyscanner, SCANSTATE_META); return META; }
+"mark" { return MARK; }
+"iif" { return IIF; }
+"iifname" { return IIFNAME; }
+"iiftype" { return IIFTYPE; }
+"oif" { return OIF; }
+"oifname" { return OIFNAME; }
+"oiftype" { return OIFTYPE; }
+"skuid" { return SKUID; }
+"skgid" { return SKGID; }
+"nftrace" { return NFTRACE; }
+"rtclassid" { return RTCLASSID; }
+"ibriport" { return IBRIPORT; }
+"ibrname" { return IBRIDGENAME; }
+"obriport" { return OBRIPORT; }
+"obrname" { return OBRIDGENAME; }
+"pkttype" { return PKTTYPE; }
+"cpu" { return CPU; }
+"iifgroup" { return IIFGROUP; }
+"oifgroup" { return OIFGROUP; }
+"cgroup" { return CGROUP; }
+
+<SCANSTATE_EXPR_RT>{
+ "nexthop" { return NEXTHOP; }
+ "seg-left" { return SEG_LEFT; }
+ "mtu" { return MTU; }
+ "last-entry" { return LAST_ENT; }
+ "tag" { return TAG; }
+ "sid" { return SID; }
+}
+<SCANSTATE_EXPR_RT,SCANSTATE_TYPE>{
+ "classid" { return CLASSID; }
+}
+
+"ct" { scanner_push_start_cond(yyscanner, SCANSTATE_CT); return CT; }
+<SCANSTATE_CT>{
+ "avgpkt" { return AVGPKT; }
+ "l3proto" { return L3PROTOCOL; }
+ "proto-src" { return PROTO_SRC; }
+ "proto-dst" { return PROTO_DST; }
+ "zone" { return ZONE; }
+ "original" { return ORIGINAL; }
+ "reply" { return REPLY; }
+ "direction" { return DIRECTION; }
+ "event" { return EVENT; }
+ "expectation" { return EXPECTATION; }
+ "expiration" { return EXPIRATION; }
+ "helper" { return HELPER; }
+ "helpers" { return HELPERS; }
+ "label" { return LABEL; }
+ "state" { return STATE; }
+ "status" { return STATUS; }
+ "count" { return COUNT; }
+}
+
+"numgen" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_NUMGEN); return NUMGEN; }
+<SCANSTATE_EXPR_NUMGEN>{
+ "inc" { return INC; }
+}
+
+"jhash" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_HASH); return JHASH; }
+"symhash" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_HASH); return SYMHASH; }
+
+<SCANSTATE_EXPR_HASH>{
+ "seed" { return SEED; }
+}
+<SCANSTATE_EXPR_HASH,SCANSTATE_EXPR_NUMGEN>{
+ "mod" { return MOD; }
+ "offset" { return OFFSET; }
+}
+"dup" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_DUP); return DUP; }
+"fwd" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_FWD); return FWD; }
+
+"fib" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_FIB); return FIB; }
+
+"osf" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_OSF); return OSF; }
+
+"synproxy" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_SYNPROXY); return SYNPROXY; }
+<SCANSTATE_STMT_SYNPROXY>{
+ "wscale" { return WSCALE; }
+ "maxseg" { return MSS; }
+ "mss" { return MSS; }
+ "timestamp" { return TIMESTAMP; }
+ "sack-permitted" { return SACK_PERM; }
+ "sack-perm" { return SACK_PERM; }
+}
+
+"notrack" { return NOTRACK; }
+
+"all" { return ALL; }
+
+<SCANSTATE_CMD_EXPORT,SCANSTATE_CMD_IMPORT,SCANSTATE_CMD_MONITOR>{
+ "xml" { return XML; }
+ "json" { return JSON; }
+ "vm" { return VM; }
+}
+
+"exists" { return EXISTS; }
+"missing" { return MISSING; }
+
+"exthdr" { return EXTHDR; }
+
+"ipsec" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_IPSEC); return IPSEC; }
+<SCANSTATE_EXPR_IPSEC>{
+ "reqid" { return REQID; }
+ "spnum" { return SPNUM; }
+
+ "in" { return IN; }
+ "out" { return OUT; }
+}
+
+"secmark" { scanner_push_start_cond(yyscanner, SCANSTATE_SECMARK); return SECMARK; }
+
+"xt" { scanner_push_start_cond(yyscanner, SCANSTATE_XT); return XT; }
+
+{addrstring} {
+ yylval->string = xstrdup(yytext);
+ return STRING;
+ }
+
+{ip6addr_rfc2732} {
+ yytext[yyleng - 1] = '\0';
+ yylval->string = xstrdup(yytext + 1);
+ return STRING;
+ }
+
+{timestring} {
+ yylval->string = xstrdup(yytext);
+ return STRING;
+ }
+
+{hexstring} {
+ errno = 0;
+ yylval->val = strtoull(yytext, NULL, 16);
+ if (errno != 0) {
+ yylval->string = xstrdup(yytext);
+ return STRING;
+ }
+ return NUM;
+ }
+
+{decstring} {
+ int base = yytext[0] == '0' ? 8 : 10;
+ char *end;
+
+ errno = 0;
+ yylval->val = strtoull(yytext, &end, base);
+ if (errno != 0 || *end) {
+ yylval->string = xstrdup(yytext);
+ return STRING;
+ }
+ return NUM;
+ }
+
+{classid}/[ \t\n:\-},] {
+ yylval->string = xstrdup(yytext);
+ return STRING;
+ }
+
+{quotedstring} {
+ yytext[yyleng - 1] = '\0';
+ yylval->string = xstrdup(yytext + 1);
+ return QUOTED_STRING;
+ }
+
+{asteriskstring} {
+ yylval->string = xstrdup(yytext);
+ return ASTERISK_STRING;
+ }
+
+{string} {
+ yylval->string = xstrdup(yytext);
+ return STRING;
+ }
+
+\\{newline} {
+ reset_pos(yyget_extra(yyscanner), yylloc);
+ }
+
+{newline} {
+ reset_pos(yyget_extra(yyscanner), yylloc);
+ return NEWLINE;
+ }
+
+{tab}+
+{space}+
+{comment_line} {
+ reset_pos(yyget_extra(yyscanner), yylloc);
+ }
+{comment}
+
+<<EOF>> {
+ update_pos(yyget_extra(yyscanner), yylloc, 1);
+ scanner_pop_buffer(yyscanner);
+ if (YY_CURRENT_BUFFER == NULL)
+ return TOKEN_EOF;
+ }
+
+. { return JUNK; }
+
+%%
+
+static void scanner_push_indesc(struct parser_state *state,
+ struct input_descriptor *indesc)
+{
+ if (!state->indesc)
+ list_add_tail(&indesc->list, &state->indesc_list);
+ else
+ list_add(&indesc->list, &state->indesc->list);
+
+ state->indesc = indesc;
+}
+
+static void scanner_pop_indesc(struct parser_state *state)
+{
+ if (!list_is_first(&state->indesc->list, &state->indesc_list)) {
+ state->indesc = list_entry(state->indesc->list.prev,
+ struct input_descriptor, list);
+ } else {
+ state->indesc = NULL;
+ }
+}
+
+static void scanner_pop_buffer(yyscan_t scanner)
+{
+ struct parser_state *state = yyget_extra(scanner);
+
+ yypop_buffer_state(scanner);
+ scanner_pop_indesc(state);
+}
+
+static void scanner_push_file(struct nft_ctx *nft, void *scanner,
+ FILE *f, const char *filename,
+ const struct location *loc,
+ const struct input_descriptor *parent_indesc)
+{
+ struct parser_state *state = yyget_extra(scanner);
+ struct input_descriptor *indesc;
+ YY_BUFFER_STATE b;
+
+ b = yy_create_buffer(f, YY_BUF_SIZE, scanner);
+ yypush_buffer_state(b, scanner);
+
+ indesc = xzalloc(sizeof(struct input_descriptor));
+
+ if (loc != NULL)
+ indesc->location = *loc;
+ indesc->type = INDESC_FILE;
+ indesc->name = xstrdup(filename);
+ indesc->f = f;
+ if (!parent_indesc) {
+ indesc->depth = 1;
+ } else {
+ indesc->depth = parent_indesc->depth + 1;
+ }
+ init_pos(indesc);
+
+ scanner_push_indesc(state, indesc);
+}
+
+enum nft_include_type {
+ NFT_INCLUDE,
+ NFT_CMDLINE,
+};
+
+static bool __is_useable(unsigned int type, enum nft_include_type t)
+{
+ type &= S_IFMT;
+ switch (type) {
+ case S_IFREG: return true;
+ case S_IFIFO:
+ return t == NFT_CMDLINE; /* disallow include /path/to/fifo */
+ default:
+ break;
+ }
+
+ return false;
+}
+
+/* need to use stat() to, fopen() will block for named fifos */
+static bool filename_is_useable(const char *name)
+{
+ struct stat sb;
+ int err;
+
+ err = stat(name, &sb);
+ if (err)
+ return false;
+
+ return __is_useable(sb.st_mode, NFT_INCLUDE);
+}
+
+static bool fp_is_useable(FILE *fp, enum nft_include_type t)
+{
+ int fd = fileno(fp);
+ struct stat sb;
+ int err;
+
+ if (fd < 0)
+ return false;
+
+ err = fstat(fd, &sb);
+ if (err < 0)
+ return false;
+
+ return __is_useable(sb.st_mode, t);
+}
+
+static int include_file(struct nft_ctx *nft, void *scanner,
+ const char *filename, const struct location *loc,
+ const struct input_descriptor *parent_indesc,
+ enum nft_include_type includetype)
+
+{
+ struct parser_state *state = yyget_extra(scanner);
+ struct error_record *erec;
+ FILE *f;
+
+ if (parent_indesc && parent_indesc->depth == MAX_INCLUDE_DEPTH) {
+ erec = error(loc, "Include nested too deeply, max %u levels",
+ MAX_INCLUDE_DEPTH);
+ goto err;
+ }
+
+ if (includetype == NFT_INCLUDE && !filename_is_useable(filename)) {
+ erec = error(loc, "Not a regular file: \"%s\"\n", filename);
+ goto err;
+ }
+
+ f = fopen(filename, "r");
+ if (f == NULL) {
+ erec = error(loc, "Could not open file \"%s\": %s\n",
+ filename, strerror(errno));
+ goto err;
+ }
+
+ if (!fp_is_useable(f, includetype)) {
+ fclose(f);
+ erec = error(loc, "Not a regular file: \"%s\"\n", filename);
+ goto err;
+ }
+
+ scanner_push_file(nft, scanner, f, filename, loc, parent_indesc);
+ return 0;
+err:
+ erec_queue(erec, state->msgs);
+ return -1;
+}
+
+static int include_glob(struct nft_ctx *nft, void *scanner, const char *pattern,
+ const struct location *loc)
+{
+ struct parser_state *state = yyget_extra(scanner);
+ struct input_descriptor *indesc = state->indesc;
+ struct error_record *erec = NULL;
+ bool wildcard = false;
+ glob_t glob_data;
+ unsigned int i;
+ int flags = 0;
+ int ret;
+ char *p;
+
+ /* This function can return four meaningful values:
+ *
+ * -1 means that there was an error.
+ * 0 means that a single non-wildcard match was done.
+ * 1 means that there are no wildcards in the pattern and the
+ * search can continue.
+ * 2 means that there are wildcards in the pattern and the search
+ * can continue.
+ *
+ * The diffrence is needed, because there is a semantic difference
+ * between patterns with wildcards and no wildcards. Not finding a
+ * non-wildcard file is an error but not finding any matches for a
+ * wildcard pattern is not.
+ */
+
+ /* There shouldn't be a need to use escape characters in include paths.
+ */
+ flags |= GLOB_NOESCAPE;
+
+ /* Mark directories so we can filter them out (also links). */
+ flags |= GLOB_MARK;
+
+ /* If there is no match, glob() doesn't set GLOB_MAGCHAR even if there
+ * are wildcard characters in the pattern. We need to look for (luckily
+ * well-known and not likely to change) magic characters ourselves. In a
+ * perfect world, we could use glob() itself to figure out if there are
+ * wildcards in the pattern.
+ */
+ p = (char *)pattern;
+ while (*p) {
+ if (*p == '*' || *p == '?' || *p == '[') {
+ wildcard = true;
+ break;
+ }
+ p++;
+ }
+
+ ret = glob(pattern, flags, NULL, &glob_data);
+ if (ret == 0) {
+ char *path;
+ int len;
+
+ /* reverse alphabetical order due to stack */
+ for (i = glob_data.gl_pathc; i > 0; i--) {
+
+ path = glob_data.gl_pathv[i-1];
+
+ /* ignore directories */
+ len = strlen(path);
+ if (len == 0 || path[len - 1] == '/')
+ continue;
+
+ ret = include_file(nft, scanner, path, loc, indesc, NFT_INCLUDE);
+ if (ret != 0)
+ goto err;
+ }
+
+ globfree(&glob_data);
+
+ /* If no wildcards and we found the file, stop the search (with
+ * 0). In case of wildcards we need to still continue the
+ * search, because other matches might be in other include
+ * directories. We handled the case with a non-wildcard pattern
+ * and no matches already before.
+ */
+ return wildcard ? 2 : 0;
+ } else if (ret == GLOB_NOMATCH) {
+ globfree(&glob_data);
+
+ /* We need to tell the caller whether wildcards were used in
+ * case of no match, because the semantics for handling the
+ * cases are different.
+ */
+ return wildcard ? 2 : 1;
+ }
+
+ erec = error(loc, "Failed to glob the pattern %s", pattern);
+
+ /* intentional fall through */
+err:
+ if (erec)
+ erec_queue(erec, state->msgs);
+ globfree(&glob_data);
+ return -1;
+}
+
+int scanner_read_file(struct nft_ctx *nft, const char *filename,
+ const struct location *loc)
+{
+ return include_file(nft, nft->scanner, filename, loc, NULL, NFT_CMDLINE);
+}
+
+static bool search_in_include_path(const char *filename)
+{
+ return (strncmp(filename, "./", strlen("./")) != 0 &&
+ strncmp(filename, "../", strlen("../")) != 0 &&
+ filename[0] != '/');
+}
+
+int scanner_include_file(struct nft_ctx *nft, void *scanner,
+ const char *filename, const struct location *loc)
+{
+ struct parser_state *state = yyget_extra(scanner);
+ struct error_record *erec;
+ char buf[PATH_MAX];
+ unsigned int i;
+ int ret = -1;
+
+ if (search_in_include_path(filename)) {
+ for (i = 0; i < nft->num_include_paths; i++) {
+ ret = snprintf(buf, sizeof(buf), "%s/%s",
+ nft->include_paths[i], filename);
+ if (ret < 0 || ret >= PATH_MAX) {
+ erec = error(loc, "Too long file path \"%s/%s\"\n",
+ nft->include_paths[i], filename);
+ erec_queue(erec, state->msgs);
+ return -1;
+ }
+
+ ret = include_glob(nft, scanner, buf, loc);
+
+ /* error was already handled */
+ if (ret == -1)
+ return -1;
+ /* no wildcards and file was processed: break early. */
+ if (ret == 0)
+ return 0;
+
+ /* else 1 (no wildcards) or 2 (wildcards): keep
+ * searching.
+ */
+ }
+ } else {
+ /* an absolute path (starts with '/') */
+ ret = include_glob(nft, scanner, filename, loc);
+ }
+
+ /* handle the case where no file was found */
+ if (ret == -1)
+ return -1;
+ else if (ret == 0 || ret == 2)
+ return 0;
+
+ /* 1 means an error, because there are no more include directories to
+ * search, and the pattern does not have wildcard characters.
+ */
+ erec = error(loc, "File not found: %s", filename);
+ erec_queue(erec, state->msgs);
+ return -1;
+}
+
+void scanner_push_buffer(void *scanner, const struct input_descriptor *indesc,
+ const char *buffer)
+{
+ struct parser_state *state = yyget_extra(scanner);
+ struct input_descriptor *new_indesc;
+ YY_BUFFER_STATE b;
+
+ new_indesc = xzalloc(sizeof(struct input_descriptor));
+ memcpy(new_indesc, indesc, sizeof(*new_indesc));
+ new_indesc->data = buffer;
+ new_indesc->name = xstrdup(indesc->name);
+ scanner_push_indesc(state, new_indesc);
+
+ b = yy_scan_string(buffer, scanner);
+ assert(b != NULL);
+ init_pos(state->indesc);
+}
+
+void *scanner_init(struct parser_state *state)
+{
+ yyscan_t scanner;
+
+ yylex_init_extra(state, &scanner);
+ yyset_out(NULL, scanner);
+
+ state->startcond_active = xzalloc_array(__SC_MAX,
+ sizeof(*state->startcond_active));
+ return scanner;
+}
+
+static void input_descriptor_destroy(const struct input_descriptor *indesc)
+{
+ if (indesc->name)
+ xfree(indesc->name);
+ xfree(indesc);
+}
+
+static void input_descriptor_list_destroy(struct parser_state *state)
+{
+ struct input_descriptor *indesc, *next;
+
+ list_for_each_entry_safe(indesc, next, &state->indesc_list, list) {
+ if (indesc->f) {
+ fclose(indesc->f);
+ indesc->f = NULL;
+ }
+ list_del(&indesc->list);
+ input_descriptor_destroy(indesc);
+ }
+}
+
+void scanner_destroy(struct nft_ctx *nft)
+{
+ struct parser_state *state = yyget_extra(nft->scanner);
+
+ input_descriptor_list_destroy(state);
+ xfree(state->startcond_active);
+
+ yylex_destroy(nft->scanner);
+}
+
+static void scanner_push_start_cond(void *scanner, enum startcond_type type)
+{
+ struct parser_state *state = yyget_extra(scanner);
+
+ state->startcond_type = type;
+ state->startcond_active[type]++;
+
+ yy_push_state((int)type, scanner);
+}
+
+void scanner_pop_start_cond(void *scanner, enum startcond_type t)
+{
+ struct parser_state *state = yyget_extra(scanner);
+
+ state->startcond_active[t]--;
+
+ if (state->startcond_type != t) {
+ state->flex_state_pop++;
+ return; /* Can't pop just yet! */
+ }
+
+ while (state->flex_state_pop) {
+ state->flex_state_pop--;
+ state->startcond_type = yy_top_state(scanner);
+ yy_pop_state(scanner);
+
+ t = state->startcond_type;
+ if (state->startcond_active[t])
+ return;
+ }
+
+ state->startcond_type = yy_top_state(scanner);
+
+ yy_pop_state(scanner);
+}