summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2018-05-31 18:08:06 +0200
committerPablo Neira Ayuso <pablo@netfilter.org>2018-06-06 15:49:47 +0200
commit57e4a095edc4dab19e14fc8d1bca3febde1ca86c (patch)
treec51aaa1f1d3a6d1b42d2ee3da073b46289524ea5
parent3384849c113b1ec3906c7a22cc71d708aae1218e (diff)
src: connlimit support
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>
-rw-r--r--include/linux/netfilter/nf_tables.h21
-rw-r--r--include/statement.h10
-rw-r--r--src/evaluate.c1
-rw-r--r--src/netlink_delinearize.c16
-rw-r--r--src/netlink_linearize.c18
-rw-r--r--src/parser_bison.y18
-rw-r--r--src/statement.c21
7 files changed, 102 insertions, 3 deletions
diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index 51d54d67..40d43271 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
*
@@ -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)
/**
diff --git a/include/statement.h b/include/statement.h
index de26549b..d4bcaf3a 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 ff75fc45..039e02db 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -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:
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 2c938e52..7dbf596a 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 2ab8accf..13c3564f 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 d13eaa66..5797ee76 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 4a646e06..6f490132 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");