All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH libnftnl WIP] expr: add synproxy support
@ 2019-06-17 10:32 Fernando Fernandez Mancera
  2019-06-17 10:32 ` [PATCH nf-next WIP] netfilter: nf_tables: Add SYNPROXY support Fernando Fernandez Mancera
  2019-06-17 10:32 ` [PATCH nft WIP] src: introduce SYNPROXY matching Fernando Fernandez Mancera
  0 siblings, 2 replies; 9+ messages in thread
From: Fernando Fernandez Mancera @ 2019-06-17 10:32 UTC (permalink / raw)
  To: netfilter-devel; +Cc: Fernando Fernandez Mancera

Signed-off-by: Fernando Fernandez Mancera <ffmancera@riseup.net>
---
 include/libnftnl/expr.h             |   6 +
 include/linux/netfilter/nf_tables.h |  16 +++
 src/Makefile.am                     |   1 +
 src/expr/synproxy.c                 | 170 ++++++++++++++++++++++++++++
 src/expr_ops.c                      |   2 +
 5 files changed, 195 insertions(+)
 create mode 100644 src/expr/synproxy.c

diff --git a/include/libnftnl/expr.h b/include/libnftnl/expr.h
index b2f8d75..3e0f5b0 100644
--- a/include/libnftnl/expr.h
+++ b/include/libnftnl/expr.h
@@ -291,6 +291,12 @@ enum {
 	NFTNL_EXPR_XFRM_SPNUM,
 };
 
+enum {
+	NFTNL_EXPR_SYNPROXY_MSS	= NFTNL_EXPR_BASE,
+	NFTNL_EXPR_SYNPROXY_WSCALE,
+	NFTNL_EXPR_SYNPROXY_FLAGS,
+};
+
 #ifdef __cplusplus
 } /* extern "C" */
 #endif
diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index fd38cdc..12dc74b 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -951,6 +951,22 @@ enum nft_osf_attributes {
 };
 #define NFTA_OSF_MAX (__NFTA_OSF_MAX - 1)
 
