aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorBalazs Scheidler <bazsi@balabit.hu>2010-10-21 10:21:10 -0400
committerPatrick McHardy <kaber@trash.net>2010-10-21 10:21:10 -0400
commitcc6eb433856983e91071469c4ce57accb6947ccb (patch)
tree283b72a9aea1af83b7a48de6833d0c554e5b3a06 /net
parentb64c9256a9b76fc9f059f71bd08ba88fb0cbba2e (diff)
tproxy: use the interface primary IP address as a default value for --on-ip
The REDIRECT target and the older TProxy versions used the primary address of the incoming interface as the default value of the --on-ip parameter. This was unintentionally changed during the initial TProxy submission and caused confusion among users. Since IPv6 has no notion of primary address, we just select the first address on the list: this way the socket lookup finds wildcard bound sockets properly and we cannot really do better without the user telling us the IPv6 address of the proxy. This is implemented for both IPv4 and IPv6. Signed-off-by: Balazs Scheidler <bazsi@balabit.hu> Signed-off-by: KOVACS Krisztian <hidden@balabit.hu> Signed-off-by: Patrick McHardy <kaber@trash.net>
Diffstat (limited to 'net')
-rw-r--r--net/netfilter/xt_TPROXY.c202
1 files changed, 132 insertions, 70 deletions
diff --git a/net/netfilter/xt_TPROXY.c b/net/netfilter/xt_TPROXY.c
index d5f97e2302b8..19c482caf30b 100644
--- a/net/netfilter/xt_TPROXY.c
+++ b/net/netfilter/xt_TPROXY.c
@@ -16,15 +16,41 @@
16#include <net/checksum.h> 16#include <net/checksum.h>
17#include <net/udp.h> 17#include <net/udp.h>
18#include <net/inet_sock.h> 18#include <net/inet_sock.h>
19 19#include <linux/inetdevice.h>
20#include <linux/netfilter/x_tables.h> 20#include <linux/netfilter/x_tables.h>
21#include <linux/netfilter_ipv4/ip_tables.h> 21#include <linux/netfilter_ipv4/ip_tables.h>
22#include <linux/netfilter_ipv6/ip6_tables.h>
23#include <linux/netfilter/xt_TPROXY.h>
24 22
25#include <net/netfilter/ipv4/nf_defrag_ipv4.h> 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>
26#include <net/netfilter/ipv6/nf_defrag_ipv6.h> 28#include <net/netfilter/ipv6/nf_defrag_ipv6.h>
29#endif
30
27#include <net/netfilter/nf_tproxy_core.h> 31#include <net/netfilter/nf_tproxy_core.h>
32#include <linux/netfilter/xt_TPROXY.h>
33
34static inline __be32
35tproxy_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}
28 54
29/** 55/**
30 * tproxy_handle_time_wait4() - handle IPv4 TCP TIME_WAIT reopen redirections 56 * tproxy_handle_time_wait4() - handle IPv4 TCP TIME_WAIT reopen redirections
@@ -75,60 +101,6 @@ tproxy_handle_time_wait4(struct sk_buff *skb, __be32 laddr, __be16 lport,
75 return sk; 101 return sk;
76} 102}
77 103
78/**
79 * tproxy_handle_time_wait6() - handle IPv6 TCP TIME_WAIT reopen redirections
80 * @skb: The skb being processed.
81 * @tproto: Transport protocol.
82 * @thoff: Transport protocol header offset.
83 * @par: Iptables target parameters.
84 * @sk: The TIME_WAIT TCP socket found by the lookup.
85 *
86 * We have to handle SYN packets arriving to TIME_WAIT sockets
87 * differently: instead of reopening the connection we should rather
88 * redirect the new connection to the proxy if there's a listener
89 * socket present.
90 *
91 * tproxy_handle_time_wait6() consumes the socket reference passed in.
92 *
93 * Returns the listener socket if there's one, the TIME_WAIT socket if
94 * no such listener is found, or NULL if the TCP header is incomplete.
95 */
96static struct sock *
97tproxy_handle_time_wait6(struct sk_buff *skb, int tproto, int thoff,
98 const struct xt_action_param *par,
99 struct sock *sk)
100{
101 const struct ipv6hdr *iph = ipv6_hdr(skb);
102 struct tcphdr _hdr, *hp;
103 const struct xt_tproxy_target_info_v1 *tgi = par->targinfo;
104
105 hp = skb_header_pointer(skb, thoff, sizeof(_hdr), &_hdr);
106 if (hp == NULL) {
107 inet_twsk_put(inet_twsk(sk));
108 return NULL;
109 }
110
111 if (hp->syn && !hp->rst && !hp->ack && !hp->fin) {
112 /* SYN to a TIME_WAIT socket, we'd rather redirect it
113 * to a listener socket if there's one */
114 struct sock *sk2;
115
116 sk2 = nf_tproxy_get_sock_v6(dev_net(skb->dev), tproto,
117 &iph->saddr,
118 !ipv6_addr_any(&tgi->laddr.in6) ? &tgi->laddr.in6 : &iph->daddr,
119 hp->source,
120 tgi->lport ? tgi->lport : hp->dest,
121 skb->dev, NFT_LOOKUP_LISTENER);
122 if (sk2) {
123 inet_twsk_deschedule(inet_twsk(sk), &tcp_death_row);
124 inet_twsk_put(inet_twsk(sk));
125 sk = sk2;
126 }
127 }
128
129 return sk;
130}
131
132static unsigned int 104static unsigned int
133tproxy_tg4(struct sk_buff *skb, __be32 laddr, __be16 lport, 105tproxy_tg4(struct sk_buff *skb, __be32 laddr, __be16 lport,
134 u_int32_t mark_mask, u_int32_t mark_value) 106 u_int32_t mark_mask, u_int32_t mark_value)
@@ -150,6 +122,10 @@ tproxy_tg4(struct sk_buff *skb, __be32 laddr, __be16 lport,
150 hp->source, hp->dest, 122 hp->source, hp->dest,
151 skb->dev, NFT_LOOKUP_ESTABLISHED); 123 skb->dev, NFT_LOOKUP_ESTABLISHED);
152 124
125 laddr = tproxy_laddr4(skb, laddr, iph->daddr);
126 if (!lport)
127 lport = hp->dest;
128
153 /* UDP has no TCP_TIME_WAIT state, so we never enter here */ 129 /* UDP has no TCP_TIME_WAIT state, so we never enter here */
154 if (sk && sk->sk_state == TCP_TIME_WAIT) 130 if (sk && sk->sk_state == TCP_TIME_WAIT)
155 /* reopening a TIME_WAIT connection needs special handling */ 131 /* reopening a TIME_WAIT connection needs special handling */
@@ -158,8 +134,8 @@ tproxy_tg4(struct sk_buff *skb, __be32 laddr, __be16 lport,
158 /* no, there's no established connection, check if 134 /* no, there's no established connection, check if
159 * there's a listener on the redirected addr/port */ 135 * there's a listener on the redirected addr/port */
160 sk = nf_tproxy_get_sock_v4(dev_net(skb->dev), iph->protocol, 136 sk = nf_tproxy_get_sock_v4(dev_net(skb->dev), iph->protocol,
161 iph->saddr, laddr ? laddr : iph->daddr, 137 iph->saddr, laddr,
162 hp->source, lport ? lport : hp->dest, 138 hp->source, lport,
163 skb->dev, NFT_LOOKUP_LISTENER); 139 skb->dev, NFT_LOOKUP_LISTENER);
164 140
165 /* NOTE: assign_sock consumes our sk reference */ 141 /* NOTE: assign_sock consumes our sk reference */
@@ -174,9 +150,9 @@ tproxy_tg4(struct sk_buff *skb, __be32 laddr, __be16 lport,
174 return NF_ACCEPT; 150 return NF_ACCEPT;
175 } 151 }
176 152
177 pr_debug("no socket, dropping: proto %hhu %08x:%hu -> %08x:%hu, mark: %x\n", 153 pr_debug("no socket, dropping: proto %hhu %pI4:%hu -> %pI4:%hu, mark: %x\n",
178 iph->protocol, ntohl(iph->daddr), ntohs(hp->dest), 154 iph->protocol, &iph->saddr, ntohs(hp->source),
179 ntohl(laddr), ntohs(lport), skb->mark); 155 &iph->daddr, ntohs(hp->dest), skb->mark);
180 return NF_DROP; 156 return NF_DROP;
181} 157}
182 158
@@ -197,6 +173,88 @@ tproxy_tg4_v1(struct sk_buff *skb, const struct xt_action_param *par)
197} 173}
198 174
199#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 175#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
176
177static inline const struct in6_addr *
178tproxy_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 */
222static struct sock *
223tproxy_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
200static unsigned int 258static unsigned int
201tproxy_tg6_v1(struct sk_buff *skb, const struct xt_action_param *par) 259tproxy_tg6_v1(struct sk_buff *skb, const struct xt_action_param *par)
202{ 260{
@@ -204,6 +262,8 @@ tproxy_tg6_v1(struct sk_buff *skb, const struct xt_action_param *par)
204 const struct xt_tproxy_target_info_v1 *tgi = par->targinfo; 262 const struct xt_tproxy_target_info_v1 *tgi = par->targinfo;
205 struct udphdr _hdr, *hp; 263 struct udphdr _hdr, *hp;
206 struct sock *sk; 264 struct sock *sk;
265 const struct in6_addr *laddr;
266 __be16 lport;
207 int thoff; 267 int thoff;
208 int tproto; 268 int tproto;
209 269
@@ -228,6 +288,9 @@ tproxy_tg6_v1(struct sk_buff *skb, const struct xt_action_param *par)
228 hp->source, hp->dest, 288 hp->source, hp->dest,
229 par->in, NFT_LOOKUP_ESTABLISHED); 289 par->in, NFT_LOOKUP_ESTABLISHED);
230 290
291 laddr = tproxy_laddr6(skb, &tgi->laddr.in6, &iph->daddr);
292 lport = tgi->lport ? tgi->lport : hp->dest;
293
231 /* UDP has no TCP_TIME_WAIT state, so we never enter here */ 294 /* UDP has no TCP_TIME_WAIT state, so we never enter here */
232 if (sk && sk->sk_state == TCP_TIME_WAIT) 295 if (sk && sk->sk_state == TCP_TIME_WAIT)
233 /* reopening a TIME_WAIT connection needs special handling */ 296 /* reopening a TIME_WAIT connection needs special handling */
@@ -236,10 +299,8 @@ tproxy_tg6_v1(struct sk_buff *skb, const struct xt_action_param *par)
236 /* no there's no established connection, check if 299 /* no there's no established connection, check if
237 * there's a listener on the redirected addr/port */ 300 * there's a listener on the redirected addr/port */
238 sk = nf_tproxy_get_sock_v6(dev_net(skb->dev), tproto, 301 sk = nf_tproxy_get_sock_v6(dev_net(skb->dev), tproto,
239 &iph->saddr, 302 &iph->saddr, laddr,
240 !ipv6_addr_any(&tgi->laddr.in6) ? &tgi->laddr.in6 : &iph->daddr, 303 hp->source, lport,
241 hp->source,
242 tgi->lport ? tgi->lport : hp->dest,
243 par->in, NFT_LOOKUP_LISTENER); 304 par->in, NFT_LOOKUP_LISTENER);
244 305
245 /* NOTE: assign_sock consumes our sk reference */ 306 /* NOTE: assign_sock consumes our sk reference */
@@ -249,14 +310,15 @@ tproxy_tg6_v1(struct sk_buff *skb, const struct xt_action_param *par)
249 skb->mark = (skb->mark & ~tgi->mark_mask) ^ tgi->mark_value; 310 skb->mark = (skb->mark & ~tgi->mark_mask) ^ tgi->mark_value;
250 311
251 pr_debug("redirecting: proto %hhu %pI6:%hu -> %pI6:%hu, mark: %x\n", 312 pr_debug("redirecting: proto %hhu %pI6:%hu -> %pI6:%hu, mark: %x\n",
252 tproto, &iph->saddr, ntohs(hp->dest), 313 tproto, &iph->saddr, ntohs(hp->source),
253 &tgi->laddr.in6, ntohs(tgi->lport), skb->mark); 314 laddr, ntohs(lport), skb->mark);
254 return NF_ACCEPT; 315 return NF_ACCEPT;
255 } 316 }
256 317
257 pr_debug("no socket, dropping: proto %hhu %pI6:%hu -> %pI6:%hu, mark: %x\n", 318 pr_debug("no socket, dropping: proto %hhu %pI6:%hu -> %pI6:%hu, mark: %x\n",
258 tproto, &iph->saddr, ntohs(hp->dest), 319 tproto, &iph->saddr, ntohs(hp->source),
259 &tgi->laddr.in6, ntohs(tgi->lport), skb->mark); 320 &iph->daddr, ntohs(hp->dest), skb->mark);
321
260 return NF_DROP; 322 return NF_DROP;
261} 323}
262 324