Netfilter-Devel Archive on lore.kernel.org
 help / color / Atom feed
* [PATCH nf-next 0/4] Add nf_tables ingress hook for the inet family
@ 2020-10-07 23:14 Pablo Neira Ayuso
  2020-10-07 23:14 ` [PATCH nf-next 1/4] netfilter: add nf_static_key_{inc,dec} Pablo Neira Ayuso
                   ` (4 more replies)
  0 siblings, 5 replies; 8+ messages in thread
From: Pablo Neira Ayuso @ 2020-10-07 23:14 UTC (permalink / raw)
  To: netfilter-devel

Hi,

The following patchset adds support for the inet ingress hook:

Patch #1 adds nf_static_key_inc() and nf_static_key_dec() helper functions.
Patch #2 adds nf_ingress_hook() helper function.
Patch #3 adds inet ingress hook support to the core.
Patch #4 adds inet ingress hook support for nf_tables.

The following example shows how to place offenders into the 'blackhole'
set. Offenders in this case are those that connect to the local SSH port
over the specified rate limit. The inet ingress chain is used to
shortcircuit the evaluation of the traffic coming from the offender at
early stage in the packet processing receive path.

  table inet filter {
        set blackhole {
                type ipv4_addr
                size 65535
                flags dynamic,timeout
                timeout 5m
        }

        chain input {
                type filter hook input priority filter; policy accept;
                ct state new tcp dport 22 update @blackhole { ip saddr limit rate over 4/minute } counter packets 0 bytes 0
        }

        chain ingress {
                type filter hook unknown device "enp0s25" priority filter; policy accept;
                ip saddr @blackhole counter packets 0 bytes 0 drop
        }
  }

Pablo Neira Ayuso (4):
  netfilter: add nf_static_key_{inc,dec}
  netfilter: add nf_ingress_hook() helper function
  netfilter: add inet ingress support
  netfilter: nf_tables: add inet ingress support

 include/net/netfilter/nf_tables.h      |   6 ++
 include/net/netfilter/nf_tables_ipv4.h |  33 +++++++
 include/net/netfilter/nf_tables_ipv6.h |  46 +++++++++
 include/uapi/linux/netfilter.h         |   1 +
 net/netfilter/core.c                   | 127 ++++++++++++++++++++-----
 net/netfilter/nf_tables_api.c          |  14 +--
 net/netfilter/nft_chain_filter.c       |  35 ++++++-
 7 files changed, 228 insertions(+), 34 deletions(-)

--
2.20.1


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

* [PATCH nf-next 1/4] netfilter: add nf_static_key_{inc,dec}
  2020-10-07 23:14 [PATCH nf-next 0/4] Add nf_tables ingress hook for the inet family Pablo Neira Ayuso
@ 2020-10-07 23:14 ` Pablo Neira Ayuso
  2020-10-07 23:14 ` [PATCH nf-next 2/4] netfilter: add nf_ingress_hook() helper function Pablo Neira Ayuso
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 8+ messages in thread
From: Pablo Neira Ayuso @ 2020-10-07 23:14 UTC (permalink / raw)
  To: netfilter-devel

Add helper functions increment and decrement the hook static keys.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 net/netfilter/core.c | 23 +++++++++++++++++------
 1 file changed, 17 insertions(+), 6 deletions(-)

diff --git a/net/netfilter/core.c b/net/netfilter/core.c
index 3ac7c8c1548d..b9ec8ecf7e30 100644
--- a/net/netfilter/core.c
+++ b/net/netfilter/core.c
@@ -311,6 +311,20 @@ nf_hook_entry_head(struct net *net, int pf, unsigned int hooknum,
 	return NULL;
 }
 
+static void nf_static_key_inc(const struct nf_hook_ops *reg, int pf)
+{
+#ifdef CONFIG_JUMP_LABEL
+       static_key_slow_inc(&nf_hooks_needed[pf][reg->hooknum]);
+#endif
+}
+
+static void nf_static_key_dec(const struct nf_hook_ops *reg, int pf)
+{
+#ifdef CONFIG_JUMP_LABEL
+       static_key_slow_dec(&nf_hooks_needed[pf][reg->hooknum]);
+#endif
+}
+
 static int __nf_register_net_hook(struct net *net, int pf,
 				  const struct nf_hook_ops *reg)
 {
@@ -348,9 +362,8 @@ static int __nf_register_net_hook(struct net *net, int pf,
 	if (pf == NFPROTO_NETDEV && reg->hooknum == NF_NETDEV_INGRESS)
 		net_inc_ingress_queue();
 #endif
-#ifdef CONFIG_JUMP_LABEL
-	static_key_slow_inc(&nf_hooks_needed[pf][reg->hooknum]);
-#endif
+	nf_static_key_inc(reg, pf);
+
 	BUG_ON(p == new_hooks);
 	nf_hook_entries_free(p);
 	return 0;
@@ -406,9 +419,7 @@ static void __nf_unregister_net_hook(struct net *net, int pf,
 		if (pf == NFPROTO_NETDEV && reg->hooknum == NF_NETDEV_INGRESS)
 			net_dec_ingress_queue();
 #endif
-#ifdef CONFIG_JUMP_LABEL
-		static_key_slow_dec(&nf_hooks_needed[pf][reg->hooknum]);
-#endif
+		nf_static_key_dec(reg, pf);
 	} else {
 		WARN_ONCE(1, "hook not found, pf %d num %d", pf, reg->hooknum);
 	}
-- 
2.20.1


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

* [PATCH nf-next 2/4] netfilter: add nf_ingress_hook() helper function
  2020-10-07 23:14 [PATCH nf-next 0/4] Add nf_tables ingress hook for the inet family Pablo Neira Ayuso
  2020-10-07 23:14 ` [PATCH nf-next 1/4] netfilter: add nf_static_key_{inc,dec} Pablo Neira Ayuso
@ 2020-10-07 23:14 ` Pablo Neira Ayuso
  2020-10-07 23:14 ` [PATCH nf-next 3/4] netfilter: add inet ingress support Pablo Neira Ayuso
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 8+ messages in thread
From: Pablo Neira Ayuso @ 2020-10-07 23:14 UTC (permalink / raw)
  To: netfilter-devel

Add helper function to check if this is an ingress hook.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 net/netfilter/core.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/net/netfilter/core.c b/net/netfilter/core.c
index b9ec8ecf7e30..a7639501d78b 100644
--- a/net/netfilter/core.c
+++ b/net/netfilter/core.c
@@ -311,6 +311,11 @@ nf_hook_entry_head(struct net *net, int pf, unsigned int hooknum,
 	return NULL;
 }
 
+static bool nf_ingress_hook(const struct nf_hook_ops *reg, int pf)
+{
+	return pf == NFPROTO_NETDEV && reg->hooknum == NF_NETDEV_INGRESS;
+}
+
 static void nf_static_key_inc(const struct nf_hook_ops *reg, int pf)
 {
 #ifdef CONFIG_JUMP_LABEL
@@ -359,7 +364,7 @@ static int __nf_register_net_hook(struct net *net, int pf,
 
 	hooks_validate(new_hooks);
 #ifdef CONFIG_NETFILTER_INGRESS
-	if (pf == NFPROTO_NETDEV && reg->hooknum == NF_NETDEV_INGRESS)
+	if (nf_ingress_hook(reg, pf))
 		net_inc_ingress_queue();
 #endif
 	nf_static_key_inc(reg, pf);
@@ -416,7 +421,7 @@ static void __nf_unregister_net_hook(struct net *net, int pf,
 
 	if (nf_remove_net_hook(p, reg)) {
 #ifdef CONFIG_NETFILTER_INGRESS
-		if (pf == NFPROTO_NETDEV && reg->hooknum == NF_NETDEV_INGRESS)
+		if (nf_ingress_hook(reg, pf))
 			net_dec_ingress_queue();
 #endif
 		nf_static_key_dec(reg, pf);
-- 
2.20.1


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

* [PATCH nf-next 3/4] netfilter: add inet ingress support
  2020-10-07 23:14 [PATCH nf-next 0/4] Add nf_tables ingress hook for the inet family Pablo Neira Ayuso
  2020-10-07 23:14 ` [PATCH nf-next 1/4] netfilter: add nf_static_key_{inc,dec} Pablo Neira Ayuso
  2020-10-07 23:14 ` [PATCH nf-next 2/4] netfilter: add nf_ingress_hook() helper function Pablo Neira Ayuso
@ 2020-10-07 23:14 ` Pablo Neira Ayuso
  2020-10-08  1:04   ` kernel test robot
  2020-10-08  2:23   ` kernel test robot
  2020-10-07 23:14 ` [PATCH nf-next 4/4] netfilter: nf_tables: " Pablo Neira Ayuso
  2020-10-07 23:22 ` [PATCH nf-next 0/4] Add nf_tables ingress hook for the inet family Pablo Neira Ayuso
  4 siblings, 2 replies; 8+ messages in thread
From: Pablo Neira Ayuso @ 2020-10-07 23:14 UTC (permalink / raw)
  To: netfilter-devel

This patch adds the NF_INET_INGRESS pseudohook for the NFPROTO_INET
family. This is a mapping this new hook to the existing NFPROTO_NETDEV
and NF_NETDEV_INGRESS hook. The hook does not guarantee that packets are
inet only, users must filter out non-ip traffic explicitly.

This infrastructure makes it easier to support this new hook in nf_tables.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 include/uapi/linux/netfilter.h |   1 +
 net/netfilter/core.c           | 101 ++++++++++++++++++++++++++-------
 2 files changed, 81 insertions(+), 21 deletions(-)

diff --git a/include/uapi/linux/netfilter.h b/include/uapi/linux/netfilter.h
index ca9e63d6e0e4..6a6179af0d7c 100644
--- a/include/uapi/linux/netfilter.h
+++ b/include/uapi/linux/netfilter.h
@@ -45,6 +45,7 @@ enum nf_inet_hooks {
 	NF_INET_FORWARD,
 	NF_INET_LOCAL_OUT,
 	NF_INET_POST_ROUTING,
+	NF_INET_INGRESS,
 	NF_INET_NUMHOOKS
 };
 
diff --git a/net/netfilter/core.c b/net/netfilter/core.c
index a7639501d78b..38feb1f0feda 100644
--- a/net/netfilter/core.c
+++ b/net/netfilter/core.c
@@ -282,6 +282,14 @@ nf_hook_entry_head(struct net *net, int pf, unsigned int hooknum,
 			return NULL;
 		return net->nf.hooks_bridge + hooknum;
 #endif
+	case NFPROTO_INET:
+		if (WARN_ON_ONCE(hooknum != NF_INET_INGRESS))
+			return NULL;
+		if (!dev || dev_net(dev) != net) {
+			WARN_ON_ONCE(1);
+			return NULL;
+		}
+		return &dev->nf_hooks_ingress;
 	case NFPROTO_IPV4:
 		if (WARN_ON_ONCE(ARRAY_SIZE(net->nf.hooks_ipv4) <= hooknum))
 			return NULL;
@@ -311,22 +319,56 @@ nf_hook_entry_head(struct net *net, int pf, unsigned int hooknum,
 	return NULL;
 }
 
+static int nf_ingress_check(struct net *net, const struct nf_hook_ops *reg,
+			    int hooknum)
+{
+#ifndef CONFIG_NETFILTER_INGRESS
+	if (reg->hooknum == hooknum)
+		return -EOPNOTSUPP;
+#endif
+	if (reg->hooknum != hooknum ||
+	    !reg->dev || dev_net(reg->dev) != net)
+		return -EINVAL;
+
+	return 0;
+}
+
 static bool nf_ingress_hook(const struct nf_hook_ops *reg, int pf)
 {
-	return pf == NFPROTO_NETDEV && reg->hooknum == NF_NETDEV_INGRESS;
+	if ((pf == NFPROTO_NETDEV && reg->hooknum == NF_NETDEV_INGRESS) ||
+	    (pf == NFPROTO_INET && reg->hooknum == NF_INET_INGRESS))
+		return true;
+
+	return false;
 }
 
 static void nf_static_key_inc(const struct nf_hook_ops *reg, int pf)
 {
 #ifdef CONFIG_JUMP_LABEL
-       static_key_slow_inc(&nf_hooks_needed[pf][reg->hooknum]);
+	int hooknum;
+
+	if (pf == NFPROTO_INET && reg->hooknum == NF_INET_INGRESS) {
+		pf = NFPROTO_NETDEV;
+		hooknum = NF_NETDEV_INGRESS;
+	} else {
+		hooknum = reg->hooknum;
+	}
+	static_key_slow_inc(&nf_hooks_needed[pf][hooknum]);
 #endif
 }
 
 static void nf_static_key_dec(const struct nf_hook_ops *reg, int pf)
 {
 #ifdef CONFIG_JUMP_LABEL
-       static_key_slow_dec(&nf_hooks_needed[pf][reg->hooknum]);
+	int hooknum;
+
+	if (pf == NFPROTO_INET && reg->hooknum == NF_INET_INGRESS) {
+		pf = NFPROTO_NETDEV;
+		hooknum = NF_NETDEV_INGRESS;
+	} else {
+		hooknum = reg->hooknum;
+	}
+	static_key_slow_dec(&nf_hooks_needed[pf][hooknum]);
 #endif
 }
 
@@ -335,15 +377,22 @@ static int __nf_register_net_hook(struct net *net, int pf,
 {
 	struct nf_hook_entries *p, *new_hooks;
 	struct nf_hook_entries __rcu **pp;
+	int err;
 
-	if (pf == NFPROTO_NETDEV) {
-#ifndef CONFIG_NETFILTER_INGRESS
-		if (reg->hooknum == NF_NETDEV_INGRESS)
-			return -EOPNOTSUPP;
-#endif
-		if (reg->hooknum != NF_NETDEV_INGRESS ||
-		    !reg->dev || dev_net(reg->dev) != net)
-			return -EINVAL;
+	switch (pf) {
+	case NFPROTO_NETDEV:
+		err = nf_ingress_check(net, reg, NF_NETDEV_INGRESS);
+		if (err < 0)
+			return err;
+		break;
+	case NFPROTO_INET:
+		if (reg->hooknum != NF_INET_INGRESS)
+			break;
+
+		err = nf_ingress_check(net, reg, NF_INET_INGRESS);
+		if (err < 0)
+			return err;
+		break;
 	}
 
 	pp = nf_hook_entry_head(net, pf, reg->hooknum, reg->dev);
@@ -441,8 +490,12 @@ static void __nf_unregister_net_hook(struct net *net, int pf,
 void nf_unregister_net_hook(struct net *net, const struct nf_hook_ops *reg)
 {
 	if (reg->pf == NFPROTO_INET) {
-		__nf_unregister_net_hook(net, NFPROTO_IPV4, reg);
-		__nf_unregister_net_hook(net, NFPROTO_IPV6, reg);
+		if (reg->hooknum == NF_INET_INGRESS) {
+			__nf_unregister_net_hook(net, NFPROTO_INET, reg);
+		} else {
+			__nf_unregister_net_hook(net, NFPROTO_IPV4, reg);
+			__nf_unregister_net_hook(net, NFPROTO_IPV6, reg);
+		}
 	} else {
 		__nf_unregister_net_hook(net, reg->pf, reg);
 	}
@@ -467,14 +520,20 @@ int nf_register_net_hook(struct net *net, const struct nf_hook_ops *reg)
 	int err;
 
 	if (reg->pf == NFPROTO_INET) {
-		err = __nf_register_net_hook(net, NFPROTO_IPV4, reg);
-		if (err < 0)
-			return err;
-
-		err = __nf_register_net_hook(net, NFPROTO_IPV6, reg);
-		if (err < 0) {
-			__nf_unregister_net_hook(net, NFPROTO_IPV4, reg);
-			return err;
+		if (reg->hooknum == NF_INET_INGRESS) {
+			err = __nf_register_net_hook(net, NFPROTO_INET, reg);
+			if (err < 0)
+				return err;
+		} else {
+			err = __nf_register_net_hook(net, NFPROTO_IPV4, reg);
+			if (err < 0)
+				return err;
+
+			err = __nf_register_net_hook(net, NFPROTO_IPV6, reg);
+			if (err < 0) {
+				__nf_unregister_net_hook(net, NFPROTO_IPV4, reg);
+				return err;
+			}
 		}
 	} else {
 		err = __nf_register_net_hook(net, reg->pf, reg);
-- 
2.20.1


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

* [PATCH nf-next 4/4] netfilter: nf_tables: add inet ingress support
  2020-10-07 23:14 [PATCH nf-next 0/4] Add nf_tables ingress hook for the inet family Pablo Neira Ayuso
                   ` (2 preceding siblings ...)
  2020-10-07 23:14 ` [PATCH nf-next 3/4] netfilter: add inet ingress support Pablo Neira Ayuso
@ 2020-10-07 23:14 ` Pablo Neira Ayuso
  2020-10-07 23:22 ` [PATCH nf-next 0/4] Add nf_tables ingress hook for the inet family Pablo Neira Ayuso
  4 siblings, 0 replies; 8+ messages in thread
From: Pablo Neira Ayuso @ 2020-10-07 23:14 UTC (permalink / raw)
  To: netfilter-devel

This patch adds a new ingress hook for the inet family. The inet ingress
hook emulates the IP receive path code, therefore, unclean packets are
drop before walking over the ruleset in this basechain.

This patch also introduces the nft_base_chain_netdev() helper function
to check if this hook is bound to one or more devices (through the hook
list infrastructure). This check allows to perform the same handling for
the inet ingress as it would be a netdev ingress chain from the control
plane.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 include/net/netfilter/nf_tables.h      |  6 ++++
 include/net/netfilter/nf_tables_ipv4.h | 33 ++++++++++++++++++
 include/net/netfilter/nf_tables_ipv6.h | 46 ++++++++++++++++++++++++++
 net/netfilter/nf_tables_api.c          | 14 ++++----
 net/netfilter/nft_chain_filter.c       | 35 +++++++++++++++++++-
 5 files changed, 126 insertions(+), 8 deletions(-)

diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
index 0bd2a081ae39..3965ce18226f 100644
--- a/include/net/netfilter/nf_tables.h
+++ b/include/net/netfilter/nf_tables.h
@@ -1081,6 +1081,12 @@ struct nft_table {
 	u8				*udata;
 };
 
+static inline bool nft_base_chain_netdev(int family, u32 hooknum)
+{
+	return family == NFPROTO_NETDEV ||
+	       (family == NFPROTO_INET && hooknum == NF_INET_INGRESS);
+}
+
 void nft_register_chain_type(const struct nft_chain_type *);
 void nft_unregister_chain_type(const struct nft_chain_type *);
 
diff --git a/include/net/netfilter/nf_tables_ipv4.h b/include/net/netfilter/nf_tables_ipv4.h
index ed7b511f0a59..1f7bea39ad1b 100644
--- a/include/net/netfilter/nf_tables_ipv4.h
+++ b/include/net/netfilter/nf_tables_ipv4.h
@@ -53,4 +53,37 @@ static inline void nft_set_pktinfo_ipv4_validate(struct nft_pktinfo *pkt,
 		nft_set_pktinfo_unspec(pkt, skb);
 }
 
+static inline int nft_set_pktinfo_ipv4_ingress(struct nft_pktinfo *pkt,
+					       struct sk_buff *skb)
+{
+	struct iphdr *iph;
+	u32 len, thoff;
+
+	if (!pskb_may_pull(skb, sizeof(*iph)))
+		return -1;
+
+	iph = ip_hdr(skb);
+	if (iph->ihl < 5 || iph->version != 4)
+		goto inhdr_error;
+
+	len = ntohs(iph->tot_len);
+	thoff = iph->ihl * 4;
+	if (skb->len < len) {
+		__IP_INC_STATS(nft_net(pkt), IPSTATS_MIB_INTRUNCATEDPKTS);
+		return -1;
+	} else if (len < thoff) {
+		goto inhdr_error;
+	}
+
+	pkt->tprot_set = true;
+	pkt->tprot = iph->protocol;
+	pkt->xt.thoff = thoff;
+	pkt->xt.fragoff = ntohs(iph->frag_off) & IP_OFFSET;
+
+	return 0;
+
+inhdr_error:
+	__IP_INC_STATS(nft_net(pkt), IPSTATS_MIB_INHDRERRORS);
+	return -1;
+}
 #endif
diff --git a/include/net/netfilter/nf_tables_ipv6.h b/include/net/netfilter/nf_tables_ipv6.h
index d0f1c537b017..867de29f3f7a 100644
--- a/include/net/netfilter/nf_tables_ipv6.h
+++ b/include/net/netfilter/nf_tables_ipv6.h
@@ -70,4 +70,50 @@ static inline void nft_set_pktinfo_ipv6_validate(struct nft_pktinfo *pkt,
 		nft_set_pktinfo_unspec(pkt, skb);
 }
 
+static inline int nft_set_pktinfo_ipv6_ingress(struct nft_pktinfo *pkt,
+					       struct sk_buff *skb)
+{
+#if IS_ENABLED(CONFIG_IPV6)
+	unsigned int flags = IP6_FH_F_AUTH;
+	unsigned short frag_off;
+	unsigned int thoff = 0;
+	struct inet6_dev *idev;
+	struct ipv6hdr *ip6h;
+	int protohdr;
+	u32 pkt_len;
+
+	if (!pskb_may_pull(skb, sizeof(*ip6h)))
+		return -1;
+
+	ip6h = ipv6_hdr(skb);
+	if (ip6h->version != 6)
+		goto inhdr_error;
+
+	pkt_len = ntohs(ip6h->payload_len);
+	if (pkt_len + sizeof(*ip6h) > skb->len) {
+		idev = __in6_dev_get(nft_in(pkt));
+		__IP6_INC_STATS(nft_net(pkt), idev, IPSTATS_MIB_INTRUNCATEDPKTS);
+		return -1;
+	}
+
+	protohdr = ipv6_find_hdr(pkt->skb, &thoff, -1, &frag_off, &flags);
+	if (protohdr < 0)
+		goto inhdr_error;
+
+	pkt->tprot_set = true;
+	pkt->tprot = protohdr;
+	pkt->xt.thoff = thoff;
+	pkt->xt.fragoff = frag_off;
+
+	return 0;
+
+inhdr_error:
+	idev = __in6_dev_get(nft_in(pkt));
+	__IP6_INC_STATS(nft_net(pkt), idev, IPSTATS_MIB_INHDRERRORS);
+	return -1;
+#else
+	return -1;
+#endif
+}
+
 #endif
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index ae2c04d411b1..f22ad21d0230 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -206,7 +206,7 @@ static int nf_tables_register_hook(struct net *net,
 	if (basechain->type->ops_register)
 		return basechain->type->ops_register(net, ops);
 
-	if (table->family == NFPROTO_NETDEV)
+	if (nft_base_chain_netdev(table->family, basechain->ops.hooknum))
 		return nft_netdev_register_hooks(net, &basechain->hook_list);
 
 	return nf_register_net_hook(net, &basechain->ops);
@@ -228,7 +228,7 @@ static void nf_tables_unregister_hook(struct net *net,
 	if (basechain->type->ops_unregister)
 		return basechain->type->ops_unregister(net, ops);
 
-	if (table->family == NFPROTO_NETDEV)
+	if (nft_base_chain_netdev(table->family, basechain->ops.hooknum))
 		nft_netdev_unregister_hooks(net, &basechain->hook_list);
 	else
 		nf_unregister_net_hook(net, &basechain->ops);
@@ -1381,7 +1381,7 @@ static int nft_dump_basechain_hook(struct sk_buff *skb, int family,
 	if (nla_put_be32(skb, NFTA_HOOK_PRIORITY, htonl(ops->priority)))
 		goto nla_put_failure;
 
-	if (family == NFPROTO_NETDEV) {
+	if (nft_base_chain_netdev(family, ops->hooknum)) {
 		nest_devs = nla_nest_start_noflag(skb, NFTA_HOOK_DEVS);
 		list_for_each_entry(hook, &basechain->hook_list, list) {
 			if (!first)
@@ -1685,7 +1685,7 @@ void nf_tables_chain_destroy(struct nft_ctx *ctx)
 	if (nft_is_base_chain(chain)) {
 		struct nft_base_chain *basechain = nft_base_chain(chain);
 
-		if (ctx->family == NFPROTO_NETDEV) {
+		if (nft_base_chain_netdev(ctx->family, basechain->ops.hooknum)) {
 			list_for_each_entry_safe(hook, next,
 						 &basechain->hook_list, list) {
 				list_del_rcu(&hook->list);
@@ -1877,7 +1877,7 @@ static int nft_chain_parse_hook(struct net *net,
 	hook->type = type;
 
 	INIT_LIST_HEAD(&hook->list);
-	if (family == NFPROTO_NETDEV) {
+	if (nft_base_chain_netdev(family, hook->num)) {
 		err = nft_chain_parse_netdev(net, ha, &hook->list);
 		if (err < 0) {
 			module_put(type->owner);
@@ -1944,7 +1944,7 @@ static int nft_basechain_init(struct nft_base_chain *basechain, u8 family,
 	INIT_LIST_HEAD(&basechain->hook_list);
 	chain = &basechain->chain;
 
-	if (family == NFPROTO_NETDEV) {
+	if (nft_base_chain_netdev(family, hook->num)) {
 		list_splice_init(&hook->list, &basechain->hook_list);
 		list_for_each_entry(h, &basechain->hook_list, list)
 			nft_basechain_hook_init(&h->ops, family, hook, chain);
@@ -2168,7 +2168,7 @@ static int nf_tables_updchain(struct nft_ctx *ctx, u8 genmask, u8 policy,
 			return -EEXIST;
 		}
 
-		if (ctx->family == NFPROTO_NETDEV) {
+		if (nft_base_chain_netdev(ctx->family, hook.num)) {
 			if (!nft_hook_list_equal(&basechain->hook_list,
 						 &hook.list)) {
 				nft_chain_release_hook(&hook);
diff --git a/net/netfilter/nft_chain_filter.c b/net/netfilter/nft_chain_filter.c
index c78d01bc02e9..eb6b8679fe8f 100644
--- a/net/netfilter/nft_chain_filter.c
+++ b/net/netfilter/nft_chain_filter.c
@@ -161,16 +161,49 @@ static unsigned int nft_do_chain_inet(void *priv, struct sk_buff *skb,
 	return nft_do_chain(&pkt, priv);
 }
 
+static unsigned int nft_do_chain_inet_ingress(void *priv, struct sk_buff *skb,
+					      const struct nf_hook_state *state)
+{
+	struct nf_hook_state ingress_state = *state;
+	struct nft_pktinfo pkt;
+
+	switch (skb->protocol) {
+	case htons(ETH_P_IP):
+		/* Original hook is NFPROTO_NETDEV and NF_NETDEV_INGRESS. */
+		ingress_state.pf = NFPROTO_IPV4;
+		ingress_state.hook = NF_INET_INGRESS;
+		nft_set_pktinfo(&pkt, skb, &ingress_state);
+
+		if (nft_set_pktinfo_ipv4_ingress(&pkt, skb) < 0)
+			return NF_DROP;
+		break;
+	case htons(ETH_P_IPV6):
+		ingress_state.pf = NFPROTO_IPV4;
+		ingress_state.hook = NF_INET_INGRESS;
+		nft_set_pktinfo(&pkt, skb, &ingress_state);
+
+		if (nft_set_pktinfo_ipv6_ingress(&pkt, skb) < 0)
+			return NF_DROP;
+		break;
+	default:
+		return NF_ACCEPT;
+	}
+
+	return nft_do_chain(&pkt, priv);
+}
+
 static const struct nft_chain_type nft_chain_filter_inet = {
 	.name		= "filter",
 	.type		= NFT_CHAIN_T_DEFAULT,
 	.family		= NFPROTO_INET,
-	.hook_mask	= (1 << NF_INET_LOCAL_IN) |
+	.hook_mask	= (1 << NF_INET_INGRESS) |
+			  (1 << NF_INET_LOCAL_IN) |
 			  (1 << NF_INET_LOCAL_OUT) |
 			  (1 << NF_INET_FORWARD) |
 			  (1 << NF_INET_PRE_ROUTING) |
 			  (1 << NF_INET_POST_ROUTING),
 	.hooks		= {
+		[NF_INET_INGRESS]	= nft_do_chain_inet_ingress,
 		[NF_INET_LOCAL_IN]	= nft_do_chain_inet,
 		[NF_INET_LOCAL_OUT]	= nft_do_chain_inet,
 		[NF_INET_FORWARD]	= nft_do_chain_inet,
-- 
2.20.1


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

* Re: [PATCH nf-next 0/4] Add nf_tables ingress hook for the inet family
  2020-10-07 23:14 [PATCH nf-next 0/4] Add nf_tables ingress hook for the inet family Pablo Neira Ayuso
                   ` (3 preceding siblings ...)
  2020-10-07 23:14 ` [PATCH nf-next 4/4] netfilter: nf_tables: " Pablo Neira Ayuso
@ 2020-10-07 23:22 ` Pablo Neira Ayuso
  4 siblings, 0 replies; 8+ messages in thread
From: Pablo Neira Ayuso @ 2020-10-07 23:22 UTC (permalink / raw)
  To: netfilter-devel

On Thu, Oct 08, 2020 at 01:14:44AM +0200, Pablo Neira Ayuso wrote:
> Hi,
> 
> The following patchset adds support for the inet ingress hook:
> 
> Patch #1 adds nf_static_key_inc() and nf_static_key_dec() helper functions.
> Patch #2 adds nf_ingress_hook() helper function.
> Patch #3 adds inet ingress hook support to the core.
> Patch #4 adds inet ingress hook support for nf_tables.
> 
> The following example shows how to place offenders into the 'blackhole'
> set. Offenders in this case are those that connect to the local SSH port
> over the specified rate limit. The inet ingress chain is used to
> shortcircuit the evaluation of the traffic coming from the offender at
> early stage in the packet processing receive path.
> 
>   table inet filter {
>         set blackhole {
>                 type ipv4_addr
>                 size 65535
>                 flags dynamic,timeout
>                 timeout 5m
>         }
> 
>         chain input {
>                 type filter hook input priority filter; policy accept;
>                 ct state new tcp dport 22 update @blackhole { ip saddr limit rate over 4/minute } counter packets 0 bytes 0

Actually, this should be:

                  ct state new tcp dport 22 limit rate over 4/minute update @blackhole { ip saddr } counter packets 0 bytes 0

maybe this example is not that useful...

... But the overall idea is to share sets with the ingress hook, which
was not possible so far :-)

>         }
> 
>         chain ingress {
>                 type filter hook unknown device "enp0s25" priority filter; policy accept;
>                 ip saddr @blackhole counter packets 0 bytes 0 drop
>         }
>   }
> 
> Pablo Neira Ayuso (4):
>   netfilter: add nf_static_key_{inc,dec}
>   netfilter: add nf_ingress_hook() helper function
>   netfilter: add inet ingress support
>   netfilter: nf_tables: add inet ingress support
> 
>  include/net/netfilter/nf_tables.h      |   6 ++
>  include/net/netfilter/nf_tables_ipv4.h |  33 +++++++
>  include/net/netfilter/nf_tables_ipv6.h |  46 +++++++++
>  include/uapi/linux/netfilter.h         |   1 +
>  net/netfilter/core.c                   | 127 ++++++++++++++++++++-----
>  net/netfilter/nf_tables_api.c          |  14 +--
>  net/netfilter/nft_chain_filter.c       |  35 ++++++-
>  7 files changed, 228 insertions(+), 34 deletions(-)
> 
> --
> 2.20.1
> 

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

* Re: [PATCH nf-next 3/4] netfilter: add inet ingress support
  2020-10-07 23:14 ` [PATCH nf-next 3/4] netfilter: add inet ingress support Pablo Neira Ayuso
@ 2020-10-08  1:04   ` kernel test robot
  2020-10-08  2:23   ` kernel test robot
  1 sibling, 0 replies; 8+ messages in thread
From: kernel test robot @ 2020-10-08  1:04 UTC (permalink / raw)
  To: Pablo Neira Ayuso, netfilter-devel; +Cc: kbuild-all


[-- Attachment #1: Type: text/plain, Size: 3613 bytes --]

Hi Pablo,

I love your patch! Yet something to improve:

[auto build test ERROR on nf-next/master]

url:    https://github.com/0day-ci/linux/commits/Pablo-Neira-Ayuso/Add-nf_tables-ingress-hook-for-the-inet-family/20201008-071530
base:   https://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next.git master
config: x86_64-randconfig-s022-20201008 (attached as .config)
compiler: gcc-9 (Debian 9.3.0-15) 9.3.0
reproduce:
        # apt-get install sparse
        # sparse version: v0.6.2-218-gc0e96d6d-dirty
        # https://github.com/0day-ci/linux/commit/4a788f545ac2e08b0c08658e156da55e2fce5ae6
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Pablo-Neira-Ayuso/Add-nf_tables-ingress-hook-for-the-inet-family/20201008-071530
        git checkout 4a788f545ac2e08b0c08658e156da55e2fce5ae6
        # save the attached .config to linux build tree
        make W=1 C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' ARCH=x86_64 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All error/warnings (new ones prefixed by >>):

   net/netfilter/core.c: In function 'nf_hook_entry_head':
>> net/netfilter/core.c:292:14: error: 'struct net_device' has no member named 'nf_hooks_ingress'
     292 |   return &dev->nf_hooks_ingress;
         |              ^~
>> net/netfilter/core.c:288:12: warning: this statement may fall through [-Wimplicit-fallthrough=]
     288 |   if (!dev || dev_net(dev) != net) {
         |       ~~~~~^~~~~~~~~~~~~~~~~~~~~~
   net/netfilter/core.c:293:2: note: here
     293 |  case NFPROTO_IPV4:
         |  ^~~~
   At top level:
   net/netfilter/core.c:336:13: warning: 'nf_ingress_hook' defined but not used [-Wunused-function]
     336 | static bool nf_ingress_hook(const struct nf_hook_ops *reg, int pf)
         |             ^~~~~~~~~~~~~~~

vim +292 net/netfilter/core.c

   265	
   266	static struct nf_hook_entries __rcu **
   267	nf_hook_entry_head(struct net *net, int pf, unsigned int hooknum,
   268			   struct net_device *dev)
   269	{
   270		switch (pf) {
   271		case NFPROTO_NETDEV:
   272			break;
   273	#ifdef CONFIG_NETFILTER_FAMILY_ARP
   274		case NFPROTO_ARP:
   275			if (WARN_ON_ONCE(ARRAY_SIZE(net->nf.hooks_arp) <= hooknum))
   276				return NULL;
   277			return net->nf.hooks_arp + hooknum;
   278	#endif
   279	#ifdef CONFIG_NETFILTER_FAMILY_BRIDGE
   280		case NFPROTO_BRIDGE:
   281			if (WARN_ON_ONCE(ARRAY_SIZE(net->nf.hooks_bridge) <= hooknum))
   282				return NULL;
   283			return net->nf.hooks_bridge + hooknum;
   284	#endif
   285		case NFPROTO_INET:
   286			if (WARN_ON_ONCE(hooknum != NF_INET_INGRESS))
   287				return NULL;
 > 288			if (!dev || dev_net(dev) != net) {
   289				WARN_ON_ONCE(1);
   290				return NULL;
   291			}
 > 292			return &dev->nf_hooks_ingress;
   293		case NFPROTO_IPV4:
   294			if (WARN_ON_ONCE(ARRAY_SIZE(net->nf.hooks_ipv4) <= hooknum))
   295				return NULL;
   296			return net->nf.hooks_ipv4 + hooknum;
   297		case NFPROTO_IPV6:
   298			if (WARN_ON_ONCE(ARRAY_SIZE(net->nf.hooks_ipv6) <= hooknum))
   299				return NULL;
   300			return net->nf.hooks_ipv6 + hooknum;
   301	#if IS_ENABLED(CONFIG_DECNET)
   302		case NFPROTO_DECNET:
   303			if (WARN_ON_ONCE(ARRAY_SIZE(net->nf.hooks_decnet) <= hooknum))
   304				return NULL;
   305			return net->nf.hooks_decnet + hooknum;
   306	#endif
   307		default:
   308			WARN_ON_ONCE(1);
   309			return NULL;
   310		}
   311	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 32199 bytes --]

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

* Re: [PATCH nf-next 3/4] netfilter: add inet ingress support
  2020-10-07 23:14 ` [PATCH nf-next 3/4] netfilter: add inet ingress support Pablo Neira Ayuso
  2020-10-08  1:04   ` kernel test robot
@ 2020-10-08  2:23   ` kernel test robot
  1 sibling, 0 replies; 8+ messages in thread
From: kernel test robot @ 2020-10-08  2:23 UTC (permalink / raw)
  To: Pablo Neira Ayuso, netfilter-devel; +Cc: kbuild-all, clang-built-linux


[-- Attachment #1: Type: text/plain, Size: 3319 bytes --]

Hi Pablo,

I love your patch! Yet something to improve:

[auto build test ERROR on nf-next/master]

url:    https://github.com/0day-ci/linux/commits/Pablo-Neira-Ayuso/Add-nf_tables-ingress-hook-for-the-inet-family/20201008-071530
base:   https://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next.git master
config: arm-randconfig-r033-20201008 (attached as .config)
compiler: clang version 12.0.0 (https://github.com/llvm/llvm-project 8da0df3d6dcc0dd42740be60b0da4ec201190904)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # install arm cross compiling tool for clang build
        # apt-get install binutils-arm-linux-gnueabi
        # https://github.com/0day-ci/linux/commit/4a788f545ac2e08b0c08658e156da55e2fce5ae6
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Pablo-Neira-Ayuso/Add-nf_tables-ingress-hook-for-the-inet-family/20201008-071530
        git checkout 4a788f545ac2e08b0c08658e156da55e2fce5ae6
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=arm 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

>> net/netfilter/core.c:292:16: error: no member named 'nf_hooks_ingress' in 'struct net_device'
                   return &dev->nf_hooks_ingress;
                           ~~~  ^
   1 error generated.

vim +292 net/netfilter/core.c

   265	
   266	static struct nf_hook_entries __rcu **
   267	nf_hook_entry_head(struct net *net, int pf, unsigned int hooknum,
   268			   struct net_device *dev)
   269	{
   270		switch (pf) {
   271		case NFPROTO_NETDEV:
   272			break;
   273	#ifdef CONFIG_NETFILTER_FAMILY_ARP
   274		case NFPROTO_ARP:
   275			if (WARN_ON_ONCE(ARRAY_SIZE(net->nf.hooks_arp) <= hooknum))
   276				return NULL;
   277			return net->nf.hooks_arp + hooknum;
   278	#endif
   279	#ifdef CONFIG_NETFILTER_FAMILY_BRIDGE
   280		case NFPROTO_BRIDGE:
   281			if (WARN_ON_ONCE(ARRAY_SIZE(net->nf.hooks_bridge) <= hooknum))
   282				return NULL;
   283			return net->nf.hooks_bridge + hooknum;
   284	#endif
   285		case NFPROTO_INET:
   286			if (WARN_ON_ONCE(hooknum != NF_INET_INGRESS))
   287				return NULL;
   288			if (!dev || dev_net(dev) != net) {
   289				WARN_ON_ONCE(1);
   290				return NULL;
   291			}
 > 292			return &dev->nf_hooks_ingress;
   293		case NFPROTO_IPV4:
   294			if (WARN_ON_ONCE(ARRAY_SIZE(net->nf.hooks_ipv4) <= hooknum))
   295				return NULL;
   296			return net->nf.hooks_ipv4 + hooknum;
   297		case NFPROTO_IPV6:
   298			if (WARN_ON_ONCE(ARRAY_SIZE(net->nf.hooks_ipv6) <= hooknum))
   299				return NULL;
   300			return net->nf.hooks_ipv6 + hooknum;
   301	#if IS_ENABLED(CONFIG_DECNET)
   302		case NFPROTO_DECNET:
   303			if (WARN_ON_ONCE(ARRAY_SIZE(net->nf.hooks_decnet) <= hooknum))
   304				return NULL;
   305			return net->nf.hooks_decnet + hooknum;
   306	#endif
   307		default:
   308			WARN_ON_ONCE(1);
   309			return NULL;
   310		}
   311	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 34912 bytes --]

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

end of thread, back to index

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-10-07 23:14 [PATCH nf-next 0/4] Add nf_tables ingress hook for the inet family Pablo Neira Ayuso
2020-10-07 23:14 ` [PATCH nf-next 1/4] netfilter: add nf_static_key_{inc,dec} Pablo Neira Ayuso
2020-10-07 23:14 ` [PATCH nf-next 2/4] netfilter: add nf_ingress_hook() helper function Pablo Neira Ayuso
2020-10-07 23:14 ` [PATCH nf-next 3/4] netfilter: add inet ingress support Pablo Neira Ayuso
2020-10-08  1:04   ` kernel test robot
2020-10-08  2:23   ` kernel test robot
2020-10-07 23:14 ` [PATCH nf-next 4/4] netfilter: nf_tables: " Pablo Neira Ayuso
2020-10-07 23:22 ` [PATCH nf-next 0/4] Add nf_tables ingress hook for the inet family Pablo Neira Ayuso

Netfilter-Devel Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/netfilter-devel/0 netfilter-devel/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 netfilter-devel netfilter-devel/ https://lore.kernel.org/netfilter-devel \
		netfilter-devel@vger.kernel.org
	public-inbox-index netfilter-devel

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.netfilter-devel


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git