From patchwork Thu May 17 07:36:54 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?b?TcOhdMOpIEVja2w=?= X-Patchwork-Id: 915144 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="ULlef3Lk"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 40mjn60gSxz9s3X for ; Thu, 17 May 2018 17:37:14 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752071AbeEQHhM (ORCPT ); Thu, 17 May 2018 03:37:12 -0400 Received: from mail-wr0-f194.google.com ([209.85.128.194]:36351 "EHLO mail-wr0-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751533AbeEQHhL (ORCPT ); Thu, 17 May 2018 03:37:11 -0400 Received: by mail-wr0-f194.google.com with SMTP id p4-v6so4553481wrh.3 for ; Thu, 17 May 2018 00:37:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references:mime-version :content-transfer-encoding; bh=LWQW+npSRrzTCDmcvzEmYrUoAjBf6SkeR8X0tRWZzT0=; b=ULlef3LkO6YA+Uaup9sWVQ8JBDE02jZ//4yJUC/rqP1m53zuDxffSFJ8lMfQNeRh1G snrRz2Hq7AMUqK+JqpULi8X1WheGiqCzGzIr7I/E/KQpRepHxc6bQTkS8RxKS9i/UXV9 FSfYPpeeHoNZrxA0CpVFZxREct4JOmbgtuoMhKBzmrUqoC/87cn3Czre2i8fUdnQROov yL76YreexlK5/KGyZXSNXJdX6S9lOnnSpPfWhGfSSif4C28bufOYopVtzdpDmq/A/+F/ HFH1N7rEo3ZYSR1nWCs7z3Z2/XzYHcl0xTQ56A8AATXHmAHb28RoUcJDSbatIWL9LYJz M3XQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=LWQW+npSRrzTCDmcvzEmYrUoAjBf6SkeR8X0tRWZzT0=; b=ZyqgoIfSIqPz9bLU6ErowS1d9/F84CIhMvF7vv2d6ClfR4GGbu3M//0FnJS17Z/YHc hrTHntt74Qnnp7noIInI5CKTrkcpyn+HCk88kiyYyWnkkM05lR0v71RMdii4e33gGx6f L0q6VWlCJIFfGdbDJLQtFzp3mygfZJi3GP3fbuVyDx3k43ewjLyWxT03q3D96Kcxind7 NmecYhL3NxIUCL7hkNeKqoZvXheHdtvAHELIbSQfQxH+qqPLu1pEfREdfiP9pJlQ7SuR PAHb08g88DnuOyeFh1Qjz3zDTAwAVUV85K+wpengZRVHwE2t3Da24oYwFHWvpVkNHKtb Q+vg== X-Gm-Message-State: ALKqPwcoTiCwyX2nAfhnCCilfhdW92ul/+5PkFoajcLNX3wY9CcxVW85 w2BbaFATnkN/e6F5Alm4JEN8ISvN X-Google-Smtp-Source: AB8JxZrxQffmZ34DFJA4uyqONKEEgSyoL9yWWtf6dkQxeTbsdTsy+cjvVAB8DL3x9nBrX+hSqhqokA== X-Received: by 2002:adf:85b8:: with SMTP id 53-v6mr3456709wrt.31.1526542629477; Thu, 17 May 2018 00:37:09 -0700 (PDT) Received: from ecklm-lapos.sch.bme.hu (ecklapos.sch.bme.hu. [152.66.210.16]) by smtp.gmail.com with ESMTPSA id 123-v6sm5614787wmt.19.2018.05.17.00.37.08 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 17 May 2018 00:37:09 -0700 (PDT) From: =?utf-8?b?TcOhdMOpIEVja2w=?= To: netfilter-devel@vger.kernel.org Subject: [PATCH nft 1/2] Introduce socket matching Date: Thu, 17 May 2018 09:36:54 +0200 Message-Id: X-Mailer: git-send-email 2.17.0 In-Reply-To: References: MIME-Version: 1.0 Sender: netfilter-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org Socket matching is achieved using the nft_compat interface. The list of known limitations of the current implementation are: * The absence of a corresponding socket cannot be matched (`socket missing`). * Only transparent socket flag can be matched, nowildcard is not a flag, it should be matched with a different expression if desired. Other options that can be set with `setsockopt` are unavailable. * Such a rule cannot be added to an `inet` table. In the long term native implementation might be worth it. Example: table ip stable { chain tchain { type filter hook prerouting priority -150; policy accept; socket flags transparent counter packets 12 bytes 608 mark set 0x00000001 accept socket exists counter packets 52 bytes 3316 } } table ip6 stable { chain tchain { type filter hook prerouting priority -150; policy accept; socket flags transparent counter packets 0 bytes 0 mark set 0x00000001 accept socket exists counter packets 0 bytes 0 } } Signed-off-by: Máté Eckl --- include/linux/netfilter/nf_tables.h | 4 ++++ include/statement.h | 10 +++++++++ include/xt.h | 4 ++-- src/evaluate.c | 11 ++++++++++ src/netlink_delinearize.c | 19 ++++++++++++++++ src/netlink_linearize.c | 21 ++++++++++++++++++ src/parser_bison.y | 31 ++++++++++++++++++++++++-- src/scanner.l | 3 +++ src/statement.c | 34 +++++++++++++++++++++++++++++ src/xt.c | 2 +- 10 files changed, 134 insertions(+), 5 deletions(-) diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h index 3395faf..31fd6f4 100644 --- a/include/linux/netfilter/nf_tables.h +++ b/include/linux/netfilter/nf_tables.h @@ -1284,6 +1284,10 @@ enum nft_fib_flags { NFTA_FIB_F_PRESENT = 1 << 5, /* check existence only */ }; +enum nft_socket_flags { + NFTA_SOCKET_TRANSPARENT = (1<<0), +}; + enum nft_ct_helper_attributes { NFTA_CT_HELPER_UNSPEC, NFTA_CT_HELPER_NAME, diff --git a/include/statement.h b/include/statement.h index de26549..84a8f3f 100644 --- a/include/statement.h +++ b/include/statement.h @@ -32,6 +32,13 @@ struct counter_stmt { extern struct stmt *counter_stmt_alloc(const struct location *loc); +struct socket_stmt { + bool exists; + __u8 flags; +}; + +extern struct stmt *socket_stmt_alloc(const struct location *loc, bool exists, __u8 flags); + struct exthdr_stmt { struct expr *expr; struct expr *val; @@ -248,6 +255,7 @@ extern struct stmt *xt_stmt_alloc(const struct location *loc); * @STMT_EXTHDR: extension header statement * @STMT_FLOW_OFFLOAD: flow offload statement * @STMT_MAP: map statement + * @STMT_SOCKET: socket statement */ enum stmt_types { STMT_INVALID, @@ -273,6 +281,7 @@ enum stmt_types { STMT_EXTHDR, STMT_FLOW_OFFLOAD, STMT_MAP, + STMT_SOCKET, }; /** @@ -335,6 +344,7 @@ struct stmt { struct objref_stmt objref; struct flow_stmt flow; struct map_stmt map; + struct socket_stmt socket; }; }; diff --git a/include/xt.h b/include/xt.h index 753511e..5b29522 100644 --- a/include/xt.h +++ b/include/xt.h @@ -14,7 +14,7 @@ void xt_stmt_release(const struct stmt *stmt); void netlink_parse_target(struct netlink_parse_ctx *ctx, const struct location *loc, const struct nftnl_expr *nle); -void netlink_parse_match(struct netlink_parse_ctx *ctx, +void xt_netlink_parse_match(struct netlink_parse_ctx *ctx, const struct location *loc, const struct nftnl_expr *nle); void stmt_xt_postprocess(struct rule_pp_ctx *rctx, struct stmt *stmt, @@ -28,7 +28,7 @@ static inline void xt_stmt_release(const struct stmt *stmt) {} static inline void netlink_parse_target(struct netlink_parse_ctx *ctx, const struct location *loc, const struct nftnl_expr *nle) {} -static inline void netlink_parse_match(struct netlink_parse_ctx *ctx, +static inline void xt_netlink_parse_match(struct netlink_parse_ctx *ctx, const struct location *loc, const struct nftnl_expr *nle) {} static inline void stmt_xt_postprocess(struct rule_pp_ctx *rctx, diff --git a/src/evaluate.c b/src/evaluate.c index 4eb36e2..5222f4e 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -2686,6 +2686,15 @@ static int stmt_evaluate_objref(struct eval_ctx *ctx, struct stmt *stmt) return 0; } +static int stmt_evaluate_socket(struct eval_ctx *ctx, struct stmt *stmt) +{ + const struct socket_stmt * const s = &stmt->socket; + + if (!s->exists && s->flags) + return -1; + return 0; +} + int stmt_evaluate(struct eval_ctx *ctx, struct stmt *stmt) { if (ctx->debug_mask & NFT_DEBUG_EVALUATION) { @@ -2737,6 +2746,8 @@ int stmt_evaluate(struct eval_ctx *ctx, struct stmt *stmt) return stmt_evaluate_objref(ctx, stmt); case STMT_MAP: return stmt_evaluate_map(ctx, stmt); + case STMT_SOCKET: + return stmt_evaluate_socket(ctx, stmt); default: BUG("unknown statement type %s\n", stmt->ops->name); } diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c index 8f4035a..19c753a 100644 --- a/src/netlink_delinearize.c +++ b/src/netlink_delinearize.c @@ -27,6 +27,7 @@ #include #include #include +#include static int netlink_parse_expr(const struct nftnl_expr *nle, struct netlink_parse_ctx *ctx); @@ -1278,6 +1279,24 @@ static void netlink_parse_objref(struct netlink_parse_ctx *ctx, ctx->stmt = stmt; } +static void netlink_parse_match(struct netlink_parse_ctx *ctx, + const struct location *loc, + const struct nftnl_expr *nle) +{ + if (!strcmp(nftnl_expr_get_str(nle, NFTNL_EXPR_MT_NAME), "socket") && + nftnl_expr_get_u32(nle, NFTNL_EXPR_MT_REV) == 3) { + const struct xt_socket_mtinfo3 *info; + uint32_t len = 0; + + info = nftnl_expr_get(nle, NFTNL_EXPR_MT_INFO, &len); + if(!info) + return; + ctx->stmt = socket_stmt_alloc(loc, true, info->flags); // true is placeholder + } else { + xt_netlink_parse_match(ctx, loc, nle); + } +} + static const struct { const char *name; void (*parse)(struct netlink_parse_ctx *ctx, diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c index 2ab8acc..5e9345a 100644 --- a/src/netlink_linearize.c +++ b/src/netlink_linearize.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -1155,6 +1156,24 @@ static void netlink_gen_flow_offload_stmt(struct netlink_linearize_ctx *ctx, nftnl_rule_add_expr(ctx->nlr, nle); } +static void netlink_gen_socket_match_stmt(struct netlink_linearize_ctx *ctx, + const struct stmt *stmt) +{ + struct nftnl_expr *nle = alloc_nft_expr("match"); + struct xt_socket_mtinfo3 *info; + + nftnl_expr_set_str(nle, NFTNL_EXPR_MT_NAME, "socket"); + nftnl_expr_set_u32(nle, NFTNL_EXPR_MT_REV, 3); + + info = xzalloc(sizeof(struct xt_socket_mtinfo3)); + info->flags = stmt->socket.flags; + + nftnl_expr_set(nle, NFTNL_EXPR_MT_INFO, info, sizeof(struct xt_socket_mtinfo3)); + + nftnl_rule_add_expr(ctx->nlr, nle); +} + + static void netlink_gen_set_stmt(struct netlink_linearize_ctx *ctx, const struct stmt *stmt) { @@ -1283,6 +1302,8 @@ static void netlink_gen_stmt(struct netlink_linearize_ctx *ctx, return netlink_gen_objref_stmt(ctx, stmt); case STMT_MAP: return netlink_gen_map_stmt(ctx, stmt); + case STMT_SOCKET: + return netlink_gen_socket_match_stmt(ctx, stmt); default: BUG("unknown statement type %s\n", stmt->ops->name); } diff --git a/src/parser_bison.y b/src/parser_bison.y index 0e3ee84..67a5b6f 100644 --- a/src/parser_bison.y +++ b/src/parser_bison.y @@ -189,6 +189,9 @@ int nft_lex(void *, void *, void *); %token FIB "fib" +%token SOCKET "socket" +%token TRANSPARENT "transparent" + %token HOOK "hook" %token DEVICE "device" %token DEVICES "devices" @@ -547,8 +550,11 @@ int nft_lex(void *, void *, void *); %type stmt_list %destructor { stmt_list_free($$); xfree($$); } stmt_list -%type stmt match_stmt verdict_stmt -%destructor { stmt_free($$); } stmt match_stmt verdict_stmt +%type stmt match_stmt verdict_stmt socket_stmt +%destructor { stmt_free($$); } stmt match_stmt verdict_stmt socket_stmt + +%type socket_stmt_flag socket_stmt_flags + %type counter_stmt counter_stmt_alloc %destructor { stmt_free($$); } counter_stmt counter_stmt_alloc %type payload_stmt @@ -2078,6 +2084,27 @@ stmt : verdict_stmt | fwd_stmt | set_stmt | map_stmt + | socket_stmt + ; + +socket_stmt_flag : TRANSPARENT { $$ = NFTA_SOCKET_TRANSPARENT; } + ; + +socket_stmt_flags : socket_stmt_flags COMMA socket_stmt_flag + { + $$ = $1 | $3; + } + | socket_stmt_flag + ; + +socket_stmt : SOCKET EXISTS /* with the actual implementation we cannot match abscence */ + { + $$ = socket_stmt_alloc(&@$, true, 0); + } + | SOCKET FLAGS socket_stmt_flags /* we suppose existance criterion in this case */ + { + $$ = socket_stmt_alloc(&@$, true, $3); + } ; verdict_stmt : verdict_expr diff --git a/src/scanner.l b/src/scanner.l index 6a861cf..416bd27 100644 --- a/src/scanner.l +++ b/src/scanner.l @@ -258,6 +258,9 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr}) "ruleset" { return RULESET; } "trace" { return TRACE; } +"socket" { return SOCKET; } +"transparent" { return TRANSPARENT;} + "accept" { return ACCEPT; } "drop" { return DROP; } "continue" { return CONTINUE; } diff --git a/src/statement.c b/src/statement.c index d291001..ff6a98a 100644 --- a/src/statement.c +++ b/src/statement.c @@ -176,6 +176,40 @@ struct stmt *counter_stmt_alloc(const struct location *loc) return stmt; } +static void socket_stmt_print(const struct stmt *stmt, struct output_ctx *octx) +{ + const struct socket_stmt *s = &stmt->socket; + const char *transp_str = "transparent", + *existance_str = (s->exists) ? "exists" : "missing"; + + nft_print(octx, "socket"); + if (s->flags) { + __u8 f = s->flags; + + nft_print(octx, " flags "); + if(f & NFTA_SOCKET_TRANSPARENT) + nft_print(octx, "%s", transp_str); + } else { + nft_print(octx, " %s", existance_str); + } + // (!s->exists && s->flags) is impossible, see stmt_evaluate_socket +} + +static const struct stmt_ops socket_stmt_ops = { + .type = STMT_SOCKET, + .name = "socket", + .print = socket_stmt_print, +}; + +extern struct stmt *socket_stmt_alloc(const struct location *loc, bool exists, __u8 flags) +{ + struct stmt *stmt = stmt_alloc(loc, &socket_stmt_ops); + + stmt->socket.exists = exists; + stmt->socket.flags = flags; + return stmt; +} + static const char *objref_type[NFT_OBJECT_MAX + 1] = { [NFT_OBJECT_COUNTER] = "counter", [NFT_OBJECT_QUOTA] = "quota", diff --git a/src/xt.c b/src/xt.c index 95d0c5f..4f7c235 100644 --- a/src/xt.c +++ b/src/xt.c @@ -188,7 +188,7 @@ static struct xtables_match *xt_match_clone(struct xtables_match *m) * Delinearization */ -void netlink_parse_match(struct netlink_parse_ctx *ctx, +void xt_netlink_parse_match(struct netlink_parse_ctx *ctx, const struct location *loc, const struct nftnl_expr *nle) {