+/**
+ * enum nft_synproxy_attributes - nf_tables synproxy expression
+ * netlink attributes
+ *
+ * @NFTA_SYNPROXY_MSS: mss value sent to the backend (NLA_U16)
+ * @NFTA_SYNPROXY_WSCALE: wscale value sent to the backend (NLA_U8)
+ * @NFTA_SYNPROXY_FLAGS: flags (NLA_U32)
+ */
+enum nft_synproxy_attributes {
+        NFTA_SYNPROXY_MSS,
+        NFTA_SYNPROXY_WSCALE,
+        NFTA_SYNPROXY_FLAGS,
+        __NFTA_SYNPROXY_MAX,
+};
+#define NFTA_SYNPROXY_MAX (__NFTA_SYNPROXY_MAX - 1)
+
 /**
  * enum nft_ct_keys - nf_tables ct expression keys
  *
diff --git a/src/Makefile.am b/src/Makefile.am
index 2d5873f..d100a9e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -58,6 +58,7 @@ libnftnl_la_SOURCES = utils.c		\
 		      expr/socket.c	\
 		      expr/osf.c	\
 		      expr/xfrm.c	\
+		      expr/synproxy.c	\
 		      obj/counter.c	\
 		      obj/ct_helper.c	\
 		      obj/quota.c	\
diff --git a/src/expr/synproxy.c b/src/expr/synproxy.c
new file mode 100644
index 0000000..245f4fb
--- /dev/null
+++ b/src/expr/synproxy.c
@@ -0,0 +1,170 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <linux/netfilter/nf_tables.h>
+
+#include "internal.h"
+#include <libmnl/libmnl.h>
+#include <libnftnl/expr.h>
+#include <libnftnl/rule.h>
+
+struct nftnl_expr_synproxy {
+	uint16_t	mss;
+	uint8_t		wscale;
+	uint32_t	flags;
+};
+
+static int nftnl_expr_synproxy_set(struct nftnl_expr *e, uint16_t type,
+				   const void *data, uint32_t data_len)
+{
+	struct nftnl_expr_synproxy *synproxy = nftnl_expr_data(e);
+
+	switch(type) {
+	case NFTNL_EXPR_SYNPROXY_MSS:
+		memcpy(&synproxy->mss, data, sizeof(synproxy->mss));
+		break;
+	case NFTNL_EXPR_SYNPROXY_WSCALE:
+		memcpy(&synproxy->wscale, data, sizeof(synproxy->wscale));
+		break;
+	case NFTNL_EXPR_SYNPROXY_FLAGS:
+		memcpy(&synproxy->flags, data, sizeof(synproxy->flags));
+		break;
+	}
+	return 0;
+}
+
+static const void *
+nftnl_expr_synproxy_get(const struct nftnl_expr *e, uint16_t type,
+			uint32_t *data_len)
+{
+	struct nftnl_expr_synproxy *synproxy = nftnl_expr_data(e);
+
+	switch(type) {
+	case NFTNL_EXPR_SYNPROXY_MSS:
+		*data_len = sizeof(synproxy->mss);
+		return &synproxy->mss;
+	case NFTNL_EXPR_SYNPROXY_WSCALE:
+		*data_len = sizeof(synproxy->wscale);
+		return &synproxy->wscale;
+	case NFTNL_EXPR_SYNPROXY_FLAGS:
+		*data_len = sizeof(synproxy->flags);
+		return &synproxy->flags;
+	}
+	return NULL;
+}
+
+static int nftnl_expr_synproxy_cb(const struct nlattr *attr, void *data)
+{
+	const struct nlattr **tb = data;
+	int type = mnl_attr_get_type(attr);
+
+	if (mnl_attr_type_valid(attr, NFTA_SYNPROXY_MAX) < 0)
+		return MNL_CB_OK;
+
+	switch(type) {
+	case NFTNL_EXPR_SYNPROXY_MSS:
+		if (mnl_attr_validate(attr, MNL_TYPE_U16) < 0)
+			abi_breakage();
+		break;
+
+	case NFTNL_EXPR_SYNPROXY_WSCALE:
+		if (mnl_attr_validate(attr, MNL_TYPE_U8) < 0)
+			abi_breakage();
+		break;
+
+	case NFTNL_EXPR_SYNPROXY_FLAGS:
+		if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
+			abi_breakage();
+		break;
+	}
+
+	tb[type] = attr;
+	return MNL_CB_OK;
+}
+
+static void
+nftnl_expr_synproxy_build(struct nlmsghdr *nlh, const struct nftnl_expr *e)
+{
+	struct nftnl_expr_synproxy *synproxy = nftnl_expr_data(e);
+
+	if (e->flags & (1 << NFTNL_EXPR_SYNPROXY_MSS))
+		mnl_attr_put_u16(nlh, NFTNL_EXPR_SYNPROXY_MSS,
+				 htons(synproxy->mss));
+	if (e->flags & (1 << NFTNL_EXPR_SYNPROXY_WSCALE))
+		mnl_attr_put_u8(nlh, NFTNL_EXPR_SYNPROXY_WSCALE,
+				synproxy->wscale);
+	if (e->flags & (1 << NFTNL_EXPR_SYNPROXY_FLAGS))
+		mnl_attr_put_u32(nlh, NFTNL_EXPR_SYNPROXY_FLAGS,
+				 htonl(synproxy->flags));
+}
+
+static int
+nftnl_expr_synproxy_parse(struct nftnl_expr *e, struct nlattr *attr)
+{
+	struct nftnl_expr_synproxy *synproxy = nftnl_expr_data(e);
+	struct nlattr *tb[NFTA_SYNPROXY_MAX + 1] = {};
+
+	if (mnl_attr_parse_nested(attr, nftnl_expr_synproxy_cb, tb) < 0)
+		return -1;
+
+	if (tb[NFTA_SYNPROXY_MSS]) {
+		synproxy->mss = ntohs(mnl_attr_get_u16(tb[NFTA_SYNPROXY_MSS]));
+		e->flags |= (1 << NFTNL_EXPR_SYNPROXY_MSS);
+	}
+
+	if (tb[NFTA_SYNPROXY_WSCALE]) {
+		synproxy->wscale = mnl_attr_get_u8(tb[NFTA_SYNPROXY_WSCALE]);
+		e->flags |= (1 << NFTNL_EXPR_SYNPROXY_WSCALE);
+	}
+
+	if (tb[NFTA_SYNPROXY_FLAGS]) {
+		synproxy->flags = ntohl(mnl_attr_get_u32(tb[NFTA_SYNPROXY_FLAGS]));
+		e->flags |= (1 << NFTNL_EXPR_SYNPROXY_FLAGS);
+	}
+
+	return 0;
+}
+
+static int nftnl_expr_synproxy_snprintf_default(char *buf, size_t size,
+						const struct nftnl_expr *e)
+{
+	struct nftnl_expr_synproxy *synproxy = nftnl_expr_data(e);
+	int ret, offset = 0, len = size;
+
+	if (e->flags & (1 << NFTNL_EXPR_SYNPROXY_MSS) &&
+	    e->flags & (1 << NFTNL_EXPR_SYNPROXY_WSCALE)) {
+		ret = snprintf(buf, len, "mss %u wscale %u ", synproxy->mss,
+			       synproxy->wscale);
+		SNPRINTF_BUFFER_SIZE(ret, len, offset);
+	}
+
+	return offset;
+}
+
+static int
+nftnl_expr_synproxy_snprintf(char *buf, size_t len, uint32_t type,
+			     uint32_t flags, const struct nftnl_expr *e)
+{
+	switch(type) {
+	case NFTNL_OUTPUT_DEFAULT:
+		return nftnl_expr_synproxy_snprintf_default(buf, len, e);
+	case NFTNL_OUTPUT_XML:
+	case NFTNL_OUTPUT_JSON:
+	default:
+		break;
+	}
+	return -1;
+}
+
+struct expr_ops expr_ops_synproxy = {
+	.name		= "synproxy",
+	.alloc_len	= sizeof(struct nftnl_expr_synproxy),
+	.max_attr	= NFTA_SYNPROXY_MAX,
+	.set		= nftnl_expr_synproxy_set,
+	.get		= nftnl_expr_synproxy_get,
+	.parse		= nftnl_expr_synproxy_parse,
+	.build		= nftnl_expr_synproxy_build,
+	.snprintf	= nftnl_expr_synproxy_snprintf,
+};
diff --git a/src/expr_ops.c b/src/expr_ops.c
index 051140f..9655e2f 100644
--- a/src/expr_ops.c
+++ b/src/expr_ops.c
@@ -40,6 +40,7 @@ extern struct expr_ops expr_ops_socket;
 extern struct expr_ops expr_ops_tunnel;
 extern struct expr_ops expr_ops_osf;
 extern struct expr_ops expr_ops_xfrm;
+extern struct expr_ops expr_ops_synproxy;
 
 static struct expr_ops expr_ops_notrack = {
 	.name	= "notrack",
@@ -83,6 +84,7 @@ static struct expr_ops *expr_ops[] = {
 	&expr_ops_tunnel,
 	&expr_ops_osf,
 	&expr_ops_xfrm,
+	&expr_ops_synproxy,
 	NULL,
 };
 
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH nf-next WIP] netfilter: nf_tables: Add SYNPROXY support
  2019-06-17 10:32 [PATCH libnftnl WIP] expr: add synproxy support Fernando Fernandez Mancera
@ 2019-06-17 10:32 ` Fernando Fernandez Mancera
  2019-06-17 15:25   ` Pablo Neira Ayuso
  2019-06-17 15:45   ` Pablo Neira Ayuso
  2019-06-17 10:32 ` [PATCH nft WIP] src: introduce SYNPROXY matching Fernando Fernandez Mancera
  1 sibling, 2 replies; 9+ messages in thread
From: Fernando Fernandez Mancera @ 2019-06-17 10:32 UTC (permalink / raw)
  To: netfilter-devel; +Cc: Fernando Fernandez Mancera

Add SYNPROXY module support in nf_tables. It preserves the behaviour of the
SYNPROXY target of iptables but structured in a different way to propose
improvements in the future.

Signed-off-by: Fernando Fernandez Mancera <ffmancera@riseup.net>
---
 include/uapi/linux/netfilter/nf_SYNPROXY.h |   4 +
 include/uapi/linux/netfilter/nf_tables.h   |  16 +
 net/netfilter/Kconfig                      |  11 +
 net/netfilter/Makefile                     |   1 +
 net/netfilter/nft_synproxy.c               | 328 +++++++++++++++++++++
 5 files changed, 360 insertions(+)
 create mode 100644 net/netfilter/nft_synproxy.c

diff --git a/include/uapi/linux/netfilter/nf_SYNPROXY.h b/include/uapi/linux/netfilter/nf_SYNPROXY.h
index 068d1b3a6f06..0e7c39191819 100644
--- a/include/uapi/linux/netfilter/nf_SYNPROXY.h
+++ b/include/uapi/linux/netfilter/nf_SYNPROXY.h
@@ -9,6 +9,10 @@
 #define NF_SYNPROXY_OPT_SACK_PERM	0x04
 #define NF_SYNPROXY_OPT_TIMESTAMP	0x08
 #define NF_SYNPROXY_OPT_ECN		0x10
+#define NF_SYNPROXY_FLAGMASK		(NF_SYNPROXY_OPT_MSS | \
+					 NF_SYNPROXY_OPT_WSCALE | \
+					 NF_SYNPROXY_OPT_SACK_PERM | \
+					 NF_SYNPROXY_OPT_TIMESTAMP)
 
 struct nf_synproxy_info {
 	__u8	options;
diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
index 505393c6e959..f225f237f98a 100644
--- a/include/uapi/linux/netfilter/nf_tables.h
+++ b/include/uapi/linux/netfilter/nf_tables.h
@@ -1537,6 +1537,22 @@ enum nft_osf_flags {
 	NFT_OSF_F_VERSION = (1 << 0),
 };
 
+/**
+ * enum nft_synproxy_attributes - nf_tables synproxy expression
+ * netlink attributes
+ *
+ * @NFTA_SYNPROXY_MSS: mss value sent to the backend (NLA_U16)
+ * @NFTA_SYNPROXY_WSCALE: wscale value sent to the backend (NLA_U8)
+ * @NFTA_SYNPROXY_FLAGS: flags (NLA_U32)
+ */
+enum nft_synproxy_attributes {
+	NFTA_SYNPROXY_MSS,
+	NFTA_SYNPROXY_WSCALE,
+	NFTA_SYNPROXY_FLAGS,
+	__NFTA_SYNPROXY_MAX,
+};
+#define NFTA_SYNPROXY_MAX (__NFTA_SYNPROXY_MAX - 1)
+
 /**
  * enum nft_device_attributes - nf_tables device netlink attributes
  *
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index 21025c2c605b..d59742408d9b 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -651,6 +651,17 @@ config NFT_TPROXY
 	help
 	  This makes transparent proxy support available in nftables.
 
+config NFT_SYNPROXY
+	tristate "Netfilter nf_tables SYNPROXY expression support"
+	depends on NF_CONNTRACK && NETFILTER_ADVANCED
+	select NETFILTER_SYNPROXY
+	select SYN_COOKIES
+	help
+	  The SYNPROXY expression allows you to intercept TCP connections and
+	  establish them using syncookies before they are passed on to the
+	  server. This allows to avoid conntrack and server resource usage
+	  during SYN-flood attacks.
+
 if NF_TABLES_NETDEV
 
 config NF_DUP_NETDEV
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index 72cca6b48960..deada20975ff 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -110,6 +110,7 @@ obj-$(CONFIG_NFT_SOCKET)	+= nft_socket.o
 obj-$(CONFIG_NFT_OSF)		+= nft_osf.o
 obj-$(CONFIG_NFT_TPROXY)	+= nft_tproxy.o
 obj-$(CONFIG_NFT_XFRM)		+= nft_xfrm.o
+obj-$(CONFIG_NFT_SYNPROXY)	+= nft_synproxy.o
 
 obj-$(CONFIG_NFT_NAT)		+= nft_chain_nat.o
 
diff --git a/net/netfilter/nft_synproxy.c b/net/netfilter/nft_synproxy.c
new file mode 100644
index 000000000000..e94e0a1c1722
--- /dev/null
+++ b/net/netfilter/nft_synproxy.c
@@ -0,0 +1,328 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/types.h>
+
+#include <net/ip.h>
+#include <net/tcp.h>
+#include <net/netlink.h>
+
+#include <net/netfilter/nf_tables.h>
+#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_ecache.h>
+#include <net/netfilter/nf_conntrack_extend.h>
+#include <net/netfilter/nf_conntrack_seqadj.h>
+#include <net/netfilter/nf_conntrack_synproxy.h>
+#include <net/netfilter/nf_synproxy.h>
+
+#include <linux/netfilter/nf_tables.h>
+#include <linux/netfilter/nf_SYNPROXY.h>
+
+struct nft_synproxy {
+	u16			mss;
+	u8			wscale;
+	u32			flags;
+};
+
+static const struct nla_policy nft_synproxy_policy[NFTA_SYNPROXY_MAX + 1] = {
+	[NFTA_SYNPROXY_MSS]		= { .type = NLA_U16 },
+	[NFTA_SYNPROXY_WSCALE]		= { .type = NLA_U8 },
+	[NFTA_SYNPROXY_FLAGS]		= { .type = NLA_U32 },
+};
+
+static struct nf_synproxy_info create_synproxy_info(struct nft_synproxy *expr)
+{
+	struct nf_synproxy_info info;
+
+	info.options = expr->flags;
+	info.wscale = expr->wscale;
+	info.mss = expr->mss;
+
+	return info;
+}
+
+static void nft_synproxy_eval_v4(const struct nft_expr *expr,
+				 struct nft_regs *regs,
+				 const struct nft_pktinfo *pkt)
+{
+	struct nft_synproxy *priv = nft_expr_priv(expr);
+	struct nf_synproxy_info info = create_synproxy_info(priv);
+	struct synproxy_options opts = {};
+	struct net *net = nft_net(pkt);
+	struct synproxy_net *snet = synproxy_pernet(net);
+	struct sk_buff *skb = pkt->skb;
+	int thoff = pkt->xt.thoff;
+	const struct tcphdr *tcp;
+	struct tcphdr _tcph;
+
+	if (nf_ip_checksum(skb, nft_hook(pkt), thoff, IPPROTO_TCP)) {
+		regs->verdict.code = NF_DROP;
+		return;
+	}
+
+	tcp = skb_header_pointer(skb, ip_hdrlen(skb),
+				 sizeof(struct tcphdr), &_tcph);
+	if (!tcp) {
+		regs->verdict.code = NF_DROP;
+		return;
+	}
+
+	if (!synproxy_parse_options(skb, thoff, tcp, &opts)) {
+		regs->verdict.code = NF_DROP;
+		return;
+	}
+
+	if (tcp->syn) {
+		/* Initial SYN from client */
+		this_cpu_inc(snet->stats->syn_received);
+
+		if (tcp->ece && tcp->cwr)
+			opts.options |= NF_SYNPROXY_OPT_ECN;
+
+		opts.options &= priv->flags;
+		if (opts.options & NF_SYNPROXY_OPT_TIMESTAMP)
+			synproxy_init_timestamp_cookie(&info, &opts);
+		else
+			opts.options &= ~(NF_SYNPROXY_OPT_WSCALE |
+					  NF_SYNPROXY_OPT_SACK_PERM |
+					  NF_SYNPROXY_OPT_ECN);
+
+		synproxy_send_client_synack(net, skb, tcp, &opts);
+		consume_skb(skb);
+		regs->verdict.code = NF_STOLEN;
+		return;
+	} else if (tcp->ack) {
+		/* ACK from client */
+		if (synproxy_recv_client_ack(net, skb, tcp, &opts,
+					     ntohl(tcp->seq))) {
+			consume_skb(skb);
+			regs->verdict.code = NF_STOLEN;
+		} else {
+			regs->verdict.code = NF_DROP;
+		}
+		return;
+	}
+
+	regs->verdict.code = NFT_CONTINUE;
+}
+
+#if IS_ENABLED(CONFIG_NF_TABLES_IPV6)
+static void nft_synproxy_eval_v6(const struct nft_expr *expr,
+				 struct nft_regs *regs,
+				 const struct nft_pktinfo *pkt)
+{
+	struct nft_synproxy *priv = nft_expr_priv(expr);
+	struct nf_synproxy_info info = create_synproxy_info(priv);
+	struct synproxy_options opts = {};
+	struct net *net = nft_net(pkt);
+	struct synproxy_net *snet = synproxy_pernet(net);
+	struct sk_buff *skb = pkt->skb;
+	int thoff = pkt->xt.thoff;
+	const struct tcphdr *tcp;
+	struct tcphdr _tcph;
+
+	if (nf_ip_checksum(skb, nft_hook(pkt), thoff, IPPROTO_TCP)) {
+		regs->verdict.code = NF_DROP;
+		return;
+	}
+
+	tcp = skb_header_pointer(skb, ip_hdrlen(skb),
+				 sizeof(struct tcphdr), &_tcph);
+	if (!tcp) {
+		regs->verdict.code = NF_DROP;
+		return;
+	}
+
+	if (!synproxy_parse_options(skb, thoff, tcp, &opts)) {
+		regs->verdict.code = NF_DROP;
+		return;
+	}
+
+	if (tcp->syn) {
+		/* Initial SYN from client */
+		this_cpu_inc(snet->stats->syn_received);
+
+		if (tcp->ece && tcp->cwr)
+			opts.options |= NF_SYNPROXY_OPT_ECN;
+
+		opts.options &= priv->flags;
+		if (opts.options & NF_SYNPROXY_OPT_TIMESTAMP)
+			synproxy_init_timestamp_cookie(&info, &opts);
+		else
+			opts.options &= ~(NF_SYNPROXY_OPT_WSCALE |
+					  NF_SYNPROXY_OPT_SACK_PERM |
+					  NF_SYNPROXY_OPT_ECN);
+
+		synproxy_send_client_synack_ipv6(net, skb, tcp, &opts);
+		consume_skb(skb);
+		regs->verdict.code = NF_STOLEN;
+		return;
+	} else if (tcp->ack) {
+		/* ACK from client */
+		if (synproxy_recv_client_ack_ipv6(net, skb, tcp, &opts,
+						  ntohl(tcp->seq))) {
+			consume_skb(skb);
+			regs->verdict.code = NF_STOLEN;
+		} else {
+			regs->verdict.code = NF_DROP;
+		}
+		return;
+	}
+
+	regs->verdict.code = NFT_CONTINUE;
+}
+#endif /* IPv6 support */
+
+static void nft_synproxy_eval(const struct nft_expr *expr,
+			      struct nft_regs *regs,
+			      const struct nft_pktinfo *pkt)
+{
+	switch (nft_pf(pkt)) {
+	case NFPROTO_IPV4:
+		nft_synproxy_eval_v4(expr, regs, pkt);
+		return;
+#if IS_ENABLED(CONFIG_NF_TABLES_IPV6)
+	case NFPROTO_IPV6:
+		nft_synproxy_eval_v6(expr, regs, pkt);
+		return;
+#endif
+	}
+	regs->verdict.code = NFT_BREAK;
+}
+
+static int nft_synproxy_init(const struct nft_ctx *ctx,
+			     const struct nft_expr *expr,
+			     const struct nlattr * const tb[])
+{
+	struct synproxy_net *snet = synproxy_pernet(ctx->net);
+	struct nft_synproxy *priv = nft_expr_priv(expr);
+	u32 flags;
+	int err;
+
+	err = nf_ct_netns_get(ctx->net, ctx->family);
+	if (err)
+		goto nf_ct_failure;
+
+	switch (ctx->family) {
+	case NFPROTO_IPV4:
+		err = nf_synproxy_ipv4_init(snet, ctx->net);
+		if (err)
+			goto nf_ct_failure;
+		snet->hook_ref4++;
+		break;
+	case NFPROTO_IPV6:
+		err = nf_synproxy_ipv6_init(snet, ctx->net);
+		if (err)
+			goto nf_ct_failure;
+		snet->hook_ref6++;
+		break;
+	case NFPROTO_INET:
+		err = nf_synproxy_ipv4_init(snet, ctx->net);
+		if (err)
+			goto nf_ct_failure;
+		err = nf_synproxy_ipv6_init(snet, ctx->net);
+		if (err)
+			goto nf_ct_failure;
+		snet->hook_ref4++;
+		snet->hook_ref6++;
+		break;
+	}
+
+	if (tb[NFTA_SYNPROXY_MSS])
+		priv->mss = ntohs(nla_get_be16(tb[NFTA_SYNPROXY_MSS]));
+	if (tb[NFTA_SYNPROXY_WSCALE])
+		priv->wscale = nla_get_u8(tb[NFTA_SYNPROXY_WSCALE]);
+	if (tb[NFTA_SYNPROXY_FLAGS]) {
+		flags = ntohl(nla_get_be32(tb[NFTA_SYNPROXY_FLAGS]));
+		if (flags != 0 && (flags & NF_SYNPROXY_FLAGMASK) == 0)
+			return -EINVAL;
+		priv->flags = flags;
+	}
+	return 0;
+
+nf_ct_failure:
+	nf_ct_netns_put(ctx->net, ctx->family);
+	return err;
+}
+
+static void nft_synproxy_destroy(const struct nft_ctx *ctx,
+				 const struct nft_expr *expr)
+{
+	struct synproxy_net *snet = synproxy_pernet(ctx->net);
+
+	switch (ctx->family) {
+	case NFPROTO_IPV4:
+		nf_synproxy_ipv4_fini(snet, ctx->net);
+		break;
+	case NFPROTO_IPV6:
+		nf_synproxy_ipv6_fini(snet, ctx->net);
+		break;
+	case NFPROTO_INET:
+		nf_synproxy_ipv4_fini(snet, ctx->net);
+		nf_synproxy_ipv6_fini(snet, ctx->net);
+		break;
+	}
+	nf_ct_netns_put(ctx->net, ctx->family);
+}
+
+static int nft_synproxy_dump(struct sk_buff *skb, const struct nft_expr *expr)
+{
+	const struct nft_synproxy *priv = nft_expr_priv(expr);
+
+	if (nla_put_be16(skb, NFTA_SYNPROXY_MSS, ntohs(priv->mss)))
+		goto nla_put_failure;
+
+	if (nla_put_u8(skb, NFTA_SYNPROXY_WSCALE, priv->wscale))
+		goto nla_put_failure;
+
+	if (nla_put_be32(skb, NFTA_SYNPROXY_FLAGS, ntohl(priv->flags)))
+		goto nla_put_failure;
+
+	return 0;
+
+nla_put_failure:
+	return -1;
+}
+
+static int nft_synproxy_validate(const struct nft_ctx *ctx,
+				 const struct nft_expr *expr,
+				 const struct nft_data **data)
+{
+	return nft_chain_validate_hooks(ctx->chain, (1 << NF_INET_LOCAL_IN) |
+						    (1 << NF_INET_FORWARD));
+}
+
+static struct nft_expr_type nft_synproxy_type;
+static const struct nft_expr_ops nft_synproxy_ops = {
+	.eval		= nft_synproxy_eval,
+	.size		= NFT_EXPR_SIZE(sizeof(struct nft_synproxy)),
+	.init		= nft_synproxy_init,
+	.destroy	= nft_synproxy_destroy,
+	.dump		= nft_synproxy_dump,
+	.type		= &nft_synproxy_type,
+	.validate	= nft_synproxy_validate,
+};
+
+static struct nft_expr_type nft_synproxy_type __read_mostly = {
+	.ops		= &nft_synproxy_ops,
+	.name		= "synproxy",
+	.owner		= THIS_MODULE,
+	.policy		= nft_synproxy_policy,
+	.maxattr	= NFTA_OSF_MAX,
+};
+
+static int __init nft_synproxy_module_init(void)
+{
+	return nft_register_expr(&nft_synproxy_type);
+}
+
+static void __exit nft_synproxy_module_exit(void)
+{
+	return nft_unregister_expr(&nft_synproxy_type);
+}
+
+module_init(nft_synproxy_module_init);
+module_exit(nft_synproxy_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Fernando Fernandez <ffmancera@riseup.net>");
+MODULE_ALIAS_NFT_EXPR("synproxy");
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH nft WIP] src: introduce SYNPROXY matching
  2019-06-17 10:32 [PATCH libnftnl WIP] expr: add synproxy support Fernando Fernandez Mancera
  2019-06-17 10:32 ` [PATCH nf-next WIP] netfilter: nf_tables: Add SYNPROXY support Fernando Fernandez Mancera
@ 2019-06-17 10:32 ` Fernando Fernandez Mancera
  2019-06-17 10:41   ` Fernando Fernandez Mancera
  1 sibling, 1 reply; 9+ messages in thread
From: Fernando Fernandez Mancera @ 2019-06-17 10:32 UTC (permalink / raw)
  To: netfilter-devel; +Cc: Fernando Fernandez Mancera

Signed-off-by: Fernando Fernandez Mancera <ffmancera@riseup.net>
---
 include/linux/netfilter/nf_SYNPROXY.h | 23 ++++++++++++
 include/linux/netfilter/nf_tables.h   | 16 +++++++++
 include/statement.h                   | 11 ++++++
 src/evaluate.c                        | 16 +++++++++
 src/netlink_delinearize.c             | 17 +++++++++
 src/netlink_linearize.c               | 17 +++++++++
 src/parser_bison.y                    | 48 +++++++++++++++++++++++++
 src/scanner.l                         |  6 ++++
 src/statement.c                       | 50 +++++++++++++++++++++++++++
 9 files changed, 204 insertions(+)
 create mode 100644 include/linux/netfilter/nf_SYNPROXY.h

diff --git a/include/linux/netfilter/nf_SYNPROXY.h b/include/linux/netfilter/nf_SYNPROXY.h
new file mode 100644
index 0000000..0e7c391
--- /dev/null
+++ b/include/linux/netfilter/nf_SYNPROXY.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _NF_SYNPROXY_H
+#define _NF_SYNPROXY_H
+
+#include <linux/types.h>
+
+#define NF_SYNPROXY_OPT_MSS		0x01
+#define NF_SYNPROXY_OPT_WSCALE		0x02
+#define NF_SYNPROXY_OPT_SACK_PERM	0x04
+#define NF_SYNPROXY_OPT_TIMESTAMP	0x08
+#define NF_SYNPROXY_OPT_ECN		0x10
+#define NF_SYNPROXY_FLAGMASK		(NF_SYNPROXY_OPT_MSS | \
+					 NF_SYNPROXY_OPT_WSCALE | \
+					 NF_SYNPROXY_OPT_SACK_PERM | \
+					 NF_SYNPROXY_OPT_TIMESTAMP)
+
+struct nf_synproxy_info {
+	__u8	options;
+	__u8	wscale;
+	__u16	mss;
+};
+
+#endif /* _NF_SYNPROXY_H */
diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index 7bdb234..d9ccf3f 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -1529,6 +1529,22 @@ enum nft_osf_attributes {
 };
 #define NFTA_OSF_MAX (__NFTA_OSF_MAX - 1)
 
+/**
+ * enum nft_synproxy_attributes - nftables synproxy expression
+ * netlink attributes
+ *
+ * @NFTA_SYNPROXY_MSS: mss value sent to the backend (NLA_U16)
+ * @NFTA_SYNPROXY_WSCALE: wscale value sent to the backend (NLA_U8)
+ * @NFTA_SYNPROXY_FLAGS: flags (NLA_U32)
+ */
+enum nft_synproxy_attributes {
+	NFTA_SYNPROXY_MSS,
+	NFTA_SYNPROXY_WSCALE,
+	NFTA_SYNPROXY_FLAGS,
+	__NFTA_SYNPROXY_MAX,
+};
+#define NFTA_SYNPROXY_MAX (__NFTA_SYNPROXY_MAX - 1)
+
 /**
  * enum nft_device_attributes - nf_tables device netlink attributes
  *
diff --git a/include/statement.h b/include/statement.h
index 91d6e0e..f789ced 100644
--- a/include/statement.h
+++ b/include/statement.h
@@ -203,6 +203,14 @@ struct map_stmt {
 
 extern struct stmt *map_stmt_alloc(const struct location *loc);
 
+struct synproxy_stmt {
+	uint16_t	mss;
+	uint8_t		wscale;
+	uint32_t	flags;
+};
+
+extern struct stmt *synproxy_stmt_alloc(const struct location *loc);
+
 struct meter_stmt {
 	struct expr		*set;
 	struct expr		*key;
@@ -270,6 +278,7 @@ extern struct stmt *xt_stmt_alloc(const struct location *loc);
  * @STMT_FLOW_OFFLOAD:	flow offload statement
  * @STMT_CONNLIMIT:	connection limit statement
  * @STMT_MAP:		map statement
+ * @STMT_SYNPROXY:	synproxy statement
  */
 enum stmt_types {
 	STMT_INVALID,
@@ -297,6 +306,7 @@ enum stmt_types {
 	STMT_FLOW_OFFLOAD,
 	STMT_CONNLIMIT,
 	STMT_MAP,
+	STMT_SYNPROXY,
 };
 
 /**
@@ -361,6 +371,7 @@ struct stmt {
 		struct objref_stmt	objref;
 		struct flow_stmt	flow;
 		struct map_stmt		map;
+		struct synproxy_stmt	synproxy;
 	};
 };
 
diff --git a/src/evaluate.c b/src/evaluate.c
index 39101b4..04692b8 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -17,6 +17,7 @@
 #include <linux/netfilter.h>
 #include <linux/netfilter_arp.h>
 #include <linux/netfilter/nf_tables.h>
+#include <linux/netfilter/nf_SYNPROXY.h>
 #include <linux/netfilter_ipv4.h>
 #include <netinet/ip_icmp.h>
 #include <netinet/icmp6.h>
@@ -2704,6 +2705,19 @@ static int stmt_evaluate_tproxy(struct eval_ctx *ctx, struct stmt *stmt)
 	return 0;
 }
 
+static int stmt_evaluate_synproxy(struct eval_ctx *ctx, struct stmt *stmt)
+{
+	printf("Values of the synproxy expr: %u %u\n", stmt->synproxy.mss, stmt->synproxy.wscale);
+	if (stmt->synproxy.flags != 0 &&
+	    !(stmt->synproxy.flags & (NF_SYNPROXY_OPT_MSS |
+				      NF_SYNPROXY_OPT_WSCALE |
+				      NF_SYNPROXY_OPT_TIMESTAMP |
+				      NF_SYNPROXY_OPT_SACK_PERM)))
+		return stmt_error(ctx, stmt, "This flags are not supported for SYNPROXY");
+
+	return 0;
+}
+
 static int stmt_evaluate_dup(struct eval_ctx *ctx, struct stmt *stmt)
 {
 	int err;
@@ -3048,6 +3062,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_SYNPROXY:
+		return stmt_evaluate_synproxy(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 0270e1f..2785325 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -1010,6 +1010,22 @@ out_err:
 	xfree(stmt);
 }
 
+static void netlink_parse_synproxy(struct netlink_parse_ctx *ctx,
+				   const struct location *loc,
+				   const struct nftnl_expr *nle)
+{
+	struct stmt *stmt;
+
+	stmt = synproxy_stmt_alloc(loc);
+	stmt->synproxy.mss = nftnl_expr_get_u16(nle, NFTNL_EXPR_SYNPROXY_MSS);
+	stmt->synproxy.wscale = nftnl_expr_get_u8(nle,
+						  NFTNL_EXPR_SYNPROXY_WSCALE);
+	stmt->synproxy.flags = nftnl_expr_get_u32(nle,
+						  NFTNL_EXPR_SYNPROXY_FLAGS);
+
+	ctx->stmt = stmt;
+}
+
 static void netlink_parse_tproxy(struct netlink_parse_ctx *ctx,
 			      const struct location *loc,
 			      const struct nftnl_expr *nle)
@@ -1476,6 +1492,7 @@ static const struct {
 	{ .name = "tcpopt",	.parse = netlink_parse_exthdr },
 	{ .name = "flow_offload", .parse = netlink_parse_flow_offload },
 	{ .name = "xfrm",	.parse = netlink_parse_xfrm },
+	{ .name = "synproxy",	.parse = netlink_parse_synproxy },
 };
 
 static int netlink_parse_expr(const struct nftnl_expr *nle,
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
index 2c6aa64..498326d 100644
--- a/src/netlink_linearize.c
+++ b/src/netlink_linearize.c
@@ -1141,6 +1141,21 @@ static void netlink_gen_tproxy_stmt(struct netlink_linearize_ctx *ctx,
 	nftnl_rule_add_expr(ctx->nlr, nle);
 }
 
+static void netlink_gen_synproxy_stmt(struct netlink_linearize_ctx *ctx,
+				      const struct stmt *stmt)
+{
+	struct nftnl_expr *nle;
+
+	nle = alloc_nft_expr("synproxy");
+	nftnl_expr_set_u16(nle, NFTNL_EXPR_SYNPROXY_MSS, stmt->synproxy.mss);
+	nftnl_expr_set_u8(nle, NFTNL_EXPR_SYNPROXY_WSCALE,
+			  stmt->synproxy.wscale);
+	nftnl_expr_set_u32(nle, NFTNL_EXPR_SYNPROXY_FLAGS,
+			   stmt->synproxy.flags);
+
+	nftnl_rule_add_expr(ctx->nlr, nle);
+}
+
 static void netlink_gen_dup_stmt(struct netlink_linearize_ctx *ctx,
 				 const struct stmt *stmt)
 {
@@ -1382,6 +1397,8 @@ static void netlink_gen_stmt(struct netlink_linearize_ctx *ctx,
 		return netlink_gen_nat_stmt(ctx, stmt);
 	case STMT_TPROXY:
 		return netlink_gen_tproxy_stmt(ctx, stmt);
+	case STMT_SYNPROXY:
+		return netlink_gen_synproxy_stmt(ctx, stmt);
 	case STMT_DUP:
 		return netlink_gen_dup_stmt(ctx, stmt);
 	case STMT_QUEUE:
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 97a48f3..61e0888 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -23,6 +23,7 @@
 #include <linux/netfilter/nf_nat.h>
 #include <linux/netfilter/nf_log.h>
 #include <linux/netfilter/nfnetlink_osf.h>
+#include <linux/netfilter/nf_SYNPROXY.h>
 #include <linux/xfrm.h>
 #include <netinet/ip_icmp.h>
 #include <netinet/icmp6.h>
@@ -200,6 +201,12 @@ int nft_lex(void *, void *, void *);
 
 %token OSF			"osf"
 
+%token SYNPROXY			"synproxy"
+%token MSS			"mss"
+%token WSCALE			"wscale"
+%token TIMESTAMP		"timestamp"
+%token SACKPERM			"sack-perm"
+
 %token HOOK			"hook"
 %token DEVICE			"device"
 %token DEVICES			"devices"
@@ -601,6 +608,9 @@ int nft_lex(void *, void *, void *);
 %type <val>			nf_nat_flags nf_nat_flag offset_opt
 %type <stmt>			tproxy_stmt
 %destructor { stmt_free($$); }	tproxy_stmt
+%type <stmt>			synproxy_stmt synproxy_stmt_alloc
+%destructor { stmt_free($$); }	synproxy_stmt synproxy_stmt_alloc
+
 
 %type <stmt>			queue_stmt queue_stmt_alloc
 %destructor { stmt_free($$); }	queue_stmt queue_stmt_alloc
@@ -2245,6 +2255,7 @@ stmt			:	verdict_stmt
 			|	fwd_stmt
 			|	set_stmt
 			|	map_stmt
+			|	synproxy_stmt
 			;
 
 verdict_stmt		:	verdict_expr
@@ -2675,6 +2686,43 @@ tproxy_stmt		:	TPROXY TO stmt_expr
 			}
 			;
 
+synproxy_stmt		:	synproxy_stmt_alloc
+			|	synproxy_stmt_alloc	synproxy_args
+			;
+
+synproxy_stmt_alloc	:	SYNPROXY
+			{
+				$$ = synproxy_stmt_alloc(&@$);
+			}
+			;
+
+synproxy_args		:	synproxy_arg
+			{
+				$<stmt>$	= $<stmt>0;
+			}
+			|	synproxy_args	synproxy_arg
+			;
+
+synproxy_arg		:	MSS	NUM
+			{
+				$<stmt>0->synproxy.mss = $2;
+				$<stmt>0->synproxy.flags |= NF_SYNPROXY_OPT_MSS;
+			}
+			|	WSCALE	NUM
+			{
+				$<stmt>0->synproxy.wscale = $2;
+				$<stmt>0->synproxy.flags |= NF_SYNPROXY_OPT_WSCALE;
+			}
+			|	TIMESTAMP
+			{
+				$<stmt>0->synproxy.flags |= NF_SYNPROXY_OPT_TIMESTAMP;
+			}
+			|	SACKPERM
+			{
+				$<stmt>0->synproxy.flags |= NF_SYNPROXY_OPT_SACK_PERM;
+			}
+			;
+
 primary_stmt_expr	:	symbol_expr		{ $$ = $1; }
 			|	integer_expr		{ $$ = $1; }
 			|	boolean_expr		{ $$ = $1; }
diff --git a/src/scanner.l b/src/scanner.l
index d1f6e87..e990cc6 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -543,6 +543,12 @@ addrstring	({macaddr}|{ip4addr}|{ip6addr})
 
 "osf"			{ return OSF; }
 
+"synproxy"		{ return SYNPROXY; }
+"mss"			{ return MSS; }
+"wscale"		{ return WSCALE; }
+"timestamp"		{ return TIMESTAMP; }
+"sack-perm"		{ return SACKPERM; }
+
 "notrack"		{ return NOTRACK; }
 
 "options"		{ return OPTIONS; }
diff --git a/src/statement.c b/src/statement.c
index a9e8b3a..3489e3e 100644
--- a/src/statement.c
+++ b/src/statement.c
@@ -29,6 +29,7 @@
 #include <netinet/in.h>
 #include <linux/netfilter/nf_nat.h>
 #include <linux/netfilter/nf_log.h>
+#include <linux/netfilter/nf_SYNPROXY.h>
 
 struct stmt *stmt_alloc(const struct location *loc,
 			const struct stmt_ops *ops)
@@ -877,3 +878,52 @@ struct stmt *xt_stmt_alloc(const struct location *loc)
 {
 	return stmt_alloc(loc, &xt_stmt_ops);
 }
+
+static const char *synproxy_sack_to_str(const uint32_t flags)
+{
+	if (flags & NF_SYNPROXY_OPT_SACK_PERM)
+		return " sack-perm";
+
+	return "";
+}
+
+static const char *synproxy_timestamp_to_str(const uint32_t flags)
+{
+	if (flags & NF_SYNPROXY_OPT_TIMESTAMP)
+		return " timestamp";
+
+	return "";
+}
+
+static void synproxy_stmt_print(const struct stmt *stmt,
+				struct output_ctx *octx)
+{
+	uint32_t flags = stmt->synproxy.flags;
+	const char *ts_str = synproxy_timestamp_to_str(flags);
+	const char *sack_str = synproxy_sack_to_str(flags);
+
+	if (flags & (NF_SYNPROXY_OPT_MSS | NF_SYNPROXY_OPT_WSCALE))
+		nft_print(octx, "synproxy mss %u wscale %u%s%s",
+			  stmt->synproxy.mss, stmt->synproxy.wscale,
+			  ts_str, sack_str);
+	else if (flags & NF_SYNPROXY_OPT_MSS)
+		nft_print(octx, "synproxy mss %u%s%s", stmt->synproxy.mss,
+			  ts_str, sack_str);
+	else if (flags & NF_SYNPROXY_OPT_WSCALE)
+		nft_print(octx, "synproxy wscale %u%s%s", stmt->synproxy.wscale,
+			  ts_str, sack_str);
+	else
+		nft_print(octx, "synproxy%s%s", ts_str, sack_str);
+
+}
+
+static const struct stmt_ops synproxy_stmt_ops = {
+	.type		= STMT_SYNPROXY,
+	.name		= "synproxy",
+	.print		= synproxy_stmt_print,
+};
+
+struct stmt *synproxy_stmt_alloc(const struct location *loc)
+{
+	return stmt_alloc(loc, &synproxy_stmt_ops);
+}
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH nft WIP] src: introduce SYNPROXY matching
  2019-06-17 10:32 ` [PATCH nft WIP] src: introduce SYNPROXY matching Fernando Fernandez Mancera
@ 2019-06-17 10:41   ` Fernando Fernandez Mancera
  0 siblings, 0 replies; 9+ messages in thread
From: Fernando Fernandez Mancera @ 2019-06-17 10:41 UTC (permalink / raw)
  To: netfilter-devel; +Cc: Pablo Neira Ayuso, Florian Westphal

Hi,

I have been working on the synproxy expression. In my opinion, there is
no way to use sets or maps with synproxy so I think it should be a
statement.

This patch is almost finished, but I have been dealing with the
following error.

# nft add table ip foo
# nft add chain ip foo bar
# nft add rule ip foo bar synproxy mss 1460 wscale 7

> Error: Could not process rule: Numerical result out of range
> add rule ip foo bar synproxy mss 10 wscale 2
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

I have tried to debug it using libnftables directly. And I still getting
the same error. The problem should be in the libnftnl or nf-next patch.
I am probably missing something. Any suggestion? Thanks :-)

On 6/17/19 12:32 PM, Fernando Fernandez Mancera wrote:
> Signed-off-by: Fernando Fernandez Mancera <ffmancera@riseup.net>
> ---
>  include/linux/netfilter/nf_SYNPROXY.h | 23 ++++++++++++
>  include/linux/netfilter/nf_tables.h   | 16 +++++++++
>  include/statement.h                   | 11 ++++++
>  src/evaluate.c                        | 16 +++++++++
>  src/netlink_delinearize.c             | 17 +++++++++
>  src/netlink_linearize.c               | 17 +++++++++
>  src/parser_bison.y                    | 48 +++++++++++++++++++++++++
>  src/scanner.l                         |  6 ++++
>  src/statement.c                       | 50 +++++++++++++++++++++++++++
>  9 files changed, 204 insertions(+)
>  create mode 100644 include/linux/netfilter/nf_SYNPROXY.h
> 
> diff --git a/include/linux/netfilter/nf_SYNPROXY.h b/include/linux/netfilter/nf_SYNPROXY.h
> new file mode 100644
> index 0000000..0e7c391
> --- /dev/null
> +++ b/include/linux/netfilter/nf_SYNPROXY.h
> @@ -0,0 +1,23 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef _NF_SYNPROXY_H
> +#define _NF_SYNPROXY_H
> +
> +#include <linux/types.h>
> +
> +#define NF_SYNPROXY_OPT_MSS		0x01
> +#define NF_SYNPROXY_OPT_WSCALE		0x02
> +#define NF_SYNPROXY_OPT_SACK_PERM	0x04
> +#define NF_SYNPROXY_OPT_TIMESTAMP	0x08
> +#define NF_SYNPROXY_OPT_ECN		0x10
> +#define NF_SYNPROXY_FLAGMASK		(NF_SYNPROXY_OPT_MSS | \
> +					 NF_SYNPROXY_OPT_WSCALE | \
> +					 NF_SYNPROXY_OPT_SACK_PERM | \
> +					 NF_SYNPROXY_OPT_TIMESTAMP)
> +
> +struct nf_synproxy_info {
> +	__u8	options;
> +	__u8	wscale;
> +	__u16	mss;
> +};
> +
> +#endif /* _NF_SYNPROXY_H */
> diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
> index 7bdb234..d9ccf3f 100644
> --- a/include/linux/netfilter/nf_tables.h
> +++ b/include/linux/netfilter/nf_tables.h
> @@ -1529,6 +1529,22 @@ enum nft_osf_attributes {
>  };
>  #define NFTA_OSF_MAX (__NFTA_OSF_MAX - 1)
>  
> +/**
> + * enum nft_synproxy_attributes - nftables synproxy expression
> + * netlink attributes
> + *
> + * @NFTA_SYNPROXY_MSS: mss value sent to the backend (NLA_U16)
> + * @NFTA_SYNPROXY_WSCALE: wscale value sent to the backend (NLA_U8)
> + * @NFTA_SYNPROXY_FLAGS: flags (NLA_U32)
> + */
> +enum nft_synproxy_attributes {
> +	NFTA_SYNPROXY_MSS,
> +	NFTA_SYNPROXY_WSCALE,
> +	NFTA_SYNPROXY_FLAGS,
> +	__NFTA_SYNPROXY_MAX,
> +};
> +#define NFTA_SYNPROXY_MAX (__NFTA_SYNPROXY_MAX - 1)
> +
>  /**
>   * enum nft_device_attributes - nf_tables device netlink attributes
>   *
> diff --git a/include/statement.h b/include/statement.h
> index 91d6e0e..f789ced 100644
> --- a/include/statement.h
> +++ b/include/statement.h
> @@ -203,6 +203,14 @@ struct map_stmt {
>  
>  extern struct stmt *map_stmt_alloc(const struct location *loc);
>  
> +struct synproxy_stmt {
> +	uint16_t	mss;
> +	uint8_t		wscale;
> +	uint32_t	flags;
> +};
> +
> +extern struct stmt *synproxy_stmt_alloc(const struct location *loc);
> +
>  struct meter_stmt {
>  	struct expr		*set;
>  	struct expr		*key;
> @@ -270,6 +278,7 @@ extern struct stmt *xt_stmt_alloc(const struct location *loc);
>   * @STMT_FLOW_OFFLOAD:	flow offload statement
>   * @STMT_CONNLIMIT:	connection limit statement
>   * @STMT_MAP:		map statement
> + * @STMT_SYNPROXY:	synproxy statement
>   */
>  enum stmt_types {
>  	STMT_INVALID,
> @@ -297,6 +306,7 @@ enum stmt_types {
>  	STMT_FLOW_OFFLOAD,
>  	STMT_CONNLIMIT,
>  	STMT_MAP,
> +	STMT_SYNPROXY,
>  };
>  
>  /**
> @@ -361,6 +371,7 @@ struct stmt {
>  		struct objref_stmt	objref;
>  		struct flow_stmt	flow;
>  		struct map_stmt		map;
> +		struct synproxy_stmt	synproxy;
>  	};
>  };
>  
> diff --git a/src/evaluate.c b/src/evaluate.c
> index 39101b4..04692b8 100644
> --- a/src/evaluate.c
> +++ b/src/evaluate.c
> @@ -17,6 +17,7 @@
>  #include <linux/netfilter.h>
>  #include <linux/netfilter_arp.h>
>  #include <linux/netfilter/nf_tables.h>
> +#include <linux/netfilter/nf_SYNPROXY.h>
>  #include <linux/netfilter_ipv4.h>
>  #include <netinet/ip_icmp.h>
>  #include <netinet/icmp6.h>
> @@ -2704,6 +2705,19 @@ static int stmt_evaluate_tproxy(struct eval_ctx *ctx, struct stmt *stmt)
>  	return 0;
>  }
>  
> +static int stmt_evaluate_synproxy(struct eval_ctx *ctx, struct stmt *stmt)
> +{
> +	printf("Values of the synproxy expr: %u %u\n", stmt->synproxy.mss, stmt->synproxy.wscale);
> +	if (stmt->synproxy.flags != 0 &&
> +	    !(stmt->synproxy.flags & (NF_SYNPROXY_OPT_MSS |
> +				      NF_SYNPROXY_OPT_WSCALE |
> +				      NF_SYNPROXY_OPT_TIMESTAMP |
> +				      NF_SYNPROXY_OPT_SACK_PERM)))
> +		return stmt_error(ctx, stmt, "This flags are not supported for SYNPROXY");
> +
> +	return 0;
> +}
> +
>  static int stmt_evaluate_dup(struct eval_ctx *ctx, struct stmt *stmt)
>  {
>  	int err;
> @@ -3048,6 +3062,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_SYNPROXY:
> +		return stmt_evaluate_synproxy(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 0270e1f..2785325 100644
> --- a/src/netlink_delinearize.c
> +++ b/src/netlink_delinearize.c
> @@ -1010,6 +1010,22 @@ out_err:
>  	xfree(stmt);
>  }
>  
> +static void netlink_parse_synproxy(struct netlink_parse_ctx *ctx,
> +				   const struct location *loc,
> +				   const struct nftnl_expr *nle)
> +{
> +	struct stmt *stmt;
> +
> +	stmt = synproxy_stmt_alloc(loc);
> +	stmt->synproxy.mss = nftnl_expr_get_u16(nle, NFTNL_EXPR_SYNPROXY_MSS);
> +	stmt->synproxy.wscale = nftnl_expr_get_u8(nle,
> +						  NFTNL_EXPR_SYNPROXY_WSCALE);
> +	stmt->synproxy.flags = nftnl_expr_get_u32(nle,
> +						  NFTNL_EXPR_SYNPROXY_FLAGS);
> +
> +	ctx->stmt = stmt;
> +}
> +
>  static void netlink_parse_tproxy(struct netlink_parse_ctx *ctx,
>  			      const struct location *loc,
>  			      const struct nftnl_expr *nle)
> @@ -1476,6 +1492,7 @@ static const struct {
>  	{ .name = "tcpopt",	.parse = netlink_parse_exthdr },
>  	{ .name = "flow_offload", .parse = netlink_parse_flow_offload },
>  	{ .name = "xfrm",	.parse = netlink_parse_xfrm },
> +	{ .name = "synproxy",	.parse = netlink_parse_synproxy },
>  };
>  
>  static int netlink_parse_expr(const struct nftnl_expr *nle,
> diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
> index 2c6aa64..498326d 100644
> --- a/src/netlink_linearize.c
> +++ b/src/netlink_linearize.c
> @@ -1141,6 +1141,21 @@ static void netlink_gen_tproxy_stmt(struct netlink_linearize_ctx *ctx,
>  	nftnl_rule_add_expr(ctx->nlr, nle);
>  }
>  
> +static void netlink_gen_synproxy_stmt(struct netlink_linearize_ctx *ctx,
> +				      const struct stmt *stmt)
> +{
> +	struct nftnl_expr *nle;
> +
> +	nle = alloc_nft_expr("synproxy");
> +	nftnl_expr_set_u16(nle, NFTNL_EXPR_SYNPROXY_MSS, stmt->synproxy.mss);
> +	nftnl_expr_set_u8(nle, NFTNL_EXPR_SYNPROXY_WSCALE,
> +			  stmt->synproxy.wscale);
> +	nftnl_expr_set_u32(nle, NFTNL_EXPR_SYNPROXY_FLAGS,
> +			   stmt->synproxy.flags);
> +
> +	nftnl_rule_add_expr(ctx->nlr, nle);
> +}
> +
>  static void netlink_gen_dup_stmt(struct netlink_linearize_ctx *ctx,
>  				 const struct stmt *stmt)
>  {
> @@ -1382,6 +1397,8 @@ static void netlink_gen_stmt(struct netlink_linearize_ctx *ctx,
>  		return netlink_gen_nat_stmt(ctx, stmt);
>  	case STMT_TPROXY:
>  		return netlink_gen_tproxy_stmt(ctx, stmt);
> +	case STMT_SYNPROXY:
> +		return netlink_gen_synproxy_stmt(ctx, stmt);
>  	case STMT_DUP:
>  		return netlink_gen_dup_stmt(ctx, stmt);
>  	case STMT_QUEUE:
> diff --git a/src/parser_bison.y b/src/parser_bison.y
> index 97a48f3..61e0888 100644
> --- a/src/parser_bison.y
> +++ b/src/parser_bison.y
> @@ -23,6 +23,7 @@
>  #include <linux/netfilter/nf_nat.h>
>  #include <linux/netfilter/nf_log.h>
>  #include <linux/netfilter/nfnetlink_osf.h>
> +#include <linux/netfilter/nf_SYNPROXY.h>
>  #include <linux/xfrm.h>
>  #include <netinet/ip_icmp.h>
>  #include <netinet/icmp6.h>
> @@ -200,6 +201,12 @@ int nft_lex(void *, void *, void *);
>  
>  %token OSF			"osf"
>  
> +%token SYNPROXY			"synproxy"
> +%token MSS			"mss"
> +%token WSCALE			"wscale"
> +%token TIMESTAMP		"timestamp"
> +%token SACKPERM			"sack-perm"
> +
>  %token HOOK			"hook"
>  %token DEVICE			"device"
>  %token DEVICES			"devices"
> @@ -601,6 +608,9 @@ int nft_lex(void *, void *, void *);
>  %type <val>			nf_nat_flags nf_nat_flag offset_opt
>  %type <stmt>			tproxy_stmt
>  %destructor { stmt_free($$); }	tproxy_stmt
> +%type <stmt>			synproxy_stmt synproxy_stmt_alloc
> +%destructor { stmt_free($$); }	synproxy_stmt synproxy_stmt_alloc
> +
>  
>  %type <stmt>			queue_stmt queue_stmt_alloc
>  %destructor { stmt_free($$); }	queue_stmt queue_stmt_alloc
> @@ -2245,6 +2255,7 @@ stmt			:	verdict_stmt
>  			|	fwd_stmt
>  			|	set_stmt
>  			|	map_stmt
> +			|	synproxy_stmt
>  			;
>  
>  verdict_stmt		:	verdict_expr
> @@ -2675,6 +2686,43 @@ tproxy_stmt		:	TPROXY TO stmt_expr
>  			}
>  			;
>  
> +synproxy_stmt		:	synproxy_stmt_alloc
> +			|	synproxy_stmt_alloc	synproxy_args
> +			;
> +
> +synproxy_stmt_alloc	:	SYNPROXY
> +			{
> +				$$ = synproxy_stmt_alloc(&@$);
> +			}
> +			;
> +
> +synproxy_args		:	synproxy_arg
> +			{
> +				$<stmt>$	= $<stmt>0;
> +			}
> +			|	synproxy_args	synproxy_arg
> +			;
> +
> +synproxy_arg		:	MSS	NUM
> +			{
> +				$<stmt>0->synproxy.mss = $2;
> +				$<stmt>0->synproxy.flags |= NF_SYNPROXY_OPT_MSS;
> +			}
> +			|	WSCALE	NUM
> +			{
> +				$<stmt>0->synproxy.wscale = $2;
> +				$<stmt>0->synproxy.flags |= NF_SYNPROXY_OPT_WSCALE;
> +			}
> +			|	TIMESTAMP
> +			{
> +				$<stmt>0->synproxy.flags |= NF_SYNPROXY_OPT_TIMESTAMP;
> +			}
> +			|	SACKPERM
> +			{
> +				$<stmt>0->synproxy.flags |= NF_SYNPROXY_OPT_SACK_PERM;
> +			}
> +			;
> +
>  primary_stmt_expr	:	symbol_expr		{ $$ = $1; }
>  			|	integer_expr		{ $$ = $1; }
>  			|	boolean_expr		{ $$ = $1; }
> diff --git a/src/scanner.l b/src/scanner.l
> index d1f6e87..e990cc6 100644
> --- a/src/scanner.l
> +++ b/src/scanner.l
> @@ -543,6 +543,12 @@ addrstring	({macaddr}|{ip4addr}|{ip6addr})
>  
>  "osf"			{ return OSF; }
>  
> +"synproxy"		{ return SYNPROXY; }
> +"mss"			{ return MSS; }
> +"wscale"		{ return WSCALE; }
> +"timestamp"		{ return TIMESTAMP; }
> +"sack-perm"		{ return SACKPERM; }
> +
>  "notrack"		{ return NOTRACK; }
>  
>  "options"		{ return OPTIONS; }
> diff --git a/src/statement.c b/src/statement.c
> index a9e8b3a..3489e3e 100644
> --- a/src/statement.c
> +++ b/src/statement.c
> @@ -29,6 +29,7 @@
>  #include <netinet/in.h>
>  #include <linux/netfilter/nf_nat.h>
>  #include <linux/netfilter/nf_log.h>
> +#include <linux/netfilter/nf_SYNPROXY.h>
>  
>  struct stmt *stmt_alloc(const struct location *loc,
>  			const struct stmt_ops *ops)
> @@ -877,3 +878,52 @@ struct stmt *xt_stmt_alloc(const struct location *loc)
>  {
>  	return stmt_alloc(loc, &xt_stmt_ops);
>  }
> +
> +static const char *synproxy_sack_to_str(const uint32_t flags)
> +{
> +	if (flags & NF_SYNPROXY_OPT_SACK_PERM)
> +		return " sack-perm";
> +
> +	return "";
> +}
> +
> +static const char *synproxy_timestamp_to_str(const uint32_t flags)
> +{
> +	if (flags & NF_SYNPROXY_OPT_TIMESTAMP)
> +		return " timestamp";
> +
> +	return "";
> +}
> +
> +static void synproxy_stmt_print(const struct stmt *stmt,
> +				struct output_ctx *octx)
> +{
> +	uint32_t flags = stmt->synproxy.flags;
> +	const char *ts_str = synproxy_timestamp_to_str(flags);
> +	const char *sack_str = synproxy_sack_to_str(flags);
> +
> +	if (flags & (NF_SYNPROXY_OPT_MSS | NF_SYNPROXY_OPT_WSCALE))
> +		nft_print(octx, "synproxy mss %u wscale %u%s%s",
> +			  stmt->synproxy.mss, stmt->synproxy.wscale,
> +			  ts_str, sack_str);
> +	else if (flags & NF_SYNPROXY_OPT_MSS)
> +		nft_print(octx, "synproxy mss %u%s%s", stmt->synproxy.mss,
> +			  ts_str, sack_str);
> +	else if (flags & NF_SYNPROXY_OPT_WSCALE)
> +		nft_print(octx, "synproxy wscale %u%s%s", stmt->synproxy.wscale,
> +			  ts_str, sack_str);
> +	else
> +		nft_print(octx, "synproxy%s%s", ts_str, sack_str);
> +
> +}
> +
> +static const struct stmt_ops synproxy_stmt_ops = {
> +	.type		= STMT_SYNPROXY,
> +	.name		= "synproxy",
> +	.print		= synproxy_stmt_print,
> +};
> +
> +struct stmt *synproxy_stmt_alloc(const struct location *loc)
> +{
> +	return stmt_alloc(loc, &synproxy_stmt_ops);
> +}
> 

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH nf-next WIP] netfilter: nf_tables: Add SYNPROXY support
  2019-06-17 10:32 ` [PATCH nf-next WIP] netfilter: nf_tables: Add SYNPROXY support Fernando Fernandez Mancera
