diff options
-rw-r--r-- | include/linux/netfilter/xt_TEE.h | 3 | ||||
-rw-r--r-- | net/netfilter/xt_TEE.c | 103 |
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 @@ | |||
4 | struct xt_tee_tginfo { | 4 | struct 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 | ||
36 | struct xt_tee_priv { | ||
37 | struct notifier_block notifier; | ||
38 | struct xt_tee_tginfo *tginfo; | ||
39 | int oif; | ||
40 | }; | ||
41 | |||
35 | static const union nf_inet_addr tee_zero_address; | 42 | static const union nf_inet_addr tee_zero_address; |
36 | static DEFINE_PER_CPU(bool, tee_active); | 43 | static 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 | ||
52 | static 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 | |||
66 | static bool | 59 | static bool |
67 | tee_tg_route4(struct sk_buff *skb, const struct xt_tee_tginfo *info) | 60 | tee_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 | ||
200 | static 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 | |||
201 | static int tee_tg_check(const struct xt_tgchk_param *par) | 227 | static 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 | |||
257 | static 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 | ||
212 | static struct xt_target tee_tg_reg[] __read_mostly = { | 267 | static 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 |