* [PATCH/RFC 00/13] Transparent proxying patches, take two
@ 2007-03-05 15:44 KOVACS Krisztian
2007-03-05 15:45 ` [PATCH/RFC 01/13] Implement local diversion of IPv4 skbs KOVACS Krisztian
` (12 more replies)
0 siblings, 13 replies; 14+ messages in thread
From: KOVACS Krisztian @ 2007-03-05 15:44 UTC (permalink / raw)
To: netdev
Hi,
These patches are my second try at providing Linux 2.2-like transparent
proxying support for Linux 2.6.
Major changes since the first version:
- iptable_tproxy now does IPv4 fragment reassembly (necessary for
processing TCP/UDP header)
- The removal of the source address check in ip_route_output() was
incorrect. Instead, I've implemented a separate setsockopt-settable
per-socket flag (setting it requires CAP_NET_ADMIN) to selectively
loosen that check in ip_route_output().
Besides these, I've tried to fix all the problems raised on netdev@ in
January.
Unfortunately the newly introduced IP_TRANSPARENT socket option leads to
a quite intrusive set of patches touching core IPv4 routing and TCP
code, however this was necessary as DaveM rejected our idea of using
IP_FREEBIND instead (and he's right, of course, as it would have caused
ABI breakage.) The current approach works by adding a new bit to the
flag field in "struct flowi".
Furthermore, I haven't removed the IPv4 routing local diversion code
(caching socket lookups in the skb) yet. Patrick recommended throwing it
out altogether and use mark-based policy routing instead, but I still
think that would be harming usability as the user would need to
harmonize the configuration in order to have two completely independent
subsystems interoperate.
--
Regards,
Krisztian Kovacs
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH/RFC 01/13] Implement local diversion of IPv4 skbs
2007-03-05 15:44 [PATCH/RFC 00/13] Transparent proxying patches, take two KOVACS Krisztian
@ 2007-03-05 15:45 ` KOVACS Krisztian
2007-03-05 15:45 ` [PATCH/RFC 02/13] Port redirection support for TCP KOVACS Krisztian
` (11 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: KOVACS Krisztian @ 2007-03-05 15:45 UTC (permalink / raw)
To: netdev
The input path for non-local bound sockets requires diverting certain
packets locally, even if their destination IP address is not
considered local. We achieve this by assigning a specially crafted dst
entry to these skbs, and optionally also attaching a socket to the skb
so that the upper layer code does not need to redo the socket lookup.
We also have to be able to differentiate between these fake entries
and "real" entries in the cache: it is perfectly legal that the
diversion is done only for certain TCP or UDP packets and not for all
packets of the flow. Since these special dst entries are used only by
the iptables tproxy code, and that code uses exclusively these
entries, simply flagging these entries as DST_DIVERTED is OK. All
other cache lookup paths skip diverted entries, while our new
ip_divert_local() function uses exclusively diverted dst entries.
Signed-off-by: KOVACS Krisztian <hidden@balabit.hu>
---
include/net/dst.h | 1
include/net/route.h | 2 +
net/ipv4/route.c | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 115 insertions(+), 1 deletions(-)
diff --git a/include/net/dst.h b/include/net/dst.h
index e12a8ce..4cd0745 100644
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -48,6 +48,7 @@ struct dst_entry
#define DST_NOPOLICY 4
#define DST_NOHASH 8
#define DST_BALANCED 0x10
+#define DST_DIVERTED 0x20
unsigned long expires;
unsigned short header_len; /* more space at head required */
diff --git a/include/net/route.h b/include/net/route.h
index 749e4df..efaa6b2 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -125,6 +125,8 @@ extern int ip_rt_ioctl(unsigned int cmd, void __user *arg);
extern void ip_rt_get_source(u8 *src, struct rtable *rt);
extern int ip_rt_dump(struct sk_buff *skb, struct netlink_callback *cb);
+extern int ip_divert_local(struct sk_buff *skb, const struct in_device *in, struct sock *sk);
+
struct in_ifaddr;
extern void fib_add_ifaddr(struct in_ifaddr *);
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 37e0d4d..c526fb2 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -100,6 +100,7 @@
#include <net/ip_fib.h>
#include <net/arp.h>
#include <net/tcp.h>
+#include <linux/dccp.h>
#include <net/icmp.h>
#include <net/xfrm.h>
#include <net/ip_mp_alg.h>
@@ -941,9 +942,11 @@ restart:
while ((rth = *rthp) != NULL) {
#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
if (!(rth->u.dst.flags & DST_BALANCED) &&
+ !((rt->u.dst.flags ^ rth->u.dst.flags) & DST_DIVERTED) &&
compare_keys(&rth->fl, &rt->fl)) {
#else
- if (compare_keys(&rth->fl, &rt->fl)) {
+ if (!((rt->u.dst.flags ^ rth->u.dst.flags) & DST_DIVERTED) &&
+ compare_keys(&rth->fl, &rt->fl)) {
#endif
/* Put it first */
*rthp = rth->u.dst.rt_next;
@@ -1165,6 +1168,7 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw,
if (rth->fl.fl4_dst != daddr ||
rth->fl.fl4_src != skeys[i] ||
rth->fl.oif != ikeys[k] ||
+ (rth->u.dst.flags & DST_DIVERTED) ||
rth->fl.iif != 0) {
rthp = &rth->u.dst.rt_next;
continue;
@@ -1525,6 +1529,111 @@ static int ip_rt_bug(struct sk_buff *skb)
return 0;
}
+static void ip_divert_free_sock(struct sk_buff *skb)
+{
+ struct sock *sk = skb->sk;
+
+ skb->sk = NULL;
+ skb->destructor = NULL;
+
+ if (sk) {
+ /* TIME_WAIT inet sockets have to be handled differently */
+ if (((sk->sk_protocol == IPPROTO_TCP) && (sk->sk_state == TCP_TIME_WAIT)) ||
+ ((sk->sk_protocol == IPPROTO_DCCP) && (sk->sk_state == DCCP_TIME_WAIT)))
+ inet_twsk_put(inet_twsk(sk));
+ else
+ sock_put(sk);
+ }
+}
+
+int ip_divert_local(struct sk_buff *skb, const struct in_device *in, struct sock *sk)
+{
+ struct iphdr *iph = skb->nh.iph;
+ struct rtable *rth, *rtres;
+ unsigned hash;
+ const int iif = in->dev->ifindex;
+ u_int8_t tos;
+ int err;
+
+ /* look up hash first */
+ tos = iph->tos & IPTOS_RT_MASK;
+ hash = rt_hash_code(iph->daddr, iph->saddr ^ (iif << 5));
+
+ rcu_read_lock();
+ for (rth = rcu_dereference(rt_hash_table[hash].chain); rth;
+ rth = rcu_dereference(rth->u.dst.rt_next)) {
+ if (rth->fl.fl4_dst == iph->daddr &&
+ rth->fl.fl4_src == iph->saddr &&
+ rth->fl.iif == iif &&
+ rth->fl.oif == 0 &&
+ (rth->u.dst.flags & DST_DIVERTED)) {
+ rth->u.dst.lastuse = jiffies;
+ dst_hold(&rth->u.dst);
+ rth->u.dst.__use++;
+ RT_CACHE_STAT_INC(in_hit);
+ rcu_read_unlock();
+
+ dst_release(skb->dst);
+ skb->dst = (struct dst_entry*)rth;
+
+ if (sk) {
+ sock_hold(sk);
+ skb->sk = sk;
+ skb->destructor = ip_divert_free_sock;
+ }
+
+ return 0;
+ }
+ RT_CACHE_STAT_INC(in_hlist_search);
+ }
+ rcu_read_unlock();
+
+ /* not found in cache, try to allocate a new dst entry */
+ rth = dst_alloc(&ipv4_dst_ops);
+ if (!rth)
+ return -ENOMEM;
+
+ rth->u.dst.output= ip_rt_bug;
+
+ atomic_set(&rth->u.dst.__refcnt, 1);
+ rth->u.dst.flags = DST_HOST | DST_DIVERTED;
+
+ if (in->cnf.no_policy)
+ rth->u.dst.flags |= DST_NOPOLICY;
+
+ rth->fl.fl4_dst = iph->daddr;
+ rth->rt_dst = iph->daddr;
+ rth->fl.fl4_tos = iph->tos;
+ rth->fl.mark = skb->mark;
+ rth->fl.fl4_src = iph->saddr;
+ rth->rt_src = iph->saddr;
+ rth->rt_iif =
+ rth->fl.iif = skb->dev->ifindex;
+ rth->u.dst.dev = &loopback_dev;
+ dev_hold(rth->u.dst.dev);
+ rth->idev = in_dev_get(rth->u.dst.dev);
+ rth->rt_gateway = iph->daddr;
+ rth->rt_spec_dst= iph->daddr;
+ rth->u.dst.input= ip_local_deliver;
+ rth->rt_flags = RTCF_LOCAL;
+ rth->rt_type = RTN_LOCAL;
+
+ err = rt_intern_hash(hash, rth, &rtres);
+ if (err)
+ return err;
+
+ dst_release(skb->dst);
+ skb->dst = (struct dst_entry *) rth;
+
+ if (sk) {
+ sock_hold(sk);
+ skb->sk = sk;
+ skb->destructor = ip_divert_free_sock;
+ }
+
+ return 0;
+}
+
/*
We do not cache source address of outgoing interface,
because it is used only by IP RR, TS and SRR options,
@@ -2103,6 +2212,7 @@ int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr,
rth->fl.fl4_src == saddr &&
rth->fl.iif == iif &&
rth->fl.oif == 0 &&
+ !(rth->u.dst.flags & DST_DIVERTED) &&
rth->fl.mark == skb->mark &&
rth->fl.fl4_tos == tos) {
rth->u.dst.lastuse = jiffies;
@@ -3199,3 +3309,4 @@ int __init ip_rt_init(void)
EXPORT_SYMBOL(__ip_select_ident);
EXPORT_SYMBOL(ip_route_input);
EXPORT_SYMBOL(ip_route_output_key);
+EXPORT_SYMBOL_GPL(ip_divert_local);
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH/RFC 02/13] Port redirection support for TCP
2007-03-05 15:44 [PATCH/RFC 00/13] Transparent proxying patches, take two KOVACS Krisztian
2007-03-05 15:45 ` [PATCH/RFC 01/13] Implement local diversion of IPv4 skbs KOVACS Krisztian
@ 2007-03-05 15:45 ` KOVACS Krisztian
2007-03-05 15:45 ` [PATCH/RFC 03/13] Don't do the TCP socket lookup if we already have one attached KOVACS Krisztian
` (10 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: KOVACS Krisztian @ 2007-03-05 15:45 UTC (permalink / raw)
To: netdev
Current TCP code relies on the local port of the listening socket
being the same as the destination address of the incoming
connection. Port redirection used by many transparent proxying
techniques obviously breaks this, so we have to store the original
destination port address.
This patch extends struct inet_request_sock and stores the incoming
destination port value there. It also modifies the handshake code to
use that value as the source port when sending reply packets.
Signed-off-by: KOVACS Krisztian <hidden@balabit.hu>
---
include/net/inet_sock.h | 1 +
include/net/tcp.h | 1 +
net/ipv4/inet_connection_sock.c | 2 ++
net/ipv4/syncookies.c | 1 +
net/ipv4/tcp_output.c | 2 +-
5 files changed, 6 insertions(+), 1 deletions(-)
diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h
index ce6da97..0bd167b 100644
--- a/include/net/inet_sock.h
+++ b/include/net/inet_sock.h
@@ -64,6 +64,7 @@ struct inet_request_sock {
#endif
__be32 loc_addr;
__be32 rmt_addr;
+ __be16 loc_port;
__be16 rmt_port;
u16 snd_wscale : 4,
rcv_wscale : 4,
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 5c472f2..e1cb3d0 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -982,6 +982,7 @@ static inline void tcp_openreq_init(struct request_sock *req,
ireq->acked = 0;
ireq->ecn_ok = 0;
ireq->rmt_port = skb->h.th->source;
+ ireq->loc_port = skb->h.th->dest;
}
extern void tcp_enter_memory_pressure(void);
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
index 43fb160..83ad972 100644
--- a/net/ipv4/inet_connection_sock.c
+++ b/net/ipv4/inet_connection_sock.c
@@ -502,6 +502,8 @@ struct sock *inet_csk_clone(struct sock *sk, const struct request_sock *req,
newicsk->icsk_bind_hash = NULL;
inet_sk(newsk)->dport = inet_rsk(req)->rmt_port;
+ inet_sk(newsk)->num = ntohs(inet_rsk(req)->loc_port);
+ inet_sk(newsk)->sport = inet_rsk(req)->loc_port;
newsk->sk_write_space = sk_stream_write_space;
newicsk->icsk_retransmits = 0;
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
index 33016cc..431c81d 100644
--- a/net/ipv4/syncookies.c
+++ b/net/ipv4/syncookies.c
@@ -223,6 +223,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
treq->rcv_isn = ntohl(skb->h.th->seq) - 1;
treq->snt_isn = cookie;
req->mss = mss;
+ ireq->loc_port = skb->h.th->dest;
ireq->rmt_port = skb->h.th->source;
ireq->loc_addr = skb->nh.iph->daddr;
ireq->rmt_addr = skb->nh.iph->saddr;
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index dc15113..a3ea7a1 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -2135,7 +2135,7 @@ struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst,
th->syn = 1;
th->ack = 1;
TCP_ECN_make_synack(req, th);
- th->source = inet_sk(sk)->sport;
+ th->source = ireq->loc_port;
th->dest = ireq->rmt_port;
TCP_SKB_CB(skb)->seq = tcp_rsk(req)->snt_isn;
TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(skb)->seq + 1;
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH/RFC 03/13] Don't do the TCP socket lookup if we already have one attached
2007-03-05 15:44 [PATCH/RFC 00/13] Transparent proxying patches, take two KOVACS Krisztian
2007-03-05 15:45 ` [PATCH/RFC 01/13] Implement local diversion of IPv4 skbs KOVACS Krisztian
2007-03-05 15:45 ` [PATCH/RFC 02/13] Port redirection support for TCP KOVACS Krisztian
@ 2007-03-05 15:45 ` KOVACS Krisztian
2007-03-05 15:45 ` [PATCH/RFC 04/13] Don't do the UDP " KOVACS Krisztian
` (9 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: KOVACS Krisztian @ 2007-03-05 15:45 UTC (permalink / raw)
To: netdev
TCP input code path looks up the TCP socket hash tables to find a
socket matching the incoming packet. However, as iptable_tproxy does
socket lookups early the skb may already have the appropriate
reference attached, in that case we steal that reference instead of
doing the lookup.
Signed-off-by: KOVACS Krisztian <hidden@balabit.hu>
---
net/ipv4/tcp_ipv4.c | 13 ++++++++++---
1 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 0ba74bb..536db7b 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1647,9 +1647,16 @@ int tcp_v4_rcv(struct sk_buff *skb)
TCP_SKB_CB(skb)->flags = skb->nh.iph->tos;
TCP_SKB_CB(skb)->sacked = 0;
- sk = __inet_lookup(&tcp_hashinfo, skb->nh.iph->saddr, th->source,
- skb->nh.iph->daddr, th->dest,
- inet_iif(skb));
+ if (unlikely(skb->sk)) {
+ /* steal reference */
+ sk = skb->sk;
+ skb->destructor = NULL;
+ skb->sk = NULL;
+ } else {
+ sk = __inet_lookup(&tcp_hashinfo, skb->nh.iph->saddr, th->source,
+ skb->nh.iph->daddr, th->dest,
+ inet_iif(skb));
+ }
if (!sk)
goto no_tcp_socket;
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH/RFC 04/13] Don't do the UDP socket lookup if we already have one attached
2007-03-05 15:44 [PATCH/RFC 00/13] Transparent proxying patches, take two KOVACS Krisztian
` (2 preceding siblings ...)
2007-03-05 15:45 ` [PATCH/RFC 03/13] Don't do the TCP socket lookup if we already have one attached KOVACS Krisztian
@ 2007-03-05 15:45 ` KOVACS Krisztian
2007-03-05 15:45 ` [PATCH/RFC 05/13] Loosen source address check on IPv4 output KOVACS Krisztian
` (8 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: KOVACS Krisztian @ 2007-03-05 15:45 UTC (permalink / raw)
To: netdev
UDP input code path looks up the UDP socket hash tables to find a
socket matching the incoming packet. However, as iptable_tproxy does
socket lookups early the skb may already have the appropriate
reference attached, in that case we steal that reference instead of
doing the lookup.
Signed-off-by: KOVACS Krisztian <hidden@balabit.hu>
---
net/ipv4/udp.c | 11 +++++++++--
1 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index ce6c460..1d15edc 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -1226,8 +1226,15 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[],
if(rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST))
return __udp4_lib_mcast_deliver(skb, uh, saddr, daddr, udptable);
- sk = __udp4_lib_lookup(saddr, uh->source, daddr, uh->dest,
- skb->dev->ifindex, udptable );
+ if (skb->sk) {
+ /* steal reference */
+ sk = skb->sk;
+ skb->destructor = NULL;
+ skb->sk = NULL;
+ } else {
+ sk = __udp4_lib_lookup(saddr, uh->source, daddr, uh->dest,
+ skb->dev->ifindex, udptable );
+ }
if (sk != NULL) {
int ret = udp_queue_rcv_skb(sk, skb);
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH/RFC 05/13] Loosen source address check on IPv4 output
2007-03-05 15:44 [PATCH/RFC 00/13] Transparent proxying patches, take two KOVACS Krisztian
` (3 preceding siblings ...)
2007-03-05 15:45 ` [PATCH/RFC 04/13] Don't do the UDP " KOVACS Krisztian
@ 2007-03-05 15:45 ` KOVACS Krisztian
2007-03-05 15:45 ` [PATCH/RFC 06/13] Implement IP_TRANSPARENT socket option KOVACS Krisztian
` (7 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: KOVACS Krisztian @ 2007-03-05 15:45 UTC (permalink / raw)
To: netdev
ip_route_output() contains a check to make sure that no flows with
non-local source IP addresses are routed. This obviously makes using
such addresses impossible.
This patch introduces a flowi flag which makes omitting this check
possible. The new flag provides a way of handling transparent and
non-transparent connections differently.
Signed-off-by: KOVACS Krisztian <hidden@balabit.hu>
---
include/net/flow.h | 1 +
net/ipv4/route.c | 8 ++++++--
2 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/include/net/flow.h b/include/net/flow.h
index ce4b10d..9eb91f2 100644
--- a/include/net/flow.h
+++ b/include/net/flow.h
@@ -49,6 +49,7 @@ struct flowi {
__u8 proto;
__u8 flags;
#define FLOWI_FLAG_MULTIPATHOLDROUTE 0x01
+#define FLOWI_FLAG_TRANSPARENT 0x02
union {
struct {
__be16 sport;
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index c526fb2..8091a96 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -572,7 +572,8 @@ static inline int compare_keys(struct flowi *fl1, struct flowi *fl2)
(*(u16 *)&fl1->nl_u.ip4_u.tos ^
*(u16 *)&fl2->nl_u.ip4_u.tos) |
(fl1->oif ^ fl2->oif) |
- (fl1->iif ^ fl2->iif)) == 0;
+ (fl1->iif ^ fl2->iif) |
+ ((fl1->flags ^ fl2->flags) & FLOWI_FLAG_TRANSPARENT)) == 0;
}
#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
@@ -2338,6 +2339,7 @@ static inline int __mkroute_output(struct rtable **result,
rth->fl.fl4_src = oldflp->fl4_src;
rth->fl.oif = oldflp->oif;
rth->fl.mark = oldflp->mark;
+ rth->fl.flags = oldflp->flags;
rth->rt_dst = fl->fl4_dst;
rth->rt_src = fl->fl4_src;
rth->rt_iif = oldflp->oif ? : dev_out->ifindex;
@@ -2482,6 +2484,7 @@ static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp)
RT_SCOPE_LINK :
RT_SCOPE_UNIVERSE),
} },
+ .flags = oldflp->flags,
.mark = oldflp->mark,
.iif = loopback_dev.ifindex,
.oif = oldflp->oif };
@@ -2506,7 +2509,7 @@ static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp)
/* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */
dev_out = ip_dev_find(oldflp->fl4_src);
- if (dev_out == NULL)
+ if (dev_out == NULL && !(oldflp->flags & FLOWI_FLAG_TRANSPARENT))
goto out;
/* I removed check for oif == dev_out->oif here.
@@ -2678,6 +2681,7 @@ int __ip_route_output_key(struct rtable **rp, const struct flowi *flp)
rth->fl.iif == 0 &&
rth->fl.oif == flp->oif &&
rth->fl.mark == flp->mark &&
+ !((rth->fl.flags ^ flp->flags) & FLOWI_FLAG_TRANSPARENT) &&
!((rth->fl.fl4_tos ^ flp->fl4_tos) &
(IPTOS_RT_MASK | RTO_ONLINK))) {
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH/RFC 06/13] Implement IP_TRANSPARENT socket option
2007-03-05 15:44 [PATCH/RFC 00/13] Transparent proxying patches, take two KOVACS Krisztian
` (4 preceding siblings ...)
2007-03-05 15:45 ` [PATCH/RFC 05/13] Loosen source address check on IPv4 output KOVACS Krisztian
@ 2007-03-05 15:45 ` KOVACS Krisztian
2007-03-05 15:46 ` [PATCH/RFC 07/13] Conditionally enable transparent flow flag when connecting KOVACS Krisztian
` (6 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: KOVACS Krisztian @ 2007-03-05 15:45 UTC (permalink / raw)
To: netdev
This patch introduces the IP_TRANSPARENT socket option: enabling that will make
the IPv4 routing omit the non-local source address check on output. Setting
IP_TRANSPARENT requires NET_ADMIN capability.
Signed-off-by: KOVACS Krisztian <hidden@balabit.hu>
---
include/linux/in.h | 1 +
include/net/inet_sock.h | 3 ++-
include/net/inet_timewait_sock.h | 3 ++-
include/net/route.h | 1 +
net/ipv4/inet_timewait_sock.c | 1 +
net/ipv4/ip_sockglue.c | 12 +++++++++++-
6 files changed, 18 insertions(+), 3 deletions(-)
diff --git a/include/linux/in.h b/include/linux/in.h
index 1912e7c..66be615 100644
--- a/include/linux/in.h
+++ b/include/linux/in.h
@@ -75,6 +75,7 @@ struct in_addr {
#define IP_IPSEC_POLICY 16
#define IP_XFRM_POLICY 17
#define IP_PASSSEC 18
+#define IP_TRANSPARENT 19
/* BSD compatibility */
#define IP_RECVRETOPTS IP_RETOPTS
diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h
index 0bd167b..14b597d 100644
--- a/include/net/inet_sock.h
+++ b/include/net/inet_sock.h
@@ -128,7 +128,8 @@ struct inet_sock {
is_icsk:1,
freebind:1,
hdrincl:1,
- mc_loop:1;
+ mc_loop:1,
+ transparent:1;
int mc_index;
__be32 mc_addr;
struct ip_mc_socklist *mc_list;
diff --git a/include/net/inet_timewait_sock.h b/include/net/inet_timewait_sock.h
index f7be1ac..e30dd61 100644
--- a/include/net/inet_timewait_sock.h
+++ b/include/net/inet_timewait_sock.h
@@ -126,7 +126,8 @@ struct inet_timewait_sock {
__be16 tw_dport;
__u16 tw_num;
/* And these are ours. */
- __u8 tw_ipv6only:1;
+ __u8 tw_ipv6only:1,
+ tw_transparent:1;
/* 15 bits hole, try to pack */
__u16 tw_ipv6_offset;
int tw_timeout;
diff --git a/include/net/route.h b/include/net/route.h
index efaa6b2..13da592 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -27,6 +27,7 @@
#include <net/dst.h>
#include <net/inetpeer.h>
#include <net/flow.h>
+#include <net/inet_sock.h>
#include <linux/in_route.h>
#include <linux/rtnetlink.h>
#include <linux/route.h>
diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c
index a73cf93..f57f81a 100644
--- a/net/ipv4/inet_timewait_sock.c
+++ b/net/ipv4/inet_timewait_sock.c
@@ -108,6 +108,7 @@ struct inet_timewait_sock *inet_twsk_alloc(const struct sock *sk, const int stat
tw->tw_reuse = sk->sk_reuse;
tw->tw_hash = sk->sk_hash;
tw->tw_ipv6only = 0;
+ tw->tw_transparent = inet->transparent;
tw->tw_prot = sk->sk_prot_creator;
atomic_set(&tw->tw_refcnt, 1);
inet_twsk_dead_node_init(tw);
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index 23048d9..02e8d9f 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -414,7 +414,7 @@ static int do_ip_setsockopt(struct sock *sk, int level,
(1<<IP_TTL) | (1<<IP_HDRINCL) |
(1<<IP_MTU_DISCOVER) | (1<<IP_RECVERR) |
(1<<IP_ROUTER_ALERT) | (1<<IP_FREEBIND) |
- (1<<IP_PASSSEC))) ||
+ (1<<IP_PASSSEC) | (1<<IP_TRANSPARENT))) ||
optname == IP_MULTICAST_TTL ||
optname == IP_MULTICAST_LOOP) {
if (optlen >= sizeof(int)) {
@@ -875,6 +875,16 @@ mc_msf_out:
err = xfrm_user_policy(sk, optname, optval, optlen);
break;
+ case IP_TRANSPARENT:
+ if (!capable(CAP_NET_ADMIN)) {
+ err = -EPERM;
+ break;
+ }
+ if (optlen < 1)
+ goto e_inval;
+ inet->transparent = !!val;
+ break;
+
default:
err = -ENOPROTOOPT;
break;
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH/RFC 07/13] Conditionally enable transparent flow flag when connecting
2007-03-05 15:44 [PATCH/RFC 00/13] Transparent proxying patches, take two KOVACS Krisztian
` (5 preceding siblings ...)
2007-03-05 15:45 ` [PATCH/RFC 06/13] Implement IP_TRANSPARENT socket option KOVACS Krisztian
@ 2007-03-05 15:46 ` KOVACS Krisztian
2007-03-05 15:46 ` [PATCH/RFC 08/13] Handle TCP SYN+ACK/ACK/RST transparency KOVACS Krisztian
` (5 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: KOVACS Krisztian @ 2007-03-05 15:46 UTC (permalink / raw)
To: netdev
Set FLOWI_FLAG_TRANSPARENT in flowi->flags if the socket has the
transparent socket option set. This way we selectively enable certain
connections with non-local source addresses to be routed.
Signed-off-by: KOVACS Krisztian <hidden@balabit.hu>
---
include/net/route.h | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/include/net/route.h b/include/net/route.h
index 13da592..4dff368 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -161,6 +161,10 @@ static inline int ip_route_connect(struct rtable **rp, __be32 dst,
.dport = dport } } };
int err;
+
+ if (inet_sk(sk)->transparent)
+ fl.flags |= FLOWI_FLAG_TRANSPARENT;
+
if (!dst || !src) {
err = __ip_route_output_key(rp, &fl);
if (err)
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH/RFC 08/13] Handle TCP SYN+ACK/ACK/RST transparency
2007-03-05 15:44 [PATCH/RFC 00/13] Transparent proxying patches, take two KOVACS Krisztian
` (6 preceding siblings ...)
2007-03-05 15:46 ` [PATCH/RFC 07/13] Conditionally enable transparent flow flag when connecting KOVACS Krisztian
@ 2007-03-05 15:46 ` KOVACS Krisztian
2007-03-05 15:46 ` [PATCH/RFC 09/13] Create a tproxy flag in struct sk_buff KOVACS Krisztian
` (4 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: KOVACS Krisztian @ 2007-03-05 15:46 UTC (permalink / raw)
To: netdev
The TCP stack sends out SYN+ACK/ACK/RST reply packets in response to
incoming packets. The non-local source address check on output bites
us again, as replies for transparently redirected traffic won't have a
chance to leave the node.
This patch selectively sets the FLOWI_FLAG_TRANSPARENT flag when doing
the route lookup for those replies. Transparent replies are enabled if
the listening socket has the transparent socket flag set.
Signed-off-by: KOVACS Krisztian <hidden@balabit.hu>
---
include/net/ip.h | 3 +++
include/net/request_sock.h | 3 ++-
net/ipv4/inet_connection_sock.c | 2 ++
net/ipv4/ip_output.c | 6 +++++-
net/ipv4/syncookies.c | 2 ++
net/ipv4/tcp_ipv4.c | 16 ++++++++++------
net/ipv4/tcp_minisocks.c | 3 ++-
7 files changed, 26 insertions(+), 9 deletions(-)
diff --git a/include/net/ip.h b/include/net/ip.h
index e79c3e3..8b71991 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -133,8 +133,11 @@ static inline void ip_tr_mc_map(__be32 addr, char *buf)
buf[5]=0x00;
}
+#define IP_REPLY_ARG_NOSRCCHECK 1
+
struct ip_reply_arg {
struct kvec iov[1];
+ int flags;
__wsum csum;
int csumoffset; /* u16 offset of csum in iov[0].iov_base */
/* -1 if not needed */
diff --git a/include/net/request_sock.h b/include/net/request_sock.h
index 7aed02c..b9c8974 100644
--- a/include/net/request_sock.h
+++ b/include/net/request_sock.h
@@ -34,7 +34,8 @@ struct request_sock_ops {
struct request_sock *req,
struct dst_entry *dst);
void (*send_ack)(struct sk_buff *skb,
- struct request_sock *req);
+ struct request_sock *req,
+ int reply_flags);
void (*send_reset)(struct sock *sk,
struct sk_buff *skb);
void (*destructor)(struct request_sock *req);
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
index 83ad972..90459a1 100644
--- a/net/ipv4/inet_connection_sock.c
+++ b/net/ipv4/inet_connection_sock.c
@@ -323,6 +323,8 @@ struct dst_entry* inet_csk_route_req(struct sock *sk,
.saddr = ireq->loc_addr,
.tos = RT_CONN_FLAGS(sk) } },
.proto = sk->sk_protocol,
+ .flags = inet_sk(sk)->transparent ?
+ FLOWI_FLAG_TRANSPARENT : 0,
.uli_u = { .ports =
{ .sport = inet_sk(sk)->sport,
.dport = ireq->rmt_port } } };
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index d096332..7af25d4 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -312,6 +312,8 @@ int ip_queue_xmit(struct sk_buff *skb, int ipfragok)
.saddr = inet->saddr,
.tos = RT_CONN_FLAGS(sk) } },
.proto = sk->sk_protocol,
+ .flags = inet->transparent ?
+ FLOWI_FLAG_TRANSPARENT : 0,
.uli_u = { .ports =
{ .sport = inet->sport,
.dport = inet->dport } } };
@@ -1357,7 +1359,9 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar
.uli_u = { .ports =
{ .sport = skb->h.th->dest,
.dport = skb->h.th->source } },
- .proto = sk->sk_protocol };
+ .proto = sk->sk_protocol,
+ .flags = (arg->flags & IP_REPLY_ARG_NOSRCCHECK) ?
+ FLOWI_FLAG_TRANSPARENT : 0 };
security_skb_classify_flow(skb, &fl);
if (ip_route_output_key(&rt, &fl))
return;
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
index 431c81d..08d8920 100644
--- a/net/ipv4/syncookies.c
+++ b/net/ipv4/syncookies.c
@@ -261,6 +261,8 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
.saddr = ireq->loc_addr,
.tos = RT_CONN_FLAGS(sk) } },
.proto = IPPROTO_TCP,
+ .flags = inet_sk(sk)->transparent ?
+ FLOWI_FLAG_TRANSPARENT : 0,
.uli_u = { .ports =
{ .sport = skb->h.th->dest,
.dport = skb->h.th->source } } };
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 536db7b..9374c5b 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -607,6 +607,7 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb)
skb->nh.iph->saddr, /* XXX */
sizeof(struct tcphdr), IPPROTO_TCP, 0);
arg.csumoffset = offsetof(struct tcphdr, check) / 2;
+ arg.flags = (sk && inet_sk(sk)->transparent) ? IP_REPLY_ARG_NOSRCCHECK : 0;
ip_send_reply(tcp_socket->sk, skb, &arg, arg.iov[0].iov_len);
@@ -620,7 +621,7 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb)
static void tcp_v4_send_ack(struct tcp_timewait_sock *twsk,
struct sk_buff *skb, u32 seq, u32 ack,
- u32 win, u32 ts)
+ u32 win, u32 ts, int reply_flags)
{
struct tcphdr *th = skb->h.th;
struct {
@@ -700,30 +701,32 @@ static void tcp_v4_send_ack(struct tcp_timewait_sock *twsk,
skb->nh.iph->saddr, /* XXX */
arg.iov[0].iov_len, IPPROTO_TCP, 0);
arg.csumoffset = offsetof(struct tcphdr, check) / 2;
+ arg.flags = reply_flags;
ip_send_reply(tcp_socket->sk, skb, &arg, arg.iov[0].iov_len);
TCP_INC_STATS_BH(TCP_MIB_OUTSEGS);
}
-static void tcp_v4_timewait_ack(struct sock *sk, struct sk_buff *skb)
+static void tcp_v4_timewait_ack(struct sock *sk, struct sk_buff *skb, int reply_flags)
{
struct inet_timewait_sock *tw = inet_twsk(sk);
struct tcp_timewait_sock *tcptw = tcp_twsk(sk);
tcp_v4_send_ack(tcptw, skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt,
tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale,
- tcptw->tw_ts_recent);
+ tcptw->tw_ts_recent, reply_flags);
inet_twsk_put(tw);
}
static void tcp_v4_reqsk_send_ack(struct sk_buff *skb,
- struct request_sock *req)
+ struct request_sock *req,
+ int reply_flags)
{
tcp_v4_send_ack(NULL, skb, tcp_rsk(req)->snt_isn + 1,
tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd,
- req->ts_recent);
+ req->ts_recent, reply_flags);
}
/*
@@ -1743,7 +1746,8 @@ do_time_wait:
/* Fall through to ACK */
}
case TCP_TW_ACK:
- tcp_v4_timewait_ack(sk, skb);
+ tcp_v4_timewait_ack(sk, skb, inet_twsk(sk)->tw_transparent ?
+ IP_REPLY_ARG_NOSRCCHECK : 0);
break;
case TCP_TW_RST:
goto no_tcp_socket;
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index 6b5c64f..c63c25b 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -605,7 +605,8 @@ struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb,
tcp_rsk(req)->rcv_isn + 1, tcp_rsk(req)->rcv_isn + 1 + req->rcv_wnd)) {
/* Out of window: send ACK and drop. */
if (!(flg & TCP_FLAG_RST))
- req->rsk_ops->send_ack(skb, req);
+ req->rsk_ops->send_ack(skb, req, inet_sk(sk)->transparent ?
+ IP_REPLY_ARG_NOSRCCHECK : 0);
if (paws_reject)
NET_INC_STATS_BH(LINUX_MIB_PAWSESTABREJECTED);
return NULL;
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH/RFC 09/13] Create a tproxy flag in struct sk_buff
2007-03-05 15:44 [PATCH/RFC 00/13] Transparent proxying patches, take two KOVACS Krisztian
` (7 preceding siblings ...)
2007-03-05 15:46 ` [PATCH/RFC 08/13] Handle TCP SYN+ACK/ACK/RST transparency KOVACS Krisztian
@ 2007-03-05 15:46 ` KOVACS Krisztian
2007-03-05 15:46 ` [PATCH/RFC 10/13] Export UDP socket lookup function KOVACS Krisztian
` (3 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: KOVACS Krisztian @ 2007-03-05 15:46 UTC (permalink / raw)
To: netdev
We would like to be able to match on whether or not a given packet has
been diverted by tproxy. To make this possible we need a flag in
sk_buff.
Signed-off-by: KOVACS Krisztian <hidden@balabit.hu>
---
include/linux/skbuff.h | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 4ff3940..6d7f5c7 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -284,7 +284,8 @@ struct sk_buff {
nfctinfo:3;
__u8 pkt_type:3,
fclone:2,
- ipvs_property:1;
+ ipvs_property:1,
+ ip_tproxy:1;
__be16 protocol;
void (*destructor)(struct sk_buff *skb);
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH/RFC 10/13] Export UDP socket lookup function
2007-03-05 15:44 [PATCH/RFC 00/13] Transparent proxying patches, take two KOVACS Krisztian
` (8 preceding siblings ...)
2007-03-05 15:46 ` [PATCH/RFC 09/13] Create a tproxy flag in struct sk_buff KOVACS Krisztian
@ 2007-03-05 15:46 ` KOVACS Krisztian
2007-03-05 15:46 ` [PATCH/RFC 11/13] iptables tproxy table KOVACS Krisztian
` (2 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: KOVACS Krisztian @ 2007-03-05 15:46 UTC (permalink / raw)
To: netdev
The iptables tproxy code has to be able to do UDP socket hash lookups,
so we have to provide an exported lookup function for this purpose.
Signed-off-by: KOVACS Krisztian <hidden@balabit.hu>
---
include/net/udp.h | 4 ++++
net/ipv4/udp.c | 8 ++++++++
2 files changed, 12 insertions(+), 0 deletions(-)
diff --git a/include/net/udp.h b/include/net/udp.h
index 1b921fa..ea5aa31 100644
--- a/include/net/udp.h
+++ b/include/net/udp.h
@@ -141,6 +141,10 @@ extern int udp_lib_setsockopt(struct sock *sk, int level, int optname,
char __user *optval, int optlen,
int (*push_pending_frames)(struct sock *));
+extern struct sock *udp4_lib_lookup(__be32 saddr, __be16 sport,
+ __be32 daddr, __be16 dport,
+ int dif);
+
DECLARE_SNMP_STAT(struct udp_mib, udp_statistics);
/*
* SNMP statistics for UDP and UDP-Lite
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 1d15edc..52695a6 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -285,6 +285,14 @@ static struct sock *__udp4_lib_lookup(__be32 saddr, __be16 sport,
return result;
}
+struct sock *udp4_lib_lookup(__be32 saddr, __be16 sport,
+ __be32 daddr, __be16 dport,
+ int dif)
+{
+ return __udp4_lib_lookup(saddr, sport, daddr, dport, dif, udp_hash);
+}
+EXPORT_SYMBOL_GPL(udp4_lib_lookup);
+
static inline struct sock *udp_v4_mcast_next(struct sock *sk,
__be16 loc_port, __be32 loc_addr,
__be16 rmt_port, __be32 rmt_addr,
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH/RFC 11/13] iptables tproxy table
2007-03-05 15:44 [PATCH/RFC 00/13] Transparent proxying patches, take two KOVACS Krisztian
` (9 preceding siblings ...)
2007-03-05 15:46 ` [PATCH/RFC 10/13] Export UDP socket lookup function KOVACS Krisztian
@ 2007-03-05 15:46 ` KOVACS Krisztian
2007-03-05 15:46 ` [PATCH/RFC 12/13] iptables TPROXY target KOVACS Krisztian
2007-03-05 15:47 ` [PATCH/RFC 13/13] iptables tproxy match KOVACS Krisztian
12 siblings, 0 replies; 14+ messages in thread
From: KOVACS Krisztian @ 2007-03-05 15:46 UTC (permalink / raw)
To: netdev
The iptables tproxy table registers a new hook on PRE_ROUTING and for
each incoming TCP/UDP packet performs as follows:
1. Does IPv4 fragment reassembly. We need this to be able to do TCP/UDP
header processing.
2. Does a TCP/UDP socket hash lookup to decide whether or not the packet
is sent to a non-local bound socket. If a matching socket is found
and the socket has the IP_TRANSPARENT socket option enabled the skb is
diverted locally and the socket reference is stored in the skb.
3. If no matching socket was found, the PREROUTING chain of the
iptables tproxy table is consulted. Matching rules with the TPROXY
target can do transparent redirection here. (In this case it is not
necessary to have the IP_TRANSPARENT socket option enabled for the
target socket, redirection takes place even for "regular"
sockets. This way no modification of the application is necessary.)
Signed-off-by: KOVACS Krisztian <hidden@balabit.hu>
---
include/linux/netfilter_ipv4.h | 1
include/linux/netfilter_ipv4/ip_tproxy.h | 20 ++
include/net/ip.h | 3
net/ipv4/netfilter/Kconfig | 10 +
net/ipv4/netfilter/Makefile | 1
net/ipv4/netfilter/iptable_tproxy.c | 267 ++++++++++++++++++++++++++++++
6 files changed, 301 insertions(+), 1 deletions(-)
diff --git a/include/linux/netfilter_ipv4.h b/include/linux/netfilter_ipv4.h
index ceae87a..cc4d83b 100644
--- a/include/linux/netfilter_ipv4.h
+++ b/include/linux/netfilter_ipv4.h
@@ -58,6 +58,7 @@ enum nf_ip_hook_priorities {
NF_IP_PRI_SELINUX_FIRST = -225,
NF_IP_PRI_CONNTRACK = -200,
NF_IP_PRI_MANGLE = -150,
+ NF_IP_PRI_TPROXY = -125,
NF_IP_PRI_NAT_DST = -100,
NF_IP_PRI_FILTER = 0,
NF_IP_PRI_NAT_SRC = 100,
diff --git a/include/linux/netfilter_ipv4/ip_tproxy.h b/include/linux/netfilter_ipv4/ip_tproxy.h
new file mode 100644
index 0000000..ae890e3
--- /dev/null
+++ b/include/linux/netfilter_ipv4/ip_tproxy.h
@@ -0,0 +1,20 @@
+#ifndef _IP_TPROXY_H
+#define _IP_TPROXY_H
+
+#include <linux/types.h>
+
+/* look up and get a reference to a matching socket */
+extern struct sock *
+ip_tproxy_get_sock(const u8 protocol,
+ const __be32 saddr, const __be32 daddr,
+ const __be16 sport, const __be16 dport,
+ const struct net_device *in);
+
+/* divert skb to a given socket */
+extern int
+ip_tproxy_do_divert(struct sk_buff *skb,
+ const struct sock *sk,
+ const int require_freebind,
+ const struct net_device *in);
+
+#endif
diff --git a/include/net/ip.h b/include/net/ip.h
index 8b71991..a589e6e 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -321,7 +321,8 @@ enum ip_defrag_users
IP_DEFRAG_CONNTRACK_OUT,
IP_DEFRAG_VS_IN,
IP_DEFRAG_VS_OUT,
- IP_DEFRAG_VS_FWD
+ IP_DEFRAG_VS_FWD,
+ IP_DEFRAG_TP_IN,
};
struct sk_buff *ip_defrag(struct sk_buff *skb, u32 user);
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index 601808c..17c3ec8 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -628,6 +628,16 @@ config IP_NF_RAW
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `N'.
+# tproxy table
+config IP_NF_TPROXY
+ tristate "Transparent proxying"
+ depends on IP_NF_IPTABLES
+ help
+ Transparent proxying. For more information see
+ http://www.balabit.com/downloads/tproxy.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
# ARP tables
config IP_NF_ARPTABLES
tristate "ARP tables support"
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile
index 6625ec6..21a29f4 100644
--- a/net/ipv4/netfilter/Makefile
+++ b/net/ipv4/netfilter/Makefile
@@ -81,6 +81,7 @@ obj-$(CONFIG_IP_NF_MANGLE) += iptable_mangle.o
obj-$(CONFIG_IP_NF_NAT) += iptable_nat.o
obj-$(CONFIG_NF_NAT) += iptable_nat.o
obj-$(CONFIG_IP_NF_RAW) += iptable_raw.o
+obj-$(CONFIG_IP_NF_TPROXY) += iptable_tproxy.o
# matches
obj-$(CONFIG_IP_NF_MATCH_IPRANGE) += ipt_iprange.o
diff --git a/net/ipv4/netfilter/iptable_tproxy.c b/net/ipv4/netfilter/iptable_tproxy.c
new file mode 100644
index 0000000..a241f11
--- /dev/null
+++ b/net/ipv4/netfilter/iptable_tproxy.c
@@ -0,0 +1,267 @@
+/*
+ * Transparent proxy support for Linux/iptables
+ *
+ * Copyright (c) 2006-2007 BalaBit IT Ltd.
+ * Author: Balazs Scheidler, 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 <linux/version.h>
+#include <linux/module.h>
+
+#include <linux/net.h>
+#include <linux/if.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/in.h>
+#include <net/tcp.h>
+#include <net/udp.h>
+#include <net/sock.h>
+#include <net/inet_sock.h>
+
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+
+#define TPROXY_VALID_HOOKS (1 << NF_IP_PRE_ROUTING)
+
+#if 1
+#define DEBUGP printk
+#else
+#define DEBUGP(f, args...)
+#endif
+
+static struct
+{
+ struct ipt_replace repl;
+ struct ipt_standard entries[1];
+ struct ipt_error term;
+} initial_table __initdata = {
+ .repl = {
+ .name = "tproxy",
+ .valid_hooks = TPROXY_VALID_HOOKS,
+ .num_entries = 2,
+ .size = sizeof(struct ipt_standard) + sizeof(struct ipt_error),
+ .hook_entry = {
+ [NF_IP_PRE_ROUTING] = 0 },
+ .underflow = {
+ [NF_IP_PRE_ROUTING] = 0 },
+ },
+ .entries = {
+ /* PRE_ROUTING */
+ {
+ .entry = {
+ .target_offset = sizeof(struct ipt_entry),
+ .next_offset = sizeof(struct ipt_standard),
+ },
+ .target = {
+ .target = {
+ .u = {
+ .target_size = IPT_ALIGN(sizeof(struct ipt_standard_target)),
+ },
+ },
+ .verdict = -NF_ACCEPT - 1,
+ },
+ },
+ },
+ /* ERROR */
+ .term = {
+ .entry = {
+ .target_offset = sizeof(struct ipt_entry),
+ .next_offset = sizeof(struct ipt_error),
+ },
+ .target = {
+ .target = {
+ .u = {
+ .user = {
+ .target_size = IPT_ALIGN(sizeof(struct ipt_error_target)),
+ .name = IPT_ERROR_TARGET,
+ },
+ },
+ },
+ .errorname = "ERROR",
+ },
+ }
+};
+
+static struct ipt_table tproxy_table = {
+ .name = "tproxy",
+ .valid_hooks = TPROXY_VALID_HOOKS,
+ .lock = RW_LOCK_UNLOCKED,
+ .me = THIS_MODULE,
+ .af = AF_INET,
+};
+
+struct sock *
+ip_tproxy_get_sock(const u8 protocol,
+ const __be32 saddr, const __be32 daddr,
+ const __be16 sport, const __be16 dport,
+ const struct net_device *in)
+{
+ struct sock *sk = NULL;
+
+ /* look up socket */
+ switch (protocol) {
+ case IPPROTO_TCP:
+ sk = __inet_lookup(&tcp_hashinfo,
+ saddr, sport, daddr, dport,
+ in->ifindex);
+ break;
+ case IPPROTO_UDP:
+ sk = udp4_lib_lookup(saddr, sport, daddr, dport,
+ in->ifindex);
+ break;
+ default:
+ WARN_ON(1);
+ }
+
+ return sk;
+}
+EXPORT_SYMBOL_GPL(ip_tproxy_get_sock);
+
+int
+ip_tproxy_do_divert(struct sk_buff *skb, struct sock *sk,
+ const int require_transparent,
+ const struct net_device *in)
+{
+ const struct inet_sock *inet = inet_sk(sk);
+ struct in_device *indev;
+
+ if (unlikely(inet == NULL))
+ return -EINVAL;
+
+ if (!require_transparent || inet->transparent) {
+ indev = in_dev_get(in);
+ if (indev == NULL)
+ return -ENODEV;
+
+ skb->ip_tproxy = 1;
+
+ ip_divert_local(skb, indev, sk);
+ in_dev_put(indev);
+
+ DEBUGP(KERN_DEBUG "IP_TPROXY: diverted to socket %p\n", sk);
+ } else {
+ DEBUGP(KERN_DEBUG "IP_TPROXY: diversion to non-transparent socket %p failed\n", sk);
+ return -ENOENT;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ip_tproxy_do_divert);
+
+static unsigned int
+ip_tproxy_prerouting(unsigned int hooknum,
+ struct sk_buff **pskb,
+ const struct net_device *in,
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+{
+ int verdict = NF_ACCEPT;
+ int diverted = -1;
+ struct sk_buff *skb = *pskb;
+ struct sock *sk = NULL;
+ const struct iphdr *iph;
+ struct udphdr *hp, _hdr;
+ u8 protocol;
+
+ /* reassemble fragments */
+ if (skb->nh.iph->frag_off & __constant_htons(IP_MF|IP_OFFSET)) {
+ skb = ip_defrag(skb, IP_DEFRAG_TP_IN);
+ if (skb == NULL)
+ return NF_STOLEN;
+
+ ip_send_check(skb->nh.iph);
+ *pskb = skb;
+ }
+
+ protocol = skb->nh.iph->protocol;
+ iph = skb->nh.iph;
+
+ /* TCP and UDP only */
+ if ((protocol != IPPROTO_TCP) && (protocol != IPPROTO_UDP))
+ return NF_ACCEPT;
+
+ if (unlikely(in == NULL))
+ return NF_ACCEPT;
+
+ if (unlikely(skb->ip_tproxy))
+ return NF_ACCEPT;
+
+ hp = skb_header_pointer(skb, iph->ihl * 4, sizeof(_hdr), &_hdr);
+ if (unlikely(hp == NULL)) {
+ DEBUGP(KERN_DEBUG "IP_TPROXY: ip_tproxy_fn(): "
+ "failed to get protocol header\n");
+ return NF_DROP;
+ }
+
+ sk = ip_tproxy_get_sock(protocol,
+ iph->saddr, iph->daddr,
+ hp->source, hp->dest, in);
+ if (sk) {
+ diverted = ip_tproxy_do_divert(skb, sk, 1, in);
+
+ if ((sk->sk_protocol == IPPROTO_TCP) && (sk->sk_state == TCP_TIME_WAIT))
+ inet_twsk_put(inet_twsk(sk));
+ else
+ sock_put(sk);
+ }
+
+ if (diverted < 0) {
+ /* no socket or diversion failed: lookup table */
+ verdict = ipt_do_table(pskb, hooknum, in, out, &tproxy_table);
+ }
+
+ return verdict;
+}
+
+static struct nf_hook_ops ip_tproxy_pre_ops = {
+ .hook = ip_tproxy_prerouting,
+ .owner = THIS_MODULE,
+ .pf = PF_INET,
+ .hooknum = NF_IP_PRE_ROUTING,
+ .priority = NF_IP_PRI_TPROXY
+};
+
+static int __init init(void)
+{
+ int ret;
+
+ ret = ipt_register_table(&tproxy_table, &initial_table.repl);
+ if (ret < 0) {
+ printk("IP_TPROXY: can't register tproxy table.\n");
+ return ret;
+ }
+
+ ret = nf_register_hook(&ip_tproxy_pre_ops);
+ if (ret < 0) {
+ printk("IP_TPROXY: can't register prerouting hook.\n");
+ goto clean_table;
+ }
+
+ printk("IP_TPROXY: Transparent proxy support initialized, version 4.0.0\n"
+ "IP_TPROXY: Copyright (c) 2006-2007 BalaBit IT Ltd.\n");
+
+ return ret;
+
+ clean_table:
+ ipt_unregister_table(&tproxy_table);
+ return ret;
+}
+
+static void __exit fini(void)
+{
+ nf_unregister_hook(&ip_tproxy_pre_ops);
+ ipt_unregister_table(&tproxy_table);
+}
+
+module_init(init);
+module_exit(fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Krisztian Kovacs <hidden@balabit.hu>");
+MODULE_DESCRIPTION("iptables transparent proxy table");
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH/RFC 12/13] iptables TPROXY target
2007-03-05 15:44 [PATCH/RFC 00/13] Transparent proxying patches, take two KOVACS Krisztian
` (10 preceding siblings ...)
2007-03-05 15:46 ` [PATCH/RFC 11/13] iptables tproxy table KOVACS Krisztian
@ 2007-03-05 15:46 ` KOVACS Krisztian
2007-03-05 15:47 ` [PATCH/RFC 13/13] iptables tproxy match KOVACS Krisztian
12 siblings, 0 replies; 14+ messages in thread
From: KOVACS Krisztian @ 2007-03-05 15:46 UTC (permalink / raw)
To: netdev
The TPROXY target implements redirection of non-local TCP/UDP traffic
to local sockets. It is simply a wrapper around functionality exported
from iptable_tproxy.
Signed-off-by: KOVACS Krisztian <hidden@balabit.hu>
---
include/linux/netfilter_ipv4/ipt_TPROXY.h | 9 +++
net/ipv4/netfilter/Kconfig | 11 +++
net/ipv4/netfilter/Makefile | 1
net/ipv4/netfilter/ipt_TPROXY.c | 92 +++++++++++++++++++++++++++++
4 files changed, 113 insertions(+), 0 deletions(-)
diff --git a/include/linux/netfilter_ipv4/ipt_TPROXY.h b/include/linux/netfilter_ipv4/ipt_TPROXY.h
new file mode 100644
index 0000000..d05c956
--- /dev/null
+++ b/include/linux/netfilter_ipv4/ipt_TPROXY.h
@@ -0,0 +1,9 @@
+#ifndef _IPT_TPROXY_H_target
+#define _IPT_TPROXY_H_target
+
+struct ipt_tproxy_target_info {
+ u_int16_t lport;
+ u_int32_t laddr;
+};
+
+#endif
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index 17c3ec8..ecd8da5 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -638,6 +638,17 @@ config IP_NF_TPROXY
To compile it as a module, choose M here. If unsure, say N.
+config IP_NF_TARGET_TPROXY
+ tristate "TPROXY target support"
+ depends on IP_NF_TPROXY
+ help
+ This option adds a `TPROXY' target, which is somewhat similar to
+ REDIRECT. It can only be used in the tproxy table and is useful
+ to redirect traffic to a transparent proxy. It does _not_ depend
+ on Netfilter connection tracking.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
# ARP tables
config IP_NF_ARPTABLES
tristate "ARP tables support"
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile
index 21a29f4..a50a64e 100644
--- a/net/ipv4/netfilter/Makefile
+++ b/net/ipv4/netfilter/Makefile
@@ -106,6 +106,7 @@ obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o
obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o
obj-$(CONFIG_IP_NF_TARGET_CLUSTERIP) += ipt_CLUSTERIP.o
obj-$(CONFIG_IP_NF_TARGET_TTL) += ipt_TTL.o
+obj-$(CONFIG_IP_NF_TARGET_TPROXY) += ipt_TPROXY.o
# generic ARP tables
obj-$(CONFIG_IP_NF_ARPTABLES) += arp_tables.o
diff --git a/net/ipv4/netfilter/ipt_TPROXY.c b/net/ipv4/netfilter/ipt_TPROXY.c
new file mode 100644
index 0000000..89a08b1
--- /dev/null
+++ b/net/ipv4/netfilter/ipt_TPROXY.c
@@ -0,0 +1,92 @@
+/*
+ * Transparent proxy support for Linux/iptables
+ *
+ * Copyright (c) 2006-2007 BalaBit IT Ltd.
+ * Author: Balazs Scheidler, 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 <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ip.h>
+#include <net/checksum.h>
+#include <net/udp.h>
+#include <net/inet_sock.h>
+
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ip_tproxy.h>
+#include <linux/netfilter_ipv4/ipt_TPROXY.h>
+
+static unsigned int
+target(struct sk_buff **pskb,
+ const struct net_device *in,
+ const struct net_device *out,
+ unsigned int hooknum,
+ const struct xt_target *target,
+ const void *targinfo)
+{
+ const struct iphdr *iph = (*pskb)->nh.iph;
+ const struct ipt_tproxy_target_info *tgi =
+ (const struct ipt_tproxy_target_info *) targinfo;
+ unsigned int verdict = NF_ACCEPT;
+ struct sk_buff *skb = *pskb;
+ struct udphdr _hdr, *hp;
+ struct sock *sk;
+ __be32 daddr;
+ __be16 dport;
+
+ /* TCP/UDP only */
+ if ((iph->protocol != IPPROTO_TCP) &&
+ (iph->protocol != IPPROTO_UDP))
+ return NF_ACCEPT;
+
+ hp = skb_header_pointer(*pskb, iph->ihl * 4, sizeof(_hdr), &_hdr);
+ if (hp == NULL)
+ return NF_DROP;
+
+ daddr = tgi->laddr ? : iph->daddr;
+ dport = tgi->lport ? : hp->dest;
+ sk = ip_tproxy_get_sock(iph->protocol,
+ iph->saddr, daddr,
+ hp->source, dport, in);
+ if (sk != NULL) {
+ if (ip_tproxy_do_divert(skb, sk, 0, in) < 0)
+ verdict = NF_DROP;
+
+ if ((iph->protocol == IPPROTO_TCP) && (sk->sk_state == TCP_TIME_WAIT))
+ inet_twsk_put(inet_twsk(sk));
+ else
+ sock_put(sk);
+ }
+
+ return verdict;
+}
+
+static struct xt_target ipt_tproxy_reg = {
+ .name = "TPROXY",
+ .family = AF_INET,
+ .target = target,
+ .targetsize = sizeof(struct ipt_tproxy_target_info),
+ .table = "tproxy",
+ .me = THIS_MODULE,
+};
+
+static int __init init(void)
+{
+ return xt_register_target(&ipt_tproxy_reg);
+}
+
+static void __exit fini(void)
+{
+ xt_unregister_target(&ipt_tproxy_reg);
+}
+
+module_init(init);
+module_exit(fini);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Krisztian Kovacs <hidden@balabit.hu>");
+MODULE_DESCRIPTION("Netfilter transparent proxy TPROXY target module.");
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH/RFC 13/13] iptables tproxy match
2007-03-05 15:44 [PATCH/RFC 00/13] Transparent proxying patches, take two KOVACS Krisztian
` (11 preceding siblings ...)
2007-03-05 15:46 ` [PATCH/RFC 12/13] iptables TPROXY target KOVACS Krisztian
@ 2007-03-05 15:47 ` KOVACS Krisztian
12 siblings, 0 replies; 14+ messages in thread
From: KOVACS Krisztian @ 2007-03-05 15:47 UTC (permalink / raw)
To: netdev
Implements an iptables module which matches packets which have the
tproxy flag set, that is, packets diverted in the tproxy table.
Signed-off-by: KOVACS Krisztian <hidden@balabit.hu>
---
net/netfilter/Kconfig | 9 +++++
net/netfilter/Makefile | 1 +
net/netfilter/xt_tproxy.c | 77 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 87 insertions(+), 0 deletions(-)
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index 253fce3..b22346e 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -603,6 +603,15 @@ config NETFILTER_XT_MATCH_QUOTA
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `N'.
+config NETFILTER_XT_MATCH_TPROXY
+ tristate '"tproxy" match support'
+ depends on NETFILTER_XTABLES
+ help
+ This option adds a `tproxy' match, which allows you to match
+ packets which have been diverted to local sockets by TProxy.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
config NETFILTER_XT_MATCH_REALM
tristate '"realm" match support'
depends on NETFILTER_XTABLES
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index b2b5c75..83b2fd9 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -64,6 +64,7 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_MARK) += xt_mark.o
obj-$(CONFIG_NETFILTER_XT_MATCH_MULTIPORT) += xt_multiport.o
obj-$(CONFIG_NETFILTER_XT_MATCH_POLICY) += xt_policy.o
obj-$(CONFIG_NETFILTER_XT_MATCH_PKTTYPE) += xt_pkttype.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_TPROXY) += xt_tproxy.o
obj-$(CONFIG_NETFILTER_XT_MATCH_QUOTA) += xt_quota.o
obj-$(CONFIG_NETFILTER_XT_MATCH_REALM) += xt_realm.o
obj-$(CONFIG_NETFILTER_XT_MATCH_SCTP) += xt_sctp.o
diff --git a/net/netfilter/xt_tproxy.c b/net/netfilter/xt_tproxy.c
new file mode 100644
index 0000000..53f8bee
--- /dev/null
+++ b/net/netfilter/xt_tproxy.c
@@ -0,0 +1,77 @@
+/*
+ * Transparent proxy support for Linux/iptables
+ *
+ * Copyright (c) 2007 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 <linux/module.h>
+#include <linux/skbuff.h>
+
+#include <linux/netfilter/x_tables.h>
+
+static int
+match(const struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ const struct xt_match *match,
+ const void *matchinfo,
+ int offset,
+ unsigned int protoff,
+ int *hotdrop)
+{
+ return skb->ip_tproxy;
+}
+
+static int
+check(const char *tablename,
+ const void *entry,
+ const struct xt_match *match,
+ void *matchinfo,
+ unsigned int hook_mask)
+{
+ return 1;
+}
+
+static struct xt_match tproxy_matches[] = {
+ {
+ .name = "tproxy",
+ .match = match,
+ .matchsize = 0,
+ .checkentry = check,
+ .family = AF_INET,
+ .me = THIS_MODULE,
+ },
+ {
+ .name = "tproxy",
+ .match = match,
+ .matchsize = 0,
+ .checkentry = check,
+ .family = AF_INET6,
+ .me = THIS_MODULE,
+ },
+};
+
+static int __init xt_tproxy_init(void)
+{
+ return xt_register_matches(tproxy_matches, ARRAY_SIZE(tproxy_matches));
+}
+
+static void __exit xt_tproxy_fini(void)
+{
+ xt_unregister_matches(tproxy_matches, ARRAY_SIZE(tproxy_matches));
+}
+
+module_init(xt_tproxy_init);
+module_exit(xt_tproxy_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Krisztian Kovacs <hidden@balabit.hu>");
+MODULE_DESCRIPTION("iptables tproxy match module");
+MODULE_ALIAS("ipt_tproxy");
+MODULE_ALIAS("ip6t_tproxy");
^ permalink raw reply related [flat|nested] 14+ messages in thread
end of thread, other threads:[~2007-03-05 15:47 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-03-05 15:44 [PATCH/RFC 00/13] Transparent proxying patches, take two KOVACS Krisztian
2007-03-05 15:45 ` [PATCH/RFC 01/13] Implement local diversion of IPv4 skbs KOVACS Krisztian
2007-03-05 15:45 ` [PATCH/RFC 02/13] Port redirection support for TCP KOVACS Krisztian
2007-03-05 15:45 ` [PATCH/RFC 03/13] Don't do the TCP socket lookup if we already have one attached KOVACS Krisztian
2007-03-05 15:45 ` [PATCH/RFC 04/13] Don't do the UDP " KOVACS Krisztian
2007-03-05 15:45 ` [PATCH/RFC 05/13] Loosen source address check on IPv4 output KOVACS Krisztian
2007-03-05 15:45 ` [PATCH/RFC 06/13] Implement IP_TRANSPARENT socket option KOVACS Krisztian
2007-03-05 15:46 ` [PATCH/RFC 07/13] Conditionally enable transparent flow flag when connecting KOVACS Krisztian
2007-03-05 15:46 ` [PATCH/RFC 08/13] Handle TCP SYN+ACK/ACK/RST transparency KOVACS Krisztian
2007-03-05 15:46 ` [PATCH/RFC 09/13] Create a tproxy flag in struct sk_buff KOVACS Krisztian
2007-03-05 15:46 ` [PATCH/RFC 10/13] Export UDP socket lookup function KOVACS Krisztian
2007-03-05 15:46 ` [PATCH/RFC 11/13] iptables tproxy table KOVACS Krisztian
2007-03-05 15:46 ` [PATCH/RFC 12/13] iptables TPROXY target KOVACS Krisztian
2007-03-05 15:47 ` [PATCH/RFC 13/13] iptables tproxy match KOVACS Krisztian
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox