aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2017-11-27 16:50:26 -0500
committerPablo Neira Ayuso <pablo@netfilter.org>2018-01-08 12:10:53 -0500
commitce388f452f0af2013c657dd24be4415d94e7704f (patch)
tree05f43955eee02314af8eab159ccbc2c0363c0c82
parent3f87c08c615f567799b426aff0341ea8010a0ebb (diff)
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>
-rw-r--r--include/linux/netfilter.h3
-rw-r--r--include/linux/netfilter_ipv4.h8
-rw-r--r--include/linux/netfilter_ipv6.h3
-rw-r--r--net/bridge/netfilter/nf_tables_bridge.c7
-rw-r--r--net/ipv4/netfilter.c8
-rw-r--r--net/ipv6/netfilter.c6
-rw-r--r--net/netfilter/nf_queue.c4
-rw-r--r--net/netfilter/utils.c19
8 files changed, 39 insertions, 19 deletions
diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
index 02c35eabd348..8358e717eabd 100644
--- a/include/linux/netfilter.h
+++ b/include/linux/netfilter.h
@@ -311,8 +311,6 @@ struct nf_queue_entry;
311 311
312struct nf_afinfo { 312struct nf_afinfo {
313 unsigned short family; 313 unsigned short family;
314 int (*reroute)(struct net *net, struct sk_buff *skb,
315 const struct nf_queue_entry *entry);
316 int route_key_size; 314 int route_key_size;
317}; 315};
318 316
@@ -331,6 +329,7 @@ __sum16 nf_checksum_partial(struct sk_buff *skb, unsigned int hook,
331 u_int8_t protocol, unsigned short family); 329 u_int8_t protocol, unsigned short family);
332int nf_route(struct net *net, struct dst_entry **dst, struct flowi *fl, 330int nf_route(struct net *net, struct dst_entry **dst, struct flowi *fl,
333 bool strict, unsigned short family); 331 bool strict, unsigned short family);
332int nf_reroute(struct sk_buff *skb, struct nf_queue_entry *entry);
334 333
335int nf_register_afinfo(const struct nf_afinfo *afinfo); 334int nf_register_afinfo(const struct nf_afinfo *afinfo);
336void nf_unregister_afinfo(const struct nf_afinfo *afinfo); 335void nf_unregister_afinfo(const struct nf_afinfo *afinfo);
diff --git a/include/linux/netfilter_ipv4.h b/include/linux/netfilter_ipv4.h
index 2a4e2c415647..b31dabfdb453 100644
--- a/include/linux/netfilter_ipv4.h
+++ b/include/linux/netfilter_ipv4.h
@@ -18,6 +18,8 @@ struct ip_rt_info {
18 18
19int ip_route_me_harder(struct net *net, struct sk_buff *skb, unsigned addr_type); 19int ip_route_me_harder(struct net *net, struct sk_buff *skb, unsigned addr_type);
20 20
21struct nf_queue_entry;
22
21#ifdef CONFIG_INET 23#ifdef CONFIG_INET
22__sum16 nf_ip_checksum(struct sk_buff *skb, unsigned int hook, 24__sum16 nf_ip_checksum(struct sk_buff *skb, unsigned int hook,
23 unsigned int dataoff, u_int8_t protocol); 25 unsigned int dataoff, u_int8_t protocol);
@@ -26,6 +28,7 @@ __sum16 nf_ip_checksum_partial(struct sk_buff *skb, unsigned int hook,
26 u_int8_t protocol); 28 u_int8_t protocol);
27int nf_ip_route(struct net *net, struct dst_entry **dst, struct flowi *fl, 29int nf_ip_route(struct net *net, struct dst_entry **dst, struct flowi *fl,
28 bool strict); 30 bool strict);
31int nf_ip_reroute(struct sk_buff *skb, const struct nf_queue_entry *entry);
29#else 32#else
30static inline __sum16 nf_ip_checksum(struct sk_buff *skb, unsigned int hook, 33static inline __sum16 nf_ip_checksum(struct sk_buff *skb, unsigned int hook,
31 unsigned int dataoff, u_int8_t protocol) 34 unsigned int dataoff, u_int8_t protocol)
@@ -45,6 +48,11 @@ static inline int nf_ip_route(struct net *net, struct dst_entry **dst,
45{ 48{
46 return -EOPNOTSUPP; 49 return -EOPNOTSUPP;
47} 50}
51static inline int nf_ip_reroute(struct sk_buff *skb,
52 const struct nf_queue_entry *entry)
53{
54 return -EOPNOTSUPP;
55}
48#endif /* CONFIG_INET */ 56#endif /* CONFIG_INET */
49 57
50#endif /*__LINUX_IP_NETFILTER_H*/ 58#endif /*__LINUX_IP_NETFILTER_H*/
diff --git a/include/linux/netfilter_ipv6.h b/include/linux/netfilter_ipv6.h
index e5700bb314a1..288c597e75b3 100644
--- a/include/linux/netfilter_ipv6.h
+++ b/include/linux/netfilter_ipv6.h
@@ -18,6 +18,8 @@ struct ip6_rt_info {
18 u_int32_t mark; 18 u_int32_t mark;
19}; 19};
20 20
21struct nf_queue_entry;
22
21/* 23/*
22 * Hook functions for ipv6 to allow xt_* modules to be built-in even 24 * Hook functions for ipv6 to allow xt_* modules to be built-in even
23 * if IPv6 is a module. 25 * if IPv6 is a module.
@@ -35,6 +37,7 @@ struct nf_ipv6_ops {
35 u_int8_t protocol); 37 u_int8_t protocol);
36 int (*route)(struct net *net, struct dst_entry **dst, struct flowi *fl, 38 int (*route)(struct net *net, struct dst_entry **dst, struct flowi *fl,
37 bool strict); 39 bool strict);
40 int (*reroute)(struct sk_buff *skb, const struct nf_queue_entry *entry);
38}; 41};
39 42
40#ifdef CONFIG_NETFILTER 43#ifdef CONFIG_NETFILTER
diff --git a/net/bridge/netfilter/nf_tables_bridge.c b/net/bridge/netfilter/nf_tables_bridge.c
index 014b6571f2ac..e7348b49bc0d 100644
--- 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_bridge = {
95 }, 95 },
96}; 96};
97 97
98static int nf_br_reroute(struct net *net, struct sk_buff *skb,
99 const struct nf_queue_entry *entry)
100{
101 return 0;
102}
103
104static const struct nf_afinfo nf_br_afinfo = { 98static const struct nf_afinfo nf_br_afinfo = {
105 .family = AF_BRIDGE, 99 .family = AF_BRIDGE,
106 .reroute = nf_br_reroute,
107 .route_key_size = 0, 100 .route_key_size = 0,
108}; 101};
109 102
diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c
index e9d47e4ec182..ec73be3b2f14 100644
--- a/net/ipv4/netfilter.c
+++ b/net/ipv4/netfilter.c
@@ -80,8 +80,7 @@ int ip_route_me_harder(struct net *net, struct sk_buff *skb, unsigned int addr_t
80} 80}
81EXPORT_SYMBOL(ip_route_me_harder); 81EXPORT_SYMBOL(ip_route_me_harder);
82 82
83static int nf_ip_reroute(struct net *net, struct sk_buff *skb, 83int nf_ip_reroute(struct sk_buff *skb, const struct nf_queue_entry *entry)
84 const struct nf_queue_entry *entry)
85{ 84{
86 const struct ip_rt_info *rt_info = nf_queue_entry_reroute(entry); 85 const struct ip_rt_info *rt_info = nf_queue_entry_reroute(entry);
87 86
@@ -92,10 +91,12 @@ static int nf_ip_reroute(struct net *net, struct sk_buff *skb,
92 skb->mark == rt_info->mark && 91 skb->mark == rt_info->mark &&
93 iph->daddr == rt_info->daddr && 92 iph->daddr == rt_info->daddr &&
94 iph->saddr == rt_info->saddr)) 93 iph->saddr == rt_info->saddr))
95 return ip_route_me_harder(net, skb, RTN_UNSPEC); 94 return ip_route_me_harder(entry->state.net, skb,
95 RTN_UNSPEC);
96 } 96 }
97 return 0; 97 return 0;
98} 98}
99EXPORT_SYMBOL_GPL(nf_ip_reroute);
99 100
100__sum16 nf_ip_checksum(struct sk_buff *skb, unsigned int hook, 101__sum16 nf_ip_checksum(struct sk_buff *skb, unsigned int hook,
101 unsigned int dataoff, u_int8_t protocol) 102 unsigned int dataoff, u_int8_t protocol)
@@ -163,7 +164,6 @@ EXPORT_SYMBOL_GPL(nf_ip_route);
163 164
164static const struct nf_afinfo nf_ip_afinfo = { 165static const struct nf_afinfo nf_ip_afinfo = {
165 .family = AF_INET, 166 .family = AF_INET,
166 .reroute = nf_ip_reroute,
167 .route_key_size = sizeof(struct ip_rt_info), 167 .route_key_size = sizeof(struct ip_rt_info),
168}; 168};
169 169
diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c
index f03bb043e4e4..d633b78be06f 100644
--- a/net/ipv6/netfilter.c
+++ b/net/ipv6/netfilter.c
@@ -68,7 +68,7 @@ int ip6_route_me_harder(struct net *net, struct sk_buff *skb)
68} 68}
69EXPORT_SYMBOL(ip6_route_me_harder); 69EXPORT_SYMBOL(ip6_route_me_harder);
70 70
71static int nf_ip6_reroute(struct net *net, struct sk_buff *skb, 71static int nf_ip6_reroute(struct sk_buff *skb,
72 const struct nf_queue_entry *entry) 72 const struct nf_queue_entry *entry)
73{ 73{
74 struct ip6_rt_info *rt_info = nf_queue_entry_reroute(entry); 74 struct ip6_rt_info *rt_info = nf_queue_entry_reroute(entry);
@@ -78,7 +78,7 @@ static int nf_ip6_reroute(struct net *net, struct sk_buff *skb,
78 if (!ipv6_addr_equal(&iph->daddr, &rt_info->daddr) || 78 if (!ipv6_addr_equal(&iph->daddr, &rt_info->daddr) ||
79 !ipv6_addr_equal(&iph->saddr, &rt_info->saddr) || 79 !ipv6_addr_equal(&iph->saddr, &rt_info->saddr) ||
80 skb->mark != rt_info->mark) 80 skb->mark != rt_info->mark)
81 return ip6_route_me_harder(net, skb); 81 return ip6_route_me_harder(entry->state.net, skb);
82 } 82 }
83 return 0; 83 return 0;
84} 84}
@@ -171,11 +171,11 @@ static const struct nf_ipv6_ops ipv6ops = {
171 .checksum = nf_ip6_checksum, 171 .checksum = nf_ip6_checksum,
172 .checksum_partial = nf_ip6_checksum_partial, 172 .checksum_partial = nf_ip6_checksum_partial,
173 .route = nf_ip6_route, 173 .route = nf_ip6_route,
174 .reroute = nf_ip6_reroute,
174}; 175};
175 176
176static const struct nf_afinfo nf_ip6_afinfo = { 177static const struct nf_afinfo nf_ip6_afinfo = {
177 .family = AF_INET6, 178 .family = AF_INET6,
178 .reroute = nf_ip6_reroute,
179 .route_key_size = sizeof(struct ip6_rt_info), 179 .route_key_size = sizeof(struct ip6_rt_info),
180}; 180};
181 181
diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c
index dfa35bd292c8..15382ff83e7a 100644
--- a/net/netfilter/nf_queue.c
+++ b/net/netfilter/nf_queue.c
@@ -266,7 +266,6 @@ void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict)
266 const struct nf_hook_entry *hook_entry; 266 const struct nf_hook_entry *hook_entry;
267 const struct nf_hook_entries *hooks; 267 const struct nf_hook_entries *hooks;
268 struct sk_buff *skb = entry->skb; 268 struct sk_buff *skb = entry->skb;
269 const struct nf_afinfo *afinfo;
270 const struct net *net; 269 const struct net *net;
271 unsigned int i; 270 unsigned int i;
272 int err; 271 int err;
@@ -293,8 +292,7 @@ void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict)
293 verdict = nf_hook_entry_hookfn(hook_entry, skb, &entry->state); 292 verdict = nf_hook_entry_hookfn(hook_entry, skb, &entry->state);
294 293
295 if (verdict == NF_ACCEPT) { 294 if (verdict == NF_ACCEPT) {
296 afinfo = nf_get_afinfo(entry->state.pf); 295 if (nf_reroute(skb, entry) < 0)
297 if (!afinfo || afinfo->reroute(entry->state.net, skb, entry) < 0)
298 verdict = NF_DROP; 296 verdict = NF_DROP;
299 } 297 }
300 298
diff --git a/net/netfilter/utils.c b/net/netfilter/utils.c
index 45c22418c955..0b660c568156 100644
--- a/net/netfilter/utils.c
+++ b/net/netfilter/utils.c
@@ -2,6 +2,7 @@
2#include <linux/netfilter.h> 2#include <linux/netfilter.h>
3#include <linux/netfilter_ipv4.h> 3#include <linux/netfilter_ipv4.h>
4#include <linux/netfilter_ipv6.h> 4#include <linux/netfilter_ipv6.h>
5#include <net/netfilter/nf_queue.h>
5 6
6__sum16 nf_checksum(struct sk_buff *skb, unsigned int hook, 7__sum16 nf_checksum(struct sk_buff *skb, unsigned int hook,
7 unsigned int dataoff, u_int8_t protocol, 8 unsigned int dataoff, u_int8_t protocol,
@@ -69,3 +70,21 @@ int nf_route(struct net *net, struct dst_entry **dst, struct flowi *fl,
69 return ret; 70 return ret;
70} 71}
71EXPORT_SYMBOL_GPL(nf_route); 72EXPORT_SYMBOL_GPL(nf_route);
73
74int nf_reroute(struct sk_buff *skb, struct nf_queue_entry *entry)
75{
76 const struct nf_ipv6_ops *v6ops;
77 int ret = 0;
78
79 switch (entry->state.pf) {
80 case AF_INET:
81 ret = nf_ip_reroute(skb, entry);
82 break;
83 case AF_INET6:
84 v6ops = rcu_dereference(nf_ipv6_ops);
85 if (v6ops)
86 ret = v6ops->reroute(skb, entry);
87 break;
88 }
89 return ret;
90}