aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Engelhardt <jengelh@medozas.de>2010-04-19 10:06:52 -0400
committerPatrick McHardy <kaber@trash.net>2010-04-19 10:06:52 -0400
commitcd58bcd9787ef4c16ab6e442c4f1bf3539b3ab39 (patch)
tree949741c18227ae46f841501507ad440f35e659e5
parentf3c5c1bfd430858d3a05436f82c51e53104feb6b (diff)
netfilter: xt_TEE: have cloned packet travel through Xtables too
Since Xtables is now reentrant/nestable, the cloned packet can also go through Xtables and be subject to rules itself. Signed-off-by: Jan Engelhardt <jengelh@medozas.de> Signed-off-by: Patrick McHardy <kaber@trash.net>
-rw-r--r--net/ipv4/ip_output.c1
-rw-r--r--net/ipv6/ip6_output.c1
-rw-r--r--net/netfilter/xt_TEE.c40
3 files changed, 18 insertions, 24 deletions
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 0abfddec1e26..f09135e1e14f 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -309,7 +309,6 @@ int ip_output(struct sk_buff *skb)
309 ip_finish_output, 309 ip_finish_output,
310 !(IPCB(skb)->flags & IPSKB_REROUTED)); 310 !(IPCB(skb)->flags & IPSKB_REROUTED));
311} 311}
312EXPORT_SYMBOL_GPL(ip_output);
313 312
314int ip_queue_xmit(struct sk_buff *skb, int ipfragok) 313int ip_queue_xmit(struct sk_buff *skb, int ipfragok)
315{ 314{
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index d09be7ff8735..c10a38a71a5e 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -176,7 +176,6 @@ int ip6_output(struct sk_buff *skb)
176 ip6_finish_output, 176 ip6_finish_output,
177 !(IP6CB(skb)->flags & IP6SKB_REROUTED)); 177 !(IP6CB(skb)->flags & IP6SKB_REROUTED));
178} 178}
179EXPORT_SYMBOL_GPL(ip6_output);
180 179
181/* 180/*
182 * xmit an sk_buff (used by TCP) 181 * xmit an sk_buff (used by TCP)
diff --git a/net/netfilter/xt_TEE.c b/net/netfilter/xt_TEE.c
index b3d730163f12..842e7012eca7 100644
--- a/net/netfilter/xt_TEE.c
+++ b/net/netfilter/xt_TEE.c
@@ -12,6 +12,7 @@
12 */ 12 */
13#include <linux/ip.h> 13#include <linux/ip.h>
14#include <linux/module.h> 14#include <linux/module.h>
15#include <linux/percpu.h>
15#include <linux/route.h> 16#include <linux/route.h>
16#include <linux/skbuff.h> 17#include <linux/skbuff.h>
17#include <net/checksum.h> 18#include <net/checksum.h>
@@ -32,6 +33,7 @@
32#endif 33#endif
33 34
34static const union nf_inet_addr tee_zero_address; 35static const union nf_inet_addr tee_zero_address;
36static DEFINE_PER_CPU(bool, tee_active);
35 37
36static struct net *pick_net(struct sk_buff *skb) 38static struct net *pick_net(struct sk_buff *skb)
37{ 39{
@@ -91,6 +93,8 @@ tee_tg4(struct sk_buff *skb, const struct xt_target_param *par)
91 const struct xt_tee_tginfo *info = par->targinfo; 93 const struct xt_tee_tginfo *info = par->targinfo;
92 struct iphdr *iph; 94 struct iphdr *iph;
93 95
96 if (percpu_read(tee_active))
97 return XT_CONTINUE;
94 /* 98 /*
95 * Copy the skb, and route the copy. Will later return %XT_CONTINUE for 99 * Copy the skb, and route the copy. Will later return %XT_CONTINUE for
96 * the original skb, which should continue on its way as if nothing has 100 * the original skb, which should continue on its way as if nothing has
@@ -125,24 +129,13 @@ tee_tg4(struct sk_buff *skb, const struct xt_target_param *par)
125 --iph->ttl; 129 --iph->ttl;
126 ip_send_check(iph); 130 ip_send_check(iph);
127 131
128 /* 132 if (tee_tg_route4(skb, info)) {
129 * Xtables is not reentrant currently, so a choice has to be made: 133 percpu_write(tee_active, true);
130 * 1. return absolute verdict for the original and let the cloned 134 ip_local_out(skb);
131 * packet travel through the chains 135 percpu_write(tee_active, false);
132 * 2. let the original continue travelling and not pass the clone 136 } else {
133 * to Xtables.
134 * #2 is chosen. Normally, we would use ip_local_out for the clone.
135 * Because iph->check is already correct and we don't pass it to
136 * Xtables anyway, a shortcut to dst_output [forwards to ip_output] can
137 * be taken. %IPSKB_REROUTED needs to be set so that ip_output does not
138 * invoke POSTROUTING on the cloned packet.
139 */
140 IPCB(skb)->flags |= IPSKB_REROUTED;
141 if (tee_tg_route4(skb, info))
142 ip_output(skb);
143 else
144 kfree_skb(skb); 137 kfree_skb(skb);
145 138 }
146 return XT_CONTINUE; 139 return XT_CONTINUE;
147} 140}
148 141
@@ -177,6 +170,8 @@ tee_tg6(struct sk_buff *skb, const struct xt_target_param *par)
177{ 170{
178 const struct xt_tee_tginfo *info = par->targinfo; 171 const struct xt_tee_tginfo *info = par->targinfo;
179 172
173 if (percpu_read(tee_active))
174 return XT_CONTINUE;
180 skb = pskb_copy(skb, GFP_ATOMIC); 175 skb = pskb_copy(skb, GFP_ATOMIC);
181 if (skb == NULL) 176 if (skb == NULL)
182 return XT_CONTINUE; 177 return XT_CONTINUE;
@@ -192,12 +187,13 @@ tee_tg6(struct sk_buff *skb, const struct xt_target_param *par)
192 struct ipv6hdr *iph = ipv6_hdr(skb); 187 struct ipv6hdr *iph = ipv6_hdr(skb);
193 --iph->hop_limit; 188 --iph->hop_limit;
194 } 189 }
195 IP6CB(skb)->flags |= IP6SKB_REROUTED; 190 if (tee_tg_route6(skb, info)) {
196 if (tee_tg_route6(skb, info)) 191 percpu_write(tee_active, true);
197 ip6_output(skb); 192 ip6_local_out(skb);
198 else 193 percpu_write(tee_active, false);
194 } else {
199 kfree_skb(skb); 195 kfree_skb(skb);
200 196 }
201 return XT_CONTINUE; 197 return XT_CONTINUE;
202} 198}
203#endif /* WITH_IPV6 */ 199#endif /* WITH_IPV6 */