]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
src: add tcp option reset support
authorFlorian Westphal <fw@strlen.de>
Mon, 20 Dec 2021 11:30:18 +0000 (12:30 +0100)
committerFlorian Westphal <fw@strlen.de>
Mon, 28 Feb 2022 21:44:51 +0000 (22:44 +0100)
This allows to replace a tcp option with nops, similar
to the TCPOPTSTRIP feature of iptables.

Signed-off-by: Florian Westphal <fw@strlen.de>
13 files changed:
doc/statements.txt
include/json.h
include/statement.h
src/evaluate.c
src/json.c
src/netlink_delinearize.c
src/netlink_linearize.c
src/parser_bison.y
src/parser_json.c
src/statement.c
tests/py/any/tcpopt.t
tests/py/any/tcpopt.t.json
tests/py/any/tcpopt.t.payload

index 8675892a3159dcc7c653106f9199927b6c4b2817..6aaf806bcff25a6024e3ccfecec11d8ea223853b 100644 (file)
@@ -71,7 +71,7 @@ EXTENSION HEADER STATEMENT
 
 The extension header statement alters packet content in variable-sized headers.
 This can currently be used to alter the TCP Maximum segment size of packets,
-similar to TCPMSS.
+similar to the TCPMSS target in iptables.
 
 .change tcp mss
 ---------------
@@ -80,6 +80,13 @@ tcp flags syn tcp option maxseg size set 1360
 tcp flags syn tcp option maxseg size set rt mtu
 ---------------
 
+You can also remove tcp options via reset keyword.
+
+.remove tcp option
+---------------
+tcp flags syn reset tcp option sack-perm
+---------------
+
 LOG STATEMENT
 ~~~~~~~~~~~~~
 [verse]
index a753f359aa52791d1c37cd8ac2193f37a91c86f5..b0d78eb84987e0791d5aecb42da42bf0a307d784 100644 (file)
@@ -91,6 +91,7 @@ json_t *verdict_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
 json_t *connlimit_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
 json_t *tproxy_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
 json_t *synproxy_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
+json_t *optstrip_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
 
 int do_command_list_json(struct netlink_ctx *ctx, struct cmd *cmd);
 
@@ -192,6 +193,7 @@ STMT_PRINT_STUB(verdict)
 STMT_PRINT_STUB(connlimit)
 STMT_PRINT_STUB(tproxy)
 STMT_PRINT_STUB(synproxy)
+STMT_PRINT_STUB(optstrip)
 
 #undef STMT_PRINT_STUB
 #undef EXPR_PRINT_STUB
