Skip to content

Commit b64c925

Browse files
bazsikaber
authored andcommitted
tproxy: added IPv6 support to the socket match
The ICMP extraction bits were contributed by Harry Mason. Signed-off-by: Balazs Scheidler <[email protected]> Signed-off-by: KOVACS Krisztian <[email protected]> Signed-off-by: Patrick McHardy <[email protected]>
1 parent 6ad7889 commit b64c925

File tree

1 file changed

+154
-11
lines changed

1 file changed

+154
-11
lines changed

net/netfilter/xt_socket.c

Lines changed: 154 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,15 @@
1414
#include <linux/skbuff.h>
1515
#include <linux/netfilter/x_tables.h>
1616
#include <linux/netfilter_ipv4/ip_tables.h>
17+
#include <linux/netfilter_ipv6/ip6_tables.h>
1718
#include <net/tcp.h>
1819
#include <net/udp.h>
1920
#include <net/icmp.h>
2021
#include <net/sock.h>
2122
#include <net/inet_sock.h>
2223
#include <net/netfilter/nf_tproxy_core.h>
2324
#include <net/netfilter/ipv4/nf_defrag_ipv4.h>
25+
#include <net/netfilter/ipv6/nf_defrag_ipv6.h>
2426

2527
#include <linux/netfilter/xt_socket.h>
2628

@@ -30,7 +32,7 @@
3032
#endif
3133

