From e02bd59c4009bedba89da88b199e715441975439 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 10 Mar 2017 18:13:51 +0100 Subject: exthdr: Implement existence check This allows to check for existence of an IPv6 extension or TCP option header by using the following syntax: | exthdr frag exists | tcpopt window exists Signed-off-by: Phil Sutter Signed-off-by: Pablo Neira Ayuso --- src/evaluate.c | 3 +++ src/exthdr.c | 28 ++++++++++++++++++++++++---- src/parser_bison.y | 34 ++++++++++++++++++++++++++++++++++ src/scanner.l | 2 ++ src/tcpopt.c | 6 +++++- 5 files changed, 68 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/evaluate.c b/src/evaluate.c index efcafc72..7c039cba 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -432,6 +432,9 @@ static int __expr_evaluate_exthdr(struct eval_ctx *ctx, struct expr **exprp) { struct expr *expr = *exprp; + if (expr->exthdr.flags & NFT_EXTHDR_F_PRESENT) + expr->dtype = &boolean_type; + if (expr_evaluate_primary(ctx, exprp) < 0) return -1; diff --git a/src/exthdr.c b/src/exthdr.c index 21fe734f..375e18fc 100644 --- a/src/exthdr.c +++ b/src/exthdr.c @@ -32,14 +32,22 @@ static void exthdr_expr_print(const struct expr *expr) unsigned int offset = expr->exthdr.offset / 64; char buf[3] = {0}; + if (expr->exthdr.flags & NFT_EXTHDR_F_PRESENT) { + printf("tcp option %s", expr->exthdr.desc->name); + return; + } + if (offset) snprintf(buf, sizeof buf, "%d", offset); printf("tcp option %s%s %s", expr->exthdr.desc->name, buf, expr->exthdr.tmpl->token); + } else { + if (expr->exthdr.flags & NFT_EXTHDR_F_PRESENT) + printf("exthdr %s", expr->exthdr.desc->name); + else + printf("%s %s", expr->exthdr.desc->name, + expr->exthdr.tmpl->token); } - else - printf("%s %s", expr->exthdr.desc->name, - expr->exthdr.tmpl->token); } static bool exthdr_expr_cmp(const struct expr *e1, const struct expr *e2) @@ -97,6 +105,13 @@ static const struct exthdr_desc *exthdr_protocols[IPPROTO_MAX] = { [IPPROTO_MH] = &exthdr_mh, }; +const struct exthdr_desc *exthdr_find_proto(uint8_t proto) +{ + assert(exthdr_protocols[proto]); + + return exthdr_protocols[proto]; +} + void exthdr_init_raw(struct expr *expr, uint8_t type, unsigned int offset, unsigned int len, enum nft_exthdr_op op, uint32_t flags) @@ -119,7 +134,12 @@ void exthdr_init_raw(struct expr *expr, uint8_t type, if (tmpl->offset != offset || tmpl->len != len) continue; - expr->dtype = tmpl->dtype; + + if (flags & NFT_EXTHDR_F_PRESENT) + expr->dtype = &boolean_type; + else + expr->dtype = tmpl->dtype; + expr->exthdr.tmpl = tmpl; return; } diff --git a/src/parser_bison.y b/src/parser_bison.y index f2ae82f4..12a6e646 100644 --- a/src/parser_bison.y +++ b/src/parser_bison.y @@ -139,6 +139,7 @@ static void location_update(struct location *loc, struct location *rhs, int n) const struct datatype *datatype; struct handle_spec handle_spec; struct position_spec position_spec; + const struct exthdr_desc *exthdr_desc; } %token TOKEN_EOF 0 "end of file" @@ -451,6 +452,8 @@ static void location_update(struct location *loc, struct location *rhs, int n) %token EXISTS "exists" %token MISSING "missing" +%token EXTHDR "exthdr" + %type identifier type_identifier string comment_spec %destructor { xfree($$); } identifier type_identifier string comment_spec @@ -658,6 +661,10 @@ static void location_update(struct location *loc, struct location *rhs, int n) %destructor { expr_free($$); } boolean_expr %type boolean_keys +%type exthdr_exists_expr +%destructor { expr_free($$); } exthdr_exists_expr +%type exthdr_key + %% input : /* empty */ @@ -2291,6 +2298,7 @@ primary_expr : symbol_expr { $$ = $1; } | integer_expr { $$ = $1; } | payload_expr { $$ = $1; } | exthdr_expr { $$ = $1; } + | exthdr_exists_expr { $$ = $1; } | meta_expr { $$ = $1; } | rt_expr { $$ = $1; } | ct_expr { $$ = $1; } @@ -3254,6 +3262,11 @@ tcp_hdr_expr : TCP tcp_hdr_field { $$ = tcpopt_expr_alloc(&@$, $3, $4); } + | TCP OPTION tcp_hdr_option_type + { + $$ = tcpopt_expr_alloc(&@$, $3, TCPOPTHDR_FIELD_KIND); + $$->exthdr.flags = NFT_EXTHDR_F_PRESENT; + } ; tcp_hdr_field : SPORT { $$ = TCPHDR_SPORT; } @@ -3404,4 +3417,25 @@ mh_hdr_field : NEXTHDR { $$ = MHHDR_NEXTHDR; } | CHECKSUM { $$ = MHHDR_CHECKSUM; } ; +exthdr_exists_expr : EXTHDR exthdr_key + { + const struct exthdr_desc *desc; + + desc = exthdr_find_proto($2); + + /* Assume that NEXTHDR template is always + * the fist 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; } + ; + %% diff --git a/src/scanner.l b/src/scanner.l index b0d57198..c2c008d6 100644 --- a/src/scanner.l +++ b/src/scanner.l @@ -507,6 +507,8 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr}) "exists" { return EXISTS; } "missing" { return MISSING; } +"exthdr" { return EXTHDR; } + {addrstring} { yylval->string = xstrdup(yytext); return STRING; diff --git a/src/tcpopt.c b/src/tcpopt.c index d34dfd45..dac4fdb9 100644 --- a/src/tcpopt.c +++ b/src/tcpopt.c @@ -205,6 +205,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); for (i = 0; i < array_size(expr->exthdr.desc->templates); ++i) { @@ -216,7 +217,10 @@ void tcpopt_init_raw(struct expr *expr, uint8_t type, unsigned int offset, if (tmpl->offset != off || tmpl->len != len) continue; - expr->dtype = tmpl->dtype; + if (flags & NFT_EXTHDR_F_PRESENT) + expr->dtype = &boolean_type; + else + expr->dtype = tmpl->dtype; expr->exthdr.tmpl = tmpl; expr->exthdr.op = NFT_EXTHDR_OP_TCPOPT; break; -- cgit v1.2.3