diff mbox series

[v2,nft] Introduce socket matching

Message ID 20180530140955.14386-1-ecklm94@gmail.com
State Changes Requested
Delegated to: Pablo Neira
Headers show
Series [v2,nft] Introduce socket matching | expand

Commit Message

Máté Eckl May 30, 2018, 2:09 p.m. UTC
For now it can only match sockets with IP(V6)_TRANSPARENT socket option
set.

Example:
table inet sockin {
	chain sockchain {
		type filter hook prerouting priority -150; policy accept;
		socket transparent 1 mark set 0x00000001 nftrace set 1 counter packets 9 bytes 504 accept

	}
}

Signed-off-by: Máté Eckl <ecklm94@gmail.com>
---
 include/expression.h                |  7 ++++
 include/linux/netfilter/nf_tables.h | 28 ++++++++++++++
 include/socket.h                    | 24 ++++++++++++
 src/Makefile.am                     |  1 +
 src/evaluate.c                      |  7 ++++
 src/netlink_delinearize.c           | 20 ++++++++++
 src/netlink_linearize.c             | 14 +++++++
 src/parser_bison.y                  | 17 +++++++++
 src/scanner.l                       |  3 ++
 src/socket.c                        | 58 +++++++++++++++++++++++++++++
 10 files changed, 179 insertions(+)
 create mode 100644 include/socket.h
 create mode 100644 src/socket.c
diff mbox series

Patch

diff --git a/include/expression.h b/include/expression.h
index 15af35e..2bb51e5 100644
--- a/include/expression.h
+++ b/include/expression.h
@@ -24,6 +24,7 @@ 
  * @EXPR_PAYLOAD:	payload expression
  * @EXPR_EXTHDR:	exthdr expression
  * @EXPR_META:		meta expression
+ * @EXPR_SOCKET:	socket expression
  * @EXPR_CT:		conntrack expression
  * @EXPR_CONCAT:	concatenation
  * @EXPR_LIST:		list of expressions
