From 57e4a095edc4dab19e14fc8d1bca3febde1ca86c Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 31 May 2018 18:08:06 +0200 Subject: 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 --- src/evaluate.c | 1 + src/netlink_delinearize.c | 16 ++++++++++++++++ src/netlink_linearize.c | 18 ++++++++++++++++++ src/parser_bison.y | 18 ++++++++++++++++-- src/statement.c | 21 +++++++++++++++++++++ 5 files changed, 72 insertions(+), 2 deletions(-) (limited to 'src') 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 @@ -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: 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 log_stmt log_stmt_alloc %destructor { stmt_free($$); } log_stmt log_stmt_alloc %type level_type log_flags log_flags_tcp log_flag_tcp -%type limit_stmt quota_stmt -%destructor { stmt_free($$); } limit_stmt quota_stmt +%type limit_stmt quota_stmt connlimit_stmt +%destructor { stmt_free($$); } limit_stmt quota_stmt connlimit_stmt %type limit_burst limit_mode time_unit quota_mode %type 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"); -- cgit v1.2.3