3234
static int
33-
extract_icmp_fields(const struct sk_buff *skb,
35+
extract_icmp4_fields(const struct sk_buff *skb,
3436
u8 *protocol,
3537
__be32 *raddr,
3638
__be32 *laddr,
@@ -86,7 +88,6 @@ extract_icmp_fields(const struct sk_buff *skb,
8688
return 0;
8789
}
8890

89-
9091
static bool
9192
socket_match(const struct sk_buff *skb, struct xt_action_param *par,
9293
const struct xt_socket_mtinfo1 *info)
@@ -115,7 +116,7 @@ socket_match(const struct sk_buff *skb, struct xt_action_param *par,
115116
dport = hp->dest;
116117

117118
} else if (iph->protocol == IPPROTO_ICMP) {
118-
if (extract_icmp_fields(skb, &protocol, &saddr, &daddr,
119+
if (extract_icmp4_fields(skb, &protocol, &saddr, &daddr,
119120
&sport, &dport))
120121
return false;
121122
} else {
@@ -165,32 +166,157 @@ socket_match(const struct sk_buff *skb, struct xt_action_param *par,
165166
sk = NULL;
166167
}
167168

168-
pr_debug("proto %u %08x:%u -> %08x:%u (orig %08x:%u) sock %p\n",
169-
protocol, ntohl(saddr), ntohs(sport),
170-
ntohl(daddr), ntohs(dport),
171-
ntohl(iph->daddr), hp ? ntohs(hp->dest) : 0, sk);
169+
pr_debug("proto %hhu %pI4:%hu -> %pI4:%hu (orig %pI4:%hu) sock %p\n",
170+
protocol, &saddr, ntohs(sport),
171+
&daddr, ntohs(dport),
172+
&iph->daddr, hp ? ntohs(hp->dest) : 0, sk);
172173

173174
return (sk != NULL);
174175
}
175176

176177
static bool
177-
socket_mt_v0(const struct sk_buff *skb, struct xt_action_param *par)
178+
socket_mt4_v0(const struct sk_buff *skb, struct xt_action_param *par)
178179
{
179180
return socket_match(skb, par, NULL);
180181
}
181182

182183
static bool
183-
socket_mt_v1(const struct sk_buff *skb, struct xt_action_param *par)
184+
socket_mt4_v1(const struct sk_buff *skb, struct xt_action_param *par)
184185
{
185186
return socket_match(skb, par, par->matchinfo);
186187
}
187188

189+
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
190+
191+
static int
192+
extract_icmp6_fields(const struct sk_buff *skb,
193+
unsigned int outside_hdrlen,
194+
u8 *protocol,
195+
struct in6_addr **raddr,
196+
struct in6_addr **laddr,
197+
__be16 *rport,
198+
__be16 *lport)
199+
{
200+
struct ipv6hdr *inside_iph, _inside_iph;
201+
struct icmp6hdr *icmph, _icmph;
202+
__be16 *ports, _ports[2];
203+
u8 inside_nexthdr;
204+
int inside_hdrlen;
205+
206+
icmph = skb_header_pointer(skb, outside_hdrlen,
207+
sizeof(_icmph), &_icmph);
208+
if (icmph == NULL)
209+
return 1;
210+
211+
if (icmph->icmp6_type & ICMPV6_INFOMSG_MASK)
212+
return 1;
213+
214+
inside_iph = skb_header_pointer(skb, outside_hdrlen + sizeof(_icmph), sizeof(_inside_iph), &_inside_iph);
215+
if (inside_iph == NULL)
216+
return 1;
217+
inside_nexthdr = inside_iph->nexthdr;
218+
219+
inside_hdrlen = ipv6_skip_exthdr(skb, outside_hdrlen + sizeof(_icmph) + sizeof(_inside_iph), &inside_nexthdr);
220+
if (inside_hdrlen < 0)
221+
return 1; /* hjm: Packet has no/incomplete transport layer headers. */
222+
223+
if (inside_nexthdr != IPPROTO_TCP &&
224+
inside_nexthdr != IPPROTO_UDP)
225+
return 1;
226+
227+
ports = skb_header_pointer(skb, inside_hdrlen,
228+
sizeof(_ports), &_ports);
229+
if (ports == NULL)
230+
return 1;
231+
232+
/* the inside IP packet is the one quoted from our side, thus
233+
* its saddr is the local address */
234+
*protocol = inside_nexthdr;
235+
*laddr = &inside_iph->saddr;
236+
*lport = ports[0];
237+
*raddr = &inside_iph->daddr;
238+
*rport = ports[1];
239+
240+
return 0;
241+
}
242+
243+
static bool
244+
socket_mt6_v1(const struct sk_buff *skb, struct xt_action_param *par)
245+
{
246+
struct ipv6hdr *iph = ipv6_hdr(skb);
247+
struct udphdr _hdr, *hp = NULL;
248+
struct sock *sk;
249+
struct in6_addr *daddr, *saddr;
250+
__be16 dport, sport;
251+
int thoff;
252+
u8 tproto;
253+
const struct xt_socket_mtinfo1 *info = (struct xt_socket_mtinfo1 *) par->matchinfo;
254+
255+
tproto = ipv6_find_hdr(skb, &thoff, -1, NULL);
256+
if (tproto < 0) {
257+
pr_debug("unable to find transport header in IPv6 packet, dropping\n");
258+
return NF_DROP;
259+
}
260+
261+
if (tproto == IPPROTO_UDP || tproto == IPPROTO_TCP) {
262+
hp = skb_header_pointer(skb, thoff,
263+
sizeof(_hdr), &_hdr);
264+
if (hp == NULL)
265+
return false;
266+
267+
saddr = &iph->saddr;
268+
sport = hp->source;
269+
daddr = &iph->daddr;
270+
dport = hp->dest;
271+
272+
} else if (tproto == IPPROTO_ICMPV6) {
273+
if (extract_icmp6_fields(skb, thoff, &tproto, &saddr, &daddr,
274+
&sport, &dport))
275+
return false;
276+
} else {
277+
return false;
278+
}
279+
280+
sk = nf_tproxy_get_sock_v6(dev_net(skb->dev), tproto,
281+
saddr, daddr, sport, dport, par->in, NFT_LOOKUP_ANY);
282+
if (sk != NULL) {
283+
bool wildcard;
284+
bool transparent = true;
285+
286+
/* Ignore sockets listening on INADDR_ANY */
287+
wildcard = (sk->sk_state != TCP_TIME_WAIT &&
288+
ipv6_addr_any(&inet6_sk(sk)->rcv_saddr));
289+
290+
/* Ignore non-transparent sockets,
291+
if XT_SOCKET_TRANSPARENT is used */
292+
if (info && info->flags & XT_SOCKET_TRANSPARENT)
293+
transparent = ((sk->sk_state != TCP_TIME_WAIT &&
294+
inet_sk(sk)->transparent) ||
295+
(sk->sk_state == TCP_TIME_WAIT &&
296+
inet_twsk(sk)->tw_transparent));
297+
298+
nf_tproxy_put_sock(sk);
299+
300+
if (wildcard || !transparent)
301+
sk = NULL;
302+
}
303+
304+
pr_debug("proto %hhu %pI6:%hu -> %pI6:%hu "
305+
"(orig %pI6:%hu) sock %p\n",
306+
tproto, saddr, ntohs(sport),
307+
daddr, ntohs(dport),
308+
&iph->daddr, hp ? ntohs(hp->dest) : 0, sk);
309+
310+
return (sk != NULL);
311+
}
312+
#endif
313+
188314
static struct xt_match socket_mt_reg[] __read_mostly = {
189315
{
190316
.name = "socket",
191317
.revision = 0,
192318
.family = NFPROTO_IPV4,
193-
.match = socket_mt_v0,
319+
.match = socket_mt4_v0,
194320
.hooks = (1 << NF_INET_PRE_ROUTING) |
195321
(1 << NF_INET_LOCAL_IN),
196322
.me = THIS_MODULE,
@@ -199,17 +325,33 @@ static struct xt_match socket_mt_reg[] __read_mostly = {
199325
.name = "socket",
200326
.revision = 1,
201327
.family = NFPROTO_IPV4,
202-
.match = socket_mt_v1,
328+
.match = socket_mt4_v1,
203329
.matchsize = sizeof(struct xt_socket_mtinfo1),
204330
.hooks = (1 << NF_INET_PRE_ROUTING) |
205331
(1 << NF_INET_LOCAL_IN),
206332
.me = THIS_MODULE,
207333
},
334+
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
335+
{
336+
.name = "socket",
337+
.revision = 1,
338+
.family = NFPROTO_IPV6,
339+
.match = socket_mt6_v1,
340+
.matchsize = sizeof(struct xt_socket_mtinfo1),
341+
.hooks = (1 << NF_INET_PRE_ROUTING) |
342+
(1 << NF_INET_LOCAL_IN),
343+
.me = THIS_MODULE,
344+
},
345+
#endif
208346
};
209347

210348
static int __init socket_mt_init(void)
211349
{
212350
nf_defrag_ipv4_enable();
351+
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
352+
nf_defrag_ipv6_enable();
353+
#endif
354+
213355
return xt_register_matches(socket_mt_reg, ARRAY_SIZE(socket_mt_reg));
214356
}
215357

@@ -225,3 +367,4 @@ MODULE_LICENSE("GPL");
225367
MODULE_AUTHOR("Krisztian Kovacs, Balazs Scheidler");
226368
MODULE_DESCRIPTION("x_tables socket match module");
227369
MODULE_ALIAS("ipt_socket");
370+
MODULE_ALIAS("ip6t_socket");

0 commit comments

Comments
 (0)