@ 2019-06-17 15:25   ` Pablo Neira Ayuso
  2019-06-17 15:45   ` Pablo Neira Ayuso
  1 sibling, 0 replies; 9+ messages in thread
From: Pablo Neira Ayuso @ 2019-06-17 15:25 UTC (permalink / raw)
  To: Fernando Fernandez Mancera; +Cc: netfilter-devel

On Mon, Jun 17, 2019 at 12:32:35PM +0200, Fernando Fernandez Mancera wrote:
> diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
> index 505393c6e959..f225f237f98a 100644
> --- a/include/uapi/linux/netfilter/nf_tables.h
> +++ b/include/uapi/linux/netfilter/nf_tables.h
> @@ -1537,6 +1537,22 @@ enum nft_osf_flags {
>  	NFT_OSF_F_VERSION = (1 << 0),
>  };
>  
> +/**
> + * enum nft_synproxy_attributes - nf_tables synproxy expression
> + * netlink attributes
> + *
> + * @NFTA_SYNPROXY_MSS: mss value sent to the backend (NLA_U16)
> + * @NFTA_SYNPROXY_WSCALE: wscale value sent to the backend (NLA_U8)
> + * @NFTA_SYNPROXY_FLAGS: flags (NLA_U32)
> + */
> +enum nft_synproxy_attributes {

        NFTA_SYNPROXY_UNSPEC,

is missing.

> +	NFTA_SYNPROXY_MSS,
> +	NFTA_SYNPROXY_WSCALE,
> +	NFTA_SYNPROXY_FLAGS,
> +	__NFTA_SYNPROXY_MAX,
> +};
> +#define NFTA_SYNPROXY_MAX (__NFTA_SYNPROXY_MAX - 1)
> +
>  /**
>   * enum nft_device_attributes - nf_tables device netlink attributes
>   *

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH nf-next WIP] netfilter: nf_tables: Add SYNPROXY support
  2019-06-17 10:32 ` [PATCH nf-next WIP] netfilter: nf_tables: Add SYNPROXY support Fernando Fernandez Mancera
  2019-06-17 15:25   ` Pablo Neira Ayuso
@ 2019-06-17 15:45   ` Pablo Neira Ayuso
  2019-06-17 19:49     ` Fernando Fernandez Mancera
  1 sibling, 1 reply; 9+ messages in thread
From: Pablo Neira Ayuso @ 2019-06-17 15:45 UTC (permalink / raw)
  To: Fernando Fernandez Mancera; +Cc: netfilter-devel

On Mon, Jun 17, 2019 at 12:32:35PM +0200, Fernando Fernandez Mancera wrote:
> Add SYNPROXY module support in nf_tables. It preserves the behaviour of the
> SYNPROXY target of iptables but structured in a different way to propose
> improvements in the future.
> 
> Signed-off-by: Fernando Fernandez Mancera <ffmancera@riseup.net>
> ---
>  include/uapi/linux/netfilter/nf_SYNPROXY.h |   4 +
>  include/uapi/linux/netfilter/nf_tables.h   |  16 +
>  net/netfilter/Kconfig                      |  11 +
>  net/netfilter/Makefile                     |   1 +
>  net/netfilter/nft_synproxy.c               | 328 +++++++++++++++++++++
>  5 files changed, 360 insertions(+)
>  create mode 100644 net/netfilter/nft_synproxy.c
> 
> diff --git a/include/uapi/linux/netfilter/nf_SYNPROXY.h b/include/uapi/linux/netfilter/nf_SYNPROXY.h
> index 068d1b3a6f06..0e7c39191819 100644
> --- a/include/uapi/linux/netfilter/nf_SYNPROXY.h
> +++ b/include/uapi/linux/netfilter/nf_SYNPROXY.h
> @@ -9,6 +9,10 @@
>  #define NF_SYNPROXY_OPT_SACK_PERM	0x04
>  #define NF_SYNPROXY_OPT_TIMESTAMP	0x08
>  #define NF_SYNPROXY_OPT_ECN		0x10
> +#define NF_SYNPROXY_FLAGMASK		(NF_SYNPROXY_OPT_MSS | \
> +					 NF_SYNPROXY_OPT_WSCALE | \
> +					 NF_SYNPROXY_OPT_SACK_PERM | \
> +					 NF_SYNPROXY_OPT_TIMESTAMP)

Suggestion:

#define NF_SYNPROXY_OPT_MASK		(...

>  struct nf_synproxy_info {
>  	__u8	options;
[...]
> diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
> index 21025c2c605b..d59742408d9b 100644
> --- a/net/netfilter/Kconfig
> +++ b/net/netfilter/Kconfig
> @@ -651,6 +651,17 @@ config NFT_TPROXY
>  	help
>  	  This makes transparent proxy support available in nftables.
>  
> +config NFT_SYNPROXY
> +	tristate "Netfilter nf_tables SYNPROXY expression support"
> +	depends on NF_CONNTRACK && NETFILTER_ADVANCED
> +	select NETFILTER_SYNPROXY
> +	select SYN_COOKIES
> +	help
> +	  The SYNPROXY expression allows you to intercept TCP connections and
> +	  establish them using syncookies before they are passed on to the
> +	  server. This allows to avoid conntrack and server resource usage
> +	  during SYN-flood attacks.
> +
>  if NF_TABLES_NETDEV
>  
>  config NF_DUP_NETDEV
> diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
> index 72cca6b48960..deada20975ff 100644
> --- a/net/netfilter/Makefile
> +++ b/net/netfilter/Makefile
> @@ -110,6 +110,7 @@ obj-$(CONFIG_NFT_SOCKET)	+= nft_socket.o
>  obj-$(CONFIG_NFT_OSF)		+= nft_osf.o
>  obj-$(CONFIG_NFT_TPROXY)	+= nft_tproxy.o
>  obj-$(CONFIG_NFT_XFRM)		+= nft_xfrm.o
> +obj-$(CONFIG_NFT_SYNPROXY)	+= nft_synproxy.o
>  
>  obj-$(CONFIG_NFT_NAT)		+= nft_chain_nat.o
>  
> diff --git a/net/netfilter/nft_synproxy.c b/net/netfilter/nft_synproxy.c
> new file mode 100644
> index 000000000000..e94e0a1c1722
> --- /dev/null
> +++ b/net/netfilter/nft_synproxy.c
> @@ -0,0 +1,328 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#include <linux/types.h>
> +
> +#include <net/ip.h>
> +#include <net/tcp.h>
> +#include <net/netlink.h>
> +
> +#include <net/netfilter/nf_tables.h>
> +#include <net/netfilter/nf_conntrack.h>
> +#include <net/netfilter/nf_conntrack_ecache.h>
> +#include <net/netfilter/nf_conntrack_extend.h>
> +#include <net/netfilter/nf_conntrack_seqadj.h>
> +#include <net/netfilter/nf_conntrack_synproxy.h>
> +#include <net/netfilter/nf_synproxy.h>
> +
> +#include <linux/netfilter/nf_tables.h>
> +#include <linux/netfilter/nf_SYNPROXY.h>
> +
> +struct nft_synproxy {
> +	u16			mss;
> +	u8			wscale;
> +	u32			flags;
> +};

maybe...

   struct nft_synproxy {
        struct nf_synproxy_info info;
   };

> +static const struct nla_policy nft_synproxy_policy[NFTA_SYNPROXY_MAX + 1] = {
> +	[NFTA_SYNPROXY_MSS]		= { .type = NLA_U16 },
> +	[NFTA_SYNPROXY_WSCALE]		= { .type = NLA_U8 },
> +	[NFTA_SYNPROXY_FLAGS]		= { .type = NLA_U32 },
> +};
> +
> +static struct nf_synproxy_info create_synproxy_info(struct nft_synproxy *expr)

... so you can remove this helper function?

> +{
> +	struct nf_synproxy_info info;
> +
> +	info.options = expr->flags;
> +	info.wscale = expr->wscale;
> +	info.mss = expr->mss;
> +
> +	return info;
> +}
> +
> +static void nft_synproxy_eval_v4(const struct nft_expr *expr,
> +				 struct nft_regs *regs,
> +				 const struct nft_pktinfo *pkt)
> +{
> +	struct nft_synproxy *priv = nft_expr_priv(expr);
> +	struct nf_synproxy_info info = create_synproxy_info(priv);
> +	struct synproxy_options opts = {};
> +	struct net *net = nft_net(pkt);
> +	struct synproxy_net *snet = synproxy_pernet(net);
> +	struct sk_buff *skb = pkt->skb;
> +	int thoff = pkt->xt.thoff;
> +	const struct tcphdr *tcp;
> +	struct tcphdr _tcph;
> +
> +	if (nf_ip_checksum(skb, nft_hook(pkt), thoff, IPPROTO_TCP)) {
> +		regs->verdict.code = NF_DROP;
> +		return;
> +	}
> +
> +	tcp = skb_header_pointer(skb, ip_hdrlen(skb),
> +				 sizeof(struct tcphdr), &_tcph);
> +	if (!tcp) {
> +		regs->verdict.code = NF_DROP;
> +		return;
> +	}
> +	if (!synproxy_parse_options(skb, thoff, tcp, &opts)) {
> +		regs->verdict.code = NF_DROP;
> +		return;
> +	}
> +
> +	if (tcp->syn) {
> +		/* Initial SYN from client */
> +		this_cpu_inc(snet->stats->syn_received);
> +
> +		if (tcp->ece && tcp->cwr)
> +			opts.options |= NF_SYNPROXY_OPT_ECN;
> +
> +		opts.options &= priv->flags;
> +		if (opts.options & NF_SYNPROXY_OPT_TIMESTAMP)
> +			synproxy_init_timestamp_cookie(&info, &opts);
> +		else
> +			opts.options &= ~(NF_SYNPROXY_OPT_WSCALE |
> +					  NF_SYNPROXY_OPT_SACK_PERM |
> +					  NF_SYNPROXY_OPT_ECN);
> +
> +		synproxy_send_client_synack(net, skb, tcp, &opts);
> +		consume_skb(skb);
> +		regs->verdict.code = NF_STOLEN;
> +		return;
> +	} else if (tcp->ack) {
> +		/* ACK from client */
> +		if (synproxy_recv_client_ack(net, skb, tcp, &opts,
> +					     ntohl(tcp->seq))) {
> +			consume_skb(skb);
> +			regs->verdict.code = NF_STOLEN;
> +		} else {
> +			regs->verdict.code = NF_DROP;
> +		}
> +		return;
> +	}
> +
> +	regs->verdict.code = NFT_CONTINUE;
> +}
> +
> +#if IS_ENABLED(CONFIG_NF_TABLES_IPV6)
> +static void nft_synproxy_eval_v6(const struct nft_expr *expr,
> +				 struct nft_regs *regs,
> +				 const struct nft_pktinfo *pkt)
> +{
> +	struct nft_synproxy *priv = nft_expr_priv(expr);
> +	struct nf_synproxy_info info = create_synproxy_info(priv);
> +	struct synproxy_options opts = {};
> +	struct net *net = nft_net(pkt);
> +	struct synproxy_net *snet = synproxy_pernet(net);
> +	struct sk_buff *skb = pkt->skb;
> +	int thoff = pkt->xt.thoff;
> +	const struct tcphdr *tcp;
> +	struct tcphdr _tcph;
> +
> +	if (nf_ip_checksum(skb, nft_hook(pkt), thoff, IPPROTO_TCP)) {
> +		regs->verdict.code = NF_DROP;
> +		return;
> +	}
> +
> +	tcp = skb_header_pointer(skb, ip_hdrlen(skb),
> +				 sizeof(struct tcphdr), &_tcph);
> +	if (!tcp) {
> +		regs->verdict.code = NF_DROP;
> +		return;
> +	}
> +
> +	if (!synproxy_parse_options(skb, thoff, tcp, &opts)) {
> +		regs->verdict.code = NF_DROP;
> +		return;
> +	}
> +
> +	if (tcp->syn) {
> +		/* Initial SYN from client */
> +		this_cpu_inc(snet->stats->syn_received);
> +
> +		if (tcp->ece && tcp->cwr)
> +			opts.options |= NF_SYNPROXY_OPT_ECN;
> +
> +		opts.options &= priv->flags;
> +		if (opts.options & NF_SYNPROXY_OPT_TIMESTAMP)
> +			synproxy_init_timestamp_cookie(&info, &opts);
> +		else
> +			opts.options &= ~(NF_SYNPROXY_OPT_WSCALE |
> +					  NF_SYNPROXY_OPT_SACK_PERM |
> +					  NF_SYNPROXY_OPT_ECN);
> +
> +		synproxy_send_client_synack_ipv6(net, skb, tcp, &opts);
> +		consume_skb(skb);
> +		regs->verdict.code = NF_STOLEN;
> +		return;
> +	} else if (tcp->ack) {
> +		/* ACK from client */
> +		if (synproxy_recv_client_ack_ipv6(net, skb, tcp, &opts,
> +						  ntohl(tcp->seq))) {
> +			consume_skb(skb);
> +			regs->verdict.code = NF_STOLEN;
> +		} else {
> +			regs->verdict.code = NF_DROP;
> +		}
> +		return;
> +	}
> +
> +	regs->verdict.code = NFT_CONTINUE;
> +}
> +#endif /* IPv6 support */
> +
> +static void nft_synproxy_eval(const struct nft_expr *expr,
> +			      struct nft_regs *regs,
> +			      const struct nft_pktinfo *pkt)
> +{

You have to check if this is TCP traffic in first place, otherwise UDP
packets may enter this path :-).

