]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
src: add tcp options set support
authorFlorian Westphal <fw@strlen.de>
Sun, 11 Dec 2016 17:02:34 +0000 (18:02 +0100)
committerFlorian Westphal <fw@strlen.de>
Tue, 22 Aug 2017 21:51:02 +0000 (23:51 +0200)
This adds support for tcp mss mangling:

nft add rule filter input tcp option maxseg size 1200

Its also possible to change other tcp option fields, but
maxseg is one of the more useful ones to change.

Signed-off-by: Florian Westphal <fw@strlen.de>
Acked-by: Pablo Neira Ayuso <pablo@netfilter.org>
doc/nft.xml
include/statement.h
include/tcpopt.h
src/evaluate.c
src/exthdr.c
src/netlink_delinearize.c
src/netlink_linearize.c
src/parser_bison.y

index d7aae3f03b8c1c74fab687fe963a2097343d82f7..d3213d0281e1ec445fecd144b70668b85e0c3b2e 100644 (file)
@@ -4258,6 +4258,22 @@ ip forward ip dscp set 42
                                </example>
                        </para>
                </refsect2>
+               <refsect2>
+                       <title>Extension header statement</title>
+                       <para>
+                               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.
+                       </para>
+                       <para>
+                               <example>
+                                       <title>change tcp mss</title>
+                                       <programlisting>
+tcp option maxseg size set 1360
+                                       </programlisting>
+                               </example>
+                       </para>
+               </refsect2>
                <refsect2>
                        <title>Log statement</title>
                        <para>
