From 0aa694acf7c233f9426e48d0644b29ddec4fb16d Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Mon, 12 Jul 2021 17:44:08 +0200 Subject: [PATCH] tcpopts: clean up parser -> tcpopt.c plumbing Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1979334 Upstream Status: nftables commit 41158e0388ac5 commit 41158e0388ac56380fc0ee301f0d43f95ec43fab Author: Florian Westphal Date: Mon Nov 2 14:53:26 2020 +0100 tcpopts: clean up parser -> tcpopt.c plumbing tcpopt template mapping is asymmetric: one mapping is to match dumped netlink exthdr expression to the original tcp option template. This struct is indexed by the raw, on-write kind/type number. The other mapping maps parsed options to the tcp option template. Remove the latter. The parser is changed to translate the textual option name, e.g. "maxseg" to the on-wire number. This avoids the second mapping, it will also allow to more easily support raw option matching in a followup patch. Signed-off-by: Florian Westphal --- doc/payload-expression.txt | 4 +- include/tcpopt.h | 35 ++++++++------- src/parser_bison.y | 26 +++++------ src/parser_json.c | 10 ++--- src/scanner.l | 3 +- src/tcpopt.c | 92 +++++++++++++++----------------------- 6 files changed, 75 insertions(+), 95 deletions(-) diff --git a/doc/payload-expression.txt b/doc/payload-expression.txt index 3d7057c..27145c3 100644 --- a/doc/payload-expression.txt +++ b/doc/payload-expression.txt @@ -525,13 +525,13 @@ nftables currently supports matching (finding) a given ipv6 extension header, TC *dst* {*nexthdr* | *hdrlength*} *mh* {*nexthdr* | *hdrlength* | *checksum* | *type*} *srh* {*flags* | *tag* | *sid* | *seg-left*} -*tcp option* {*eol* | *noop* | *maxseg* | *window* | *sack-perm* | *sack* | *sack0* | *sack1* | *sack2* | *sack3* | *timestamp*} 'tcp_option_field' +*tcp option* {*eol* | *nop* | *maxseg* | *window* | *sack-perm* | *sack* | *sack0* | *sack1* | *sack2* | *sack3* | *timestamp*} 'tcp_option_field' *ip option* { lsrr | ra | rr | ssrr } 'ip_option_field' The following syntaxes are valid only in a relational expression with boolean type on right-hand side for checking header existence only: [verse] *exthdr* {*hbh* | *frag* | *rt* | *dst* | *mh*} -*tcp option* {*eol* | *noop* | *maxseg* | *window* | *sack-perm* | *sack* | *sack0* | *sack1* | *sack2* | *sack3* | *timestamp*} +*tcp option* {*eol* | *nop* | *maxseg* | *window* | *sack-perm* | *sack* | *sack0* | *sack1* | *sack2* | *sack3* | *timestamp*} *ip option* { lsrr | ra | rr | ssrr } .IPv6 extension headers diff --git a/include/tcpopt.h b/include/tcpopt.h index ffdbcb0..7f3fbb8 100644 --- a/include/tcpopt.h +++ b/include/tcpopt.h @@ -6,7 +6,7 @@ #include extern struct expr *tcpopt_expr_alloc(const struct location *loc, - uint8_t type, uint8_t field); + unsigned int kind, unsigned int field); extern void tcpopt_init_raw(struct expr *expr, uint8_t type, unsigned int offset, unsigned int len, @@ -15,21 +15,22 @@ extern void tcpopt_init_raw(struct expr *expr, uint8_t type, extern bool tcpopt_find_template(struct expr *expr, const struct expr *mask, unsigned int *shift); -enum tcpopt_hdr_types { - TCPOPTHDR_INVALID, - TCPOPTHDR_EOL, - TCPOPTHDR_NOOP, - TCPOPTHDR_MAXSEG, - TCPOPTHDR_WINDOW, - TCPOPTHDR_SACK_PERMITTED, - TCPOPTHDR_SACK0, - TCPOPTHDR_SACK1, - TCPOPTHDR_SACK2, - TCPOPTHDR_SACK3, - TCPOPTHDR_TIMESTAMP, - TCPOPTHDR_ECHO, - TCPOPTHDR_ECHO_REPLY, - __TCPOPTHDR_MAX +/* TCP option numbers used on wire */ +enum tcpopt_kind { + TCPOPT_KIND_EOL = 0, + TCPOPT_KIND_NOP = 1, + TCPOPT_KIND_MAXSEG = 2, + TCPOPT_KIND_WINDOW = 3, + TCPOPT_KIND_SACK_PERMITTED = 4, + TCPOPT_KIND_SACK = 5, + TCPOPT_KIND_TIMESTAMP = 8, + TCPOPT_KIND_ECHO = 8, + __TCPOPT_KIND_MAX, + + /* extra oob info, internal to nft */ + TCPOPT_KIND_SACK1 = 256, + TCPOPT_KIND_SACK2 = 257, + TCPOPT_KIND_SACK3 = 258, }; enum tcpopt_hdr_fields { @@ -44,6 +45,6 @@ enum tcpopt_hdr_fields { TCPOPTHDR_FIELD_TSECR, }; -extern const struct exthdr_desc *tcpopthdr_protocols[__TCPOPTHDR_MAX]; +extern const struct exthdr_desc *tcpopt_protocols[__TCPOPT_KIND_MAX]; #endif /* NFTABLES_TCPOPT_H */ diff --git a/src/parser_bison.y b/src/parser_bison.y index 56d26e3..8f77766 100644 --- a/src/parser_bison.y +++ b/src/parser_bison.y @@ -384,7 +384,7 @@ int nft_lex(void *, void *, void *); %token OPTION "option" %token ECHO "echo" %token EOL "eol" -%token NOOP "noop" +%token NOP "nop" %token SACK "sack" %token SACK0 "sack0" %token SACK1 "sack1" @@ -4732,18 +4732,18 @@ tcp_hdr_field : SPORT { $$ = TCPHDR_SPORT; } | URGPTR { $$ = TCPHDR_URGPTR; } ; -tcp_hdr_option_type : EOL { $$ = TCPOPTHDR_EOL; } - | NOOP { $$ = TCPOPTHDR_NOOP; } - | MSS { $$ = TCPOPTHDR_MAXSEG; } - | WINDOW { $$ = TCPOPTHDR_WINDOW; } - | SACK_PERM { $$ = 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_type : EOL { $$ = TCPOPT_KIND_EOL; } + | NOP { $$ = TCPOPT_KIND_NOP; } + | MSS { $$ = TCPOPT_KIND_MAXSEG; } + | WINDOW { $$ = TCPOPT_KIND_WINDOW; } + | SACK_PERM { $$ = TCPOPT_KIND_SACK_PERMITTED; } + | SACK { $$ = TCPOPT_KIND_SACK; } + | SACK0 { $$ = TCPOPT_KIND_SACK; } + | SACK1 { $$ = TCPOPT_KIND_SACK1; } + | SACK2 { $$ = TCPOPT_KIND_SACK2; } + | SACK3 { $$ = TCPOPT_KIND_SACK3; } + | ECHO { $$ = TCPOPT_KIND_ECHO; } + | TIMESTAMP { $$ = TCPOPT_KIND_TIMESTAMP; } ; tcp_hdr_option_field : KIND { $$ = TCPOPTHDR_FIELD_KIND; } diff --git a/src/parser_json.c b/src/parser_json.c index 662bb4b..44b58a0 100644 --- a/src/parser_json.c +++ b/src/parser_json.c @@ -456,9 +456,9 @@ static int json_parse_tcp_option_type(const char *name, int *val) { unsigned int i; - for (i = 0; i < array_size(tcpopthdr_protocols); i++) { - if (tcpopthdr_protocols[i] && - !strcmp(tcpopthdr_protocols[i]->name, name)) { + for (i = 0; i < array_size(tcpopt_protocols); i++) { + if (tcpopt_protocols[i] && + !strcmp(tcpopt_protocols[i]->name, name)) { if (val) *val = i; return 0; @@ -467,7 +467,7 @@ static int json_parse_tcp_option_type(const char *name, int *val) /* special case for sack0 - sack3 */ if (sscanf(name, "sack%u", &i) == 1 && i < 4) { if (val) - *val = TCPOPTHDR_SACK0 + i; + *val = TCPOPT_KIND_SACK + i; return 0; } return 1; @@ -476,7 +476,7 @@ static int json_parse_tcp_option_type(const char *name, int *val) static int json_parse_tcp_option_field(int type, const char *name, int *val) { unsigned int i; - const struct exthdr_desc *desc = tcpopthdr_protocols[type]; + const struct exthdr_desc *desc = tcpopt_protocols[type]; for (i = 0; i < array_size(desc->templates); i++) { if (desc->templates[i].token && diff --git a/src/scanner.l b/src/scanner.l index a369802..20b1b2d 100644 --- a/src/scanner.l +++ b/src/scanner.l @@ -421,7 +421,8 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr}) "eol" { return EOL; } "maxseg" { return MSS; } "mss" { return MSS; } -"noop" { return NOOP; } +"nop" { return NOP; } +"noop" { return NOP; } "sack" { return SACK; } "sack0" { return SACK0; } "sack1" { return SACK1; } diff --git a/src/tcpopt.c b/src/tcpopt.c index 6dbaa9e..8d5bdec 100644 --- a/src/tcpopt.c +++ b/src/tcpopt.c @@ -20,7 +20,7 @@ static const struct proto_hdr_template tcpopt_unknown_template = __offset, __len) static const struct exthdr_desc tcpopt_eol = { .name = "eol", - .type = TCPOPT_EOL, + .type = TCPOPT_KIND_EOL, .templates = { [TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8), }, @@ -28,7 +28,7 @@ static const struct exthdr_desc tcpopt_eol = { static const struct exthdr_desc tcpopt_nop = { .name = "noop", - .type = TCPOPT_NOP, + .type = TCPOPT_KIND_NOP, .templates = { [TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8), }, @@ -36,7 +36,7 @@ static const struct exthdr_desc tcpopt_nop = { static const struct exthdr_desc tcptopt_maxseg = { .name = "maxseg", - .type = TCPOPT_MAXSEG, + .type = TCPOPT_KIND_MAXSEG, .templates = { [TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8), [TCPOPTHDR_FIELD_LENGTH] = PHT("length", 8, 8), @@ -46,7 +46,7 @@ static const struct exthdr_desc tcptopt_maxseg = { static const struct exthdr_desc tcpopt_window = { .name = "window", - .type = TCPOPT_WINDOW, + .type = TCPOPT_KIND_WINDOW, .templates = { [TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8), [TCPOPTHDR_FIELD_LENGTH] = PHT("length", 8, 8), @@ -56,7 +56,7 @@ static const struct exthdr_desc tcpopt_window = { static const struct exthdr_desc tcpopt_sack_permitted = { .name = "sack-perm", - .type = TCPOPT_SACK_PERMITTED, + .type = TCPOPT_KIND_SACK_PERMITTED, .templates = { [TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8), [TCPOPTHDR_FIELD_LENGTH] = PHT("length", 8, 8), @@ -65,7 +65,7 @@ static const struct exthdr_desc tcpopt_sack_permitted = { static const struct exthdr_desc tcpopt_sack = { .name = "sack", - .type = TCPOPT_SACK, + .type = TCPOPT_KIND_SACK, .templates = { [TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8), [TCPOPTHDR_FIELD_LENGTH] = PHT("length", 8, 8), @@ -76,7 +76,7 @@ static const struct exthdr_desc tcpopt_sack = { static const struct exthdr_desc tcpopt_timestamp = { .name = "timestamp", - .type = TCPOPT_TIMESTAMP, + .type = TCPOPT_KIND_TIMESTAMP, .templates = { [TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8), [TCPOPTHDR_FIELD_LENGTH] = PHT("length", 8, 8), @@ -86,19 +86,14 @@ static const struct exthdr_desc tcpopt_timestamp = { }; #undef PHT -#define TCPOPT_OBSOLETE ((struct exthdr_desc *)NULL) -#define TCPOPT_ECHO 6 -#define TCPOPT_ECHO_REPLY 7 -static const struct exthdr_desc *tcpopt_protocols[] = { - [TCPOPT_EOL] = &tcpopt_eol, - [TCPOPT_NOP] = &tcpopt_nop, - [TCPOPT_MAXSEG] = &tcptopt_maxseg, - [TCPOPT_WINDOW] = &tcpopt_window, - [TCPOPT_SACK_PERMITTED] = &tcpopt_sack_permitted, - [TCPOPT_SACK] = &tcpopt_sack, - [TCPOPT_ECHO] = TCPOPT_OBSOLETE, - [TCPOPT_ECHO_REPLY] = TCPOPT_OBSOLETE, - [TCPOPT_TIMESTAMP] = &tcpopt_timestamp, +const struct exthdr_desc *tcpopt_protocols[] = { + [TCPOPT_KIND_EOL] = &tcpopt_eol, + [TCPOPT_KIND_NOP] = &tcpopt_nop, + [TCPOPT_KIND_MAXSEG] = &tcptopt_maxseg, + [TCPOPT_KIND_WINDOW] = &tcpopt_window, + [TCPOPT_KIND_SACK_PERMITTED] = &tcpopt_sack_permitted, + [TCPOPT_KIND_SACK] = &tcpopt_sack, + [TCPOPT_KIND_TIMESTAMP] = &tcpopt_timestamp, }; static unsigned int calc_offset(const struct exthdr_desc *desc, @@ -136,51 +131,34 @@ static unsigned int calc_offset_reverse(const struct exthdr_desc *desc, } } -const struct exthdr_desc *tcpopthdr_protocols[__TCPOPTHDR_MAX] = { - [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, -}; - -static uint8_t tcpopt_find_optnum(uint8_t optnum) -{ - if (optnum > TCPOPTHDR_SACK3) - return 0; - - return tcpopt_optnum[optnum]; -} - -struct expr *tcpopt_expr_alloc(const struct location *loc, uint8_t type, - uint8_t field) +struct expr *tcpopt_expr_alloc(const struct location *loc, + unsigned int kind, + unsigned int field) { const struct proto_hdr_template *tmpl; const struct exthdr_desc *desc; + uint8_t optnum = 0; struct expr *expr; - uint8_t optnum; - desc = tcpopthdr_protocols[type]; + switch (kind) { + case TCPOPT_KIND_SACK1: + kind = TCPOPT_KIND_SACK; + optnum = 1; + break; + case TCPOPT_KIND_SACK2: + kind = TCPOPT_KIND_SACK; + optnum = 2; + break; + case TCPOPT_KIND_SACK3: + kind = TCPOPT_KIND_SACK; + optnum = 3; + } + + desc = tcpopt_protocols[kind]; tmpl = &desc->templates[field]; if (!tmpl) return NULL; - optnum = tcpopt_find_optnum(type); - expr = expr_alloc(loc, EXPR_EXTHDR, tmpl->dtype, BYTEORDER_BIG_ENDIAN, tmpl->len); expr->exthdr.desc = desc; @@ -206,7 +184,7 @@ void tcpopt_init_raw(struct expr *expr, uint8_t type, unsigned int offset, assert(type < array_size(tcpopt_protocols)); expr->exthdr.desc = tcpopt_protocols[type]; expr->exthdr.flags = flags; - assert(expr->exthdr.desc != TCPOPT_OBSOLETE); + assert(expr->exthdr.desc != NULL); for (i = 0; i < array_size(expr->exthdr.desc->templates); ++i) { tmpl = &expr->exthdr.desc->templates[i]; -- 2.31.1