> +	switch (nft_pf(pkt)) {
> +	case NFPROTO_IPV4:
> +		nft_synproxy_eval_v4(expr, regs, pkt);
> +		return;
> +#if IS_ENABLED(CONFIG_NF_TABLES_IPV6)
> +	case NFPROTO_IPV6:
> +		nft_synproxy_eval_v6(expr, regs, pkt);
> +		return;
> +#endif

Please, use skb->protocol instead of nft_pf(), I would like we can use
nft_synproxy from NFPROTO_NETDEV (ingress) and NFPROTO_BRIDGE families
too.

> +	}
> +	regs->verdict.code = NFT_BREAK;
> +}
> +
> +static int nft_synproxy_init(const struct nft_ctx *ctx,
> +			     const struct nft_expr *expr,
> +			     const struct nlattr * const tb[])
> +{
> +	struct synproxy_net *snet = synproxy_pernet(ctx->net);
> +	struct nft_synproxy *priv = nft_expr_priv(expr);
> +	u32 flags;
> +	int err;
> +
> +	err = nf_ct_netns_get(ctx->net, ctx->family);
> +	if (err)
> +		goto nf_ct_failure;
> +
> +	switch (ctx->family) {
> +	case NFPROTO_IPV4:
> +		err = nf_synproxy_ipv4_init(snet, ctx->net);
> +		if (err)
> +			goto nf_ct_failure;
> +		snet->hook_ref4++;
> +		break;
> +	case NFPROTO_IPV6:
> +		err = nf_synproxy_ipv6_init(snet, ctx->net);
> +		if (err)
> +			goto nf_ct_failure;
> +		snet->hook_ref6++;
> +		break;
> +	case NFPROTO_INET:

Add NFPROTO_BRIDGE here too, ie.

        case NFPROTO_INET:
        case NFPROTO_BRIDGE:

the code below will handle both cases: inet and bridge.

> +		err = nf_synproxy_ipv4_init(snet, ctx->net);
> +		if (err)
> +			goto nf_ct_failure;
> +		err = nf_synproxy_ipv6_init(snet, ctx->net);
> +		if (err)
> +			goto nf_ct_failure;
> +		snet->hook_ref4++;
> +		snet->hook_ref6++;
> +		break;
> +	}
> +
> +	if (tb[NFTA_SYNPROXY_MSS])
> +		priv->mss = ntohs(nla_get_be16(tb[NFTA_SYNPROXY_MSS]));
> +	if (tb[NFTA_SYNPROXY_WSCALE])
> +		priv->wscale = nla_get_u8(tb[NFTA_SYNPROXY_WSCALE]);
> +	if (tb[NFTA_SYNPROXY_FLAGS]) {
> +		flags = ntohl(nla_get_be32(tb[NFTA_SYNPROXY_FLAGS]));
> +		if (flags != 0 && (flags & NF_SYNPROXY_FLAGMASK) == 0)
> +			return -EINVAL;
> +		priv->flags = flags;
> +	}
> +	return 0;
> +
> +nf_ct_failure:
> +	nf_ct_netns_put(ctx->net, ctx->family);
> +	return err;
> +}
> +
> +static void nft_synproxy_destroy(const struct nft_ctx *ctx,
> +				 const struct nft_expr *expr)
> +{
> +	struct synproxy_net *snet = synproxy_pernet(ctx->net);
> +
> +	switch (ctx->family) {
> +	case NFPROTO_IPV4:
> +		nf_synproxy_ipv4_fini(snet, ctx->net);
> +		break;
> +	case NFPROTO_IPV6:
> +		nf_synproxy_ipv6_fini(snet, ctx->net);
> +		break;
> +	case NFPROTO_INET:
> +		nf_synproxy_ipv4_fini(snet, ctx->net);
> +		nf_synproxy_ipv6_fini(snet, ctx->net);
> +		break;
> +	}
> +	nf_ct_netns_put(ctx->net, ctx->family);
> +}
> +
> +static int nft_synproxy_dump(struct sk_buff *skb, const struct nft_expr *expr)
> +{
> +	const struct nft_synproxy *priv = nft_expr_priv(expr);
> +
> +	if (nla_put_be16(skb, NFTA_SYNPROXY_MSS, ntohs(priv->mss)))
> +		goto nla_put_failure;
> +
> +	if (nla_put_u8(skb, NFTA_SYNPROXY_WSCALE, priv->wscale))
> +		goto nla_put_failure;
> +
> +	if (nla_put_be32(skb, NFTA_SYNPROXY_FLAGS, ntohl(priv->flags)))

Probably:

	if (nla_put_be16(skb, NFTA_SYNPROXY_MSS, ntohs(priv->mss)) ||
            nla_put_u8(skb, NFTA_SYNPROXY_WSCALE, priv->wscale) ||
            nla_put_be32(skb, NFTA_SYNPROXY_FLAGS, ntohl(priv->flags)))
		goto nla_put_failure;

so we save a bit of LoC.

> +	return 0;
> +
> +nla_put_failure:
> +	return -1;
> +}
> +
> +static int nft_synproxy_validate(const struct nft_ctx *ctx,
> +				 const struct nft_expr *expr,
> +				 const struct nft_data **data)
> +{
> +	return nft_chain_validate_hooks(ctx->chain, (1 << NF_INET_LOCAL_IN) |
> +						    (1 << NF_INET_FORWARD));
> +}
> +
> +static struct nft_expr_type nft_synproxy_type;
> +static const struct nft_expr_ops nft_synproxy_ops = {
> +	.eval		= nft_synproxy_eval,
> +	.size		= NFT_EXPR_SIZE(sizeof(struct nft_synproxy)),
> +	.init		= nft_synproxy_init,
> +	.destroy	= nft_synproxy_destroy,
> +	.dump		= nft_synproxy_dump,
> +	.type		= &nft_synproxy_type,
> +	.validate	= nft_synproxy_validate,
> +};
> +
> +static struct nft_expr_type nft_synproxy_type __read_mostly = {
> +	.ops		= &nft_synproxy_ops,
> +	.name		= "synproxy",
> +	.owner		= THIS_MODULE,
> +	.policy		= nft_synproxy_policy,
> +	.maxattr	= NFTA_OSF_MAX,
> +};
> +
> +static int __init nft_synproxy_module_init(void)
> +{
> +	return nft_register_expr(&nft_synproxy_type);
> +}
> +
> +static void __exit nft_synproxy_module_exit(void)
> +{
> +	return nft_unregister_expr(&nft_synproxy_type);
> +}
> +
> +module_init(nft_synproxy_module_init);
> +module_exit(nft_synproxy_module_exit);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Fernando Fernandez <ffmancera@riseup.net>");
> +MODULE_ALIAS_NFT_EXPR("synproxy");
> -- 
> 2.20.1
> 

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH nf-next WIP] netfilter: nf_tables: Add SYNPROXY support
  2019-06-17 15:45   ` Pablo Neira Ayuso
@ 2019-06-17 19:49     ` Fernando Fernandez Mancera
  2019-06-17 21:55       ` Pablo Neira Ayuso
  0 siblings, 1 reply; 9+ messages in thread
From: Fernando Fernandez Mancera @ 2019-06-17 19:49 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel

Hi Pablo, comments below.

On 6/17/19 5:45 PM, Pablo Neira Ayuso wrote:
> On Mon, Jun 17, 2019 at 12:32:35PM +0200, Fernando Fernandez Mancera wrote:
>> Add SYNPROXY module support in nf_tables. It preserves the behaviour of the
>> SYNPROXY target of iptables but structured in a different way to propose
>> improvements in the future.
>>
>> Signed-off-by: Fernando Fernandez Mancera <ffmancera@riseup.net>
>> ---
>>  include/uapi/linux/netfilter/nf_SYNPROXY.h |   4 +
>>  include/uapi/linux/netfilter/nf_tables.h   |  16 +
>>  net/netfilter/Kconfig                      |  11 +
>>  net/netfilter/Makefile                     |   1 +
>>  net/netfilter/nft_synproxy.c               | 328 +++++++++++++++++++++
>>  5 files changed, 360 insertions(+)
>>  create mode 100644 net/netfilter/nft_synproxy.c
>>
[...]
>> +
>> +static void nft_synproxy_eval(const struct nft_expr *expr,
>> +			      struct nft_regs *regs,
>> +			      const struct nft_pktinfo *pkt)
>> +{
> 
> You have to check if this is TCP traffic in first place, otherwise UDP
> packets may enter this path :-).
> 
>> +	switch (nft_pf(pkt)) {
>> +	case NFPROTO_IPV4:
>> +		nft_synproxy_eval_v4(expr, regs, pkt);
>> +		return;
>> +#if IS_ENABLED(CONFIG_NF_TABLES_IPV6)
>> +	case NFPROTO_IPV6:
>> +		nft_synproxy_eval_v6(expr, regs, pkt);
>> +		return;
>> +#endif
> 
> Please, use skb->protocol instead of nft_pf(), I would like we can use
> nft_synproxy from NFPROTO_NETDEV (ingress) and NFPROTO_BRIDGE families
> too.
> 

If I use skb->protocol no packet enters in the path. What do you
recommend me? Other than that, the rest of the suggestions are done and
it has been tested and it worked as expected. Thanks :-)

>> +	}
>> +	regs->verdict.code = NFT_BREAK;
>> +}
>> +
>> +static int nft_synproxy_init(const struct nft_ctx *ctx,
>> +			     const struct nft_expr *expr,
>> +			     const struct nlattr * const tb[])
>> +{
>> +	struct synproxy_net *snet = synproxy_pernet(ctx->net);
>> +	struct nft_synproxy *priv = nft_expr_priv(expr);
>> +	u32 flags;
>> +	int err;
>> +
>> +	err = nf_ct_netns_get(ctx->net, ctx->family);
>> +	if (err)
>> +		goto nf_ct_failure;
>> +
>> +	switch (ctx->family) {
>> +	case NFPROTO_IPV4:
>> +		err = nf_synproxy_ipv4_init(snet, ctx->net);
>> +		if (err)
>> +			goto nf_ct_failure;
>> +		snet->hook_ref4++;
>> +		break;
>> +	case NFPROTO_IPV6:
>> +		err = nf_synproxy_ipv6_init(snet, ctx->net);
>> +		if (err)
>> +			goto nf_ct_failure;
>> +		snet->hook_ref6++;
>> +		break;
>> +	case NFPROTO_INET:
> 
> Add NFPROTO_BRIDGE here too, ie.
> 
>         case NFPROTO_INET:
>         case NFPROTO_BRIDGE:
> 
> the code below will handle both cases: inet and bridge.
> 
>> +		err = nf_synproxy_ipv4_init(snet, ctx->net);
>> +		if (err)
>> +			goto nf_ct_failure;
>> +		err = nf_synproxy_ipv6_init(snet, ctx->net);
>> +		if (err)
>> +			goto nf_ct_failure;
>> +		snet->hook_ref4++;
>> +		snet->hook_ref6++;
>> +		break;
>> +	}
>> +
>> +	if (tb[NFTA_SYNPROXY_MSS])
>> +		priv->mss = ntohs(nla_get_be16(tb[NFTA_SYNPROXY_MSS]));
>> +	if (tb[NFTA_SYNPROXY_WSCALE])
>> +		priv->wscale = nla_get_u8(tb[NFTA_SYNPROXY_WSCALE]);
>> +	if (tb[NFTA_SYNPROXY_FLAGS]) {
>> +		flags = ntohl(nla_get_be32(tb[NFTA_SYNPROXY_FLAGS]));
>> +		if (flags != 0 && (flags & NF_SYNPROXY_FLAGMASK) == 0)
>> +			return -EINVAL;
>> +		priv->flags = flags;
>> +	}
>> +	return 0;
>> +
>> +nf_ct_failure:
>> +	nf_ct_netns_put(ctx->net, ctx->family);
>> +	return err;
>> +}
>> +
>> +static void nft_synproxy_destroy(const struct nft_ctx *ctx,
>> +				 const struct nft_expr *expr)
>> +{
>> +	struct synproxy_net *snet = synproxy_pernet(ctx->net);
>> +
>> +	switch (ctx->family) {
>> +	case NFPROTO_IPV4:
>> +		nf_synproxy_ipv4_fini(snet, ctx->net);
>> +		break;
>> +	case NFPROTO_IPV6:
>> +		nf_synproxy_ipv6_fini(snet, ctx->net);
>> +		break;
>> +	case NFPROTO_INET:
>> +		nf_synproxy_ipv4_fini(snet, ctx->net);
>> +		nf_synproxy_ipv6_fini(snet, ctx->net);
>> +		break;
>> +	}
>> +	nf_ct_netns_put(ctx->net, ctx->family);
>> +}
>> +
>> +static int nft_synproxy_dump(struct sk_buff *skb, const struct nft_expr *expr)
>> +{
>> +	const struct nft_synproxy *priv = nft_expr_priv(expr);
>> +
>> +	if (nla_put_be16(skb, NFTA_SYNPROXY_MSS, ntohs(priv->mss)))
>> +		goto nla_put_failure;
>> +
>> +	if (nla_put_u8(skb, NFTA_SYNPROXY_WSCALE, priv->wscale))
>> +		goto nla_put_failure;
>> +
>> +	if (nla_put_be32(skb, NFTA_SYNPROXY_FLAGS, ntohl(priv->flags)))
> 
> Probably:
> 
> 	if (nla_put_be16(skb, NFTA_SYNPROXY_MSS, ntohs(priv->mss)) ||
>             nla_put_u8(skb, NFTA_SYNPROXY_WSCALE, priv->wscale) ||
>             nla_put_be32(skb, NFTA_SYNPROXY_FLAGS, ntohl(priv->flags)))
> 		goto nla_put_failure;
> 
> so we save a bit of LoC.
> 
>> +	return 0;
>> +
>> +nla_put_failure:
>> +	return -1;
>> +}
>> +
>> +static int nft_synproxy_validate(const struct nft_ctx *ctx,
>> +				 const struct nft_expr *expr,
>> +				 const struct nft_data **data)
>> +{
>> +	return nft_chain_validate_hooks(ctx->chain, (1 << NF_INET_LOCAL_IN) |
>> +						    (1 << NF_INET_FORWARD));
>> +}
>> +
>> +static struct nft_expr_type nft_synproxy_type;
>> +static const struct nft_expr_ops nft_synproxy_ops = {
>> +	.eval		= nft_synproxy_eval,
>> +	.size		= NFT_EXPR_SIZE(sizeof(struct nft_synproxy)),
>> +	.init		= nft_synproxy_init,
>> +	.destroy	= nft_synproxy_destroy,
>> +	.dump		= nft_synproxy_dump,
>> +	.type		= &nft_synproxy_type,
>> +	.validate	= nft_synproxy_validate,
>> +};
>> +
>> +static struct nft_expr_type nft_synproxy_type __read_mostly = {
>> +	.ops		= &nft_synproxy_ops,
>> +	.name		= "synproxy",
>> +	.owner		= THIS_MODULE,
>> +	.policy		= nft_synproxy_policy,
>> +	.maxattr	= NFTA_OSF_MAX,
>> +};
>> +
>> +static int __init nft_synproxy_module_init(void)
>> +{
>> +	return nft_register_expr(&nft_synproxy_type);
>> +}
>> +
>> +static void __exit nft_synproxy_module_exit(void)
>> +{
>> +	return nft_unregister_expr(&nft_synproxy_type);
>> +}
>> +
>> +module_init(nft_synproxy_module_init);
>> +module_exit(nft_synproxy_module_exit);
>> +
>> +MODULE_LICENSE("GPL");
>> +MODULE_AUTHOR("Fernando Fernandez <ffmancera@riseup.net>");
>> +MODULE_ALIAS_NFT_EXPR("synproxy");
>> -- 
>> 2.20.1
>>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH nf-next WIP] netfilter: nf_tables: Add SYNPROXY support
  2019-06-17 19:49     ` Fernando Fernandez Mancera