index 61b5027b97f1e7377cd480afd490a8dd45d02d74..6d8aaa8ba72b556c019c42dbaabc9e5e50822fed 100644 (file)
@@ -24,6 +24,14 @@ struct counter_stmt {
 
 extern struct stmt *counter_stmt_alloc(const struct location *loc);
 
+struct exthdr_stmt {
+       struct expr                     *expr;
+       struct expr                     *val;
+};
+
+extern struct stmt *exthdr_stmt_alloc(const struct location *loc,
+                                     struct expr *payload, struct expr *expr);
+
 struct payload_stmt {
        struct expr                     *expr;
        struct expr                     *val;
@@ -220,6 +228,7 @@ struct xt_stmt {
  * @STMT_QUOTA:                quota statement
  * @STMT_NOTRACK:      notrack statement
  * @STMT_OBJREF:       stateful object reference statement
+ * @STMT_EXTHDR:       extension header statement
  */
 enum stmt_types {
        STMT_INVALID,
@@ -244,6 +253,7 @@ enum stmt_types {
        STMT_QUOTA,
        STMT_NOTRACK,
        STMT_OBJREF,
+       STMT_EXTHDR,
 };
 
 /**
@@ -285,6 +295,7 @@ struct stmt {
 
        union {
                struct expr             *expr;
+               struct exthdr_stmt      exthdr;
                struct flow_stmt        flow;
                struct counter_stmt     counter;
                struct payload_stmt     payload;
index f96c04c6ee93912542e5b2052a6470b92dcb0660..9be84817e6f20813c84a5905a105f72f999ee415 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <proto.h>
 #include <exthdr.h>
+#include <statement.h>
 
 extern struct expr *tcpopt_expr_alloc(const struct location *loc,
                                      uint8_t type, uint8_t field);
index f52a0843a0c0fc5b679771b7ad10a63dd6689b1d..3989d5e31f56a013956dbcf954d3e70430505342 100644 (file)
@@ -1835,6 +1835,19 @@ static bool stmt_evaluate_payload_need_csum(const struct expr *payload)
        return desc && desc->checksum_key;
 }
 
+static int stmt_evaluate_exthdr(struct eval_ctx *ctx, struct stmt *stmt)
+{
+       struct expr *exthdr;
+
+       if (__expr_evaluate_exthdr(ctx, &stmt->exthdr.expr) < 0)
+               return -1;
+
+       exthdr = stmt->exthdr.expr;
+       return stmt_evaluate_arg(ctx, stmt, exthdr->dtype, exthdr->len,
+                                BYTEORDER_BIG_ENDIAN,
+                                &stmt->exthdr.val);
+}
+
 static int stmt_evaluate_payload(struct eval_ctx *ctx, struct stmt *stmt)
 {
        struct expr *binop, *mask, *and, *payload_bytes;
@@ -2700,6 +2713,8 @@ int stmt_evaluate(struct eval_ctx *ctx, struct stmt *stmt)
                return stmt_evaluate_verdict(ctx, stmt);
        case STMT_PAYLOAD:
                return stmt_evaluate_payload(ctx, stmt);
+       case STMT_EXTHDR:
+               return stmt_evaluate_exthdr(ctx, stmt);
        case STMT_FLOW:
                return stmt_evaluate_flow(ctx, stmt);
        case STMT_META:
index a412025c9a486f8181c9d91357228c812f5e5562..4add3da24ad8726f7241f0e29d8381fae9111314 100644 (file)
@@ -21,6 +21,7 @@
 #include <utils.h>
 #include <headers.h>
 #include <expression.h>
+#include <statement.h>
 
 static void exthdr_expr_print(const struct expr *expr, struct output_ctx *octx)
 {
@@ -98,6 +99,30 @@ struct expr *exthdr_expr_alloc(const struct location *loc,
        return expr;
 }
 
+static void exthdr_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
+{
+       expr_print(stmt->exthdr.expr, octx);
+       printf(" set ");
+       expr_print(stmt->exthdr.val, octx);
+}
+
+static const struct stmt_ops exthdr_stmt_ops = {
+       .type           = STMT_EXTHDR,
+       .name           = "exthdr",
+       .print          = exthdr_stmt_print,
+};
+
+struct stmt *exthdr_stmt_alloc(const struct location *loc,
+                               struct expr *expr, struct expr *val)
+{
+       struct stmt *stmt;
+
+       stmt = stmt_alloc(loc, &exthdr_stmt_ops);
+       stmt->exthdr.expr = expr;
+       stmt->exthdr.val  = val;
+       return stmt;
+}
+
 static const struct exthdr_desc *exthdr_protocols[IPPROTO_MAX] = {
        [IPPROTO_HOPOPTS]       = &exthdr_hbh,
        [IPPROTO_ROUTING]       = &exthdr_rt,
index 5317a830ac6de3d1b00dda39650323565b6bedd9..51a61472a0f1abca0ad6e502e330de87abb092eb 100644 (file)
@@ -513,8 +513,25 @@ static void netlink_parse_exthdr(struct netlink_parse_ctx *ctx,
        expr = exthdr_expr_alloc(loc, NULL, 0);
        exthdr_init_raw(expr, type, offset, len, op, flags);
 
-       dreg = netlink_parse_register(nle, NFTNL_EXPR_EXTHDR_DREG);
-       netlink_set_register(ctx, dreg, expr);
+       if (nftnl_expr_is_set(nle, NFTNL_EXPR_EXTHDR_DREG)) {
+               dreg = netlink_parse_register(nle, NFTNL_EXPR_EXTHDR_DREG);
+               netlink_set_register(ctx, dreg, expr);
+       } else if (nftnl_expr_is_set(nle, NFTNL_EXPR_EXTHDR_SREG)) {
+               enum nft_registers sreg;
+               struct stmt *stmt;
+               struct expr *val;
+
+               sreg = netlink_parse_register(nle, NFTNL_EXPR_EXTHDR_SREG);
+               val = netlink_get_register(ctx, loc, sreg);
+               if (val == NULL)
+                       return netlink_error(ctx, loc,
+                                            "exthdr statement has no expression");
+
+               expr_set_type(val, expr->dtype, expr->byteorder);
+
+               stmt = exthdr_stmt_alloc(loc, expr, val);
+               list_add_tail(&stmt->list, &ctx->rule->stmts);
+       }
 }
 
 static void netlink_parse_hash(struct netlink_parse_ctx *ctx,
index 3d684569cabff61d885b68adb9702ea7d08c7aad..c5a47dec7d105ad4f57b1f46518ba28fdb5f40dc 100644 (file)
@@ -816,6 +816,33 @@ static bool payload_needs_l4csum_update_pseudohdr(const struct expr *expr,
        return false;
 }
 
+static void netlink_gen_exthdr_stmt(struct netlink_linearize_ctx *ctx,
+                                   const struct stmt *stmt)
+{
+       struct nftnl_expr *nle;
+       const struct expr *expr;
+       enum nft_registers sreg;
+       unsigned int offset;
+
+       sreg = get_register(ctx, stmt->exthdr.val);
+       netlink_gen_expr(ctx, stmt->exthdr.val, sreg);
+       release_register(ctx, stmt->exthdr.val);
+
+       expr = stmt->exthdr.expr;
+
+       offset = expr->exthdr.tmpl->offset + expr->exthdr.offset;
+
+       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);
+       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));
+       nftnl_expr_set_u8(nle, NFTNL_EXPR_EXTHDR_OP, expr->exthdr.op);
+       nftnl_rule_add_expr(ctx->nlr, nle);
+}
+
 static void netlink_gen_payload_stmt(struct netlink_linearize_ctx *ctx,
                                     const struct stmt *stmt)
 {
@@ -1239,6 +1266,8 @@ static void netlink_gen_stmt(struct netlink_linearize_ctx *ctx,
                return netlink_gen_verdict_stmt(ctx, stmt);
        case STMT_FLOW:
                return netlink_gen_flow_stmt(ctx, stmt);
+       case STMT_EXTHDR:
+               return netlink_gen_exthdr_stmt(ctx, stmt);
        case STMT_PAYLOAD:
                return netlink_gen_payload_stmt(ctx, stmt);
        case STMT_META:
index 783b72f5a343ee509ef69fcb6535215bf5364241..7898ea3fe7bc7ea68f0085cad65f068319cc2a7f 100644 (file)
@@ -3209,7 +3209,10 @@ ct_stmt                  :       CT      ct_key          SET     expr
 
 payload_stmt           :       payload_expr            SET     expr
                        {
-                               $$ = payload_stmt_alloc(&@$, $1, $3);
+                               if ($1->ops->type == EXPR_EXTHDR)
+                                       $$ = exthdr_stmt_alloc(&@$, $1, $3);
+                               else
+                                       $$ = payload_stmt_alloc(&@$, $1, $3);
                        }
                        ;