1616#include <net/checksum.h>
1717#include <net/udp.h>
1818#include <net/inet_sock.h>
19-
19+ #include <linux/inetdevice.h>
2020#include <linux/netfilter/x_tables.h>
2121#include <linux/netfilter_ipv4/ip_tables.h>
22- #include <linux/netfilter_ipv6/ip6_tables.h>
23- #include <linux/netfilter/xt_TPROXY.h>
2422
2523#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>
2628#include <net/netfilter/ipv6/nf_defrag_ipv6.h>
29+ #endif
30+
2731#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+ }
2854
2955/**
3056 * 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,
75101 return sk ;
76102}
77103
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-
132104static unsigned int
133105tproxy_tg4 (struct sk_buff * skb , __be32 laddr , __be16 lport ,
134106 u_int32_t mark_mask , u_int32_t mark_value )
@@ -150,6 +122,10 @@ tproxy_tg4(struct sk_buff *skb, __be32 laddr, __be16 lport,
150122 hp -> source , hp -> dest ,
151123 skb -> dev , NFT_LOOKUP_ESTABLISHED );
152124
125+ laddr = tproxy_laddr4 (skb , laddr , iph -> daddr );
126+ if (!lport )
127+ lport = hp -> dest ;
128+
153129 /* UDP has no TCP_TIME_WAIT state, so we never enter here */
154130 if (sk && sk -> sk_state == TCP_TIME_WAIT )
155131 /* reopening a TIME_WAIT connection needs special handling */
@@ -158,8 +134,8 @@ tproxy_tg4(struct sk_buff *skb, __be32 laddr, __be16 lport,
158134 /* no, there's no established connection, check if
159135 * there's a listener on the redirected addr/port */
160136 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 ,
163139 skb -> dev , NFT_LOOKUP_LISTENER );
164140
165141 /* NOTE: assign_sock consumes our sk reference */
@@ -174,9 +150,9 @@ tproxy_tg4(struct sk_buff *skb, __be32 laddr, __be16 lport,
174150 return NF_ACCEPT ;
175151 }
176152
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 );
180156 return NF_DROP ;
181157}
182158
@@ -197,13 +173,97 @@ tproxy_tg4_v1(struct sk_buff *skb, const struct xt_action_param *par)
197173}
198174
199175#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+
200258static unsigned int
201259tproxy_tg6_v1 (struct sk_buff * skb , const struct xt_action_param * par )
202260{
203261 const struct ipv6hdr * iph = ipv6_hdr (skb );
204262 const struct xt_tproxy_target_info_v1 * tgi = par -> targinfo ;
205263 struct udphdr _hdr , * hp ;
206264 struct sock * sk ;
265+ const struct in6_addr * laddr ;
266+ __be16 lport ;
207267 int thoff ;
208268 int tproto ;
209269
@@ -228,6 +288,9 @@ tproxy_tg6_v1(struct sk_buff *skb, const struct xt_action_param *par)
228288 hp -> source , hp -> dest ,
229289 par -> in , NFT_LOOKUP_ESTABLISHED );
230290
291+ laddr = tproxy_laddr6 (skb , & tgi -> laddr .in6 , & iph -> daddr );
292+ lport = tgi -> lport ? tgi -> lport : hp -> dest ;
293+
231294 /* UDP has no TCP_TIME_WAIT state, so we never enter here */
232295 if (sk && sk -> sk_state == TCP_TIME_WAIT )
233296 /* 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)
236299 /* no there's no established connection, check if
237300 * there's a listener on the redirected addr/port */
238301 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 ,
243304 par -> in , NFT_LOOKUP_LISTENER );
244305
245306 /* NOTE: assign_sock consumes our sk reference */
@@ -249,14 +310,15 @@ tproxy_tg6_v1(struct sk_buff *skb, const struct xt_action_param *par)
249310 skb -> mark = (skb -> mark & ~tgi -> mark_mask ) ^ tgi -> mark_value ;
250311
251312 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 );
254315 return NF_ACCEPT ;
255316 }
256317
257318 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+
260322 return NF_DROP ;
261323}
262324
0 commit comments