-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
The extracted functions will likely be usefull to implement tproxy support in nf_tables. Extrancted functions: - nf_tproxy_sk_is_transparent - nf_tproxy_laddr4 - nf_tproxy_handle_time_wait4 - nf_tproxy_get_sock_v4 - nf_tproxy_laddr6 - nf_tproxy_handle_time_wait6 - nf_tproxy_get_sock_v6 (nf_)tproxy_handle_time_wait6 also needed some refactor as its current implementation was xtables-specific. Signed-off-by: Máté Eckl <ecklm94@gmail.com> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
- Loading branch information
Máté Eckl
authored and
Pablo Neira Ayuso
committed
Jun 2, 2018
1 parent
8d6e555
commit 45ca4e0
Showing
9 changed files
with
436 additions
and
339 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
#ifndef _NF_TPROXY_H_ | ||
#define _NF_TPROXY_H_ | ||
|
||
#include <net/tcp.h> | ||
|
||
enum nf_tproxy_lookup_t { | ||
NF_TPROXY_LOOKUP_LISTENER, | ||
NF_TPROXY_LOOKUP_ESTABLISHED, | ||
}; | ||
|
||
static inline bool nf_tproxy_sk_is_transparent(struct sock *sk) | ||
{ | ||
if (inet_sk_transparent(sk)) | ||
return true; | ||
|
||
sock_gen_put(sk); | ||
return false; | ||
} | ||
|
||
__be32 nf_tproxy_laddr4(struct sk_buff *skb, __be32 user_laddr, __be32 daddr); | ||
|
||
/** | ||
* nf_tproxy_handle_time_wait4 - handle IPv4 TCP TIME_WAIT reopen redirections | ||
* @skb: The skb being processed. | ||
* @laddr: IPv4 address to redirect to or zero. | ||
* @lport: TCP port to redirect to or zero. | ||
* @sk: The TIME_WAIT TCP socket found by the lookup. | ||
* | ||
* We have to handle SYN packets arriving to TIME_WAIT sockets | ||
* differently: instead of reopening the connection we should rather | ||
* redirect the new connection to the proxy if there's a listener | ||
* socket present. | ||
* | ||
* nf_tproxy_handle_time_wait4() consumes the socket reference passed in. | ||
* | ||
* Returns the listener socket if there's one, the TIME_WAIT socket if | ||
* no such listener is found, or NULL if the TCP header is incomplete. | ||
*/ | ||
struct sock * | ||
nf_tproxy_handle_time_wait4(struct net *net, struct sk_buff *skb, | ||
__be32 laddr, __be16 lport, struct sock *sk); | ||
|
||
/* | ||
* This is used when the user wants to intercept a connection matching | ||
* an explicit iptables rule. In this case the sockets are assumed | ||
* matching in preference order: | ||
* | ||
* - match: if there's a fully established connection matching the | ||
* _packet_ tuple, it is returned, assuming the redirection | ||
* already took place and we process a packet belonging to an | ||
* established connection | ||
* | ||
* - match: if there's a listening socket matching the redirection | ||
* (e.g. on-port & on-ip of the connection), it is returned, | ||
* regardless if it was bound to 0.0.0.0 or an explicit | ||
* address. The reasoning is that if there's an explicit rule, it | ||
* does not really matter if the listener is bound to an interface | ||
* or to 0. The user already stated that he wants redirection | ||
* (since he added the rule). | ||
* | ||
* Please note that there's an overlap between what a TPROXY target | ||
* and a socket match will match. Normally if you have both rules the | ||
* "socket" match will be the first one, effectively all packets | ||
* belonging to established connections going through that one. | ||
*/ | ||
struct sock * | ||
nf_tproxy_get_sock_v4(struct net *net, struct sk_buff *skb, void *hp, | ||
const u8 protocol, | ||
const __be32 saddr, const __be32 daddr, | ||
const __be16 sport, const __be16 dport, | ||
const struct net_device *in, | ||
const enum nf_tproxy_lookup_t lookup_type); | ||
|
||
const struct in6_addr * | ||
nf_tproxy_laddr6(struct sk_buff *skb, const struct in6_addr *user_laddr, | ||
const struct in6_addr *daddr); | ||
|
||
/** | ||
* nf_tproxy_handle_time_wait6 - handle IPv6 TCP TIME_WAIT reopen redirections | ||
* @skb: The skb being processed. | ||
* @tproto: Transport protocol. | ||
* @thoff: Transport protocol header offset. | ||
* @net: Network namespace. | ||
* @laddr: IPv6 address to redirect to. | ||
* @lport: TCP port to redirect to or zero. | ||
* @sk: The TIME_WAIT TCP socket found by the lookup. | ||
* | ||
* We have to handle SYN packets arriving to TIME_WAIT sockets | ||
* differently: instead of reopening the connection we should rather | ||
* redirect the new connection to the proxy if there's a listener | ||
* socket present. | ||
* | ||
* nf_tproxy_handle_time_wait6() consumes the socket reference passed in. | ||
* | ||
* Returns the listener socket if there's one, the TIME_WAIT socket if | ||
* no such listener is found, or NULL if the TCP header is incomplete. | ||
*/ | ||
struct sock * | ||
nf_tproxy_handle_time_wait6(struct sk_buff *skb, int tproto, int thoff, | ||
struct net *net, | ||
const struct in6_addr *laddr, | ||
const __be16 lport, | ||
struct sock *sk); | ||
|
||
struct sock * | ||
nf_tproxy_get_sock_v6(struct net *net, struct sk_buff *skb, int thoff, void *hp, | ||
const u8 protocol, | ||
const struct in6_addr *saddr, const struct in6_addr *daddr, | ||
const __be16 sport, const __be16 dport, | ||
const struct net_device *in, | ||
const enum nf_tproxy_lookup_t lookup_type); | ||
|
||
#endif /* _NF_TPROXY_H_ */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
/* | ||
* Copyright (C) 2007-2008 BalaBit IT Ltd. | ||
* Author: Krisztian Kovacs | ||
* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License version 2 as | ||
* published by the Free Software Foundation. | ||
* | ||
*/ | ||
|
||
#include <net/netfilter/nf_tproxy.h> | ||
#include <linux/module.h> | ||
#include <linux/skbuff.h> | ||
#include <net/sock.h> | ||
#include <net/inet_sock.h> | ||
#include <linux/ip.h> | ||
#include <net/checksum.h> | ||
#include <net/udp.h> | ||
#include <net/tcp.h> | ||
#include <linux/inetdevice.h> | ||
|
||
struct sock * | ||
nf_tproxy_handle_time_wait4(struct net *net, struct sk_buff *skb, | ||
__be32 laddr, __be16 lport, struct sock *sk) | ||
{ | ||
const struct iphdr *iph = ip_hdr(skb); | ||
struct tcphdr _hdr, *hp; | ||
|
||
hp = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_hdr), &_hdr); | ||
if (hp == NULL) { | ||
inet_twsk_put(inet_twsk(sk)); | ||
return NULL; | ||
} | ||
|
||
if (hp->syn && !hp->rst && !hp->ack && !hp->fin) { | ||
/* SYN to a TIME_WAIT socket, we'd rather redirect it | ||
* to a listener socket if there's one */ | ||
struct sock *sk2; | ||
|
||
sk2 = nf_tproxy_get_sock_v4(net, skb, hp, iph->protocol, | ||
iph->saddr, laddr ? laddr : iph->daddr, | ||
hp->source, lport ? lport : hp->dest, | ||
skb->dev, NF_TPROXY_LOOKUP_LISTENER); | ||
if (sk2) { | ||
inet_twsk_deschedule_put(inet_twsk(sk)); | ||
sk = sk2; | ||
} | ||
} | ||
|
||
return sk; | ||
} | ||
EXPORT_SYMBOL_GPL(nf_tproxy_handle_time_wait4); | ||
|
||
__be32 nf_tproxy_laddr4(struct sk_buff *skb, __be32 user_laddr, __be32 daddr) | ||
{ | ||
struct in_device *indev; | ||
__be32 laddr; | ||
|
||
if (user_laddr) | ||
return user_laddr; | ||
|
||
laddr = 0; | ||
indev = __in_dev_get_rcu(skb->dev); | ||
for_primary_ifa(indev) { | ||
laddr = ifa->ifa_local; | ||
break; | ||
} endfor_ifa(indev); | ||
|
||
return laddr ? laddr : daddr; | ||
} | ||
EXPORT_SYMBOL_GPL(nf_tproxy_laddr4); | ||
|
||
struct sock * | ||
nf_tproxy_get_sock_v4(struct net *net, struct sk_buff *skb, void *hp, | ||
const u8 protocol, | ||
const __be32 saddr, const __be32 daddr, | ||
const __be16 sport, const __be16 dport, | ||
const struct net_device *in, | ||
const enum nf_tproxy_lookup_t lookup_type) | ||
{ | ||
struct sock *sk; | ||
struct tcphdr *tcph; | ||
|
||
switch (protocol) { | ||
case IPPROTO_TCP: | ||
switch (lookup_type) { | ||
case NF_TPROXY_LOOKUP_LISTENER: | ||
tcph = hp; | ||
sk = inet_lookup_listener(net, &tcp_hashinfo, skb, | ||
ip_hdrlen(skb) + | ||
__tcp_hdrlen(tcph), | ||
saddr, sport, | ||
daddr, dport, | ||
in->ifindex, 0); | ||
|
||
if (sk && !refcount_inc_not_zero(&sk->sk_refcnt)) | ||
sk = NULL; | ||
/* NOTE: we return listeners even if bound to | ||
* 0.0.0.0, those are filtered out in | ||
* xt_socket, since xt_TPROXY needs 0 bound | ||
* listeners too | ||
*/ | ||
break; | ||
case NF_TPROXY_LOOKUP_ESTABLISHED: | ||
sk = inet_lookup_established(net, &tcp_hashinfo, | ||
saddr, sport, daddr, dport, | ||
in->ifindex); | ||
break; | ||
default: | ||
BUG(); | ||
} | ||
break; | ||
case IPPROTO_UDP: | ||
sk = udp4_lib_lookup(net, saddr, sport, daddr, dport, | ||
in->ifindex); | ||
if (sk) { | ||
int connected = (sk->sk_state == TCP_ESTABLISHED); | ||
int wildcard = (inet_sk(sk)->inet_rcv_saddr == 0); | ||
|
||
/* NOTE: we return listeners even if bound to | ||
* 0.0.0.0, those are filtered out in | ||
* xt_socket, since xt_TPROXY needs 0 bound | ||
* listeners too | ||
*/ | ||
if ((lookup_type == NF_TPROXY_LOOKUP_ESTABLISHED && | ||
(!connected || wildcard)) || | ||
(lookup_type == NF_TPROXY_LOOKUP_LISTENER && connected)) { | ||
sock_put(sk); | ||
sk = NULL; | ||
} | ||
} | ||
break; | ||
default: | ||
WARN_ON(1); | ||
sk = NULL; | ||
} | ||
|
||
pr_debug("tproxy socket lookup: proto %u %08x:%u -> %08x:%u, lookup type: %d, sock %p\n", | ||
protocol, ntohl(saddr), ntohs(sport), ntohl(daddr), ntohs(dport), lookup_type, sk); | ||
|
||
return sk; | ||
} | ||
EXPORT_SYMBOL_GPL(nf_tproxy_get_sock_v4); | ||
|
||
MODULE_LICENSE("GPL"); | ||
MODULE_AUTHOR("Balazs Scheidler, Krisztian Kovacs"); | ||
MODULE_DESCRIPTION("Netfilter IPv4 transparent proxy support"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.