/* * Copyright (c) 2007-2008 Patrick McHardy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Development of this code funded by Astaro AG (http://www.astaro.com/) */ %{ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "parser.h" #include "scanner.h" void parser_init(struct parser_state *state, struct list_head *msgs) { memset(state, 0, sizeof(*state)); init_list_head(&state->cmds); state->msgs = msgs; } static void yyerror(struct location *loc, void *scanner, struct parser_state *state, const char *s) { erec_queue(error(loc, "%s", s), state->msgs); } static void location_init(void *scanner, struct parser_state *state, struct location *loc) { memset(loc, 0, sizeof(*loc)); loc->indesc = state->indesc; } static void location_update(struct location *loc, struct location *rhs, int n) { if (n) { loc->indesc = rhs[n].indesc; loc->token_offset = rhs[1].token_offset; loc->line_offset = rhs[1].line_offset; loc->first_line = rhs[1].first_line; loc->first_column = rhs[1].first_column; loc->last_line = rhs[n].last_line; loc->last_column = rhs[n].last_column; } else { loc->indesc = rhs[0].indesc; loc->token_offset = rhs[0].token_offset; loc->line_offset = rhs[0].line_offset; loc->first_line = loc->last_line = rhs[0].last_line; loc->first_column = loc->last_column = rhs[0].last_column; } } #define YYLLOC_DEFAULT(Current, Rhs, N) location_update(&Current, Rhs, N) %} /* Declaration section */ %name-prefix="nft_" %debug %pure-parser %parse-param { void *scanner } %parse-param { struct parser_state *state } %lex-param { scanner } %error-verbose %locations %initial-action { location_init(scanner, state, &yylloc); #if 0 nft_set_debug(1, scanner); yydebug = 1; #endif } %union { uint64_t val; const char * string; struct list_head *list; struct cmd *cmd; struct handle handle; struct table *table; struct chain *chain; struct rule *rule; struct stmt *stmt; struct expr *expr; } %token TOKEN_EOF 0 "end of file" %token JUNK "junk" %token NEWLINE "newline" %token COLON "colon" %token SEMICOLON "semicolon" %token COMMA "comma" %token DOT "." %token EQ "==" %token NEQ "!=" %token LT "<" %token GT ">" %token GTE ">=" %token LTE "<=" %token LSHIFT "<<" %token RSHIFT ">>" %token AMPERSAND "&" %token CARET "^" %token NOT "!" %token SLASH "/" %token ASTERISK "*" %token DASH "-" %token AT "@" %token ARROW "=>" %token MAP "map" %token VMAP "vmap" %token SET "set" %token INCLUDE "include" %token HOOK "hook" %token HOOKNUM "hooknum" %token TABLE "table" %token CHAIN "chain" %token RULE "rule" %token HANDLE "handle" %token ADD "add" %token DELETE "delete" %token LIST "list" %token FLUSH "flush" %token DESCRIBE "describe" %token ACCEPT "accept" %token DROP "drop" %token CONTINUE "continue" %token JUMP "jump" %token GOTO "goto" %token RETURN "return" %token QUEUE "queue" %token NUM "number" %token STRING "string" %token QUOTED_STRING %destructor { xfree($$); } STRING QUOTED_STRING %token LL_HDR "ll" %token NETWORK_HDR "nh" %token TRANSPORT_HDR "th" %token BRIDGE "bridge" %token ETH "eth" %token SADDR "saddr" %token DADDR "daddr" %token TYPE "type" %token VLAN "vlan" %token ID "id" %token CFI "cfi" %token PCP "pcp" %token ARP "arp" %token HTYPE "htype" %token PTYPE "ptype" %token HLEN "hlen" %token PLEN "plen" %token OPERATION "operation" %token IP "ip" %token VERSION "version" %token HDRLENGTH "hdrlength" %token TOS "tos" %token LENGTH "length" %token FRAG_OFF "frag-off" %token TTL "ttl" %token PROTOCOL "protocol" %token CHECKSUM "checksum" %token ICMP "icmp" %token CODE "code" %token SEQUENCE "seq" %token GATEWAY "gateway" %token MTU "mtu" %token IP6 "ip6" %token PRIORITY "priority" %token FLOWLABEL "flowlabel" %token NEXTHDR "nexthdr" %token HOPLIMIT "hoplimit" %token AH "ah" %token RESERVED "reserved" %token SPI "spi" %token ESP "esp" %token COMP "comp" %token FLAGS "flags" %token CPI "cpi" %token UDP "udp" %token SPORT "sport" %token DPORT "dport" %token UDPLITE "udplite" %token CSUMCOV "csumcov" %token TCP "tcp" %token ACKSEQ "ackseq" %token DOFF "doff" %token WINDOW "window" %token URGPTR "urgptr" %token DCCP "dccp" %token SCTP "sctp" %token VTAG "vtag" %token RT "rt" %token RT0 "rt0" %token RT2 "rt2" %token SEG_LEFT "seg-left" %token ADDR "addr" %token HBH "hbh" %token FRAG "frag" %token RESERVED2 "reserved2" %token MORE_FRAGMENTS "more-fragments" %token DST "dst" %token MH "mh" %token META "meta" %token MARK "mark" %token IIF "iif" %token IIFNAME "iifname" %token IIFTYPE "iiftype" %token OIF "oif" %token OIFNAME "oifname" %token OIFTYPE "oiftype" %token SKUID "skuid" %token SKGID "skgid" %token NFTRACE "nftrace" %token RTCLASSID "rtclassid" %token SECMARK "secmark" %token CT "ct" %token DIRECTION "direction" %token STATE "state" %token STATUS "status" %token EXPIRATION "expiration" %token HELPER "helper" %token PROTO_SRC "proto-src" %token PROTO_DST "proto-dst" %token COUNTER "counter" %token LOG "log" %token PREFIX "prefix" %token GROUP "group" %token SNAPLEN "snaplen" %token QUEUE_THRESHOLD "queue-threshold" %token LIMIT "limit" %token RATE "rate" %token NANOSECOND "nanosecond" %token MICROSECOND "microsecond" %token MILLISECOND "millisecond" %token SECOND "second" %token MINUTE "minute" %token HOUR "hour" %token DAY "day" %token WEEK "week" %token _REJECT "reject" %token SNAT "snat" %token DNAT "dnat" %type identifier string %destructor { xfree($$); } identifier string %type line %destructor { cmd_free($$); } line %type base_cmd add_cmd delete_cmd list_cmd flush_cmd %destructor { cmd_free($$); } base_cmd add_cmd delete_cmd list_cmd flush_cmd %type table_spec chain_spec chain_identifier ruleid_spec %destructor { handle_free(&$$); } table_spec chain_spec chain_identifier ruleid_spec %type handle_spec family_spec %type table_block_alloc table_block %destructor { table_free($$); } table_block_alloc %type table_line chain_block_alloc chain_block %destructor { chain_free($$); } table_line chain_block_alloc %type rule %destructor { rule_free($$); } rule %type stmt_list %destructor { stmt_list_free($$); xfree($$); } stmt_list %type stmt match_stmt verdict_stmt %destructor { stmt_free($$); } stmt match_stmt verdict_stmt %type counter_stmt %destructor { stmt_free($$); } counter_stmt %type meta_stmt %destructor { stmt_free($$); } meta_stmt %type log_stmt log_stmt_alloc %destructor { stmt_free($$); } log_stmt log_stmt_alloc %type limit_stmt %destructor { stmt_free($$); } limit_stmt %type time_unit %type reject_stmt %destructor { stmt_free($$); } reject_stmt %type nat_stmt nat_stmt_alloc %destructor { stmt_free($$); } nat_stmt nat_stmt_alloc %type symbol_expr verdict_expr integer_expr %destructor { expr_free($$); } symbol_expr verdict_expr integer_expr %type primary_expr shift_expr and_expr %destructor { expr_free($$); } primary_expr shift_expr and_expr %type exclusive_or_expr inclusive_or_expr %destructor { expr_free($$); } exclusive_or_expr inclusive_or_expr %type basic_expr %destructor { expr_free($$); } basic_expr %type multiton_expr %destructor { expr_free($$); } multiton_expr %type prefix_expr range_expr wildcard_expr %destructor { expr_free($$); } prefix_expr range_expr wildcard_expr %type list_expr %destructor { expr_free($$); } list_expr %type concat_expr map_lhs_expr %destructor { expr_free($$); } concat_expr map_lhs_expr %type map_expr map_list map_list_expr %destructor { expr_free($$); } map_expr map_list map_list_expr %type verdict_map_expr verdict_map_list verdict_map_list_expr %destructor { expr_free($$); } verdict_map_expr verdict_map_list verdict_map_list_expr %type set_expr %destructor { expr_free($$); } set_expr %type expr %destructor { expr_free($$); } expr %type match_expr %destructor { expr_free($$); } match_expr %type relational_expr membership_expr %destructor { expr_free($$); } relational_expr membership_expr %type relational_op %type payload_expr payload_raw_expr %destructor { expr_free($$); } payload_expr payload_raw_expr %type payload_base_spec %type eth_hdr_expr vlan_hdr_expr %destructor { expr_free($$); } eth_hdr_expr vlan_hdr_expr %type eth_hdr_field vlan_hdr_field %type arp_hdr_expr %destructor { expr_free($$); } arp_hdr_expr %type arp_hdr_field %type ip_hdr_expr icmp_hdr_expr %destructor { expr_free($$); } ip_hdr_expr icmp_hdr_expr %type ip_hdr_field icmp_hdr_field %type ip6_hdr_expr %destructor { expr_free($$); } ip6_hdr_expr %type ip6_hdr_field %type auth_hdr_expr esp_hdr_expr comp_hdr_expr %destructor { expr_free($$); } auth_hdr_expr esp_hdr_expr comp_hdr_expr %type auth_hdr_field esp_hdr_field comp_hdr_field %type udp_hdr_expr udplite_hdr_expr tcp_hdr_expr %destructor { expr_free($$); } udp_hdr_expr udplite_hdr_expr tcp_hdr_expr %type udp_hdr_field udplite_hdr_field tcp_hdr_field %type dccp_hdr_expr sctp_hdr_expr %destructor { expr_free($$); } dccp_hdr_expr sctp_hdr_expr %type dccp_hdr_field sctp_hdr_field %type exthdr_expr %destructor { expr_free($$); } exthdr_expr %type hbh_hdr_expr frag_hdr_expr dst_hdr_expr %destructor { expr_free($$); } hbh_hdr_expr frag_hdr_expr dst_hdr_expr %type hbh_hdr_field frag_hdr_field dst_hdr_field %type rt_hdr_expr rt0_hdr_expr rt2_hdr_expr %destructor { expr_free($$); } rt_hdr_expr rt0_hdr_expr rt2_hdr_expr %type rt_hdr_field rt0_hdr_field rt2_hdr_field %type mh_hdr_expr %destructor { expr_free($$); } mh_hdr_expr %type mh_hdr_field %type meta_expr %destructor { expr_free($$); } meta_expr %type meta_key %type ct_expr %destructor { expr_free($$); } ct_expr %type ct_key %% input : /* empty */ | input line { if ($2 != NULL) { $2->location = @2; list_add_tail(&$2->list, &state->cmds); } } ; stmt_seperator : NEWLINE | SEMICOLON ; common_block : INCLUDE QUOTED_STRING stmt_seperator { if (scanner_include_file(scanner, $2, &@$) < 0) { xfree($2); YYERROR; } xfree($2); } ; line : common_block { $$ = NULL; } | stmt_seperator { $$ = NULL; } | base_cmd stmt_seperator { $$ = $1; } | base_cmd TOKEN_EOF { $$ = $1; } | base_cmd error { $$ = $1; } ; base_cmd : /* empty */ add_cmd { $$ = $1; } | ADD add_cmd { $$ = $2; } | DELETE delete_cmd { $$ = $2; } | LIST list_cmd { $$ = $2; } | FLUSH flush_cmd { $$ = $2; } | DESCRIBE primary_expr { expr_describe($2); expr_free($2); $$ = NULL; } ; add_cmd : TABLE table_spec { $$ = cmd_alloc(CMD_ADD, CMD_OBJ_TABLE, &$2, NULL); } | TABLE table_spec table_block_alloc '{' table_block '}' { handle_merge(&$3->handle, &$2); $$ = cmd_alloc(CMD_ADD, CMD_OBJ_TABLE, &$2, $5); } | CHAIN chain_spec { $$ = cmd_alloc(CMD_ADD, CMD_OBJ_CHAIN, &$2, NULL); } | CHAIN chain_spec chain_block_alloc '{' chain_block '}' { handle_merge(&$3->handle, &$2); $$ = cmd_alloc(CMD_ADD, CMD_OBJ_CHAIN, &$2, $5); } | RULE ruleid_spec rule { $$ = cmd_alloc(CMD_ADD, CMD_OBJ_RULE, &$2, $3); } | /* empty */ ruleid_spec rule { $$ = cmd_alloc(CMD_ADD, CMD_OBJ_RULE, &$1, $2); } ; delete_cmd : TABLE table_spec { $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_TABLE, &$2, NULL); } | CHAIN chain_spec { $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_CHAIN, &$2, NULL); } | RULE ruleid_spec { $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_RULE, &$2, NULL); } ; list_cmd : TABLE table_spec { $$ = cmd_alloc(CMD_LIST, CMD_OBJ_TABLE, &$2, NULL); } | CHAIN chain_spec { $$ = cmd_alloc(CMD_LIST, CMD_OBJ_CHAIN, &$2, NULL); } ; flush_cmd : TABLE table_spec { $$ = cmd_alloc(CMD_FLUSH, CMD_OBJ_TABLE, &$2, NULL); } | CHAIN chain_spec { $$ = cmd_alloc(CMD_FLUSH, CMD_OBJ_CHAIN, &$2, NULL); } ; table_block_alloc : /* empty */ { $$ = table_alloc(); } ; table_block : /* empty */ { $$ = $
-1; } | common_block { $$ = $
-1; } | table_block stmt_seperator | table_block table_line stmt_seperator { list_add_tail(&$2->list, &$1->chains); $$ = $1; } ; table_line : CHAIN chain_identifier chain_block_alloc '{' chain_block '}' { handle_merge(&$3->handle, &$2); $$ = $3; } ; chain_block_alloc : /* empty */ { $$ = chain_alloc(NULL); } ; chain_block : /* empty */ { $$ = $-1; } | common_block { $$ = $-1; } | chain_block stmt_seperator | chain_block hook_spec stmt_seperator | chain_block rule stmt_seperator { list_add_tail(&$2->list, &$1->rules); $$ = $1; } ; hook_spec : HOOK HOOKNUM NUM { $0->hooknum = $2; $0->priority = $3; } | HOOK HOOKNUM DASH NUM { $0->hooknum = $2; $0->priority = -$4; } ; identifier : STRING ; string : STRING | QUOTED_STRING ; family_spec : /* empty */ { $$ = NFPROTO_IPV4; } | IP { $$ = NFPROTO_IPV4; } | IP6 { $$ = NFPROTO_IPV6; } | ARP { $$ = NFPROTO_ARP; } | BRIDGE { $$ = NFPROTO_BRIDGE; } ; table_spec : family_spec identifier { memset(&$$, 0, sizeof($$)); $$.family = $1; $$.table = $2; } ; chain_spec : table_spec identifier { $$ = $1; $$.chain = $2; } ; chain_identifier : identifier { memset(&$$, 0, sizeof($$)); $$.chain = $1; } ; handle_spec : /* empty */ { $$ = 0; } | HANDLE NUM { $$ = $2; } ; ruleid_spec : chain_spec handle_spec { $$ = $1; $$.handle = $2; } ; rule : stmt_list { struct stmt *i; $$ = rule_alloc(&@$, NULL); list_for_each_entry(i, $1, list) $$->num_stmts++; list_splice_tail($1, &$$->stmts); xfree($1); } ; stmt_list : stmt { $$ = xmalloc(sizeof(*$$)); init_list_head($$); list_add_tail(&$1->list, $$); } | stmt_list stmt { $$ = $1; list_add_tail(&$2->list, $1); } ; stmt : verdict_stmt | match_stmt | counter_stmt | meta_stmt | log_stmt | limit_stmt | reject_stmt | nat_stmt ; verdict_stmt : verdict_expr { $$ = verdict_stmt_alloc(&@1, $1); } | verdict_map_expr { $$ = verdict_stmt_alloc(&@1, $1); } ; counter_stmt : COUNTER { $$ = counter_stmt_alloc(&@1); } ; log_stmt : log_stmt_alloc | log_stmt_alloc log_args ; log_stmt_alloc : LOG { $$ = log_stmt_alloc(&@1); } ; log_args : log_arg { $$ = $0; } | log_args log_arg ; log_arg : PREFIX string { $0->log.prefix = $2; } | GROUP NUM { $0->log.group = $2; } | SNAPLEN NUM { $0->log.snaplen = $2; } | QUEUE_THRESHOLD NUM { $0->log.qthreshold = $2; } ; limit_stmt : LIMIT RATE NUM SLASH time_unit { $$ = limit_stmt_alloc(&@$); $$->limit.rate = $3; $$->limit.unit = $5; } ; time_unit : NANOSECOND { $$ = 1ULL; } | MICROSECOND { $$ = 1ULL * 1000; } | MILLISECOND { $$ = 1ULL * 1000 * 1000; } | SECOND { $$ = 1ULL * 1000 * 1000 * 1000; } | MINUTE { $$ = 1ULL * 1000 * 1000 * 1000 * 60; } | HOUR { $$ = 1ULL * 1000 * 1000 * 1000 * 60 * 60; } | DAY { $$ = 1ULL * 1000 * 1000 * 1000 * 60 * 60 * 24; } | WEEK { $$ = 1ULL * 1000 * 1000 * 1000 * 60 * 60 * 24 * 7; } ; reject_stmt : _REJECT { $$ = reject_stmt_alloc(&@$); } ; nat_stmt : nat_stmt_alloc nat_stmt_args ; nat_stmt_alloc : SNAT { $$ = nat_stmt_alloc(&@$); $$->nat.type = NFT_NAT_SNAT; } | DNAT { $$ = nat_stmt_alloc(&@$); $$->nat.type = NFT_NAT_DNAT; } ; nat_stmt_args : expr { $0->nat.addr = $1; } | expr COLON expr { $0->nat.addr = $1; $0->nat.proto = $3; } | COLON expr { $0->nat.proto = $2; } ; match_stmt : match_expr { $$ = expr_stmt_alloc(&@$, $1); } ; symbol_expr : string { $$ = symbol_expr_alloc(&@1, $1); xfree($1); } ; integer_expr : NUM { char str[64]; snprintf(str, sizeof(str), "%" PRIu64, $1); $$ = symbol_expr_alloc(&@1, str); } ; primary_expr : symbol_expr { $$ = $1; } | integer_expr { $$ = $1; } | payload_expr { $$ = $1; } | exthdr_expr { $$ = $1; } | meta_expr { $$ = $1; } | ct_expr { $$ = $1; } | '(' basic_expr ')' { $$ = $2; } ; shift_expr : primary_expr | shift_expr LSHIFT primary_expr { $$ = binop_expr_alloc(&@$, OP_LSHIFT, $1, $3); } | shift_expr RSHIFT primary_expr { $$ = binop_expr_alloc(&@$, OP_RSHIFT, $1, $3); } ; and_expr : shift_expr | and_expr AMPERSAND shift_expr { $$ = binop_expr_alloc(&@$, OP_AND, $1, $3); } ; exclusive_or_expr : and_expr | exclusive_or_expr CARET and_expr { $$ = binop_expr_alloc(&@$, OP_XOR, $1, $3); } ; inclusive_or_expr : exclusive_or_expr | inclusive_or_expr '|' exclusive_or_expr { $$ = binop_expr_alloc(&@$, OP_OR, $1, $3); } ; basic_expr : inclusive_or_expr ; concat_expr : basic_expr | concat_expr DOT basic_expr { if ($$->ops->type != EXPR_CONCAT) { $$ = concat_expr_alloc(&@$); compound_expr_add($$, $1); } else { $$ = $1; $$->location = @$; } compound_expr_add($$, $3); } ; list_expr : basic_expr COMMA basic_expr { $$ = list_expr_alloc(&@$); compound_expr_add($$, $1); compound_expr_add($$, $3); } | list_expr COMMA basic_expr { $1->location = @$; compound_expr_add($1, $3); $$ = $1; } ; prefix_expr : basic_expr SLASH NUM { $$ = prefix_expr_alloc(&@$, $1, $3); } ; range_expr : basic_expr DASH basic_expr { $$ = range_expr_alloc(&@$, $1, $3); } ; wildcard_expr : ASTERISK { struct expr *expr; expr = constant_expr_alloc(&@1, &integer_type, BYTEORDER_HOST_ENDIAN, 0, NULL); $$ = prefix_expr_alloc(&@$, expr, 0); } ; multiton_expr : prefix_expr | range_expr | wildcard_expr ; map_lhs_expr : multiton_expr | concat_expr ; map_expr : concat_expr MAP '{' map_list '}' { $$ = map_expr_alloc(&@$, $1, $4); } ; map_list : map_list_expr { $$ = set_expr_alloc(&@$); compound_expr_add($$, $1); } | map_list COMMA map_list_expr { compound_expr_add($1, $3); $1->location = @$; $$ = $1; } | map_list COMMA ; map_list_expr : map_lhs_expr ARROW concat_expr { $$ = mapping_expr_alloc(&@$, $1, $3); } ; verdict_map_expr : concat_expr VMAP '{' verdict_map_list '}' { $$ = map_expr_alloc(&@$, $1, $4); } ; verdict_map_list : verdict_map_list_expr { $$ = set_expr_alloc(&@$); compound_expr_add($$, $1); } | verdict_map_list COMMA verdict_map_list_expr { compound_expr_add($1, $3); $1->location = @$; $$ = $1; } | verdict_map_list COMMA ; verdict_map_list_expr : map_lhs_expr ARROW verdict_expr { $$ = mapping_expr_alloc(&@$, $1, $3); } ; expr : concat_expr | map_expr | multiton_expr ; match_expr : relational_expr | membership_expr ; relational_expr : expr /* implicit */ expr { enum ops op; /* RHS determines operation */ op = ($2->ops->type == EXPR_RANGE) ? OP_RANGE : OP_EQ; $$ = relational_expr_alloc(&@$, op, $1, $2); } | expr /* implicit */ list_expr { $$ = relational_expr_alloc(&@$, OP_FLAGCMP, $1, $2); } | expr relational_op expr { $$ = relational_expr_alloc(&@2, $2, $1, $3); } ; relational_op : EQ { $$ = OP_EQ; } | NEQ { $$ = OP_NEQ; } | LT { $$ = OP_LT; } | GT { $$ = OP_GT; } | GTE { $$ = OP_GTE; } | LTE { $$ = OP_LTE; } ; membership_expr : expr '{' set_expr '}' { $3->location = @$; $$ = relational_expr_alloc(&@$, OP_LOOKUP, $1, $3); } ; set_expr : expr { $$ = set_expr_alloc(&@1); compound_expr_add($$, $1); } | set_expr COMMA expr { compound_expr_add($1, $3); $$ = $1; } | set_expr COMMA ; verdict_expr : ACCEPT { $$ = verdict_expr_alloc(&@1, NF_ACCEPT, NULL); } | DROP { $$ = verdict_expr_alloc(&@1, NF_DROP, NULL); } | QUEUE { $$ = verdict_expr_alloc(&@1, NF_QUEUE, NULL); } | CONTINUE { $$ = verdict_expr_alloc(&@1, NFT_CONTINUE, NULL); } | JUMP identifier { $$ = verdict_expr_alloc(&@1, NFT_JUMP, $2); } | GOTO identifier { $$ = verdict_expr_alloc(&@1, NFT_GOTO, $2); } | RETURN { $$ = verdict_expr_alloc(&@1, NFT_RETURN, NULL); } ; meta_expr : META meta_key { $$ = meta_expr_alloc(&@$, $2); } ; meta_key : LENGTH { $$ = NFT_META_LEN; } | PROTOCOL { $$ = NFT_META_PROTOCOL; } | PRIORITY { $$ = NFT_META_PRIORITY; } | MARK { $$ = NFT_META_MARK; } | IIF { $$ = NFT_META_IIF; } | IIFNAME { $$ = NFT_META_IIFNAME; } | IIFTYPE { $$ = NFT_META_IIFTYPE; } | OIF { $$ = NFT_META_OIF; } | OIFNAME { $$ = NFT_META_OIFNAME; } | OIFTYPE { $$ = NFT_META_OIFTYPE; } | SKUID { $$ = NFT_META_SKUID; } | SKGID { $$ = NFT_META_SKGID; } | NFTRACE { $$ = NFT_META_NFTRACE; } | RTCLASSID { $$ = NFT_META_RTCLASSID; } | SECMARK { $$ = NFT_META_SECMARK; } ; meta_stmt : META meta_key SET expr { $$ = meta_stmt_alloc(&@$, $2, $4); } ; ct_expr : CT ct_key { $$ = ct_expr_alloc(&@$, $2); } ; ct_key : STATE { $$ = NFT_CT_STATE; } | DIRECTION { $$ = NFT_CT_DIRECTION; } | STATUS { $$ = NFT_CT_STATUS; } | MARK { $$ = NFT_CT_MARK; } | SECMARK { $$ = NFT_CT_SECMARK; } | EXPIRATION { $$ = NFT_CT_EXPIRATION; } | HELPER { $$ = NFT_CT_HELPER; } | PROTOCOL { $$ = NFT_CT_PROTOCOL; } | SADDR { $$ = NFT_CT_SADDR; } | DADDR { $$ = NFT_CT_DADDR; } | PROTO_SRC { $$ = NFT_CT_PROTO_SRC; } | PROTO_DST { $$ = NFT_CT_PROTO_DST; } ; payload_expr : payload_raw_expr | eth_hdr_expr | vlan_hdr_expr | arp_hdr_expr | ip_hdr_expr | icmp_hdr_expr | ip6_hdr_expr | auth_hdr_expr | esp_hdr_expr | comp_hdr_expr | udp_hdr_expr | udplite_hdr_expr | tcp_hdr_expr | dccp_hdr_expr | sctp_hdr_expr ; payload_raw_expr : AT payload_base_spec COMMA NUM COMMA NUM { $$ = payload_expr_alloc(&@$, NULL, 0); $$->payload.base = $2; $$->payload.offset = $4; $$->len = $6; $$->dtype = &integer_type; } ; payload_base_spec : LL_HDR { $$ = PAYLOAD_BASE_LL_HDR; } | NETWORK_HDR { $$ = PAYLOAD_BASE_NETWORK_HDR; } | TRANSPORT_HDR { $$ = PAYLOAD_BASE_TRANSPORT_HDR; } ; eth_hdr_expr : ETH eth_hdr_field { $$ = payload_expr_alloc(&@$, &payload_eth, $2); } ; eth_hdr_field : SADDR { $$ = ETHHDR_SADDR; } | DADDR { $$ = ETHHDR_DADDR; } | TYPE { $$ = ETHHDR_TYPE; } ; vlan_hdr_expr : VLAN vlan_hdr_field { $$ = payload_expr_alloc(&@$, &payload_vlan, $2); } ; vlan_hdr_field : ID { $$ = VLANHDR_VID; } | CFI { $$ = VLANHDR_CFI; } | PCP { $$ = VLANHDR_PCP; } | TYPE { $$ = VLANHDR_TYPE; } ; arp_hdr_expr : ARP arp_hdr_field { $$ = payload_expr_alloc(&@$, &payload_arp, $2); } ; arp_hdr_field : HTYPE { $$ = ARPHDR_HRD; } | PTYPE { $$ = ARPHDR_PRO; } | HLEN { $$ = ARPHDR_HLN; } | PLEN { $$ = ARPHDR_PLN; } | OPERATION { $$ = ARPHDR_OP; } ; ip_hdr_expr : IP ip_hdr_field { $$ = payload_expr_alloc(&@$, &payload_ip, $2); } ; ip_hdr_field : VERSION { $$ = IPHDR_VERSION; } | HDRLENGTH { $$ = IPHDR_HDRLENGTH; } | TOS { $$ = IPHDR_TOS; } | LENGTH { $$ = IPHDR_LENGTH; } | ID { $$ = IPHDR_ID; } | FRAG_OFF { $$ = IPHDR_FRAG_OFF; } | TTL { $$ = IPHDR_TTL; } | PROTOCOL { $$ = IPHDR_PROTOCOL; } | CHECKSUM { $$ = IPHDR_CHECKSUM; } | SADDR { $$ = IPHDR_SADDR; } | DADDR { $$ = IPHDR_DADDR; } ; icmp_hdr_expr : ICMP icmp_hdr_field { $$ = payload_expr_alloc(&@$, &payload_icmp, $2); } ; icmp_hdr_field : TYPE { $$ = ICMPHDR_TYPE; } | CODE { $$ = ICMPHDR_CODE; } | CHECKSUM { $$ = ICMPHDR_CHECKSUM; } | ID { $$ = ICMPHDR_ID; } | SEQUENCE { $$ = ICMPHDR_SEQ; } | GATEWAY { $$ = ICMPHDR_GATEWAY; } | MTU { $$ = ICMPHDR_MTU; } ; ip6_hdr_expr : IP6 ip6_hdr_field { $$ = payload_expr_alloc(&@$, &payload_ip6, $2); } ; ip6_hdr_field : VERSION { $$ = IP6HDR_VERSION; } | PRIORITY { $$ = IP6HDR_PRIORITY; } | FLOWLABEL { $$ = IP6HDR_FLOWLABEL; } | LENGTH { $$ = IP6HDR_LENGTH; } | NEXTHDR { $$ = IP6HDR_NEXTHDR; } | HOPLIMIT { $$ = IP6HDR_HOPLIMIT; } | SADDR { $$ = IP6HDR_SADDR; } | DADDR { $$ = IP6HDR_DADDR; } ; auth_hdr_expr : AH auth_hdr_field { $$ = payload_expr_alloc(&@$, &payload_ah, $2); } ; auth_hdr_field : NEXTHDR { $$ = AHHDR_NEXTHDR; } | HDRLENGTH { $$ = AHHDR_HDRLENGTH; } | RESERVED { $$ = AHHDR_RESERVED; } | SPI { $$ = AHHDR_SPI; } | SEQUENCE { $$ = AHHDR_SEQUENCE; } ; esp_hdr_expr : ESP esp_hdr_field { $$ = payload_expr_alloc(&@$, &payload_esp, $2); } ; esp_hdr_field : SPI { $$ = ESPHDR_SPI; } | SEQUENCE { $$ = ESPHDR_SEQUENCE; } ; comp_hdr_expr : COMP comp_hdr_field { $$ = payload_expr_alloc(&@$, &payload_comp, $2); } ; comp_hdr_field : NEXTHDR { $$ = COMPHDR_NEXTHDR; } | FLAGS { $$ = COMPHDR_FLAGS; } | CPI { $$ = COMPHDR_CPI; } ; udp_hdr_expr : UDP udp_hdr_field { $$ = payload_expr_alloc(&@$, &payload_udp, $2); } ; udp_hdr_field : SPORT { $$ = UDPHDR_SPORT; } | DPORT { $$ = UDPHDR_DPORT; } | LENGTH { $$ = UDPHDR_LENGTH; } | CHECKSUM { $$ = UDPHDR_CHECKSUM; } ; udplite_hdr_expr : UDPLITE udplite_hdr_field { $$ = payload_expr_alloc(&@$, &payload_udplite, $2); } ; udplite_hdr_field : SPORT { $$ = UDPHDR_SPORT; } | DPORT { $$ = UDPHDR_DPORT; } | CSUMCOV { $$ = UDPHDR_LENGTH; } | CHECKSUM { $$ = UDPHDR_CHECKSUM; } ; tcp_hdr_expr : TCP tcp_hdr_field { $$ = payload_expr_alloc(&@$, &payload_tcp, $2); } ; tcp_hdr_field : SPORT { $$ = TCPHDR_SPORT; } | DPORT { $$ = TCPHDR_DPORT; } | SEQUENCE { $$ = TCPHDR_SEQ; } | ACKSEQ { $$ = TCPHDR_ACKSEQ; } | DOFF { $$ = TCPHDR_DOFF; } | RESERVED { $$ = TCPHDR_RESERVED; } | FLAGS { $$ = TCPHDR_FLAGS; } | WINDOW { $$ = TCPHDR_WINDOW; } | CHECKSUM { $$ = TCPHDR_CHECKSUM; } | URGPTR { $$ = TCPHDR_URGPTR; } ; dccp_hdr_expr : DCCP dccp_hdr_field { $$ = payload_expr_alloc(&@$, &payload_dccp, $2); } ; dccp_hdr_field : SPORT { $$ = DCCPHDR_SPORT; } | DPORT { $$ = DCCPHDR_DPORT; } ; sctp_hdr_expr : SCTP sctp_hdr_field { $$ = payload_expr_alloc(&@$, &payload_sctp, $2); } ; sctp_hdr_field : SPORT { $$ = SCTPHDR_SPORT; } | DPORT { $$ = SCTPHDR_DPORT; } | VTAG { $$ = SCTPHDR_VTAG; } | CHECKSUM { $$ = SCTPHDR_CHECKSUM; } ; exthdr_expr : hbh_hdr_expr | rt_hdr_expr | rt0_hdr_expr | rt2_hdr_expr | frag_hdr_expr | dst_hdr_expr | mh_hdr_expr ; hbh_hdr_expr : HBH hbh_hdr_field { $$ = exthdr_expr_alloc(&@$, &exthdr_hbh, $2); } ; hbh_hdr_field : NEXTHDR { $$ = HBHHDR_NEXTHDR; } | HDRLENGTH { $$ = HBHHDR_HDRLENGTH; } ; rt_hdr_expr : RT rt_hdr_field { $$ = exthdr_expr_alloc(&@$, &exthdr_rt, $2); } ; rt_hdr_field : NEXTHDR { $$ = RTHDR_NEXTHDR; } | HDRLENGTH { $$ = RTHDR_HDRLENGTH; } | TYPE { $$ = RTHDR_TYPE; } | SEG_LEFT { $$ = RTHDR_SEG_LEFT; } ; rt0_hdr_expr : RT0 rt0_hdr_field { $$ = exthdr_expr_alloc(&@$, &exthdr_rt0, $2); } ; rt0_hdr_field : ADDR '[' NUM ']' { $$ = RT0HDR_ADDR_1 + $3 - 1; } ; rt2_hdr_expr : RT2 rt2_hdr_field { $$ = exthdr_expr_alloc(&@$, &exthdr_rt2, $2); } ; rt2_hdr_field : ADDR { $$ = RT2HDR_ADDR; } ; frag_hdr_expr : FRAG frag_hdr_field { $$ = exthdr_expr_alloc(&@$, &exthdr_frag, $2); } ; frag_hdr_field : NEXTHDR { $$ = FRAGHDR_NEXTHDR; } | RESERVED { $$ = FRAGHDR_RESERVED; } | FRAG_OFF { $$ = FRAGHDR_FRAG_OFF; } | RESERVED2 { $$ = FRAGHDR_RESERVED2; } | MORE_FRAGMENTS { $$ = FRAGHDR_MFRAGS; } | ID { $$ = FRAGHDR_ID; } ; dst_hdr_expr : DST dst_hdr_field { $$ = exthdr_expr_alloc(&@$, &exthdr_dst, $2); } ; dst_hdr_field : NEXTHDR { $$ = DSTHDR_NEXTHDR; } | HDRLENGTH { $$ = DSTHDR_HDRLENGTH; } ; mh_hdr_expr : MH mh_hdr_field { $$ = exthdr_expr_alloc(&@$, &exthdr_mh, $2); } ; mh_hdr_field : NEXTHDR { $$ = MHHDR_NEXTHDR; } | HDRLENGTH { $$ = MHHDR_HDRLENGTH; } | TYPE { $$ = MHHDR_TYPE; } | RESERVED { $$ = MHHDR_RESERVED; } | CHECKSUM { $$ = MHHDR_CHECKSUM; } ; %%