@@ -50,6 +51,7 @@  enum expr_types {
 	EXPR_PAYLOAD,
 	EXPR_EXTHDR,
 	EXPR_META,
+	EXPR_SOCKET,
 	EXPR_CT,
 	EXPR_CONCAT,
 	EXPR_LIST,
@@ -188,6 +190,7 @@  enum expr_flags {
 #include <rt.h>
 #include <hash.h>
 #include <ct.h>
+#include <socket.h>
 
 /**
  * struct expr
@@ -296,6 +299,10 @@  struct expr {
 			enum nft_meta_keys	key;
 			enum proto_bases	base;
 		} meta;
+		struct {
+			/* SOCKET */
+			enum nft_socket_keys	key;
+		} socket;
 		struct {
 			/* EXPR_RT */
 			enum nft_rt_keys	key;
diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index 660168a..25b8080 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -904,6 +904,34 @@  enum nft_rt_attributes {
 };
 #define NFTA_RT_MAX		(__NFTA_RT_MAX - 1)
 
+/**
+ * enum nft_socket_attributes - nf_tables socket expression netlink attributes
+ *
+ * @NFTA_SOCKET_KEY: socket key to match
+ * @NFTA_SOCKET_DREG: destination register
+ */
+enum nft_socket_attributes {
+	NFTA_SOCKET_UNSPEC,
+
+	NFTA_SOCKET_KEY,
+	NFTA_SOCKET_DREG,
+
+	__NFTA_SOCKET_MAX
+};
+#define NFTA_SOCKET_MAX		(__NFTA_SOCKET_MAX - 1)
+
+/*
+ * enum nft_socket_keys - nf_tables socket expression keys
+ *
+ * @NFT_SOCKET_TRANSPARENT: Value of the IP(V6)_TRANSPARENT socket option_
+ */
+enum nft_socket_keys {
+	NFT_SOCKET_TRANSPARENT,
+
+	__NFT_SOCKET_MAX
+};
+#define NFT_SOCKET_MAX	(__NFT_SOCKET_MAX - 1)
+
 /**
  * enum nft_ct_keys - nf_tables ct expression keys
  *
diff --git a/include/socket.h b/include/socket.h
new file mode 100644
index 0000000..a2ae9f1
--- /dev/null
+++ b/include/socket.h
@@ -0,0 +1,24 @@ 
+#ifndef NFTABLES_SOCKET_H
+#define NFTABLES_SOCKET_H
+
+//#include <parser.h>
+
+/**
+ * struct rt_template - template for routing expressions
+ *
+ * @token:	parser token for the expression
+ * @dtype:	data type of the expression
+ * @len:	length of the expression
+ * @byteorder:	byteorder
+ */
+struct socket_template {
+	const char		*token;
+	const struct datatype	*dtype;
+	unsigned int		len;
+	enum byteorder		byteorder;
+};
+
+extern struct expr *socket_expr_alloc(const struct location *loc,
+				    enum nft_socket_keys key);
+
+#endif /* NFTABLES_SOCKET_H */
diff --git a/src/Makefile.am b/src/Makefile.am
index 6db31c8..a4ad8cb 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -55,6 +55,7 @@  libnftables_la_SOURCES =			\
 		services.c			\
 		mergesort.c			\
 		tcpopt.c			\
+		socket.c			\
 		libnftables.c
 
 # yacc and lex generate dirty code
diff --git a/src/evaluate.c b/src/evaluate.c
index 4eb36e2..56fea26 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -1712,6 +1712,11 @@  static int expr_evaluate_meta(struct eval_ctx *ctx, struct expr **exprp)
 	return expr_evaluate_primary(ctx, exprp);
 }
 
+static int expr_evaluate_socket(struct eval_ctx *ctx, struct expr **exprp)
+{
+	return expr_evaluate_primary(ctx, exprp);
+}
+
 static int expr_evaluate_variable(struct eval_ctx *ctx, struct expr **exprp)
 {
 	struct expr *new = expr_clone((*exprp)->sym->expr);
@@ -1749,6 +1754,8 @@  static int expr_evaluate(struct eval_ctx *ctx, struct expr **expr)
 		return expr_evaluate_primary(ctx, expr);
 	case EXPR_META:
 		return expr_evaluate_meta(ctx, expr);
+	case EXPR_SOCKET:
+		return expr_evaluate_socket(ctx, expr);
 	case EXPR_FIB:
 		return expr_evaluate_fib(ctx, expr);
 	case EXPR_PAYLOAD:
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 7d882eb..2ad9d32 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -615,6 +615,24 @@  static void netlink_parse_meta_expr(struct netlink_parse_ctx *ctx,
 	netlink_set_register(ctx, dreg, expr);
 }
 
+static void netlink_parse_socket(struct netlink_parse_ctx *ctx,
+				      const struct location *loc,
+				      const struct nftnl_expr *nle)
+{
+	enum nft_registers dreg;
+	uint32_t key;
+	struct expr * expr;
+
+	key = nftnl_expr_get_u32(nle, NFTNL_EXPR_SOCKET_KEY);
+	expr = socket_expr_alloc(loc, key);
+
+	/* Workaround for size mismatch netlink error. */
+	expr->len = BITS_PER_BYTE;
+
+	dreg = netlink_parse_register(nle, NFTNL_EXPR_SOCKET_DREG);
+	netlink_set_register(ctx, dreg, expr);
+}
+
 static void netlink_parse_meta_stmt(struct netlink_parse_ctx *ctx,
 				    const struct location *loc,
 				    const struct nftnl_expr *nle)
@@ -1292,6 +1310,7 @@  static const struct {
 	{ .name = "payload",	.parse = netlink_parse_payload },
 	{ .name = "exthdr",	.parse = netlink_parse_exthdr },
 	{ .name = "meta",	.parse = netlink_parse_meta },
+	{ .name = "socket",	.parse = netlink_parse_socket },
 	{ .name = "rt",		.parse = netlink_parse_rt },
 	{ .name = "ct",		.parse = netlink_parse_ct },
 	{ .name = "counter",	.parse = netlink_parse_counter },
@@ -1976,6 +1995,7 @@  static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp)
 	case EXPR_VERDICT:
 	case EXPR_NUMGEN:
 	case EXPR_FIB:
+	case EXPR_SOCKET:
 		break;
 	case EXPR_HASH:
 		if (expr->hash.expr)
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
index 2ab8acc..05a1dbd 100644
--- a/src/netlink_linearize.c
+++ b/src/netlink_linearize.c
@@ -207,6 +207,18 @@  static void netlink_gen_rt(struct netlink_linearize_ctx *ctx,
 	nftnl_rule_add_expr(ctx->nlr, nle);
 }
 
+static void netlink_gen_socket(struct netlink_linearize_ctx *ctx,
+			     const struct expr *expr,
+			     enum nft_registers dreg)
+{
+	struct nftnl_expr *nle;
+
+	nle = alloc_nft_expr("socket");
+	netlink_put_register(nle, NFTNL_EXPR_SOCKET_DREG, dreg);
+	nftnl_expr_set_u32(nle, NFTNL_EXPR_SOCKET_KEY, expr->socket.key);
+	nftnl_rule_add_expr(ctx->nlr, nle);
+}
+
 static void netlink_gen_numgen(struct netlink_linearize_ctx *ctx,
 			    const struct expr *expr,
 			    enum nft_registers dreg)
@@ -694,6 +706,8 @@  static void netlink_gen_expr(struct netlink_linearize_ctx *ctx,
 		return netlink_gen_hash(ctx, expr, dreg);
 	case EXPR_FIB:
 		return netlink_gen_fib(ctx, expr, dreg);
+	case EXPR_SOCKET:
+		return netlink_gen_socket(ctx, expr, dreg);
 	default:
 		BUG("unknown expression type %s\n", expr->ops->name);
 	}
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 1eb6ec6..5885b21 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"
@@ -692,6 +695,10 @@  int nft_lex(void *, void *, void *);
 %destructor { expr_free($$); }	meta_expr
 %type <val>			meta_key	meta_key_qualified	meta_key_unqualified	numgen_type
 
+%type <expr>			socket_expr
+%destructor { expr_free($$); } socket_expr
+%type<val>			socket_key
+
 %type <val>			nf_key_proto
 
 %type <expr>			rt_expr
@@ -2863,6 +2870,7 @@  primary_expr		:	symbol_expr			{ $$ = $1; }
 			|	exthdr_expr			{ $$ = $1; }
 			|	exthdr_exists_expr		{ $$ = $1; }
 			|	meta_expr			{ $$ = $1; }
+			|	socket_expr			{ $$ = $1; }
 			|	rt_expr				{ $$ = $1; }
 			|	ct_expr				{ $$ = $1; }
 			|	numgen_expr			{ $$ = $1; }
@@ -3540,6 +3548,15 @@  meta_stmt		:	META	meta_key	SET	stmt_expr
 			}
 			;
 
+socket_expr		:	SOCKET	socket_key
+			{
+				$$ = socket_expr_alloc(&@$, $2);
+			}
+			;
+
+socket_key 		: TRANSPARENT { $$ = NFT_SOCKET_TRANSPARENT; }
+			;
+
 offset_opt		:	/* empty */	{ $$ = 0; }
 			|	OFFSET	NUM	{ $$ = $2; }
 			;
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/socket.c b/src/socket.c
new file mode 100644
index 0000000..8e5eee3
--- /dev/null
+++ b/src/socket.c
@@ -0,0 +1,58 @@ 
+/*
+ * Socket expression/statement related definition and types.
+ *
+ * Copyright (c) 2018 Máté Eckl <ecklm94@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <nftables.h>
+#include <expression.h>
+#include <socket.h>
+
+const struct socket_template socket_templates[] = {
+	[NFT_SOCKET_TRANSPARENT]	= {.token = "transparent",
+					   .dtype = &integer_type,
+					   .len = 1,
+					   .byteorder = BYTEORDER_HOST_ENDIAN,
+					  }
+};
+
+static void socket_expr_print(const struct expr *expr, struct output_ctx *octx)
+{
+	nft_print(octx, "socket %s", socket_templates[expr->socket.key].token);
+}
+
+static bool socket_expr_cmp(const struct expr *e1, const struct expr *e2)
+{
+	return e1->socket.key == e2->socket.key;
+}
+
+static void socket_expr_clone(struct expr *new, const struct expr *expr)
+{
+	new->socket.key = expr->socket.key;
+}
+
+static const struct expr_ops socket_expr_ops = {
+	.type		= EXPR_SOCKET,
+	.name		= "socket",
+	.print		= socket_expr_print,
+	.cmp		= socket_expr_cmp,
+	.clone		= socket_expr_clone,
+};
+
+struct expr *socket_expr_alloc(const struct location *loc, enum nft_socket_keys key)
+{
+	const struct socket_template *tmpl = &socket_templates[key];
+	struct expr *expr;
+
+	expr = expr_alloc(loc, &socket_expr_ops, tmpl->dtype,
+			  tmpl->byteorder, tmpl->len);
+	expr->socket.key = key;
+
+	return expr;
+}
+
+