/* * Copyright (c) 2007-2012 Patrick McHardy * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "parser_bison.h" void parser_init(struct nft_ctx *nft, struct parser_state *state, struct list_head *msgs, struct list_head *cmds, struct scope *top_scope) { memset(state, 0, sizeof(*state)); state->msgs = msgs; state->cmds = cmds; state->scopes[0] = scope_init(top_scope, NULL); init_list_head(&state->indesc_list); } static void yyerror(struct location *loc, struct nft_ctx *nft, void *scanner, struct parser_state *state, const char *s) { erec_queue(error(loc, "%s", s), state->msgs); } static struct scope *current_scope(const struct parser_state *state) { return state->scopes[state->scope]; } static void open_scope(struct parser_state *state, struct scope *scope) { assert(state->scope < array_size(state->scopes) - 1); scope_init(scope, current_scope(state)); state->scopes[++state->scope] = scope; } static void close_scope(struct parser_state *state) { assert(state->scope > 0); state->scope--; } static void location_init(void *scanner, struct parser_state *state, struct location *loc) { memset(loc, 0, sizeof(*loc)); loc->indesc = state->indesc; } static void location_update(struct location *loc, struct location *rhs, int n) { if (n) { loc->indesc = rhs[n].indesc; loc->token_offset = rhs[1].token_offset; loc->line_offset = rhs[1].line_offset; loc->first_line = rhs[1].first_line; loc->first_column = rhs[1].first_column; loc->last_line = rhs[n].last_line; loc->last_column = rhs[n].last_column; } else { loc->indesc = rhs[0].indesc; loc->token_offset = rhs[0].token_offset; loc->line_offset = rhs[0].line_offset; loc->first_line = loc->last_line = rhs[0].last_line; loc->first_column = loc->last_column = rhs[0].last_column; } } static struct expr *handle_concat_expr(const struct location *loc, struct expr *expr, struct expr *expr_l, struct expr *expr_r, struct location loc_rhs[3]) { if (expr->etype != EXPR_CONCAT) { expr = concat_expr_alloc(loc); compound_expr_add(expr, expr_l); } else { location_update(&expr_r->location, loc_rhs, 2); expr = expr_l; expr->location = *loc; } compound_expr_add(expr, expr_r); return expr; } #define YYLLOC_DEFAULT(Current, Rhs, N) location_update(&Current, Rhs, N) #define symbol_value(loc, str) \ symbol_expr_alloc(loc, SYMBOL_VALUE, current_scope(state), str) /* Declare those here to avoid compiler warnings */ void nft_set_debug(int, void *); int nft_lex(void *, void *, void *); %} /* Declaration section */ %name-prefix "nft_" %debug %define api.pure %parse-param { struct nft_ctx *nft } %parse-param { void *scanner } %parse-param { struct parser_state *state } %lex-param { scanner } %define parse.error verbose %locations %initial-action { location_init(scanner, state, &yylloc); if (nft->debug_mask & NFT_DEBUG_SCANNER) nft_set_debug(1, scanner); if (nft->debug_mask & NFT_DEBUG_PARSER) yydebug = 1; } %union { uint64_t val; uint32_t val32; uint8_t val8; const char * string; struct list_head *list; struct cmd *cmd; struct handle handle; struct table *table; struct chain *chain; struct rule *rule; struct stmt *stmt; struct expr *expr; struct set *set; struct obj *obj; struct flowtable *flowtable; struct ct *ct; const struct datatype *datatype; struct handle_spec handle_spec; struct position_spec position_spec; struct prio_spec prio_spec; const struct exthdr_desc *exthdr_desc; } %token TOKEN_EOF 0 "end of file" %token JUNK "junk" %token NEWLINE "newline" %token COLON "colon" %token SEMICOLON "semicolon" %token COMMA "comma" %token DOT "." %token EQ "==" %token NEQ "!=" %token LT "<" %token GT ">" %token GTE ">=" %token LTE "<=" %token LSHIFT "<<" %token RSHIFT ">>" %token AMPERSAND "&" %token CARET "^" %token NOT "!" %token SLASH "/" %token ASTERISK "*" %token DASH "-" %token AT "@" %token VMAP "vmap" %token PLUS "+" %token INCLUDE "include" %token DEFINE "define" %token REDEFINE "redefine" %token UNDEFINE "undefine" %token FIB "fib" %token SOCKET "socket" %token TRANSPARENT "transparent" %token TPROXY "tproxy" %token OSF "osf" %token SYNPROXY "synproxy" %token MSS "mss" %token WSCALE "wscale" %token SACKPERM "sack-perm" %token TYPEOF "typeof" %token HOOK "hook" %token DEVICE "device" %token DEVICES "devices" %token TABLE "table" %token TABLES "tables" %token CHAIN "chain" %token CHAINS "chains" %token RULE "rule" %token RULES "rules" %token SETS "sets" %token SET "set" %token ELEMENT "element" %token MAP "map" %token MAPS "maps" %token FLOWTABLE "flowtable" %token HANDLE "handle" %token RULESET "ruleset" %token TRACE "trace" %token INET "inet" %token NETDEV "netdev" %token ADD "add" %token UPDATE "update" %token REPLACE "replace" %token CREATE "create" %token INSERT "insert" %token DELETE "delete" %token GET "get" %token LIST "list" %token RESET "reset" %token FLUSH "flush" %token RENAME "rename" %token DESCRIBE "describe" %token IMPORT "import" %token EXPORT "export" %token MONITOR "monitor" %token ALL "all" %token ACCEPT "accept" %token DROP "drop" %token CONTINUE "continue" %token JUMP "jump" %token GOTO "goto" %token RETURN "return" %token TO "to" %token CONSTANT "constant" %token INTERVAL "interval" %token DYNAMIC "dynamic" %token AUTOMERGE "auto-merge" %token TIMEOUT "timeout" %token GC_INTERVAL "gc-interval" %token ELEMENTS "elements" %token EXPIRES "expires" %token POLICY "policy" %token MEMORY "memory" %token PERFORMANCE "performance" %token SIZE "size" %token FLOW "flow" %token OFFLOAD "offload" %token METER "meter" %token METERS "meters" %token FLOWTABLES "flowtables" %token NUM "number" %token STRING "string" %token QUOTED_STRING "quoted string" %token ASTERISK_STRING "string with a trailing asterisk" %destructor { xfree($$); } STRING QUOTED_STRING ASTERISK_STRING %token LL_HDR "ll" %token NETWORK_HDR "nh" %token TRANSPORT_HDR "th" %token BRIDGE "bridge" %token ETHER "ether" %token SADDR "saddr" %token DADDR "daddr" %token TYPE "type" %token VLAN "vlan" %token ID "id" %token CFI "cfi" %token PCP "pcp" %token ARP "arp" %token HTYPE "htype" %token PTYPE "ptype" %token HLEN "hlen" %token PLEN "plen" %token OPERATION "operation" %token IP "ip" %token HDRVERSION "version" %token HDRLENGTH "hdrlength" %token DSCP "dscp" %token ECN "ecn" %token LENGTH "length" %token FRAG_OFF "frag-off" %token TTL "ttl" %token PROTOCOL "protocol" %token CHECKSUM "checksum" %token PTR "ptr" %token VALUE "value" %token LSRR "lsrr" %token RR "rr" %token SSRR "ssrr" %token RA "ra" %token ICMP "icmp" %token CODE "code" %token SEQUENCE "seq" %token GATEWAY "gateway" %token MTU "mtu" %token IGMP "igmp" %token MRT "mrt" %token OPTIONS "options" %token IP6 "ip6" %token PRIORITY "priority" %token FLOWLABEL "flowlabel" %token NEXTHDR "nexthdr" %token HOPLIMIT "hoplimit" %token ICMP6 "icmpv6" %token PPTR "param-problem" %token MAXDELAY "max-delay" %token AH "ah" %token RESERVED "reserved" %token SPI "spi" %token ESP "esp" %token COMP "comp" %token FLAGS "flags" %token CPI "cpi" %token PORT "port" %token UDP "udp" %token SPORT "sport" %token DPORT "dport" %token UDPLITE "udplite" %token CSUMCOV "csumcov" %token TCP "tcp" %token ACKSEQ "ackseq" %token DOFF "doff" %token WINDOW "window" %token URGPTR "urgptr" %token OPTION "option" %token ECHO "echo" %token EOL "eol" %token MAXSEG "maxseg" %token NOOP "noop" %token SACK "sack" %token SACK0 "sack0" %token SACK1 "sack1" %token SACK2 "sack2" %token SACK3 "sack3" %token SACK_PERMITTED "sack-permitted" %token TIMESTAMP "timestamp" %token KIND "kind" %token COUNT "count" %token LEFT "left" %token RIGHT "right" %token TSVAL "tsval" %token TSECR "tsecr" %token DCCP "dccp" %token SCTP "sctp" %token VTAG "vtag" %token RT "rt" %token RT0 "rt0" %token RT2 "rt2" %token RT4 "srh" %token SEG_LEFT "seg-left" %token ADDR "addr" %token LAST_ENT "last-entry" %token TAG "tag" %token SID "sid" %token HBH "hbh" %token FRAG "frag" %token RESERVED2 "reserved2" %token MORE_FRAGMENTS "more-fragments" %token DST "dst" %token MH "mh" %token META "meta" %token MARK "mark" %token IIF "iif" %token IIFNAME "iifname" %token IIFTYPE "iiftype" %token OIF "oif" %token OIFNAME "oifname" %token OIFTYPE "oiftype" %token SKUID "skuid" %token SKGID "skgid" %token NFTRACE "nftrace" %token RTCLASSID "rtclassid" %token IBRIPORT "ibriport" %token OBRIPORT "obriport" %token IBRIDGENAME "ibrname" %token OBRIDGENAME "obrname" %token PKTTYPE "pkttype" %token CPU "cpu" %token IIFGROUP "iifgroup" %token OIFGROUP "oifgroup" %token CGROUP "cgroup" %token TIME "time" %token CLASSID "classid" %token NEXTHOP "nexthop" %token CT "ct" %token L3PROTOCOL "l3proto" %token PROTO_SRC "proto-src" %token PROTO_DST "proto-dst" %token ZONE "zone" %token DIRECTION "direction" %token EVENT "event" %token EXPECTATION "expectation" %token EXPIRATION "expiration" %token HELPER "helper" %token LABEL "label" %token STATE "state" %token STATUS "status" %token ORIGINAL "original" %token REPLY "reply" %token COUNTER "counter" %token NAME "name" %token PACKETS "packets" %token BYTES "bytes" %token AVGPKT "avgpkt" %token COUNTERS "counters" %token QUOTAS "quotas" %token LIMITS "limits" %token SYNPROXYS "synproxys" %token HELPERS "helpers" %token LOG "log" %token PREFIX "prefix" %token GROUP "group" %token SNAPLEN "snaplen" %token QUEUE_THRESHOLD "queue-threshold" %token LEVEL "level" %token LIMIT "limit" %token RATE "rate" %token BURST "burst" %token OVER "over" %token UNTIL "until" %token QUOTA "quota" %token USED "used" %token SECMARK "secmark" %token SECMARKS "secmarks" %token NANOSECOND "nanosecond" %token MICROSECOND "microsecond" %token MILLISECOND "millisecond" %token SECOND "second" %token MINUTE "minute" %token HOUR "hour" %token DAY "day" %token WEEK "week" %token _REJECT "reject" %token WITH "with" %token ICMPX "icmpx" %token SNAT "snat" %token DNAT "dnat" %token MASQUERADE "masquerade" %token REDIRECT "redirect" %token RANDOM "random" %token FULLY_RANDOM "fully-random" %token PERSISTENT "persistent" %token QUEUE "queue" %token QUEUENUM "num" %token BYPASS "bypass" %token FANOUT "fanout" %token DUP "dup" %token FWD "fwd" %token NUMGEN "numgen" %token INC "inc" %token MOD "mod" %token OFFSET "offset" %token JHASH "jhash" %token SYMHASH "symhash" %token SEED "seed" %token POSITION "position" %token INDEX "index" %token COMMENT "comment" %token XML "xml" %token JSON "json" %token VM "vm" %token NOTRACK "notrack" %token EXISTS "exists" %token MISSING "missing" %token EXTHDR "exthdr" %token IPSEC "ipsec" %token MODE "mode" %token REQID "reqid" %token SPNUM "spnum" %token TRANSPORT "transport" %token TUNNEL "tunnel" %token IN "in" %token OUT "out" %type identifier type_identifier string comment_spec %destructor { xfree($$); } identifier type_identifier string comment_spec %type time_spec quota_used %type data_type_expr data_type_atom_expr %destructor { expr_free($$); } data_type_expr data_type_atom_expr %type line %destructor { cmd_free($$); } line %type base_cmd add_cmd replace_cmd create_cmd insert_cmd delete_cmd get_cmd list_cmd reset_cmd flush_cmd rename_cmd export_cmd monitor_cmd describe_cmd import_cmd %destructor { cmd_free($$); } base_cmd add_cmd replace_cmd create_cmd insert_cmd delete_cmd get_cmd list_cmd reset_cmd flush_cmd rename_cmd export_cmd monitor_cmd describe_cmd import_cmd %type table_spec tableid_spec chain_spec chainid_spec flowtable_spec chain_identifier ruleid_spec handle_spec position_spec rule_position ruleset_spec index_spec %destructor { handle_free(&$$); } table_spec tableid_spec chain_spec chainid_spec flowtable_spec chain_identifier ruleid_spec handle_spec position_spec rule_position ruleset_spec index_spec %type set_spec setid_spec set_identifier flowtableid_spec flowtable_identifier obj_spec objid_spec obj_identifier %destructor { handle_free(&$$); } set_spec setid_spec set_identifier flowtableid_spec obj_spec objid_spec obj_identifier %type family_spec family_spec_explicit %type int_num chain_policy %type extended_prio_spec prio_spec %type extended_prio_name quota_unit %destructor { xfree($$); } extended_prio_name quota_unit %type dev_spec %destructor { xfree($$); } dev_spec %type table_block_alloc table_block %destructor { close_scope(state); table_free($$); } table_block_alloc %type chain_block_alloc chain_block %destructor { close_scope(state); chain_free($$); } chain_block_alloc %type rule rule_alloc %destructor { rule_free($$); } rule %type set_flag_list set_flag %type set_policy_spec %type set_block_alloc set_block %destructor { set_free($$); } set_block_alloc %type map_block_alloc map_block %destructor { set_free($$); } map_block_alloc %type flowtable_block_alloc flowtable_block %destructor { flowtable_free($$); } flowtable_block_alloc %type obj_block_alloc counter_block quota_block ct_helper_block ct_timeout_block ct_expect_block limit_block secmark_block synproxy_block %destructor { obj_free($$); } obj_block_alloc %type stmt_list %destructor { stmt_list_free($$); xfree($$); } stmt_list %type stmt match_stmt verdict_stmt %destructor { stmt_free($$); } stmt match_stmt verdict_stmt %type counter_stmt counter_stmt_alloc stateful_stmt %destructor { stmt_free($$); } counter_stmt counter_stmt_alloc stateful_stmt %type payload_stmt %destructor { stmt_free($$); } payload_stmt %type ct_stmt %destructor { stmt_free($$); } ct_stmt %type meta_stmt %destructor { stmt_free($$); } meta_stmt %type log_stmt log_stmt_alloc %destructor { stmt_free($$); } log_stmt log_stmt_alloc %type level_type log_flags log_flags_tcp log_flag_tcp %type limit_stmt quota_stmt connlimit_stmt %destructor { stmt_free($$); } limit_stmt quota_stmt connlimit_stmt %type limit_burst_pkts limit_burst_bytes limit_mode time_unit quota_mode %type reject_stmt reject_stmt_alloc %destructor { stmt_free($$); } reject_stmt reject_stmt_alloc %type nat_stmt nat_stmt_alloc masq_stmt masq_stmt_alloc redir_stmt redir_stmt_alloc %destructor { stmt_free($$); } nat_stmt nat_stmt_alloc masq_stmt masq_stmt_alloc redir_stmt redir_stmt_alloc %type nf_nat_flags nf_nat_flag offset_opt %type tproxy_stmt %destructor { stmt_free($$); } tproxy_stmt %type synproxy_stmt synproxy_stmt_alloc %destructor { stmt_free($$); } synproxy_stmt synproxy_stmt_alloc %type queue_stmt queue_stmt_alloc %destructor { stmt_free($$); } queue_stmt queue_stmt_alloc %type queue_stmt_flags queue_stmt_flag %type dup_stmt %destructor { stmt_free($$); } dup_stmt %type fwd_stmt %destructor { stmt_free($$); } fwd_stmt %type set_stmt %destructor { stmt_free($$); } set_stmt %type set_stmt_op %type map_stmt %destructor { stmt_free($$); } map_stmt %type meter_stmt meter_stmt_alloc flow_stmt_legacy_alloc %destructor { stmt_free($$); } meter_stmt meter_stmt_alloc flow_stmt_legacy_alloc %type symbol_expr verdict_expr integer_expr variable_expr chain_expr policy_expr %destructor { expr_free($$); } symbol_expr verdict_expr integer_expr variable_expr chain_expr policy_expr %type primary_expr shift_expr and_expr typeof_expr %destructor { expr_free($$); } primary_expr shift_expr and_expr typeof_expr %type exclusive_or_expr inclusive_or_expr %destructor { expr_free($$); } exclusive_or_expr inclusive_or_expr %type basic_expr %destructor { expr_free($$); } basic_expr %type set_ref_expr set_ref_symbol_expr %destructor { expr_free($$); } set_ref_expr set_ref_symbol_expr %type multiton_rhs_expr %destructor { expr_free($$); } multiton_rhs_expr %type prefix_rhs_expr range_rhs_expr %destructor { expr_free($$); } prefix_rhs_expr range_rhs_expr %type stmt_expr concat_stmt_expr map_stmt_expr map_stmt_expr_set %destructor { expr_free($$); } stmt_expr concat_stmt_expr map_stmt_expr map_stmt_expr_set %type multiton_stmt_expr %destructor { expr_free($$); } multiton_stmt_expr %type prefix_stmt_expr range_stmt_expr wildcard_expr %destructor { expr_free($$); } prefix_stmt_expr range_stmt_expr wildcard_expr %type primary_stmt_expr basic_stmt_expr %destructor { expr_free($$); } primary_stmt_expr basic_stmt_expr %type list_stmt_expr shift_stmt_expr %destructor { expr_free($$); } list_stmt_expr shift_stmt_expr %type and_stmt_expr exclusive_or_stmt_expr inclusive_or_stmt_expr %destructor { expr_free($$); } and_stmt_expr exclusive_or_stmt_expr inclusive_or_stmt_expr %type concat_expr %destructor { expr_free($$); } concat_expr %type map_expr %destructor { expr_free($$); } map_expr %type verdict_map_stmt %destructor { expr_free($$); } verdict_map_stmt %type verdict_map_expr verdict_map_list_expr verdict_map_list_member_expr %destructor { expr_free($$); } verdict_map_expr verdict_map_list_expr verdict_map_list_member_expr %type set_expr set_block_expr set_list_expr set_list_member_expr flowtable_expr flowtable_list_expr flowtable_expr_member %destructor { expr_free($$); } set_expr set_block_expr set_list_expr set_list_member_expr flowtable_expr flowtable_list_expr flowtable_expr_member %type set_elem_expr set_elem_expr_alloc set_lhs_expr set_rhs_expr %destructor { expr_free($$); } set_elem_expr set_elem_expr_alloc set_lhs_expr set_rhs_expr %type set_elem_expr_stmt set_elem_expr_stmt_alloc %destructor { expr_free($$); } set_elem_expr_stmt set_elem_expr_stmt_alloc %type meter_key_expr meter_key_expr_alloc %destructor { expr_free($$); } meter_key_expr meter_key_expr_alloc %type expr initializer_expr keyword_expr %destructor { expr_free($$); } expr initializer_expr keyword_expr %type rhs_expr concat_rhs_expr basic_rhs_expr %destructor { expr_free($$); } rhs_expr concat_rhs_expr basic_rhs_expr %type primary_rhs_expr list_rhs_expr shift_rhs_expr symbol_stmt_expr %destructor { expr_free($$); } primary_rhs_expr list_rhs_expr shift_rhs_expr symbol_stmt_expr %type and_rhs_expr exclusive_or_rhs_expr inclusive_or_rhs_expr %destructor { expr_free($$); } and_rhs_expr exclusive_or_rhs_expr inclusive_or_rhs_expr %type counter_obj quota_obj ct_obj_alloc limit_obj secmark_obj synproxy_obj %destructor { obj_free($$); } counter_obj quota_obj ct_obj_alloc limit_obj secmark_obj synproxy_obj %type relational_expr %destructor { expr_free($$); } relational_expr %type relational_op %type payload_expr payload_raw_expr %destructor { expr_free($$); } payload_expr payload_raw_expr %type payload_base_spec %type eth_hdr_expr vlan_hdr_expr %destructor { expr_free($$); } eth_hdr_expr vlan_hdr_expr %type eth_hdr_field vlan_hdr_field %type arp_hdr_expr %destructor { expr_free($$); } arp_hdr_expr %type arp_hdr_field %type ip_hdr_expr icmp_hdr_expr igmp_hdr_expr numgen_expr hash_expr %destructor { expr_free($$); } ip_hdr_expr icmp_hdr_expr igmp_hdr_expr numgen_expr hash_expr %type ip_hdr_field icmp_hdr_field igmp_hdr_field %type ip_option_type ip_option_field %type ip6_hdr_expr icmp6_hdr_expr %destructor { expr_free($$); } ip6_hdr_expr icmp6_hdr_expr %type ip6_hdr_field icmp6_hdr_field %type auth_hdr_expr esp_hdr_expr comp_hdr_expr %destructor { expr_free($$); } auth_hdr_expr esp_hdr_expr comp_hdr_expr %type auth_hdr_field esp_hdr_field comp_hdr_field %type udp_hdr_expr udplite_hdr_expr %destructor { expr_free($$); } udp_hdr_expr udplite_hdr_expr %type udp_hdr_field udplite_hdr_field %type dccp_hdr_expr sctp_hdr_expr %destructor { expr_free($$); } dccp_hdr_expr sctp_hdr_expr %type dccp_hdr_field sctp_hdr_field %type th_hdr_expr %destructor { expr_free($$); } th_hdr_expr %type th_hdr_field %type exthdr_expr %destructor { expr_free($$); } exthdr_expr %type hbh_hdr_expr frag_hdr_expr dst_hdr_expr %destructor { expr_free($$); } hbh_hdr_expr frag_hdr_expr dst_hdr_expr %type hbh_hdr_field frag_hdr_field dst_hdr_field %type rt_hdr_expr rt0_hdr_expr rt2_hdr_expr rt4_hdr_expr %destructor { expr_free($$); } rt_hdr_expr rt0_hdr_expr rt2_hdr_expr rt4_hdr_expr %type rt_hdr_field rt0_hdr_field rt2_hdr_field rt4_hdr_field %type mh_hdr_expr %destructor { expr_free($$); } mh_hdr_expr %type mh_hdr_field %type meta_expr %destructor { expr_free($$); } meta_expr %type meta_key meta_key_qualified meta_key_unqualified numgen_type %type socket_expr %destructor { expr_free($$); } socket_expr %type socket_key %type nf_key_proto %type rt_expr %destructor { expr_free($$); } rt_expr %type rt_key %type ct_expr %destructor { expr_free($$); } ct_expr %type ct_key ct_dir ct_key_dir_optional ct_key_dir ct_key_proto_field %type fib_expr %destructor { expr_free($$); } fib_expr %type fib_tuple fib_result fib_flag %type osf_expr %type osf_ttl %destructor { expr_free($$); } osf_expr %type markup_format %type monitor_event %destructor { xfree($$); } monitor_event %type monitor_object monitor_format %type synproxy_ts synproxy_sack %type tcp_hdr_expr %destructor { expr_free($$); } tcp_hdr_expr %type tcp_hdr_field %type tcp_hdr_option_type tcp_hdr_option_field %type boolean_expr %destructor { expr_free($$); } boolean_expr %type boolean_keys %type exthdr_exists_expr %destructor { expr_free($$); } exthdr_exists_expr %type exthdr_key %type ct_l4protoname ct_obj_type %type timeout_states timeout_state %destructor { xfree($$); } timeout_states timeout_state %type xfrm_state_key xfrm_state_proto_key xfrm_dir xfrm_spnum %type xfrm_expr %destructor { expr_free($$); } xfrm_expr %% input : /* empty */ | input line { if ($2 != NULL) { $2->location = @2; list_add_tail(&$2->list, state->cmds); } } ; stmt_separator : NEWLINE | SEMICOLON ; opt_newline : NEWLINE | /* empty */ ; common_block : INCLUDE QUOTED_STRING stmt_separator { if (scanner_include_file(nft, scanner, $2, &@$) < 0) { xfree($2); YYERROR; } xfree($2); } | DEFINE identifier '=' initializer_expr stmt_separator { struct scope *scope = current_scope(state); if (symbol_lookup(scope, $2) != NULL) { erec_queue(error(&@2, "redefinition of symbol '%s'", $2), state->msgs); xfree($2); YYERROR; } symbol_bind(scope, $2, $4); xfree($2); } | REDEFINE identifier '=' initializer_expr stmt_separator { struct scope *scope = current_scope(state); symbol_bind(scope, $2, $4); xfree($2); } | UNDEFINE identifier stmt_separator { struct scope *scope = current_scope(state); if (symbol_unbind(scope, $2) < 0) { erec_queue(error(&@2, "undefined symbol '%s'", $2), state->msgs); YYERROR; } xfree($2); } | error stmt_separator { if (++state->nerrs == nft->parser_max_errors) YYABORT; yyerrok; } ; line : common_block { $$ = NULL; } | stmt_separator { $$ = NULL; } | base_cmd stmt_separator { $$ = $1; } | base_cmd TOKEN_EOF { /* * Very hackish workaround for bison >= 2.4: previous versions * terminated parsing after EOF, 2.4+ tries to get further input * in 'input' and calls the scanner again, causing a crash when * the final input buffer has been popped. Terminate manually to * avoid this. The correct fix should be to adjust the grammar * to accept EOF in input, but for unknown reasons it does not * work. */ if ($1 != NULL) { $1->location = @1; list_add_tail(&$1->list, state->cmds); } $$ = NULL; YYACCEPT; } ; base_cmd : /* empty */ add_cmd { $$ = $1; } | ADD add_cmd { $$ = $2; } | REPLACE replace_cmd { $$ = $2; } | CREATE create_cmd { $$ = $2; } | INSERT insert_cmd { $$ = $2; } | DELETE delete_cmd { $$ = $2; } | GET get_cmd { $$ = $2; } | LIST list_cmd { $$ = $2; } | RESET reset_cmd { $$ = $2; } | FLUSH flush_cmd { $$ = $2; } | RENAME rename_cmd { $$ = $2; } | IMPORT import_cmd { $$ = $2; } | EXPORT export_cmd { $$ = $2; } | MONITOR monitor_cmd { $$ = $2; } | DESCRIBE describe_cmd { $$ = $2; } ; add_cmd : TABLE table_spec { $$ = cmd_alloc(CMD_ADD, CMD_OBJ_TABLE, &$2, &@$, NULL); } | TABLE table_spec table_block_alloc '{' table_block '}' { handle_merge(&$3->handle, &$2); close_scope(state); $$ = cmd_alloc(CMD_ADD, CMD_OBJ_TABLE, &$2, &@$, $5); } | CHAIN chain_spec { $$ = cmd_alloc(CMD_ADD, CMD_OBJ_CHAIN, &$2, &@$, NULL); } | CHAIN chain_spec chain_block_alloc '{' chain_block '}' { $5->location = @5; handle_merge(&$3->handle, &$2); close_scope(state); $$ = cmd_alloc(CMD_ADD, CMD_OBJ_CHAIN, &$2, &@$, $5); } | RULE rule_position rule { $$ = cmd_alloc(CMD_ADD, CMD_OBJ_RULE, &$2, &@$, $3); } | /* empty */ rule_position rule { $$ = cmd_alloc(CMD_ADD, CMD_OBJ_RULE, &$1, &@$, $2); } | SET set_spec set_block_alloc '{' set_block '}' { $5->location = @5; handle_merge(&$3->handle, &$2); $$ = cmd_alloc(CMD_ADD, CMD_OBJ_SET, &$2, &@$, $5); } | MAP set_spec map_block_alloc '{' map_block '}' { $5->location = @5; handle_merge(&$3->handle, &$2); $$ = cmd_alloc(CMD_ADD, CMD_OBJ_SET, &$2, &@$, $5); } | ELEMENT set_spec set_block_expr { $$ = cmd_alloc(CMD_ADD, CMD_OBJ_SETELEM, &$2, &@$, $3); } | FLOWTABLE flowtable_spec flowtable_block_alloc '{' flowtable_block '}' { $5->location = @5; handle_merge(&$3->handle, &$2); $$ = cmd_alloc(CMD_ADD, CMD_OBJ_FLOWTABLE, &$2, &@$, $5); } | COUNTER obj_spec { struct obj *obj; obj = obj_alloc(&@$); obj->type = NFT_OBJECT_COUNTER; handle_merge(&obj->handle, &$2); $$ = cmd_alloc(CMD_ADD, CMD_OBJ_COUNTER, &$2, &@$, obj); } | COUNTER obj_spec counter_obj counter_config { $$ = cmd_alloc(CMD_ADD, CMD_OBJ_COUNTER, &$2, &@$, $3); } | QUOTA obj_spec quota_obj quota_config { $$ = cmd_alloc(CMD_ADD, CMD_OBJ_QUOTA, &$2, &@$, $3); } | CT HELPER obj_spec ct_obj_alloc '{' ct_helper_block '}' { $$ = cmd_alloc_obj_ct(CMD_ADD, NFT_OBJECT_CT_HELPER, &$3, &@$, $4); } | CT TIMEOUT obj_spec ct_obj_alloc '{' ct_timeout_block '}' { $$ = cmd_alloc_obj_ct(CMD_ADD, NFT_OBJECT_CT_TIMEOUT, &$3, &@$, $4); } | CT EXPECTATION obj_spec ct_obj_alloc '{' ct_expect_block '}' { $$ = cmd_alloc_obj_ct(CMD_ADD, NFT_OBJECT_CT_EXPECT, &$3, &@$, $4); } | LIMIT obj_spec limit_obj limit_config { $$ = cmd_alloc(CMD_ADD, CMD_OBJ_LIMIT, &$2, &@$, $3); } | SECMARK obj_spec secmark_obj secmark_config { $$ = cmd_alloc(CMD_ADD, CMD_OBJ_SECMARK, &$2, &@$, $3); } | SYNPROXY obj_spec synproxy_obj synproxy_config { $$ = cmd_alloc(CMD_ADD, CMD_OBJ_SYNPROXY, &$2, &@$, $3); } ; replace_cmd : RULE ruleid_spec rule { $$ = cmd_alloc(CMD_REPLACE, CMD_OBJ_RULE, &$2, &@$, $3); } ; create_cmd : TABLE table_spec { $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_TABLE, &$2, &@$, NULL); } | TABLE table_spec table_block_alloc '{' table_block '}' { handle_merge(&$3->handle, &$2); close_scope(state); $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_TABLE, &$2, &@$, $5); } | CHAIN chain_spec { $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_CHAIN, &$2, &@$, NULL); } | CHAIN chain_spec chain_block_alloc '{' chain_block '}' { $5->location = @5; handle_merge(&$3->handle, &$2); close_scope(state); $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_CHAIN, &$2, &@$, $5); } | SET set_spec set_block_alloc '{' set_block '}' { $5->location = @5; handle_merge(&$3->handle, &$2); $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_SET, &$2, &@$, $5); } | MAP set_spec map_block_alloc '{' map_block '}' { $5->location = @5; handle_merge(&$3->handle, &$2); $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_SET, &$2, &@$, $5); } | ELEMENT set_spec set_block_expr { $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_SETELEM, &$2, &@$, $3); } | FLOWTABLE flowtable_spec flowtable_block_alloc '{' flowtable_block '}' { $5->location = @5; handle_merge(&$3->handle, &$2); $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_FLOWTABLE, &$2, &@$, $5); } | COUNTER obj_spec { struct obj *obj; obj = obj_alloc(&@$); obj->type = NFT_OBJECT_COUNTER; handle_merge(&obj->handle, &$2); $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_COUNTER, &$2, &@$, obj); } | COUNTER obj_spec counter_obj counter_config { $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_COUNTER, &$2, &@$, $3); } | QUOTA obj_spec quota_obj quota_config { $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_QUOTA, &$2, &@$, $3); } | CT HELPER obj_spec ct_obj_alloc '{' ct_helper_block '}' { $$ = cmd_alloc_obj_ct(CMD_CREATE, NFT_OBJECT_CT_HELPER, &$3, &@$, $4); } | CT TIMEOUT obj_spec ct_obj_alloc '{' ct_timeout_block '}' { $$ = cmd_alloc_obj_ct(CMD_CREATE, NFT_OBJECT_CT_TIMEOUT, &$3, &@$, $4); } | CT EXPECTATION obj_spec ct_obj_alloc '{' ct_expect_block '}' { $$ = cmd_alloc_obj_ct(CMD_CREATE, NFT_OBJECT_CT_EXPECT, &$3, &@$, $4); } | LIMIT obj_spec limit_obj limit_config { $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_LIMIT, &$2, &@$, $3); } | SECMARK obj_spec secmark_obj secmark_config { $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_SECMARK, &$2, &@$, $3); } | SYNPROXY obj_spec synproxy_obj synproxy_config { $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_SYNPROXY, &$2, &@$, $3); } ; insert_cmd : RULE rule_position rule { $$ = cmd_alloc(CMD_INSERT, CMD_OBJ_RULE, &$2, &@$, $3); } ; delete_cmd : TABLE table_spec { $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_TABLE, &$2, &@$, NULL); } | TABLE tableid_spec { $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_TABLE, &$2, &@$, NULL); } | CHAIN chain_spec { $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_CHAIN, &$2, &@$, NULL); } | CHAIN chainid_spec { $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_CHAIN, &$2, &@$, NULL); } | RULE ruleid_spec { $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_RULE, &$2, &@$, NULL); } | SET set_spec { $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_SET, &$2, &@$, NULL); } | SET setid_spec { $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_SET, &$2, &@$, NULL); } | MAP set_spec { $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_SET, &$2, &@$, NULL); } | ELEMENT set_spec set_block_expr { $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_SETELEM, &$2, &@$, $3); } | FLOWTABLE flowtable_spec { $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_FLOWTABLE, &$2, &@$, NULL); } | FLOWTABLE flowtableid_spec { $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_FLOWTABLE, &$2, &@$, NULL); } | COUNTER obj_spec { $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_COUNTER, &$2, &@$, NULL); } | COUNTER objid_spec { $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_COUNTER, &$2, &@$, NULL); } | QUOTA obj_spec { $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_QUOTA, &$2, &@$, NULL); } | QUOTA objid_spec { $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_QUOTA, &$2, &@$, NULL); } | CT ct_obj_type obj_spec ct_obj_alloc { $$ = cmd_alloc_obj_ct(CMD_DELETE, $2, &$3, &@$, $4); } | LIMIT obj_spec { $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_LIMIT, &$2, &@$, NULL); } | LIMIT objid_spec { $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_LIMIT, &$2, &@$, NULL); } | SECMARK obj_spec { $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_SECMARK, &$2, &@$, NULL); } | SECMARK objid_spec { $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_SECMARK, &$2, &@$, NULL); } | SYNPROXY obj_spec { $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_SYNPROXY, &$2, &@$, NULL); } | SYNPROXY objid_spec { $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_SYNPROXY, &$2, &@$, NULL); } ; get_cmd : ELEMENT set_spec set_block_expr { $$ = cmd_alloc(CMD_GET, CMD_OBJ_SETELEM, &$2, &@$, $3); } ; list_cmd : TABLE table_spec { $$ = cmd_alloc(CMD_LIST, CMD_OBJ_TABLE, &$2, &@$, NULL); } | TABLES ruleset_spec { $$ = cmd_alloc(CMD_LIST, CMD_OBJ_TABLE, &$2, &@$, NULL); } | CHAIN chain_spec { $$ = cmd_alloc(CMD_LIST, CMD_OBJ_CHAIN, &$2, &@$, NULL); } | CHAINS ruleset_spec { $$ = cmd_alloc(CMD_LIST, CMD_OBJ_CHAINS, &$2, &@$, NULL); } | SETS ruleset_spec { $$ = cmd_alloc(CMD_LIST, CMD_OBJ_SETS, &$2, &@$, NULL); } | SETS TABLE table_spec { $$ = cmd_alloc(CMD_LIST, CMD_OBJ_SETS, &$3, &@$, NULL); } | SET set_spec { $$ = cmd_alloc(CMD_LIST, CMD_OBJ_SET, &$2, &@$, NULL); } | COUNTERS ruleset_spec { $$ = cmd_alloc(CMD_LIST, CMD_OBJ_COUNTERS, &$2, &@$, NULL); } | COUNTERS TABLE table_spec { $$ = cmd_alloc(CMD_LIST, CMD_OBJ_COUNTERS, &$3, &@$, NULL); } | COUNTER obj_spec { $$ = cmd_alloc(CMD_LIST, CMD_OBJ_COUNTER, &$2, &@$, NULL); } | QUOTAS ruleset_spec { $$ = cmd_alloc(CMD_LIST, CMD_OBJ_QUOTAS, &$2, &@$, NULL); } | QUOTAS TABLE table_spec { $$ = cmd_alloc(CMD_LIST, CMD_OBJ_QUOTAS, &$3, &@$, NULL); } | QUOTA obj_spec { $$ = cmd_alloc(CMD_LIST, CMD_OBJ_QUOTA, &$2, &@$, NULL); } | LIMITS ruleset_spec { $$ = cmd_alloc(CMD_LIST, CMD_OBJ_LIMITS, &$2, &@$, NULL); } | LIMITS TABLE table_spec { $$ = cmd_alloc(CMD_LIST, CMD_OBJ_LIMITS, &$3, &@$, NULL); } | LIMIT obj_spec { $$ = cmd_alloc(CMD_LIST, CMD_OBJ_LIMIT, &$2, &@$, NULL); } | SECMARKS ruleset_spec { $$ = cmd_alloc(CMD_LIST, CMD_OBJ_SECMARKS, &$2, &@$, NULL); } | SECMARKS TABLE table_spec { $$ = cmd_alloc(CMD_LIST, CMD_OBJ_SECMARKS, &$3, &@$, NULL); } | SECMARK obj_spec { $$ = cmd_alloc(CMD_LIST, CMD_OBJ_SECMARK, &$2, &@$, NULL); } | SYNPROXYS ruleset_spec { $$ = cmd_alloc(CMD_LIST, CMD_OBJ_SYNPROXYS, &$2, &@$, NULL); } | SYNPROXYS TABLE table_spec { $$ = cmd_alloc(CMD_LIST, CMD_OBJ_SYNPROXYS, &$3, &@$, NULL); } | SYNPROXY obj_spec { $$ = cmd_alloc(CMD_LIST, CMD_OBJ_SYNPROXY, &$2, &@$, NULL); } | RULESET ruleset_spec { $$ = cmd_alloc(CMD_LIST, CMD_OBJ_RULESET, &$2, &@$, NULL); } | FLOW TABLES ruleset_spec { $$ = cmd_alloc(CMD_LIST, CMD_OBJ_METERS, &$3, &@$, NULL); } | FLOW TABLE set_spec { $$ = cmd_alloc(CMD_LIST, CMD_OBJ_METER, &$3, &@$, NULL); } | METERS ruleset_spec { $$ = cmd_alloc(CMD_LIST, CMD_OBJ_METERS, &$2, &@$, NULL); } | METER set_spec { $$ = cmd_alloc(CMD_LIST, CMD_OBJ_METER, &$2, &@$, NULL); } | FLOWTABLES ruleset_spec { $$ = cmd_alloc(CMD_LIST, CMD_OBJ_FLOWTABLES, &$2, &@$, NULL); } | FLOWTABLE flowtable_spec { $$ = cmd_alloc(CMD_LIST, CMD_OBJ_FLOWTABLE, &$2, &@$, NULL); } | MAPS ruleset_spec { $$ = cmd_alloc(CMD_LIST, CMD_OBJ_MAPS, &$2, &@$, NULL); } | MAP set_spec { $$ = cmd_alloc(CMD_LIST, CMD_OBJ_MAP, &$2, &@$, NULL); } | CT ct_obj_type obj_spec { $$ = cmd_alloc_obj_ct(CMD_LIST, $2, &$3, &@$, NULL); } | CT HELPERS TABLE table_spec { $$ = cmd_alloc(CMD_LIST, CMD_OBJ_CT_HELPERS, &$4, &@$, NULL); } | CT TIMEOUT TABLE table_spec { $$ = cmd_alloc(CMD_LIST, CMD_OBJ_CT_TIMEOUT, &$4, &@$, NULL); } | CT EXPECTATION TABLE table_spec { $$ = cmd_alloc(CMD_LIST, CMD_OBJ_CT_EXPECT, &$4, &@$, NULL); } ; reset_cmd : COUNTERS ruleset_spec { $$ = cmd_alloc(CMD_RESET, CMD_OBJ_COUNTERS, &$2, &@$, NULL); } | COUNTERS TABLE table_spec { $$ = cmd_alloc(CMD_RESET, CMD_OBJ_COUNTERS, &$3, &@$, NULL); } | COUNTER obj_spec { $$ = cmd_alloc(CMD_RESET, CMD_OBJ_COUNTER, &$2,&@$, NULL); } | QUOTAS ruleset_spec { $$ = cmd_alloc(CMD_RESET, CMD_OBJ_QUOTAS, &$2, &@$, NULL); } | QUOTAS TABLE table_spec { $$ = cmd_alloc(CMD_RESET, CMD_OBJ_QUOTAS, &$3, &@$, NULL); } | QUOTA obj_spec { $$ = cmd_alloc(CMD_RESET, CMD_OBJ_QUOTA, &$2, &@$, NULL); } ; flush_cmd : TABLE table_spec { $$ = cmd_alloc(CMD_FLUSH, CMD_OBJ_TABLE, &$2, &@$, NULL); } | CHAIN chain_spec { $$ = cmd_alloc(CMD_FLUSH, CMD_OBJ_CHAIN, &$2, &@$, NULL); } | SET set_spec { $$ = cmd_alloc(CMD_FLUSH, CMD_OBJ_SET, &$2, &@$, NULL); } | MAP set_spec { $$ = cmd_alloc(CMD_FLUSH, CMD_OBJ_MAP, &$2, &@$, NULL); } | FLOW TABLE set_spec { $$ = cmd_alloc(CMD_FLUSH, CMD_OBJ_METER, &$3, &@$, NULL); } | METER set_spec { $$ = cmd_alloc(CMD_FLUSH, CMD_OBJ_METER, &$2, &@$, NULL); } | RULESET ruleset_spec { $$ = cmd_alloc(CMD_FLUSH, CMD_OBJ_RULESET, &$2, &@$, NULL); } ; rename_cmd : CHAIN chain_spec identifier { $$ = cmd_alloc(CMD_RENAME, CMD_OBJ_CHAIN, &$2, &@$, NULL); $$->arg = $3; } ; import_cmd : RULESET markup_format { struct handle h = { .family = NFPROTO_UNSPEC }; struct markup *markup = markup_alloc($2); $$ = cmd_alloc(CMD_IMPORT, CMD_OBJ_MARKUP, &h, &@$, markup); } | markup_format { struct handle h = { .family = NFPROTO_UNSPEC }; struct markup *markup = markup_alloc($1); $$ = cmd_alloc(CMD_IMPORT, CMD_OBJ_MARKUP, &h, &@$, markup); } ; export_cmd : RULESET markup_format { struct handle h = { .family = NFPROTO_UNSPEC }; struct markup *markup = markup_alloc($2); $$ = cmd_alloc(CMD_EXPORT, CMD_OBJ_MARKUP, &h, &@$, markup); } | markup_format { struct handle h = { .family = NFPROTO_UNSPEC }; struct markup *markup = markup_alloc($1); $$ = cmd_alloc(CMD_EXPORT, CMD_OBJ_MARKUP, &h, &@$, markup); } ; monitor_cmd : monitor_event monitor_object monitor_format { struct handle h = { .family = NFPROTO_UNSPEC }; struct monitor *m = monitor_alloc($3, $2, $1); m->location = @1; $$ = cmd_alloc(CMD_MONITOR, CMD_OBJ_MONITOR, &h, &@$, m); } ; monitor_event : /* empty */ { $$ = NULL; } | STRING { $$ = $1; } ; monitor_object : /* empty */ { $$ = CMD_MONITOR_OBJ_ANY; } | TABLES { $$ = CMD_MONITOR_OBJ_TABLES; } | CHAINS { $$ = CMD_MONITOR_OBJ_CHAINS; } | SETS { $$ = CMD_MONITOR_OBJ_SETS; } | RULES { $$ = CMD_MONITOR_OBJ_RULES; } | ELEMENTS { $$ = CMD_MONITOR_OBJ_ELEMS; } | RULESET { $$ = CMD_MONITOR_OBJ_RULESET; } | TRACE { $$ = CMD_MONITOR_OBJ_TRACE; } ; monitor_format : /* empty */ { $$ = NFTNL_OUTPUT_DEFAULT; } | markup_format ; markup_format : XML { $$ = __NFT_OUTPUT_NOTSUPP; } | JSON { $$ = NFTNL_OUTPUT_JSON; } | VM JSON { $$ = NFTNL_OUTPUT_JSON; } ; describe_cmd : primary_expr { struct handle h = { .family = NFPROTO_UNSPEC }; $$ = cmd_alloc(CMD_DESCRIBE, CMD_OBJ_EXPR, &h, &@$, NULL); $$->expr = $1; } ; table_block_alloc : /* empty */ { $$ = table_alloc(); open_scope(state, &$$->scope); } ; table_options : FLAGS STRING { if (strcmp($2, "dormant") == 0) { $
0->flags = TABLE_F_DORMANT; xfree($2); } else { erec_queue(error(&@2, "unknown table option %s", $2), state->msgs); xfree($2); YYERROR; } } ; table_block : /* empty */ { $$ = $
-1; } | table_block common_block | table_block stmt_separator | table_block table_options stmt_separator | table_block CHAIN chain_identifier chain_block_alloc '{' chain_block '}' stmt_separator { $4->location = @3; handle_merge(&$4->handle, &$3); handle_free(&$3); close_scope(state); list_add_tail(&$4->list, &$1->chains); $$ = $1; } | table_block SET set_identifier set_block_alloc '{' set_block '}' stmt_separator { $4->location = @3; handle_merge(&$4->handle, &$3); handle_free(&$3); list_add_tail(&$4->list, &$1->sets); $$ = $1; } | table_block MAP set_identifier map_block_alloc '{' map_block '}' stmt_separator { $4->location = @3; handle_merge(&$4->handle, &$3); handle_free(&$3); list_add_tail(&$4->list, &$1->sets); $$ = $1; } | table_block FLOWTABLE flowtable_identifier flowtable_block_alloc '{' flowtable_block '}' stmt_separator { $4->location = @3; handle_merge(&$4->handle, &$3); handle_free(&$3); list_add_tail(&$4->list, &$1->flowtables); $$ = $1; } | table_block COUNTER obj_identifier obj_block_alloc '{' counter_block '}' stmt_separator { $4->location = @3; $4->type = NFT_OBJECT_COUNTER; handle_merge(&$4->handle, &$3); handle_free(&$3); list_add_tail(&$4->list, &$1->objs); $$ = $1; } | table_block QUOTA obj_identifier obj_block_alloc '{' quota_block '}' stmt_separator { $4->location = @3; $4->type = NFT_OBJECT_QUOTA; handle_merge(&$4->handle, &$3); handle_free(&$3); list_add_tail(&$4->list, &$1->objs); $$ = $1; } | table_block CT HELPER obj_identifier obj_block_alloc '{' ct_helper_block '}' stmt_separator { $5->location = @4; $5->type = NFT_OBJECT_CT_HELPER; handle_merge(&$5->handle, &$4); handle_free(&$4); list_add_tail(&$5->list, &$1->objs); $$ = $1; } | table_block CT TIMEOUT obj_identifier obj_block_alloc '{' ct_timeout_block '}' stmt_separator { $5->location = @4; $5->type = NFT_OBJECT_CT_TIMEOUT; handle_merge(&$5->handle, &$4); handle_free(&$4); list_add_tail(&$5->list, &$1->objs); $$ = $1; } | table_block CT EXPECTATION obj_identifier obj_block_alloc '{' ct_expect_block '}' stmt_separator { $5->location = @4; $5->type = NFT_OBJECT_CT_EXPECT; handle_merge(&$5->handle, &$4); handle_free(&$4); list_add_tail(&$5->list, &$1->objs); $$ = $1; } | table_block LIMIT obj_identifier obj_block_alloc '{' limit_block '}' stmt_separator { $4->location = @3; $4->type = NFT_OBJECT_LIMIT; handle_merge(&$4->handle, &$3); handle_free(&$3); list_add_tail(&$4->list, &$1->objs); $$ = $1; } | table_block SECMARK obj_identifier obj_block_alloc '{' secmark_block '}' stmt_separator { $4->location = @3; $4->type = NFT_OBJECT_SECMARK; handle_merge(&$4->handle, &$3); handle_free(&$3); list_add_tail(&$4->list, &$1->objs); $$ = $1; } | table_block SYNPROXY obj_identifier obj_block_alloc '{' synproxy_block '}' stmt_separator { $4->location = @3; $4->type = NFT_OBJECT_SYNPROXY; handle_merge(&$4->handle, &$3); handle_free(&$3); list_add_tail(&$4->list, &$1->objs); $$ = $1; } ; chain_block_alloc : /* empty */ { $$ = chain_alloc(NULL); open_scope(state, &$$->scope); } ; chain_block : /* empty */ { $$ = $-1; } | chain_block common_block | chain_block stmt_separator | chain_block hook_spec stmt_separator | chain_block policy_spec stmt_separator | chain_block flags_spec stmt_separator | chain_block rule stmt_separator { list_add_tail(&$2->list, &$1->rules); $$ = $1; } ; typeof_expr : primary_expr { if (expr_ops($1)->build_udata == NULL) { erec_queue(error(&@1, "primary expression type '%s' lacks typeof serialization", expr_ops($1)->name), state->msgs); expr_free($1); YYERROR; } $$ = $1; } | typeof_expr DOT primary_expr { struct location rhs[] = { [1] = @2, [2] = @3, }; $$ = handle_concat_expr(&@$, $$, $1, $3, rhs); } ; set_block_alloc : /* empty */ { $$ = set_alloc(NULL); } ; set_block : /* empty */ { $$ = $-1; } | set_block common_block | set_block stmt_separator | set_block TYPE data_type_expr stmt_separator { $1->key = $3; $$ = $1; } | set_block TYPEOF typeof_expr stmt_separator { $1->key = $3; datatype_set($1->key, $3->dtype); $$ = $1; } | set_block FLAGS set_flag_list stmt_separator { $1->flags = $3; $$ = $1; } | set_block TIMEOUT time_spec stmt_separator { $1->timeout = $3; $$ = $1; } | set_block GC_INTERVAL time_spec stmt_separator { $1->gc_int = $3; $$ = $1; } | set_block COUNTER stmt_separator { $1->stmt = counter_stmt_alloc(&@$); $$ = $1; } | set_block ELEMENTS '=' set_block_expr { $1->init = $4; $$ = $1; } | set_block AUTOMERGE { $1->automerge = true; $$ = $1; } | set_block set_mechanism stmt_separator ; set_block_expr : set_expr | variable_expr ; set_flag_list : set_flag_list COMMA set_flag { $$ = $1 | $3; } | set_flag ; set_flag : CONSTANT { $$ = NFT_SET_CONSTANT; } | INTERVAL { $$ = NFT_SET_INTERVAL; } | TIMEOUT { $$ = NFT_SET_TIMEOUT; } | DYNAMIC { $$ = NFT_SET_EVAL; } ; map_block_alloc : /* empty */ { $$ = set_alloc(NULL); } ; map_block : /* empty */ { $$ = $-1; } | map_block common_block | map_block stmt_separator | map_block TIMEOUT time_spec stmt_separator { $1->timeout = $3; $$ = $1; } | map_block TYPE data_type_expr COLON data_type_expr stmt_separator { $1->key = $3; $1->data = $5; $1->flags |= NFT_SET_MAP; $$ = $1; } | map_block TYPEOF typeof_expr COLON typeof_expr stmt_separator { $1->key = $3; datatype_set($1->key, $3->dtype); $1->data = $5; $1->flags |= NFT_SET_MAP; $$ = $1; } | map_block TYPE data_type_expr COLON COUNTER stmt_separator { $1->key = $3; $1->objtype = NFT_OBJECT_COUNTER; $1->flags |= NFT_SET_OBJECT; $$ = $1; } | map_block TYPE data_type_expr COLON QUOTA stmt_separator { $1->key = $3; $1->objtype = NFT_OBJECT_QUOTA; $1->flags |= NFT_SET_OBJECT; $$ = $1; } | map_block TYPE data_type_expr COLON LIMIT stmt_separator { $1->key = $3; $1->objtype = NFT_OBJECT_LIMIT; $1->flags |= NFT_SET_OBJECT; $$ = $1; } | map_block TYPE data_type_expr COLON SECMARK stmt_separator { $1->key = $3; $1->objtype = NFT_OBJECT_SECMARK; $1->flags |= NFT_SET_OBJECT; $$ = $1; } | map_block FLAGS set_flag_list stmt_separator { $1->flags |= $3; $$ = $1; } | map_block ELEMENTS '=' set_block_expr { $1->init = $4; $$ = $1; } | map_block set_mechanism stmt_separator ; set_mechanism : POLICY set_policy_spec { $0->policy = $2; } | SIZE NUM { $0->desc.size = $2; } ; set_policy_spec : PERFORMANCE { $$ = NFT_SET_POL_PERFORMANCE; } | MEMORY { $$ = NFT_SET_POL_MEMORY; } ; flowtable_block_alloc : /* empty */ { $$ = flowtable_alloc(NULL); } ; flowtable_block : /* empty */ { $$ = $-1; } | flowtable_block common_block | flowtable_block stmt_separator | flowtable_block HOOK STRING prio_spec stmt_separator { $$->hook.loc = @3; $$->hook.name = chain_hookname_lookup($3); if ($$->hook.name == NULL) { erec_queue(error(&@3, "unknown chain hook %s", $3), state->msgs); xfree($3); YYERROR; } xfree($3); $$->priority = $4; } | flowtable_block DEVICES '=' flowtable_expr stmt_separator { $$->dev_expr = $4; } | flowtable_block COUNTER { $$->flags |= NFT_FLOWTABLE_COUNTER; } ; flowtable_expr : '{' flowtable_list_expr '}' { $2->location = @$; $$ = $2; } ; flowtable_list_expr : flowtable_expr_member { $$ = compound_expr_alloc(&@$, EXPR_LIST); compound_expr_add($$, $1); } | flowtable_list_expr COMMA flowtable_expr_member { compound_expr_add($1, $3); $$ = $1; } | flowtable_list_expr COMMA opt_newline ; flowtable_expr_member : STRING { $$ = constant_expr_alloc(&@$, &string_type, BYTEORDER_HOST_ENDIAN, strlen($1) * BITS_PER_BYTE, $1); xfree($1); } ; data_type_atom_expr : type_identifier { const struct datatype *dtype = datatype_lookup_byname($1); if (dtype == NULL) { erec_queue(error(&@1, "unknown datatype %s", $1), state->msgs); YYERROR; } $$ = constant_expr_alloc(&@1, dtype, dtype->byteorder, dtype->size, NULL); xfree($1); } | TIME { $$ = constant_expr_alloc(&@1, &time_type, time_type.byteorder, time_type.size, NULL); } ; data_type_expr : data_type_atom_expr | data_type_expr DOT data_type_atom_expr { struct location rhs[] = { [1] = @2, [2] = @3, }; $$ = handle_concat_expr(&@$, $$, $1, $3, rhs); } ; obj_block_alloc : /* empty */ { $$ = obj_alloc(NULL); } ; counter_block : /* empty */ { $$ = $-1; } | counter_block common_block | counter_block stmt_separator | counter_block counter_config { $$ = $1; } ; quota_block : /* empty */ { $$ = $-1; } | quota_block common_block | quota_block stmt_separator | quota_block quota_config { $$ = $1; } ; ct_helper_block : /* empty */ { $$ = $-1; } | ct_helper_block common_block | ct_helper_block stmt_separator | ct_helper_block ct_helper_config { $$ = $1; } ; ct_timeout_block : /*empty */ { $$ = $-1; } | ct_timeout_block common_block | ct_timeout_block stmt_separator | ct_timeout_block ct_timeout_config { $$ = $1; } ; ct_expect_block : /*empty */ { $$ = $-1; } | ct_expect_block common_block | ct_expect_block stmt_separator | ct_expect_block ct_expect_config { $$ = $1; } ; limit_block : /* empty */ { $$ = $-1; } | limit_block common_block | limit_block stmt_separator | limit_block limit_config { $$ = $1; } ; secmark_block : /* empty */ { $$ = $-1; } | secmark_block common_block | secmark_block stmt_separator | secmark_block secmark_config { $$ = $1; } ; synproxy_block : /* empty */ { $$ = $-1; } | synproxy_block common_block | synproxy_block stmt_separator | synproxy_block synproxy_config { $$ = $1; } ; type_identifier : STRING { $$ = $1; } | MARK { $$ = xstrdup("mark"); } | DSCP { $$ = xstrdup("dscp"); } | ECN { $$ = xstrdup("ecn"); } | CLASSID { $$ = xstrdup("classid"); } ; hook_spec : TYPE STRING HOOK STRING dev_spec prio_spec { const char *chain_type = chain_type_name_lookup($2); if (chain_type == NULL) { erec_queue(error(&@2, "unknown chain type %s", $2), state->msgs); xfree($2); YYERROR; } $0->type = xstrdup(chain_type); xfree($2); $0->hook.loc = @4; $0->hook.name = chain_hookname_lookup($4); if ($0->hook.name == NULL) { erec_queue(error(&@4, "unknown chain hook %s", $4), state->msgs); xfree($4); YYERROR; } xfree($4); $0->dev_expr = $5; $0->priority = $6; $0->flags |= CHAIN_F_BASECHAIN; } ; prio_spec : PRIORITY extended_prio_spec { $$ = $2; $$.loc = @$; } ; extended_prio_name : OUT { $$ = strdup("out"); } | STRING ; extended_prio_spec : int_num { struct prio_spec spec = {0}; spec.expr = constant_expr_alloc(&@$, &integer_type, BYTEORDER_HOST_ENDIAN, sizeof(int) * BITS_PER_BYTE, &$1); $$ = spec; } | variable_expr { struct prio_spec spec = {0}; datatype_set($1->sym->expr, &priority_type); spec.expr = $1; $$ = spec; } | extended_prio_name { struct prio_spec spec = {0}; spec.expr = constant_expr_alloc(&@$, &string_type, BYTEORDER_HOST_ENDIAN, strlen($1) * BITS_PER_BYTE, $1); xfree($1); $$ = spec; } | extended_prio_name PLUS NUM { struct prio_spec spec = {0}; char str[NFT_NAME_MAXLEN]; snprintf(str, sizeof(str), "%s + %" PRIu64, $1, $3); spec.expr = constant_expr_alloc(&@$, &string_type, BYTEORDER_HOST_ENDIAN, strlen(str) * BITS_PER_BYTE, str); xfree($1); $$ = spec; } | extended_prio_name DASH NUM { struct prio_spec spec = {0}; char str[NFT_NAME_MAXLEN]; snprintf(str, sizeof(str), "%s - %" PRIu64, $1, $3); spec.expr = constant_expr_alloc(&@$, &string_type, BYTEORDER_HOST_ENDIAN, strlen(str) * BITS_PER_BYTE, str); $$ = spec; } ; int_num : NUM { $$ = $1; } | DASH NUM { $$ = -$2; } ; dev_spec : DEVICE string { struct expr *expr; expr = constant_expr_alloc(&@$, &string_type, BYTEORDER_HOST_ENDIAN, strlen($2) * BITS_PER_BYTE, $2); xfree($2); $$ = compound_expr_alloc(&@$, EXPR_LIST); compound_expr_add($$, expr); } | DEVICES '=' flowtable_expr { $$ = $3; } | /* empty */ { $$ = NULL; } ; flags_spec : FLAGS OFFLOAD { $0->flags |= CHAIN_F_HW_OFFLOAD; } ; policy_spec : POLICY policy_expr { if ($0->policy) { erec_queue(error(&@$, "you cannot set chain policy twice"), state->msgs); expr_free($2); YYERROR; } $0->policy = $2; $0->policy->location = @$; } ; policy_expr : variable_expr { datatype_set($1->sym->expr, &policy_type); $$ = $1; } | chain_policy { $$ = constant_expr_alloc(&@$, &integer_type, BYTEORDER_HOST_ENDIAN, sizeof(int) * BITS_PER_BYTE, &$1); } ; chain_policy : ACCEPT { $$ = NF_ACCEPT; } | DROP { $$ = NF_DROP; } ; identifier : STRING ; string : STRING | QUOTED_STRING | ASTERISK_STRING ; time_spec : STRING { struct error_record *erec; uint64_t res; erec = time_parse(&@1, $1, &res); xfree($1); if (erec != NULL) { erec_queue(erec, state->msgs); YYERROR; } $$ = res; } ; family_spec : /* empty */ { $$ = NFPROTO_IPV4; } | family_spec_explicit ; family_spec_explicit : IP { $$ = NFPROTO_IPV4; } | IP6 { $$ = NFPROTO_IPV6; } | INET { $$ = NFPROTO_INET; } | ARP { $$ = NFPROTO_ARP; } | BRIDGE { $$ = NFPROTO_BRIDGE; } | NETDEV { $$ = NFPROTO_NETDEV; } ; table_spec : family_spec identifier { memset(&$$, 0, sizeof($$)); $$.family = $1; $$.table.location = @2; $$.table.name = $2; } ; tableid_spec : family_spec HANDLE NUM { memset(&$$, 0, sizeof($$)); $$.family = $1; $$.handle.id = $3; $$.handle.location = @3; } ; chain_spec : table_spec identifier { $$ = $1; $$.chain.name = $2; $$.chain.location = @2; } ; chainid_spec : table_spec HANDLE NUM { $$ = $1; $$.handle.location = @3; $$.handle.id = $3; } ; chain_identifier : identifier { memset(&$$, 0, sizeof($$)); $$.chain.name = $1; $$.chain.location = @1; } ; set_spec : table_spec identifier { $$ = $1; $$.set.name = $2; $$.set.location = @2; } ; setid_spec : table_spec HANDLE NUM { $$ = $1; $$.handle.location = @3; $$.handle.id = $3; } ; set_identifier : identifier { memset(&$$, 0, sizeof($$)); $$.set.name = $1; $$.set.location = @1; } ; flowtable_spec : table_spec identifier { $$ = $1; $$.flowtable.name = $2; $$.flowtable.location = @2; } ; flowtableid_spec : table_spec HANDLE NUM { $$ = $1; $$.handle.location = @3; $$.handle.id = $3; } ; flowtable_identifier : identifier { memset(&$$, 0, sizeof($$)); $$.flowtable.name = $1; $$.flowtable.location = @1; } ; obj_spec : table_spec identifier { $$ = $1; $$.obj.name = $2; $$.obj.location = @2; } ; objid_spec : table_spec HANDLE NUM { $$ = $1; $$.handle.location = @3; $$.handle.id = $3; } ; obj_identifier : identifier { memset(&$$, 0, sizeof($$)); $$.obj.name = $1; $$.obj.location = @1; } ; handle_spec : HANDLE NUM { memset(&$$, 0, sizeof($$)); $$.handle.location = @2; $$.handle.id = $2; } ; position_spec : POSITION NUM { memset(&$$, 0, sizeof($$)); $$.position.location = @$; $$.position.id = $2; } ; index_spec : INDEX NUM { memset(&$$, 0, sizeof($$)); $$.index.location = @$; $$.index.id = $2 + 1; } ; rule_position : chain_spec { $$ = $1; } | chain_spec position_spec { handle_merge(&$1, &$2); $$ = $1; } | chain_spec handle_spec { $2.position.location = $2.handle.location; $2.position.id = $2.handle.id; $2.handle.id = 0; handle_merge(&$1, &$2); $$ = $1; } | chain_spec index_spec { handle_merge(&$1, &$2); $$ = $1; } ; ruleid_spec : chain_spec handle_spec { handle_merge(&$1, &$2); $$ = $1; } ; comment_spec : COMMENT string { if (strlen($2) > NFTNL_UDATA_COMMENT_MAXLEN) { erec_queue(error(&@2, "comment too long, %d characters maximum allowed", NFTNL_UDATA_COMMENT_MAXLEN), state->msgs); YYERROR; } $$ = $2; } ; ruleset_spec : /* empty */ { memset(&$$, 0, sizeof($$)); $$.family = NFPROTO_UNSPEC; } | family_spec_explicit { memset(&$$, 0, sizeof($$)); $$.family = $1; } ; rule : rule_alloc { $$->comment = NULL; } | rule_alloc comment_spec { $$->comment = $2; } ; rule_alloc : stmt_list { struct stmt *i; $$ = rule_alloc(&@$, NULL); list_for_each_entry(i, $1, list) $$->num_stmts++; list_splice_tail($1, &$$->stmts); xfree($1); } ; stmt_list : stmt { $$ = xmalloc(sizeof(*$$)); init_list_head($$); list_add_tail(&$1->list, $$); } | stmt_list stmt { $$ = $1; list_add_tail(&$2->list, $1); } ; stateful_stmt : counter_stmt | limit_stmt | quota_stmt | connlimit_stmt ; stmt : verdict_stmt | match_stmt | meter_stmt | payload_stmt | stateful_stmt | meta_stmt | log_stmt | reject_stmt | nat_stmt | tproxy_stmt | queue_stmt | ct_stmt | masq_stmt | redir_stmt | dup_stmt | fwd_stmt | set_stmt | map_stmt | synproxy_stmt ; verdict_stmt : verdict_expr { $$ = verdict_stmt_alloc(&@$, $1); } | verdict_map_stmt { $$ = verdict_stmt_alloc(&@$, $1); } ; verdict_map_stmt : concat_expr VMAP verdict_map_expr { $$ = map_expr_alloc(&@$, $1, $3); } ; verdict_map_expr : '{' verdict_map_list_expr '}' { $2->location = @$; $$ = $2; } | set_ref_expr ; verdict_map_list_expr : verdict_map_list_member_expr { $$ = set_expr_alloc(&@$, NULL); compound_expr_add($$, $1); } | verdict_map_list_expr COMMA verdict_map_list_member_expr { compound_expr_add($1, $3); $$ = $1; } | verdict_map_list_expr COMMA opt_newline ; verdict_map_list_member_expr: opt_newline set_elem_expr COLON verdict_expr opt_newline { $$ = mapping_expr_alloc(&@$, $2, $4); } ; connlimit_stmt : CT COUNT NUM { $$ = connlimit_stmt_alloc(&@$); $$->connlimit.count = $3; } | CT COUNT OVER NUM { $$ = connlimit_stmt_alloc(&@$); $$->connlimit.count = $4; $$->connlimit.flags = NFT_CONNLIMIT_F_INV; } ; counter_stmt : counter_stmt_alloc | counter_stmt_alloc counter_args counter_stmt_alloc : COUNTER { $$ = counter_stmt_alloc(&@$); } | COUNTER NAME stmt_expr { $$ = objref_stmt_alloc(&@$); $$->objref.type = NFT_OBJECT_COUNTER; $$->objref.expr = $3; } ; counter_args : counter_arg { $$ = $0; } | counter_args counter_arg ; counter_arg : PACKETS NUM { $0->counter.packets = $2; } | BYTES NUM { $0->counter.bytes = $2; } ; log_stmt : log_stmt_alloc | log_stmt_alloc log_args ; log_stmt_alloc : LOG { $$ = log_stmt_alloc(&@$); } ; log_args : log_arg { $$ = $0; } | log_args log_arg ; log_arg : PREFIX string { $0->log.prefix = $2; $0->log.flags |= STMT_LOG_PREFIX; } | GROUP NUM { $0->log.group = $2; $0->log.flags |= STMT_LOG_GROUP; } | SNAPLEN NUM { $0->log.snaplen = $2; $0->log.flags |= STMT_LOG_SNAPLEN; } | QUEUE_THRESHOLD NUM { $0->log.qthreshold = $2; $0->log.flags |= STMT_LOG_QTHRESHOLD; } | LEVEL level_type { $0->log.level = $2; $0->log.flags |= STMT_LOG_LEVEL; } | FLAGS log_flags { $0->log.logflags |= $2; } ; level_type : string { if (!strcmp("emerg", $1)) $$ = NFT_LOGLEVEL_EMERG; else if (!strcmp("alert", $1)) $$ = NFT_LOGLEVEL_ALERT; else if (!strcmp("crit", $1)) $$ = NFT_LOGLEVEL_CRIT; else if (!strcmp("err", $1)) $$ = NFT_LOGLEVEL_ERR; else if (!strcmp("warn", $1)) $$ = NFT_LOGLEVEL_WARNING; else if (!strcmp("notice", $1)) $$ = NFT_LOGLEVEL_NOTICE; else if (!strcmp("info", $1)) $$ = NFT_LOGLEVEL_INFO; else if (!strcmp("debug", $1)) $$ = NFT_LOGLEVEL_DEBUG; else if (!strcmp("audit", $1)) $$ = NFT_LOGLEVEL_AUDIT; else { erec_queue(error(&@1, "invalid log level"), state->msgs); xfree($1); YYERROR; } xfree($1); } ; log_flags : TCP log_flags_tcp { $$ = $2; } | IP OPTIONS { $$ = NF_LOG_IPOPT; } | SKUID { $$ = NF_LOG_UID; } | ETHER { $$ = NF_LOG_MACDECODE; } | ALL { $$ = NF_LOG_MASK; } ; log_flags_tcp : log_flags_tcp COMMA log_flag_tcp { $$ = $1 | $3; } | log_flag_tcp ; log_flag_tcp : SEQUENCE { $$ = NF_LOG_TCPSEQ; } | OPTIONS { $$ = NF_LOG_TCPOPT; } ; limit_stmt : LIMIT RATE limit_mode NUM SLASH time_unit limit_burst_pkts { $$ = limit_stmt_alloc(&@$); $$->limit.rate = $4; $$->limit.unit = $6; $$->limit.burst = $7; $$->limit.type = NFT_LIMIT_PKTS; $$->limit.flags = $3; } | LIMIT RATE limit_mode NUM STRING limit_burst_bytes { struct error_record *erec; uint64_t rate, unit; erec = rate_parse(&@$, $5, &rate, &unit); xfree($5); if (erec != NULL) { erec_queue(erec, state->msgs); YYERROR; } $$ = limit_stmt_alloc(&@$); $$->limit.rate = rate * $4; $$->limit.unit = unit; $$->limit.burst = $6; $$->limit.type = NFT_LIMIT_PKT_BYTES; $$->limit.flags = $3; } | LIMIT NAME stmt_expr { $$ = objref_stmt_alloc(&@$); $$->objref.type = NFT_OBJECT_LIMIT; $$->objref.expr = $3; } ; quota_mode : OVER { $$ = NFT_QUOTA_F_INV; } | UNTIL { $$ = 0; } | /* empty */ { $$ = 0; } ; quota_unit : BYTES { $$ = xstrdup("bytes"); } | STRING { $$ = $1; } ; quota_used : /* empty */ { $$ = 0; } | USED NUM quota_unit { struct error_record *erec; uint64_t rate; erec = data_unit_parse(&@$, $3, &rate); xfree($3); if (erec != NULL) { erec_queue(erec, state->msgs); YYERROR; } $$ = $2 * rate; } ; quota_stmt : QUOTA quota_mode NUM quota_unit quota_used { struct error_record *erec; uint64_t rate; erec = data_unit_parse(&@$, $4, &rate); xfree($4); if (erec != NULL) { erec_queue(erec, state->msgs); YYERROR; } $$ = quota_stmt_alloc(&@$); $$->quota.bytes = $3 * rate; $$->quota.used = $5; $$->quota.flags = $2; } | QUOTA NAME stmt_expr { $$ = objref_stmt_alloc(&@$); $$->objref.type = NFT_OBJECT_QUOTA; $$->objref.expr = $3; } ; limit_mode : OVER { $$ = NFT_LIMIT_F_INV; } | UNTIL { $$ = 0; } | /* empty */ { $$ = 0; } ; limit_burst_pkts : /* empty */ { $$ = 0; } | BURST NUM PACKETS { $$ = $2; } ; limit_burst_bytes : /* empty */ { $$ = 0; } | BURST NUM BYTES { $$ = $2; } | BURST NUM STRING { struct error_record *erec; uint64_t rate; erec = data_unit_parse(&@$, $3, &rate); xfree($3); if (erec != NULL) { erec_queue(erec, state->msgs); YYERROR; } $$ = $2 * rate; } ; time_unit : SECOND { $$ = 1ULL; } | MINUTE { $$ = 1ULL * 60; } | HOUR { $$ = 1ULL * 60 * 60; } | DAY { $$ = 1ULL * 60 * 60 * 24; } | WEEK { $$ = 1ULL * 60 * 60 * 24 * 7; } ; reject_stmt : reject_stmt_alloc reject_opts ; reject_stmt_alloc : _REJECT { $$ = reject_stmt_alloc(&@$); } ; reject_opts : /* empty */ { $0->reject.type = -1; $0->reject.icmp_code = -1; } | WITH ICMP TYPE STRING { $0->reject.family = NFPROTO_IPV4; $0->reject.type = NFT_REJECT_ICMP_UNREACH; $0->reject.expr = symbol_expr_alloc(&@$, SYMBOL_VALUE, current_scope(state), $4); datatype_set($0->reject.expr, &icmp_code_type); xfree($4); } | WITH ICMP6 TYPE STRING { $0->reject.family = NFPROTO_IPV6; $0->reject.type = NFT_REJECT_ICMP_UNREACH; $0->reject.expr = symbol_expr_alloc(&@$, SYMBOL_VALUE, current_scope(state), $4); datatype_set($0->reject.expr, &icmpv6_code_type); xfree($4); } | WITH ICMPX TYPE STRING { $0->reject.type = NFT_REJECT_ICMPX_UNREACH; $0->reject.expr = symbol_expr_alloc(&@$, SYMBOL_VALUE, current_scope(state), $4); datatype_set($0->reject.expr, &icmpx_code_type); xfree($4); } | WITH TCP RESET { $0->reject.type = NFT_REJECT_TCP_RST; } ; nat_stmt : nat_stmt_alloc nat_stmt_args ; nat_stmt_alloc : SNAT { $$ = nat_stmt_alloc(&@$, NFT_NAT_SNAT); } | DNAT { $$ = nat_stmt_alloc(&@$, NFT_NAT_DNAT); } ; tproxy_stmt : TPROXY TO stmt_expr { $$ = tproxy_stmt_alloc(&@$); $$->tproxy.family = NFPROTO_UNSPEC; $$->tproxy.addr = $3; } | TPROXY nf_key_proto TO stmt_expr { $$ = tproxy_stmt_alloc(&@$); $$->tproxy.family = $2; $$->tproxy.addr = $4; } | TPROXY TO COLON stmt_expr { $$ = tproxy_stmt_alloc(&@$); $$->tproxy.family = NFPROTO_UNSPEC; $$->tproxy.port = $4; } | TPROXY TO stmt_expr COLON stmt_expr { $$ = tproxy_stmt_alloc(&@$); $$->tproxy.family = NFPROTO_UNSPEC; $$->tproxy.addr = $3; $$->tproxy.port = $5; } | TPROXY nf_key_proto TO stmt_expr COLON stmt_expr { $$ = tproxy_stmt_alloc(&@$); $$->tproxy.family = $2; $$->tproxy.addr = $4; $$->tproxy.port = $6; } | TPROXY nf_key_proto TO COLON stmt_expr { $$ = tproxy_stmt_alloc(&@$); $$->tproxy.family = $2; $$->tproxy.port = $5; } ; synproxy_stmt : synproxy_stmt_alloc | synproxy_stmt_alloc synproxy_args ; synproxy_stmt_alloc : SYNPROXY { $$ = synproxy_stmt_alloc(&@$); } | SYNPROXY NAME stmt_expr { $$ = objref_stmt_alloc(&@$); $$->objref.type = NFT_OBJECT_SYNPROXY; $$->objref.expr = $3; } ; synproxy_args : synproxy_arg { $$ = $0; } | synproxy_args synproxy_arg ; synproxy_arg : MSS NUM { $0->synproxy.mss = $2; $0->synproxy.flags |= NF_SYNPROXY_OPT_MSS; } | WSCALE NUM { $0->synproxy.wscale = $2; $0->synproxy.flags |= NF_SYNPROXY_OPT_WSCALE; } | TIMESTAMP { $0->synproxy.flags |= NF_SYNPROXY_OPT_TIMESTAMP; } | SACKPERM { $0->synproxy.flags |= NF_SYNPROXY_OPT_SACK_PERM; } ; synproxy_config : MSS NUM WSCALE NUM synproxy_ts synproxy_sack { struct synproxy *synproxy; uint32_t flags = 0; synproxy = &$0->synproxy; synproxy->mss = $2; flags |= NF_SYNPROXY_OPT_MSS; synproxy->wscale = $4; flags |= NF_SYNPROXY_OPT_WSCALE; if ($5) flags |= $5; if ($6) flags |= $6; synproxy->flags = flags; } | MSS NUM stmt_separator WSCALE NUM stmt_separator synproxy_ts synproxy_sack { struct synproxy *synproxy; uint32_t flags = 0; synproxy = &$0->synproxy; synproxy->mss = $2; flags |= NF_SYNPROXY_OPT_MSS; synproxy->wscale = $5; flags |= NF_SYNPROXY_OPT_WSCALE; if ($7) flags |= $7; if ($8) flags |= $8; synproxy->flags = flags; } ; synproxy_obj : /* empty */ { $$ = obj_alloc(&@$); $$->type = NFT_OBJECT_SYNPROXY; } ; synproxy_ts : /* empty */ { $$ = 0; } | TIMESTAMP { $$ = NF_SYNPROXY_OPT_TIMESTAMP; } ; synproxy_sack : /* empty */ { $$ = 0; } | SACKPERM { $$ = NF_SYNPROXY_OPT_SACK_PERM; } ; primary_stmt_expr : symbol_expr { $$ = $1; } | integer_expr { $$ = $1; } | boolean_expr { $$ = $1; } | meta_expr { $$ = $1; } | rt_expr { $$ = $1; } | ct_expr { $$ = $1; } | numgen_expr { $$ = $1; } | hash_expr { $$ = $1; } | payload_expr { $$ = $1; } | keyword_expr { $$ = $1; } | socket_expr { $$ = $1; } | osf_expr { $$ = $1; } | '(' basic_stmt_expr ')' { $$ = $2; } ; shift_stmt_expr : primary_stmt_expr | shift_stmt_expr LSHIFT primary_stmt_expr { $$ = binop_expr_alloc(&@$, OP_LSHIFT, $1, $3); } | shift_stmt_expr RSHIFT primary_stmt_expr { $$ = binop_expr_alloc(&@$, OP_RSHIFT, $1, $3); } ; and_stmt_expr : shift_stmt_expr | and_stmt_expr AMPERSAND shift_stmt_expr { $$ = binop_expr_alloc(&@$, OP_AND, $1, $3); } ; exclusive_or_stmt_expr : and_stmt_expr | exclusive_or_stmt_expr CARET and_stmt_expr { $$ = binop_expr_alloc(&@$, OP_XOR, $1, $3); } ; inclusive_or_stmt_expr : exclusive_or_stmt_expr | inclusive_or_stmt_expr '|' exclusive_or_stmt_expr { $$ = binop_expr_alloc(&@$, OP_OR, $1, $3); } ; basic_stmt_expr : inclusive_or_stmt_expr ; concat_stmt_expr : basic_stmt_expr | concat_stmt_expr DOT primary_stmt_expr { struct location rhs[] = { [1] = @2, [2] = @3, }; $$ = handle_concat_expr(&@$, $$, $1, $3, rhs); } ; map_stmt_expr_set : set_expr | set_ref_expr ; map_stmt_expr : concat_stmt_expr MAP map_stmt_expr_set { $$ = map_expr_alloc(&@$, $1, $3); } | concat_stmt_expr { $$ = $1; } ; prefix_stmt_expr : basic_stmt_expr SLASH NUM { $$ = prefix_expr_alloc(&@$, $1, $3); } ; range_stmt_expr : basic_stmt_expr DASH basic_stmt_expr { $$ = range_expr_alloc(&@$, $1, $3); } ; wildcard_expr : ASTERISK { struct expr *expr; expr = constant_expr_alloc(&@$, &integer_type, BYTEORDER_HOST_ENDIAN, 0, NULL); $$ = prefix_expr_alloc(&@$, expr, 0); } ; multiton_stmt_expr : prefix_stmt_expr | range_stmt_expr | wildcard_expr ; stmt_expr : map_stmt_expr | multiton_stmt_expr | list_stmt_expr ; nat_stmt_args : stmt_expr { $0->nat.addr = $1; } | TO stmt_expr { $0->nat.addr = $2; } | nf_key_proto TO stmt_expr { $0->nat.family = $1; $0->nat.addr = $3; } | stmt_expr COLON stmt_expr { $0->nat.addr = $1; $0->nat.proto = $3; } | TO stmt_expr COLON stmt_expr { $0->nat.addr = $2; $0->nat.proto = $4; } | nf_key_proto TO stmt_expr COLON stmt_expr { $0->nat.family = $1; $0->nat.addr = $3; $0->nat.proto = $5; } | COLON stmt_expr { $0->nat.proto = $2; } | TO COLON stmt_expr { $0->nat.proto = $3; } | nat_stmt_args nf_nat_flags { $0->nat.flags = $2; } | nf_key_proto ADDR DOT PORT TO stmt_expr { $0->nat.family = $1; $0->nat.addr = $6; $0->nat.ipportmap = true; } ; masq_stmt : masq_stmt_alloc masq_stmt_args | masq_stmt_alloc ; masq_stmt_alloc : MASQUERADE { $$ = nat_stmt_alloc(&@$, NFT_NAT_MASQ); } ; masq_stmt_args : TO COLON stmt_expr { $0->nat.proto = $3; } | TO COLON stmt_expr nf_nat_flags { $0->nat.proto = $3; $0->nat.flags = $4; } | nf_nat_flags { $0->nat.flags = $1; } ; redir_stmt : redir_stmt_alloc redir_stmt_arg | redir_stmt_alloc ; redir_stmt_alloc : REDIRECT { $$ = nat_stmt_alloc(&@$, NFT_NAT_REDIR); } ; redir_stmt_arg : TO stmt_expr { $0->nat.proto = $2; } | TO COLON stmt_expr { $0->nat.proto = $3; } | nf_nat_flags { $0->nat.flags = $1; } | TO stmt_expr nf_nat_flags { $0->nat.proto = $2; $0->nat.flags = $3; } | TO COLON stmt_expr nf_nat_flags { $0->nat.proto = $3; $0->nat.flags = $4; } ; dup_stmt : DUP TO stmt_expr { $$ = dup_stmt_alloc(&@$); $$->dup.to = $3; } | DUP TO stmt_expr DEVICE stmt_expr { $$ = dup_stmt_alloc(&@$); $$->dup.to = $3; $$->dup.dev = $5; } ; fwd_stmt : FWD TO stmt_expr { $$ = fwd_stmt_alloc(&@$); $$->fwd.dev = $3; } | FWD nf_key_proto TO stmt_expr DEVICE stmt_expr { $$ = fwd_stmt_alloc(&@$); $$->fwd.family = $2; $$->fwd.addr = $4; $$->fwd.dev = $6; } ; nf_nat_flags : nf_nat_flag | nf_nat_flags COMMA nf_nat_flag { $$ = $1 | $3; } ; nf_nat_flag : RANDOM { $$ = NF_NAT_RANGE_PROTO_RANDOM; } | FULLY_RANDOM { $$ = NF_NAT_RANGE_PROTO_RANDOM_FULLY; } | PERSISTENT { $$ = NF_NAT_RANGE_PERSISTENT; } ; queue_stmt : queue_stmt_alloc | queue_stmt_alloc queue_stmt_args ; queue_stmt_alloc : QUEUE { $$ = queue_stmt_alloc(&@$); } ; queue_stmt_args : queue_stmt_arg { $$ = $0; } | queue_stmt_args queue_stmt_arg ; queue_stmt_arg : QUEUENUM stmt_expr { $0->queue.queue = $2; $0->queue.queue->location = @$; } | queue_stmt_flags { $0->queue.flags |= $1; } ; queue_stmt_flags : queue_stmt_flag | queue_stmt_flags COMMA queue_stmt_flag { $$ = $1 | $3; } ; queue_stmt_flag : BYPASS { $$ = NFT_QUEUE_FLAG_BYPASS; } | FANOUT { $$ = NFT_QUEUE_FLAG_CPU_FANOUT; } ; set_elem_expr_stmt : set_elem_expr_stmt_alloc | set_elem_expr_stmt_alloc set_elem_options ; set_elem_expr_stmt_alloc: concat_expr { $$ = set_elem_expr_alloc(&@1, $1); } ; set_stmt : SET set_stmt_op set_elem_expr_stmt set_ref_expr { $$ = set_stmt_alloc(&@$); $$->set.op = $2; $$->set.key = $3; $$->set.set = $4; } | set_stmt_op set_ref_expr '{' set_elem_expr_stmt '}' { $$ = set_stmt_alloc(&@$); $$->set.op = $1; $$->set.key = $4; $$->set.set = $2; } | set_stmt_op set_ref_expr '{' set_elem_expr_stmt stateful_stmt '}' { $$ = set_stmt_alloc(&@$); $$->set.op = $1; $$->set.key = $4; $$->set.set = $2; $$->set.stmt = $5; } ; set_stmt_op : ADD { $$ = NFT_DYNSET_OP_ADD; } | UPDATE { $$ = NFT_DYNSET_OP_UPDATE; } | DELETE { $$ = NFT_DYNSET_OP_DELETE; } ; map_stmt : set_stmt_op set_ref_expr '{' set_elem_expr_stmt COLON set_elem_expr_stmt '}' { $$ = map_stmt_alloc(&@$); $$->map.op = $1; $$->map.key = $4; $$->map.data = $6; $$->map.set = $2; } | set_stmt_op set_ref_expr '{' set_elem_expr_stmt stateful_stmt COLON set_elem_expr_stmt '}' { $$ = map_stmt_alloc(&@$); $$->map.op = $1; $$->map.key = $4; $$->map.data = $7; $$->map.stmt = $5; $$->map.set = $2; } ; meter_stmt : flow_stmt_legacy_alloc flow_stmt_opts '{' meter_key_expr stmt '}' { $1->meter.key = $4; $1->meter.stmt = $5; $$->location = @$; $$ = $1; } | meter_stmt_alloc { $$ = $1; } ; flow_stmt_legacy_alloc : FLOW { $$ = meter_stmt_alloc(&@$); } ; flow_stmt_opts : flow_stmt_opt { $$ = $0; } | flow_stmt_opts flow_stmt_opt ; flow_stmt_opt : TABLE identifier { $0->meter.name = $2; } ; meter_stmt_alloc : METER identifier '{' meter_key_expr stmt '}' { $$ = meter_stmt_alloc(&@$); $$->meter.name = $2; $$->meter.size = 0; $$->meter.key = $4; $$->meter.stmt = $5; $$->location = @$; } | METER identifier SIZE NUM '{' meter_key_expr stmt '}' { $$ = meter_stmt_alloc(&@$); $$->meter.name = $2; $$->meter.size = $4; $$->meter.key = $6; $$->meter.stmt = $7; $$->location = @$; } ; match_stmt : relational_expr { $$ = expr_stmt_alloc(&@$, $1); } ; variable_expr : '$' identifier { struct scope *scope = current_scope(state); struct symbol *sym; sym = symbol_get(scope, $2); if (!sym) { sym = symbol_lookup_fuzzy(scope, $2); if (sym) { erec_queue(error(&@2, "unknown identifier '%s'; " "did you mean identifier ā€˜%sā€™?", $2, sym->identifier), state->msgs); } else { erec_queue(error(&@2, "unknown identifier '%s'", $2), state->msgs); } xfree($2); YYERROR; } $$ = variable_expr_alloc(&@$, scope, sym); xfree($2); } ; symbol_expr : variable_expr | string { $$ = symbol_expr_alloc(&@$, SYMBOL_VALUE, current_scope(state), $1); xfree($1); } ; set_ref_expr : set_ref_symbol_expr | variable_expr ; set_ref_symbol_expr : AT identifier { $$ = symbol_expr_alloc(&@$, SYMBOL_SET, current_scope(state), $2); xfree($2); } ; integer_expr : NUM { char str[64]; snprintf(str, sizeof(str), "%" PRIu64, $1); $$ = symbol_expr_alloc(&@$, SYMBOL_VALUE, current_scope(state), str); } ; primary_expr : symbol_expr { $$ = $1; } | integer_expr { $$ = $1; } | payload_expr { $$ = $1; } | exthdr_expr { $$ = $1; } | exthdr_exists_expr { $$ = $1; } | meta_expr { $$ = $1; } | socket_expr { $$ = $1; } | rt_expr { $$ = $1; } | ct_expr { $$ = $1; } | numgen_expr { $$ = $1; } | hash_expr { $$ = $1; } | fib_expr { $$ = $1; } | osf_expr { $$ = $1; } | xfrm_expr { $$ = $1; } | '(' basic_expr ')' { $$ = $2; } ; fib_expr : FIB fib_tuple fib_result { if (($2 & (NFTA_FIB_F_SADDR|NFTA_FIB_F_DADDR)) == 0) { erec_queue(error(&@2, "fib: need either saddr or daddr"), state->msgs); YYERROR; } if (($2 & (NFTA_FIB_F_SADDR|NFTA_FIB_F_DADDR)) == (NFTA_FIB_F_SADDR|NFTA_FIB_F_DADDR)) { erec_queue(error(&@2, "fib: saddr and daddr are mutually exclusive"), state->msgs); YYERROR; } if (($2 & (NFTA_FIB_F_IIF|NFTA_FIB_F_OIF)) == (NFTA_FIB_F_IIF|NFTA_FIB_F_OIF)) { erec_queue(error(&@2, "fib: iif and oif are mutually exclusive"), state->msgs); YYERROR; } $$ = fib_expr_alloc(&@$, $2, $3); } ; fib_result : OIF { $$ =NFT_FIB_RESULT_OIF; } | OIFNAME { $$ =NFT_FIB_RESULT_OIFNAME; } | TYPE { $$ =NFT_FIB_RESULT_ADDRTYPE; } ; fib_flag : SADDR { $$ = NFTA_FIB_F_SADDR; } | DADDR { $$ = NFTA_FIB_F_DADDR; } | MARK { $$ = NFTA_FIB_F_MARK; } | IIF { $$ = NFTA_FIB_F_IIF; } | OIF { $$ = NFTA_FIB_F_OIF; } ; fib_tuple : fib_flag DOT fib_tuple { $$ = $1 | $3; } | fib_flag ; osf_expr : OSF osf_ttl HDRVERSION { $$ = osf_expr_alloc(&@$, $2, NFT_OSF_F_VERSION); } | OSF osf_ttl NAME { $$ = osf_expr_alloc(&@$, $2, 0); } ; osf_ttl : /* empty */ { $$ = NF_OSF_TTL_TRUE; } | TTL STRING { if (!strcmp($2, "loose")) $$ = NF_OSF_TTL_LESS; else if (!strcmp($2, "skip")) $$ = NF_OSF_TTL_NOCHECK; else { erec_queue(error(&@2, "invalid ttl option"), state->msgs); YYERROR; } } ; shift_expr : primary_expr | shift_expr LSHIFT primary_rhs_expr { $$ = binop_expr_alloc(&@$, OP_LSHIFT, $1, $3); } | shift_expr RSHIFT primary_rhs_expr { $$ = binop_expr_alloc(&@$, OP_RSHIFT, $1, $3); } ; and_expr : shift_expr | and_expr AMPERSAND shift_rhs_expr { $$ = binop_expr_alloc(&@$, OP_AND, $1, $3); } ; exclusive_or_expr : and_expr | exclusive_or_expr CARET and_rhs_expr { $$ = binop_expr_alloc(&@$, OP_XOR, $1, $3); } ; inclusive_or_expr : exclusive_or_expr | inclusive_or_expr '|' exclusive_or_rhs_expr { $$ = binop_expr_alloc(&@$, OP_OR, $1, $3); } ; basic_expr : inclusive_or_expr ; concat_expr : basic_expr | concat_expr DOT basic_expr { struct location rhs[] = { [1] = @2, [2] = @3, }; $$ = handle_concat_expr(&@$, $$, $1, $3, rhs); } ; prefix_rhs_expr : basic_rhs_expr SLASH NUM { $$ = prefix_expr_alloc(&@$, $1, $3); } ; range_rhs_expr : basic_rhs_expr DASH basic_rhs_expr { $$ = range_expr_alloc(&@$, $1, $3); } ; multiton_rhs_expr : prefix_rhs_expr | range_rhs_expr ; map_expr : concat_expr MAP rhs_expr { $$ = map_expr_alloc(&@$, $1, $3); } ; expr : concat_expr | set_expr | map_expr ; set_expr : '{' set_list_expr '}' { $2->location = @$; $$ = $2; } ; set_list_expr : set_list_member_expr { $$ = set_expr_alloc(&@$, NULL); compound_expr_add($$, $1); } | set_list_expr COMMA set_list_member_expr { compound_expr_add($1, $3); $$ = $1; } | set_list_expr COMMA opt_newline ; set_list_member_expr : opt_newline set_expr opt_newline { $$ = $2; } | opt_newline set_elem_expr opt_newline { $$ = $2; } | opt_newline set_elem_expr COLON set_rhs_expr opt_newline { $$ = mapping_expr_alloc(&@$, $2, $4); } ; meter_key_expr : meter_key_expr_alloc | meter_key_expr_alloc set_elem_options { $$->location = @$; $$ = $1; } ; meter_key_expr_alloc : concat_expr { $$ = set_elem_expr_alloc(&@1, $1); } ; set_elem_expr : set_elem_expr_alloc | set_elem_expr_alloc set_elem_expr_options ; set_elem_expr_alloc : set_lhs_expr { $$ = set_elem_expr_alloc(&@1, $1); } ; set_elem_options : set_elem_option { $$ = $0; } | set_elem_options set_elem_option ; set_elem_option : TIMEOUT time_spec { $0->timeout = $2; } | EXPIRES time_spec { $0->expiration = $2; } | comment_spec { $0->comment = $1; } ; set_elem_expr_options : set_elem_expr_option { $$ = $0; } | set_elem_expr_options set_elem_expr_option ; set_elem_expr_option : TIMEOUT time_spec { $0->timeout = $2; } | EXPIRES time_spec { $0->expiration = $2; } | COUNTER { $0->stmt = counter_stmt_alloc(&@$); } | COUNTER PACKETS NUM BYTES NUM { struct stmt *stmt; stmt = counter_stmt_alloc(&@$); stmt->counter.packets = $3; stmt->counter.bytes = $5; $0->stmt = stmt; } | comment_spec { $0->comment = $1; } ; set_lhs_expr : concat_rhs_expr | wildcard_expr ; set_rhs_expr : concat_rhs_expr | verdict_expr ; initializer_expr : rhs_expr | list_rhs_expr ; counter_config : PACKETS NUM BYTES NUM { struct counter *counter; counter = &$0->counter; counter->packets = $2; counter->bytes = $4; } ; counter_obj : /* empty */ { $$ = obj_alloc(&@$); $$->type = NFT_OBJECT_COUNTER; } ; quota_config : quota_mode NUM quota_unit quota_used { struct error_record *erec; struct quota *quota; uint64_t rate; erec = data_unit_parse(&@$, $3, &rate); xfree($3); if (erec != NULL) { erec_queue(erec, state->msgs); YYERROR; } quota = &$0->quota; quota->bytes = $2 * rate; quota->used = $4; quota->flags = $1; } ; quota_obj : /* empty */ { $$ = obj_alloc(&@$); $$->type = NFT_OBJECT_QUOTA; } ; secmark_config : string { int ret; struct secmark *secmark; secmark = &$0->secmark; ret = snprintf(secmark->ctx, sizeof(secmark->ctx), "%s", $1); if (ret <= 0 || ret >= (int)sizeof(secmark->ctx)) { erec_queue(error(&@1, "invalid context '%s', max length is %u\n", $1, (int)sizeof(secmark->ctx)), state->msgs); xfree($1); YYERROR; } xfree($1); } ; secmark_obj : /* empty */ { $$ = obj_alloc(&@$); $$->type = NFT_OBJECT_SECMARK; } ; ct_obj_type : HELPER { $$ = NFT_OBJECT_CT_HELPER; } | TIMEOUT { $$ = NFT_OBJECT_CT_TIMEOUT; } | EXPECTATION { $$ = NFT_OBJECT_CT_EXPECT; } ; ct_l4protoname : TCP { $$ = IPPROTO_TCP; } | UDP { $$ = IPPROTO_UDP; } ; ct_helper_config : TYPE QUOTED_STRING PROTOCOL ct_l4protoname stmt_separator { struct ct_helper *ct; int ret; ct = &$0->ct_helper; ret = snprintf(ct->name, sizeof(ct->name), "%s", $2); if (ret <= 0 || ret >= (int)sizeof(ct->name)) { erec_queue(error(&@2, "invalid name '%s', max length is %u\n", $2, (int)sizeof(ct->name)), state->msgs); YYERROR; } ct->l4proto = $4; } | L3PROTOCOL family_spec_explicit stmt_separator { $0->ct_helper.l3proto = $2; } ; timeout_states : timeout_state { $$ = xmalloc(sizeof(*$$)); init_list_head($$); list_add_tail($1, $$); } | timeout_states COMMA timeout_state { list_add_tail($3, $1); $$ = $1; } ; timeout_state : STRING COLON NUM { struct timeout_state *ts; ts = xzalloc(sizeof(*ts)); ts->timeout_str = $1; ts->timeout_value = $3; ts->location = @1; init_list_head(&ts->head); $$ = &ts->head; } ; ct_timeout_config : PROTOCOL ct_l4protoname stmt_separator { struct ct_timeout *ct; int l4proto = $2; ct = &$0->ct_timeout; ct->l4proto = l4proto; } | POLICY '=' '{' timeout_states '}' stmt_separator { struct ct_timeout *ct; ct = &$0->ct_timeout; init_list_head(&ct->timeout_list); list_splice_tail($4, &ct->timeout_list); } | L3PROTOCOL family_spec_explicit stmt_separator { $0->ct_timeout.l3proto = $2; } ; ct_expect_config : PROTOCOL ct_l4protoname stmt_separator { $0->ct_expect.l4proto = $2; } | DPORT NUM stmt_separator { $0->ct_expect.dport = $2; } | TIMEOUT time_spec stmt_separator { $0->ct_expect.timeout = $2; } | SIZE NUM stmt_separator { $0->ct_expect.size = $2; } | L3PROTOCOL family_spec_explicit stmt_separator { $0->ct_expect.l3proto = $2; } ; ct_obj_alloc : /* empty */ { $$ = obj_alloc(&@$); } ; limit_config : RATE limit_mode NUM SLASH time_unit limit_burst_pkts { struct limit *limit; limit = &$0->limit; limit->rate = $3; limit->unit = $5; limit->burst = $6; limit->type = NFT_LIMIT_PKTS; limit->flags = $2; } | RATE limit_mode NUM STRING limit_burst_bytes { struct limit *limit; struct error_record *erec; uint64_t rate, unit; erec = rate_parse(&@$, $4, &rate, &unit); if (erec != NULL) { erec_queue(erec, state->msgs); YYERROR; } limit = &$0->limit; limit->rate = rate * $3; limit->unit = unit; limit->burst = $5; limit->type = NFT_LIMIT_PKT_BYTES; limit->flags = $2; } ; limit_obj : /* empty */ { $$ = obj_alloc(&@$); $$->type = NFT_OBJECT_LIMIT; } ; relational_expr : expr /* implicit */ rhs_expr { $$ = relational_expr_alloc(&@$, OP_IMPLICIT, $1, $2); } | expr /* implicit */ list_rhs_expr { $$ = relational_expr_alloc(&@$, OP_IMPLICIT, $1, $2); } | expr relational_op rhs_expr { $$ = relational_expr_alloc(&@2, $2, $1, $3); } ; list_rhs_expr : basic_rhs_expr COMMA basic_rhs_expr { $$ = list_expr_alloc(&@$); compound_expr_add($$, $1); compound_expr_add($$, $3); } | list_rhs_expr COMMA basic_rhs_expr { $1->location = @$; compound_expr_add($1, $3); $$ = $1; } ; rhs_expr : concat_rhs_expr { $$ = $1; } | wildcard_expr { $$ = $1; } | set_expr { $$ = $1; } | set_ref_symbol_expr { $$ = $1; } ; shift_rhs_expr : primary_rhs_expr | shift_rhs_expr LSHIFT primary_rhs_expr { $$ = binop_expr_alloc(&@$, OP_LSHIFT, $1, $3); } | shift_rhs_expr RSHIFT primary_rhs_expr { $$ = binop_expr_alloc(&@$, OP_RSHIFT, $1, $3); } ; and_rhs_expr : shift_rhs_expr | and_rhs_expr AMPERSAND shift_rhs_expr { $$ = binop_expr_alloc(&@$, OP_AND, $1, $3); } ; exclusive_or_rhs_expr : and_rhs_expr | exclusive_or_rhs_expr CARET and_rhs_expr { $$ = binop_expr_alloc(&@$, OP_XOR, $1, $3); } ; inclusive_or_rhs_expr : exclusive_or_rhs_expr | inclusive_or_rhs_expr '|' exclusive_or_rhs_expr { $$ = binop_expr_alloc(&@$, OP_OR, $1, $3); } ; basic_rhs_expr : inclusive_or_rhs_expr ; concat_rhs_expr : basic_rhs_expr | multiton_rhs_expr | concat_rhs_expr DOT multiton_rhs_expr { struct location rhs[] = { [1] = @2, [2] = @3, }; $$ = handle_concat_expr(&@$, $$, $1, $3, rhs); } | concat_rhs_expr DOT basic_rhs_expr { struct location rhs[] = { [1] = @2, [2] = @3, }; $$ = handle_concat_expr(&@$, $$, $1, $3, rhs); } ; boolean_keys : EXISTS { $$ = true; } | MISSING { $$ = false; } ; boolean_expr : boolean_keys { $$ = constant_expr_alloc(&@$, &boolean_type, BYTEORDER_HOST_ENDIAN, sizeof($1) * BITS_PER_BYTE, &$1); } ; keyword_expr : ETHER { $$ = symbol_value(&@$, "ether"); } | IP { $$ = symbol_value(&@$, "ip"); } | IP6 { $$ = symbol_value(&@$, "ip6"); } | VLAN { $$ = symbol_value(&@$, "vlan"); } | ARP { $$ = symbol_value(&@$, "arp"); } | DNAT { $$ = symbol_value(&@$, "dnat"); } | SNAT { $$ = symbol_value(&@$, "snat"); } | ECN { $$ = symbol_value(&@$, "ecn"); } | RESET { $$ = symbol_value(&@$, "reset"); } | ORIGINAL { $$ = symbol_value(&@$, "original"); } | REPLY { $$ = symbol_value(&@$, "reply"); } | LABEL { $$ = symbol_value(&@$, "label"); } ; primary_rhs_expr : symbol_expr { $$ = $1; } | integer_expr { $$ = $1; } | boolean_expr { $$ = $1; } | keyword_expr { $$ = $1; } | TCP { uint8_t data = IPPROTO_TCP; $$ = constant_expr_alloc(&@$, &inet_protocol_type, BYTEORDER_HOST_ENDIAN, sizeof(data) * BITS_PER_BYTE, &data); } | UDP { uint8_t data = IPPROTO_UDP; $$ = constant_expr_alloc(&@$, &inet_protocol_type, BYTEORDER_HOST_ENDIAN, sizeof(data) * BITS_PER_BYTE, &data); } | UDPLITE { uint8_t data = IPPROTO_UDPLITE; $$ = constant_expr_alloc(&@$, &inet_protocol_type, BYTEORDER_HOST_ENDIAN, sizeof(data) * BITS_PER_BYTE, &data); } | ESP { uint8_t data = IPPROTO_ESP; $$ = constant_expr_alloc(&@$, &inet_protocol_type, BYTEORDER_HOST_ENDIAN, sizeof(data) * BITS_PER_BYTE, &data); } | AH { uint8_t data = IPPROTO_AH; $$ = constant_expr_alloc(&@$, &inet_protocol_type, BYTEORDER_HOST_ENDIAN, sizeof(data) * BITS_PER_BYTE, &data); } | ICMP { uint8_t data = IPPROTO_ICMP; $$ = constant_expr_alloc(&@$, &inet_protocol_type, BYTEORDER_HOST_ENDIAN, sizeof(data) * BITS_PER_BYTE, &data); } | IGMP { uint8_t data = IPPROTO_IGMP; $$ = constant_expr_alloc(&@$, &inet_protocol_type, BYTEORDER_HOST_ENDIAN, sizeof(data) * BITS_PER_BYTE, &data); } | ICMP6 { uint8_t data = IPPROTO_ICMPV6; $$ = constant_expr_alloc(&@$, &inet_protocol_type, BYTEORDER_HOST_ENDIAN, sizeof(data) * BITS_PER_BYTE, &data); } | COMP { uint8_t data = IPPROTO_COMP; $$ = constant_expr_alloc(&@$, &inet_protocol_type, BYTEORDER_HOST_ENDIAN, sizeof(data) * BITS_PER_BYTE, &data); } | DCCP { uint8_t data = IPPROTO_DCCP; $$ = constant_expr_alloc(&@$, &inet_protocol_type, BYTEORDER_HOST_ENDIAN, sizeof(data) * BITS_PER_BYTE, &data); } | SCTP { uint8_t data = IPPROTO_SCTP; $$ = constant_expr_alloc(&@$, &inet_protocol_type, BYTEORDER_HOST_ENDIAN, sizeof(data) * BITS_PER_BYTE, &data); } | REDIRECT { uint8_t data = ICMP_REDIRECT; $$ = constant_expr_alloc(&@$, &icmp_type_type, BYTEORDER_HOST_ENDIAN, sizeof(data) * BITS_PER_BYTE, &data); } | '(' basic_rhs_expr ')' { $$ = $2; } ; relational_op : EQ { $$ = OP_EQ; } | NEQ { $$ = OP_NEQ; } | LT { $$ = OP_LT; } | GT { $$ = OP_GT; } | GTE { $$ = OP_GTE; } | LTE { $$ = OP_LTE; } ; verdict_expr : ACCEPT { $$ = verdict_expr_alloc(&@$, NF_ACCEPT, NULL); } | DROP { $$ = verdict_expr_alloc(&@$, NF_DROP, NULL); } | CONTINUE { $$ = verdict_expr_alloc(&@$, NFT_CONTINUE, NULL); } | JUMP chain_expr { $$ = verdict_expr_alloc(&@$, NFT_JUMP, $2); } | GOTO chain_expr { $$ = verdict_expr_alloc(&@$, NFT_GOTO, $2); } | RETURN { $$ = verdict_expr_alloc(&@$, NFT_RETURN, NULL); } ; chain_expr : variable_expr | identifier { $$ = constant_expr_alloc(&@$, &string_type, BYTEORDER_HOST_ENDIAN, strlen($1) * BITS_PER_BYTE, $1); xfree($1); } ; meta_expr : META meta_key { $$ = meta_expr_alloc(&@$, $2); } | meta_key_unqualified { $$ = meta_expr_alloc(&@$, $1); } | META STRING { struct error_record *erec; unsigned int key; erec = meta_key_parse(&@$, $2, &key); xfree($2); if (erec != NULL) { erec_queue(erec, state->msgs); YYERROR; } $$ = meta_expr_alloc(&@$, key); } ; meta_key : meta_key_qualified | meta_key_unqualified ; meta_key_qualified : LENGTH { $$ = NFT_META_LEN; } | PROTOCOL { $$ = NFT_META_PROTOCOL; } | PRIORITY { $$ = NFT_META_PRIORITY; } | RANDOM { $$ = NFT_META_PRANDOM; } | SECMARK { $$ = NFT_META_SECMARK; } ; meta_key_unqualified : MARK { $$ = NFT_META_MARK; } | IIF { $$ = NFT_META_IIF; } | IIFNAME { $$ = NFT_META_IIFNAME; } | IIFTYPE { $$ = NFT_META_IIFTYPE; } | OIF { $$ = NFT_META_OIF; } | OIFNAME { $$ = NFT_META_OIFNAME; } | OIFTYPE { $$ = NFT_META_OIFTYPE; } | SKUID { $$ = NFT_META_SKUID; } | SKGID { $$ = NFT_META_SKGID; } | NFTRACE { $$ = NFT_META_NFTRACE; } | RTCLASSID { $$ = NFT_META_RTCLASSID; } | IBRIPORT { $$ = NFT_META_BRI_IIFNAME; } | OBRIPORT { $$ = NFT_META_BRI_OIFNAME; } | IBRIDGENAME { $$ = NFT_META_BRI_IIFNAME; } | OBRIDGENAME { $$ = NFT_META_BRI_OIFNAME; } | PKTTYPE { $$ = NFT_META_PKTTYPE; } | CPU { $$ = NFT_META_CPU; } | IIFGROUP { $$ = NFT_META_IIFGROUP; } | OIFGROUP { $$ = NFT_META_OIFGROUP; } | CGROUP { $$ = NFT_META_CGROUP; } | IPSEC { $$ = NFT_META_SECPATH; } | TIME { $$ = NFT_META_TIME_NS; } | DAY { $$ = NFT_META_TIME_DAY; } | HOUR { $$ = NFT_META_TIME_HOUR; } ; meta_stmt : META meta_key SET stmt_expr { switch ($2) { case NFT_META_SECMARK: switch ($4->etype) { case EXPR_CT: $$ = meta_stmt_alloc(&@$, $2, $4); break; default: $$ = objref_stmt_alloc(&@$); $$->objref.type = NFT_OBJECT_SECMARK; $$->objref.expr = $4; break; } break; default: $$ = meta_stmt_alloc(&@$, $2, $4); break; } } | meta_key_unqualified SET stmt_expr { $$ = meta_stmt_alloc(&@$, $1, $3); } | META STRING SET stmt_expr { struct error_record *erec; unsigned int key; erec = meta_key_parse(&@$, $2, &key); xfree($2); if (erec != NULL) { erec_queue(erec, state->msgs); YYERROR; } $$ = meta_stmt_alloc(&@$, key, $4); } | NOTRACK { $$ = notrack_stmt_alloc(&@$); } | FLOW OFFLOAD AT string { $$ = flow_offload_stmt_alloc(&@$, $4); } | FLOW ADD AT string { $$ = flow_offload_stmt_alloc(&@$, $4); } ; socket_expr : SOCKET socket_key { $$ = socket_expr_alloc(&@$, $2); } ; socket_key : TRANSPARENT { $$ = NFT_SOCKET_TRANSPARENT; } | MARK { $$ = NFT_SOCKET_MARK; } ; offset_opt : /* empty */ { $$ = 0; } | OFFSET NUM { $$ = $2; } ; numgen_type : INC { $$ = NFT_NG_INCREMENTAL; } | RANDOM { $$ = NFT_NG_RANDOM; } ; numgen_expr : NUMGEN numgen_type MOD NUM offset_opt { $$ = numgen_expr_alloc(&@$, $2, $4, $5); } ; xfrm_spnum : SPNUM NUM { $$ = $2; } | { $$ = 0; } ; xfrm_dir : IN { $$ = XFRM_POLICY_IN; } | OUT { $$ = XFRM_POLICY_OUT; } ; xfrm_state_key : SPI { $$ = NFT_XFRM_KEY_SPI; } | REQID { $$ = NFT_XFRM_KEY_REQID; } ; xfrm_state_proto_key : DADDR { $$ = NFT_XFRM_KEY_DADDR_IP4; } | SADDR { $$ = NFT_XFRM_KEY_SADDR_IP4; } ; xfrm_expr : IPSEC xfrm_dir xfrm_spnum xfrm_state_key { if ($3 > 255) { erec_queue(error(&@3, "value too large"), state->msgs); YYERROR; } $$ = xfrm_expr_alloc(&@$, $2, $3, $4); } | IPSEC xfrm_dir xfrm_spnum nf_key_proto xfrm_state_proto_key { enum nft_xfrm_keys xfrmk = $5; switch ($4) { case NFPROTO_IPV4: break; case NFPROTO_IPV6: if ($5 == NFT_XFRM_KEY_SADDR_IP4) xfrmk = NFT_XFRM_KEY_SADDR_IP6; else if ($5 == NFT_XFRM_KEY_DADDR_IP4) xfrmk = NFT_XFRM_KEY_DADDR_IP6; break; default: YYERROR; break; } if ($3 > 255) { erec_queue(error(&@3, "value too large"), state->msgs); YYERROR; } $$ = xfrm_expr_alloc(&@$, $2, $3, xfrmk); } ; hash_expr : JHASH expr MOD NUM SEED NUM offset_opt { $$ = hash_expr_alloc(&@$, $4, true, $6, $7, NFT_HASH_JENKINS); $$->hash.expr = $2; } | JHASH expr MOD NUM offset_opt { $$ = hash_expr_alloc(&@$, $4, false, 0, $5, NFT_HASH_JENKINS); $$->hash.expr = $2; } | SYMHASH MOD NUM offset_opt { $$ = hash_expr_alloc(&@$, $3, false, 0, $4, NFT_HASH_SYM); } ; nf_key_proto : IP { $$ = NFPROTO_IPV4; } | IP6 { $$ = NFPROTO_IPV6; } ; rt_expr : RT rt_key { $$ = rt_expr_alloc(&@$, $2, true); } | RT nf_key_proto rt_key { enum nft_rt_keys rtk = $3; switch ($2) { case NFPROTO_IPV4: break; case NFPROTO_IPV6: if ($3 == NFT_RT_NEXTHOP4) rtk = NFT_RT_NEXTHOP6; break; default: YYERROR; break; } $$ = rt_expr_alloc(&@$, rtk, false); } ; rt_key : CLASSID { $$ = NFT_RT_CLASSID; } | NEXTHOP { $$ = NFT_RT_NEXTHOP4; } | MTU { $$ = NFT_RT_TCPMSS; } | IPSEC { $$ = NFT_RT_XFRM; } ; ct_expr : CT ct_key { $$ = ct_expr_alloc(&@$, $2, -1); } | CT ct_dir ct_key_dir { $$ = ct_expr_alloc(&@$, $3, $2); } | CT ct_dir ct_key_proto_field { $$ = ct_expr_alloc(&@$, $3, $2); } ; ct_dir : ORIGINAL { $$ = IP_CT_DIR_ORIGINAL; } | REPLY { $$ = IP_CT_DIR_REPLY; } ; ct_key : L3PROTOCOL { $$ = NFT_CT_L3PROTOCOL; } | PROTOCOL { $$ = NFT_CT_PROTOCOL; } | MARK { $$ = NFT_CT_MARK; } | STATE { $$ = NFT_CT_STATE; } | DIRECTION { $$ = NFT_CT_DIRECTION; } | STATUS { $$ = NFT_CT_STATUS; } | EXPIRATION { $$ = NFT_CT_EXPIRATION; } | HELPER { $$ = NFT_CT_HELPER; } | SADDR { $$ = NFT_CT_SRC; } | DADDR { $$ = NFT_CT_DST; } | PROTO_SRC { $$ = NFT_CT_PROTO_SRC; } | PROTO_DST { $$ = NFT_CT_PROTO_DST; } | LABEL { $$ = NFT_CT_LABELS; } | EVENT { $$ = NFT_CT_EVENTMASK; } | SECMARK { $$ = NFT_CT_SECMARK; } | ct_key_dir_optional ; ct_key_dir : SADDR { $$ = NFT_CT_SRC; } | DADDR { $$ = NFT_CT_DST; } | L3PROTOCOL { $$ = NFT_CT_L3PROTOCOL; } | PROTOCOL { $$ = NFT_CT_PROTOCOL; } | PROTO_SRC { $$ = NFT_CT_PROTO_SRC; } | PROTO_DST { $$ = NFT_CT_PROTO_DST; } | ct_key_dir_optional ; ct_key_proto_field : IP SADDR { $$ = NFT_CT_SRC_IP; } | IP DADDR { $$ = NFT_CT_DST_IP; } | IP6 SADDR { $$ = NFT_CT_SRC_IP6; } | IP6 DADDR { $$ = NFT_CT_DST_IP6; } ; ct_key_dir_optional : BYTES { $$ = NFT_CT_BYTES; } | PACKETS { $$ = NFT_CT_PKTS; } | AVGPKT { $$ = NFT_CT_AVGPKT; } | ZONE { $$ = NFT_CT_ZONE; } ; symbol_stmt_expr : symbol_expr | keyword_expr ; list_stmt_expr : symbol_stmt_expr COMMA symbol_stmt_expr { $$ = list_expr_alloc(&@$); compound_expr_add($$, $1); compound_expr_add($$, $3); } | list_stmt_expr COMMA symbol_stmt_expr { $1->location = @$; compound_expr_add($1, $3); $$ = $1; } ; ct_stmt : CT ct_key SET stmt_expr { switch ($2) { case NFT_CT_HELPER: $$ = objref_stmt_alloc(&@$); $$->objref.type = NFT_OBJECT_CT_HELPER; $$->objref.expr = $4; break; default: $$ = ct_stmt_alloc(&@$, $2, -1, $4); break; } } | CT TIMEOUT SET stmt_expr { $$ = objref_stmt_alloc(&@$); $$->objref.type = NFT_OBJECT_CT_TIMEOUT; $$->objref.expr = $4; } | CT EXPECTATION SET stmt_expr { $$ = objref_stmt_alloc(&@$); $$->objref.type = NFT_OBJECT_CT_EXPECT; $$->objref.expr = $4; } | CT ct_dir ct_key_dir_optional SET stmt_expr { $$ = ct_stmt_alloc(&@$, $3, $2, $5); } ; payload_stmt : payload_expr SET stmt_expr { if ($1->etype == EXPR_EXTHDR) $$ = exthdr_stmt_alloc(&@$, $1, $3); else $$ = payload_stmt_alloc(&@$, $1, $3); } ; payload_expr : payload_raw_expr | eth_hdr_expr | vlan_hdr_expr | arp_hdr_expr | ip_hdr_expr | icmp_hdr_expr | igmp_hdr_expr | ip6_hdr_expr | icmp6_hdr_expr | auth_hdr_expr | esp_hdr_expr | comp_hdr_expr | udp_hdr_expr | udplite_hdr_expr | tcp_hdr_expr | dccp_hdr_expr | sctp_hdr_expr | th_hdr_expr ; payload_raw_expr : AT payload_base_spec COMMA NUM COMMA NUM { $$ = payload_expr_alloc(&@$, NULL, 0); payload_init_raw($$, $2, $4, $6); $$->byteorder = BYTEORDER_BIG_ENDIAN; $$->payload.is_raw = true; } ; payload_base_spec : LL_HDR { $$ = PROTO_BASE_LL_HDR; } | NETWORK_HDR { $$ = PROTO_BASE_NETWORK_HDR; } | TRANSPORT_HDR { $$ = PROTO_BASE_TRANSPORT_HDR; } ; eth_hdr_expr : ETHER eth_hdr_field { $$ = payload_expr_alloc(&@$, &proto_eth, $2); } ; eth_hdr_field : SADDR { $$ = ETHHDR_SADDR; } | DADDR { $$ = ETHHDR_DADDR; } | TYPE { $$ = ETHHDR_TYPE; } ; vlan_hdr_expr : VLAN vlan_hdr_field { $$ = payload_expr_alloc(&@$, &proto_vlan, $2); } ; vlan_hdr_field : ID { $$ = VLANHDR_VID; } | CFI { $$ = VLANHDR_CFI; } | PCP { $$ = VLANHDR_PCP; } | TYPE { $$ = VLANHDR_TYPE; } ; arp_hdr_expr : ARP arp_hdr_field { $$ = payload_expr_alloc(&@$, &proto_arp, $2); } ; arp_hdr_field : HTYPE { $$ = ARPHDR_HRD; } | PTYPE { $$ = ARPHDR_PRO; } | HLEN { $$ = ARPHDR_HLN; } | PLEN { $$ = ARPHDR_PLN; } | OPERATION { $$ = ARPHDR_OP; } | SADDR ETHER { $$ = ARPHDR_SADDR_ETHER; } | DADDR ETHER { $$ = ARPHDR_DADDR_ETHER; } | SADDR IP { $$ = ARPHDR_SADDR_IP; } | DADDR IP { $$ = ARPHDR_DADDR_IP; } ; ip_hdr_expr : IP ip_hdr_field { $$ = payload_expr_alloc(&@$, &proto_ip, $2); } | IP OPTION ip_option_type ip_option_field { $$ = ipopt_expr_alloc(&@$, $3, $4, 0); } | IP OPTION ip_option_type { $$ = ipopt_expr_alloc(&@$, $3, IPOPT_FIELD_TYPE, 0); $$->exthdr.flags = NFT_EXTHDR_F_PRESENT; } ; ip_hdr_field : HDRVERSION { $$ = IPHDR_VERSION; } | HDRLENGTH { $$ = IPHDR_HDRLENGTH; } | DSCP { $$ = IPHDR_DSCP; } | ECN { $$ = IPHDR_ECN; } | LENGTH { $$ = IPHDR_LENGTH; } | ID { $$ = IPHDR_ID; } | FRAG_OFF { $$ = IPHDR_FRAG_OFF; } | TTL { $$ = IPHDR_TTL; } | PROTOCOL { $$ = IPHDR_PROTOCOL; } | CHECKSUM { $$ = IPHDR_CHECKSUM; } | SADDR { $$ = IPHDR_SADDR; } | DADDR { $$ = IPHDR_DADDR; } ; ip_option_type : LSRR { $$ = IPOPT_LSRR; } | RR { $$ = IPOPT_RR; } | SSRR { $$ = IPOPT_SSRR; } | RA { $$ = IPOPT_RA; } ; ip_option_field : TYPE { $$ = IPOPT_FIELD_TYPE; } | LENGTH { $$ = IPOPT_FIELD_LENGTH; } | VALUE { $$ = IPOPT_FIELD_VALUE; } | PTR { $$ = IPOPT_FIELD_PTR; } | ADDR { $$ = IPOPT_FIELD_ADDR_0; } ; icmp_hdr_expr : ICMP icmp_hdr_field { $$ = payload_expr_alloc(&@$, &proto_icmp, $2); } ; icmp_hdr_field : TYPE { $$ = ICMPHDR_TYPE; } | CODE { $$ = ICMPHDR_CODE; } | CHECKSUM { $$ = ICMPHDR_CHECKSUM; } | ID { $$ = ICMPHDR_ID; } | SEQUENCE { $$ = ICMPHDR_SEQ; } | GATEWAY { $$ = ICMPHDR_GATEWAY; } | MTU { $$ = ICMPHDR_MTU; } ; igmp_hdr_expr : IGMP igmp_hdr_field { $$ = payload_expr_alloc(&@$, &proto_igmp, $2); } ; igmp_hdr_field : TYPE { $$ = IGMPHDR_TYPE; } | CHECKSUM { $$ = IGMPHDR_CHECKSUM; } | MRT { $$ = IGMPHDR_MRT; } | GROUP { $$ = IGMPHDR_GROUP; } ; ip6_hdr_expr : IP6 ip6_hdr_field { $$ = payload_expr_alloc(&@$, &proto_ip6, $2); } ; ip6_hdr_field : HDRVERSION { $$ = IP6HDR_VERSION; } | DSCP { $$ = IP6HDR_DSCP; } | ECN { $$ = IP6HDR_ECN; } | FLOWLABEL { $$ = IP6HDR_FLOWLABEL; } | LENGTH { $$ = IP6HDR_LENGTH; } | NEXTHDR { $$ = IP6HDR_NEXTHDR; } | HOPLIMIT { $$ = IP6HDR_HOPLIMIT; } | SADDR { $$ = IP6HDR_SADDR; } | DADDR { $$ = IP6HDR_DADDR; } ; icmp6_hdr_expr : ICMP6 icmp6_hdr_field { $$ = payload_expr_alloc(&@$, &proto_icmp6, $2); } ; icmp6_hdr_field : TYPE { $$ = ICMP6HDR_TYPE; } | CODE { $$ = ICMP6HDR_CODE; } | CHECKSUM { $$ = ICMP6HDR_CHECKSUM; } | PPTR { $$ = ICMP6HDR_PPTR; } | MTU { $$ = ICMP6HDR_MTU; } | ID { $$ = ICMP6HDR_ID; } | SEQUENCE { $$ = ICMP6HDR_SEQ; } | MAXDELAY { $$ = ICMP6HDR_MAXDELAY; } ; auth_hdr_expr : AH auth_hdr_field { $$ = payload_expr_alloc(&@$, &proto_ah, $2); } ; auth_hdr_field : NEXTHDR { $$ = AHHDR_NEXTHDR; } | HDRLENGTH { $$ = AHHDR_HDRLENGTH; } | RESERVED { $$ = AHHDR_RESERVED; } | SPI { $$ = AHHDR_SPI; } | SEQUENCE { $$ = AHHDR_SEQUENCE; } ; esp_hdr_expr : ESP esp_hdr_field { $$ = payload_expr_alloc(&@$, &proto_esp, $2); } ; esp_hdr_field : SPI { $$ = ESPHDR_SPI; } | SEQUENCE { $$ = ESPHDR_SEQUENCE; } ; comp_hdr_expr : COMP comp_hdr_field { $$ = payload_expr_alloc(&@$, &proto_comp, $2); } ; comp_hdr_field : NEXTHDR { $$ = COMPHDR_NEXTHDR; } | FLAGS { $$ = COMPHDR_FLAGS; } | CPI { $$ = COMPHDR_CPI; } ; udp_hdr_expr : UDP udp_hdr_field { $$ = payload_expr_alloc(&@$, &proto_udp, $2); } ; udp_hdr_field : SPORT { $$ = UDPHDR_SPORT; } | DPORT { $$ = UDPHDR_DPORT; } | LENGTH { $$ = UDPHDR_LENGTH; } | CHECKSUM { $$ = UDPHDR_CHECKSUM; } ; udplite_hdr_expr : UDPLITE udplite_hdr_field { $$ = payload_expr_alloc(&@$, &proto_udplite, $2); } ; udplite_hdr_field : SPORT { $$ = UDPHDR_SPORT; } | DPORT { $$ = UDPHDR_DPORT; } | CSUMCOV { $$ = UDPHDR_LENGTH; } | CHECKSUM { $$ = UDPHDR_CHECKSUM; } ; tcp_hdr_expr : TCP tcp_hdr_field { $$ = payload_expr_alloc(&@$, &proto_tcp, $2); } | TCP OPTION tcp_hdr_option_type tcp_hdr_option_field { $$ = tcpopt_expr_alloc(&@$, $3, $4); } | TCP OPTION tcp_hdr_option_type { $$ = tcpopt_expr_alloc(&@$, $3, TCPOPTHDR_FIELD_KIND); $$->exthdr.flags = NFT_EXTHDR_F_PRESENT; } ; tcp_hdr_field : SPORT { $$ = TCPHDR_SPORT; } | DPORT { $$ = TCPHDR_DPORT; } | SEQUENCE { $$ = TCPHDR_SEQ; } | ACKSEQ { $$ = TCPHDR_ACKSEQ; } | DOFF { $$ = TCPHDR_DOFF; } | RESERVED { $$ = TCPHDR_RESERVED; } | FLAGS { $$ = TCPHDR_FLAGS; } | WINDOW { $$ = TCPHDR_WINDOW; } | CHECKSUM { $$ = TCPHDR_CHECKSUM; } | URGPTR { $$ = TCPHDR_URGPTR; } ; tcp_hdr_option_type : EOL { $$ = TCPOPTHDR_EOL; } | NOOP { $$ = TCPOPTHDR_NOOP; } | MAXSEG { $$ = TCPOPTHDR_MAXSEG; } | WINDOW { $$ = TCPOPTHDR_WINDOW; } | SACK_PERMITTED { $$ = TCPOPTHDR_SACK_PERMITTED; } | SACK { $$ = TCPOPTHDR_SACK0; } | SACK0 { $$ = TCPOPTHDR_SACK0; } | SACK1 { $$ = TCPOPTHDR_SACK1; } | SACK2 { $$ = TCPOPTHDR_SACK2; } | SACK3 { $$ = TCPOPTHDR_SACK3; } | ECHO { $$ = TCPOPTHDR_ECHO; } | TIMESTAMP { $$ = TCPOPTHDR_TIMESTAMP; } ; tcp_hdr_option_field : KIND { $$ = TCPOPTHDR_FIELD_KIND; } | LENGTH { $$ = TCPOPTHDR_FIELD_LENGTH; } | SIZE { $$ = TCPOPTHDR_FIELD_SIZE; } | COUNT { $$ = TCPOPTHDR_FIELD_COUNT; } | LEFT { $$ = TCPOPTHDR_FIELD_LEFT; } | RIGHT { $$ = TCPOPTHDR_FIELD_RIGHT; } | TSVAL { $$ = TCPOPTHDR_FIELD_TSVAL; } | TSECR { $$ = TCPOPTHDR_FIELD_TSECR; } ; dccp_hdr_expr : DCCP dccp_hdr_field { $$ = payload_expr_alloc(&@$, &proto_dccp, $2); } ; dccp_hdr_field : SPORT { $$ = DCCPHDR_SPORT; } | DPORT { $$ = DCCPHDR_DPORT; } | TYPE { $$ = DCCPHDR_TYPE; } ; sctp_hdr_expr : SCTP sctp_hdr_field { $$ = payload_expr_alloc(&@$, &proto_sctp, $2); } ; sctp_hdr_field : SPORT { $$ = SCTPHDR_SPORT; } | DPORT { $$ = SCTPHDR_DPORT; } | VTAG { $$ = SCTPHDR_VTAG; } | CHECKSUM { $$ = SCTPHDR_CHECKSUM; } ; th_hdr_expr : TRANSPORT_HDR th_hdr_field { $$ = payload_expr_alloc(&@$, &proto_th, $2); if ($$) $$->payload.is_raw = true; } ; th_hdr_field : SPORT { $$ = THDR_SPORT; } | DPORT { $$ = THDR_DPORT; } ; exthdr_expr : hbh_hdr_expr | rt_hdr_expr | rt0_hdr_expr | rt2_hdr_expr | rt4_hdr_expr | frag_hdr_expr | dst_hdr_expr | mh_hdr_expr ; hbh_hdr_expr : HBH hbh_hdr_field { $$ = exthdr_expr_alloc(&@$, &exthdr_hbh, $2); } ; hbh_hdr_field : NEXTHDR { $$ = HBHHDR_NEXTHDR; } | HDRLENGTH { $$ = HBHHDR_HDRLENGTH; } ; rt_hdr_expr : RT rt_hdr_field { $$ = exthdr_expr_alloc(&@$, &exthdr_rt, $2); } ; rt_hdr_field : NEXTHDR { $$ = RTHDR_NEXTHDR; } | HDRLENGTH { $$ = RTHDR_HDRLENGTH; } | TYPE { $$ = RTHDR_TYPE; } | SEG_LEFT { $$ = RTHDR_SEG_LEFT; } ; rt0_hdr_expr : RT0 rt0_hdr_field { $$ = exthdr_expr_alloc(&@$, &exthdr_rt0, $2); } ; rt0_hdr_field : ADDR '[' NUM ']' { $$ = RT0HDR_ADDR_1 + $3 - 1; } ; rt2_hdr_expr : RT2 rt2_hdr_field { $$ = exthdr_expr_alloc(&@$, &exthdr_rt2, $2); } ; rt2_hdr_field : ADDR { $$ = RT2HDR_ADDR; } ; rt4_hdr_expr : RT4 rt4_hdr_field { $$ = exthdr_expr_alloc(&@$, &exthdr_rt4, $2); } ; rt4_hdr_field : LAST_ENT { $$ = RT4HDR_LASTENT; } | FLAGS { $$ = RT4HDR_FLAGS; } | TAG { $$ = RT4HDR_TAG; } | SID '[' NUM ']' { $$ = RT4HDR_SID_1 + $3 - 1; } ; frag_hdr_expr : FRAG frag_hdr_field { $$ = exthdr_expr_alloc(&@$, &exthdr_frag, $2); } ; frag_hdr_field : NEXTHDR { $$ = FRAGHDR_NEXTHDR; } | RESERVED { $$ = FRAGHDR_RESERVED; } | FRAG_OFF { $$ = FRAGHDR_FRAG_OFF; } | RESERVED2 { $$ = FRAGHDR_RESERVED2; } | MORE_FRAGMENTS { $$ = FRAGHDR_MFRAGS; } | ID { $$ = FRAGHDR_ID; } ; dst_hdr_expr : DST dst_hdr_field { $$ = exthdr_expr_alloc(&@$, &exthdr_dst, $2); } ; dst_hdr_field : NEXTHDR { $$ = DSTHDR_NEXTHDR; } | HDRLENGTH { $$ = DSTHDR_HDRLENGTH; } ; mh_hdr_expr : MH mh_hdr_field { $$ = exthdr_expr_alloc(&@$, &exthdr_mh, $2); } ; mh_hdr_field : NEXTHDR { $$ = MHHDR_NEXTHDR; } | HDRLENGTH { $$ = MHHDR_HDRLENGTH; } | TYPE { $$ = MHHDR_TYPE; } | RESERVED { $$ = MHHDR_RESERVED; } | CHECKSUM { $$ = MHHDR_CHECKSUM; } ; exthdr_exists_expr : EXTHDR exthdr_key { const struct exthdr_desc *desc; desc = exthdr_find_proto($2); /* Assume that NEXTHDR template is always * the fist one in list of templates. */ $$ = exthdr_expr_alloc(&@$, desc, 1); $$->exthdr.flags = NFT_EXTHDR_F_PRESENT; } ; exthdr_key : HBH { $$ = IPPROTO_HOPOPTS; } | RT { $$ = IPPROTO_ROUTING; } | FRAG { $$ = IPPROTO_FRAGMENT; } | DST { $$ = IPPROTO_DSTOPTS; } | MH { $$ = IPPROTO_MH; } ; %%