diff options
author | Manuel Messner <mm@skelett.io> | 2017-02-07 03:14:12 +0100 |
---|---|---|
committer | Florian Westphal <fw@strlen.de> | 2017-02-12 15:34:47 +0100 |
commit | 864a1b44e1937a42753648644a812f70f9500a73 (patch) | |
tree | 97976d52c9d08746bd68d611be1c8443090475da /src/evaluate.c | |
parent | 9574c263569f477114d7885ebcf5af8af6411582 (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/evaluate.c')
-rw-r--r-- | src/evaluate.c | 35 |
1 files changed, 34 insertions, 1 deletions
diff --git a/src/evaluate.c b/src/evaluate.c index 0e02548c..4817a55c 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -438,6 +438,26 @@ static int __expr_evaluate_exthdr(struct eval_ctx *ctx, struct expr **exprp) expr->len % BITS_PER_BYTE != 0) expr_evaluate_bits(ctx, exprp); + switch (expr->exthdr.op) { + case NFT_EXTHDR_OP_TCPOPT: { + static const uint8_t tcphdrlen = 20 * BITS_PER_BYTE; + static const unsigned int max_tcpoptlen = 15 * 4 * BITS_PER_BYTE - tcphdrlen; + unsigned int totlen = 0; + + totlen += expr->exthdr.tmpl->offset; + totlen += expr->exthdr.tmpl->len; + totlen += expr->exthdr.offset; + + if (totlen > max_tcpoptlen) + return expr_error(ctx->msgs, expr, + "offset and size %u exceeds max tcp headerlen (%u)", + totlen, max_tcpoptlen); + break; + } + default: + break; + } + return 0; } @@ -448,11 +468,24 @@ static int __expr_evaluate_exthdr(struct eval_ctx *ctx, struct expr **exprp) */ static int expr_evaluate_exthdr(struct eval_ctx *ctx, struct expr **exprp) { - const struct proto_desc *base, *dependency = &proto_ip6; + const struct proto_desc *base, *dependency = NULL; enum proto_bases pb = PROTO_BASE_NETWORK_HDR; struct expr *expr = *exprp; struct stmt *nstmt; + switch (expr->exthdr.op) { + case NFT_EXTHDR_OP_TCPOPT: + dependency = &proto_tcp; + pb = PROTO_BASE_TRANSPORT_HDR; + break; + case NFT_EXTHDR_OP_IPV6: + default: + dependency = &proto_ip6; + break; + } + + assert(dependency); + base = ctx->pctx.protocol[pb].desc; if (base == dependency) return __expr_evaluate_exthdr(ctx, exprp); |