summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2017-02-28 13:31:54 +0100
committerPablo Neira Ayuso <pablo@netfilter.org>2017-02-28 13:52:17 +0100
commit22535a98470a908b879db8fc0354c5f2bbb3984e (patch)
treeddb527050d4db4e527c111a17bd1bc353069d324 /src
parent68ca39b68fb97733b7d04d9a5439cad4f38bfa2e (diff)
src: revisit tcp options support
Rework syntax, add tokens so we can extend the grammar more easily. This has triggered several syntax changes with regards to the original patch, specifically: tcp option sack0 left 1 There is no space between sack and the block number anymore, no more offset field, now they are a single field. Just like we do with rt, rt0 and rt2. This simplifies our grammar and that is good since it makes our life easier when extending it later on to accomodate new features. I have also renamed sack_permitted to sack-permitted. I couldn't find any option using underscore so far, so let's keep it consistent with what we have. Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'src')
-rw-r--r--src/exthdr.c2
-rw-r--r--src/parser_bison.y81
-rw-r--r--src/scanner.l19
-rw-r--r--src/tcpopt.c147
4 files changed, 126 insertions, 123 deletions
diff --git a/src/exthdr.c b/src/exthdr.c
index cfc6bb60..ddda1b87 100644
--- a/src/exthdr.c
+++ b/src/exthdr.c
@@ -33,7 +33,7 @@ static void exthdr_expr_print(const struct expr *expr)
char buf[3] = {0};
if (offset)
- snprintf(buf, sizeof buf, " %d", offset);
+ snprintf(buf, sizeof buf, "%d", offset);
printf("tcp option %s%s %s", expr->exthdr.desc->name, buf,
expr->exthdr.tmpl->token);
}
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 36d46050..15931e96 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -309,6 +309,23 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%token WINDOW "window"
%token URGPTR "urgptr"
%token OPTION "option"
+%token ECHO "echo"
+%token EOL "eol"
+%token MAXSEG "maxseg"
+%token NOOP "noop"
+%token SACK "sack"
+%token SACK0 "sack0"
+%token SACK1 "sack1"
+%token SACK2 "sack2"
+%token SACK3 "sack3"
+%token SACK_PERMITTED "sack-permitted"
+%token TIMESTAMP "timestamp"
+%token KIND "kind"
+%token COUNT "count"
+%token LEFT "left"
+%token RIGHT "right"
+%token TSVAL "tsval"
+%token TSECR "tsecr"
%token DCCP "dccp"
@@ -430,8 +447,8 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%token NOTRACK "notrack"
-%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 <string> identifier type_identifier string comment_spec
+%destructor { xfree($$); } identifier type_identifier string comment_spec
%type <val> time_spec quota_used
@@ -602,9 +619,6 @@ 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
@@ -634,6 +648,7 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%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
%%
@@ -3211,6 +3226,10 @@ 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_hdr_field : SPORT { $$ = TCPHDR_SPORT; }
@@ -3225,6 +3244,30 @@ 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_field : KIND { $$ = TCPOPTHDR_FIELD_KIND; }
+ | LENGTH { $$ = TCPOPTHDR_FIELD_LENGTH; }
+ | SIZE { $$ = TCPOPTHDR_FIELD_SIZE; }
+ | COUNT { $$ = TCPOPTHDR_FIELD_COUNT; }
+ | LEFT { $$ = TCPOPTHDR_FIELD_LEFT; }
+ | RIGHT { $$ = TCPOPTHDR_FIELD_RIGHT; }
+ | TSVAL { $$ = TCPOPTHDR_FIELD_TSVAL; }
+ | TSECR { $$ = TCPOPTHDR_FIELD_TSECR; }
+ ;
+
dccp_hdr_expr : DCCP dccp_hdr_field
{
$$ = payload_expr_alloc(&@$, &proto_dccp, $2);
@@ -3255,7 +3298,6 @@ exthdr_expr : hbh_hdr_expr
| frag_hdr_expr
| dst_hdr_expr
| mh_hdr_expr
- | tcp_hdr_optexpr
;
hbh_hdr_expr : HBH hbh_hdr_field
@@ -3338,31 +3380,4 @@ 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);
- }
- ;
%%
diff --git a/src/scanner.l b/src/scanner.l
index e0ddcac1..b70e1a80 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -375,6 +375,25 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
"protocol" { return PROTOCOL; }
"checksum" { return CHECKSUM; }
+"echo" { return ECHO; }
+"eol" { return EOL; }
+"maxseg" { return MAXSEG; }
+"noop" { return NOOP; }
+"sack" { return SACK; }
+"sack0" { return SACK0; }
+"sack1" { return SACK1; }
+"sack2" { return SACK2; }
+"sack3" { return SACK3; }
+"sack-permitted" { return SACK_PERMITTED; }
+"timestamp" { return TIMESTAMP; }
+
+"kind" { return KIND; }
+"count" { return COUNT; }
+"left" { return LEFT; }
+"right" { return RIGHT; }
+"tsval" { return TSVAL; }
+"tsecr" { return TSECR; }
+
"icmp" { return ICMP; }
"code" { return CODE; }
"sequence" { return SEQUENCE; }
diff --git a/src/tcpopt.c b/src/tcpopt.c
index e6f92bc6..f8612141 100644
--- a/src/tcpopt.c
+++ b/src/tcpopt.c
@@ -12,48 +12,6 @@
#include <expression.h>
#include <tcpopt.h>
-/* We do not need to export these enums, because the tcpopts are parsed at
- * runtime and not by bison.
- */
-enum tcpopt_eol_hdr_fields {
- TCPOPT_EOLHDR_KIND,
-};
-
-enum tcpopt_nop_hdr_fields {
- TCPOPT_NOPHDR_KIND,
-};
-
-enum tcpopt_maxseg_hdr_fields {
- TCPOPT_MAXSEGHDR_KIND,
- TCPOPT_MAXSEGHDR_LENGTH,
- TCPOPT_MAXSEGHDR_SIZE,
-};
-
-enum tcpopt_window_hdr_fields {
- TCPOPT_WINDOWHDR_KIND,
- TCPOPT_WINDOWHDR_LENGTH,
- TCPOPT_WINDOWHDR_COUNT,
-};
-
-enum tcpopt_sack_permitted_hdr_fields {
- TCPOPT_SACKPERMHDR_KIND,
- TCPOPT_SACKPERMHDR_LENGTH,
-};
-
-enum tcpopt_sack_hdr_fields {
- TCPOPT_SACKHDR_KIND,
- TCPOPT_SACKHDR_LENGTH,
- TCPOPT_SACKHDR_LEFT,
- TCPOPT_SACKHDR_RIGHT,
-};
-
-enum tcpopt_timestamp_hdr_fields {
- TCPOPT_TIMESTAMPSHDR_KIND,
- TCPOPT_TIMESTAMPSHDR_LENGTH,
- TCPOPT_TIMESTAMPSHDR_TSVAL,
- TCPOPT_TIMESTAMPSHDR_TSECR,
-};
-
static const struct proto_hdr_template tcpopt_unknown_template =
PROTO_HDR_TEMPLATE("unknown", &invalid_type, BYTEORDER_INVALID, 0, 0);
@@ -64,7 +22,7 @@ const struct exthdr_desc tcpopt_eol = {
.name = "eol",
.type = TCPOPT_EOL,
.templates = {
- [TCPOPT_EOLHDR_KIND] = PHT("kind", 0, 8),
+ [TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8),
},
};
@@ -72,7 +30,7 @@ const struct exthdr_desc tcpopt_nop = {
.name = "noop",
.type = TCPOPT_NOP,
.templates = {
- [TCPOPT_NOPHDR_KIND] = PHT("kind", 0, 8),
+ [TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8),
},
};
@@ -80,9 +38,9 @@ const struct exthdr_desc tcptopt_maxseg = {
.name = "maxseg",
.type = TCPOPT_MAXSEG,
.templates = {
- [TCPOPT_MAXSEGHDR_KIND] = PHT("kind", 0, 8),
- [TCPOPT_MAXSEGHDR_LENGTH] = PHT("length", 8, 8),
- [TCPOPT_MAXSEGHDR_SIZE] = PHT("size", 16, 16),
+ [TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8),
+ [TCPOPTHDR_FIELD_LENGTH] = PHT("length", 8, 8),
+ [TCPOPTHDR_FIELD_SIZE] = PHT("size", 16, 16),
},
};
@@ -90,18 +48,18 @@ const struct exthdr_desc tcpopt_window = {
.name = "window",
.type = TCPOPT_WINDOW,
.templates = {
- [TCPOPT_WINDOWHDR_KIND] = PHT("kind", 0, 8),
- [TCPOPT_WINDOWHDR_LENGTH] = PHT("length", 8, 8),
- [TCPOPT_WINDOWHDR_COUNT] = PHT("count", 16, 8),
+ [TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8),
+ [TCPOPTHDR_FIELD_LENGTH] = PHT("length", 8, 8),
+ [TCPOPTHDR_FIELD_COUNT] = PHT("count", 16, 8),
},
};
const struct exthdr_desc tcpopt_sack_permitted = {
- .name = "sack_permitted",
+ .name = "sack-permitted",
.type = TCPOPT_SACK_PERMITTED,
.templates = {
- [TCPOPT_SACKPERMHDR_KIND] = PHT("kind", 0, 8),
- [TCPOPT_SACKPERMHDR_LENGTH] = PHT("length", 8, 8),
+ [TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8),
+ [TCPOPTHDR_FIELD_LENGTH] = PHT("length", 8, 8),
},
};
@@ -109,10 +67,10 @@ const struct exthdr_desc tcpopt_sack = {
.name = "sack",
.type = TCPOPT_SACK,
.templates = {
- [TCPOPT_SACKHDR_KIND] = PHT("kind", 0, 8),
- [TCPOPT_SACKHDR_LENGTH] = PHT("length", 8, 8),
- [TCPOPT_SACKHDR_LEFT] = PHT("left", 16, 32),
- [TCPOPT_SACKHDR_RIGHT] = PHT("right", 48, 32),
+ [TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8),
+ [TCPOPTHDR_FIELD_LENGTH] = PHT("length", 8, 8),
+ [TCPOPTHDR_FIELD_LEFT] = PHT("left", 16, 32),
+ [TCPOPTHDR_FIELD_RIGHT] = PHT("right", 48, 32),
},
};
@@ -120,10 +78,10 @@ const struct exthdr_desc tcpopt_timestamp = {
.name = "timestamp",
.type = TCPOPT_TIMESTAMP,
.templates = {
- [TCPOPT_TIMESTAMPSHDR_KIND] = PHT("kind", 0, 8),
- [TCPOPT_TIMESTAMPSHDR_LENGTH] = PHT("length", 8, 8),
- [TCPOPT_TIMESTAMPSHDR_TSVAL] = PHT("tsval", 16, 32),
- [TCPOPT_TIMESTAMPSHDR_TSECR] = PHT("tsecr", 48, 32),
+ [TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8),
+ [TCPOPTHDR_FIELD_LENGTH] = PHT("length", 8, 8),
+ [TCPOPTHDR_FIELD_TSVAL] = PHT("tsval", 16, 32),
+ [TCPOPTHDR_FIELD_TSECR] = PHT("tsecr", 48, 32),
},
};
#undef PHT
@@ -178,46 +136,57 @@ static unsigned int calc_offset_reverse(const struct exthdr_desc *desc,
}
}
+static const struct exthdr_desc *tcpopthdr_protocols[] = {
+ [TCPOPTHDR_EOL] = &tcpopt_eol,
+ [TCPOPTHDR_NOOP] = &tcpopt_nop,
+ [TCPOPTHDR_MAXSEG] = &tcptopt_maxseg,
+ [TCPOPTHDR_WINDOW] = &tcpopt_window,
+ [TCPOPTHDR_SACK_PERMITTED] = &tcpopt_sack_permitted,
+ [TCPOPTHDR_SACK0] = &tcpopt_sack,
+ [TCPOPTHDR_SACK1] = &tcpopt_sack,
+ [TCPOPTHDR_SACK2] = &tcpopt_sack,
+ [TCPOPTHDR_SACK3] = &tcpopt_sack,
+ [TCPOPTHDR_ECHO] = TCPOPT_OBSOLETE,
+ [TCPOPTHDR_ECHO_REPLY] = TCPOPT_OBSOLETE,
+ [TCPOPTHDR_TIMESTAMP] = &tcpopt_timestamp,
+};
+
+static uint8_t tcpopt_optnum[] = {
+ [TCPOPTHDR_SACK0] = 0,
+ [TCPOPTHDR_SACK1] = 1,
+ [TCPOPTHDR_SACK2] = 2,
+ [TCPOPTHDR_SACK3] = 3,
+};
-struct expr *tcpopt_expr_alloc(const struct location *loc,
- const char *option_str,
- const unsigned int option_num,
- const char *option_field)
+static uint8_t tcpopt_find_optnum(uint8_t optnum)
{
- const struct proto_hdr_template *tmp, *tmpl = &tcpopt_unknown_template;
- const struct exthdr_desc *desc = NULL;
- struct expr *expr;
- unsigned int i, j;
+ if (optnum > TCPOPTHDR_SACK3)
+ return 0;
- for (i = 0; i < array_size(tcpopt_protocols); ++i) {
- if (tcpopt_protocols[i] == TCPOPT_OBSOLETE)
- continue;
+ return tcpopt_optnum[optnum];
+}
- if (!tcpopt_protocols[i]->name ||
- strcmp(option_str, tcpopt_protocols[i]->name))
- continue;
+struct expr *tcpopt_expr_alloc(const struct location *loc, uint8_t type,
+ uint8_t field)
+{
+ const struct proto_hdr_template *tmpl;
+ const struct exthdr_desc *desc;
+ struct expr *expr;
+ uint8_t optnum;
- for (j = 0; j < array_size(tcpopt_protocols[i]->templates); ++j) {
- tmp = &tcpopt_protocols[i]->templates[j];
- if (!tmp->token || strcmp(option_field, tmp->token))
- continue;
+ desc = tcpopthdr_protocols[type];
+ tmpl = &desc->templates[field];
+ if (!tmpl)
+ return NULL;
- desc = tcpopt_protocols[i];
- tmpl = tmp;
- goto found;
- }
- }
+ optnum = tcpopt_find_optnum(type);
-found:
- /* tmpl still points to tcpopt_unknown_template if nothing was found and
- * desc is null
- */
expr = expr_alloc(loc, &exthdr_expr_ops, tmpl->dtype,
BYTEORDER_BIG_ENDIAN, tmpl->len);
expr->exthdr.desc = desc;
expr->exthdr.tmpl = tmpl;
expr->exthdr.op = NFT_EXTHDR_OP_TCPOPT;
- expr->exthdr.offset = calc_offset(desc, tmpl, option_num);
+ expr->exthdr.offset = calc_offset(desc, tmpl, optnum);
return expr;
}