@ 2019-06-17 21:55       ` Pablo Neira Ayuso
  2019-06-17 21:58         ` Fernando Fernandez Mancera
  0 siblings, 1 reply; 9+ messages in thread
From: Pablo Neira Ayuso @ 2019-06-17 21:55 UTC (permalink / raw)
  To: Fernando Fernandez Mancera; +Cc: netfilter-devel

On Mon, Jun 17, 2019 at 09:49:43PM +0200, Fernando Fernandez Mancera wrote:
> Hi Pablo, comments below.
> 
> On 6/17/19 5:45 PM, Pablo Neira Ayuso wrote:
> > On Mon, Jun 17, 2019 at 12:32:35PM +0200, Fernando Fernandez Mancera wrote:
> >> Add SYNPROXY module support in nf_tables. It preserves the behaviour of the
> >> SYNPROXY target of iptables but structured in a different way to propose
> >> improvements in the future.
> >>
> >> Signed-off-by: Fernando Fernandez Mancera <ffmancera@riseup.net>
> >> ---
> >>  include/uapi/linux/netfilter/nf_SYNPROXY.h |   4 +
> >>  include/uapi/linux/netfilter/nf_tables.h   |  16 +
> >>  net/netfilter/Kconfig                      |  11 +
> >>  net/netfilter/Makefile                     |   1 +
> >>  net/netfilter/nft_synproxy.c               | 328 +++++++++++++++++++++
> >>  5 files changed, 360 insertions(+)
> >>  create mode 100644 net/netfilter/nft_synproxy.c
> >>
> [...]
> >> +
> >> +static void nft_synproxy_eval(const struct nft_expr *expr,
> >> +			      struct nft_regs *regs,
> >> +			      const struct nft_pktinfo *pkt)
> >> +{
> > 
> > You have to check if this is TCP traffic in first place, otherwise UDP
> > packets may enter this path :-).
> > 
> >> +	switch (nft_pf(pkt)) {
> >> +	case NFPROTO_IPV4:
> >> +		nft_synproxy_eval_v4(expr, regs, pkt);
> >> +		return;
> >> +#if IS_ENABLED(CONFIG_NF_TABLES_IPV6)
> >> +	case NFPROTO_IPV6:
> >> +		nft_synproxy_eval_v6(expr, regs, pkt);
> >> +		return;
> >> +#endif
> > 
> > Please, use skb->protocol instead of nft_pf(), I would like we can use
> > nft_synproxy from NFPROTO_NETDEV (ingress) and NFPROTO_BRIDGE families
> > too.
> > 
> 
> If I use skb->protocol no packet enters in the path. What do you
> recommend me? Other than that, the rest of the suggestions are done and
> it has been tested and it worked as expected. Thanks :-)

