Commit 93742cf8af9dd3b053242b273040aa35fcbf93b3
Committed by
Pablo Neira Ayuso
1 parent
fd158d79d3
netfilter: tproxy: remove nf_tproxy_core.h
We've removed nf_tproxy_core.ko, so also remove its header. The lookup helpers are split and then moved to tproxy target/socket match. Signed-off-by: Florian Westphal <fw@strlen.de> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Showing 3 changed files with 220 additions and 212 deletions Side-by-side Diff
include/net/netfilter/nf_tproxy_core.h
1 | -#ifndef _NF_TPROXY_CORE_H | |
2 | -#define _NF_TPROXY_CORE_H | |
3 | - | |
4 | -#include <linux/types.h> | |
5 | -#include <linux/in.h> | |
6 | -#include <linux/skbuff.h> | |
7 | -#include <net/sock.h> | |
8 | -#include <net/inet_hashtables.h> | |
9 | -#include <net/inet6_hashtables.h> | |
10 | -#include <net/tcp.h> | |
11 | - | |
12 | -#define NFT_LOOKUP_ANY 0 | |
13 | -#define NFT_LOOKUP_LISTENER 1 | |
14 | -#define NFT_LOOKUP_ESTABLISHED 2 | |
15 | - | |
16 | -/* look up and get a reference to a matching socket */ | |
17 | - | |
18 | - | |
19 | -/* This function is used by the 'TPROXY' target and the 'socket' | |
20 | - * match. The following lookups are supported: | |
21 | - * | |
22 | - * Explicit TProxy target rule | |
23 | - * =========================== | |
24 | - * | |
25 | - * This is used when the user wants to intercept a connection matching | |
26 | - * an explicit iptables rule. In this case the sockets are assumed | |
27 | - * matching in preference order: | |
28 | - * | |
29 | - * - match: if there's a fully established connection matching the | |
30 | - * _packet_ tuple, it is returned, assuming the redirection | |
31 | - * already took place and we process a packet belonging to an | |
32 | - * established connection | |
33 | - * | |
34 | - * - match: if there's a listening socket matching the redirection | |
35 | - * (e.g. on-port & on-ip of the connection), it is returned, | |
36 | - * regardless if it was bound to 0.0.0.0 or an explicit | |
37 | - * address. The reasoning is that if there's an explicit rule, it | |
38 | - * does not really matter if the listener is bound to an interface | |
39 | - * or to 0. The user already stated that he wants redirection | |
40 | - * (since he added the rule). | |
41 | - * | |
42 | - * "socket" match based redirection (no specific rule) | |
43 | - * =================================================== | |
44 | - * | |
45 | - * There are connections with dynamic endpoints (e.g. FTP data | |
46 | - * connection) that the user is unable to add explicit rules | |
47 | - * for. These are taken care of by a generic "socket" rule. It is | |
48 | - * assumed that the proxy application is trusted to open such | |
49 | - * connections without explicit iptables rule (except of course the | |
50 | - * generic 'socket' rule). In this case the following sockets are | |
51 | - * matched in preference order: | |
52 | - * | |
53 | - * - match: if there's a fully established connection matching the | |
54 | - * _packet_ tuple | |
55 | - * | |
56 | - * - match: if there's a non-zero bound listener (possibly with a | |
57 | - * non-local address) We don't accept zero-bound listeners, since | |
58 | - * then local services could intercept traffic going through the | |
59 | - * box. | |
60 | - * | |
61 | - * Please note that there's an overlap between what a TPROXY target | |
62 | - * and a socket match will match. Normally if you have both rules the | |
63 | - * "socket" match will be the first one, effectively all packets | |
64 | - * belonging to established connections going through that one. | |
65 | - */ | |
66 | -static inline struct sock * | |
67 | -nf_tproxy_get_sock_v4(struct net *net, const u8 protocol, | |
68 | - const __be32 saddr, const __be32 daddr, | |
69 | - const __be16 sport, const __be16 dport, | |
70 | - const struct net_device *in, int lookup_type) | |
71 | -{ | |
72 | - struct sock *sk; | |
73 | - | |
74 | - /* look up socket */ | |
75 | - switch (protocol) { | |
76 | - case IPPROTO_TCP: | |
77 | - switch (lookup_type) { | |
78 | - case NFT_LOOKUP_ANY: | |
79 | - sk = __inet_lookup(net, &tcp_hashinfo, | |
80 | - saddr, sport, daddr, dport, | |
81 | - in->ifindex); | |
82 | - break; | |
83 | - case NFT_LOOKUP_LISTENER: | |
84 | - sk = inet_lookup_listener(net, &tcp_hashinfo, | |
85 | - saddr, sport, | |
86 | - daddr, dport, | |
87 | - in->ifindex); | |
88 | - | |
89 | - /* NOTE: we return listeners even if bound to | |
90 | - * 0.0.0.0, those are filtered out in | |
91 | - * xt_socket, since xt_TPROXY needs 0 bound | |
92 | - * listeners too */ | |
93 | - | |
94 | - break; | |
95 | - case NFT_LOOKUP_ESTABLISHED: | |
96 | - sk = inet_lookup_established(net, &tcp_hashinfo, | |
97 | - saddr, sport, daddr, dport, | |
98 | - in->ifindex); | |
99 | - break; | |
100 | - default: | |
101 | - WARN_ON(1); | |
102 | - sk = NULL; | |
103 | - break; | |
104 | - } | |
105 | - break; | |
106 | - case IPPROTO_UDP: | |
107 | - sk = udp4_lib_lookup(net, saddr, sport, daddr, dport, | |
108 | - in->ifindex); | |
109 | - if (sk && lookup_type != NFT_LOOKUP_ANY) { | |
110 | - int connected = (sk->sk_state == TCP_ESTABLISHED); | |
111 | - int wildcard = (inet_sk(sk)->inet_rcv_saddr == 0); | |
112 | - | |
113 | - /* NOTE: we return listeners even if bound to | |
114 | - * 0.0.0.0, those are filtered out in | |
115 | - * xt_socket, since xt_TPROXY needs 0 bound | |
116 | - * listeners too */ | |
117 | - if ((lookup_type == NFT_LOOKUP_ESTABLISHED && (!connected || wildcard)) || | |
118 | - (lookup_type == NFT_LOOKUP_LISTENER && connected)) { | |
119 | - sock_put(sk); | |
120 | - sk = NULL; | |
121 | - } | |
122 | - } | |
123 | - break; | |
124 | - default: | |
125 | - WARN_ON(1); | |
126 | - sk = NULL; | |
127 | - } | |
128 | - | |
129 | - pr_debug("tproxy socket lookup: proto %u %08x:%u -> %08x:%u, lookup type: %d, sock %p\n", | |
130 | - protocol, ntohl(saddr), ntohs(sport), ntohl(daddr), ntohs(dport), lookup_type, sk); | |
131 | - | |
132 | - return sk; | |
133 | -} | |
134 | - | |
135 | -#if IS_ENABLED(CONFIG_IPV6) | |
136 | -static inline struct sock * | |
137 | -nf_tproxy_get_sock_v6(struct net *net, const u8 protocol, | |
138 | - const struct in6_addr *saddr, const struct in6_addr *daddr, | |
139 | - const __be16 sport, const __be16 dport, | |
140 | - const struct net_device *in, int lookup_type) | |
141 | -{ | |
142 | - struct sock *sk; | |
143 | - | |
144 | - /* look up socket */ | |
145 | - switch (protocol) { | |
146 | - case IPPROTO_TCP: | |
147 | - switch (lookup_type) { | |
148 | - case NFT_LOOKUP_ANY: | |
149 | - sk = inet6_lookup(net, &tcp_hashinfo, | |
150 | - saddr, sport, daddr, dport, | |
151 | - in->ifindex); | |
152 | - break; | |
153 | - case NFT_LOOKUP_LISTENER: | |
154 | - sk = inet6_lookup_listener(net, &tcp_hashinfo, | |
155 | - saddr, sport, | |
156 | - daddr, ntohs(dport), | |
157 | - in->ifindex); | |
158 | - | |
159 | - /* NOTE: we return listeners even if bound to | |
160 | - * 0.0.0.0, those are filtered out in | |
161 | - * xt_socket, since xt_TPROXY needs 0 bound | |
162 | - * listeners too */ | |
163 | - | |
164 | - break; | |
165 | - case NFT_LOOKUP_ESTABLISHED: | |
166 | - sk = __inet6_lookup_established(net, &tcp_hashinfo, | |
167 | - saddr, sport, daddr, ntohs(dport), | |
168 | - in->ifindex); | |
169 | - break; | |
170 | - default: | |
171 | - WARN_ON(1); | |
172 | - sk = NULL; | |
173 | - break; | |
174 | - } | |
175 | - break; | |
176 | - case IPPROTO_UDP: | |
177 | - sk = udp6_lib_lookup(net, saddr, sport, daddr, dport, | |
178 | - in->ifindex); | |
179 | - if (sk && lookup_type != NFT_LOOKUP_ANY) { | |
180 | - int connected = (sk->sk_state == TCP_ESTABLISHED); | |
181 | - int wildcard = ipv6_addr_any(&inet6_sk(sk)->rcv_saddr); | |
182 | - | |
183 | - /* NOTE: we return listeners even if bound to | |
184 | - * 0.0.0.0, those are filtered out in | |
185 | - * xt_socket, since xt_TPROXY needs 0 bound | |
186 | - * listeners too */ | |
187 | - if ((lookup_type == NFT_LOOKUP_ESTABLISHED && (!connected || wildcard)) || | |
188 | - (lookup_type == NFT_LOOKUP_LISTENER && connected)) { | |
189 | - sock_put(sk); | |
190 | - sk = NULL; | |
191 | - } | |
192 | - } | |
193 | - break; | |
194 | - default: | |
195 | - WARN_ON(1); | |
196 | - sk = NULL; | |
197 | - } | |
198 | - | |
199 | - pr_debug("tproxy socket lookup: proto %u %pI6:%u -> %pI6:%u, lookup type: %d, sock %p\n", | |
200 | - protocol, saddr, ntohs(sport), daddr, ntohs(dport), lookup_type, sk); | |
201 | - | |
202 | - return sk; | |
203 | -} | |
204 | -#endif | |
205 | - | |
206 | -#endif |
net/netfilter/xt_TPROXY.c
... | ... | @@ -15,7 +15,9 @@ |
15 | 15 | #include <linux/ip.h> |
16 | 16 | #include <net/checksum.h> |
17 | 17 | #include <net/udp.h> |
18 | +#include <net/tcp.h> | |
18 | 19 | #include <net/inet_sock.h> |
20 | +#include <net/inet_hashtables.h> | |
19 | 21 | #include <linux/inetdevice.h> |
20 | 22 | #include <linux/netfilter/x_tables.h> |
21 | 23 | #include <linux/netfilter_ipv4/ip_tables.h> |
22 | 24 | |
23 | 25 | |
... | ... | @@ -26,13 +28,18 @@ |
26 | 28 | #define XT_TPROXY_HAVE_IPV6 1 |
27 | 29 | #include <net/if_inet6.h> |
28 | 30 | #include <net/addrconf.h> |
31 | +#include <net/inet6_hashtables.h> | |
29 | 32 | #include <linux/netfilter_ipv6/ip6_tables.h> |
30 | 33 | #include <net/netfilter/ipv6/nf_defrag_ipv6.h> |
31 | 34 | #endif |
32 | 35 | |
33 | -#include <net/netfilter/nf_tproxy_core.h> | |
34 | 36 | #include <linux/netfilter/xt_TPROXY.h> |
35 | 37 | |
38 | +enum nf_tproxy_lookup_t { | |
39 | + NFT_LOOKUP_LISTENER, | |
40 | + NFT_LOOKUP_ESTABLISHED, | |
41 | +}; | |
42 | + | |
36 | 43 | static bool tproxy_sk_is_transparent(struct sock *sk) |
37 | 44 | { |
38 | 45 | if (sk->sk_state != TCP_TIME_WAIT) { |
... | ... | @@ -67,6 +74,157 @@ |
67 | 74 | |
68 | 75 | return laddr ? laddr : daddr; |
69 | 76 | } |
77 | + | |
78 | +/* | |
79 | + * This is used when the user wants to intercept a connection matching | |
80 | + * an explicit iptables rule. In this case the sockets are assumed | |
81 | + * matching in preference order: | |
82 | + * | |
83 | + * - match: if there's a fully established connection matching the | |
84 | + * _packet_ tuple, it is returned, assuming the redirection | |
85 | + * already took place and we process a packet belonging to an | |
86 | + * established connection | |
87 | + * | |
88 | + * - match: if there's a listening socket matching the redirection | |
89 | + * (e.g. on-port & on-ip of the connection), it is returned, | |
90 | + * regardless if it was bound to 0.0.0.0 or an explicit | |
91 | + * address. The reasoning is that if there's an explicit rule, it | |
92 | + * does not really matter if the listener is bound to an interface | |
93 | + * or to 0. The user already stated that he wants redirection | |
94 | + * (since he added the rule). | |
95 | + * | |
96 | + * Please note that there's an overlap between what a TPROXY target | |
97 | + * and a socket match will match. Normally if you have both rules the | |
98 | + * "socket" match will be the first one, effectively all packets | |
99 | + * belonging to established connections going through that one. | |
100 | + */ | |
101 | +static inline struct sock * | |
102 | +nf_tproxy_get_sock_v4(struct net *net, const u8 protocol, | |
103 | + const __be32 saddr, const __be32 daddr, | |
104 | + const __be16 sport, const __be16 dport, | |
105 | + const struct net_device *in, | |
106 | + const enum nf_tproxy_lookup_t lookup_type) | |
107 | +{ | |
108 | + struct sock *sk; | |
109 | + | |
110 | + switch (protocol) { | |
111 | + case IPPROTO_TCP: | |
112 | + switch (lookup_type) { | |
113 | + case NFT_LOOKUP_LISTENER: | |
114 | + sk = inet_lookup_listener(net, &tcp_hashinfo, | |
115 | + saddr, sport, | |
116 | + daddr, dport, | |
117 | + in->ifindex); | |
118 | + | |
119 | + /* NOTE: we return listeners even if bound to | |
120 | + * 0.0.0.0, those are filtered out in | |
121 | + * xt_socket, since xt_TPROXY needs 0 bound | |
122 | + * listeners too | |
123 | + */ | |
124 | + break; | |
125 | + case NFT_LOOKUP_ESTABLISHED: | |
126 | + sk = inet_lookup_established(net, &tcp_hashinfo, | |
127 | + saddr, sport, daddr, dport, | |
128 | + in->ifindex); | |
129 | + break; | |
130 | + default: | |
131 | + BUG(); | |
132 | + } | |
133 | + break; | |
134 | + case IPPROTO_UDP: | |
135 | + sk = udp4_lib_lookup(net, saddr, sport, daddr, dport, | |
136 | + in->ifindex); | |
137 | + if (sk) { | |
138 | + int connected = (sk->sk_state == TCP_ESTABLISHED); | |
139 | + int wildcard = (inet_sk(sk)->inet_rcv_saddr == 0); | |
140 | + | |
141 | + /* NOTE: we return listeners even if bound to | |
142 | + * 0.0.0.0, those are filtered out in | |
143 | + * xt_socket, since xt_TPROXY needs 0 bound | |
144 | + * listeners too | |
145 | + */ | |
146 | + if ((lookup_type == NFT_LOOKUP_ESTABLISHED && (!connected || wildcard)) || | |
147 | + (lookup_type == NFT_LOOKUP_LISTENER && connected)) { | |
148 | + sock_put(sk); | |
149 | + sk = NULL; | |
150 | + } | |
151 | + } | |
152 | + break; | |
153 | + default: | |
154 | + WARN_ON(1); | |
155 | + sk = NULL; | |
156 | + } | |
157 | + | |
158 | + pr_debug("tproxy socket lookup: proto %u %08x:%u -> %08x:%u, lookup type: %d, sock %p\n", | |
159 | + protocol, ntohl(saddr), ntohs(sport), ntohl(daddr), ntohs(dport), lookup_type, sk); | |
160 | + | |
161 | + return sk; | |
162 | +} | |
163 | + | |
164 | +#if IS_ENABLED(CONFIG_IPV6) | |
165 | +static inline struct sock * | |
166 | +nf_tproxy_get_sock_v6(struct net *net, const u8 protocol, | |
167 | + const struct in6_addr *saddr, const struct in6_addr *daddr, | |
168 | + const __be16 sport, const __be16 dport, | |
169 | + const struct net_device *in, | |
170 | + const enum nf_tproxy_lookup_t lookup_type) | |
171 | +{ | |
172 | + struct sock *sk; | |
173 | + | |
174 | + switch (protocol) { | |
175 | + case IPPROTO_TCP: | |
176 | + switch (lookup_type) { | |
177 | + case NFT_LOOKUP_LISTENER: | |
178 | + sk = inet6_lookup_listener(net, &tcp_hashinfo, | |
179 | + saddr, sport, | |
180 | + daddr, ntohs(dport), | |
181 | + in->ifindex); | |
182 | + | |
183 | + /* NOTE: we return listeners even if bound to | |
184 | + * 0.0.0.0, those are filtered out in | |
185 | + * xt_socket, since xt_TPROXY needs 0 bound | |
186 | + * listeners too | |
187 | + */ | |
188 | + break; | |
189 | + case NFT_LOOKUP_ESTABLISHED: | |
190 | + sk = __inet6_lookup_established(net, &tcp_hashinfo, | |
191 | + saddr, sport, daddr, ntohs(dport), | |
192 | + in->ifindex); | |
193 | + break; | |
194 | + default: | |
195 | + BUG(); | |
196 | + } | |
197 | + break; | |
198 | + case IPPROTO_UDP: | |
199 | + sk = udp6_lib_lookup(net, saddr, sport, daddr, dport, | |
200 | + in->ifindex); | |
201 | + if (sk) { | |
202 | + int connected = (sk->sk_state == TCP_ESTABLISHED); | |
203 | + int wildcard = ipv6_addr_any(&inet6_sk(sk)->rcv_saddr); | |
204 | + | |
205 | + /* NOTE: we return listeners even if bound to | |
206 | + * 0.0.0.0, those are filtered out in | |
207 | + * xt_socket, since xt_TPROXY needs 0 bound | |
208 | + * listeners too | |
209 | + */ | |
210 | + if ((lookup_type == NFT_LOOKUP_ESTABLISHED && (!connected || wildcard)) || | |
211 | + (lookup_type == NFT_LOOKUP_LISTENER && connected)) { | |
212 | + sock_put(sk); | |
213 | + sk = NULL; | |
214 | + } | |
215 | + } | |
216 | + break; | |
217 | + default: | |
218 | + WARN_ON(1); | |
219 | + sk = NULL; | |
220 | + } | |
221 | + | |
222 | + pr_debug("tproxy socket lookup: proto %u %pI6:%u -> %pI6:%u, lookup type: %d, sock %p\n", | |
223 | + protocol, saddr, ntohs(sport), daddr, ntohs(dport), lookup_type, sk); | |
224 | + | |
225 | + return sk; | |
226 | +} | |
227 | +#endif | |
70 | 228 | |
71 | 229 | /** |
72 | 230 | * tproxy_handle_time_wait4 - handle IPv4 TCP TIME_WAIT reopen redirections |
net/netfilter/xt_socket.c
... | ... | @@ -19,12 +19,12 @@ |
19 | 19 | #include <net/icmp.h> |
20 | 20 | #include <net/sock.h> |
21 | 21 | #include <net/inet_sock.h> |
22 | -#include <net/netfilter/nf_tproxy_core.h> | |
23 | 22 | #include <net/netfilter/ipv4/nf_defrag_ipv4.h> |
24 | 23 | |
25 | 24 | #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) |
26 | 25 | #define XT_SOCKET_HAVE_IPV6 1 |
27 | 26 | #include <linux/netfilter_ipv6/ip6_tables.h> |
27 | +#include <net/inet6_hashtables.h> | |
28 | 28 | #include <net/netfilter/ipv6/nf_defrag_ipv6.h> |
29 | 29 | #endif |
30 | 30 | |
... | ... | @@ -101,6 +101,43 @@ |
101 | 101 | return 0; |
102 | 102 | } |
103 | 103 | |
104 | +/* "socket" match based redirection (no specific rule) | |
105 | + * =================================================== | |
106 | + * | |
107 | + * There are connections with dynamic endpoints (e.g. FTP data | |
108 | + * connection) that the user is unable to add explicit rules | |
109 | + * for. These are taken care of by a generic "socket" rule. It is | |
110 | + * assumed that the proxy application is trusted to open such | |
111 | + * connections without explicit iptables rule (except of course the | |
112 | + * generic 'socket' rule). In this case the following sockets are | |
113 | + * matched in preference order: | |
114 | + * | |
115 | + * - match: if there's a fully established connection matching the | |
116 | + * _packet_ tuple | |
117 | + * | |
118 | + * - match: if there's a non-zero bound listener (possibly with a | |
119 | + * non-local address) We don't accept zero-bound listeners, since | |
120 | + * then local services could intercept traffic going through the | |
121 | + * box. | |
122 | + */ | |
123 | +static struct sock * | |
124 | +xt_socket_get_sock_v4(struct net *net, const u8 protocol, | |
125 | + const __be32 saddr, const __be32 daddr, | |
126 | + const __be16 sport, const __be16 dport, | |
127 | + const struct net_device *in) | |
128 | +{ | |
129 | + switch (protocol) { | |
130 | + case IPPROTO_TCP: | |
131 | + return __inet_lookup(net, &tcp_hashinfo, | |
132 | + saddr, sport, daddr, dport, | |
133 | + in->ifindex); | |
134 | + case IPPROTO_UDP: | |
135 | + return udp4_lib_lookup(net, saddr, sport, daddr, dport, | |
136 | + in->ifindex); | |
137 | + } | |
138 | + return NULL; | |
139 | +} | |
140 | + | |
104 | 141 | static bool |
105 | 142 | socket_match(const struct sk_buff *skb, struct xt_action_param *par, |
106 | 143 | const struct xt_socket_mtinfo1 *info) |
107 | 144 | |
... | ... | @@ -156,9 +193,9 @@ |
156 | 193 | #endif |
157 | 194 | |
158 | 195 | if (!sk) |
159 | - sk = nf_tproxy_get_sock_v4(dev_net(skb->dev), protocol, | |
196 | + sk = xt_socket_get_sock_v4(dev_net(skb->dev), protocol, | |
160 | 197 | saddr, daddr, sport, dport, |
161 | - par->in, NFT_LOOKUP_ANY); | |
198 | + par->in); | |
162 | 199 | if (sk) { |
163 | 200 | bool wildcard; |
164 | 201 | bool transparent = true; |
... | ... | @@ -261,6 +298,25 @@ |
261 | 298 | return 0; |
262 | 299 | } |
263 | 300 | |
301 | +static struct sock * | |
302 | +xt_socket_get_sock_v6(struct net *net, const u8 protocol, | |
303 | + const struct in6_addr *saddr, const struct in6_addr *daddr, | |
304 | + const __be16 sport, const __be16 dport, | |
305 | + const struct net_device *in) | |
306 | +{ | |
307 | + switch (protocol) { | |
308 | + case IPPROTO_TCP: | |
309 | + return inet6_lookup(net, &tcp_hashinfo, | |
310 | + saddr, sport, daddr, dport, | |
311 | + in->ifindex); | |
312 | + case IPPROTO_UDP: | |
313 | + return udp6_lib_lookup(net, saddr, sport, daddr, dport, | |
314 | + in->ifindex); | |
315 | + } | |
316 | + | |
317 | + return NULL; | |
318 | +} | |
319 | + | |
264 | 320 | static bool |
265 | 321 | socket_mt6_v1_v2(const struct sk_buff *skb, struct xt_action_param *par) |
266 | 322 | { |
267 | 323 | |
... | ... | @@ -298,9 +354,9 @@ |
298 | 354 | } |
299 | 355 | |
300 | 356 | if (!sk) |
301 | - sk = nf_tproxy_get_sock_v6(dev_net(skb->dev), tproto, | |
357 | + sk = xt_socket_get_sock_v6(dev_net(skb->dev), tproto, | |
302 | 358 | saddr, daddr, sport, dport, |
303 | - par->in, NFT_LOOKUP_ANY); | |
359 | + par->in); | |
304 | 360 | if (sk) { |
305 | 361 | bool wildcard; |
306 | 362 | bool transparent = true; |