netfilter: xt_TEE: have cloned packet travel through Xtables too
[linux-3.10.git] / net / netfilter / xt_TEE.c
1 /*
2  *      "TEE" target extension for Xtables
3  *      Copyright © Sebastian Claßen, 2007
4  *      Jan Engelhardt, 2007-2010
5  *
6  *      based on ipt_ROUTE.c from Cédric de Launois
7  *      <delaunois@info.ucl.be>
8  *
9  *      This program is free software; you can redistribute it and/or
10  *      modify it under the terms of the GNU General Public License
11  *      version 2 or later, as published by the Free Software Foundation.
12  */
13 #include <linux/ip.h>
14 #include <linux/module.h>
15 #include <linux/percpu.h>
16 #include <linux/route.h>
17 #include <linux/skbuff.h>
18 #include <net/checksum.h>
19 #include <net/icmp.h>
20 #include <net/ip.h>
21 #include <net/ipv6.h>
22 #include <net/ip6_route.h>
23 #include <net/route.h>
24 #include <linux/netfilter/x_tables.h>
25 #include <linux/netfilter/xt_TEE.h>
26
27 #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
28 #       define WITH_CONNTRACK 1
29 #       include <net/netfilter/nf_conntrack.h>
30 #endif
31 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
32 #       define WITH_IPV6 1
33 #endif
34
35 static const union nf_inet_addr tee_zero_address;
36 static DEFINE_PER_CPU(bool, tee_active);
37
38 static struct net *pick_net(struct sk_buff *skb)
39 {
40 #ifdef CONFIG_NET_NS
41         const struct dst_entry *dst;
42
43         if (skb->dev != NULL)
44                 return dev_net(skb->dev);
45         dst = skb_dst(skb);
46         if (dst != NULL && dst->dev != NULL)
47                 return dev_net(dst->dev);
48 #endif
49         return &init_net;
50 }
51
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
67 tee_tg_route4(struct sk_buff *skb, const struct xt_tee_tginfo *info)
68 {
69         const struct iphdr *iph = ip_hdr(skb);
70         struct net *net = pick_net(skb);
71         struct rtable *rt;
72         struct flowi fl;
73
74         memset(&fl, 0, sizeof(fl));
75         if (!tee_tg_route_oif(&fl, net, info))
76                 return false;
77         fl.nl_u.ip4_u.daddr = info->gw.ip;
78         fl.nl_u.ip4_u.tos   = RT_TOS(iph->tos);
79         fl.nl_u.ip4_u.scope = RT_SCOPE_UNIVERSE;
80         if (ip_route_output_key(net, &rt, &fl) != 0)
81                 return false;
82
83         dst_release(skb_dst(skb));
84         skb_dst_set(skb, &rt->u.dst);
85         skb->dev      = rt->u.dst.dev;
86         skb->protocol = htons(ETH_P_IP);
87         return true;
88 }
89
90 static unsigned int
91 tee_tg4(struct sk_buff *skb, const struct xt_target_param *par)
92 {
93         const struct xt_tee_tginfo *info = par->targinfo;
94         struct iphdr *iph;
95
96         if (percpu_read(tee_active))
97                 return XT_CONTINUE;
98         /*
99          * Copy the skb, and route the copy. Will later return %XT_CONTINUE for
100          * the original skb, which should continue on its way as if nothing has
101          * happened. The copy should be independently delivered to the TEE
102          * --gateway.
103          */
104         skb = pskb_copy(skb, GFP_ATOMIC);
105         if (skb == NULL)
106                 return XT_CONTINUE;
107
108 #ifdef WITH_CONNTRACK
109         /* Avoid counting cloned packets towards the original connection. */
110         nf_conntrack_put(skb->nfct);
111         skb->nfct     = &nf_conntrack_untracked.ct_general;
112         skb->nfctinfo = IP_CT_NEW;
113         nf_conntrack_get(skb->nfct);
114 #endif
115         /*
116          * If we are in PREROUTING/INPUT, the checksum must be recalculated
117          * since the length could have changed as a result of defragmentation.
118          *
119          * We also decrease the TTL to mitigate potential TEE loops
120          * between two hosts.
121          *
122          * Set %IP_DF so that the original source is notified of a potentially
123          * decreased MTU on the clone route. IPv6 does this too.
124          */
125         iph = ip_hdr(skb);
126         iph->frag_off |= htons(IP_DF);
127         if (par->hooknum == NF_INET_PRE_ROUTING ||
128             par->hooknum == NF_INET_LOCAL_IN)
129                 --iph->ttl;
130         ip_send_check(iph);
131
132         if (tee_tg_route4(skb, info)) {
133                 percpu_write(tee_active, true);
134                 ip_local_out(skb);
135                 percpu_write(tee_active, false);
136         } else {
137                 kfree_skb(skb);
138         }
139         return XT_CONTINUE;
140 }
141
142 #ifdef WITH_IPV6
143 static bool
144 tee_tg_route6(struct sk_buff *skb, const struct xt_tee_tginfo *info)
145 {
146         const struct ipv6hdr *iph = ipv6_hdr(skb);
147         struct net *net = pick_net(skb);
148         struct dst_entry *dst;
149         struct flowi fl;
150
151         memset(&fl, 0, sizeof(fl));
152         if (!tee_tg_route_oif(&fl, net, info))
153                 return false;
154         fl.nl_u.ip6_u.daddr = info->gw.in6;
155         fl.nl_u.ip6_u.flowlabel = ((iph->flow_lbl[0] & 0xF) << 16) |
156                                   (iph->flow_lbl[1] << 8) | iph->flow_lbl[2];
157         dst = ip6_route_output(net, NULL, &fl);
158         if (dst == NULL)
159                 return false;
160
161         dst_release(skb_dst(skb));
162         skb_dst_set(skb, dst);
163         skb->dev      = dst->dev;
164         skb->protocol = htons(ETH_P_IPV6);
165         return true;
166 }
167
168 static unsigned int
169 tee_tg6(struct sk_buff *skb, const struct xt_target_param *par)
170 {
171         const struct xt_tee_tginfo *info = par->targinfo;
172
173         if (percpu_read(tee_active))
174                 return XT_CONTINUE;
175         skb = pskb_copy(skb, GFP_ATOMIC);
176         if (skb == NULL)
177                 return XT_CONTINUE;
178
179 #ifdef WITH_CONNTRACK
180         nf_conntrack_put(skb->nfct);
181         skb->nfct     = &nf_conntrack_untracked.ct_general;
182         skb->nfctinfo = IP_CT_NEW;
183         nf_conntrack_get(skb->nfct);
184 #endif
185         if (par->hooknum == NF_INET_PRE_ROUTING ||
186             par->hooknum == NF_INET_LOCAL_IN) {
187                 struct ipv6hdr *iph = ipv6_hdr(skb);
188                 --iph->hop_limit;
189         }
190         if (tee_tg_route6(skb, info)) {
191                 percpu_write(tee_active, true);
192                 ip6_local_out(skb);
193                 percpu_write(tee_active, false);
194         } else {
195                 kfree_skb(skb);
196         }
197         return XT_CONTINUE;
198 }
199 #endif /* WITH_IPV6 */
200
201 static int tee_tg_check(const struct xt_tgchk_param *par)
202 {
203         const struct xt_tee_tginfo *info = par->targinfo;
204
205         if (info->oif[sizeof(info->oif)-1] != '\0')
206                 return -EINVAL;
207         /* 0.0.0.0 and :: not allowed */
208         return (memcmp(&info->gw, &tee_zero_address,
209                sizeof(tee_zero_address)) == 0) ? -EINVAL : 0;
210 }
211
212 static struct xt_target tee_tg_reg[] __read_mostly = {
213         {
214                 .name       = "TEE",
215                 .revision   = 1,
216                 .family     = NFPROTO_IPV4,
217                 .target     = tee_tg4,
218                 .targetsize = sizeof(struct xt_tee_tginfo),
219                 .checkentry = tee_tg_check,
220                 .me         = THIS_MODULE,
221         },
222 #ifdef WITH_IPV6
223         {
224                 .name       = "TEE",
225                 .revision   = 1,
226                 .family     = NFPROTO_IPV6,
227                 .target     = tee_tg6,
228                 .targetsize = sizeof(struct xt_tee_tginfo),
229                 .checkentry = tee_tg_check,
230                 .me         = THIS_MODULE,
231         },
232 #endif
233 };
234
235 static int __init tee_tg_init(void)
236 {
237         return xt_register_targets(tee_tg_reg, ARRAY_SIZE(tee_tg_reg));
238 }
239
240 static void __exit tee_tg_exit(void)
241 {
242         xt_unregister_targets(tee_tg_reg, ARRAY_SIZE(tee_tg_reg));
243 }
244
245 module_init(tee_tg_init);
246 module_exit(tee_tg_exit);
247 MODULE_AUTHOR("Sebastian Claßen <sebastian.classen@freenet.ag>");
248 MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>");
249 MODULE_DESCRIPTION("Xtables: Reroute packet copy");
250 MODULE_LICENSE("GPL");
251 MODULE_ALIAS("ipt_TEE");
252 MODULE_ALIAS("ip6t_TEE");