index 06221040fa0c5aa2f4b66532b9995d56b7b82db0..2a2d3001061817df0f5696a61ddd0a9a3eefa566 100644 (file)
@@ -145,6 +145,12 @@ struct nat_stmt {
 extern struct stmt *nat_stmt_alloc(const struct location *loc,
                                   enum nft_nat_etypes type);
 
+struct optstrip_stmt {
+       struct expr     *expr;
+};
+
+extern struct stmt *optstrip_stmt_alloc(const struct location *loc, struct expr *e);
+
 struct tproxy_stmt {
        struct expr     *addr;
        struct expr     *port;
@@ -297,6 +303,7 @@ extern struct stmt *xt_stmt_alloc(const struct location *loc);
  * @STMT_MAP:          map statement
  * @STMT_SYNPROXY:     synproxy statement
  * @STMT_CHAIN:                chain statement
+ * @STMT_OPTSTRIP:     optstrip statement
  */
 enum stmt_types {
        STMT_INVALID,
@@ -326,6 +333,7 @@ enum stmt_types {
        STMT_MAP,
        STMT_SYNPROXY,
        STMT_CHAIN,
+       STMT_OPTSTRIP,
 };
 
 /**
@@ -380,6 +388,7 @@ struct stmt {
                struct reject_stmt      reject;
                struct nat_stmt         nat;
                struct tproxy_stmt      tproxy;
+               struct optstrip_stmt    optstrip;
                struct queue_stmt       queue;
                struct quota_stmt       quota;
                struct ct_stmt          ct;
index 437eacb8209f66299300cc3fa9e755a216980479..2732f5f49e064525ea89b4a9104f6699c5674981 100644 (file)
@@ -3448,6 +3448,11 @@ static int stmt_evaluate_chain(struct eval_ctx *ctx, struct stmt *stmt)
        return 0;
 }
 
+static int stmt_evaluate_optstrip(struct eval_ctx *ctx, struct stmt *stmt)
+{
+       return expr_evaluate(ctx, &stmt->optstrip.expr);
+}
+
 static int stmt_evaluate_dup(struct eval_ctx *ctx, struct stmt *stmt)
 {
        int err;
@@ -3857,6 +3862,8 @@ int stmt_evaluate(struct eval_ctx *ctx, struct stmt *stmt)
                return stmt_evaluate_synproxy(ctx, stmt);
        case STMT_CHAIN:
                return stmt_evaluate_chain(ctx, stmt);
+       case STMT_OPTSTRIP:
+               return stmt_evaluate_optstrip(ctx, stmt);
        default:
                BUG("unknown statement type %s\n", stmt->ops->name);
        }
index 4f800c908c6638556e3bf565e8ab9e7da73988b3..0b7224c28736dd344bd54be475194a872b0acb85 100644 (file)
@@ -1578,6 +1578,12 @@ json_t *synproxy_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
        return json_pack("{s:o}", "synproxy", root);
 }
 
+json_t *optstrip_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
+{
+       return json_pack("{s:o}", "reset",
+                        expr_print_json(stmt->optstrip.expr, octx));
+}
+
 static json_t *table_print_json_full(struct netlink_ctx *ctx,
                                     struct table *table)
 {
index 6619b4121a2c273d0ddc806558549c505d3a8feb..a1b00dee209a44076107d127c878b32b4885b389 100644 (file)
@@ -696,6 +696,10 @@ static void netlink_parse_exthdr(struct netlink_parse_ctx *ctx,
                expr_set_type(val, expr->dtype, expr->byteorder);
 
                stmt = exthdr_stmt_alloc(loc, expr, val);
+               rule_stmt_append(ctx->rule, stmt);
+       } else {
+               struct stmt *stmt = optstrip_stmt_alloc(loc, expr);
+
                rule_stmt_append(ctx->rule, stmt);
        }
 }
index 34a6e1a941b56f412ebb77a52c920a960ef7f554..c8bbcb7452b051bc166505b8aa6aec2d04b0e5e3 100644 (file)
@@ -986,7 +986,7 @@ static void netlink_gen_exthdr_stmt(struct netlink_linearize_ctx *ctx,
        nle = alloc_nft_expr("exthdr");
        netlink_put_register(nle, NFTNL_EXPR_EXTHDR_SREG, sreg);
        nftnl_expr_set_u8(nle, NFTNL_EXPR_EXTHDR_TYPE,
-                         expr->exthdr.desc->type);
+                         expr->exthdr.raw_type);
        nftnl_expr_set_u32(nle, NFTNL_EXPR_EXTHDR_OFFSET, offset / BITS_PER_BYTE);
        nftnl_expr_set_u32(nle, NFTNL_EXPR_EXTHDR_LEN,
                           div_round_up(expr->len, BITS_PER_BYTE));
@@ -1353,6 +1353,18 @@ static void netlink_gen_fwd_stmt(struct netlink_linearize_ctx *ctx,
        nft_rule_add_expr(ctx, nle, &stmt->location);
 }
 
+static void netlink_gen_optstrip_stmt(struct netlink_linearize_ctx *ctx,
+                                     const struct stmt *stmt)
+{
+       struct nftnl_expr *nle = alloc_nft_expr("exthdr");
+       struct expr *expr = stmt->optstrip.expr;
+
+       nftnl_expr_set_u8(nle, NFTNL_EXPR_EXTHDR_TYPE,
+                         expr->exthdr.raw_type);
+       nftnl_expr_set_u32(nle, NFTNL_EXPR_EXTHDR_OP, expr->exthdr.op);
+       nft_rule_add_expr(ctx, nle, &expr->location);
+}
+
 static void netlink_gen_queue_stmt(struct netlink_linearize_ctx *ctx,
                                 const struct stmt *stmt)
 {
@@ -1616,6 +1628,8 @@ static void netlink_gen_stmt(struct netlink_linearize_ctx *ctx,
                return netlink_gen_map_stmt(ctx, stmt);
        case STMT_CHAIN:
                return netlink_gen_chain_stmt(ctx, stmt);
+       case STMT_OPTSTRIP:
+               return netlink_gen_optstrip_stmt(ctx, stmt);
        default:
                BUG("unknown statement type %s\n", stmt->ops->name);
        }
index d67d16b8bc8c77d656d23e611185a961141ad26d..ffbaf1813e63668f7bdb23fc1f04bba8b1ac8b10 100644 (file)
@@ -886,6 +886,9 @@ int nft_lex(void *, void *, void *);
 %type <val>                    tcpopt_field_maxseg     tcpopt_field_mptcp      tcpopt_field_sack        tcpopt_field_tsopt     tcpopt_field_window
 %type <tcp_kind_field>         tcp_hdr_option_kind_and_field
 
+%type <stmt>                   optstrip_stmt
+%destructor { stmt_free($$); } optstrip_stmt
+
 %type <expr>                   boolean_expr
 %destructor { expr_free($$); } boolean_expr
 %type <val8>                   boolean_keys
@@ -2828,6 +2831,7 @@ stmt                      :       verdict_stmt
                        |       map_stmt
                        |       synproxy_stmt
                        |       chain_stmt
+                       |       optstrip_stmt
                        ;
 
 chain_stmt_type                :       JUMP    { $$ = NFT_JUMP; }
@@ -5516,6 +5520,13 @@ tcp_hdr_expr             :       TCP     tcp_hdr_field
                        }
                        ;
 
+optstrip_stmt          :       RESET   TCP     OPTION  tcp_hdr_option_type     close_scope_tcp
+                       {
+                               $$ = optstrip_stmt_alloc(&@$, tcpopt_expr_alloc(&@$,
+                                                                               $4, TCPOPT_COMMON_KIND));
+                       }
+                       ;
+
 tcp_hdr_field          :       SPORT           { $$ = TCPHDR_SPORT; }
                        |       DPORT           { $$ = TCPHDR_DPORT; }
                        |       SEQUENCE        { $$ = TCPHDR_SEQ; }
index 4913260434f47841567a638ece0be7dfbabd508a..fb401009a499729898312a7d59e2c383312bb3db 100644 (file)
@@ -2652,6 +2652,14 @@ static struct stmt *json_parse_connlimit_stmt(struct json_ctx *ctx,
        return stmt;
 }
 
+static struct stmt *json_parse_optstrip_stmt(struct json_ctx *ctx,
+                                            const char *key, json_t *value)
+{
+       struct expr *expr = json_parse_expr(ctx, value);
+
+       return expr ? optstrip_stmt_alloc(int_loc, expr) : NULL;
+}
+
 static struct stmt *json_parse_stmt(struct json_ctx *ctx, json_t *root)
 {
        struct {
@@ -2688,6 +2696,7 @@ static struct stmt *json_parse_stmt(struct json_ctx *ctx, json_t *root)
                { "ct count", json_parse_connlimit_stmt },
                { "tproxy", json_parse_tproxy_stmt },
                { "synproxy", json_parse_synproxy_stmt },
+               { "reset", json_parse_optstrip_stmt },
        };
        const char *type;
        unsigned int i;
index 03c0acf6a36101d3d9290e307f89bab7be06ee67..30caf9c7f6e1f2dff2bf00dfb1c36a9f835840dd 100644 (file)
@@ -23,6 +23,7 @@
 #include <netinet/ip_icmp.h>
 #include <netinet/icmp6.h>
 #include <statement.h>
+#include <tcpopt.h>
 #include <utils.h>
 #include <list.h>
 #include <xt.h>
@@ -909,6 +910,37 @@ struct stmt *fwd_stmt_alloc(const struct location *loc)
        return stmt_alloc(loc, &fwd_stmt_ops);
 }
 
+static void optstrip_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
+{
+       const struct expr *expr = stmt->optstrip.expr;
+
+       nft_print(octx, "reset ");
+       expr_print(expr, octx);
+}
+
+static void optstrip_stmt_destroy(struct stmt *stmt)
+{
+       expr_free(stmt->optstrip.expr);
+}
+
+static const struct stmt_ops optstrip_stmt_ops = {
+       .type           = STMT_OPTSTRIP,
+       .name           = "optstrip",
+       .print          = optstrip_stmt_print,
+       .json           = optstrip_stmt_json,
+       .destroy        = optstrip_stmt_destroy,
+};
+
+struct stmt *optstrip_stmt_alloc(const struct location *loc, struct expr *e)
+{
+       struct stmt *stmt = stmt_alloc(loc, &optstrip_stmt_ops);
+
+       e->exthdr.flags |= NFT_EXTHDR_F_PRESENT;
+       stmt->optstrip.expr = e;
+
+       return stmt;
+}
+
 static void tproxy_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
 {
        nft_print(octx, "tproxy");
index 3d4be2a274dfd56020f63c35719615945dc8a3a0..177f01c455066d9eec395be4ee72694ff870d31f 100644 (file)
@@ -54,3 +54,9 @@ tcp option mptcp exists;ok
 tcp option mptcp subtype 0;ok
 tcp option mptcp subtype 1;ok
 tcp option mptcp subtype { 0, 2};ok
+
+reset tcp option mptcp;ok
+reset tcp option 2;ok;reset tcp option maxseg
+reset tcp option 123;ok
+reset tcp option meh;fail
+reset tcp option 256;fail
index 5cc6f8f424466fe644fd47cdee0ba74e0050a1f0..4466f14fac638a8ecc7abf8b803e21ae15682489 100644 (file)
         }
    }
 ]
+
+# reset tcp option mptcp
+[
+    {
+        "reset": {
+            "tcp option": {
+                "name": "mptcp"
+            }
+        }
+    }
+]
+
+# reset tcp option 2
+[
+    {
+        "reset": {
+            "tcp option": {
+                "name": "maxseg"
+            }
+        }
+    }
+]
+
+# reset tcp option 123
+[
+    {
+        "reset": {
+            "tcp option": {
+                "base": 123,
+                "len": 0,
+                "offset": 0
+            }
+        }
+    }
+]
index 121cc97fac09be5884f3caa32687df5d858d8fde..99b8985f0f68ae92824fc228483ff086561c8865 100644 (file)
@@ -188,3 +188,15 @@ inet
   [ exthdr load tcpopt 1b @ 30 + 2 => reg 1 ]
   [ bitwise reg 1 = ( reg 1 & 0x000000f0 ) ^ 0x00000000 ]
   [ lookup reg 1 set __set%d ]
+
+# reset tcp option mptcp
+ip test-ip4 input
+  [ exthdr reset tcpopt 30 ]
+
+# reset tcp option 2
+ip test-ip4 input
+  [ exthdr reset tcpopt 2 ]
+
+# reset tcp option 123
+ip test-ip4 input
+  [ exthdr reset tcpopt 123 ]