[PATCH nft] src: connlimit support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxxxxxx>
---
 include/linux/netfilter/nf_tables.h | 21 ++++++++++++++++++++-
 include/statement.h                 | 10 ++++++++++
 src/evaluate.c                      |  1 +
 src/netlink_delinearize.c           | 16 ++++++++++++++++
 src/netlink_linearize.c             | 18 ++++++++++++++++++
 src/parser_bison.y                  | 18 ++++++++++++++++--
 src/statement.c                     | 21 +++++++++++++++++++++
 7 files changed, 102 insertions(+), 3 deletions(-)

diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index 660168ab924a..feed4954bea0 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -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
  *
@@ -1323,7 +1341,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)
 
 /**
diff --git a/include/statement.h b/include/statement.h
index de26549b32f4..d4bcaf3ae145 100644
--- a/include/statement.h
+++ b/include/statement.h
@@ -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;
diff --git a/src/evaluate.c b/src/evaluate.c
index 4eb36e2d3879..2c4e2cd17d35 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -2699,6 +2699,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:
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 7d882ebac555..3ef85c073e20 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -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 },
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
index 2ab8accf0bf4..13c3564fb007 100644
--- a/src/netlink_linearize.c
+++ b/src/netlink_linearize.c
@@ -734,6 +734,21 @@ static void netlink_gen_objref_stmt(struct netlink_linearize_ctx *ctx,
 }
 
 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:
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 1eb6ec6e93f2..3bc08e374bb6 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -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
 
diff --git a/src/statement.c b/src/statement.c
index ac151737cade..7f18da16e5a7 100644
--- a/src/statement.c
+++ b/src/statement.c
@@ -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");
-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Netfitler Users]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux