aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/generic/backport-4.14/308-v4.16-netfilter-move-reroute-indirection-to-struct-nf_ipv6.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/generic/backport-4.14/308-v4.16-netfilter-move-reroute-indirection-to-struct-nf_ipv6.patch')
-rw-r--r--target/linux/generic/backport-4.14/308-v4.16-netfilter-move-reroute-indirection-to-struct-nf_ipv6.patch223
1 files changed, 223 insertions, 0 deletions
diff --git a/target/linux/generic/backport-4.14/308-v4.16-netfilter-move-reroute-indirection-to-struct-nf_ipv6.patch b/target/linux/generic/backport-4.14/308-v4.16-netfilter-move-reroute-indirection-to-struct-nf_ipv6.patch
new file mode 100644
index 0000000000..2ffb39d9af
--- /dev/null
+++ b/target/linux/generic/backport-4.14/308-v4.16-netfilter-move-reroute-indirection-to-struct-nf_ipv6.patch
@@ -0,0 +1,223 @@
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+Date: Mon, 27 Nov 2017 22:50:26 +0100
+Subject: [PATCH] netfilter: move reroute indirection to struct nf_ipv6_ops
+
+We cannot make a direct call to nf_ip6_reroute() because that would result
+in autoloading the 'ipv6' module because of symbol dependencies.
+Therefore, define reroute indirection in nf_ipv6_ops where this really
+belongs to.
+
+For IPv4, we can indeed make a direct function call, which is faster,
+given IPv4 is built-in in the networking code by default. Still,
+CONFIG_INET=n and CONFIG_NETFILTER=y is possible, so define empty inline
+stub for IPv4 in such case.
+
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+---
+
+--- a/include/linux/netfilter.h
++++ b/include/linux/netfilter.h
+@@ -274,8 +274,6 @@ struct nf_queue_entry;
+
+ struct nf_afinfo {
+ unsigned short family;
+- int (*reroute)(struct net *net, struct sk_buff *skb,
+- const struct nf_queue_entry *entry);
+ int route_key_size;
+ };
+
+@@ -294,6 +292,7 @@ __sum16 nf_checksum_partial(struct sk_bu
+ u_int8_t protocol, unsigned short family);
+ int nf_route(struct net *net, struct dst_entry **dst, struct flowi *fl,
+ bool strict, unsigned short family);
++int nf_reroute(struct sk_buff *skb, struct nf_queue_entry *entry);
+
+ int nf_register_afinfo(const struct nf_afinfo *afinfo);
+ void nf_unregister_afinfo(const struct nf_afinfo *afinfo);
+--- a/include/linux/netfilter_ipv4.h
++++ b/include/linux/netfilter_ipv4.h
+@@ -18,6 +18,8 @@ struct ip_rt_info {
+
+ int ip_route_me_harder(struct net *net, struct sk_buff *skb, unsigned addr_type);
+
++struct nf_queue_entry;
++
+ #ifdef CONFIG_INET
+ __sum16 nf_ip_checksum(struct sk_buff *skb, unsigned int hook,
+ unsigned int dataoff, u_int8_t protocol);
+@@ -26,6 +28,7 @@ __sum16 nf_ip_checksum_partial(struct sk
+ u_int8_t protocol);
+ int nf_ip_route(struct net *net, struct dst_entry **dst, struct flowi *fl,
+ bool strict);
++int nf_ip_reroute(struct sk_buff *skb, const struct nf_queue_entry *entry);
+ #else
+ static inline __sum16 nf_ip_checksum(struct sk_buff *skb, unsigned int hook,
+ unsigned int dataoff, u_int8_t protocol)
+@@ -45,6 +48,11 @@ static inline int nf_ip_route(struct net
+ {
+ return -EOPNOTSUPP;
+ }
++static inline int nf_ip_reroute(struct sk_buff *skb,
++ const struct nf_queue_entry *entry)
++{
++ return -EOPNOTSUPP;
++}
+ #endif /* CONFIG_INET */
+
+ #endif /*__LINUX_IP_NETFILTER_H*/
+--- a/include/linux/netfilter_ipv6.h
++++ b/include/linux/netfilter_ipv6.h
+@@ -18,6 +18,8 @@ struct ip6_rt_info {
+ u_int32_t mark;
+ };
+
++struct nf_queue_entry;
++
+ /*
+ * Hook functions for ipv6 to allow xt_* modules to be built-in even
+ * if IPv6 is a module.
+@@ -35,6 +37,7 @@ struct nf_ipv6_ops {
+ u_int8_t protocol);
+ int (*route)(struct net *net, struct dst_entry **dst, struct flowi *fl,
+ bool strict);
++ int (*reroute)(struct sk_buff *skb, const struct nf_queue_entry *entry);
+ };
+
+ #ifdef CONFIG_NETFILTER
+--- a/net/bridge/netfilter/nf_tables_bridge.c
++++ b/net/bridge/netfilter/nf_tables_bridge.c
+@@ -95,15 +95,8 @@ static const struct nf_chain_type filter
+ (1 << NF_BR_POST_ROUTING),
+ };
+
+-static int nf_br_reroute(struct net *net, struct sk_buff *skb,
+- const struct nf_queue_entry *entry)
+-{
+- return 0;
+-}
+-
+ static const struct nf_afinfo nf_br_afinfo = {
+ .family = AF_BRIDGE,
+- .reroute = nf_br_reroute,
+ .route_key_size = 0,
+ };
+
+--- a/net/ipv4/netfilter.c
++++ b/net/ipv4/netfilter.c
+@@ -80,8 +80,7 @@ int ip_route_me_harder(struct net *net,
+ }
+ EXPORT_SYMBOL(ip_route_me_harder);
+
+-static int nf_ip_reroute(struct net *net, struct sk_buff *skb,
+- const struct nf_queue_entry *entry)
++int nf_ip_reroute(struct sk_buff *skb, const struct nf_queue_entry *entry)
+ {
+ const struct ip_rt_info *rt_info = nf_queue_entry_reroute(entry);
+
+@@ -92,10 +91,12 @@ static int nf_ip_reroute(struct net *net
+ skb->mark == rt_info->mark &&
+ iph->daddr == rt_info->daddr &&
+ iph->saddr == rt_info->saddr))
+- return ip_route_me_harder(net, skb, RTN_UNSPEC);
++ return ip_route_me_harder(entry->state.net, skb,
++ RTN_UNSPEC);
+ }
+ return 0;
+ }
++EXPORT_SYMBOL_GPL(nf_ip_reroute);
+
+ __sum16 nf_ip_checksum(struct sk_buff *skb, unsigned int hook,
+ unsigned int dataoff, u_int8_t protocol)
+@@ -163,7 +164,6 @@ EXPORT_SYMBOL_GPL(nf_ip_route);
+
+ static const struct nf_afinfo nf_ip_afinfo = {
+ .family = AF_INET,
+- .reroute = nf_ip_reroute,
+ .route_key_size = sizeof(struct ip_rt_info),
+ };
+
+--- a/net/ipv6/netfilter.c
++++ b/net/ipv6/netfilter.c
+@@ -69,7 +69,7 @@ int ip6_route_me_harder(struct net *net,
+ }
+ EXPORT_SYMBOL(ip6_route_me_harder);
+
+-static int nf_ip6_reroute(struct net *net, struct sk_buff *skb,
++static int nf_ip6_reroute(struct sk_buff *skb,
+ const struct nf_queue_entry *entry)
+ {
+ struct ip6_rt_info *rt_info = nf_queue_entry_reroute(entry);
+@@ -79,7 +79,7 @@ static int nf_ip6_reroute(struct net *ne
+ if (!ipv6_addr_equal(&iph->daddr, &rt_info->daddr) ||
+ !ipv6_addr_equal(&iph->saddr, &rt_info->saddr) ||
+ skb->mark != rt_info->mark)
+- return ip6_route_me_harder(net, skb);
++ return ip6_route_me_harder(entry->state.net, skb);
+ }
+ return 0;
+ }
+@@ -172,11 +172,11 @@ static const struct nf_ipv6_ops ipv6ops
+ .checksum = nf_ip6_checksum,
+ .checksum_partial = nf_ip6_checksum_partial,
+ .route = nf_ip6_route,
++ .reroute = nf_ip6_reroute,
+ };
+
+ static const struct nf_afinfo nf_ip6_afinfo = {
+ .family = AF_INET6,
+- .reroute = nf_ip6_reroute,
+ .route_key_size = sizeof(struct ip6_rt_info),
+ };
+
+--- a/net/netfilter/nf_queue.c
++++ b/net/netfilter/nf_queue.c
+@@ -250,7 +250,6 @@ void nf_reinject(struct nf_queue_entry *
+ const struct nf_hook_entry *hook_entry;
+ const struct nf_hook_entries *hooks;
+ struct sk_buff *skb = entry->skb;
+- const struct nf_afinfo *afinfo;
+ const struct net *net;
+ unsigned int i;
+ int err;
+@@ -277,8 +276,7 @@ void nf_reinject(struct nf_queue_entry *
+ verdict = nf_hook_entry_hookfn(hook_entry, skb, &entry->state);
+
+ if (verdict == NF_ACCEPT) {
+- afinfo = nf_get_afinfo(entry->state.pf);
+- if (!afinfo || afinfo->reroute(entry->state.net, skb, entry) < 0)
++ if (nf_reroute(skb, entry) < 0)
+ verdict = NF_DROP;
+ }
+
+--- a/net/netfilter/utils.c
++++ b/net/netfilter/utils.c
+@@ -2,6 +2,7 @@
+ #include <linux/netfilter.h>
+ #include <linux/netfilter_ipv4.h>
+ #include <linux/netfilter_ipv6.h>
++#include <net/netfilter/nf_queue.h>
+
+ __sum16 nf_checksum(struct sk_buff *skb, unsigned int hook,
+ unsigned int dataoff, u_int8_t protocol,
+@@ -69,3 +70,21 @@ int nf_route(struct net *net, struct dst
+ return ret;
+ }
+ EXPORT_SYMBOL_GPL(nf_route);
++
++int nf_reroute(struct sk_buff *skb, struct nf_queue_entry *entry)
++{
++ const struct nf_ipv6_ops *v6ops;
++ int ret = 0;
++
++ switch (entry->state.pf) {
++ case AF_INET:
++ ret = nf_ip_reroute(skb, entry);
++ break;
++ case AF_INET6:
++ v6ops = rcu_dereference(nf_ipv6_ops);
++ if (v6ops)
++ ret = v6ops->reroute(skb, entry);
++ break;
++ }
++ return ret;
++}