skb->protocol uses big endian representation, you have to check for:

        switch (skb->protocol) {
        case htons(ETH_P_IP):
                ...
                break;
        case htons(ETH_P_IPV6):
                ...
                break;
        }

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH nf-next WIP] netfilter: nf_tables: Add SYNPROXY support
  2019-06-17 21:55       ` Pablo Neira Ayuso
@ 2019-06-17 21:58         ` Fernando Fernandez Mancera
  0 siblings, 0 replies; 9+ messages in thread
From: Fernando Fernandez Mancera @ 2019-06-17 21:58 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel



On 6/17/19 11:55 PM, Pablo Neira Ayuso wrote:
> On Mon, Jun 17, 2019 at 09:49:43PM +0200, Fernando Fernandez Mancera wrote:
>> Hi Pablo, comments below.
>>
>> On 6/17/19 5:45 PM, Pablo Neira Ayuso wrote:
>>> On Mon, Jun 17, 2019 at 12:32:35PM +0200, Fernando Fernandez Mancera wrote:
>>>> Add SYNPROXY module support in nf_tables. It preserves the behaviour of the
>>>> SYNPROXY target of iptables but structured in a different way to propose
>>>> improvements in the future.
>>>>
>>>> Signed-off-by: Fernando Fernandez Mancera <ffmancera@riseup.net>
>>>> ---
>>>>  include/uapi/linux/netfilter/nf_SYNPROXY.h |   4 +
>>>>  include/uapi/linux/netfilter/nf_tables.h   |  16 +
>>>>  net/netfilter/Kconfig                      |  11 +
>>>>  net/netfilter/Makefile                     |   1 +
>>>>  net/netfilter/nft_synproxy.c               | 328 +++++++++++++++++++++
>>>>  5 files changed, 360 insertions(+)
>>>>  create mode 100644 net/netfilter/nft_synproxy.c
>>>>
>> [...]
>>>> +
>>>> +static void nft_synproxy_eval(const struct nft_expr *expr,
>>>> +			      struct nft_regs *regs,
>>>> +			      const struct nft_pktinfo *pkt)
>>>> +{
>>>
>>> You have to check if this is TCP traffic in first place, otherwise UDP
>>> packets may enter this path :-).
>>>
>>>> +	switch (nft_pf(pkt)) {
>>>> +	case NFPROTO_IPV4:
>>>> +		nft_synproxy_eval_v4(expr, regs, pkt);
>>>> +		return;
>>>> +#if IS_ENABLED(CONFIG_NF_TABLES_IPV6)
>>>> +	case NFPROTO_IPV6:
>>>> +		nft_synproxy_eval_v6(expr, regs, pkt);
>>>> +		return;
>>>> +#endif
>>>
>>> Please, use skb->protocol instead of nft_pf(), I would like we can use
>>> nft_synproxy from NFPROTO_NETDEV (ingress) and NFPROTO_BRIDGE families
>>> too.
>>>
>>
>> If I use skb->protocol no packet enters in the path. What do you
>> recommend me? Other than that, the rest of the suggestions are done and
>> it has been tested and it worked as expected. Thanks :-)
> 
> skb->protocol uses big endian representation, you have to check for:
> 
>         switch (skb->protocol) {
>         case htons(ETH_P_IP):
>                 ...
>                 break;
>         case htons(ETH_P_IPV6):
>                 ...
>                 break;
>         }
> 


Oh, I didn't know that. A patch series including tests and documentation
it is going to be ready soon if everything seem fine to you. After this,
I think we can implement some improvements. Thanks :-)

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2019-06-17 21:58 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-06-17 10:32 [PATCH libnftnl WIP] expr: add synproxy support Fernando Fernandez Mancera
2019-06-17 10:32 ` [PATCH nf-next WIP] netfilter: nf_tables: Add SYNPROXY support Fernando Fernandez Mancera
2019-06-17 15:25   ` Pablo Neira Ayuso
2019-06-17 15:45   ` Pablo Neira Ayuso
2019-06-17 19:49     ` Fernando Fernandez Mancera
2019-06-17 21:55       ` Pablo Neira Ayuso
2019-06-17 21:58         ` Fernando Fernandez Mancera
2019-06-17 10:32 ` [PATCH nft WIP] src: introduce SYNPROXY matching Fernando Fernandez Mancera
2019-06-17 10:41   ` Fernando Fernandez Mancera

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.