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 <[email protected]>
---
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 <sys/socket.h>
#include <libnftnl/udata.h>
#include <xt.h>
+#include <linux/netfilter/xt_socket.h>
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 <gmputil.h>
#include <utils.h>
#include <netinet/in.h>
+#include <linux/netfilter/xt_socket.h>
#include <linux/netfilter.h>
#include <libnftnl/udata.h>
@@ -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 <list> stmt_list
%destructor { stmt_list_free($$); xfree($$); } stmt_list
-%type <stmt> stmt match_stmt verdict_stmt
-%destructor { stmt_free($$); } stmt match_stmt verdict_stmt
+%type <stmt> stmt match_stmt verdict_stmt socket_stmt
+%destructor { stmt_free($$); } stmt match_stmt verdict_stmt socket_stmt
+
+%type <val> socket_stmt_flag socket_stmt_flags
+
%type <stmt> counter_stmt counter_stmt_alloc
%destructor { stmt_free($$); } counter_stmt counter_stmt_alloc
%type <stmt> 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)
{
--
ecklm
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html