]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
src: connlimit support
authorPablo Neira Ayuso <pablo@netfilter.org>
Thu, 31 May 2018 16:08:06 +0000 (18:08 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Wed, 6 Jun 2018 13:49:47 +0000 (15:49 +0200)
This patch adds support for the new connlimit stateful expression, that
provides a mapping with the connlimit iptables extension through meters.
eg.

  nft add rule filter input tcp dport 22 \
meter test { ip saddr ct count over 2 } counter reject

This limits the maximum amount incoming of SSH connections per source
address up to 2 simultaneous connections.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
include/linux/netfilter/nf_tables.h
include/statement.h
src/evaluate.c
src/netlink_delinearize.c
src/netlink_linearize.c
src/parser_bison.y
src/statement.c

index 51d54d6780abf16ad8bf97bc5462d2b3a5dac716..40d4327151d97f2b3053bc7c214e30b1acc0d8dd 100644 (file)
@@ -1018,6 +1018,24 @@ enum nft_limit_attributes {
 };
 #define NFTA_LIMIT_MAX         (__NFTA_LIMIT_MAX - 1)
 
+enum nft_connlimit_flags {
+       NFT_CONNLIMIT_F_INV     = (1 << 0),
+};
+
+/**
+ * enum nft_connlimit_attributes - nf_tables connlimit expression netlink attributes
+ *
+ * @NFTA_CONNLIMIT_COUNT: number of connections (NLA_U32)
+ * @NFTA_CONNLIMIT_FLAGS: flags (NLA_U32: enum nft_connlimit_flags)
+ */
+enum nft_connlimit_attributes {
+       NFTA_CONNLIMIT_UNSPEC,
+       NFTA_CONNLIMIT_COUNT,
+       NFTA_CONNLIMIT_FLAGS,
+       __NFTA_CONNLIMIT_MAX
+};
+#define NFTA_CONNLIMIT_MAX     (__NFTA_CONNLIMIT_MAX - 1)
+
 /**
  * enum nft_counter_attributes - nf_tables counter expression netlink attributes
  *
@@ -1328,7 +1346,8 @@ enum nft_ct_helper_attributes {
 #define NFT_OBJECT_QUOTA       2
 #define NFT_OBJECT_CT_HELPER   3
 #define NFT_OBJECT_LIMIT       4
-#define __NFT_OBJECT_MAX       5
+#define NFT_OBJECT_CONNLIMIT   5
+#define __NFT_OBJECT_MAX       6
 #define NFT_OBJECT_MAX         (__NFT_OBJECT_MAX - 1)
 
 /**
index de26549b32f4cf196dba95d06e7f62f2bda9fdcd..d4bcaf3ae1452084c6f6a96461591955edcb2a51 100644 (file)
@@ -25,6 +25,13 @@ struct objref_stmt {
 const char *objref_type_name(uint32_t type);
 struct stmt *objref_stmt_alloc(const struct location *loc);
 
+struct connlimit_stmt {
+       uint32_t                count;
+       uint32_t                flags;
+};
+
+extern struct stmt *connlimit_stmt_alloc(const struct location *loc);
+
 struct counter_stmt {
        uint64_t                packets;
        uint64_t                bytes;
@@ -247,6 +254,7 @@ extern struct stmt *xt_stmt_alloc(const struct location *loc);
  * @STMT_OBJREF:       stateful object reference statement
  * @STMT_EXTHDR:       extension header statement
  * @STMT_FLOW_OFFLOAD: flow offload statement
+ * @STMT_CONNLIMIT:    connection limit statement
  * @STMT_MAP:          map statement
  */
 enum stmt_types {
@@ -272,6 +280,7 @@ enum stmt_types {
        STMT_OBJREF,
        STMT_EXTHDR,
        STMT_FLOW_OFFLOAD,
+       STMT_CONNLIMIT,
        STMT_MAP,
 };
 
@@ -318,6 +327,7 @@ struct stmt {
                struct expr             *expr;
                struct exthdr_stmt      exthdr;
                struct meter_stmt       meter;
+               struct connlimit_stmt   connlimit;
                struct counter_stmt     counter;
                struct payload_stmt     payload;
                struct meta_stmt        meta;
index ff75fc451e9ab0301e9ec63b9ecea7f962e3d210..039e02dbaaaa1d151cae13d981e3b190277dfc26 100644 (file)
@@ -2703,6 +2703,7 @@ int stmt_evaluate(struct eval_ctx *ctx, struct stmt *stmt)
        }
 
        switch (stmt->ops->type) {
+       case STMT_CONNLIMIT:
        case STMT_COUNTER:
        case STMT_LIMIT:
        case STMT_QUOTA:
index 2c938e520357c856456c574012f01ebe8e6ec0ba..7dbf596af36e882c94da7adba5e019d4db6b28d8 100644 (file)
@@ -751,6 +751,21 @@ static void netlink_parse_ct(struct netlink_parse_ctx *ctx,
                netlink_parse_ct_stmt(ctx, loc, nle);
 }
 
+static void netlink_parse_connlimit(struct netlink_parse_ctx *ctx,
+                                   const struct location *loc,
+                                   const struct nftnl_expr *nle)
+{
+       struct stmt *stmt;
+
+       stmt = connlimit_stmt_alloc(loc);
+       stmt->connlimit.count =
+               nftnl_expr_get_u32(nle, NFTNL_EXPR_CONNLIMIT_COUNT);
+       stmt->connlimit.flags =
+               nftnl_expr_get_u32(nle, NFTNL_EXPR_CONNLIMIT_FLAGS);
+
+       ctx->stmt = stmt;
+}
+
 static void netlink_parse_counter(struct netlink_parse_ctx *ctx,
                                  const struct location *loc,
                                  const struct nftnl_expr *nle)
@@ -1294,6 +1309,7 @@ static const struct {
        { .name = "meta",       .parse = netlink_parse_meta },
        { .name = "rt",         .parse = netlink_parse_rt },
        { .name = "ct",         .parse = netlink_parse_ct },
+       { .name = "connlimit",  .parse = netlink_parse_connlimit },
        { .name = "counter",    .parse = netlink_parse_counter },
        { .name = "log",        .parse = netlink_parse_log },
        { .name = "limit",      .parse = netlink_parse_limit },
index 2ab8accf0bf4dfc4d2fecb2c66d081f296a95fbf..13c3564fb007fa91510bd9fe95fd6a0326376f8c 100644 (file)
@@ -733,6 +733,21 @@ static void netlink_gen_objref_stmt(struct netlink_linearize_ctx *ctx,
        nftnl_rule_add_expr(ctx->nlr, nle);
 }
 
+static struct nftnl_expr *
+netlink_gen_connlimit_stmt(struct netlink_linearize_ctx *ctx,
+                          const struct stmt *stmt)
+{
+       struct nftnl_expr *nle;
+
+       nle = alloc_nft_expr("connlimit");
+       nftnl_expr_set_u32(nle, NFTNL_EXPR_CONNLIMIT_COUNT,
+                          stmt->connlimit.count);
+       nftnl_expr_set_u32(nle, NFTNL_EXPR_CONNLIMIT_FLAGS,
+                          stmt->connlimit.flags);
+
+       return nle;
+}
+
 static struct nftnl_expr *
 netlink_gen_counter_stmt(struct netlink_linearize_ctx *ctx,
                         const struct stmt *stmt)
@@ -789,6 +804,8 @@ netlink_gen_stmt_stateful(struct netlink_linearize_ctx *ctx,
                          const struct stmt *stmt)
 {
        switch (stmt->ops->type) {
+       case STMT_CONNLIMIT:
+               return netlink_gen_connlimit_stmt(ctx, stmt);
        case STMT_COUNTER:
                return netlink_gen_counter_stmt(ctx, stmt);
        case STMT_LIMIT:
@@ -1269,6 +1286,7 @@ static void netlink_gen_stmt(struct netlink_linearize_ctx *ctx,
                return netlink_gen_set_stmt(ctx, stmt);
        case STMT_FWD:
                return netlink_gen_fwd_stmt(ctx, stmt);
+       case STMT_CONNLIMIT:
        case STMT_COUNTER:
        case STMT_LIMIT:
        case STMT_QUOTA:
index d13eaa666a1e03869f7bca34c67be13275aefeda..5797ee766090a06e5fdfa4377a9d450b6bad390d 100644 (file)
@@ -560,8 +560,8 @@ int nft_lex(void *, void *, void *);
 %type <stmt>                   log_stmt log_stmt_alloc
 %destructor { stmt_free($$); } log_stmt log_stmt_alloc
 %type <val>                    level_type log_flags log_flags_tcp log_flag_tcp
-%type <stmt>                   limit_stmt quota_stmt
-%destructor { stmt_free($$); } limit_stmt quota_stmt
+%type <stmt>                   limit_stmt quota_stmt connlimit_stmt
+%destructor { stmt_free($$); } limit_stmt quota_stmt connlimit_stmt
 %type <val>                    limit_burst limit_mode time_unit quota_mode
 %type <stmt>                   reject_stmt reject_stmt_alloc
 %destructor { stmt_free($$); } reject_stmt reject_stmt_alloc
@@ -2062,6 +2062,7 @@ stmt_list         :       stmt
 stmt                   :       verdict_stmt
                        |       match_stmt
                        |       meter_stmt
+                       |       connlimit_stmt
                        |       counter_stmt
                        |       payload_stmt
                        |       meta_stmt
@@ -2129,6 +2130,19 @@ verdict_map_list_member_expr:    opt_newline     set_elem_expr   COLON   verdict_expr    opt_n
                        }
                        ;
 
+connlimit_stmt         :       CT      COUNT   NUM
+                       {
+                               $$ = connlimit_stmt_alloc(&@$);
+                               $$->connlimit.count     = $3;
+                       }
+                       |       CT      COUNT   OVER    NUM
+                       {
+                               $$ = connlimit_stmt_alloc(&@$);
+                               $$->connlimit.count = $4;
+                               $$->connlimit.flags = NFT_CONNLIMIT_F_INV;
+                       }
+                       ;
+
 counter_stmt           :       counter_stmt_alloc
                        |       counter_stmt_alloc      counter_args
 
index 4a646e06fc2bd8006b3192e570e72f172ab4b8a8..6f490132db2661a2a9b160b6d5d0fb5e9dc8d824 100644 (file)
@@ -149,6 +149,27 @@ struct stmt *meter_stmt_alloc(const struct location *loc)
        return stmt_alloc(loc, &meter_stmt_ops);
 }
 
+static void connlimit_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
+{
+       nft_print(octx, "ct count %s%u ",
+                 stmt->connlimit.flags ? "over " : "", stmt->connlimit.count);
+}
+
+static const struct stmt_ops connlimit_stmt_ops = {
+       .type           = STMT_CONNLIMIT,
+       .name           = "connlimit",
+       .print          = connlimit_stmt_print,
+};
+
+struct stmt *connlimit_stmt_alloc(const struct location *loc)
+{
+       struct stmt *stmt;
+
+       stmt = stmt_alloc(loc, &connlimit_stmt_ops);
+       stmt->flags |= STMT_F_STATEFUL;
+       return stmt;
+}
+
 static void counter_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
 {
        nft_print(octx, "counter");