aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/netfilter/xt_TEE.h3
-rw-r--r--net/netfilter/xt_TEE.c103
2 files changed, 83 insertions, 23 deletions
diff --git a/include/linux/netfilter/xt_TEE.h b/include/linux/netfilter/xt_TEE.h
index 55d4a5011523..5c21d5c829af 100644
--- a/include/linux/netfilter/xt_TEE.h
+++ b/include/linux/netfilter/xt_TEE.h
@@ -4,6 +4,9 @@
4struct xt_tee_tginfo { 4struct xt_tee_tginfo {
5 union nf_inet_addr gw; 5 union nf_inet_addr gw;
6 char oif[16]; 6 char oif[16];
7
8 /* used internally by the kernel */
9 struct xt_tee_priv *priv __attribute__((aligned(8)));
7}; 10};
8 11
9#endif /* _XT_TEE_TARGET_H */ 12#endif /* _XT_TEE_TARGET_H */
diff --git a/net/netfilter/xt_TEE.c b/net/netfilter/xt_TEE.c
index 842e7012eca7..49da6c05f4e0 100644
--- a/net/netfilter/xt_TEE.c
+++ b/net/netfilter/xt_TEE.c
@@ -15,6 +15,7 @@
15#include <linux/percpu.h> 15#include <linux/percpu.h>
16#include <linux/route.h> 16#include <linux/route.h>
17#include <linux/skbuff.h> 17#include <linux/skbuff.h>
18#include <linux/notifier.h>
18#include <net/checksum.h> 19#include <net/checksum.h>
19#include <net/icmp.h> 20#include <net/icmp.h>
20#include <net/ip.h> 21#include <net/ip.h>
@@ -32,6 +33,12 @@
32# define WITH_IPV6 1 33# define WITH_IPV6 1
33#endif 34#endif
34 35
36struct xt_tee_priv {
37 struct notifier_block notifier;
38 struct xt_tee_tginfo *tginfo;
39 int oif;
40};
41
35static const union nf_inet_addr tee_zero_address; 42static const union nf_inet_addr tee_zero_address;
36static DEFINE_PER_CPU(bool, tee_active); 43static DEFINE_PER_CPU(bool, tee_active);
37 44
@@ -49,20 +56,6 @@ static struct net *pick_net(struct sk_buff *skb)
49 return &init_net; 56 return &init_net;
50} 57}
51 58
52static bool tee_tg_route_oif(struct flowi *f, struct net *net,
53 const struct xt_tee_tginfo *info)
54{
55 const struct net_device *dev;
56
57 if (*info->oif != '\0')
58 return true;
59 dev = dev_get_by_name(net, info->oif);
60 if (dev == NULL)
61 return false;
62 f->oif = dev->ifindex;
63 return true;
64}
65
66static bool 59static bool
67tee_tg_route4(struct sk_buff *skb, const struct xt_tee_tginfo *info) 60tee_tg_route4(struct sk_buff *skb, const struct xt_tee_tginfo *info)
68{ 61{
@@ -72,8 +65,11 @@ tee_tg_route4(struct sk_buff *skb, const struct xt_tee_tginfo *info)
72 struct flowi fl; 65 struct flowi fl;
73 66
74 memset(&fl, 0, sizeof(fl)); 67 memset(&fl, 0, sizeof(fl));
75 if (!tee_tg_route_oif(&fl, net, info)) 68 if (info->priv) {
76 return false; 69 if (info->priv->oif == -1)
70 return false;
71 fl.oif = info->priv->oif;
72 }
77 fl.nl_u.ip4_u.daddr = info->gw.ip; 73 fl.nl_u.ip4_u.daddr = info->gw.ip;
78 fl.nl_u.ip4_u.tos = RT_TOS(iph->tos); 74 fl.nl_u.ip4_u.tos = RT_TOS(iph->tos);
79 fl.nl_u.ip4_u.scope = RT_SCOPE_UNIVERSE; 75 fl.nl_u.ip4_u.scope = RT_SCOPE_UNIVERSE;
@@ -149,8 +145,11 @@ tee_tg_route6(struct sk_buff *skb, const struct xt_tee_tginfo *info)
149 struct flowi fl; 145 struct flowi fl;
150 146
151 memset(&fl, 0, sizeof(fl)); 147 memset(&fl, 0, sizeof(fl));
152 if (!tee_tg_route_oif(&fl, net, info)) 148 if (info->priv) {
153 return false; 149 if (info->priv->oif == -1)
150 return false;
151 fl.oif = info->priv->oif;
152 }
154 fl.nl_u.ip6_u.daddr = info->gw.in6; 153 fl.nl_u.ip6_u.daddr = info->gw.in6;
155 fl.nl_u.ip6_u.flowlabel = ((iph->flow_lbl[0] & 0xF) << 16) | 154 fl.nl_u.ip6_u.flowlabel = ((iph->flow_lbl[0] & 0xF) << 16) |
156 (iph->flow_lbl[1] << 8) | iph->flow_lbl[2]; 155 (iph->flow_lbl[1] << 8) | iph->flow_lbl[2];
@@ -198,15 +197,71 @@ tee_tg6(struct sk_buff *skb, const struct xt_target_param *par)
198} 197}
199#endif /* WITH_IPV6 */ 198#endif /* WITH_IPV6 */
200 199
200static int tee_netdev_event(struct notifier_block *this, unsigned long event,
201 void *ptr)
202{
203 struct net_device *dev = ptr;
204 struct xt_tee_priv *priv;
205
206 priv = container_of(this, struct xt_tee_priv, notifier);
207 switch (event) {
208 case NETDEV_REGISTER:
209 if (!strcmp(dev->name, priv->tginfo->oif))
210 priv->oif = dev->ifindex;
211 break;
212 case NETDEV_UNREGISTER:
213 if (dev->ifindex == priv->oif)
214 priv->oif = -1;
215 break;
216 case NETDEV_CHANGENAME:
217 if (!strcmp(dev->name, priv->tginfo->oif))
218 priv->oif = dev->ifindex;
219 else if (dev->ifindex == priv->oif)
220 priv->oif = -1;
221 break;
222 }
223
224 return NOTIFY_DONE;
225}
226
201static int tee_tg_check(const struct xt_tgchk_param *par) 227static int tee_tg_check(const struct xt_tgchk_param *par)
202{ 228{
203 const struct xt_tee_tginfo *info = par->targinfo; 229 struct xt_tee_tginfo *info = par->targinfo;
230 struct xt_tee_priv *priv;
204 231
205 if (info->oif[sizeof(info->oif)-1] != '\0')
206 return -EINVAL;
207 /* 0.0.0.0 and :: not allowed */ 232 /* 0.0.0.0 and :: not allowed */
208 return (memcmp(&info->gw, &tee_zero_address, 233 if (memcmp(&info->gw, &tee_zero_address,
209 sizeof(tee_zero_address)) == 0) ? -EINVAL : 0; 234 sizeof(tee_zero_address)) == 0)
235 return -EINVAL;
236
237 if (info->oif[0]) {
238 if (info->oif[sizeof(info->oif)-1] != '\0')
239 return -EINVAL;
240
241 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
242 if (priv == NULL)
243 return -ENOMEM;
244
245 priv->tginfo = info;
246 priv->oif = -1;
247 priv->notifier.notifier_call = tee_netdev_event;
248 info->priv = priv;
249
250 register_netdevice_notifier(&priv->notifier);
251 } else
252 info->priv = NULL;
253
254 return 0;
255}
256
257static void tee_tg_destroy(const struct xt_tgdtor_param *par)
258{
259 struct xt_tee_tginfo *info = par->targinfo;
260
261 if (info->priv) {
262 unregister_netdevice_notifier(&info->priv->notifier);
263 kfree(info->priv);
264 }
210} 265}
211 266
212static struct xt_target tee_tg_reg[] __read_mostly = { 267static struct xt_target tee_tg_reg[] __read_mostly = {
@@ -217,6 +272,7 @@ static struct xt_target tee_tg_reg[] __read_mostly = {
217 .target = tee_tg4, 272 .target = tee_tg4,
218 .targetsize = sizeof(struct xt_tee_tginfo), 273 .targetsize = sizeof(struct xt_tee_tginfo),
219 .checkentry = tee_tg_check, 274 .checkentry = tee_tg_check,
275 .destroy = tee_tg_destroy,
220 .me = THIS_MODULE, 276 .me = THIS_MODULE,
221 }, 277 },
222#ifdef WITH_IPV6 278#ifdef WITH_IPV6
@@ -227,6 +283,7 @@ static struct xt_target tee_tg_reg[] __read_mostly = {
227 .target = tee_tg6, 283 .target = tee_tg6,
228 .targetsize = sizeof(struct xt_tee_tginfo), 284 .targetsize = sizeof(struct xt_tee_tginfo),
229 .checkentry = tee_tg_check, 285 .checkentry = tee_tg_check,
286 .destroy = tee_tg_destroy,
230 .me = THIS_MODULE, 287 .me = THIS_MODULE,
231 }, 288 },
232#endif 289#endif