]> bbs.cooldavid.org Git - net-next-2.6.git/blob - net/netfilter/xt_TPROXY.c
Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux...
[net-next-2.6.git] / net / netfilter / xt_TPROXY.c
1 /*
2  * Transparent proxy support for Linux/iptables
3  *
4  * Copyright (c) 2006-2010 BalaBit IT Ltd.
5  * Author: Balazs Scheidler, Krisztian Kovacs
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  *
11  */
12 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
13 #include <linux/module.h>
14 #include <linux/skbuff.h>
15 #include <linux/ip.h>
16 #include <net/checksum.h>
17 #include <net/udp.h>
18 #include <net/inet_sock.h>
19 #include <linux/inetdevice.h>
20 #include <linux/netfilter/x_tables.h>
21 #include <linux/netfilter_ipv4/ip_tables.h>
22
23 #include <net/netfilter/ipv4/nf_defrag_ipv4.h>
24 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
25 #include <net/if_inet6.h>
26 #include <net/addrconf.h>
27 #include <linux/netfilter_ipv6/ip6_tables.h>
28 #include <net/netfilter/ipv6/nf_defrag_ipv6.h>
29 #endif
30
31 #include <net/netfilter/nf_tproxy_core.h>
32 #include <linux/netfilter/xt_TPROXY.h>
33
34 static inline __be32
35 tproxy_laddr4(struct sk_buff *skb, __be32 user_laddr, __be32 daddr)
36 {
37         struct in_device *indev;
38         __be32 laddr;
39
40         if (user_laddr)
41                 return user_laddr;
42
43         laddr = 0;
44         rcu_read_lock();
45         indev = __in_dev_get_rcu(skb->dev);
46         for_primary_ifa(indev) {
47                 laddr = ifa->ifa_local;
48                 break;
49         } endfor_ifa(indev);
50         rcu_read_unlock();
51
52         return laddr ? laddr : daddr;
53 }
54
55 /**
56  * tproxy_handle_time_wait4() - handle IPv4 TCP TIME_WAIT reopen redirections
57  * @skb:        The skb being processed.
58  * @laddr:      IPv4 address to redirect to or zero.
59  * @lport:      TCP port to redirect to or zero.
60  * @sk:         The TIME_WAIT TCP socket found by the lookup.
61  *
62  * We have to handle SYN packets arriving to TIME_WAIT sockets
63  * differently: instead of reopening the connection we should rather
64  * redirect the new connection to the proxy if there's a listener
65  * socket present.
66  *
67  * tproxy_handle_time_wait4() consumes the socket reference passed in.
68  *
69  * Returns the listener socket if there's one, the TIME_WAIT socket if
70  * no such listener is found, or NULL if the TCP header is incomplete.
71  */
72 static struct sock *
73 tproxy_handle_time_wait4(struct sk_buff *skb, __be32 laddr, __be16 lport,
74                         struct sock *sk)
75 {
76         const struct iphdr *iph = ip_hdr(skb);
77         struct tcphdr _hdr, *hp;
78
79         hp = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_hdr), &_hdr);
80         if (hp == NULL) {
81                 inet_twsk_put(inet_twsk(sk));
82                 return NULL;
83         }
84
85         if (hp->syn && !hp->rst && !hp->ack && !hp->fin) {
86                 /* SYN to a TIME_WAIT socket, we'd rather redirect it
87                  * to a listener socket if there's one */
88                 struct sock *sk2;
89
90                 sk2 = nf_tproxy_get_sock_v4(dev_net(skb->dev), iph->protocol,
91                                             iph->saddr, laddr ? laddr : iph->daddr,
92                                             hp->source, lport ? lport : hp->dest,
93                                             skb->dev, NFT_LOOKUP_LISTENER);
94                 if (sk2) {
95                         inet_twsk_deschedule(inet_twsk(sk), &tcp_death_row);
96                         inet_twsk_put(inet_twsk(sk));
97                         sk = sk2;
98                 }
99         }
100
101         return sk;
102 }
103
104 static unsigned int
105 tproxy_tg4(struct sk_buff *skb, __be32 laddr, __be16 lport,
106            u_int32_t mark_mask, u_int32_t mark_value)
107 {
108         const struct iphdr *iph = ip_hdr(skb);
109         struct udphdr _hdr, *hp;
110         struct sock *sk;
111
112         hp = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_hdr), &_hdr);
113         if (hp == NULL)
114                 return NF_DROP;
115
116         /* check if there's an ongoing connection on the packet
117          * addresses, this happens if the redirect already happened
118          * and the current packet belongs to an already established
119          * connection */
120         sk = nf_tproxy_get_sock_v4(dev_net(skb->dev), iph->protocol,
121                                    iph->saddr, iph->daddr,
122                                    hp->source, hp->dest,
123                                    skb->dev, NFT_LOOKUP_ESTABLISHED);
124
125         laddr = tproxy_laddr4(skb, laddr, iph->daddr);
126         if (!lport)
127                 lport = hp->dest;
128
129         /* UDP has no TCP_TIME_WAIT state, so we never enter here */
130         if (sk && sk->sk_state == TCP_TIME_WAIT)
131                 /* reopening a TIME_WAIT connection needs special handling */
132                 sk = tproxy_handle_time_wait4(skb, laddr, lport, sk);
133         else if (!sk)
134                 /* no, there's no established connection, check if
135                  * there's a listener on the redirected addr/port */
136                 sk = nf_tproxy_get_sock_v4(dev_net(skb->dev), iph->protocol,
137                                            iph->saddr, laddr,
138                                            hp->source, lport,
139                                            skb->dev, NFT_LOOKUP_LISTENER);
140
141         /* NOTE: assign_sock consumes our sk reference */
142         if (sk && nf_tproxy_assign_sock(skb, sk)) {
143                 /* This should be in a separate target, but we don't do multiple
144                    targets on the same rule yet */
145                 skb->mark = (skb->mark & ~mark_mask) ^ mark_value;
146
147                 pr_debug("redirecting: proto %hhu %pI4:%hu -> %pI4:%hu, mark: %x\n",
148                          iph->protocol, &iph->daddr, ntohs(hp->dest),
149                          &laddr, ntohs(lport), skb->mark);
150                 return NF_ACCEPT;
151         }
152
153         pr_debug("no socket, dropping: proto %hhu %pI4:%hu -> %pI4:%hu, mark: %x\n",
154                  iph->protocol, &iph->saddr, ntohs(hp->source),
155                  &iph->daddr, ntohs(hp->dest), skb->mark);
156         return NF_DROP;
157 }
158
159 static unsigned int
160 tproxy_tg4_v0(struct sk_buff *skb, const struct xt_action_param *par)
161 {
162         const struct xt_tproxy_target_info *tgi = par->targinfo;
163
164         return tproxy_tg4(skb, tgi->laddr, tgi->lport, tgi->mark_mask, tgi->mark_value);
165 }
166
167 static unsigned int
168 tproxy_tg4_v1(struct sk_buff *skb, const struct xt_action_param *par)
169 {
170         const struct xt_tproxy_target_info_v1 *tgi = par->targinfo;
171
172         return tproxy_tg4(skb, tgi->laddr.ip, tgi->lport, tgi->mark_mask, tgi->mark_value);
173 }
174
175 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
176
177 static inline const struct in6_addr *
178 tproxy_laddr6(struct sk_buff *skb, const struct in6_addr *user_laddr,
179               const struct in6_addr *daddr)
180 {
181         struct inet6_dev *indev;
182         struct inet6_ifaddr *ifa;
183         struct in6_addr *laddr;
184
185         if (!ipv6_addr_any(user_laddr))
186                 return user_laddr;
187         laddr = NULL;
188
189         rcu_read_lock();
190         indev = __in6_dev_get(skb->dev);
191         if (indev)
192                 list_for_each_entry(ifa, &indev->addr_list, if_list) {
193                         if (ifa->flags & (IFA_F_TENTATIVE | IFA_F_DEPRECATED))
194                                 continue;
195
196                         laddr = &ifa->addr;
197                         break;
198                 }
199         rcu_read_unlock();
200
201         return laddr ? laddr : daddr;
202 }
203
204 /**
205  * tproxy_handle_time_wait6() - handle IPv6 TCP TIME_WAIT reopen redirections
206  * @skb:        The skb being processed.
207  * @tproto:     Transport protocol.
208  * @thoff:      Transport protocol header offset.
209  * @par:        Iptables target parameters.
210  * @sk:         The TIME_WAIT TCP socket found by the lookup.
211  *
212  * We have to handle SYN packets arriving to TIME_WAIT sockets
213  * differently: instead of reopening the connection we should rather
214  * redirect the new connection to the proxy if there's a listener
215  * socket present.
216  *
217  * tproxy_handle_time_wait6() consumes the socket reference passed in.
218  *
219  * Returns the listener socket if there's one, the TIME_WAIT socket if
220  * no such listener is found, or NULL if the TCP header is incomplete.
221  */
222 static struct sock *
223 tproxy_handle_time_wait6(struct sk_buff *skb, int tproto, int thoff,
224                          const struct xt_action_param *par,
225                          struct sock *sk)
226 {
227         const struct ipv6hdr *iph = ipv6_hdr(skb);
228         struct tcphdr _hdr, *hp;
229         const struct xt_tproxy_target_info_v1 *tgi = par->targinfo;
230
231         hp = skb_header_pointer(skb, thoff, sizeof(_hdr), &_hdr);
232         if (hp == NULL) {
233                 inet_twsk_put(inet_twsk(sk));
234                 return NULL;
235         }
236
237         if (hp->syn && !hp->rst && !hp->ack && !hp->fin) {
238                 /* SYN to a TIME_WAIT socket, we'd rather redirect it
239                  * to a listener socket if there's one */
240                 struct sock *sk2;
241
242                 sk2 = nf_tproxy_get_sock_v6(dev_net(skb->dev), tproto,
243                                             &iph->saddr,
244                                             tproxy_laddr6(skb, &tgi->laddr.in6, &iph->daddr),
245                                             hp->source,
246                                             tgi->lport ? tgi->lport : hp->dest,
247                                             skb->dev, NFT_LOOKUP_LISTENER);
248                 if (sk2) {
249                         inet_twsk_deschedule(inet_twsk(sk), &tcp_death_row);
250                         inet_twsk_put(inet_twsk(sk));
251                         sk = sk2;
252                 }
253         }
254
255         return sk;
256 }
257
258 static unsigned int
259 tproxy_tg6_v1(struct sk_buff *skb, const struct xt_action_param *par)
260 {
261         const struct ipv6hdr *iph = ipv6_hdr(skb);
262         const struct xt_tproxy_target_info_v1 *tgi = par->targinfo;
263         struct udphdr _hdr, *hp;
264         struct sock *sk;
265         const struct in6_addr *laddr;
266         __be16 lport;
267         int thoff;
268         int tproto;
269
270         tproto = ipv6_find_hdr(skb, &thoff, -1, NULL);
271         if (tproto < 0) {
272                 pr_debug("unable to find transport header in IPv6 packet, dropping\n");
273                 return NF_DROP;
274         }
275
276         hp = skb_header_pointer(skb, thoff, sizeof(_hdr), &_hdr);
277         if (hp == NULL) {
278                 pr_debug("unable to grab transport header contents in IPv6 packet, dropping\n");
279                 return NF_DROP;
280         }
281
282         /* check if there's an ongoing connection on the packet
283          * addresses, this happens if the redirect already happened
284          * and the current packet belongs to an already established
285          * connection */
286         sk = nf_tproxy_get_sock_v6(dev_net(skb->dev), tproto,
287                                    &iph->saddr, &iph->daddr,
288                                    hp->source, hp->dest,
289                                    par->in, NFT_LOOKUP_ESTABLISHED);
290
291         laddr = tproxy_laddr6(skb, &tgi->laddr.in6, &iph->daddr);
292         lport = tgi->lport ? tgi->lport : hp->dest;
293
294         /* UDP has no TCP_TIME_WAIT state, so we never enter here */
295         if (sk && sk->sk_state == TCP_TIME_WAIT)
296                 /* reopening a TIME_WAIT connection needs special handling */
297                 sk = tproxy_handle_time_wait6(skb, tproto, thoff, par, sk);
298         else if (!sk)
299                 /* no there's no established connection, check if
300                  * there's a listener on the redirected addr/port */
301                 sk = nf_tproxy_get_sock_v6(dev_net(skb->dev), tproto,
302                                            &iph->saddr, laddr,
303                                            hp->source, lport,
304                                            par->in, NFT_LOOKUP_LISTENER);
305
306         /* NOTE: assign_sock consumes our sk reference */
307         if (sk && nf_tproxy_assign_sock(skb, sk)) {
308                 /* This should be in a separate target, but we don't do multiple
309                    targets on the same rule yet */
310                 skb->mark = (skb->mark & ~tgi->mark_mask) ^ tgi->mark_value;
311
312                 pr_debug("redirecting: proto %hhu %pI6:%hu -> %pI6:%hu, mark: %x\n",
313                          tproto, &iph->saddr, ntohs(hp->source),
314                          laddr, ntohs(lport), skb->mark);
315                 return NF_ACCEPT;
316         }
317
318         pr_debug("no socket, dropping: proto %hhu %pI6:%hu -> %pI6:%hu, mark: %x\n",
319                  tproto, &iph->saddr, ntohs(hp->source),
320                  &iph->daddr, ntohs(hp->dest), skb->mark);
321
322         return NF_DROP;
323 }
324
325 static int tproxy_tg6_check(const struct xt_tgchk_param *par)
326 {
327         const struct ip6t_ip6 *i = par->entryinfo;
328
329         if ((i->proto == IPPROTO_TCP || i->proto == IPPROTO_UDP)
330             && !(i->flags & IP6T_INV_PROTO))
331                 return 0;
332
333         pr_info("Can be used only in combination with "
334                 "either -p tcp or -p udp\n");
335         return -EINVAL;
336 }
337 #endif
338
339 static int tproxy_tg4_check(const struct xt_tgchk_param *par)
340 {
341         const struct ipt_ip *i = par->entryinfo;
342
343         if ((i->proto == IPPROTO_TCP || i->proto == IPPROTO_UDP)
344             && !(i->invflags & IPT_INV_PROTO))
345                 return 0;
346
347         pr_info("Can be used only in combination with "
348                 "either -p tcp or -p udp\n");
349         return -EINVAL;
350 }
351
352 static struct xt_target tproxy_tg_reg[] __read_mostly = {
353         {
354                 .name           = "TPROXY",
355                 .family         = NFPROTO_IPV4,
356                 .table          = "mangle",
357                 .target         = tproxy_tg4_v0,
358                 .revision       = 0,
359                 .targetsize     = sizeof(struct xt_tproxy_target_info),
360                 .checkentry     = tproxy_tg4_check,
361                 .hooks          = 1 << NF_INET_PRE_ROUTING,
362                 .me             = THIS_MODULE,
363         },
364         {
365                 .name           = "TPROXY",
366                 .family         = NFPROTO_IPV4,
367                 .table          = "mangle",
368                 .target         = tproxy_tg4_v1,
369                 .revision       = 1,
370                 .targetsize     = sizeof(struct xt_tproxy_target_info_v1),
371                 .checkentry     = tproxy_tg4_check,
372                 .hooks          = 1 << NF_INET_PRE_ROUTING,
373                 .me             = THIS_MODULE,
374         },
375 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
376         {
377                 .name           = "TPROXY",
378                 .family         = NFPROTO_IPV6,
379                 .table          = "mangle",
380                 .target         = tproxy_tg6_v1,
381                 .revision       = 1,
382                 .targetsize     = sizeof(struct xt_tproxy_target_info_v1),
383                 .checkentry     = tproxy_tg6_check,
384                 .hooks          = 1 << NF_INET_PRE_ROUTING,
385                 .me             = THIS_MODULE,
386         },
387 #endif
388
389 };
390
391 static int __init tproxy_tg_init(void)
392 {
393         nf_defrag_ipv4_enable();
394 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
395         nf_defrag_ipv6_enable();
396 #endif
397
398         return xt_register_targets(tproxy_tg_reg, ARRAY_SIZE(tproxy_tg_reg));
399 }
400
401 static void __exit tproxy_tg_exit(void)
402 {
403         xt_unregister_targets(tproxy_tg_reg, ARRAY_SIZE(tproxy_tg_reg));
404 }
405
406 module_init(tproxy_tg_init);
407 module_exit(tproxy_tg_exit);
408 MODULE_LICENSE("GPL");
409 MODULE_AUTHOR("Balazs Scheidler, Krisztian Kovacs");
410 MODULE_DESCRIPTION("Netfilter transparent proxy (TPROXY) target module.");
411 MODULE_ALIAS("ipt_TPROXY");
412 MODULE_ALIAS("ip6t_TPROXY");