diff options
Diffstat (limited to 'src/parser_bison.y')
-rw-r--r-- | src/parser_bison.y | 2475 |
1 files changed, 1766 insertions, 709 deletions
diff --git a/src/parser_bison.y b/src/parser_bison.y index 167c3158..e2936d10 100644 --- a/src/parser_bison.y +++ b/src/parser_bison.y @@ -9,11 +9,14 @@ */ %{ +#include <nft.h> +#include <ctype.h> #include <stddef.h> #include <stdio.h> #include <inttypes.h> #include <syslog.h> +#include <net/if.h> #include <netinet/ip.h> #include <netinet/tcp.h> #include <netinet/if_ether.h> @@ -38,6 +41,7 @@ #include <utils.h> #include <parser.h> #include <erec.h> +#include <sctp_chunk.h> #include "parser_bison.h" @@ -63,16 +67,26 @@ 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) +static int open_scope(struct parser_state *state, struct scope *scope) { - assert(state->scope < array_size(state->scopes) - 1); + if (state->scope >= array_size(state->scopes) - 1) { + state->scope_err = true; + return -1; + } + scope_init(scope, current_scope(state)); state->scopes[++state->scope] = scope; + + return 0; } static void close_scope(struct parser_state *state) { - assert(state->scope > 0); + if (state->scope_err || state->scope == 0) { + state->scope_err = false; + return; + } + state->scope--; } @@ -121,6 +135,62 @@ static struct expr *handle_concat_expr(const struct location *loc, return expr; } +static bool already_set(const void *attr, const struct location *loc, + struct parser_state *state) +{ + if (!attr) + return false; + + erec_queue(error(loc, "You can only specify this once. This statement is duplicated."), + state->msgs); + return true; +} + +static struct expr *ifname_expr_alloc(const struct location *location, + struct list_head *queue, + const char *name) +{ + size_t length = strlen(name); + struct expr *expr; + + if (length == 0) { + free_const(name); + erec_queue(error(location, "empty interface name"), queue); + return NULL; + } + + if (length >= IFNAMSIZ) { + free_const(name); + erec_queue(error(location, "interface name too long"), queue); + return NULL; + } + + expr = constant_expr_alloc(location, &ifname_type, BYTEORDER_HOST_ENDIAN, + length * BITS_PER_BYTE, name); + + free_const(name); + + return expr; +} + +static void timeout_state_free(struct timeout_state *s) +{ + free_const(s->timeout_str); + free(s); +} + +static void timeout_states_free(struct list_head *list) +{ + struct timeout_state *ts, *next; + + list_for_each_entry_safe(ts, next, list, head) { + list_del(&ts->head); + timeout_state_free(ts); + } + + free(list); +} + #define YYLLOC_DEFAULT(Current, Rhs, N) location_update(&Current, Rhs, N) #define symbol_value(loc, str) \ @@ -173,7 +243,12 @@ int nft_lex(void *, void *, void *); struct handle_spec handle_spec; struct position_spec position_spec; struct prio_spec prio_spec; - const struct exthdr_desc *exthdr_desc; + struct limit_rate limit_rate; + struct tcp_kind_field { + uint16_t kind; /* must allow > 255 for SACK1, 2.. hack */ + uint8_t field; + } tcp_kind_field; + struct timeout_state *timeout_state; } %token TOKEN_EOF 0 "end of file" @@ -213,6 +288,8 @@ int nft_lex(void *, void *, void *); %token SOCKET "socket" %token TRANSPARENT "transparent" +%token WILDCARD "wildcard" +%token CGROUPV2 "cgroupv2" %token TPROXY "tproxy" @@ -221,11 +298,11 @@ int nft_lex(void *, void *, void *); %token SYNPROXY "synproxy" %token MSS "mss" %token WSCALE "wscale" -%token SACKPERM "sack-perm" %token TYPEOF "typeof" %token HOOK "hook" +%token HOOKS "hooks" %token DEVICE "device" %token DEVICES "devices" %token TABLE "table" @@ -261,6 +338,8 @@ int nft_lex(void *, void *, void *); %token DESCRIBE "describe" %token IMPORT "import" %token EXPORT "export" +%token DESTROY "destroy" + %token MONITOR "monitor" %token ALL "all" @@ -298,7 +377,7 @@ int nft_lex(void *, void *, void *); %token <string> STRING "string" %token <string> QUOTED_STRING "quoted string" %token <string> ASTERISK_STRING "string with a trailing asterisk" -%destructor { xfree($$); } STRING QUOTED_STRING ASTERISK_STRING +%destructor { free_const($$); } STRING QUOTED_STRING ASTERISK_STRING %token LL_HDR "ll" %token NETWORK_HDR "nh" @@ -314,6 +393,7 @@ int nft_lex(void *, void *, void *); %token VLAN "vlan" %token ID "id" %token CFI "cfi" +%token DEI "dei" %token PCP "pcp" %token ARP "arp" @@ -362,6 +442,7 @@ int nft_lex(void *, void *, void *); %token ICMP6 "icmpv6" %token PPTR "param-problem" %token MAXDELAY "max-delay" +%token TADDR "taddr" %token AH "ah" %token RESERVED "reserved" @@ -388,25 +469,69 @@ int nft_lex(void *, void *, void *); %token OPTION "option" %token ECHO "echo" %token EOL "eol" -%token MAXSEG "maxseg" -%token NOOP "noop" +%token MPTCP "mptcp" +%token NOP "nop" %token SACK "sack" %token SACK0 "sack0" %token SACK1 "sack1" %token SACK2 "sack2" %token SACK3 "sack3" -%token SACK_PERMITTED "sack-permitted" +%token SACK_PERM "sack-permitted" +%token FASTOPEN "fastopen" +%token MD5SIG "md5sig" %token TIMESTAMP "timestamp" -%token KIND "kind" %token COUNT "count" %token LEFT "left" %token RIGHT "right" %token TSVAL "tsval" %token TSECR "tsecr" +%token SUBTYPE "subtype" %token DCCP "dccp" +%token VXLAN "vxlan" +%token VNI "vni" + +%token GRE "gre" +%token GRETAP "gretap" + +%token GENEVE "geneve" + %token SCTP "sctp" +%token CHUNK "chunk" +%token DATA "data" +%token INIT "init" +%token INIT_ACK "init-ack" +%token HEARTBEAT "heartbeat" +%token HEARTBEAT_ACK "heartbeat-ack" +%token ABORT "abort" +%token SHUTDOWN "shutdown" +%token SHUTDOWN_ACK "shutdown-ack" +%token ERROR "error" +%token COOKIE_ECHO "cookie-echo" +%token COOKIE_ACK "cookie-ack" +%token ECNE "ecne" +%token CWR "cwr" +%token SHUTDOWN_COMPLETE "shutdown-complete" +%token ASCONF_ACK "asconf-ack" +%token FORWARD_TSN "forward-tsn" +%token ASCONF "asconf" +%token TSN "tsn" +%token STREAM "stream" +%token SSN "ssn" +%token PPID "ppid" +%token INIT_TAG "init-tag" +%token A_RWND "a-rwnd" +%token NUM_OSTREAMS "num-outbound-streams" +%token NUM_ISTREAMS "num-inbound-streams" +%token INIT_TSN "initial-tsn" +%token CUM_TSN_ACK "cum-tsn-ack" +%token NUM_GACK_BLOCKS "num-gap-ack-blocks" +%token NUM_DUP_TSNS "num-dup-tsns" +%token LOWEST_TSN "lowest-tsn" +%token SEQNO "seqno" +%token NEW_CUM_TSN "new-cum-tsn" + %token VTAG "vtag" %token RT "rt" @@ -477,6 +602,9 @@ int nft_lex(void *, void *, void *); %token BYTES "bytes" %token AVGPKT "avgpkt" +%token LAST "last" +%token NEVER "never" + %token COUNTERS "counters" %token QUOTAS "quotas" %token LIMITS "limits" @@ -502,9 +630,6 @@ int nft_lex(void *, void *, void *); %token SECMARK "secmark" %token SECMARKS "secmarks" -%token NANOSECOND "nanosecond" -%token MICROSECOND "microsecond" -%token MILLISECOND "millisecond" %token SECOND "second" %token MINUTE "minute" %token HOUR "hour" @@ -556,19 +681,21 @@ int nft_lex(void *, void *, void *); %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" +%token XT "xt" + +%type <limit_rate> limit_rate_pkts +%type <limit_rate> limit_rate_bytes + %type <string> identifier type_identifier string comment_spec -%destructor { xfree($$); } identifier type_identifier string comment_spec +%destructor { free_const($$); } identifier type_identifier string comment_spec -%type <val> time_spec quota_used +%type <val> time_spec time_spec_or_num_s set_elem_time_spec quota_used %type <expr> data_type_expr data_type_atom_expr %destructor { expr_free($$); } data_type_expr data_type_atom_expr @@ -576,29 +703,47 @@ int nft_lex(void *, void *, void *); %type <cmd> line %destructor { cmd_free($$); } line -%type <cmd> 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 <cmd> 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 destroy_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 destroy_cmd + +%type <handle> table_spec tableid_spec table_or_id_spec +%destructor { handle_free(&$$); } table_spec tableid_spec table_or_id_spec +%type <handle> chain_spec chainid_spec chain_or_id_spec +%destructor { handle_free(&$$); } chain_spec chainid_spec chain_or_id_spec + +%type <handle> flowtable_spec chain_identifier ruleid_spec handle_spec position_spec rule_position ruleset_spec index_spec +%destructor { handle_free(&$$); } flowtable_spec chain_identifier ruleid_spec handle_spec position_spec rule_position ruleset_spec index_spec +%type <handle> set_spec setid_spec set_or_id_spec +%destructor { handle_free(&$$); } set_spec setid_spec set_or_id_spec +%type <handle> obj_spec objid_spec obj_or_id_spec +%destructor { handle_free(&$$); } obj_spec objid_spec obj_or_id_spec + +%type <handle> set_identifier flowtableid_spec flowtable_identifier obj_identifier +%destructor { handle_free(&$$); } set_identifier flowtableid_spec obj_identifier + +%type <handle> basehook_spec +%destructor { handle_free(&$$); } basehook_spec -%type <handle> 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 <handle> 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 <val> family_spec family_spec_explicit %type <val32> int_num chain_policy %type <prio_spec> extended_prio_spec prio_spec -%type <string> extended_prio_name quota_unit -%destructor { xfree($$); } extended_prio_name quota_unit +%destructor { expr_free($$.expr); } extended_prio_spec prio_spec + +%type <string> extended_prio_name quota_unit basehook_device_name +%destructor { free_const($$); } extended_prio_name quota_unit basehook_device_name %type <expr> dev_spec -%destructor { xfree($$); } dev_spec +%destructor { free($$); } dev_spec %type <table> table_block_alloc table_block %destructor { close_scope(state); table_free($$); } table_block_alloc %type <chain> chain_block_alloc chain_block subchain_block -%destructor { close_scope(state); chain_free($$); } chain_block_alloc subchain_block +%destructor { close_scope(state); chain_free($$); } chain_block_alloc %type <rule> rule rule_alloc %destructor { rule_free($$); } rule +%type <val> table_flags table_flag + %type <val> set_flag_list set_flag %type <val> set_policy_spec @@ -608,6 +753,7 @@ int nft_lex(void *, void *, void *); %type <set> map_block_alloc map_block %destructor { set_free($$); } map_block_alloc +%type <val> map_block_obj_type map_block_obj_typeof map_block_data_interval %type <flowtable> flowtable_block_alloc flowtable_block %destructor { flowtable_free($$); } flowtable_block_alloc @@ -615,12 +761,15 @@ int nft_lex(void *, void *, void *); %type <obj> 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 <list> stmt_list -%destructor { stmt_list_free($$); xfree($$); } stmt_list -%type <stmt> stmt match_stmt verdict_stmt -%destructor { stmt_free($$); } stmt match_stmt verdict_stmt -%type <stmt> counter_stmt counter_stmt_alloc stateful_stmt -%destructor { stmt_free($$); } counter_stmt counter_stmt_alloc stateful_stmt +%type <list> stmt_list stateful_stmt_list set_elem_stmt_list +%destructor { stmt_list_free($$); free($$); } stmt_list stateful_stmt_list set_elem_stmt_list +%type <stmt> stmt match_stmt verdict_stmt set_elem_stmt +%destructor { stmt_free($$); } stmt match_stmt verdict_stmt set_elem_stmt +%type <stmt> counter_stmt counter_stmt_alloc stateful_stmt last_stmt +%destructor { stmt_free($$); } counter_stmt counter_stmt_alloc stateful_stmt last_stmt +%type <stmt> objref_stmt objref_stmt_counter objref_stmt_limit objref_stmt_quota objref_stmt_ct objref_stmt_synproxy +%destructor { stmt_free($$); } objref_stmt objref_stmt_counter objref_stmt_limit objref_stmt_quota objref_stmt_ct objref_stmt_synproxy + %type <stmt> payload_stmt %destructor { stmt_free($$); } payload_stmt %type <stmt> ct_stmt @@ -632,7 +781,7 @@ int nft_lex(void *, void *, void *); %type <val> level_type log_flags log_flags_tcp log_flag_tcp %type <stmt> limit_stmt quota_stmt connlimit_stmt %destructor { stmt_free($$); } limit_stmt quota_stmt connlimit_stmt -%type <val> limit_burst_pkts limit_burst_bytes limit_mode time_unit quota_mode +%type <val> limit_burst_pkts limit_burst_bytes limit_mode limit_bytes time_unit quota_mode %type <stmt> reject_stmt reject_stmt_alloc %destructor { stmt_free($$); } reject_stmt reject_stmt_alloc %type <stmt> nat_stmt nat_stmt_alloc masq_stmt masq_stmt_alloc redir_stmt redir_stmt_alloc @@ -646,8 +795,10 @@ int nft_lex(void *, void *, void *); %destructor { stmt_free($$); } chain_stmt %type <val> chain_stmt_type -%type <stmt> queue_stmt queue_stmt_alloc -%destructor { stmt_free($$); } queue_stmt queue_stmt_alloc +%type <stmt> queue_stmt queue_stmt_alloc queue_stmt_compat +%destructor { stmt_free($$); } queue_stmt queue_stmt_alloc queue_stmt_compat +%type <expr> queue_stmt_expr_simple queue_stmt_expr queue_expr reject_with_expr +%destructor { expr_free($$); } queue_stmt_expr_simple queue_stmt_expr queue_expr reject_with_expr %type <val> queue_stmt_flags queue_stmt_flag %type <stmt> dup_stmt %destructor { stmt_free($$); } dup_stmt @@ -658,13 +809,13 @@ int nft_lex(void *, void *, void *); %type <val> set_stmt_op %type <stmt> map_stmt %destructor { stmt_free($$); } map_stmt -%type <stmt> meter_stmt meter_stmt_alloc flow_stmt_legacy_alloc -%destructor { stmt_free($$); } meter_stmt meter_stmt_alloc flow_stmt_legacy_alloc +%type <stmt> meter_stmt meter_stmt_alloc +%destructor { stmt_free($$); } meter_stmt meter_stmt_alloc %type <expr> 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 <expr> primary_expr shift_expr and_expr typeof_expr -%destructor { expr_free($$); } primary_expr shift_expr and_expr typeof_expr +%type <expr> primary_expr shift_expr and_expr typeof_expr typeof_data_expr typeof_key_expr typeof_verdict_expr +%destructor { expr_free($$); } primary_expr shift_expr and_expr typeof_expr typeof_data_expr typeof_key_expr typeof_verdict_expr %type <expr> exclusive_or_expr inclusive_or_expr %destructor { expr_free($$); } exclusive_or_expr inclusive_or_expr %type <expr> basic_expr @@ -682,8 +833,8 @@ int nft_lex(void *, void *, void *); %type <expr> multiton_stmt_expr %destructor { expr_free($$); } multiton_stmt_expr -%type <expr> prefix_stmt_expr range_stmt_expr wildcard_expr -%destructor { expr_free($$); } prefix_stmt_expr range_stmt_expr wildcard_expr +%type <expr> prefix_stmt_expr range_stmt_expr +%destructor { expr_free($$); } prefix_stmt_expr range_stmt_expr %type <expr> primary_stmt_expr basic_stmt_expr %destructor { expr_free($$); } primary_stmt_expr basic_stmt_expr @@ -734,6 +885,8 @@ int nft_lex(void *, void *, void *); %type <expr> payload_expr payload_raw_expr %destructor { expr_free($$); } payload_expr payload_raw_expr %type <val> payload_base_spec +%type <val> payload_raw_len + %type <expr> eth_hdr_expr vlan_hdr_expr %destructor { expr_free($$); } eth_hdr_expr vlan_hdr_expr %type <val> eth_hdr_field vlan_hdr_field @@ -753,9 +906,12 @@ int nft_lex(void *, void *, void *); %type <expr> udp_hdr_expr udplite_hdr_expr %destructor { expr_free($$); } udp_hdr_expr udplite_hdr_expr %type <val> udp_hdr_field udplite_hdr_field -%type <expr> dccp_hdr_expr sctp_hdr_expr -%destructor { expr_free($$); } dccp_hdr_expr sctp_hdr_expr +%type <expr> dccp_hdr_expr sctp_hdr_expr sctp_chunk_alloc +%destructor { expr_free($$); } dccp_hdr_expr sctp_hdr_expr sctp_chunk_alloc %type <val> dccp_hdr_field sctp_hdr_field +%type <val> sctp_chunk_type sctp_chunk_common_field +%type <val> sctp_chunk_data_field sctp_chunk_init_field +%type <val> sctp_chunk_sack_field %type <expr> th_hdr_expr %destructor { expr_free($$); } th_hdr_expr %type <val> th_hdr_field @@ -800,7 +956,7 @@ int nft_lex(void *, void *, void *); %type <val> markup_format %type <string> monitor_event -%destructor { xfree($$); } monitor_event +%destructor { free_const($$); } monitor_event %type <val> monitor_object monitor_format %type <val> synproxy_ts synproxy_sack @@ -808,7 +964,23 @@ int nft_lex(void *, void *, void *); %type <expr> tcp_hdr_expr %destructor { expr_free($$); } tcp_hdr_expr %type <val> tcp_hdr_field -%type <val> tcp_hdr_option_type tcp_hdr_option_field +%type <val> tcp_hdr_option_type +%type <val> tcp_hdr_option_sack +%type <val> tcpopt_field_maxseg tcpopt_field_mptcp tcpopt_field_sack tcpopt_field_tsopt tcpopt_field_window +%type <tcp_kind_field> tcp_hdr_option_kind_and_field + +%type <expr> inner_eth_expr inner_inet_expr inner_expr +%destructor { expr_free($$); } inner_eth_expr inner_inet_expr inner_expr + +%type <expr> vxlan_hdr_expr geneve_hdr_expr gre_hdr_expr gretap_hdr_expr +%destructor { expr_free($$); } vxlan_hdr_expr geneve_hdr_expr gre_hdr_expr gretap_hdr_expr +%type <val> vxlan_hdr_field geneve_hdr_field gre_hdr_field + +%type <stmt> optstrip_stmt +%destructor { stmt_free($$); } optstrip_stmt + +%type <stmt> xt_stmt +%destructor { stmt_free($$); } xt_stmt %type <expr> boolean_expr %destructor { expr_free($$); } boolean_expr @@ -818,15 +990,21 @@ int nft_lex(void *, void *, void *); %destructor { expr_free($$); } exthdr_exists_expr %type <val> exthdr_key -%type <val> ct_l4protoname ct_obj_type +%type <val> ct_l4protoname ct_obj_type ct_cmd_type ct_obj_type_map -%type <list> timeout_states timeout_state -%destructor { xfree($$); } timeout_states timeout_state +%type <timeout_state> timeout_state +%destructor { timeout_state_free($$); } timeout_state + +%type <list> timeout_states +%destructor { timeout_states_free($$); } timeout_states %type <val> xfrm_state_key xfrm_state_proto_key xfrm_dir xfrm_spnum %type <expr> xfrm_expr %destructor { expr_free($$); } xfrm_expr +%type <expr> set_elem_key_expr +%destructor { expr_free($$); } set_elem_key_expr + %% input : /* empty */ @@ -847,13 +1025,69 @@ opt_newline : NEWLINE | /* empty */ ; +close_scope_ah : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_AH); }; +close_scope_arp : { scanner_pop_start_cond(nft->scanner, PARSER_SC_ARP); }; +close_scope_at : { scanner_pop_start_cond(nft->scanner, PARSER_SC_AT); }; +close_scope_comp : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_COMP); }; +close_scope_ct : { scanner_pop_start_cond(nft->scanner, PARSER_SC_CT); }; +close_scope_counter : { scanner_pop_start_cond(nft->scanner, PARSER_SC_COUNTER); }; +close_scope_last : { scanner_pop_start_cond(nft->scanner, PARSER_SC_LAST); }; +close_scope_dccp : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_DCCP); }; +close_scope_destroy : { scanner_pop_start_cond(nft->scanner, PARSER_SC_CMD_DESTROY); }; +close_scope_dst : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_DST); }; +close_scope_dup : { scanner_pop_start_cond(nft->scanner, PARSER_SC_STMT_DUP); }; +close_scope_esp : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_ESP); }; +close_scope_eth : { scanner_pop_start_cond(nft->scanner, PARSER_SC_ETH); }; +close_scope_export : { scanner_pop_start_cond(nft->scanner, PARSER_SC_CMD_EXPORT); }; +close_scope_fib : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_FIB); }; +close_scope_frag : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_FRAG); }; +close_scope_fwd : { scanner_pop_start_cond(nft->scanner, PARSER_SC_STMT_FWD); }; +close_scope_gre : { scanner_pop_start_cond(nft->scanner, PARSER_SC_GRE); }; +close_scope_hash : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_HASH); }; +close_scope_hbh : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_HBH); }; +close_scope_ip : { scanner_pop_start_cond(nft->scanner, PARSER_SC_IP); }; +close_scope_ip6 : { scanner_pop_start_cond(nft->scanner, PARSER_SC_IP6); }; +close_scope_vlan : { scanner_pop_start_cond(nft->scanner, PARSER_SC_VLAN); }; +close_scope_icmp : { scanner_pop_start_cond(nft->scanner, PARSER_SC_ICMP); }; +close_scope_igmp : { scanner_pop_start_cond(nft->scanner, PARSER_SC_IGMP); }; +close_scope_import : { scanner_pop_start_cond(nft->scanner, PARSER_SC_CMD_IMPORT); }; +close_scope_ipsec : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_IPSEC); }; +close_scope_list : { scanner_pop_start_cond(nft->scanner, PARSER_SC_CMD_LIST); }; +close_scope_limit : { scanner_pop_start_cond(nft->scanner, PARSER_SC_LIMIT); }; +close_scope_meta : { scanner_pop_start_cond(nft->scanner, PARSER_SC_META); }; +close_scope_mh : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_MH); }; +close_scope_monitor : { scanner_pop_start_cond(nft->scanner, PARSER_SC_CMD_MONITOR); }; +close_scope_nat : { scanner_pop_start_cond(nft->scanner, PARSER_SC_STMT_NAT); }; +close_scope_numgen : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_NUMGEN); }; +close_scope_osf : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_OSF); }; +close_scope_policy : { scanner_pop_start_cond(nft->scanner, PARSER_SC_POLICY); }; +close_scope_quota : { scanner_pop_start_cond(nft->scanner, PARSER_SC_QUOTA); }; +close_scope_queue : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_QUEUE); }; +close_scope_reject : { scanner_pop_start_cond(nft->scanner, PARSER_SC_STMT_REJECT); }; +close_scope_reset : { scanner_pop_start_cond(nft->scanner, PARSER_SC_CMD_RESET); }; +close_scope_rt : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_RT); }; +close_scope_sctp : { scanner_pop_start_cond(nft->scanner, PARSER_SC_SCTP); }; +close_scope_sctp_chunk : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_SCTP_CHUNK); }; +close_scope_secmark : { scanner_pop_start_cond(nft->scanner, PARSER_SC_SECMARK); }; +close_scope_socket : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_SOCKET); } +close_scope_tcp : { scanner_pop_start_cond(nft->scanner, PARSER_SC_TCP); }; +close_scope_tproxy : { scanner_pop_start_cond(nft->scanner, PARSER_SC_STMT_TPROXY); }; +close_scope_type : { scanner_pop_start_cond(nft->scanner, PARSER_SC_TYPE); }; +close_scope_th : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_TH); }; +close_scope_udp : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_UDP); }; +close_scope_udplite : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_UDPLITE); }; + +close_scope_log : { scanner_pop_start_cond(nft->scanner, PARSER_SC_STMT_LOG); } +close_scope_synproxy : { scanner_pop_start_cond(nft->scanner, PARSER_SC_STMT_SYNPROXY); } +close_scope_xt : { scanner_pop_start_cond(nft->scanner, PARSER_SC_XT); } + common_block : INCLUDE QUOTED_STRING stmt_separator { if (scanner_include_file(nft, scanner, $2, &@$) < 0) { - xfree($2); + free_const($2); YYERROR; } - xfree($2); + free_const($2); } | DEFINE identifier '=' initializer_expr stmt_separator { @@ -863,19 +1097,19 @@ common_block : INCLUDE QUOTED_STRING stmt_separator erec_queue(error(&@2, "redefinition of symbol '%s'", $2), state->msgs); expr_free($4); - xfree($2); + free_const($2); YYERROR; } symbol_bind(scope, $2, $4); - xfree($2); + free_const($2); } | REDEFINE identifier '=' initializer_expr stmt_separator { struct scope *scope = current_scope(state); symbol_bind(scope, $2, $4); - xfree($2); + free_const($2); } | UNDEFINE identifier stmt_separator { @@ -884,9 +1118,10 @@ common_block : INCLUDE QUOTED_STRING stmt_separator if (symbol_unbind(scope, $2) < 0) { erec_queue(error(&@2, "undefined symbol '%s'", $2), state->msgs); + free_const($2); YYERROR; } - xfree($2); + free_const($2); } | error stmt_separator { @@ -926,14 +1161,15 @@ base_cmd : /* empty */ add_cmd { $$ = $1; } | INSERT insert_cmd { $$ = $2; } | DELETE delete_cmd { $$ = $2; } | GET get_cmd { $$ = $2; } - | LIST list_cmd { $$ = $2; } - | RESET reset_cmd { $$ = $2; } + | LIST list_cmd close_scope_list { $$ = $2; } + | RESET reset_cmd close_scope_reset { $$ = $2; } | FLUSH flush_cmd { $$ = $2; } | RENAME rename_cmd { $$ = $2; } - | IMPORT import_cmd { $$ = $2; } - | EXPORT export_cmd { $$ = $2; } - | MONITOR monitor_cmd { $$ = $2; } + | IMPORT import_cmd close_scope_import { $$ = $2; } + | EXPORT export_cmd close_scope_export { $$ = $2; } + | MONITOR monitor_cmd close_scope_monitor { $$ = $2; } | DESCRIBE describe_cmd { $$ = $2; } + | DESTROY destroy_cmd close_scope_destroy { $$ = $2; } ; add_cmd : TABLE table_spec @@ -992,7 +1228,7 @@ add_cmd : TABLE table_spec handle_merge(&$3->handle, &$2); $$ = cmd_alloc(CMD_ADD, CMD_OBJ_FLOWTABLE, &$2, &@$, $5); } - | COUNTER obj_spec + | COUNTER obj_spec close_scope_counter { struct obj *obj; @@ -1001,35 +1237,55 @@ add_cmd : TABLE table_spec handle_merge(&obj->handle, &$2); $$ = cmd_alloc(CMD_ADD, CMD_OBJ_COUNTER, &$2, &@$, obj); } - | COUNTER obj_spec counter_obj counter_config + | COUNTER obj_spec counter_obj counter_config close_scope_counter { $$ = cmd_alloc(CMD_ADD, CMD_OBJ_COUNTER, &$2, &@$, $3); } - | QUOTA obj_spec quota_obj quota_config + | COUNTER obj_spec counter_obj '{' counter_block '}' close_scope_counter + { + $$ = cmd_alloc(CMD_ADD, CMD_OBJ_COUNTER, &$2, &@$, $3); + } + | QUOTA obj_spec quota_obj quota_config close_scope_quota { $$ = cmd_alloc(CMD_ADD, CMD_OBJ_QUOTA, &$2, &@$, $3); } - | CT HELPER obj_spec ct_obj_alloc '{' ct_helper_block '}' + | QUOTA obj_spec quota_obj '{' quota_block '}' close_scope_quota + { + $$ = cmd_alloc(CMD_ADD, CMD_OBJ_QUOTA, &$2, &@$, $3); + } + | CT HELPER obj_spec ct_obj_alloc '{' ct_helper_block '}' close_scope_ct { $$ = cmd_alloc_obj_ct(CMD_ADD, NFT_OBJECT_CT_HELPER, &$3, &@$, $4); } - | CT TIMEOUT obj_spec ct_obj_alloc '{' ct_timeout_block '}' + | CT TIMEOUT obj_spec ct_obj_alloc '{' ct_timeout_block '}' close_scope_ct { $$ = cmd_alloc_obj_ct(CMD_ADD, NFT_OBJECT_CT_TIMEOUT, &$3, &@$, $4); } - | CT EXPECTATION obj_spec ct_obj_alloc '{' ct_expect_block '}' + | CT EXPECTATION obj_spec ct_obj_alloc '{' ct_expect_block '}' close_scope_ct { $$ = cmd_alloc_obj_ct(CMD_ADD, NFT_OBJECT_CT_EXPECT, &$3, &@$, $4); } - | LIMIT obj_spec limit_obj limit_config + | LIMIT obj_spec limit_obj limit_config close_scope_limit { $$ = cmd_alloc(CMD_ADD, CMD_OBJ_LIMIT, &$2, &@$, $3); } - | SECMARK obj_spec secmark_obj secmark_config + | LIMIT obj_spec limit_obj '{' limit_block '}' close_scope_limit + { + $$ = cmd_alloc(CMD_ADD, CMD_OBJ_LIMIT, &$2, &@$, $3); + } + | SECMARK obj_spec secmark_obj secmark_config close_scope_secmark + { + $$ = cmd_alloc(CMD_ADD, CMD_OBJ_SECMARK, &$2, &@$, $3); + } + | SECMARK obj_spec secmark_obj '{' secmark_block '}' close_scope_secmark { $$ = cmd_alloc(CMD_ADD, CMD_OBJ_SECMARK, &$2, &@$, $3); } - | SYNPROXY obj_spec synproxy_obj synproxy_config + | SYNPROXY obj_spec synproxy_obj synproxy_config close_scope_synproxy + { + $$ = cmd_alloc(CMD_ADD, CMD_OBJ_SYNPROXY, &$2, &@$, $3); + } + | SYNPROXY obj_spec synproxy_obj '{' synproxy_block '}' close_scope_synproxy { $$ = cmd_alloc(CMD_ADD, CMD_OBJ_SYNPROXY, &$2, &@$, $3); } @@ -1089,7 +1345,7 @@ create_cmd : TABLE table_spec handle_merge(&$3->handle, &$2); $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_FLOWTABLE, &$2, &@$, $5); } - | COUNTER obj_spec + | COUNTER obj_spec close_scope_counter { struct obj *obj; @@ -1098,35 +1354,35 @@ create_cmd : TABLE table_spec handle_merge(&obj->handle, &$2); $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_COUNTER, &$2, &@$, obj); } - | COUNTER obj_spec counter_obj counter_config + | COUNTER obj_spec counter_obj counter_config close_scope_counter { $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_COUNTER, &$2, &@$, $3); } - | QUOTA obj_spec quota_obj quota_config + | QUOTA obj_spec quota_obj quota_config close_scope_quota { $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_QUOTA, &$2, &@$, $3); } - | CT HELPER obj_spec ct_obj_alloc '{' ct_helper_block '}' + | CT HELPER obj_spec ct_obj_alloc '{' ct_helper_block '}' close_scope_ct { $$ = cmd_alloc_obj_ct(CMD_CREATE, NFT_OBJECT_CT_HELPER, &$3, &@$, $4); } - | CT TIMEOUT obj_spec ct_obj_alloc '{' ct_timeout_block '}' + | CT TIMEOUT obj_spec ct_obj_alloc '{' ct_timeout_block '}' close_scope_ct { $$ = cmd_alloc_obj_ct(CMD_CREATE, NFT_OBJECT_CT_TIMEOUT, &$3, &@$, $4); } - | CT EXPECTATION obj_spec ct_obj_alloc '{' ct_expect_block '}' + | CT EXPECTATION obj_spec ct_obj_alloc '{' ct_expect_block '}' close_scope_ct { $$ = cmd_alloc_obj_ct(CMD_CREATE, NFT_OBJECT_CT_EXPECT, &$3, &@$, $4); } - | LIMIT obj_spec limit_obj limit_config + | LIMIT obj_spec limit_obj limit_config close_scope_limit { $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_LIMIT, &$2, &@$, $3); } - | SECMARK obj_spec secmark_obj secmark_config + | SECMARK obj_spec secmark_obj secmark_config close_scope_secmark { $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_SECMARK, &$2, &@$, $3); } - | SYNPROXY obj_spec synproxy_obj synproxy_config + | SYNPROXY obj_spec synproxy_obj synproxy_config close_scope_synproxy { $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_SYNPROXY, &$2, &@$, $3); } @@ -1138,31 +1394,43 @@ insert_cmd : RULE rule_position rule } ; -delete_cmd : TABLE table_spec - { - $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_TABLE, &$2, &@$, NULL); - } - | TABLE tableid_spec +table_or_id_spec : table_spec + | tableid_spec + ; + +chain_or_id_spec : chain_spec + | chainid_spec + ; + +set_or_id_spec : set_spec + | setid_spec + ; + +obj_or_id_spec : obj_spec + | objid_spec + ; + +delete_cmd : TABLE table_or_id_spec { $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_TABLE, &$2, &@$, NULL); } - | CHAIN chain_spec + | CHAIN chain_or_id_spec { $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_CHAIN, &$2, &@$, NULL); } - | CHAIN chainid_spec + | CHAIN chain_spec chain_block_alloc + '{' chain_block '}' { - $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_CHAIN, &$2, &@$, NULL); + $5->location = @5; + handle_merge(&$3->handle, &$2); + close_scope(state); + $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_CHAIN, &$2, &@$, $5); } | 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 + | SET set_or_id_spec { $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_SET, &$2, &@$, NULL); } @@ -1189,52 +1457,102 @@ delete_cmd : TABLE table_spec handle_merge(&$3->handle, &$2); $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_FLOWTABLE, &$2, &@$, $5); } - | COUNTER obj_spec + | COUNTER obj_or_id_spec close_scope_counter { $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_COUNTER, &$2, &@$, NULL); } - | COUNTER objid_spec + | QUOTA obj_or_id_spec close_scope_quota { - $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_COUNTER, &$2, &@$, NULL); + $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_QUOTA, &$2, &@$, NULL); } - | QUOTA obj_spec + | CT ct_obj_type obj_spec ct_obj_alloc close_scope_ct { - $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_QUOTA, &$2, &@$, NULL); + $$ = cmd_alloc_obj_ct(CMD_DELETE, $2, &$3, &@$, $4); + if ($2 == NFT_OBJECT_CT_TIMEOUT) + init_list_head(&$4->ct_timeout.timeout_list); } - | QUOTA objid_spec + | LIMIT obj_or_id_spec close_scope_limit { - $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_QUOTA, &$2, &@$, NULL); + $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_LIMIT, &$2, &@$, NULL); } - | CT ct_obj_type obj_spec ct_obj_alloc + | SECMARK obj_or_id_spec close_scope_secmark { - $$ = cmd_alloc_obj_ct(CMD_DELETE, $2, &$3, &@$, $4); + $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_SECMARK, &$2, &@$, NULL); } - | LIMIT obj_spec + | SYNPROXY obj_or_id_spec close_scope_synproxy { - $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_LIMIT, &$2, &@$, NULL); + $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_SYNPROXY, &$2, &@$, NULL); } - | LIMIT objid_spec + ; + +destroy_cmd : TABLE table_or_id_spec { - $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_LIMIT, &$2, &@$, NULL); + $$ = cmd_alloc(CMD_DESTROY, CMD_OBJ_TABLE, &$2, &@$, NULL); } - | SECMARK obj_spec + | CHAIN chain_or_id_spec { - $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_SECMARK, &$2, &@$, NULL); + $$ = cmd_alloc(CMD_DESTROY, CMD_OBJ_CHAIN, &$2, &@$, NULL); + } + | RULE ruleid_spec + { + $$ = cmd_alloc(CMD_DESTROY, CMD_OBJ_RULE, &$2, &@$, NULL); } - | SECMARK objid_spec + | SET set_or_id_spec { - $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_SECMARK, &$2, &@$, NULL); + $$ = cmd_alloc(CMD_DESTROY, CMD_OBJ_SET, &$2, &@$, NULL); } - | SYNPROXY obj_spec + | MAP set_spec { - $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_SYNPROXY, &$2, &@$, NULL); + $$ = cmd_alloc(CMD_DESTROY, CMD_OBJ_SET, &$2, &@$, NULL); } - | SYNPROXY objid_spec + | ELEMENT set_spec set_block_expr { - $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_SYNPROXY, &$2, &@$, NULL); + $$ = cmd_alloc(CMD_DESTROY, CMD_OBJ_ELEMENTS, &$2, &@$, $3); + } + | FLOWTABLE flowtable_spec + { + $$ = cmd_alloc(CMD_DESTROY, CMD_OBJ_FLOWTABLE, &$2, &@$, NULL); + } + | FLOWTABLE flowtableid_spec + { + $$ = cmd_alloc(CMD_DESTROY, CMD_OBJ_FLOWTABLE, &$2, &@$, NULL); + } + | FLOWTABLE flowtable_spec flowtable_block_alloc + '{' flowtable_block '}' + { + $5->location = @5; + handle_merge(&$3->handle, &$2); + $$ = cmd_alloc(CMD_DESTROY, CMD_OBJ_FLOWTABLE, &$2, &@$, $5); + } + | COUNTER obj_or_id_spec close_scope_counter + { + $$ = cmd_alloc(CMD_DESTROY, CMD_OBJ_COUNTER, &$2, &@$, NULL); + } + | QUOTA obj_or_id_spec close_scope_quota + { + $$ = cmd_alloc(CMD_DESTROY, CMD_OBJ_QUOTA, &$2, &@$, NULL); + } + | CT ct_obj_type obj_spec ct_obj_alloc close_scope_ct + { + $$ = cmd_alloc_obj_ct(CMD_DESTROY, $2, &$3, &@$, $4); + if ($2 == NFT_OBJECT_CT_TIMEOUT) + init_list_head(&$4->ct_timeout.timeout_list); + } + | LIMIT obj_or_id_spec close_scope_limit + { + $$ = cmd_alloc(CMD_DESTROY, CMD_OBJ_LIMIT, &$2, &@$, NULL); + } + | SECMARK obj_or_id_spec close_scope_secmark + { + $$ = cmd_alloc(CMD_DESTROY, CMD_OBJ_SECMARK, &$2, &@$, NULL); + } + | SYNPROXY obj_or_id_spec close_scope_synproxy + { + $$ = cmd_alloc(CMD_DESTROY, CMD_OBJ_SYNPROXY, &$2, &@$, NULL); } ; + get_cmd : ELEMENT set_spec set_block_expr { $$ = cmd_alloc(CMD_GET, CMD_OBJ_ELEMENTS, &$2, &@$, $3); @@ -1277,7 +1595,7 @@ list_cmd : TABLE table_spec { $$ = cmd_alloc(CMD_LIST, CMD_OBJ_COUNTERS, &$3, &@$, NULL); } - | COUNTER obj_spec + | COUNTER obj_spec close_scope_counter { $$ = cmd_alloc(CMD_LIST, CMD_OBJ_COUNTER, &$2, &@$, NULL); } @@ -1289,7 +1607,7 @@ list_cmd : TABLE table_spec { $$ = cmd_alloc(CMD_LIST, CMD_OBJ_QUOTAS, &$3, &@$, NULL); } - | QUOTA obj_spec + | QUOTA obj_spec close_scope_quota { $$ = cmd_alloc(CMD_LIST, CMD_OBJ_QUOTA, &$2, &@$, NULL); } @@ -1301,7 +1619,7 @@ list_cmd : TABLE table_spec { $$ = cmd_alloc(CMD_LIST, CMD_OBJ_LIMITS, &$3, &@$, NULL); } - | LIMIT obj_spec + | LIMIT obj_spec close_scope_limit { $$ = cmd_alloc(CMD_LIST, CMD_OBJ_LIMIT, &$2, &@$, NULL); } @@ -1313,7 +1631,7 @@ list_cmd : TABLE table_spec { $$ = cmd_alloc(CMD_LIST, CMD_OBJ_SECMARKS, &$3, &@$, NULL); } - | SECMARK obj_spec + | SECMARK obj_spec close_scope_secmark { $$ = cmd_alloc(CMD_LIST, CMD_OBJ_SECMARK, &$2, &@$, NULL); } @@ -1325,7 +1643,7 @@ list_cmd : TABLE table_spec { $$ = cmd_alloc(CMD_LIST, CMD_OBJ_SYNPROXYS, &$3, &@$, NULL); } - | SYNPROXY obj_spec + | SYNPROXY obj_spec close_scope_synproxy { $$ = cmd_alloc(CMD_LIST, CMD_OBJ_SYNPROXY, &$2, &@$, NULL); } @@ -1365,21 +1683,37 @@ list_cmd : TABLE table_spec { $$ = cmd_alloc(CMD_LIST, CMD_OBJ_MAP, &$2, &@$, NULL); } - | CT ct_obj_type obj_spec + | CT ct_obj_type obj_spec close_scope_ct { $$ = cmd_alloc_obj_ct(CMD_LIST, $2, &$3, &@$, NULL); } - | CT HELPERS TABLE table_spec + | CT ct_cmd_type TABLE table_spec close_scope_ct { - $$ = cmd_alloc(CMD_LIST, CMD_OBJ_CT_HELPERS, &$4, &@$, NULL); + $$ = cmd_alloc(CMD_LIST, $2, &$4, &@$, NULL); + } + | HOOKS basehook_spec + { + $$ = cmd_alloc(CMD_LIST, CMD_OBJ_HOOKS, &$2, &@$, NULL); + } + ; + +basehook_device_name : DEVICE STRING + { + $$ = $2; } - | CT TIMEOUT TABLE table_spec + ; + +basehook_spec : ruleset_spec { - $$ = cmd_alloc(CMD_LIST, CMD_OBJ_CT_TIMEOUT, &$4, &@$, NULL); + $$ = $1; } - | CT EXPECTATION TABLE table_spec + | ruleset_spec basehook_device_name { - $$ = cmd_alloc(CMD_LIST, CMD_OBJ_CT_EXPECT, &$4, &@$, NULL); + if ($2) { + $1.obj.name = $2; + $1.obj.location = @2; + } + $$ = $1; } ; @@ -1387,11 +1721,16 @@ reset_cmd : COUNTERS ruleset_spec { $$ = cmd_alloc(CMD_RESET, CMD_OBJ_COUNTERS, &$2, &@$, NULL); } + | COUNTERS table_spec + { + $$ = cmd_alloc(CMD_RESET, CMD_OBJ_COUNTERS, &$2, &@$, NULL); + } | COUNTERS TABLE table_spec { + /* alias of previous rule. */ $$ = cmd_alloc(CMD_RESET, CMD_OBJ_COUNTERS, &$3, &@$, NULL); } - | COUNTER obj_spec + | COUNTER obj_spec close_scope_counter { $$ = cmd_alloc(CMD_RESET, CMD_OBJ_COUNTER, &$2,&@$, NULL); } @@ -1403,10 +1742,53 @@ reset_cmd : COUNTERS ruleset_spec { $$ = cmd_alloc(CMD_RESET, CMD_OBJ_QUOTAS, &$3, &@$, NULL); } - | QUOTA obj_spec + | QUOTAS table_spec + { + /* alias of previous rule. */ + $$ = cmd_alloc(CMD_RESET, CMD_OBJ_QUOTAS, &$2, &@$, NULL); + } + | QUOTA obj_spec close_scope_quota { $$ = cmd_alloc(CMD_RESET, CMD_OBJ_QUOTA, &$2, &@$, NULL); } + | RULES ruleset_spec + { + $$ = cmd_alloc(CMD_RESET, CMD_OBJ_RULES, &$2, &@$, NULL); + } + | RULES table_spec + { + $$ = cmd_alloc(CMD_RESET, CMD_OBJ_TABLE, &$2, &@$, NULL); + } + | RULES TABLE table_spec + { + /* alias of previous rule. */ + $$ = cmd_alloc(CMD_RESET, CMD_OBJ_TABLE, &$3, &@$, NULL); + } + | RULES chain_spec + { + $$ = cmd_alloc(CMD_RESET, CMD_OBJ_CHAIN, &$2, &@$, NULL); + } + | RULES CHAIN chain_spec + { + /* alias of previous rule. */ + $$ = cmd_alloc(CMD_RESET, CMD_OBJ_CHAIN, &$3, &@$, NULL); + } + | RULE ruleid_spec + { + $$ = cmd_alloc(CMD_RESET, CMD_OBJ_RULE, &$2, &@$, NULL); + } + | ELEMENT set_spec set_block_expr + { + $$ = cmd_alloc(CMD_RESET, CMD_OBJ_ELEMENTS, &$2, &@$, $3); + } + | SET set_or_id_spec + { + $$ = cmd_alloc(CMD_RESET, CMD_OBJ_SET, &$2, &@$, NULL); + } + | MAP set_or_id_spec + { + $$ = cmd_alloc(CMD_RESET, CMD_OBJ_MAP, &$2, &@$, NULL); + } ; flush_cmd : TABLE table_spec @@ -1517,19 +1899,41 @@ describe_cmd : primary_expr table_block_alloc : /* empty */ { $$ = table_alloc(); - open_scope(state, &$$->scope); + if (open_scope(state, &$$->scope) < 0) { + erec_queue(error(&@$, "too many levels of nesting"), + state->msgs); + state->nerrs++; + } } ; -table_options : FLAGS STRING +table_options : FLAGS table_flags { - if (strcmp($2, "dormant") == 0) { - $<table>0->flags = TABLE_F_DORMANT; - xfree($2); - } else { - erec_queue(error(&@2, "unknown table option %s", $2), + $<table>0->flags |= $2; + } + | comment_spec + { + if (already_set($<table>0->comment, &@$, state)) { + free_const($1); + YYERROR; + } + $<table>0->comment = $1; + } + ; + +table_flags : table_flag + | table_flags COMMA table_flag + { + $$ = $1 | $3; + } + ; +table_flag : STRING + { + $$ = parse_table_flag($1); + free_const($1); + if ($$ == 0) { + erec_queue(error(&@1, "unknown table option %s", $1), state->msgs); - xfree($2); YYERROR; } } @@ -1583,7 +1987,7 @@ table_block : /* empty */ { $$ = $<table>-1; } } | table_block COUNTER obj_identifier obj_block_alloc '{' counter_block '}' - stmt_separator + stmt_separator close_scope_counter { $4->location = @3; $4->type = NFT_OBJECT_COUNTER; @@ -1594,7 +1998,7 @@ table_block : /* empty */ { $$ = $<table>-1; } } | table_block QUOTA obj_identifier obj_block_alloc '{' quota_block '}' - stmt_separator + stmt_separator close_scope_quota { $4->location = @3; $4->type = NFT_OBJECT_QUOTA; @@ -1603,7 +2007,7 @@ table_block : /* empty */ { $$ = $<table>-1; } list_add_tail(&$4->list, &$1->objs); $$ = $1; } - | table_block CT HELPER obj_identifier obj_block_alloc '{' ct_helper_block '}' stmt_separator + | table_block CT HELPER obj_identifier obj_block_alloc '{' ct_helper_block '}' stmt_separator close_scope_ct { $5->location = @4; $5->type = NFT_OBJECT_CT_HELPER; @@ -1612,7 +2016,7 @@ table_block : /* empty */ { $$ = $<table>-1; } list_add_tail(&$5->list, &$1->objs); $$ = $1; } - | table_block CT TIMEOUT obj_identifier obj_block_alloc '{' ct_timeout_block '}' stmt_separator + | table_block CT TIMEOUT obj_identifier obj_block_alloc '{' ct_timeout_block '}' stmt_separator close_scope_ct { $5->location = @4; $5->type = NFT_OBJECT_CT_TIMEOUT; @@ -1621,7 +2025,7 @@ table_block : /* empty */ { $$ = $<table>-1; } list_add_tail(&$5->list, &$1->objs); $$ = $1; } - | table_block CT EXPECTATION obj_identifier obj_block_alloc '{' ct_expect_block '}' stmt_separator + | table_block CT EXPECTATION obj_identifier obj_block_alloc '{' ct_expect_block '}' stmt_separator close_scope_ct { $5->location = @4; $5->type = NFT_OBJECT_CT_EXPECT; @@ -1632,7 +2036,7 @@ table_block : /* empty */ { $$ = $<table>-1; } } | table_block LIMIT obj_identifier obj_block_alloc '{' limit_block '}' - stmt_separator + stmt_separator close_scope_limit { $4->location = @3; $4->type = NFT_OBJECT_LIMIT; @@ -1643,7 +2047,7 @@ table_block : /* empty */ { $$ = $<table>-1; } } | table_block SECMARK obj_identifier obj_block_alloc '{' secmark_block '}' - stmt_separator + stmt_separator close_scope_secmark { $4->location = @3; $4->type = NFT_OBJECT_SECMARK; @@ -1654,7 +2058,7 @@ table_block : /* empty */ { $$ = $<table>-1; } } | table_block SYNPROXY obj_identifier obj_block_alloc '{' synproxy_block '}' - stmt_separator + stmt_separator close_scope_synproxy { $4->location = @3; $4->type = NFT_OBJECT_SYNPROXY; @@ -1667,8 +2071,12 @@ table_block : /* empty */ { $$ = $<table>-1; } chain_block_alloc : /* empty */ { - $$ = chain_alloc(NULL); - open_scope(state, &$$->scope); + $$ = chain_alloc(); + if (open_scope(state, &$$->scope) < 0) { + erec_queue(error(&@$, "too many levels of nesting"), + state->msgs); + state->nerrs++; + } } ; @@ -1683,6 +2091,23 @@ chain_block : /* empty */ { $$ = $<chain>-1; } list_add_tail(&$2->list, &$1->rules); $$ = $1; } + | chain_block DEVICES '=' flowtable_expr stmt_separator + { + if ($$->dev_expr) { + list_splice_init(&$4->expressions, &$$->dev_expr->expressions); + expr_free($4); + break; + } + $$->dev_expr = $4; + } + | chain_block comment_spec stmt_separator + { + if (already_set($1->comment, &@2, state)) { + free_const($2); + YYERROR; + } + $1->comment = $2; + } ; subchain_block : /* empty */ { $$ = $<chain>-1; } @@ -1694,6 +2119,49 @@ subchain_block : /* empty */ { $$ = $<chain>-1; } } ; +typeof_verdict_expr : primary_expr + { + struct expr *e = $1; + + if (e->etype == EXPR_SYMBOL && + strcmp("verdict", e->identifier) == 0) { + struct expr *v = verdict_expr_alloc(&@1, NF_ACCEPT, NULL); + + expr_free(e); + v->flags &= ~EXPR_F_CONSTANT; + e = v; + } + + if (expr_ops(e)->build_udata == NULL) { + erec_queue(error(&@1, "map data type '%s' lacks typeof serialization", expr_ops(e)->name), + state->msgs); + expr_free(e); + YYERROR; + } + $$ = e; + } + | typeof_expr DOT primary_expr + { + struct location rhs[] = { + [1] = @2, + [2] = @3, + }; + + $$ = handle_concat_expr(&@$, $$, $1, $3, rhs); + } + ; + +typeof_data_expr : INTERVAL typeof_expr + { + $2->flags |= EXPR_F_INTERVAL; + $$ = $2; + } + | typeof_verdict_expr + { + $$ = $1; + } + ; + typeof_expr : primary_expr { if (expr_ops($1)->build_udata == NULL) { @@ -1719,22 +2187,25 @@ typeof_expr : primary_expr set_block_alloc : /* empty */ { - $$ = set_alloc(NULL); + $$ = set_alloc(&internal_location); } ; +typeof_key_expr : TYPEOF typeof_expr { $$ = $2; } + | TYPE data_type_expr close_scope_type { $$ = $2; } + ; + set_block : /* empty */ { $$ = $<set>-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 + | set_block typeof_key_expr stmt_separator { - $1->key = $3; - datatype_set($1->key, $3->dtype); + if (already_set($1->key, &@2, state)) { + expr_free($2); + YYERROR; + } + + $1->key = $2; $$ = $1; } | set_block FLAGS set_flag_list stmt_separator @@ -1752,13 +2223,18 @@ set_block : /* empty */ { $$ = $<set>-1; } $1->gc_int = $3; $$ = $1; } - | set_block COUNTER stmt_separator + | set_block stateful_stmt_list stmt_separator { - $1->stmt = counter_stmt_alloc(&@$); + list_splice_tail($2, &$1->stmt_list); $$ = $1; + free($2); } | set_block ELEMENTS '=' set_block_expr { + if (already_set($1->init, &@2, state)) { + expr_free($4); + YYERROR; + } $1->init = $4; $$ = $1; } @@ -1768,6 +2244,15 @@ set_block : /* empty */ { $$ = $<set>-1; } $$ = $1; } | set_block set_mechanism stmt_separator + | set_block comment_spec stmt_separator + { + if (already_set($1->comment, &@2, state)) { + free_const($2); + YYERROR; + } + $1->comment = $2; + $$ = $1; + } ; set_block_expr : set_expr @@ -1789,10 +2274,29 @@ set_flag : CONSTANT { $$ = NFT_SET_CONSTANT; } map_block_alloc : /* empty */ { - $$ = set_alloc(NULL); + $$ = set_alloc(&internal_location); } ; +ct_obj_type_map : TIMEOUT { $$ = NFT_OBJECT_CT_TIMEOUT; } + | EXPECTATION { $$ = NFT_OBJECT_CT_EXPECT; } + ; + +map_block_obj_type : COUNTER close_scope_counter { $$ = NFT_OBJECT_COUNTER; } + | QUOTA close_scope_quota { $$ = NFT_OBJECT_QUOTA; } + | LIMIT close_scope_limit { $$ = NFT_OBJECT_LIMIT; } + | SECMARK close_scope_secmark { $$ = NFT_OBJECT_SECMARK; } + | SYNPROXY close_scope_synproxy { $$ = NFT_OBJECT_SYNPROXY; } + ; + +map_block_obj_typeof : map_block_obj_type + | CT ct_obj_type_map close_scope_ct { $$ = $2; } + ; + +map_block_data_interval : INTERVAL { $$ = EXPR_F_INTERVAL; } + | { $$ = 0; } + ; + map_block : /* empty */ { $$ = $<set>-1; } | map_block common_block | map_block stmt_separator @@ -1801,100 +2305,103 @@ map_block : /* empty */ { $$ = $<set>-1; } $1->timeout = $3; $$ = $1; } - | map_block TYPE - data_type_expr COLON data_type_expr - stmt_separator + | map_block GC_INTERVAL time_spec stmt_separator { - $1->key = $3; - $1->data = $5; - - $1->flags |= NFT_SET_MAP; + $1->gc_int = $3; $$ = $1; } | map_block TYPE - data_type_expr COLON INTERVAL data_type_expr - stmt_separator + data_type_expr COLON map_block_data_interval data_type_expr + stmt_separator close_scope_type { + if (already_set($1->key, &@2, state)) { + expr_free($3); + expr_free($6); + YYERROR; + } + $1->key = $3; $1->data = $6; - $1->data->flags |= EXPR_F_INTERVAL; + $1->data->flags |= $5; $1->flags |= NFT_SET_MAP; $$ = $1; } | map_block TYPEOF - typeof_expr COLON typeof_expr + typeof_expr COLON typeof_data_expr stmt_separator { - $1->key = $3; - datatype_set($1->key, $3->dtype); - $1->data = $5; + if (already_set($1->key, &@2, state)) { + expr_free($3); + expr_free($5); + YYERROR; + } - $1->flags |= NFT_SET_MAP; - $$ = $1; - } - | map_block TYPEOF - typeof_expr COLON INTERVAL typeof_expr - stmt_separator - { $1->key = $3; - datatype_set($1->key, $3->dtype); - $1->data = $6; - $1->data->flags |= EXPR_F_INTERVAL; - $1->flags |= NFT_SET_MAP; + if ($5->etype == EXPR_CT && $5->ct.key == NFT_CT_HELPER) { + $1->objtype = NFT_OBJECT_CT_HELPER; + $1->flags |= NFT_SET_OBJECT; + expr_free($5); + } else { + $1->data = $5; + $1->flags |= NFT_SET_MAP; + } + $$ = $1; } | map_block TYPE - data_type_expr COLON COUNTER - stmt_separator + data_type_expr COLON map_block_obj_type + stmt_separator close_scope_type { + if (already_set($1->key, &@2, state)) { + expr_free($3); + YYERROR; + } + $1->key = $3; - $1->objtype = NFT_OBJECT_COUNTER; + $1->objtype = $5; $1->flags |= NFT_SET_OBJECT; $$ = $1; } - | map_block TYPE - data_type_expr COLON QUOTA + | map_block TYPEOF + typeof_expr COLON map_block_obj_typeof stmt_separator { $1->key = $3; - $1->objtype = NFT_OBJECT_QUOTA; + $1->objtype = $5; $1->flags |= NFT_SET_OBJECT; $$ = $1; } - | map_block TYPE - data_type_expr COLON LIMIT - stmt_separator + | map_block FLAGS set_flag_list stmt_separator { - $1->key = $3; - $1->objtype = NFT_OBJECT_LIMIT; - $1->flags |= NFT_SET_OBJECT; + $1->flags |= $3; $$ = $1; } - | map_block TYPE - data_type_expr COLON SECMARK - stmt_separator + | map_block stateful_stmt_list stmt_separator { - $1->key = $3; - $1->objtype = NFT_OBJECT_SECMARK; - $1->flags |= NFT_SET_OBJECT; + list_splice_tail($2, &$1->stmt_list); $$ = $1; + free($2); } - | map_block FLAGS set_flag_list stmt_separator + | map_block ELEMENTS '=' set_block_expr { - $1->flags |= $3; + $1->init = $4; $$ = $1; } - | map_block ELEMENTS '=' set_block_expr + | map_block comment_spec stmt_separator { - $1->init = $4; + if (already_set($1->comment, &@2, state)) { + free_const($2); + YYERROR; + } + $1->comment = $2; $$ = $1; } | map_block set_mechanism stmt_separator ; -set_mechanism : POLICY set_policy_spec +set_mechanism : POLICY set_policy_spec close_scope_policy { $<set>0->policy = $2; } @@ -1910,7 +2417,7 @@ set_policy_spec : PERFORMANCE { $$ = NFT_SET_POL_PERFORMANCE; } flowtable_block_alloc : /* empty */ { - $$ = flowtable_alloc(NULL); + $$ = flowtable_alloc(&internal_location); } ; @@ -1924,10 +2431,10 @@ flowtable_block : /* empty */ { $$ = $<flowtable>-1; } if ($$->hook.name == NULL) { erec_queue(error(&@3, "unknown chain hook"), state->msgs); - xfree($3); + free_const($3); YYERROR; } - xfree($3); + free_const($3); $$->priority = $4; } @@ -1935,10 +2442,14 @@ flowtable_block : /* empty */ { $$ = $<flowtable>-1; } { $$->dev_expr = $4; } - | flowtable_block COUNTER + | flowtable_block COUNTER close_scope_counter { $$->flags |= NFT_FLOWTABLE_COUNTER; } + | flowtable_block FLAGS OFFLOAD stmt_separator + { + $$->flags |= FLOWTABLE_F_HW_OFFLOAD; + } ; flowtable_expr : '{' flowtable_list_expr '}' @@ -1966,12 +2477,23 @@ flowtable_list_expr : flowtable_expr_member | flowtable_list_expr COMMA opt_newline ; -flowtable_expr_member : STRING +flowtable_expr_member : QUOTED_STRING { - $$ = constant_expr_alloc(&@$, &string_type, - BYTEORDER_HOST_ENDIAN, - strlen($1) * BITS_PER_BYTE, $1); - xfree($1); + struct expr *expr = ifname_expr_alloc(&@$, state->msgs, $1); + + if (!expr) + YYERROR; + + $$ = expr; + } + | STRING + { + struct expr *expr = ifname_expr_alloc(&@$, state->msgs, $1); + + if (!expr) + YYERROR; + + $$ = expr; } | variable_expr { @@ -1986,11 +2508,12 @@ data_type_atom_expr : type_identifier if (dtype == NULL) { erec_queue(error(&@1, "unknown datatype %s", $1), state->msgs); + free_const($1); YYERROR; } $$ = constant_expr_alloc(&@1, dtype, dtype->byteorder, dtype->size, NULL); - xfree($1); + free_const($1); } | TIME { @@ -2013,7 +2536,7 @@ data_type_expr : data_type_atom_expr obj_block_alloc : /* empty */ { - $$ = obj_alloc(NULL); + $$ = obj_alloc(&internal_location); } ; @@ -2024,6 +2547,14 @@ counter_block : /* empty */ { $$ = $<obj>-1; } { $$ = $1; } + | counter_block comment_spec + { + if (already_set($<obj>1->comment, &@2, state)) { + free_const($2); + YYERROR; + } + $<obj>1->comment = $2; + } ; quota_block : /* empty */ { $$ = $<obj>-1; } @@ -2033,6 +2564,14 @@ quota_block : /* empty */ { $$ = $<obj>-1; } { $$ = $1; } + | quota_block comment_spec + { + if (already_set($<obj>1->comment, &@2, state)) { + free_const($2); + YYERROR; + } + $<obj>1->comment = $2; + } ; ct_helper_block : /* empty */ { $$ = $<obj>-1; } @@ -2042,12 +2581,21 @@ ct_helper_block : /* empty */ { $$ = $<obj>-1; } { $$ = $1; } + | ct_helper_block comment_spec + { + if (already_set($<obj>1->comment, &@2, state)) { + free_const($2); + YYERROR; + } + $<obj>1->comment = $2; + } ; ct_timeout_block : /*empty */ { $$ = $<obj>-1; init_list_head(&$$->ct_timeout.timeout_list); + $$->type = NFT_OBJECT_CT_TIMEOUT; } | ct_timeout_block common_block | ct_timeout_block stmt_separator @@ -2055,6 +2603,14 @@ ct_timeout_block : /*empty */ { $$ = $1; } + | ct_timeout_block comment_spec + { + if (already_set($<obj>1->comment, &@2, state)) { + free_const($2); + YYERROR; + } + $<obj>1->comment = $2; + } ; ct_expect_block : /*empty */ { $$ = $<obj>-1; } @@ -2064,6 +2620,14 @@ ct_expect_block : /*empty */ { $$ = $<obj>-1; } { $$ = $1; } + | ct_expect_block comment_spec + { + if (already_set($<obj>1->comment, &@2, state)) { + free_const($2); + YYERROR; + } + $<obj>1->comment = $2; + } ; limit_block : /* empty */ { $$ = $<obj>-1; } @@ -2073,6 +2637,14 @@ limit_block : /* empty */ { $$ = $<obj>-1; } { $$ = $1; } + | limit_block comment_spec + { + if (already_set($<obj>1->comment, &@2, state)) { + free_const($2); + YYERROR; + } + $<obj>1->comment = $2; + } ; secmark_block : /* empty */ { $$ = $<obj>-1; } @@ -2082,6 +2654,14 @@ secmark_block : /* empty */ { $$ = $<obj>-1; } { $$ = $1; } + | secmark_block comment_spec + { + if (already_set($<obj>1->comment, &@2, state)) { + free_const($2); + YYERROR; + } + $<obj>1->comment = $2; + } ; synproxy_block : /* empty */ { $$ = $<obj>-1; } @@ -2091,6 +2671,14 @@ synproxy_block : /* empty */ { $$ = $<obj>-1; } { $$ = $1; } + | synproxy_block comment_spec + { + if (already_set($<obj>1->comment, &@2, state)) { + free_const($2); + YYERROR; + } + $<obj>1->comment = $2; + } ; type_identifier : STRING { $$ = $1; } @@ -2100,32 +2688,38 @@ type_identifier : STRING { $$ = $1; } | CLASSID { $$ = xstrdup("classid"); } ; -hook_spec : TYPE STRING HOOK STRING dev_spec prio_spec +hook_spec : TYPE close_scope_type STRING HOOK STRING dev_spec prio_spec { - const char *chain_type = chain_type_name_lookup($2); + const char *chain_type = chain_type_name_lookup($3); if (chain_type == NULL) { - erec_queue(error(&@2, "unknown chain type"), + erec_queue(error(&@3, "unknown chain type"), state->msgs); - xfree($2); + free_const($3); + free_const($5); + expr_free($6); + expr_free($7.expr); YYERROR; } - $<chain>0->type = xstrdup(chain_type); - xfree($2); + $<chain>0->type.loc = @3; + $<chain>0->type.str = xstrdup(chain_type); + free_const($3); $<chain>0->loc = @$; - $<chain>0->hook.loc = @4; - $<chain>0->hook.name = chain_hookname_lookup($4); + $<chain>0->hook.loc = @5; + $<chain>0->hook.name = chain_hookname_lookup($5); if ($<chain>0->hook.name == NULL) { - erec_queue(error(&@4, "unknown chain hook"), + erec_queue(error(&@5, "unknown chain hook"), state->msgs); - xfree($4); + free_const($5); + expr_free($6); + expr_free($7.expr); YYERROR; } - xfree($4); + free_const($5); - $<chain>0->dev_expr = $5; - $<chain>0->priority = $6; + $<chain>0->dev_expr = $6; + $<chain>0->priority = $7; $<chain>0->flags |= CHAIN_F_BASECHAIN; } ; @@ -2169,7 +2763,7 @@ extended_prio_spec : int_num BYTEORDER_HOST_ENDIAN, strlen($1) * BITS_PER_BYTE, $1); - xfree($1); + free_const($1); $$ = spec; } | extended_prio_name PLUS NUM @@ -2182,7 +2776,7 @@ extended_prio_spec : int_num BYTEORDER_HOST_ENDIAN, strlen(str) * BITS_PER_BYTE, str); - xfree($1); + free_const($1); $$ = spec; } | extended_prio_name DASH NUM @@ -2195,7 +2789,7 @@ extended_prio_spec : int_num BYTEORDER_HOST_ENDIAN, strlen(str) * BITS_PER_BYTE, str); - xfree($1); + free_const($1); $$ = spec; } ; @@ -2206,12 +2800,11 @@ int_num : NUM { $$ = $1; } dev_spec : DEVICE string { - struct expr *expr; + struct expr *expr = ifname_expr_alloc(&@$, state->msgs, $2); + + if (!expr) + YYERROR; - 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); @@ -2235,7 +2828,7 @@ flags_spec : FLAGS OFFLOAD } ; -policy_spec : POLICY policy_expr +policy_spec : POLICY policy_expr close_scope_policy { if ($<chain>0->policy) { erec_queue(error(&@$, "you cannot set chain policy twice"), @@ -2267,6 +2860,7 @@ chain_policy : ACCEPT { $$ = NF_ACCEPT; } ; identifier : STRING + | LAST { $$ = xstrdup("last"); } ; string : STRING @@ -2280,7 +2874,7 @@ time_spec : STRING uint64_t res; erec = time_parse(&@1, $1, &res); - xfree($1); + free_const($1); if (erec != NULL) { erec_queue(erec, state->msgs); YYERROR; @@ -2289,16 +2883,21 @@ time_spec : STRING } ; +/* compatibility kludge to allow either 60, 60s, 1m, ... */ +time_spec_or_num_s : NUM + | time_spec { $$ = $1 / 1000u; } + ; + 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; } +family_spec_explicit : IP close_scope_ip { $$ = NFPROTO_IPV4; } + | IP6 close_scope_ip6 { $$ = NFPROTO_IPV6; } + | INET { $$ = NFPROTO_INET; } + | ARP close_scope_arp { $$ = NFPROTO_ARP; } + | BRIDGE { $$ = NFPROTO_BRIDGE; } + | NETDEV { $$ = NFPROTO_NETDEV; } ; table_spec : family_spec identifier @@ -2476,6 +3075,7 @@ comment_spec : COMMENT string erec_queue(error(&@2, "comment too long, %d characters maximum allowed", NFTNL_UDATA_COMMENT_MAXLEN), state->msgs); + free_const($2); YYERROR; } $$ = $2; @@ -2512,7 +3112,7 @@ rule_alloc : stmt_list list_for_each_entry(i, $1, list) $$->num_stmts++; list_splice_tail($1, &$$->stmts); - xfree($1); + free($1); } ; @@ -2529,10 +3129,78 @@ stmt_list : stmt } ; -stateful_stmt : counter_stmt +stateful_stmt_list : stateful_stmt + { + $$ = xmalloc(sizeof(*$$)); + init_list_head($$); + list_add_tail(&$1->list, $$); + } + | stateful_stmt_list stateful_stmt + { + $$ = $1; + list_add_tail(&$2->list, $1); + } + ; + +objref_stmt_counter : COUNTER NAME stmt_expr close_scope_counter + { + $$ = objref_stmt_alloc(&@$); + $$->objref.type = NFT_OBJECT_COUNTER; + $$->objref.expr = $3; + } + ; + +objref_stmt_limit : LIMIT NAME stmt_expr close_scope_limit + { + $$ = objref_stmt_alloc(&@$); + $$->objref.type = NFT_OBJECT_LIMIT; + $$->objref.expr = $3; + } + ; + +objref_stmt_quota : QUOTA NAME stmt_expr close_scope_quota + { + $$ = objref_stmt_alloc(&@$); + $$->objref.type = NFT_OBJECT_QUOTA; + $$->objref.expr = $3; + } + ; + +objref_stmt_synproxy : SYNPROXY NAME stmt_expr close_scope_synproxy + { + $$ = objref_stmt_alloc(&@$); + $$->objref.type = NFT_OBJECT_SYNPROXY; + $$->objref.expr = $3; + } + ; + +objref_stmt_ct : CT TIMEOUT SET stmt_expr close_scope_ct + { + $$ = objref_stmt_alloc(&@$); + $$->objref.type = NFT_OBJECT_CT_TIMEOUT; + $$->objref.expr = $4; + + } + | CT EXPECTATION SET stmt_expr close_scope_ct + { + $$ = objref_stmt_alloc(&@$); + $$->objref.type = NFT_OBJECT_CT_EXPECT; + $$->objref.expr = $4; + } + ; + +objref_stmt : objref_stmt_counter + | objref_stmt_limit + | objref_stmt_quota + | objref_stmt_synproxy + | objref_stmt_ct + ; + +stateful_stmt : counter_stmt close_scope_counter | limit_stmt | quota_stmt | connlimit_stmt + | last_stmt close_scope_last ; stmt : verdict_stmt @@ -2541,20 +3209,34 @@ stmt : verdict_stmt | payload_stmt | stateful_stmt | meta_stmt - | log_stmt - | reject_stmt - | nat_stmt - | tproxy_stmt + | log_stmt close_scope_log + | reject_stmt close_scope_reject + | nat_stmt close_scope_nat + | tproxy_stmt close_scope_tproxy | queue_stmt | ct_stmt - | masq_stmt - | redir_stmt - | dup_stmt - | fwd_stmt + | masq_stmt close_scope_nat + | redir_stmt close_scope_nat + | dup_stmt close_scope_dup + | fwd_stmt close_scope_fwd | set_stmt | map_stmt - | synproxy_stmt + | synproxy_stmt close_scope_synproxy | chain_stmt + | optstrip_stmt + | xt_stmt close_scope_xt + | objref_stmt + ; + +xt_stmt : XT STRING string + { + $$ = NULL; + free_const($2); + free_const($3); + erec_queue(error(&@$, "unsupported xtables compat expression, use iptables-nft with this ruleset"), + state->msgs); + YYERROR; + } ; chain_stmt_type : JUMP { $$ = NFT_JUMP; } @@ -2609,16 +3291,16 @@ verdict_map_list_expr : verdict_map_list_member_expr verdict_map_list_member_expr: opt_newline set_elem_expr COLON verdict_expr opt_newline { - $$ = mapping_expr_alloc(&@$, $2, $4); + $$ = mapping_expr_alloc(&@2, $2, $4); } ; -connlimit_stmt : CT COUNT NUM +connlimit_stmt : CT COUNT NUM close_scope_ct { $$ = connlimit_stmt_alloc(&@$); $$->connlimit.count = $3; } - | CT COUNT OVER NUM + | CT COUNT OVER NUM close_scope_ct { $$ = connlimit_stmt_alloc(&@$); $$->connlimit.count = $4; @@ -2633,12 +3315,6 @@ 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 @@ -2650,14 +3326,32 @@ counter_args : counter_arg counter_arg : PACKETS NUM { + assert($<stmt>0->ops->type == STMT_COUNTER); $<stmt>0->counter.packets = $2; } | BYTES NUM { + assert($<stmt>0->ops->type == STMT_COUNTER); $<stmt>0->counter.bytes = $2; } ; +last_stmt : LAST + { + $$ = last_stmt_alloc(&@$); + } + | LAST USED NEVER + { + $$ = last_stmt_alloc(&@$); + } + | LAST USED time_spec + { + $$ = last_stmt_alloc(&@$); + $$->last.used = $3; + $$->last.set = true; + } + ; + log_stmt : log_stmt_alloc | log_stmt_alloc log_args ; @@ -2678,127 +3372,19 @@ log_args : log_arg log_arg : PREFIX string { struct scope *scope = current_scope(state); - bool done = false, another_var = false; - char *start, *end, scratch = '\0'; - struct expr *expr, *item; - struct symbol *sym; - enum { - PARSE_TEXT, - PARSE_VAR, - } prefix_state; - - /* No variables in log prefix, skip. */ - if (!strchr($2, '$')) { - expr = constant_expr_alloc(&@$, &string_type, - BYTEORDER_HOST_ENDIAN, - (strlen($2) + 1) * BITS_PER_BYTE, $2); - xfree($2); - $<stmt>0->log.prefix = expr; - $<stmt>0->log.flags |= STMT_LOG_PREFIX; - break; - } - - /* Parse variables in log prefix string using a - * state machine parser with two states. This - * parser creates list of expressions composed - * of constant and variable expressions. - */ - expr = compound_expr_alloc(&@$, EXPR_LIST); - - start = (char *)$2; + struct error_record *erec; + const char *prefix; - if (*start != '$') { - prefix_state = PARSE_TEXT; - } else { - prefix_state = PARSE_VAR; - start++; - } - end = start; - - /* Not nice, but works. */ - while (!done) { - switch (prefix_state) { - case PARSE_TEXT: - while (*end != '\0' && *end != '$') - end++; - - if (*end == '\0') - done = true; - - *end = '\0'; - item = constant_expr_alloc(&@$, &string_type, - BYTEORDER_HOST_ENDIAN, - (strlen(start) + 1) * BITS_PER_BYTE, - start); - compound_expr_add(expr, item); - - if (done) - break; - - start = end + 1; - end = start; - - /* fall through */ - case PARSE_VAR: - while (isalnum(*end) || *end == '_') - end++; - - if (*end == '\0') - done = true; - else if (*end == '$') - another_var = true; - else - scratch = *end; - - *end = '\0'; - - sym = symbol_get(scope, start); - if (!sym) { - sym = symbol_lookup_fuzzy(scope, start); - if (sym) { - erec_queue(error(&@2, "unknown identifier '%s'; " - "did you mean identifier ‘%s’?", - start, sym->identifier), - state->msgs); - } else { - erec_queue(error(&@2, "unknown identifier '%s'", - start), - state->msgs); - } - expr_free(expr); - xfree($2); - YYERROR; - } - item = variable_expr_alloc(&@$, scope, sym); - compound_expr_add(expr, item); - - if (done) - break; - - /* Restore original byte after - * symbol lookup. - */ - if (scratch) { - *end = scratch; - scratch = '\0'; - } - - start = end; - if (another_var) { - another_var = false; - start++; - prefix_state = PARSE_VAR; - } else { - prefix_state = PARSE_TEXT; - } - end = start; - break; - } + prefix = str_preprocess(state, &@2, scope, $2, &erec); + if (!prefix) { + erec_queue(erec, state->msgs); + free_const($2); + YYERROR; } - xfree($2); - $<stmt>0->log.prefix = expr; - $<stmt>0->log.flags |= STMT_LOG_PREFIX; + free_const($2); + $<stmt>0->log.prefix = prefix; + $<stmt>0->log.flags |= STMT_LOG_PREFIX; } | GROUP NUM { @@ -2849,18 +3435,18 @@ level_type : string else { erec_queue(error(&@1, "invalid log level"), state->msgs); - xfree($1); + free_const($1); YYERROR; } - xfree($1); + free_const($1); } ; -log_flags : TCP log_flags_tcp +log_flags : TCP log_flags_tcp close_scope_tcp { $$ = $2; } - | IP OPTIONS + | IP OPTIONS close_scope_ip { $$ = NF_LOG_IPOPT; } @@ -2868,7 +3454,7 @@ log_flags : TCP log_flags_tcp { $$ = NF_LOG_UID; } - | ETHER + | ETHER close_scope_eth { $$ = NF_LOG_MACDECODE; } @@ -2895,40 +3481,29 @@ log_flag_tcp : SEQUENCE } ; -limit_stmt : LIMIT RATE limit_mode NUM SLASH time_unit limit_burst_pkts +limit_stmt : LIMIT RATE limit_mode limit_rate_pkts limit_burst_pkts close_scope_limit { + if ($5 == 0) { + erec_queue(error(&@5, "packet limit burst must be > 0"), + state->msgs); + YYERROR; + } $$ = limit_stmt_alloc(&@$); - $$->limit.rate = $4; - $$->limit.unit = $6; - $$->limit.burst = $7; + $$->limit.rate = $4.rate; + $$->limit.unit = $4.unit; + $$->limit.burst = $5; $$->limit.type = NFT_LIMIT_PKTS; $$->limit.flags = $3; } - | LIMIT RATE limit_mode NUM STRING limit_burst_bytes + | LIMIT RATE limit_mode limit_rate_bytes limit_burst_bytes close_scope_limit { - 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.rate = $4.rate; + $$->limit.unit = $4.unit; + $$->limit.burst = $5; $$->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; } @@ -2947,7 +3522,7 @@ quota_used : /* empty */ { $$ = 0; } uint64_t rate; erec = data_unit_parse(&@$, $3, &rate); - xfree($3); + free_const($3); if (erec != NULL) { erec_queue(erec, state->msgs); YYERROR; @@ -2956,13 +3531,13 @@ quota_used : /* empty */ { $$ = 0; } } ; -quota_stmt : QUOTA quota_mode NUM quota_unit quota_used +quota_stmt : QUOTA quota_mode NUM quota_unit quota_used close_scope_quota { struct error_record *erec; uint64_t rate; erec = data_unit_parse(&@$, $4, &rate); - xfree($4); + free_const($4); if (erec != NULL) { erec_queue(erec, state->msgs); YYERROR; @@ -2972,12 +3547,6 @@ quota_stmt : QUOTA quota_mode NUM quota_unit quota_used $$->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; } @@ -2985,24 +3554,55 @@ limit_mode : OVER { $$ = NFT_LIMIT_F_INV; } | /* empty */ { $$ = 0; } ; -limit_burst_pkts : /* empty */ { $$ = 0; } +limit_burst_pkts : /* empty */ { $$ = 5; } | BURST NUM PACKETS { $$ = $2; } ; +limit_rate_pkts : NUM SLASH time_unit + { + $$.rate = $1; + $$.unit = $3; + } + ; + limit_burst_bytes : /* empty */ { $$ = 0; } - | BURST NUM BYTES { $$ = $2; } - | BURST NUM STRING + | BURST limit_bytes { $$ = $2; } + ; + +limit_rate_bytes : NUM STRING + { + struct error_record *erec; + uint64_t rate, unit; + + erec = rate_parse(&@$, $2, &rate, &unit); + free_const($2); + if (erec != NULL) { + erec_queue(erec, state->msgs); + YYERROR; + } + $$.rate = rate * $1; + $$.unit = unit; + } + | limit_bytes SLASH time_unit + { + $$.rate = $1; + $$.unit = $3; + } + ; + +limit_bytes : NUM BYTES { $$ = $1; } + | NUM STRING { struct error_record *erec; uint64_t rate; - erec = data_unit_parse(&@$, $3, &rate); - xfree($3); + erec = data_unit_parse(&@$, $2, &rate); + free_const($2); if (erec != NULL) { erec_queue(erec, state->msgs); YYERROR; } - $$ = $2 * rate; + $$ = $1 * rate; } ; @@ -3022,44 +3622,61 @@ reject_stmt_alloc : _REJECT } ; +reject_with_expr : STRING + { + $$ = symbol_expr_alloc(&@$, SYMBOL_VALUE, + current_scope(state), $1); + free_const($1); + } + | integer_expr { $$ = $1; } + ; + reject_opts : /* empty */ { $<stmt>0->reject.type = -1; $<stmt>0->reject.icmp_code = -1; } - | WITH ICMP TYPE STRING + | WITH ICMP TYPE reject_with_expr close_scope_type close_scope_icmp + { + $<stmt>0->reject.family = NFPROTO_IPV4; + $<stmt>0->reject.type = NFT_REJECT_ICMP_UNREACH; + $<stmt>0->reject.expr = $4; + datatype_set($<stmt>0->reject.expr, &reject_icmp_code_type); + } + | WITH ICMP reject_with_expr { $<stmt>0->reject.family = NFPROTO_IPV4; $<stmt>0->reject.type = NFT_REJECT_ICMP_UNREACH; - $<stmt>0->reject.expr = - symbol_expr_alloc(&@$, SYMBOL_VALUE, - current_scope(state), - $4); - datatype_set($<stmt>0->reject.expr, &icmp_code_type); - xfree($4); + $<stmt>0->reject.expr = $3; + datatype_set($<stmt>0->reject.expr, &reject_icmp_code_type); + } + | WITH ICMP6 TYPE reject_with_expr close_scope_type close_scope_icmp + { + $<stmt>0->reject.family = NFPROTO_IPV6; + $<stmt>0->reject.type = NFT_REJECT_ICMP_UNREACH; + $<stmt>0->reject.expr = $4; + datatype_set($<stmt>0->reject.expr, &reject_icmpv6_code_type); } - | WITH ICMP6 TYPE STRING + | WITH ICMP6 reject_with_expr { $<stmt>0->reject.family = NFPROTO_IPV6; $<stmt>0->reject.type = NFT_REJECT_ICMP_UNREACH; - $<stmt>0->reject.expr = - symbol_expr_alloc(&@$, SYMBOL_VALUE, - current_scope(state), - $4); - datatype_set($<stmt>0->reject.expr, &icmpv6_code_type); - xfree($4); + $<stmt>0->reject.expr = $3; + datatype_set($<stmt>0->reject.expr, &reject_icmpv6_code_type); } - | WITH ICMPX TYPE STRING + | WITH ICMPX TYPE reject_with_expr close_scope_type { $<stmt>0->reject.type = NFT_REJECT_ICMPX_UNREACH; - $<stmt>0->reject.expr = - symbol_expr_alloc(&@$, SYMBOL_VALUE, - current_scope(state), - $4); - datatype_set($<stmt>0->reject.expr, &icmpx_code_type); - xfree($4); + $<stmt>0->reject.expr = $4; + datatype_set($<stmt>0->reject.expr, &reject_icmpx_code_type); } - | WITH TCP RESET + | WITH ICMPX reject_with_expr + { + $<stmt>0->reject.type = NFT_REJECT_ICMPX_UNREACH; + $<stmt>0->reject.expr = $3; + datatype_set($<stmt>0->reject.expr, &reject_icmpx_code_type); + } + | WITH TCP close_scope_tcp RESET close_scope_reset { $<stmt>0->reject.type = NFT_REJECT_TCP_RST; } @@ -3068,8 +3685,8 @@ reject_opts : /* empty */ 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); } +nat_stmt_alloc : SNAT { $$ = nat_stmt_alloc(&@$, __NFT_NAT_SNAT); } + | DNAT { $$ = nat_stmt_alloc(&@$, __NFT_NAT_DNAT); } ; tproxy_stmt : TPROXY TO stmt_expr @@ -3120,12 +3737,6 @@ 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 @@ -3149,7 +3760,7 @@ synproxy_arg : MSS NUM { $<stmt>0->synproxy.flags |= NF_SYNPROXY_OPT_TIMESTAMP; } - | SACKPERM + | SACK_PERM { $<stmt>0->synproxy.flags |= NF_SYNPROXY_OPT_SACK_PERM; } @@ -3204,7 +3815,7 @@ synproxy_ts : /* empty */ { $$ = 0; } ; synproxy_sack : /* empty */ { $$ = 0; } - | SACKPERM + | SACK_PERM { $$ = NF_SYNPROXY_OPT_SACK_PERM; } @@ -3295,20 +3906,8 @@ range_stmt_expr : basic_stmt_expr DASH basic_stmt_expr } ; -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 @@ -3367,28 +3966,24 @@ nat_stmt_args : stmt_expr { $<stmt>0->nat.family = $1; $<stmt>0->nat.addr = $4; - $<stmt>0->nat.type_flags = STMT_NAT_F_INTERVAL; } | INTERVAL TO stmt_expr { $<stmt>0->nat.addr = $3; - $<stmt>0->nat.type_flags = STMT_NAT_F_INTERVAL; } | nf_key_proto PREFIX TO stmt_expr { $<stmt>0->nat.family = $1; $<stmt>0->nat.addr = $4; $<stmt>0->nat.type_flags = - STMT_NAT_F_PREFIX | - STMT_NAT_F_INTERVAL; + STMT_NAT_F_PREFIX; $<stmt>0->nat.flags |= NF_NAT_RANGE_NETMAP; } | PREFIX TO stmt_expr { $<stmt>0->nat.addr = $3; $<stmt>0->nat.type_flags = - STMT_NAT_F_PREFIX | - STMT_NAT_F_INTERVAL; + STMT_NAT_F_PREFIX; $<stmt>0->nat.flags |= NF_NAT_RANGE_NETMAP; } ; @@ -3485,13 +4080,28 @@ nf_nat_flag : RANDOM { $$ = NF_NAT_RANGE_PROTO_RANDOM; } | PERSISTENT { $$ = NF_NAT_RANGE_PERSISTENT; } ; -queue_stmt : queue_stmt_alloc +queue_stmt : queue_stmt_compat close_scope_queue + | QUEUE TO queue_stmt_expr close_scope_queue + { + $$ = queue_stmt_alloc(&@$, $3, 0); + } + | QUEUE FLAGS queue_stmt_flags TO queue_stmt_expr close_scope_queue + { + $$ = queue_stmt_alloc(&@$, $5, $3); + } + | QUEUE FLAGS queue_stmt_flags QUEUENUM queue_stmt_expr_simple close_scope_queue + { + $$ = queue_stmt_alloc(&@$, $5, $3); + } + ; + +queue_stmt_compat : queue_stmt_alloc | queue_stmt_alloc queue_stmt_args ; queue_stmt_alloc : QUEUE { - $$ = queue_stmt_alloc(&@$); + $$ = queue_stmt_alloc(&@$, NULL, 0); } ; @@ -3502,7 +4112,7 @@ queue_stmt_args : queue_stmt_arg | queue_stmt_args queue_stmt_arg ; -queue_stmt_arg : QUEUENUM stmt_expr +queue_stmt_arg : QUEUENUM queue_stmt_expr_simple { $<stmt>0->queue.queue = $2; $<stmt>0->queue.queue->location = @$; @@ -3513,6 +4123,24 @@ queue_stmt_arg : QUEUENUM stmt_expr } ; +queue_expr : variable_expr + | integer_expr + ; + +queue_stmt_expr_simple : integer_expr + | variable_expr + | queue_expr DASH queue_expr + { + $$ = range_expr_alloc(&@$, $1, $3); + } + ; + +queue_stmt_expr : numgen_expr + | hash_expr + | map_expr + | queue_stmt_expr_simple + ; + queue_stmt_flags : queue_stmt_flag | queue_stmt_flags COMMA queue_stmt_flag { @@ -3548,13 +4176,14 @@ set_stmt : SET set_stmt_op set_elem_expr_stmt set_ref_expr $$->set.key = $4; $$->set.set = $2; } - | set_stmt_op set_ref_expr '{' set_elem_expr_stmt stateful_stmt '}' + | set_stmt_op set_ref_expr '{' set_elem_expr_stmt stateful_stmt_list '}' { $$ = set_stmt_alloc(&@$); $$->set.op = $1; $$->set.key = $4; $$->set.set = $2; - $$->set.stmt = $5; + list_splice_tail($5, &$$->set.stmt_list); + free($5); } ; @@ -3571,44 +4200,19 @@ map_stmt : set_stmt_op set_ref_expr '{' set_elem_expr_stmt COLON set_elem_expr_ $$->map.data = $6; $$->map.set = $2; } - | set_stmt_op set_ref_expr '{' set_elem_expr_stmt stateful_stmt COLON set_elem_expr_stmt '}' + | set_stmt_op set_ref_expr '{' set_elem_expr_stmt stateful_stmt_list COLON set_elem_expr_stmt '}' { $$ = map_stmt_alloc(&@$); $$->map.op = $1; $$->map.key = $4; $$->map.data = $7; - $$->map.stmt = $5; $$->map.set = $2; + list_splice_tail($5, &$$->map.stmt_list); + free($5); } ; -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 - { - $<stmt>$ = $<stmt>0; - } - | flow_stmt_opts flow_stmt_opt - ; - -flow_stmt_opt : TABLE identifier - { - $<stmt>0->meter.name = $2; - } +meter_stmt : meter_stmt_alloc { $$ = $1; } ; meter_stmt_alloc : METER identifier '{' meter_key_expr stmt '}' @@ -3647,19 +4251,19 @@ variable_expr : '$' identifier sym = symbol_lookup_fuzzy(scope, $2); if (sym) { erec_queue(error(&@2, "unknown identifier '%s'; " - "did you mean 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); + free_const($2); YYERROR; } $$ = variable_expr_alloc(&@$, scope, sym); - xfree($2); + free_const($2); } ; @@ -3669,7 +4273,7 @@ symbol_expr : variable_expr $$ = symbol_expr_alloc(&@$, SYMBOL_VALUE, current_scope(state), $1); - xfree($1); + free_const($1); } ; @@ -3677,12 +4281,12 @@ set_ref_expr : set_ref_symbol_expr | variable_expr ; -set_ref_symbol_expr : AT identifier +set_ref_symbol_expr : AT identifier close_scope_at { $$ = symbol_expr_alloc(&@$, SYMBOL_SET, current_scope(state), $2); - xfree($2); + free_const($2); } ; @@ -3714,7 +4318,7 @@ primary_expr : symbol_expr { $$ = $1; } | '(' basic_expr ')' { $$ = $2; } ; -fib_expr : FIB fib_tuple fib_result +fib_expr : FIB fib_tuple fib_result close_scope_fib { if (($2 & (NFTA_FIB_F_SADDR|NFTA_FIB_F_DADDR)) == 0) { erec_queue(error(&@2, "fib: need either saddr or daddr"), state->msgs); @@ -3739,7 +4343,7 @@ fib_expr : FIB fib_tuple fib_result fib_result : OIF { $$ =NFT_FIB_RESULT_OIF; } | OIFNAME { $$ =NFT_FIB_RESULT_OIFNAME; } - | TYPE { $$ =NFT_FIB_RESULT_ADDRTYPE; } + | TYPE close_scope_type { $$ =NFT_FIB_RESULT_ADDRTYPE; } ; fib_flag : SADDR { $$ = NFTA_FIB_F_SADDR; } @@ -3756,11 +4360,11 @@ fib_tuple : fib_flag DOT fib_tuple | fib_flag ; -osf_expr : OSF osf_ttl HDRVERSION +osf_expr : OSF osf_ttl HDRVERSION close_scope_osf { $$ = osf_expr_alloc(&@$, $2, NFT_OSF_F_VERSION); } - | OSF osf_ttl NAME + | OSF osf_ttl NAME close_scope_osf { $$ = osf_expr_alloc(&@$, $2, 0); } @@ -3779,8 +4383,10 @@ osf_ttl : /* empty */ else { erec_queue(error(&@2, "invalid ttl option"), state->msgs); + free_const($2); YYERROR; } + free_const($2); } ; @@ -3888,7 +4494,7 @@ set_list_member_expr : opt_newline set_expr opt_newline } | opt_newline set_elem_expr COLON set_rhs_expr opt_newline { - $$ = mapping_expr_alloc(&@$, $2, $4); + $$ = mapping_expr_alloc(&@2, $2, $4); } ; @@ -3908,9 +4514,25 @@ meter_key_expr_alloc : concat_expr set_elem_expr : set_elem_expr_alloc | set_elem_expr_alloc set_elem_expr_options + | set_elem_expr_alloc set_elem_expr_options set_elem_stmt_list + { + $$ = $1; + list_splice_tail($3, &$$->stmt_list); + free($3); + } + ; + +set_elem_key_expr : set_lhs_expr { $$ = $1; } + | ASTERISK { $$ = set_elem_catchall_expr_alloc(&@1); } ; -set_elem_expr_alloc : set_lhs_expr +set_elem_expr_alloc : set_elem_key_expr set_elem_stmt_list + { + $$ = set_elem_expr_alloc(&@1, $1); + list_splice_tail($2, &$$->stmt_list); + free($2); + } + | set_elem_key_expr { $$ = set_elem_expr_alloc(&@1, $1); } @@ -3923,7 +4545,28 @@ set_elem_options : set_elem_option | set_elem_options set_elem_option ; -set_elem_option : TIMEOUT time_spec +set_elem_time_spec : STRING + { + struct error_record *erec; + uint64_t res; + + if (!strcmp("never", $1)) { + free_const($1); + $$ = NFT_NEVER_TIMEOUT; + break; + } + + erec = time_parse(&@1, $1, &res); + free_const($1); + if (erec != NULL) { + erec_queue(erec, state->msgs); + YYERROR; + } + $$ = res; + } + ; + +set_elem_option : TIMEOUT time_spec { $<expr>0->timeout = $2; } @@ -3933,6 +4576,10 @@ set_elem_option : TIMEOUT time_spec } | comment_spec { + if (already_set($<expr>0->comment, &@1, state)) { + free_const($1); + YYERROR; + } $<expr>0->comment = $1; } ; @@ -3944,35 +4591,110 @@ set_elem_expr_options : set_elem_expr_option | set_elem_expr_options set_elem_expr_option ; -set_elem_expr_option : TIMEOUT time_spec +set_elem_stmt_list : set_elem_stmt { - $<expr>0->timeout = $2; + $$ = xmalloc(sizeof(*$$)); + init_list_head($$); + list_add_tail(&$1->list, $$); } - | EXPIRES time_spec + | set_elem_stmt_list set_elem_stmt { - $<expr>0->expiration = $2; + $$ = $1; + list_add_tail(&$2->list, $1); + } + ; + +set_elem_stmt : COUNTER close_scope_counter + { + $$ = counter_stmt_alloc(&@$); + } + | COUNTER PACKETS NUM BYTES NUM close_scope_counter + { + $$ = counter_stmt_alloc(&@$); + $$->counter.packets = $3; + $$->counter.bytes = $5; + } + | LIMIT RATE limit_mode limit_rate_pkts limit_burst_pkts close_scope_limit + { + if ($5 == 0) { + erec_queue(error(&@5, "limit burst must be > 0"), + state->msgs); + YYERROR; + } + $$ = limit_stmt_alloc(&@$); + $$->limit.rate = $4.rate; + $$->limit.unit = $4.unit; + $$->limit.burst = $5; + $$->limit.type = NFT_LIMIT_PKTS; + $$->limit.flags = $3; + } + | LIMIT RATE limit_mode limit_rate_bytes limit_burst_bytes close_scope_limit + { + $$ = limit_stmt_alloc(&@$); + $$->limit.rate = $4.rate; + $$->limit.unit = $4.unit; + $$->limit.burst = $5; + $$->limit.type = NFT_LIMIT_PKT_BYTES; + $$->limit.flags = $3; + } + | CT COUNT NUM close_scope_ct + { + $$ = connlimit_stmt_alloc(&@$); + $$->connlimit.count = $3; + } + | CT COUNT OVER NUM close_scope_ct + { + $$ = connlimit_stmt_alloc(&@$); + $$->connlimit.count = $4; + $$->connlimit.flags = NFT_CONNLIMIT_F_INV; + } + | QUOTA quota_mode NUM quota_unit quota_used close_scope_quota + { + struct error_record *erec; + uint64_t rate; + + erec = data_unit_parse(&@$, $4, &rate); + free_const($4); + if (erec != NULL) { + erec_queue(erec, state->msgs); + YYERROR; + } + $$ = quota_stmt_alloc(&@$); + $$->quota.bytes = $3 * rate; + $$->quota.used = $5; + $$->quota.flags = $2; } - | COUNTER + | LAST USED NEVER close_scope_last { - $<expr>0->stmt = counter_stmt_alloc(&@$); + $$ = last_stmt_alloc(&@$); } - | COUNTER PACKETS NUM BYTES NUM + | LAST USED time_spec close_scope_last { - struct stmt *stmt; + $$ = last_stmt_alloc(&@$); + $$->last.used = $3; + $$->last.set = true; + } + ; - stmt = counter_stmt_alloc(&@$); - stmt->counter.packets = $3; - stmt->counter.bytes = $5; - $<expr>0->stmt = stmt; +set_elem_expr_option : TIMEOUT set_elem_time_spec + { + $<expr>0->timeout = $2; + } + | EXPIRES time_spec + { + $<expr>0->expiration = $2; } | comment_spec { + if (already_set($<expr>0->comment, &@1, state)) { + free_const($1); + YYERROR; + } $<expr>0->comment = $1; } ; set_lhs_expr : concat_rhs_expr - | wildcard_expr ; set_rhs_expr : concat_rhs_expr @@ -4017,7 +4739,7 @@ quota_config : quota_mode NUM quota_unit quota_used uint64_t rate; erec = data_unit_parse(&@$, $3, &rate); - xfree($3); + free_const($3); if (erec != NULL) { erec_queue(erec, state->msgs); YYERROR; @@ -4046,10 +4768,10 @@ secmark_config : string 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); + free_const($1); YYERROR; } - xfree($1); + free_const($1); } ; @@ -4065,23 +4787,35 @@ ct_obj_type : HELPER { $$ = NFT_OBJECT_CT_HELPER; } | EXPECTATION { $$ = NFT_OBJECT_CT_EXPECT; } ; -ct_l4protoname : TCP { $$ = IPPROTO_TCP; } - | UDP { $$ = IPPROTO_UDP; } +ct_cmd_type : HELPERS { $$ = CMD_OBJ_CT_HELPERS; } + | TIMEOUT { $$ = CMD_OBJ_CT_TIMEOUTS; } + | EXPECTATION { $$ = CMD_OBJ_CT_EXPECTATIONS; } ; -ct_helper_config : TYPE QUOTED_STRING PROTOCOL ct_l4protoname stmt_separator +ct_l4protoname : TCP close_scope_tcp { $$ = IPPROTO_TCP; } + | UDP close_scope_udp { $$ = IPPROTO_UDP; } + ; + +ct_helper_config : TYPE QUOTED_STRING PROTOCOL ct_l4protoname stmt_separator close_scope_type { struct ct_helper *ct; int ret; ct = &$<obj>0->ct_helper; + if (ct->l4proto) { + erec_queue(error(&@2, "You can only specify this once. This statement is already set for %s.", ct->name), state->msgs); + free_const($2); + YYERROR; + } + 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); + free_const($2); YYERROR; } - xfree($2); + free_const($2); ct->l4proto = $4; } @@ -4095,17 +4829,16 @@ timeout_states : timeout_state { $$ = xmalloc(sizeof(*$$)); init_list_head($$); - list_add_tail($1, $$); + list_add_tail(&$1->head, $$); } | timeout_states COMMA timeout_state { - list_add_tail($3, $1); + list_add_tail(&$3->head, $1); $$ = $1; } ; -timeout_state : STRING COLON NUM - +timeout_state : STRING COLON time_spec_or_num_s { struct timeout_state *ts; @@ -4114,7 +4847,7 @@ timeout_state : STRING COLON NUM ts->timeout_value = $3; ts->location = @1; init_list_head(&ts->head); - $$ = &ts->head; + $$ = ts; } ; @@ -4126,13 +4859,13 @@ ct_timeout_config : PROTOCOL ct_l4protoname stmt_separator ct = &$<obj>0->ct_timeout; ct->l4proto = l4proto; } - | POLICY '=' '{' timeout_states '}' stmt_separator + | POLICY '=' '{' timeout_states '}' stmt_separator close_scope_policy { struct ct_timeout *ct; ct = &$<obj>0->ct_timeout; list_splice_tail($4, &ct->timeout_list); - xfree($4); + free($4); } | L3PROTOCOL family_spec_explicit stmt_separator { @@ -4168,33 +4901,25 @@ ct_obj_alloc : /* empty */ } ; -limit_config : RATE limit_mode NUM SLASH time_unit limit_burst_pkts +limit_config : RATE limit_mode limit_rate_pkts limit_burst_pkts { struct limit *limit; limit = &$<obj>0->limit; - limit->rate = $3; - limit->unit = $5; - limit->burst = $6; + limit->rate = $3.rate; + limit->unit = $3.unit; + limit->burst = $4; limit->type = NFT_LIMIT_PKTS; limit->flags = $2; } - | RATE limit_mode NUM STRING limit_burst_bytes + | RATE limit_mode limit_rate_bytes 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 = &$<obj>0->limit; - limit->rate = rate * $3; - limit->unit = unit; - limit->burst = $5; + limit->rate = $3.rate; + limit->unit = $3.unit; + limit->burst = $4; limit->type = NFT_LIMIT_PKT_BYTES; limit->flags = $2; } @@ -4215,10 +4940,30 @@ relational_expr : expr /* implicit */ rhs_expr { $$ = relational_expr_alloc(&@$, OP_IMPLICIT, $1, $2); } + | expr /* implicit */ basic_rhs_expr SLASH list_rhs_expr + { + $$ = flagcmp_expr_alloc(&@$, OP_EQ, $1, $4, $2); + } + | expr /* implicit */ list_rhs_expr SLASH list_rhs_expr + { + $$ = flagcmp_expr_alloc(&@$, OP_EQ, $1, $4, $2); + } + | expr relational_op basic_rhs_expr SLASH list_rhs_expr + { + $$ = flagcmp_expr_alloc(&@$, $2, $1, $5, $3); + } + | expr relational_op list_rhs_expr SLASH list_rhs_expr + { + $$ = flagcmp_expr_alloc(&@$, $2, $1, $5, $3); + } | expr relational_op rhs_expr { $$ = relational_expr_alloc(&@2, $2, $1, $3); } + | expr relational_op list_rhs_expr + { + $$ = relational_expr_alloc(&@2, $2, $1, $3); + } ; list_rhs_expr : basic_rhs_expr COMMA basic_rhs_expr @@ -4236,7 +4981,6 @@ list_rhs_expr : basic_rhs_expr COMMA basic_rhs_expr ; rhs_expr : concat_rhs_expr { $$ = $1; } - | wildcard_expr { $$ = $1; } | set_expr { $$ = $1; } | set_ref_symbol_expr { $$ = $1; } ; @@ -4310,60 +5054,62 @@ boolean_expr : boolean_keys } ; -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"); } +keyword_expr : ETHER close_scope_eth { $$ = symbol_value(&@$, "ether"); } + | IP close_scope_ip { $$ = symbol_value(&@$, "ip"); } + | IP6 close_scope_ip6 { $$ = symbol_value(&@$, "ip6"); } + | VLAN close_scope_vlan { $$ = symbol_value(&@$, "vlan"); } + | ARP close_scope_arp { $$ = symbol_value(&@$, "arp"); } + | DNAT close_scope_nat { $$ = symbol_value(&@$, "dnat"); } + | SNAT close_scope_nat { $$ = symbol_value(&@$, "snat"); } | ECN { $$ = symbol_value(&@$, "ecn"); } - | RESET { $$ = symbol_value(&@$, "reset"); } + | RESET close_scope_reset { $$ = symbol_value(&@$, "reset"); } + | DESTROY close_scope_destroy { $$ = symbol_value(&@$, "destroy"); } | ORIGINAL { $$ = symbol_value(&@$, "original"); } | REPLY { $$ = symbol_value(&@$, "reply"); } | LABEL { $$ = symbol_value(&@$, "label"); } + | LAST close_scope_last { $$ = symbol_value(&@$, "last"); } ; primary_rhs_expr : symbol_expr { $$ = $1; } | integer_expr { $$ = $1; } | boolean_expr { $$ = $1; } | keyword_expr { $$ = $1; } - | TCP + | TCP close_scope_tcp { uint8_t data = IPPROTO_TCP; $$ = constant_expr_alloc(&@$, &inet_protocol_type, BYTEORDER_HOST_ENDIAN, sizeof(data) * BITS_PER_BYTE, &data); } - | UDP + | UDP close_scope_udp { uint8_t data = IPPROTO_UDP; $$ = constant_expr_alloc(&@$, &inet_protocol_type, BYTEORDER_HOST_ENDIAN, sizeof(data) * BITS_PER_BYTE, &data); } - | UDPLITE + | UDPLITE close_scope_udplite { uint8_t data = IPPROTO_UDPLITE; $$ = constant_expr_alloc(&@$, &inet_protocol_type, BYTEORDER_HOST_ENDIAN, sizeof(data) * BITS_PER_BYTE, &data); } - | ESP + | ESP close_scope_esp { uint8_t data = IPPROTO_ESP; $$ = constant_expr_alloc(&@$, &inet_protocol_type, BYTEORDER_HOST_ENDIAN, sizeof(data) * BITS_PER_BYTE, &data); } - | AH + | AH close_scope_ah { uint8_t data = IPPROTO_AH; $$ = constant_expr_alloc(&@$, &inet_protocol_type, BYTEORDER_HOST_ENDIAN, sizeof(data) * BITS_PER_BYTE, &data); } - | ICMP + | ICMP close_scope_icmp { uint8_t data = IPPROTO_ICMP; $$ = constant_expr_alloc(&@$, &inet_protocol_type, @@ -4377,35 +5123,42 @@ primary_rhs_expr : symbol_expr { $$ = $1; } BYTEORDER_HOST_ENDIAN, sizeof(data) * BITS_PER_BYTE, &data); } - | ICMP6 + | ICMP6 close_scope_icmp { uint8_t data = IPPROTO_ICMPV6; $$ = constant_expr_alloc(&@$, &inet_protocol_type, BYTEORDER_HOST_ENDIAN, sizeof(data) * BITS_PER_BYTE, &data); } - | COMP + | GRE close_scope_gre + { + uint8_t data = IPPROTO_GRE; + $$ = constant_expr_alloc(&@$, &inet_protocol_type, + BYTEORDER_HOST_ENDIAN, + sizeof(data) * BITS_PER_BYTE, &data); + } + | COMP close_scope_comp { uint8_t data = IPPROTO_COMP; $$ = constant_expr_alloc(&@$, &inet_protocol_type, BYTEORDER_HOST_ENDIAN, sizeof(data) * BITS_PER_BYTE, &data); } - | DCCP + | DCCP close_scope_dccp { uint8_t data = IPPROTO_DCCP; $$ = constant_expr_alloc(&@$, &inet_protocol_type, BYTEORDER_HOST_ENDIAN, sizeof(data) * BITS_PER_BYTE, &data); } - | SCTP + | SCTP close_scope_sctp { uint8_t data = IPPROTO_SCTP; $$ = constant_expr_alloc(&@$, &inet_protocol_type, BYTEORDER_HOST_ENDIAN, sizeof(data) * BITS_PER_BYTE, &data); } - | REDIRECT + | REDIRECT close_scope_nat { uint8_t data = ICMP_REDIRECT; $$ = constant_expr_alloc(&@$, &icmp_type_type, @@ -4421,6 +5174,7 @@ relational_op : EQ { $$ = OP_EQ; } | GT { $$ = OP_GT; } | GTE { $$ = OP_GTE; } | LTE { $$ = OP_LTE; } + | NOT { $$ = OP_NEG; } ; verdict_expr : ACCEPT @@ -4456,11 +5210,11 @@ chain_expr : variable_expr BYTEORDER_HOST_ENDIAN, strlen($1) * BITS_PER_BYTE, $1); - xfree($1); + free_const($1); } ; -meta_expr : META meta_key +meta_expr : META meta_key close_scope_meta { $$ = meta_expr_alloc(&@$, $2); } @@ -4468,13 +5222,13 @@ meta_expr : META meta_key { $$ = meta_expr_alloc(&@$, $1); } - | META STRING + | META STRING close_scope_meta { struct error_record *erec; unsigned int key; erec = meta_key_parse(&@$, $2, &key); - xfree($2); + free_const($2); if (erec != NULL) { erec_queue(erec, state->msgs); YYERROR; @@ -4492,7 +5246,7 @@ meta_key_qualified : LENGTH { $$ = NFT_META_LEN; } | PROTOCOL { $$ = NFT_META_PROTOCOL; } | PRIORITY { $$ = NFT_META_PRIORITY; } | RANDOM { $$ = NFT_META_PRANDOM; } - | SECMARK { $$ = NFT_META_SECMARK; } + | SECMARK close_scope_secmark { $$ = NFT_META_SECMARK; } ; meta_key_unqualified : MARK { $$ = NFT_META_MARK; } @@ -4515,13 +5269,13 @@ meta_key_unqualified : MARK { $$ = NFT_META_MARK; } | IIFGROUP { $$ = NFT_META_IIFGROUP; } | OIFGROUP { $$ = NFT_META_OIFGROUP; } | CGROUP { $$ = NFT_META_CGROUP; } - | IPSEC { $$ = NFT_META_SECPATH; } + | IPSEC close_scope_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 +meta_stmt : META meta_key SET stmt_expr close_scope_meta { switch ($2) { case NFT_META_SECMARK: @@ -4545,15 +5299,16 @@ meta_stmt : META meta_key SET stmt_expr { $$ = meta_stmt_alloc(&@$, $1, $3); } - | META STRING SET stmt_expr + | META STRING SET stmt_expr close_scope_meta { struct error_record *erec; unsigned int key; erec = meta_key_parse(&@$, $2, &key); - xfree($2); + free_const($2); if (erec != NULL) { erec_queue(erec, state->msgs); + expr_free($4); YYERROR; } @@ -4563,24 +5318,29 @@ meta_stmt : META meta_key SET stmt_expr { $$ = notrack_stmt_alloc(&@$); } - | FLOW OFFLOAD AT string + | FLOW OFFLOAD AT string close_scope_at { $$ = flow_offload_stmt_alloc(&@$, $4); } - | FLOW ADD AT string + | FLOW ADD AT string close_scope_at { $$ = flow_offload_stmt_alloc(&@$, $4); } ; -socket_expr : SOCKET socket_key +socket_expr : SOCKET socket_key close_scope_socket { - $$ = socket_expr_alloc(&@$, $2); + $$ = socket_expr_alloc(&@$, $2, 0); + } + | SOCKET CGROUPV2 LEVEL NUM close_scope_socket + { + $$ = socket_expr_alloc(&@$, NFT_SOCKET_CGROUPV2, $4); } ; socket_key : TRANSPARENT { $$ = NFT_SOCKET_TRANSPARENT; } | MARK { $$ = NFT_SOCKET_MARK; } + | WILDCARD { $$ = NFT_SOCKET_WILDCARD; } ; offset_opt : /* empty */ { $$ = 0; } @@ -4591,7 +5351,7 @@ numgen_type : INC { $$ = NFT_NG_INCREMENTAL; } | RANDOM { $$ = NFT_NG_RANDOM; } ; -numgen_expr : NUMGEN numgen_type MOD NUM offset_opt +numgen_expr : NUMGEN numgen_type MOD NUM offset_opt close_scope_numgen { $$ = numgen_expr_alloc(&@$, $2, $4, $5); } @@ -4613,7 +5373,7 @@ 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 +xfrm_expr : IPSEC xfrm_dir xfrm_spnum xfrm_state_key close_scope_ipsec { if ($3 > 255) { erec_queue(error(&@3, "value too large"), state->msgs); @@ -4621,7 +5381,7 @@ xfrm_expr : IPSEC xfrm_dir xfrm_spnum xfrm_state_key } $$ = xfrm_expr_alloc(&@$, $2, $3, $4); } - | IPSEC xfrm_dir xfrm_spnum nf_key_proto xfrm_state_proto_key + | IPSEC xfrm_dir xfrm_spnum nf_key_proto xfrm_state_proto_key close_scope_ipsec { enum nft_xfrm_keys xfrmk = $5; @@ -4648,31 +5408,31 @@ xfrm_expr : IPSEC xfrm_dir xfrm_spnum xfrm_state_key } ; -hash_expr : JHASH expr MOD NUM SEED NUM offset_opt +hash_expr : JHASH expr MOD NUM SEED NUM offset_opt close_scope_hash { $$ = hash_expr_alloc(&@$, $4, true, $6, $7, NFT_HASH_JENKINS); $$->hash.expr = $2; } - | JHASH expr MOD NUM offset_opt + | JHASH expr MOD NUM offset_opt close_scope_hash { $$ = hash_expr_alloc(&@$, $4, false, 0, $5, NFT_HASH_JENKINS); $$->hash.expr = $2; } - | SYMHASH MOD NUM offset_opt + | SYMHASH MOD NUM offset_opt close_scope_hash { $$ = hash_expr_alloc(&@$, $3, false, 0, $4, NFT_HASH_SYM); } ; -nf_key_proto : IP { $$ = NFPROTO_IPV4; } - | IP6 { $$ = NFPROTO_IPV6; } +nf_key_proto : IP close_scope_ip { $$ = NFPROTO_IPV4; } + | IP6 close_scope_ip6 { $$ = NFPROTO_IPV6; } ; -rt_expr : RT rt_key +rt_expr : RT rt_key close_scope_rt { $$ = rt_expr_alloc(&@$, $2, true); } - | RT nf_key_proto rt_key + | RT nf_key_proto rt_key close_scope_rt { enum nft_rt_keys rtk = $3; @@ -4695,18 +5455,18 @@ rt_expr : RT rt_key rt_key : CLASSID { $$ = NFT_RT_CLASSID; } | NEXTHOP { $$ = NFT_RT_NEXTHOP4; } | MTU { $$ = NFT_RT_TCPMSS; } - | IPSEC { $$ = NFT_RT_XFRM; } + | IPSEC close_scope_ipsec { $$ = NFT_RT_XFRM; } ; -ct_expr : CT ct_key +ct_expr : CT ct_key close_scope_ct { $$ = ct_expr_alloc(&@$, $2, -1); } - | CT ct_dir ct_key_dir + | CT ct_dir ct_key_dir close_scope_ct { $$ = ct_expr_alloc(&@$, $3, $2); } - | CT ct_dir ct_key_proto_field + | CT ct_dir ct_key_proto_field close_scope_ct { $$ = ct_expr_alloc(&@$, $3, $2); } @@ -4730,7 +5490,7 @@ ct_key : L3PROTOCOL { $$ = NFT_CT_L3PROTOCOL; } | PROTO_DST { $$ = NFT_CT_PROTO_DST; } | LABEL { $$ = NFT_CT_LABELS; } | EVENT { $$ = NFT_CT_EVENTMASK; } - | SECMARK { $$ = NFT_CT_SECMARK; } + | SECMARK close_scope_secmark { $$ = NFT_CT_SECMARK; } | ID { $$ = NFT_CT_ID; } | ct_key_dir_optional ; @@ -4744,10 +5504,10 @@ ct_key_dir : SADDR { $$ = NFT_CT_SRC; } | 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_proto_field : IP SADDR close_scope_ip { $$ = NFT_CT_SRC_IP; } + | IP DADDR close_scope_ip { $$ = NFT_CT_DST_IP; } + | IP6 SADDR close_scope_ip6 { $$ = NFT_CT_SRC_IP6; } + | IP6 DADDR close_scope_ip6 { $$ = NFT_CT_DST_IP6; } ; ct_key_dir_optional : BYTES { $$ = NFT_CT_BYTES; } @@ -4774,7 +5534,7 @@ list_stmt_expr : symbol_stmt_expr COMMA symbol_stmt_expr } ; -ct_stmt : CT ct_key SET stmt_expr +ct_stmt : CT ct_key SET stmt_expr close_scope_ct { switch ($2) { case NFT_CT_HELPER: @@ -4787,20 +5547,7 @@ ct_stmt : CT ct_key SET stmt_expr 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 ct_dir ct_key_dir_optional SET stmt_expr close_scope_ct { $$ = ct_stmt_alloc(&@$, $3, $2, $5); } @@ -4829,13 +5576,35 @@ payload_expr : payload_raw_expr | comp_hdr_expr | udp_hdr_expr | udplite_hdr_expr - | tcp_hdr_expr + | tcp_hdr_expr close_scope_tcp | dccp_hdr_expr | sctp_hdr_expr | th_hdr_expr + | vxlan_hdr_expr + | geneve_hdr_expr + | gre_hdr_expr + | gretap_hdr_expr + ; + +payload_raw_len : NUM + { + if ($1 > NFT_MAX_EXPR_LEN_BITS) { + erec_queue(error(&@1, "raw payload length %u exceeds upper limit of %u", + $1, NFT_MAX_EXPR_LEN_BITS), + state->msgs); + YYERROR; + } + + if ($1 == 0) { + erec_queue(error(&@1, "raw payload length cannot be 0"), state->msgs); + YYERROR; + } + + $$ = $1; + } ; -payload_raw_expr : AT payload_base_spec COMMA NUM COMMA NUM +payload_raw_expr : AT payload_base_spec COMMA NUM COMMA payload_raw_len close_scope_at { $$ = payload_expr_alloc(&@$, NULL, 0); payload_init_raw($$, $2, $4, $6); @@ -4846,10 +5615,21 @@ payload_raw_expr : AT payload_base_spec COMMA NUM COMMA NUM payload_base_spec : LL_HDR { $$ = PROTO_BASE_LL_HDR; } | NETWORK_HDR { $$ = PROTO_BASE_NETWORK_HDR; } - | TRANSPORT_HDR { $$ = PROTO_BASE_TRANSPORT_HDR; } + | TRANSPORT_HDR close_scope_th { $$ = PROTO_BASE_TRANSPORT_HDR; } + | STRING + { + if (!strcmp($1, "ih")) { + $$ = PROTO_BASE_INNER_HDR; + } else { + erec_queue(error(&@1, "unknown raw payload base"), state->msgs); + free_const($1); + YYERROR; + } + free_const($1); + } ; -eth_hdr_expr : ETHER eth_hdr_field +eth_hdr_expr : ETHER eth_hdr_field close_scope_eth { $$ = payload_expr_alloc(&@$, &proto_eth, $2); } @@ -4857,10 +5637,10 @@ eth_hdr_expr : ETHER eth_hdr_field eth_hdr_field : SADDR { $$ = ETHHDR_SADDR; } | DADDR { $$ = ETHHDR_DADDR; } - | TYPE { $$ = ETHHDR_TYPE; } + | TYPE close_scope_type { $$ = ETHHDR_TYPE; } ; -vlan_hdr_expr : VLAN vlan_hdr_field +vlan_hdr_expr : VLAN vlan_hdr_field close_scope_vlan { $$ = payload_expr_alloc(&@$, &proto_vlan, $2); } @@ -4868,11 +5648,12 @@ vlan_hdr_expr : VLAN vlan_hdr_field vlan_hdr_field : ID { $$ = VLANHDR_VID; } | CFI { $$ = VLANHDR_CFI; } + | DEI { $$ = VLANHDR_DEI; } | PCP { $$ = VLANHDR_PCP; } - | TYPE { $$ = VLANHDR_TYPE; } + | TYPE close_scope_type { $$ = VLANHDR_TYPE; } ; -arp_hdr_expr : ARP arp_hdr_field +arp_hdr_expr : ARP arp_hdr_field close_scope_arp { $$ = payload_expr_alloc(&@$, &proto_arp, $2); } @@ -4883,23 +5664,27 @@ arp_hdr_field : HTYPE { $$ = ARPHDR_HRD; } | 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; } + | SADDR ETHER close_scope_eth { $$ = ARPHDR_SADDR_ETHER; } + | DADDR ETHER close_scope_eth { $$ = ARPHDR_DADDR_ETHER; } + | SADDR IP close_scope_ip { $$ = ARPHDR_SADDR_IP; } + | DADDR IP close_scope_ip { $$ = ARPHDR_DADDR_IP; } ; -ip_hdr_expr : IP ip_hdr_field +ip_hdr_expr : IP ip_hdr_field close_scope_ip { $$ = payload_expr_alloc(&@$, &proto_ip, $2); } - | IP OPTION ip_option_type ip_option_field + | IP OPTION ip_option_type ip_option_field close_scope_ip { - $$ = ipopt_expr_alloc(&@$, $3, $4, 0); + $$ = ipopt_expr_alloc(&@$, $3, $4); + if (!$$) { + erec_queue(error(&@1, "unknown ip option type/field"), state->msgs); + YYERROR; + } } - | IP OPTION ip_option_type + | IP OPTION ip_option_type close_scope_ip { - $$ = ipopt_expr_alloc(&@$, $3, IPOPT_FIELD_TYPE, 0); + $$ = ipopt_expr_alloc(&@$, $3, IPOPT_FIELD_TYPE); $$->exthdr.flags = NFT_EXTHDR_F_PRESENT; } ; @@ -4924,20 +5709,20 @@ ip_option_type : LSRR { $$ = IPOPT_LSRR; } | RA { $$ = IPOPT_RA; } ; -ip_option_field : TYPE { $$ = IPOPT_FIELD_TYPE; } +ip_option_field : TYPE close_scope_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 +icmp_hdr_expr : ICMP icmp_hdr_field close_scope_icmp { $$ = payload_expr_alloc(&@$, &proto_icmp, $2); } ; -icmp_hdr_field : TYPE { $$ = ICMPHDR_TYPE; } +icmp_hdr_field : TYPE close_scope_type { $$ = ICMPHDR_TYPE; } | CODE { $$ = ICMPHDR_CODE; } | CHECKSUM { $$ = ICMPHDR_CHECKSUM; } | ID { $$ = ICMPHDR_ID; } @@ -4946,19 +5731,19 @@ icmp_hdr_field : TYPE { $$ = ICMPHDR_TYPE; } | MTU { $$ = ICMPHDR_MTU; } ; -igmp_hdr_expr : IGMP igmp_hdr_field +igmp_hdr_expr : IGMP igmp_hdr_field close_scope_igmp { $$ = payload_expr_alloc(&@$, &proto_igmp, $2); } ; -igmp_hdr_field : TYPE { $$ = IGMPHDR_TYPE; } +igmp_hdr_field : TYPE close_scope_type { $$ = IGMPHDR_TYPE; } | CHECKSUM { $$ = IGMPHDR_CHECKSUM; } | MRT { $$ = IGMPHDR_MRT; } | GROUP { $$ = IGMPHDR_GROUP; } ; -ip6_hdr_expr : IP6 ip6_hdr_field +ip6_hdr_expr : IP6 ip6_hdr_field close_scope_ip6 { $$ = payload_expr_alloc(&@$, &proto_ip6, $2); } @@ -4974,13 +5759,13 @@ ip6_hdr_field : HDRVERSION { $$ = IP6HDR_VERSION; } | SADDR { $$ = IP6HDR_SADDR; } | DADDR { $$ = IP6HDR_DADDR; } ; -icmp6_hdr_expr : ICMP6 icmp6_hdr_field +icmp6_hdr_expr : ICMP6 icmp6_hdr_field close_scope_icmp { $$ = payload_expr_alloc(&@$, &proto_icmp6, $2); } ; -icmp6_hdr_field : TYPE { $$ = ICMP6HDR_TYPE; } +icmp6_hdr_field : TYPE close_scope_type { $$ = ICMP6HDR_TYPE; } | CODE { $$ = ICMP6HDR_CODE; } | CHECKSUM { $$ = ICMP6HDR_CHECKSUM; } | PPTR { $$ = ICMP6HDR_PPTR; } @@ -4988,9 +5773,11 @@ icmp6_hdr_field : TYPE { $$ = ICMP6HDR_TYPE; } | ID { $$ = ICMP6HDR_ID; } | SEQUENCE { $$ = ICMP6HDR_SEQ; } | MAXDELAY { $$ = ICMP6HDR_MAXDELAY; } + | TADDR { $$ = ICMP6HDR_TADDR; } + | DADDR { $$ = ICMP6HDR_DADDR; } ; -auth_hdr_expr : AH auth_hdr_field +auth_hdr_expr : AH auth_hdr_field close_scope_ah { $$ = payload_expr_alloc(&@$, &proto_ah, $2); } @@ -5003,7 +5790,7 @@ auth_hdr_field : NEXTHDR { $$ = AHHDR_NEXTHDR; } | SEQUENCE { $$ = AHHDR_SEQUENCE; } ; -esp_hdr_expr : ESP esp_hdr_field +esp_hdr_expr : ESP esp_hdr_field close_scope_esp { $$ = payload_expr_alloc(&@$, &proto_esp, $2); } @@ -5013,7 +5800,7 @@ esp_hdr_field : SPI { $$ = ESPHDR_SPI; } | SEQUENCE { $$ = ESPHDR_SEQUENCE; } ; -comp_hdr_expr : COMP comp_hdr_field +comp_hdr_expr : COMP comp_hdr_field close_scope_comp { $$ = payload_expr_alloc(&@$, &proto_comp, $2); } @@ -5024,7 +5811,7 @@ comp_hdr_field : NEXTHDR { $$ = COMPHDR_NEXTHDR; } | CPI { $$ = COMPHDR_CPI; } ; -udp_hdr_expr : UDP udp_hdr_field +udp_hdr_expr : UDP udp_hdr_field close_scope_udp { $$ = payload_expr_alloc(&@$, &proto_udp, $2); } @@ -5036,7 +5823,7 @@ udp_hdr_field : SPORT { $$ = UDPHDR_SPORT; } | CHECKSUM { $$ = UDPHDR_CHECKSUM; } ; -udplite_hdr_expr : UDPLITE udplite_hdr_field +udplite_hdr_expr : UDPLITE udplite_hdr_field close_scope_udplite { $$ = payload_expr_alloc(&@$, &proto_udplite, $2); } @@ -5052,15 +5839,119 @@ 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); + $$ = tcpopt_expr_alloc(&@$, $3, TCPOPT_COMMON_KIND); $$->exthdr.flags = NFT_EXTHDR_F_PRESENT; } + | TCP OPTION tcp_hdr_option_kind_and_field + { + $$ = tcpopt_expr_alloc(&@$, $3.kind, $3.field); + if ($$ == NULL) { + erec_queue(error(&@1, "Could not find a tcp option template"), state->msgs); + YYERROR; + } + } + | TCP OPTION AT close_scope_at tcp_hdr_option_type COMMA NUM COMMA payload_raw_len + { + $$ = tcpopt_expr_alloc(&@$, $5, 0); + tcpopt_init_raw($$, $5, $7, $9, 0); + } + ; + +inner_inet_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 close_scope_tcp + | dccp_hdr_expr + | sctp_hdr_expr + | th_hdr_expr + ; + +inner_eth_expr : eth_hdr_expr + | vlan_hdr_expr + | arp_hdr_expr + ; + +inner_expr : inner_eth_expr + | inner_inet_expr + ; + +vxlan_hdr_expr : VXLAN vxlan_hdr_field + { + struct expr *expr; + + expr = payload_expr_alloc(&@$, &proto_vxlan, $2); + expr->payload.inner_desc = &proto_vxlan; + $$ = expr; + } + | VXLAN inner_expr + { + $$ = $2; + $$->location = @$; + $$->payload.inner_desc = &proto_vxlan; + } + ; + +vxlan_hdr_field : VNI { $$ = VXLANHDR_VNI; } + | FLAGS { $$ = VXLANHDR_FLAGS; } + ; + +geneve_hdr_expr : GENEVE geneve_hdr_field + { + struct expr *expr; + + expr = payload_expr_alloc(&@$, &proto_geneve, $2); + expr->payload.inner_desc = &proto_geneve; + $$ = expr; + } + | GENEVE inner_expr + { + $$ = $2; + $$->location = @$; + $$->payload.inner_desc = &proto_geneve; + } + ; + +geneve_hdr_field : VNI { $$ = GNVHDR_VNI; } + | TYPE { $$ = GNVHDR_TYPE; } + ; + +gre_hdr_expr : GRE gre_hdr_field close_scope_gre + { + $$ = payload_expr_alloc(&@$, &proto_gre, $2); + } + | GRE close_scope_gre inner_inet_expr + { + $$ = $3; + $$->payload.inner_desc = &proto_gre; + } + ; + +gre_hdr_field : HDRVERSION { $$ = GREHDR_VERSION; } + | FLAGS { $$ = GREHDR_FLAGS; } + | PROTOCOL { $$ = GREHDR_PROTOCOL; } + ; + +gretap_hdr_expr : GRETAP close_scope_gre inner_expr + { + $$ = $3; + $$->payload.inner_desc = &proto_gretap; + } + ; + +optstrip_stmt : RESET TCP OPTION tcp_hdr_option_type close_scope_tcp + { + $$ = optstrip_stmt_alloc(&@$, tcpopt_expr_alloc(&@$, + $4, TCPOPT_COMMON_KIND)); + } ; tcp_hdr_field : SPORT { $$ = TCPHDR_SPORT; } @@ -5075,45 +5966,211 @@ tcp_hdr_field : SPORT { $$ = TCPHDR_SPORT; } | 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_kind_and_field : MSS tcpopt_field_maxseg + { + struct tcp_kind_field kind_field = { .kind = TCPOPT_KIND_MAXSEG, .field = $2 }; + $$ = kind_field; + } + | tcp_hdr_option_sack tcpopt_field_sack + { + struct tcp_kind_field kind_field = { .kind = $1, .field = $2 }; + $$ = kind_field; + } + | WINDOW tcpopt_field_window + { + struct tcp_kind_field kind_field = { .kind = TCPOPT_KIND_WINDOW, .field = $2 }; + $$ = kind_field; + } + | TIMESTAMP tcpopt_field_tsopt + { + struct tcp_kind_field kind_field = { .kind = TCPOPT_KIND_TIMESTAMP, .field = $2 }; + $$ = kind_field; + } + | tcp_hdr_option_type LENGTH + { + struct tcp_kind_field kind_field = { .kind = $1, .field = TCPOPT_COMMON_LENGTH }; + $$ = kind_field; + } + | MPTCP tcpopt_field_mptcp + { + struct tcp_kind_field kind_field = { .kind = TCPOPT_KIND_MPTCP, .field = $2 }; + $$ = kind_field; + } + ; + +tcp_hdr_option_sack : SACK { $$ = TCPOPT_KIND_SACK; } + | SACK0 { $$ = TCPOPT_KIND_SACK; } + | SACK1 { $$ = TCPOPT_KIND_SACK1; } + | SACK2 { $$ = TCPOPT_KIND_SACK2; } + | SACK3 { $$ = TCPOPT_KIND_SACK3; } + ; + +tcp_hdr_option_type : ECHO { $$ = TCPOPT_KIND_ECHO; } + | EOL { $$ = TCPOPT_KIND_EOL; } + | FASTOPEN { $$ = TCPOPT_KIND_FASTOPEN; } + | MD5SIG { $$ = TCPOPT_KIND_MD5SIG; } + | MPTCP { $$ = TCPOPT_KIND_MPTCP; } + | MSS { $$ = TCPOPT_KIND_MAXSEG; } + | NOP { $$ = TCPOPT_KIND_NOP; } + | SACK_PERM { $$ = TCPOPT_KIND_SACK_PERMITTED; } + | TIMESTAMP { $$ = TCPOPT_KIND_TIMESTAMP; } + | WINDOW { $$ = TCPOPT_KIND_WINDOW; } + | tcp_hdr_option_sack { $$ = $1; } + | NUM { + if ($1 > 255) { + erec_queue(error(&@1, "value too large"), state->msgs); + YYERROR; + } + $$ = $1; + } + ; + +tcpopt_field_sack : LEFT { $$ = TCPOPT_SACK_LEFT; } + | RIGHT { $$ = TCPOPT_SACK_RIGHT; } + ; + +tcpopt_field_window : COUNT { $$ = TCPOPT_WINDOW_COUNT; } + ; + +tcpopt_field_tsopt : TSVAL { $$ = TCPOPT_TS_TSVAL; } + | TSECR { $$ = TCPOPT_TS_TSECR; } + ; + +tcpopt_field_maxseg : SIZE { $$ = TCPOPT_MAXSEG_SIZE; } ; -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; } +tcpopt_field_mptcp : SUBTYPE { $$ = TCPOPT_MPTCP_SUBTYPE; } ; -dccp_hdr_expr : DCCP dccp_hdr_field +dccp_hdr_expr : DCCP dccp_hdr_field close_scope_dccp { $$ = payload_expr_alloc(&@$, &proto_dccp, $2); } + | DCCP OPTION NUM close_scope_dccp + { + if ($3 > DCCPOPT_TYPE_MAX) { + erec_queue(error(&@1, "value too large"), + state->msgs); + YYERROR; + } + $$ = dccpopt_expr_alloc(&@$, $3); + } ; dccp_hdr_field : SPORT { $$ = DCCPHDR_SPORT; } | DPORT { $$ = DCCPHDR_DPORT; } - | TYPE { $$ = DCCPHDR_TYPE; } + | TYPE close_scope_type { $$ = DCCPHDR_TYPE; } + ; + +sctp_chunk_type : DATA { $$ = SCTP_CHUNK_TYPE_DATA; } + | INIT { $$ = SCTP_CHUNK_TYPE_INIT; } + | INIT_ACK { $$ = SCTP_CHUNK_TYPE_INIT_ACK; } + | SACK { $$ = SCTP_CHUNK_TYPE_SACK; } + | HEARTBEAT { $$ = SCTP_CHUNK_TYPE_HEARTBEAT; } + | HEARTBEAT_ACK { $$ = SCTP_CHUNK_TYPE_HEARTBEAT_ACK; } + | ABORT { $$ = SCTP_CHUNK_TYPE_ABORT; } + | SHUTDOWN { $$ = SCTP_CHUNK_TYPE_SHUTDOWN; } + | SHUTDOWN_ACK { $$ = SCTP_CHUNK_TYPE_SHUTDOWN_ACK; } + | ERROR { $$ = SCTP_CHUNK_TYPE_ERROR; } + | COOKIE_ECHO { $$ = SCTP_CHUNK_TYPE_COOKIE_ECHO; } + | COOKIE_ACK { $$ = SCTP_CHUNK_TYPE_COOKIE_ACK; } + | ECNE { $$ = SCTP_CHUNK_TYPE_ECNE; } + | CWR { $$ = SCTP_CHUNK_TYPE_CWR; } + | SHUTDOWN_COMPLETE { $$ = SCTP_CHUNK_TYPE_SHUTDOWN_COMPLETE; } + | ASCONF_ACK { $$ = SCTP_CHUNK_TYPE_ASCONF_ACK; } + | FORWARD_TSN { $$ = SCTP_CHUNK_TYPE_FORWARD_TSN; } + | ASCONF { $$ = SCTP_CHUNK_TYPE_ASCONF; } + ; + +sctp_chunk_common_field : TYPE close_scope_type { $$ = SCTP_CHUNK_COMMON_TYPE; } + | FLAGS { $$ = SCTP_CHUNK_COMMON_FLAGS; } + | LENGTH { $$ = SCTP_CHUNK_COMMON_LENGTH; } + ; + +sctp_chunk_data_field : TSN { $$ = SCTP_CHUNK_DATA_TSN; } + | STREAM { $$ = SCTP_CHUNK_DATA_STREAM; } + | SSN { $$ = SCTP_CHUNK_DATA_SSN; } + | PPID { $$ = SCTP_CHUNK_DATA_PPID; } + ; + +sctp_chunk_init_field : INIT_TAG { $$ = SCTP_CHUNK_INIT_TAG; } + | A_RWND { $$ = SCTP_CHUNK_INIT_RWND; } + | NUM_OSTREAMS { $$ = SCTP_CHUNK_INIT_OSTREAMS; } + | NUM_ISTREAMS { $$ = SCTP_CHUNK_INIT_ISTREAMS; } + | INIT_TSN { $$ = SCTP_CHUNK_INIT_TSN; } + ; + +sctp_chunk_sack_field : CUM_TSN_ACK { $$ = SCTP_CHUNK_SACK_CTSN_ACK; } + | A_RWND { $$ = SCTP_CHUNK_SACK_RWND; } + | NUM_GACK_BLOCKS { $$ = SCTP_CHUNK_SACK_GACK_BLOCKS; } + | NUM_DUP_TSNS { $$ = SCTP_CHUNK_SACK_DUP_TSNS; } + ; + +sctp_chunk_alloc : sctp_chunk_type + { + $$ = sctp_chunk_expr_alloc(&@$, $1, SCTP_CHUNK_COMMON_TYPE); + $$->exthdr.flags = NFT_EXTHDR_F_PRESENT; + } + | sctp_chunk_type sctp_chunk_common_field + { + $$ = sctp_chunk_expr_alloc(&@$, $1, $2); + } + | DATA sctp_chunk_data_field + { + $$ = sctp_chunk_expr_alloc(&@$, SCTP_CHUNK_TYPE_DATA, $2); + } + | INIT sctp_chunk_init_field + { + $$ = sctp_chunk_expr_alloc(&@$, SCTP_CHUNK_TYPE_INIT, $2); + } + | INIT_ACK sctp_chunk_init_field + { + $$ = sctp_chunk_expr_alloc(&@$, SCTP_CHUNK_TYPE_INIT_ACK, $2); + } + | SACK sctp_chunk_sack_field + { + $$ = sctp_chunk_expr_alloc(&@$, SCTP_CHUNK_TYPE_SACK, $2); + } + | SHUTDOWN CUM_TSN_ACK + { + $$ = sctp_chunk_expr_alloc(&@$, SCTP_CHUNK_TYPE_SHUTDOWN, + SCTP_CHUNK_SHUTDOWN_CTSN_ACK); + } + | ECNE LOWEST_TSN + { + $$ = sctp_chunk_expr_alloc(&@$, SCTP_CHUNK_TYPE_ECNE, + SCTP_CHUNK_ECNE_CWR_MIN_TSN); + } + | CWR LOWEST_TSN + { + $$ = sctp_chunk_expr_alloc(&@$, SCTP_CHUNK_TYPE_CWR, + SCTP_CHUNK_ECNE_CWR_MIN_TSN); + } + | ASCONF_ACK SEQNO + { + $$ = sctp_chunk_expr_alloc(&@$, SCTP_CHUNK_TYPE_ASCONF_ACK, + SCTP_CHUNK_ASCONF_SEQNO); + } + | FORWARD_TSN NEW_CUM_TSN + { + $$ = sctp_chunk_expr_alloc(&@$, SCTP_CHUNK_TYPE_FORWARD_TSN, + SCTP_CHUNK_FORWARD_TSN_NCTSN); + } + | ASCONF SEQNO + { + $$ = sctp_chunk_expr_alloc(&@$, SCTP_CHUNK_TYPE_ASCONF, + SCTP_CHUNK_ASCONF_SEQNO); + } ; -sctp_hdr_expr : SCTP sctp_hdr_field +sctp_hdr_expr : SCTP sctp_hdr_field close_scope_sctp { $$ = payload_expr_alloc(&@$, &proto_sctp, $2); } + | SCTP CHUNK sctp_chunk_alloc close_scope_sctp_chunk close_scope_sctp + { + $$ = $3; + } ; sctp_hdr_field : SPORT { $$ = SCTPHDR_SPORT; } @@ -5122,7 +6179,7 @@ sctp_hdr_field : SPORT { $$ = SCTPHDR_SPORT; } | CHECKSUM { $$ = SCTPHDR_CHECKSUM; } ; -th_hdr_expr : TRANSPORT_HDR th_hdr_field +th_hdr_expr : TRANSPORT_HDR th_hdr_field close_scope_th { $$ = payload_expr_alloc(&@$, &proto_th, $2); if ($$) @@ -5144,7 +6201,7 @@ exthdr_expr : hbh_hdr_expr | mh_hdr_expr ; -hbh_hdr_expr : HBH hbh_hdr_field +hbh_hdr_expr : HBH hbh_hdr_field close_scope_hbh { $$ = exthdr_expr_alloc(&@$, &exthdr_hbh, $2); } @@ -5154,7 +6211,7 @@ hbh_hdr_field : NEXTHDR { $$ = HBHHDR_NEXTHDR; } | HDRLENGTH { $$ = HBHHDR_HDRLENGTH; } ; -rt_hdr_expr : RT rt_hdr_field +rt_hdr_expr : RT rt_hdr_field close_scope_rt { $$ = exthdr_expr_alloc(&@$, &exthdr_rt, $2); } @@ -5162,11 +6219,11 @@ rt_hdr_expr : RT rt_hdr_field rt_hdr_field : NEXTHDR { $$ = RTHDR_NEXTHDR; } | HDRLENGTH { $$ = RTHDR_HDRLENGTH; } - | TYPE { $$ = RTHDR_TYPE; } + | TYPE close_scope_type { $$ = RTHDR_TYPE; } | SEG_LEFT { $$ = RTHDR_SEG_LEFT; } ; -rt0_hdr_expr : RT0 rt0_hdr_field +rt0_hdr_expr : RT0 rt0_hdr_field close_scope_rt { $$ = exthdr_expr_alloc(&@$, &exthdr_rt0, $2); } @@ -5178,7 +6235,7 @@ rt0_hdr_field : ADDR '[' NUM ']' } ; -rt2_hdr_expr : RT2 rt2_hdr_field +rt2_hdr_expr : RT2 rt2_hdr_field close_scope_rt { $$ = exthdr_expr_alloc(&@$, &exthdr_rt2, $2); } @@ -5187,7 +6244,7 @@ rt2_hdr_expr : RT2 rt2_hdr_field rt2_hdr_field : ADDR { $$ = RT2HDR_ADDR; } ; -rt4_hdr_expr : RT4 rt4_hdr_field +rt4_hdr_expr : RT4 rt4_hdr_field close_scope_rt { $$ = exthdr_expr_alloc(&@$, &exthdr_rt4, $2); } @@ -5202,7 +6259,7 @@ rt4_hdr_field : LAST_ENT { $$ = RT4HDR_LASTENT; } } ; -frag_hdr_expr : FRAG frag_hdr_field +frag_hdr_expr : FRAG frag_hdr_field close_scope_frag { $$ = exthdr_expr_alloc(&@$, &exthdr_frag, $2); } @@ -5216,7 +6273,7 @@ frag_hdr_field : NEXTHDR { $$ = FRAGHDR_NEXTHDR; } | ID { $$ = FRAGHDR_ID; } ; -dst_hdr_expr : DST dst_hdr_field +dst_hdr_expr : DST dst_hdr_field close_scope_dst { $$ = exthdr_expr_alloc(&@$, &exthdr_dst, $2); } @@ -5226,7 +6283,7 @@ dst_hdr_field : NEXTHDR { $$ = DSTHDR_NEXTHDR; } | HDRLENGTH { $$ = DSTHDR_HDRLENGTH; } ; -mh_hdr_expr : MH mh_hdr_field +mh_hdr_expr : MH mh_hdr_field close_scope_mh { $$ = exthdr_expr_alloc(&@$, &exthdr_mh, $2); } @@ -5234,7 +6291,7 @@ mh_hdr_expr : MH mh_hdr_field mh_hdr_field : NEXTHDR { $$ = MHHDR_NEXTHDR; } | HDRLENGTH { $$ = MHHDR_HDRLENGTH; } - | TYPE { $$ = MHHDR_TYPE; } + | TYPE close_scope_type { $$ = MHHDR_TYPE; } | RESERVED { $$ = MHHDR_RESERVED; } | CHECKSUM { $$ = MHHDR_CHECKSUM; } ; @@ -5246,18 +6303,18 @@ exthdr_exists_expr : EXTHDR exthdr_key desc = exthdr_find_proto($2); /* Assume that NEXTHDR template is always - * the fist one in list of templates. + * the first 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; } +exthdr_key : HBH close_scope_hbh { $$ = IPPROTO_HOPOPTS; } + | RT close_scope_rt { $$ = IPPROTO_ROUTING; } + | FRAG close_scope_frag { $$ = IPPROTO_FRAGMENT; } + | DST close_scope_dst { $$ = IPPROTO_DSTOPTS; } + | MH close_scope_mh { $$ = IPPROTO_MH; } ; %% |