16
16
#include <net/checksum.h>
17
17
#include <net/udp.h>
18
18
#include <net/inet_sock.h>
19
-
19
+ #include <linux/inetdevice.h>
20
20
#include <linux/netfilter/x_tables.h>
21
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
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
28
#include <net/netfilter/ipv6/nf_defrag_ipv6.h>
29
+ #endif
30
+
27
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
+ }
28
54
29
55
/**
30
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
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
- */
96
- static struct sock *
97
- tproxy_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
-
132
104
static unsigned int
133
105
tproxy_tg4 (struct sk_buff * skb , __be32 laddr , __be16 lport ,
134
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
122
hp -> source , hp -> dest ,
151
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
129
/* UDP has no TCP_TIME_WAIT state, so we never enter here */
154
130
if (sk && sk -> sk_state == TCP_TIME_WAIT )
155
131
/* reopening a TIME_WAIT connection needs special handling */
@@ -158,8 +134,8 @@ tproxy_tg4(struct sk_buff *skb, __be32 laddr, __be16 lport,
158
134
/* no, there's no established connection, check if
159
135
* there's a listener on the redirected addr/port */
160
136
sk = nf_tproxy_get_sock_v4 (dev_net (skb -> dev ), iph -> protocol ,
161
- iph -> saddr , laddr ? laddr : iph -> daddr ,
162
- hp -> source , lport ? lport : hp -> dest ,
137
+ iph -> saddr , laddr ,
138
+ hp -> source , lport ,
163
139
skb -> dev , NFT_LOOKUP_LISTENER );
164
140
165
141
/* NOTE: assign_sock consumes our sk reference */
@@ -174,9 +150,9 @@ tproxy_tg4(struct sk_buff *skb, __be32 laddr, __be16 lport,
174
150
return NF_ACCEPT ;
175
151
}
176
152
177
- pr_debug ("no socket, dropping: proto %hhu %08x :%hu -> %08x :%hu, mark: %x\n" ,
178
- iph -> protocol , ntohl ( iph -> daddr ) , ntohs (hp -> dest ),
179
- ntohl ( laddr ) , ntohs (lport ), skb -> mark );
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 );
180
156
return NF_DROP ;
181
157
}
182
158
@@ -197,13 +173,97 @@ tproxy_tg4_v1(struct sk_buff *skb, const struct xt_action_param *par)
197
173
}
198
174
199
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
+
200
258
static unsigned int
201
259
tproxy_tg6_v1 (struct sk_buff * skb , const struct xt_action_param * par )
202
260
{
203
261
const struct ipv6hdr * iph = ipv6_hdr (skb );
204
262
const struct xt_tproxy_target_info_v1 * tgi = par -> targinfo ;
205
263
struct udphdr _hdr , * hp ;
206
264
struct sock * sk ;
265
+ const struct in6_addr * laddr ;
266
+ __be16 lport ;
207
267
int thoff ;
208
268
int tproto ;
209
269
@@ -228,6 +288,9 @@ tproxy_tg6_v1(struct sk_buff *skb, const struct xt_action_param *par)
228
288
hp -> source , hp -> dest ,
229
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
294
/* UDP has no TCP_TIME_WAIT state, so we never enter here */
232
295
if (sk && sk -> sk_state == TCP_TIME_WAIT )
233
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
299
/* no there's no established connection, check if
237
300
* there's a listener on the redirected addr/port */
238
301
sk = nf_tproxy_get_sock_v6 (dev_net (skb -> dev ), tproto ,
239
- & iph -> saddr ,
240
- !ipv6_addr_any (& tgi -> laddr .in6 ) ? & tgi -> laddr .in6 : & iph -> daddr ,
241
- hp -> source ,
242
- tgi -> lport ? tgi -> lport : hp -> dest ,
302
+ & iph -> saddr , laddr ,
303
+ hp -> source , lport ,
243
304
par -> in , NFT_LOOKUP_LISTENER );
244
305
245
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
310
skb -> mark = (skb -> mark & ~tgi -> mark_mask ) ^ tgi -> mark_value ;
250
311
251
312
pr_debug ("redirecting: proto %hhu %pI6:%hu -> %pI6:%hu, mark: %x\n" ,
252
- tproto , & iph -> saddr , ntohs (hp -> dest ),
253
- & tgi -> laddr . in6 , ntohs (tgi -> lport ), skb -> mark );
313
+ tproto , & iph -> saddr , ntohs (hp -> source ),
314
+ laddr , ntohs (lport ), skb -> mark );
254
315
return NF_ACCEPT ;
255
316
}
256
317
257
318
pr_debug ("no socket, dropping: proto %hhu %pI6:%hu -> %pI6:%hu, mark: %x\n" ,
258
- tproto , & iph -> saddr , ntohs (hp -> dest ),
259
- & tgi -> laddr .in6 , ntohs (tgi -> lport ), skb -> mark );
319
+ tproto , & iph -> saddr , ntohs (hp -> source ),
320
+ & iph -> daddr , ntohs (hp -> dest ), skb -> mark );
321
+
260
322
return NF_DROP ;
261
323
}
262
324
0 commit comments