summaryrefslogtreecommitdiffstats
path: root/src/parser_bison.y
diff options
context:
space:
mode:
authorManuel Messner <mm@skelett.io>2017-02-07 03:14:12 +0100
committerFlorian Westphal <fw@strlen.de>2017-02-12 15:34:47 +0100
commit864a1b44e1937a42753648644a812f70f9500a73 (patch)
tree97976d52c9d08746bd68d611be1c8443090475da /src/parser_bison.y
parent9574c263569f477114d7885ebcf5af8af6411582 (diff)
src: add TCP option matching
This patch enables nft to match against TCP options. Currently these TCP options are supported: * End of Option List (eol) * No-Operation (noop) * Maximum Segment Size (maxseg) * Window Scale (window) * SACK Permitted (sack_permitted) * SACK (sack) * Timestamps (timestamp) Syntax: tcp options $option_name [$offset] $field_name Example: # count all incoming packets with a specific maximum segment size `x` # nft add rule filter input tcp option maxseg size x counter # count all incoming packets with a SACK TCP option where the third # (counted from zero) left field is greater `x`. # nft add rule filter input tcp option sack 2 left \> x counter If the offset (the `2` in the example above) is zero, it can optionally be omitted. For all non-SACK TCP options it is always zero, thus can be left out. Option names and field names are parsed from templates, similar to meta and ct options rather than via keywords to prevent adding more keywords than necessary. Signed-off-by: Manuel Messner <mm@skelett.io> Signed-off-by: Florian Westphal <fw@strlen.de>
Diffstat (limited to 'src/parser_bison.y')
-rw-r--r--src/parser_bison.y46
1 files changed, 41 insertions, 5 deletions
diff --git a/src/parser_bison.y b/src/parser_bison.y
index d543e3ea..b295bfde 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -308,6 +308,7 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%token DOFF "doff"
%token WINDOW "window"
%token URGPTR "urgptr"
+%token OPTION "option"
%token DCCP "dccp"
@@ -428,8 +429,8 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%token NOTRACK "notrack"
-%type <string> identifier type_identifier string comment_spec
-%destructor { xfree($$); } identifier type_identifier string comment_spec
+%type <string> identifier type_identifier string comment_spec tcp_option_name tcp_option_field
+%destructor { xfree($$); } identifier type_identifier string comment_spec tcp_option_name tcp_option_field
%type <val> time_spec quota_used
@@ -581,9 +582,9 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%type <expr> auth_hdr_expr esp_hdr_expr comp_hdr_expr
%destructor { expr_free($$); } auth_hdr_expr esp_hdr_expr comp_hdr_expr
%type <val> auth_hdr_field esp_hdr_field comp_hdr_field
-%type <expr> udp_hdr_expr udplite_hdr_expr tcp_hdr_expr
-%destructor { expr_free($$); } udp_hdr_expr udplite_hdr_expr tcp_hdr_expr
-%type <val> udp_hdr_field udplite_hdr_field tcp_hdr_field
+%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 <val> dccp_hdr_field sctp_hdr_field
@@ -600,6 +601,9 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%destructor { expr_free($$); } mh_hdr_expr
%type <val> mh_hdr_field
+%type <expr> tcp_hdr_optexpr
+%destructor { expr_free($$); } tcp_hdr_optexpr
+
%type <expr> meta_expr
%destructor { expr_free($$); } meta_expr
%type <val> meta_key meta_key_qualified meta_key_unqualified numgen_type
@@ -626,6 +630,10 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%type <quota> quota_config
%destructor { xfree($$); } quota_config
+%type <expr> tcp_hdr_expr
+%destructor { expr_free($$); } tcp_hdr_expr
+%type <val> tcp_hdr_field
+
%%
input : /* empty */
@@ -3232,6 +3240,7 @@ exthdr_expr : hbh_hdr_expr
| frag_hdr_expr
| dst_hdr_expr
| mh_hdr_expr
+ | tcp_hdr_optexpr
;
hbh_hdr_expr : HBH hbh_hdr_field
@@ -3314,4 +3323,31 @@ mh_hdr_field : NEXTHDR { $$ = MHHDR_NEXTHDR; }
| CHECKSUM { $$ = MHHDR_CHECKSUM; }
;
+tcp_option_name : STRING { $$ = $1; }
+ | WINDOW { $$ = xstrdup("window"); }
+ ;
+
+tcp_option_field : STRING { $$ = $1; }
+ | LENGTH { $$ = xstrdup("length"); }
+ | SIZE { $$ = xstrdup("size"); }
+ ;
+
+tcp_hdr_optexpr : TCP OPTION tcp_option_name tcp_option_field
+ {
+ $$ = tcpopt_expr_alloc(&@$, $3, 0, $4);
+ }
+ | TCP OPTION STRING NUM tcp_option_field
+ {
+ if (strcmp($3, "sack")) {
+ erec_queue(error(&@2, "tcp: number (%d) can only be used with sack option", $4), state->msgs);
+ YYERROR;
+ }
+
+ if ($4 > 3) {
+ erec_queue(error(&@2, "tcp: option block (%d) too large (0-3)", $4), state->msgs);
+ YYERROR;
+ }
+ $$ = tcpopt_expr_alloc(&@$, $3, $4, $5);
+ }
+ ;
%%