Skip to contentSkip to conversation

Transparent Proxying Patches, Take 3

PATCH In review KOVACS Krisztian 3 participants 45 messages Sep 30, 2007 – Oct 1, 2007

Subsystems (5)
Networking netfilter IPv4/IPv6 TCP +1 more subsystems
lore
Share & tools
lore
#0 lore raw

cover Transparent Proxying Patches, Take 3

Hi Patrick,

These patches are our (Balazs, Attila and me) third try at providing Linux 2.2-like transparent proxying support for Linux 2.6. During the 5th Netfilter Workshop in Karlsruhe, Germany we tried to come up with an even more lightweight approach not requiring the modification of the IPv4 routing code at all.

The most important changes relative to the previous versions[1,2] are:
* the tproxy table is gone, TPROXY targets need to be added to the mangle table instead
* the tproxy match is gone, a new "socket" match is introduced
* instead of using a separate routing trick to divert packets to the local IP stack inside the TProxy target, we are now using stock routing decisions, and need a bit in the packet MARK field, and perform diversion by using an advanced routing rule (this hopefully makes it possible to implement IPv6 support in the future
* instead of IP_FREEBIND we are using a setsockopt named IP_TRANSPARENT which requires CAP_NET_ADMIN privilege
* in previous patches the output routing decision was commented out, it is now correctly decided whether a packet belongs to a tproxied connection or not.

Usage is a bit more complicated compared to the previous approach, but it's certainly not rocket science:

# iptables rules necessary:
# create a chain named DIVERT
iptables -t mangle -N DIVERT
# everything that matches "-m socket" should go to the local stack
iptables -t mangle -A PREROUTING -p tcp -m socket -j DIVERT
# connections to be redirected should use the TPROXY target, which sets 
# up redirection, and marks the packet according to its 'tproxy-mark' 
# argument
iptables -t mangle -A PREROUTING -p tcp --dport 80 -j TPROXY \
   --tproxy-mark 0x1/0x1 --on-port 50080
# DIVERT chain: mark packets and accept
iptables -t mangle -A DIVERT -j MARK --set-mark 1
iptables -t mangle -A DIVERT -j ACCEPT
# set up advanced routing rules to deliver our marked packets locally
ip rule add fwmark 1 lookup 100
ip route add local 0.0.0.0/0 dev lo table 100

The proxy code needs to be modified as well, but these are really lightweight:
before binding, the IP_TRANSPARENT sockopt needs to be enabled on the socket. This implies IP_FREEBIND, so after enabling this socket option non-local binds will work and if you got your iptables/iproute setup right non-local traffic will be delivered to/from the socket. A netcat patch demonstrating this is available[4] as an example.

Some word about the patches:

* output path (patches 1-5): these modifications make it possible to output IPv4 datagrams with non-local IP addresses by:
- introducing a new flowi flag (FLOWI_FLAG_ANYSRC) which disables the source address check in ip_route_output_slow() [3]
- adding the IP_TRANSPARENT socket option (setting this requires CAP_NET_ADMIN)
- setting FLOWI_FLAG_ANYSRC if IP_TRANSPARENT is enabled for the originating socket
- set FLOWI_FLAG_ANYSRC where appropriate for sending reply packets generated by the kernel; this requires extending the ip_reply_arg structure with a flags field and adding an IP_REPLY_ARG_NOSRCCHECK flag

* input patch (patches 6-13): these changes implement redirection support for TCP plus the iptables socket match and TPROXY target -- these provide the actual user interface:
- split IPv4 defragmentation into a separate module, as this is needed by both our target and match
- add a 'socket' match which does a socket lookup based on the destination tuple in the packet and matches is a socket has been found
- add a 'TPROXY' target which looks up a socket based on a modified IP/port tuple and stores the socket reference in the skb
- modifying the TCP/UDP input paths to use the stored socket reference if present

All kinds of comments welcome. Patrick, I'd like to ask you to review these patches and if no issues are found by you or by anyone on the list, please consider merging them.

I'll send the necessary iptables changes in a separate mail.

References:
[1] http://marc.info/?l=linux-netdev&m=117310979603009&w=2
[2] http://www.balabit.com/downloads/files/tproxy/
[3] http://marc.info/?l=linux-netdev&m=118065358510836&w=2
[4] http://people.netfilter.org/hidden/tproxy/netcat-ip_transparent-support.patch

Signature · 1 line
KOVACS Krisztian
#1 lore raw

PATCH 1/13 Loosen source address check on IPv4 output

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.

---

 include/net/flow.h |    1 +
 net/ipv4/route.c   |   20 +++++++++++++-------
 2 files changed, 14 insertions(+), 7 deletions(-)
include/net/flow.h +1 -0
index af59fa5..c734d50 100644
@@ -49,6 +49,7 @@ struct flowi {
 	__u8	proto;
 	__u8	flags;
 #define FLOWI_FLAG_MULTIPATHOLDROUTE 0x01
+#define FLOWI_FLAG_ANYSRC 0x02
 	union {
 		struct {
 			__be16	sport;
net/ipv4/route.c +13 -7
index c7ca94b..26e9659 100644
@@ -2172,11 +2172,6 @@ static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp)
 		    ZERONET(oldflp->fl4_src))
 			goto out;
 
-		/* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */
-		dev_out = ip_dev_find(oldflp->fl4_src);
-		if (dev_out == NULL)
-			goto out;
-
 		/* I removed check for oif == dev_out->oif here.
 		   It was wrong for two reasons:
 		   1. ip_dev_find(saddr) can return wrong iface, if saddr is
@@ -2187,6 +2182,11 @@ static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp)
 
 		if (oldflp->oif == 0
 		    && (MULTICAST(oldflp->fl4_dst) || oldflp->fl4_dst == htonl(0xFFFFFFFF))) {
+			/* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */
+			dev_out = ip_dev_find(oldflp->fl4_src);
+			if (dev_out == NULL)
+				goto out;
+
 			/* Special hack: user can direct multicasts
 			   and limited broadcast via necessary interface
 			   without fiddling with IP_MULTICAST_IF or IP_PKTINFO.
@@ -2205,9 +2205,15 @@ static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp)
 			fl.oif = dev_out->ifindex;
 			goto make_route;
 		}
-		if (dev_out)
+
+		if (!(oldflp->flags & FLOWI_FLAG_ANYSRC)) {
+			/* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */
+			dev_out = ip_dev_find(oldflp->fl4_src);
+			if (dev_out == NULL)
+				goto out;
 			dev_put(dev_out);
-		dev_out = NULL;
+			dev_out = NULL;
+		}
 	}
 
 
Acked-by on v1 1/13
#2 lore raw

Re: [PATCH 01/13] Loosen source address check on IPv4 output

Quoted 10 lines · KOVACS Krisztian

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.

#3 lore raw

PATCH 2/13 Implement IP_TRANSPARENT socket option

In reply to KOVACS Krisztian

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.

---

 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(-)
include/linux/in.h +1 -0
index 3975cbf..d8c55ab 100644
@@ -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
include/net/inet_sock.h +2 -1
index 62daf21..e86832d 100644
@@ -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;
include/net/inet_timewait_sock.h +2 -1
index 47d52b2..23e2fba 100644
@@ -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;
include/net/route.h +1 -0
index f7ce625..88fed3c 100644
@@ -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>
net/ipv4/inet_timewait_sock.c +1 -0
index 2586df0..cf057a3 100644
@@ -107,6 +107,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);
net/ipv4/ip_sockglue.c +11 -1
index 6b420ae..282b187 100644
@@ -420,7 +420,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)) {
@@ -885,6 +885,16 @@ static int do_ip_setsockopt(struct sock *sk, int level,
 		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;
#5 lore raw

PATCH 3/13 Allow binding to non-local addresses if IP_TRANSPARENT is set

In reply to KOVACS Krisztian

Setting IP_TRANSPARENT is not really useful without allowing non-local binds for the socket. To make user-space code simpler we allow these binds even if IP_TRANSPARENT is set but IP_FREEBIND is not.

---

 net/ipv4/af_inet.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
net/ipv4/af_inet.c +1 -1
index e681034..90344db 100644
@@ -448,7 +448,7 @@ int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 	 */
 	err = -EADDRNOTAVAIL;
 	if (!sysctl_ip_nonlocal_bind &&
-	    !inet->freebind &&
+	    !(inet->freebind || inet->transparent) &&
 	    addr->sin_addr.s_addr != INADDR_ANY &&
 	    chk_addr_ret != RTN_LOCAL &&
 	    chk_addr_ret != RTN_MULTICAST &&

-
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

Acked-by on v1 3/13
#6 lore raw

Re: [PATCH 03/13] Allow binding to non-local addresses if IP_TRANSPARENT is set

Quoted 6 lines · KOVACS Krisztian

Setting IP_TRANSPARENT is not really useful without allowing non-local binds for the socket. To make user-space code simpler we allow these binds even if IP_TRANSPARENT is set but IP_FREEBIND is not.

-
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#7 lore raw

PATCH 4/13 Conditionally enable transparent flow flag when connecting

In reply to KOVACS Krisztian

Set FLOWI_FLAG_ANYSRC 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.

---

 include/net/route.h |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)
include/net/route.h +4 -0
index 88fed3c..9788cc2 100644
@@ -158,6 +158,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_ANYSRC;
+
 	if (!dst || !src) {
 		err = __ip_route_output_key(rp, &fl);
 		if (err)
#8 lore raw

PATCH 5/13 Handle TCP SYN+ACK/ACK/RST transparency

In reply to KOVACS Krisztian

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_ANYSRC flag when doing the route lookup for those replies. Transparent replies are enabled if the listening socket has the transparent socket flag set.

---

 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             |   17 ++++++++++-------
 net/ipv4/tcp_minisocks.c        |    3 ++-
 net/ipv6/tcp_ipv6.c             |    5 +++--
 8 files changed, 29 insertions(+), 12 deletions(-)
include/net/ip.h +3 -0
index abf2820..0084001 100644
@@ -138,8 +138,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 */ 
include/net/request_sock.h +2 -1
index 7aed02c..b9c8974 100644
@@ -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);
net/ipv4/inet_connection_sock.c +2 -0
index fbe7714..26b9dbe 100644
@@ -321,6 +321,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_ANYSRC : 0,
 			    .uli_u = { .ports =
 				       { .sport = inet_sk(sk)->sport,
 					 .dport = ireq->rmt_port } } };
net/ipv4/ip_output.c +5 -1
index 0f1d7be..40cafcd 100644
@@ -322,6 +322,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_ANYSRC : 0,
 					    .uli_u = { .ports =
 						       { .sport = inet->sport,
 							 .dport = inet->dport } } };
@@ -1364,7 +1366,9 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar
 				    .uli_u = { .ports =
 					       { .sport = tcp_hdr(skb)->dest,
 						 .dport = tcp_hdr(skb)->source } },
-				    .proto = sk->sk_protocol };
+				    .proto = sk->sk_protocol,
+				    .flags = (arg->flags & IP_REPLY_ARG_NOSRCCHECK) ?
+				    		FLOWI_FLAG_ANYSRC : 0 };
 		security_skb_classify_flow(skb, &fl);
 		if (ip_route_output_key(&rt, &fl))
 			return;
net/ipv4/syncookies.c +2 -0
index 2da1be0..f7fad59 100644
@@ -260,6 +260,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_ANYSRC : 0,
 				    .uli_u = { .ports =
 					       { .sport = th->dest,
 						 .dport = th->source } } };
net/ipv4/tcp_ipv4.c +10 -7
index e089a97..7ae47e6 100644
@@ -612,6 +612,7 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb)
 				      ip_hdr(skb)->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);
 
@@ -625,7 +626,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 = tcp_hdr(skb);
 	struct {
@@ -701,36 +702,37 @@ static void tcp_v4_send_ack(struct tcp_timewait_sock *twsk,
 					arg.iov[0].iov_len);
 	}
 #endif
+	arg.flags = reply_flags;
 	arg.csum = csum_tcpudp_nofold(ip_hdr(skb)->daddr,
 				      ip_hdr(skb)->saddr, /* XXX */
 				      arg.iov[0].iov_len, IPPROTO_TCP, 0);
 	arg.csumoffset = offsetof(struct tcphdr, check) / 2;
 	if (twsk)
 		arg.bound_dev_if = twsk->tw_sk.tw_bound_dev_if;
-
 	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);
 }
 
 /*
@@ -1742,7 +1744,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;
net/ipv4/tcp_minisocks.c +2 -1
index a12b08f..734d119 100644
@@ -604,7 +604,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;
net/ipv6/tcp_ipv6.c +3 -2
index 3e06799..b3f3c1d 100644
@@ -72,7 +72,7 @@
 static struct socket *tcp6_socket;
 
 static void	tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb);
-static void	tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req);
+static void	tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req, int reply_flags);
 static void	tcp_v6_send_check(struct sock *sk, int len,
 				  struct sk_buff *skb);
 
@@ -1183,7 +1183,8 @@ static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb)
 	inet_twsk_put(tw);
 }
 
-static void tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req)
+static void tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req,
+				  int reply_flags)
 {
 	tcp_v6_send_ack(NULL, skb, tcp_rsk(req)->snt_isn + 1, tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd, req->ts_recent);
 }
#9 lore raw

Re: [PATCH 05/13] Handle TCP SYN+ACK/ACK/RST transparency

Quoted 9 lines · KOVACS Krisztian

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_ANYSRC flag when doing the route lookup for those replies. Transparent replies are enabled if the listening socket has the transparent socket flag set.

I needed to add extra patches to actually compile it cleanly....

Quoted 10 lines
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             |   17 ++++++++++-------
net/ipv4/tcp_minisocks.c        |    3 ++-
net/ipv6/tcp_ipv6.c             |    5 +++--
8 files changed, 29 insertions(+), 12 deletions(-)
---
 net/dccp/dccp.h      |    3 ++-
 net/dccp/minisocks.c |    3 ++-
 2 files changed, 4 insertions(+), 2 deletions(-)
net/dccp/dccp.h +2 -1
Index: linux-2.6.22.1/net/dccp/dccp.h
===================================================================
@@ -209,7 +209,8 @@ extern int  dccp_retransmit_skb(struct s
 
 extern void dccp_send_ack(struct sock *sk);
 extern void dccp_send_delayed_ack(struct sock *sk);
-extern void dccp_reqsk_send_ack(struct sk_buff *sk, struct request_sock *rsk);
+extern void dccp_reqsk_send_ack(struct sk_buff *sk, struct request_sock *rsk,
+	int reply_flags);
 
 extern void dccp_send_sync(struct sock *sk, const u64 seq,
 			   const enum dccp_pkt_type pkt_type);
net/dccp/minisocks.c +2 -1
Index: linux-2.6.22.1/net/dccp/minisocks.c
===================================================================
@@ -285,7 +285,8 @@ int dccp_child_process(struct sock *pare
 
 EXPORT_SYMBOL_GPL(dccp_child_process);
 
-void dccp_reqsk_send_ack(struct sk_buff *skb, struct request_sock *rsk)
+void dccp_reqsk_send_ack(struct sk_buff *skb, struct request_sock *rsk,
+    int reply_flags)
 {
 	DCCP_BUG("DCCP-ACK packets are never sent in LISTEN/RESPOND state");
 }
#10 lore raw

Re: [PATCH 05/13] Handle TCP SYN+ACK/ACK/RST transparency

Quoted 8 lines · KOVACS Krisztian
Quoted 6 lines

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.

Quoted 16 lines
Quoted 3 lines

This patch selectively sets the FLOWI_FLAG_ANYSRC flag when doing the route lookup for those replies. Transparent replies are enabled if the listening socket has the transparent socket flag set.

I needed to add extra patches to actually compile it cleanly....

Quoted 10 lines
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             |   17 ++++++++++-------
net/ipv4/tcp_minisocks.c        |    3 ++-
net/ipv6/tcp_ipv6.c             |    5 +++--
8 files changed, 29 insertions(+), 12 deletions(-)

part 2/2.

Quoted 3 lines
---
 net/ipv6/tcp_ipv6.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
net/ipv6/tcp_ipv6.c +2 -2
Index: linux-2.6.22.3/net/ipv6/tcp_ipv6.c
===================================================================
@@ -73,7 +73,7 @@
 static struct socket *tcp6_socket;
 
 static void	tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb);
-static void	tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req);
+static void	tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req, int);
 static void	tcp_v6_send_check(struct sock *sk, int len,
 				  struct sk_buff *skb);
 
@@ -1195,7 +1195,7 @@ static void tcp_v6_timewait_ack(struct s
 	inet_twsk_put(tw);
 }
 
-static void tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req)
+static void tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req, int reply_flags)
 {
 	tcp_v6_send_ack(NULL, skb, tcp_rsk(req)->snt_isn + 1, tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd, req->ts_recent);
 }
#11 lore raw

Re: [PATCH 05/13] Handle TCP SYN+ACK/ACK/RST transparency

Hi Jan,

Quoted 27 lines · Jan Engelhardt

part 2/2.

Quoted 1 line
---
 net/ipv6/tcp_ipv6.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

Index: linux-2.6.22.3/net/ipv6/tcp_ipv6.c
===================================================================

net/ipv6/tcp_ipv6.c +0 -1
@@ -73,7 +73,7 @@
 static struct socket *tcp6_socket;
 
 static void	tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb);
-static void	tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct

request_sock *req); +static void tcp_v6_reqsk_send_ack(struct sk_buff
*skb, struct request_sock *req, int); static
void tcp_v6_send_check(struct sock *sk, int len,

net/ipv6/tcp_ipv6.c +0 -1
 				  struct sk_buff *skb);
@@ -1195,7 +1195,7 @@ static void tcp_v6_timewait_ack(struct s
 	inet_twsk_put(tw);
 }
 
-static void tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct
Quoted 8 lines

request_sock *req) +static void tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req, int reply_flags) {
tcp_v6_send_ack(NULL, skb, tcp_rsk(req)->snt_isn + 1,
tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd, req->ts_recent); } -
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

This is already _in_ the patch I've sent.

Signature · 1 line
 KOVACS Krisztian
#12 lore raw

Re: [PATCH 05/13] Handle TCP SYN+ACK/ACK/RST transparency

Quoted 11 lines · KOVACS Krisztian
Quoted 11 lines
---
 net/ipv6/tcp_ipv6.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

Index: linux-2.6.22.3/net/ipv6/tcp_ipv6.c
===================================================================

net/ipv6/tcp_ipv6.c +0 -0
@@ -73,7 +73,7 @@
 static struct socket *tcp6_socket;
 
Quoted 8 lines
Quoted 6 lines
net/ipv6/tcp_ipv6.c +0 -1
 static void	tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb);
-static void	tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct

request_sock *req); +static void tcp_v6_reqsk_send_ack(struct sk_buff
*skb, struct request_sock *req, int); static
void tcp_v6_send_check(struct sock *sk, int len,
struct sk_buff *skb);

This is already _in_ the patch I've sent.

Hm, my bad, did not look to far. (Also these were the 2.6.22 ones - I should probably update)

#13 lore raw

Re: [PATCH 05/13] Handle TCP SYN+ACK/ACK/RST transparency

In reply to Jan Engelhardt

Hi Jan,

Quoted 26 lines · Jan Engelhardt
---
 net/dccp/dccp.h      |    3 ++-
 net/dccp/minisocks.c |    3 ++-
 2 files changed, 4 insertions(+), 2 deletions(-)

Index: linux-2.6.22.1/net/dccp/dccp.h
===================================================================

net/dccp/dccp.h +0 -1
@@ -209,7 +209,8 @@ extern int  dccp_retransmit_skb(struct s
 
 extern void dccp_send_ack(struct sock *sk);
 extern void dccp_send_delayed_ack(struct sock *sk);
-extern void dccp_reqsk_send_ack(struct sk_buff *sk, struct

request_sock *rsk); +extern void dccp_reqsk_send_ack(struct sk_buff
*sk, struct request_sock *rsk, + int reply_flags);

extern void dccp_send_sync(struct sock *sk, const u64 seq,
const enum dccp_pkt_type pkt_type);
Index: linux-2.6.22.1/net/dccp/minisocks.c
===================================================================

net/dccp/minisocks.c int dccp_child_process(struct sock *pare · line 292

Quoted 9 lines
net/dccp/minisocks.c +0 -1
@@ -285,7 +285,8 @@ int dccp_child_process(struct sock *pare
 
 EXPORT_SYMBOL_GPL(dccp_child_process);
 
-void dccp_reqsk_send_ack(struct sk_buff *skb, struct request_sock
 *rsk) +void dccp_reqsk_send_ack(struct sk_buff *skb, struct
 request_sock *rsk, +    int reply_flags)
 {
 	DCCP_BUG("DCCP-ACK packets are never sent in LISTEN/RESPOND state");
 }

Yes, this was missing. Thanks.

Signature · 1 line
 KOVACS Krisztian
#14 lore raw

Re: [PATCH 05/13] Handle TCP SYN+ACK/ACK/RST transparency

In reply to KOVACS Krisztian
Quoted 17 lines · KOVACS Krisztian

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_ANYSRC flag when doing the route lookup for those replies. Transparent replies are enabled if the listening socket has the transparent socket flag set.

---

include/net/request_sock.h +0 -0
index 7aed02c..b9c8974 100644

include/net/request_sock.h struct request_sock_ops { · line 39

Quoted 7 lines
include/net/request_sock.h +2 -1
@@ -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);
 

How about putting the flags in the request_sock?

net/ipv4/inet_connection_sock.c struct dst_entry* inet_csk_route_req(struct sock *sk, · line 326

Quoted 11 lines
net/ipv4/inet_connection_sock.c +2 -0
index fbe7714..26b9dbe 100644
@@ -321,6 +321,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_ANYSRC : 0,
 

Introducing a function (sk_flowi_flags(sk) or something) might make it a bit nicer to look at.

Quoted 14 lines
net/ipv4/tcp_ipv4.c +1 -1
index e089a97..7ae47e6 100644
@@ -625,7 +626,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 = tcp_hdr(skb);
 	struct {

net/ipv4/tcp_ipv4.c static void tcp_v4_send_ack(struct tcp_timewait_sock *twsk, · line 706

Quoted 5 lines
net/ipv4/tcp_ipv4.c +1 -0
@@ -701,36 +702,37 @@ static void tcp_v4_send_ack(struct tcp_timewait_sock *twsk,
 					arg.iov[0].iov_len);
 	}
 #endif
+	arg.flags = reply_flags;
 

Shouldn't this use twsk->transparent?

net/ipv4/tcp_ipv4.c static void tcp_v4_send_ack(struct tcp_timewait_sock *twsk, · line 712

Quoted 8 lines
net/ipv4/tcp_ipv4.c +0 -1
 	arg.csum = csum_tcpudp_nofold(ip_hdr(skb)->daddr,
 				      ip_hdr(skb)->saddr, /* XXX */
 				      arg.iov[0].iov_len, IPPROTO_TCP, 0);
 	arg.csumoffset = offsetof(struct tcphdr, check) / 2;
 	if (twsk)
 		arg.bound_dev_if = twsk->tw_sk.tw_bound_dev_if;
-
 	ip_send_reply(tcp_socket->sk, skb, &arg, arg.iov[0].iov_len);

Unrelated whitespace change

#15 lore raw

Re: [PATCH 05/13] Handle TCP SYN+ACK/ACK/RST transparency

Hi Patrick,

Quoted 13 lines · Patrick McHardy
Quoted 12 lines · KOVACS Krisztian

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_ANYSRC flag when doing the route lookup for those replies. Transparent replies are enabled if the listening socket has the transparent socket flag set.

---

Quoted 13 lines

include/net/request_sock.h struct request_sock_ops { · line 38

Quoted 11 lines
include/net/request_sock.h +2 -1
index 7aed02c..b9c8974 100644
@@ -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);

How about putting the flags in the request_sock?

Nice idea, I'll give it a try.

Quoted 5 lines
Quoted 5 lines
(quoted diff) +0 -0

b/net/ipv4/inet_connection_sock.c index fbe7714..26b9dbe 100644

net/ipv4/inet_connection_sock.c +0 -0
@@ -321,6 +321,8 @@ struct dst_entry* inet_csk_route_req(struct sock
Quoted 8 lines

net/ipv4/inet_connection_sock.c struct dst_entry* inet_csk_route_req(struct sock *sk, · line 325

Quoted 5 lines
net/ipv4/inet_connection_sock.c +2 -0
 *sk, .saddr = ireq->loc_addr,
 					.tos = RT_CONN_FLAGS(sk) } },
 			    .proto = sk->sk_protocol,
+			    .flags = inet_sk(sk)->transparent ?
+					FLOWI_FLAG_ANYSRC : 0,

Introducing a function (sk_flowi_flags(sk) or something) might make it a bit nicer to look at.

Ok, done for the next round of patches.

Quoted 7 lines
Quoted 7 lines
net/ipv4/tcp_ipv4.c +0 -0
index e089a97..7ae47e6 100644
@@ -625,7 +626,7 @@ static void tcp_v4_send_reset(struct sock *sk,
 struct sk_buff *skb)
 
Quoted 14 lines

net/ipv4/tcp_ipv4.c static void tcp_v4_send_ack(struct · line 705

Quoted 12 lines
net/ipv4/tcp_ipv4.c +1 -1
 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 = tcp_hdr(skb);
net/ipv4/tcp_ipv4.c +1 -0
 	struct {
@@ -701,36 +702,37 @@ static void tcp_v4_send_ack(struct
 tcp_timewait_sock *twsk, arg.iov[0].iov_len);
 	}
 #endif
+	arg.flags = reply_flags;

Shouldn't this use twsk->transparent?

We can't, as tcp_v4_send_ack() is called with twsk == NULL from tcp_v4_reqsk_send_ack().

Signature · 1 line
 KOVACS Krisztian
#16 lore raw

PATCH 6/13 Port redirection support for TCP

In reply to KOVACS Krisztian

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.

---

 include/net/inet_sock.h         |    3 +++
 include/net/tcp.h               |    3 +++
 net/ipv4/inet_connection_sock.c |    4 ++++
 net/ipv4/syncookies.c           |    3 +++
 net/ipv4/tcp_output.c           |    4 ++++
 5 files changed, 17 insertions(+), 0 deletions(-)
include/net/inet_sock.h +3 -0
index e86832d..5339089 100644
@@ -65,6 +65,9 @@ struct inet_request_sock {
 #endif
 	__be32			loc_addr;
 	__be32			rmt_addr;
+#if defined(CONFIG_NETFILTER_TPROXY) || defined(CONFIG_NETFILTER_TPROXY_MODULE)
+	__be16			loc_port;
+#endif
 	__be16			rmt_port;
 	u16			snd_wscale : 4, 
 				rcv_wscale : 4, 
include/net/tcp.h +3 -0
index 54053de..927d235 100644
@@ -980,6 +980,9 @@ static inline void tcp_openreq_init(struct request_sock *req,
 	ireq->acked = 0;
 	ireq->ecn_ok = 0;
 	ireq->rmt_port = tcp_hdr(skb)->source;
+#if defined(CONFIG_NETFILTER_TPROXY) || defined(CONFIG_NETFILTER_TPROXY_MODULE)
+	ireq->loc_port = tcp_hdr(skb)->dest;
+#endif
 }
 
 extern void tcp_enter_memory_pressure(void);
net/ipv4/inet_connection_sock.c +4 -0
index 26b9dbe..f47d966 100644
@@ -502,6 +502,10 @@ 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;
+#if defined(CONFIG_IP_NF_TPROXY) || defined(CONFIG_IP_NF_TPROXY_MODULE)
+		inet_sk(newsk)->num = ntohs(inet_rsk(req)->loc_port);
+		inet_sk(newsk)->sport = inet_rsk(req)->loc_port;
+#endif
 		newsk->sk_write_space = sk_stream_write_space;
 
 		newicsk->icsk_retransmits = 0;
net/ipv4/syncookies.c +3 -0
index f7fad59..a55ccf1 100644
@@ -223,6 +223,9 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
 	treq->rcv_isn		= ntohl(th->seq) - 1;
 	treq->snt_isn		= cookie;
 	req->mss		= mss;
+#if defined(CONFIG_IP_NF_TPROXY) || defined(CONFIG_IP_NF_TPROXY_MODULE)
+	ireq->loc_port		= th->dest;
+#endif
 	ireq->rmt_port		= th->source;
 	ireq->loc_addr		= ip_hdr(skb)->daddr;
 	ireq->rmt_addr		= ip_hdr(skb)->saddr;
net/ipv4/tcp_output.c +4 -0
index 666d8a5..69dd230 100644
@@ -2153,7 +2153,11 @@ 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);
+#if defined(CONFIG_IP_NF_TPROXY) || defined(CONFIG_IP_NF_TPROXY_MODULE)
+	th->source = ireq->loc_port;
+#else
 	th->source = inet_sk(sk)->sport;
+#endif
 	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;
#17 lore raw

Re: [PATCH 06/13] Port redirection support for TCP

Quoted 46 lines · KOVACS Krisztian

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.

---

include/net/inet_sock.h +3 -0
index e86832d..5339089 100644
@@ -65,6 +65,9 @@ struct inet_request_sock {
 #endif
 	__be32			loc_addr;
 	__be32			rmt_addr;
+#if defined(CONFIG_NETFILTER_TPROXY) || defined(CONFIG_NETFILTER_TPROXY_MODULE)
+	__be16			loc_port;
+#endif
 	__be16			rmt_port;
 	u16			snd_wscale : 4, 
 				rcv_wscale : 4, 
include/net/tcp.h +3 -0
index 54053de..927d235 100644
@@ -980,6 +980,9 @@ static inline void tcp_openreq_init(struct request_sock *req,
 	ireq->acked = 0;
 	ireq->ecn_ok = 0;
 	ireq->rmt_port = tcp_hdr(skb)->source;
+#if defined(CONFIG_NETFILTER_TPROXY) || defined(CONFIG_NETFILTER_TPROXY_MODULE)
+	ireq->loc_port = tcp_hdr(skb)->dest;
+#endif
 }
 
 extern void tcp_enter_memory_pressure(void);
net/ipv4/inet_connection_sock.c +0 -0
index 26b9dbe..f47d966 100644

net/ipv4/inet_connection_sock.c struct sock *inet_csk_clone(struct sock *sk, const struct request_sock *req, · line 509

Quoted 8 lines
net/ipv4/inet_connection_sock.c +3 -0
@@ -502,6 +502,10 @@ 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;
+#if defined(CONFIG_IP_NF_TPROXY) || defined(CONFIG_IP_NF_TPROXY_MODULE)
+		inet_sk(newsk)->num = ntohs(inet_rsk(req)->loc_port);
 
+		inet_sk(newsk)->sport = inet_rsk(req)->loc_port;
 

Why do you store the port twice here?

Quoted 5 lines

ipv4/tcp_output.c
index 666d8a5..69dd230 100644

net/ipv4/tcp_output.c struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst, · line 2161

Quoted 9 lines
net/ipv4/tcp_output.c +4 -0
@@ -2153,7 +2153,11 @@ 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);
+#if defined(CONFIG_IP_NF_TPROXY) || defined(CONFIG_IP_NF_TPROXY_MODULE)
+	th->source = ireq->loc_port;
+#else
 	th->source = inet_sk(sk)->sport;
+#endif
 

I think this should simply use loc_port unconditionally.

#18 lore raw

Re: [PATCH 06/13] Port redirection support for TCP

Hi Patrick,

Quoted 50 lines · Patrick McHardy
Quoted 49 lines · KOVACS Krisztian

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.

---

include/net/inet_sock.h +2 -0
index e86832d..5339089 100644
@@ -65,6 +65,9 @@ struct inet_request_sock {
 #endif
 	__be32			loc_addr;
 	__be32			rmt_addr;
+#if defined(CONFIG_NETFILTER_TPROXY) ||
 defined(CONFIG_NETFILTER_TPROXY_MODULE) +	__be16			loc_port;
+#endif
 	__be16			rmt_port;
 	u16			snd_wscale : 4,
 				rcv_wscale : 4,
include/net/tcp.h +1 -0
index 54053de..927d235 100644
@@ -980,6 +980,9 @@ static inline void tcp_openreq_init(struct
 request_sock *req, ireq->acked = 0;
 	ireq->ecn_ok = 0;
 	ireq->rmt_port = tcp_hdr(skb)->source;
+#if defined(CONFIG_NETFILTER_TPROXY) ||

defined(CONFIG_NETFILTER_TPROXY_MODULE) + ireq->loc_port =
tcp_hdr(skb)->dest;

include/net/tcp.h +1 -0
+#endif
 }
 
 extern void tcp_enter_memory_pressure(void);
(quoted diff) +0 -0

b/net/ipv4/inet_connection_sock.c index 26b9dbe..f47d966 100644

net/ipv4/inet_connection_sock.c +0 -0
@@ -502,6 +502,10 @@ struct sock *inet_csk_clone(struct sock *sk,
 const struct request_sock *req, newicsk->icsk_bind_hash = NULL;
 
Quoted 8 lines

net/ipv4/inet_connection_sock.c struct sock *inet_csk_clone(struct sock *sk, const struct request_sock *req, · line 507

Quoted 6 lines
net/ipv4/inet_connection_sock.c +1 -0
 		inet_sk(newsk)->dport = inet_rsk(req)->rmt_port;
+#if defined(CONFIG_IP_NF_TPROXY) ||

defined(CONFIG_IP_NF_TPROXY_MODULE) + inet_sk(newsk)->num =
ntohs(inet_rsk(req)->loc_port);

net/ipv4/inet_connection_sock.c +1 -0
+		inet_sk(newsk)->sport = inet_rsk(req)->loc_port;

Why do you store the port twice here?

Because ->num is in host byte order while sport is host byte order.

Quoted 7 lines
Quoted 7 lines

ipv4/tcp_output.c
index 666d8a5..69dd230 100644

net/ipv4/tcp_output.c +0 -0
@@ -2153,7 +2153,11 @@ struct sk_buff * tcp_make_synack(struct sock
 *sk, struct dst_entry *dst, th->syn = 1;
 	th->ack = 1;
Quoted 8 lines

net/ipv4/tcp_output.c struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst, · line 2160

Quoted 6 lines
net/ipv4/tcp_output.c +3 -0
 	TCP_ECN_make_synack(req, th);
+#if defined(CONFIG_IP_NF_TPROXY) ||
 defined(CONFIG_IP_NF_TPROXY_MODULE) +	th->source = ireq->loc_port;
+#else
 	th->source = inet_sk(sk)->sport;
+#endif

I think this should simply use loc_port unconditionally.

Unfortunately ireq->loc_port does not exist unless tproxy is enabled in the config. (We could remove all these #ifdefs but that would mean extending inet_request_sock with 2 bytes even if tproxy is not enabled.)

Signature · 1 line
 KOVACS Krisztian
#19 lore raw

Re: [PATCH 06/13] Port redirection support for TCP

Quoted 17 lines · KOVACS Krisztian
Quoted 7 lines
Quoted 7 lines

ipv4/tcp_output.c
index 666d8a5..69dd230 100644

net/ipv4/tcp_output.c +0 -0
@@ -2153,7 +2153,11 @@ struct sk_buff * tcp_make_synack(struct sock
 *sk, struct dst_entry *dst, th->syn = 1;
 	th->ack = 1;
Quoted 8 lines

net/ipv4/tcp_output.c struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst, · line 2160

Quoted 6 lines
net/ipv4/tcp_output.c +3 -0
 	TCP_ECN_make_synack(req, th);
+#if defined(CONFIG_IP_NF_TPROXY) ||
 defined(CONFIG_IP_NF_TPROXY_MODULE) +	th->source = ireq->loc_port;
+#else
 	th->source = inet_sk(sk)->sport;
+#endif

I think this should simply use loc_port unconditionally.

Quoted 3 lines

Unfortunately ireq->loc_port does not exist unless tproxy is enabled in the config. (We could remove all these #ifdefs but that would mean extending inet_request_sock with 2 bytes even if tproxy is not enabled.)

There's a 2 byte hole with IPv6 where you could put this in. I think even without IPv6 the small waste is not worth the increased testing complexity.

#20 lore raw

Re: [PATCH 06/13] Port redirection support for TCP

Hi Patrick,

Quoted 18 lines · Patrick McHardy
Quoted 17 lines · KOVACS Krisztian
Quoted 15 lines

net/ipv4/tcp_output.c struct sk_buff * tcp_make_synack(struct sock · line 2160

Quoted 13 lines

ipv4/tcp_output.c
index 666d8a5..69dd230 100644

net/ipv4/tcp_output.c +3 -0
@@ -2153,7 +2153,11 @@ 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);
+#if defined(CONFIG_IP_NF_TPROXY) ||
 defined(CONFIG_IP_NF_TPROXY_MODULE) +	th->source = ireq->loc_port;
+#else
 	th->source = inet_sk(sk)->sport;
+#endif

I think this should simply use loc_port unconditionally.

Quoted 8 lines
Quoted 3 lines

Unfortunately ireq->loc_port does not exist unless tproxy is enabled in the config. (We could remove all these #ifdefs but that would mean extending inet_request_sock with 2 bytes even if tproxy is not enabled.)

There's a 2 byte hole with IPv6 where you could put this in. I think even without IPv6 the small waste is not worth the increased testing complexity.

Ok, I'll remove the ifdefs then and add loc_port in that hole. Thanks for your feedback.

Signature · 1 line
KOVACS Krisztian
#21 lore raw

PATCH 7/13 Export UDP socket lookup function

In reply to KOVACS Krisztian

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.

---

 include/net/udp.h |    4 ++++
 net/ipv4/udp.c    |    8 ++++++++
 2 files changed, 12 insertions(+), 0 deletions(-)
include/net/udp.h +4 -0
index 98755eb..3efae7d 100644
@@ -138,6 +138,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
net/ipv4/udp.c +8 -0
index 69d4bd1..2fb3b7c 100644
@@ -287,6 +287,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,
#22 lore raw

PATCH 8/13 Split Netfilter IPv4 defragmentation into a separate module

In reply to KOVACS Krisztian

Netfilter connection tracking requires all IPv4 packets to be defragmented. Both the socket match and the TPROXY target depend on this functionality, so this patch separates the Netfilter IPv4 defrag hooks into a separate module.

---

 include/net/netfilter/ipv4/nf_defrag_ipv4.h    |    6 ++
 net/ipv4/netfilter/Kconfig                     |    5 +
 net/ipv4/netfilter/Makefile                    |    3 +
 net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c |   55 +-------------
 net/ipv4/netfilter/nf_defrag_ipv4.c            |   94 ++++++++++++++++++++++++
 5 files changed, 110 insertions(+), 53 deletions(-)
include/net/netfilter/ipv4/nf_defrag_ipv4.h new file +6 -0
new file mode 100644
index 0000000..6b00ea3
@@ -0,0 +1,6 @@
+#ifndef _NF_DEFRAG_IPV4_H
+#define _NF_DEFRAG_IPV4_H
+
+extern void nf_defrag_ipv4_enable(void);
+
+#endif /* _NF_DEFRAG_IPV4_H */
net/ipv4/netfilter/Kconfig +5 -0
index fa97947..c9108de 100644
@@ -5,9 +5,14 @@
 menu "IP: Netfilter Configuration"
 	depends on INET && NETFILTER
 
+config NF_DEFRAG_IPV4
+	tristate
+	default n
+
 config NF_CONNTRACK_IPV4
 	tristate "IPv4 connection tracking support (required for NAT)"
 	depends on NF_CONNTRACK
+	select NF_DEFRAG_IPV4
 	---help---
 	  Connection tracking keeps a record of what packets have passed
 	  through your machine, in order to figure out how they are related
net/ipv4/netfilter/Makefile +3 -0
index 409d273..6504de5 100644
@@ -18,6 +18,9 @@ obj-$(CONFIG_NF_CONNTRACK_IPV4) += nf_conntrack_ipv4.o
 
 obj-$(CONFIG_NF_NAT) += nf_nat.o
 
+# defrag
+obj-$(CONFIG_NF_DEFRAG_IPV4) += nf_defrag_ipv4.o
+
 # NAT helpers (nf_conntrack)
 obj-$(CONFIG_NF_NAT_AMANDA) += nf_nat_amanda.o
 obj-$(CONFIG_NF_NAT_FTP) += nf_nat_ftp.o
net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +2 -53

91 lines not on this page · raw message

net/ipv4/netfilter/nf_defrag_ipv4.c new file +94 -0

94 lines not on this page · raw message

#23 lore raw

Re: [PATCH 08/13] Split Netfilter IPv4 defragmentation into a separate module

Quoted 6 lines · KOVACS Krisztian

Netfilter connection tracking requires all IPv4 packets to be defragmented. Both the socket match and the TPROXY target depend on this functionality, so this patch separates the Netfilter IPv4 defrag hooks into a separate module.

Mhh .. I don't like this too much, but I don't see a much better way myself, especially for the socket match since it can't do defragmentation itself.

#24 lore raw

PATCH 9/13 iptables tproxy core

In reply to KOVACS Krisztian

The iptables tproxy core is a module that contains the common routines used by various tproxy related modules (TPROXY target and socket match)

---

 include/net/netfilter/nf_tproxy_core.h |   32 +++++++++++
 net/netfilter/Kconfig                  |   10 +++
 net/netfilter/Makefile                 |    3 +
 net/netfilter/nf_tproxy_core.c         |   96 ++++++++++++++++++++++++++++++++
 4 files changed, 141 insertions(+), 0 deletions(-)
include/net/netfilter/nf_tproxy_core.h new file +32 -0
new file mode 100644
index 0000000..2fac3ad
@@ -0,0 +1,32 @@
+#ifndef _NF_TPROXY_CORE_H
+#define _NF_TPROXY_CORE_H
+
+#include <linux/types.h>
+#include <linux/in.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <net/inet_sock.h>
+#include <net/tcp.h>
+
+/* look up and get a reference to a matching socket */
+extern struct sock *
+nf_tproxy_get_sock_v4(const u8 protocol,
+		      const __be32 saddr, const __be32 daddr,
+		      const __be16 sport, const __be16 dport,
+		      const struct net_device *in, bool listening);
+
+static inline void
+nf_tproxy_put_sock(struct sock *sk)
+{
+	/* TIME_WAIT inet sockets have to be handled differently */
+	if ((sk->sk_protocol == IPPROTO_TCP) && (sk->sk_state == TCP_TIME_WAIT))
+		inet_twsk_put(inet_twsk(sk));
+	else
+		sock_put(sk);
+}
+
+/* assign a socket to the skb -- consumes sk */
+int
+nf_tproxy_assign_sock(struct sk_buff *skb, struct sock *sk);
+
+#endif
net/netfilter/Kconfig +10 -0
index 3599770..2187cca 100644
@@ -257,6 +257,16 @@ config NF_CT_NETLINK
 	help
 	  This option enables support for a netlink-based userspace interface
 
+# transparent proxy support
+config NETFILTER_TPROXY
+	tristate "Transparent proxying support"
+	depends on IP_NF_MANGLE
+	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.
+
 config NETFILTER_XTABLES
 	tristate "Netfilter Xtables support (required for ip_tables)"
 	help
net/netfilter/Makefile +3 -0
index 0c054bf..76e16ea 100644
@@ -34,6 +34,9 @@ obj-$(CONFIG_NF_CONNTRACK_SANE) += nf_conntrack_sane.o
 obj-$(CONFIG_NF_CONNTRACK_SIP) += nf_conntrack_sip.o
 obj-$(CONFIG_NF_CONNTRACK_TFTP) += nf_conntrack_tftp.o
 
+# transparent proxy support
+obj-$(CONFIG_NETFILTER_TPROXY) += nf_tproxy_core.o
+
 # generic X tables 
 obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o
 
net/netfilter/nf_tproxy_core.c new file +96 -0

96 lines not on this page · raw message

#25 lore raw

Re: [PATCH 09/13] iptables tproxy core

Quoted 4 lines · KOVACS Krisztian

The iptables tproxy core is a module that contains the common routines used by various tproxy related modules (TPROXY target and socket match)

Looks fine.

#26 lore raw

PATCH 10/13 iptables socket match

In reply to KOVACS Krisztian

Add iptables 'socket' match, which matches packets for which a TCP/UDP socket lookup succeeds.

---

 net/netfilter/Kconfig     |   12 ++++++
 net/netfilter/Makefile    |    1 +
 net/netfilter/xt_socket.c |   87 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 100 insertions(+), 0 deletions(-)
net/netfilter/Kconfig +12 -0
index 2187cca..899fdde 100644
@@ -632,6 +632,18 @@ config NETFILTER_XT_MATCH_SCTP
 	  If you want to compile it as a module, say M here and read
 	  <file:Documentation/kbuild/modules.txt>.  If unsure, say `N'.
 
+config NETFILTER_XT_MATCH_SOCKET
+	tristate '"socket" match support'
+	depends on NETFILTER_TPROXY
+	depends on NETFILTER_XTABLES
+	select NF_DEFRAG_IPV4
+	help
+	  This option adds a `socket' match, which can be used to match
+	  packets for which a TCP or UDP socket lookup finds a valid socket.
+	  It can only be used in the tproxy table.
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
 config NETFILTER_XT_MATCH_STATE
 	tristate '"state" match support'
 	depends on NETFILTER_XTABLES
net/netfilter/Makefile +1 -0
index 76e16ea..7d7dbd6 100644
@@ -73,6 +73,7 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_PKTTYPE) += xt_pkttype.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
+obj-$(CONFIG_NETFILTER_XT_MATCH_SOCKET) += xt_socket.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_STATE) += xt_state.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_STATISTIC) += xt_statistic.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_STRING) += xt_string.o
net/netfilter/xt_socket.c new file +87 -0

87 lines not on this page · raw message

#27 lore raw

Re: [PATCH 10/13] iptables socket match

Quoted 5 lines · KOVACS Krisztian

Add iptables 'socket' match, which matches packets for which a TCP/UDP socket lookup succeeds.

---

And here is the xt_socket that I had..

===
iptables socket match

From: KOVACS Krisztian <[email protected]>

Add iptables 'socket' match, which matches packets for which a TCP/UDP socket lookup succeeds.

---

 net/ipv4/netfilter/Kconfig |   10 +++++
 net/netfilter/Makefile     |    1 
 net/netfilter/xt_socket.c  |   80 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 91 insertions(+)
net/ipv4/netfilter/Kconfig +10 -0
Index: linux-2.6.22.1/net/ipv4/netfilter/Kconfig
===================================================================
@@ -414,6 +414,16 @@ config NETFILTER_XT_TARGET_TPROXY
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
+config NETFILTER_XT_MATCH_SOCKET
+	tristate "socket match support"
+	depends on IP_NF_TPROXY_TABLE
+	help
+	  This option adds a `socket' match, which can be used to match
+	  packets for which a TCP or UDP socket lookup finds a valid socket.
+	  It can only be used in the tproxy table.
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
 # ARP tables
 config IP_NF_ARPTABLES
 	tristate "ARP tables support"
net/netfilter/Makefile +1 -0
Index: linux-2.6.22.1/net/netfilter/Makefile
===================================================================
@@ -76,6 +76,7 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_PKTTYPE)
 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
+obj-$(CONFIG_NETFILTER_XT_MATCH_SOCKET) += xt_socket.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_STATE) += xt_state.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_STATISTIC) += xt_statistic.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_STRING) += xt_string.o
net/netfilter/xt_socket.c new file +80 -0

80 lines not on this page · raw message

#28 lore raw

Re: [PATCH 10/13] xt_socket

In reply to KOVACS Krisztian

Review

Quoted 4 lines · KOVACS Krisztian
(quoted diff) +4 -0
+
+	hp = skb_header_pointer(skb, iph->ihl * 4, sizeof(_hdr), &_hdr);
+	if (hp == NULL)
+		return false;

ip_hdrlen(skb) for 2nd arg.

Review

Quoted 3 lines
(quoted diff) +3 -0
+	pr_debug("socket match: proto %d %08x:%d -> %08x:%d sock %p\n",
+		 iph->protocol, ntohl(iph->saddr), ntohs(hp->source),
+		 ntohl(iph->daddr), ntohs(hp->dest), sk);

Should be %u.

Quoted 1 line

+static struct xt_match socket_matches[] = {

A single struct suffices.

Review

Quoted 3 lines
(quoted diff) +3 -0
+		.name		= "socket",
+		.family		= AF_INET,
+		.match		= match,

This goes against debugging. If everyone names their match function "match" (and it's done too often in netfilter and iptables-userspace already), it is hard to find out which is meant (e.g. in an oops). It also makes debugging quite impossible because setting a breakpoint will be ambiguous.

Find below a patch that makes me happy, and compiles. :)

===

Add the xt_socket match, which matches packets for which a TCP/UDP socket lookup succeeds.

(originally from: KOVACS Krisztian <[email protected]>)

A few cleanups.

---

 net/netfilter/Kconfig     |   12 +++++++
 net/netfilter/Makefile    |    1 
 net/netfilter/xt_socket.c |   76 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 89 insertions(+)
net/netfilter/Kconfig +12 -0
Index: linux-2.6.23/net/netfilter/Kconfig
===================================================================
@@ -632,6 +632,18 @@ config NETFILTER_XT_MATCH_SCTP
 	  If you want to compile it as a module, say M here and read
 	  <file:Documentation/kbuild/modules.txt>.  If unsure, say `N'.
 
+config NETFILTER_XT_MATCH_SOCKET
+	tristate '"socket" match support'
+	depends on NETFILTER_TPROXY
+	depends on NETFILTER_XTABLES
+	select NF_DEFRAG_IPV4
+	help
+	  This option adds a "socket" match, which can be used to match
+	  packets for which a TCP or UDP socket lookup finds a valid socket.
+	  It can only be used in the tproxy table.
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
 config NETFILTER_XT_MATCH_STATE
 	tristate '"state" match support'
 	depends on NETFILTER_XTABLES
net/netfilter/Makefile +1 -0
Index: linux-2.6.23/net/netfilter/Makefile
===================================================================
@@ -73,6 +73,7 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_PKTTYPE)
 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
+obj-$(CONFIG_NETFILTER_XT_MATCH_SOCKET) += xt_socket.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_STATE) += xt_state.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_STATISTIC) += xt_statistic.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_STRING) += xt_string.o
net/netfilter/xt_socket.c new file +76 -0

76 lines not on this page · raw message

#29 lore raw

PATCH 11/13 iptables TPROXY target

In reply to KOVACS Krisztian

The TPROXY target implements redirection of non-local TCP/UDP traffic to local sockets. Additionally, it's possible to manipulate the packet mark if and only if a socket has been found. (We need this because we cannot use multiple targets in the same iptables rule.)

---

 include/linux/netfilter_ipv4/ipt_TPROXY.h |   14 +++
 net/netfilter/Kconfig                     |   12 +++
 net/netfilter/Makefile                    |    1 
 net/netfilter/xt_TPROXY.c                 |  139 +++++++++++++++++++++++++++++
 4 files changed, 166 insertions(+), 0 deletions(-)
include/linux/netfilter_ipv4/ipt_TPROXY.h new file +14 -0
new file mode 100644
index 0000000..4a2dfa1
@@ -0,0 +1,14 @@
+#ifndef _IPT_TPROXY_H_target
+#define _IPT_TPROXY_H_target
+
+/* TPROXY target is capable of marking the packet to perform
+ * redirection. We can get rid of that whenever we get support for
+ * mutliple targets in the same rule. */
+struct ipt_tproxy_target_info {
+	__be32 laddr;
+	__be16 lport;
+	unsigned long mark_mask;
+	unsigned long mark_value;
+};
+
+#endif
net/netfilter/Kconfig +12 -0
index 899fdde..21e39eb 100644
@@ -363,6 +363,18 @@ config NETFILTER_XT_TARGET_NOTRACK
 	  If you want to compile it as a module, say M here and read
 	  <file:Documentation/kbuild/modules.txt>.  If unsure, say `N'.
 
+config NETFILTER_XT_TARGET_TPROXY
+	tristate "TPROXY target support"
+	depends on NETFILTER_TPROXY
+	depends on NETFILTER_XTABLES
+	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.
+
 config NETFILTER_XT_TARGET_TRACE
 	tristate  '"TRACE" target support'
 	depends on NETFILTER_XTABLES
net/netfilter/Makefile +1 -0
index 7d7dbd6..0684e2b 100644
@@ -50,6 +50,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_NFLOG) += xt_NFLOG.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_NOTRACK) += xt_NOTRACK.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_TRACE) += xt_TRACE.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_SECMARK) += xt_SECMARK.o
+obj-$(CONFIG_NETFILTER_XT_TARGET_TPROXY) += xt_TPROXY.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_TCPMSS) += xt_TCPMSS.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o
 
net/netfilter/xt_TPROXY.c new file +139 -0

139 lines not on this page · raw message

#30 lore raw

Re: [PATCH 11/13] xtables TPROXY target

Quoted 4 lines · KOVACS Krisztian

The TPROXY target implements redirection of non-local TCP/UDP traffic to local sockets. Additionally, it's possible to manipulate the packet mark if and only if a socket has been found. (We need this because we cannot use multiple targets in the same iptables rule.)

This provides xt_TPROXY.

===
iptables TPROXY target

From: KOVACS Krisztian <[email protected]>

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.

---

 include/linux/netfilter/xt_TPROXY.h |    9 ++++
 net/ipv4/netfilter/Kconfig          |   11 +++++
 net/netfilter/Makefile              |    1 
 net/netfilter/xt_TPROXY.c           |   76 ++++++++++++++++++++++++++++++++++++
 4 files changed, 97 insertions(+)
include/linux/netfilter/xt_TPROXY.h new file +9 -0
Index: linux-2.6.22.1/include/linux/netfilter/xt_TPROXY.h
===================================================================
@@ -0,0 +1,9 @@
+#ifndef _XT_TPROXY_H
+#define _XT_TPROXY_H
+
+struct xt_tproxy_info {
+	u_int32_t laddr;
+	u_int16_t lport;
+};
+
+#endif /* _XT_TPROXY_H */
net/ipv4/netfilter/Kconfig +11 -0
Index: linux-2.6.22.1/net/ipv4/netfilter/Kconfig
===================================================================
@@ -403,6 +403,17 @@ config IP_NF_TPROXY_TABLE
 
 	  To compile it as a module, choose M here.  If unsure, say `N'.
 
+config NETFILTER_XT_TARGET_TPROXY
+	tristate "TPROXY target support"
+	depends on IP_NF_TPROXY_TABLE
+	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"
net/netfilter/Makefile +1 -0
Index: linux-2.6.22.1/net/netfilter/Makefile
===================================================================
@@ -50,6 +50,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_TRACE) 
 obj-$(CONFIG_NETFILTER_XT_TARGET_SECMARK) += xt_SECMARK.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_TARPIT) += xt_TARPIT.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_TCPMSS) += xt_TCPMSS.o
+obj-$(CONFIG_NETFILTER_XT_TARGET_TPROXY) += xt_TPROXY.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o
 
 # matches
net/netfilter/xt_TPROXY.c new file +76 -0

76 lines not on this page · raw message

#31 lore raw

Re: [PATCH 11/13] xtables TPROXY target

Hi Jan,

Quoted 18 lines · Jan Engelhardt
net/netfilter/xt_TPROXY.c new file +18 -0
+static unsigned int
+tproxy_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 xt_tproxy_info *tgi = targinfo;
+	const struct iphdr *iph = ip_hdr(*pskb);
+	struct sk_buff *skb = *pskb;
+	struct udphdr _hdr, *hp;
+
+	/* 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;
+

net/netfilter/xt_TPROXY.c line 50

Quoted 10 lines
net/netfilter/xt_TPROXY.c new file +10 -0
+	skb->nf_tproxy.redirect_address = tgi->laddr ? : iph->daddr;
+	skb->nf_tproxy.redirect_port    = tgi->lport ? : hp->dest;
+
+	pr_debug(KERN_DEBUG "redirecting: proto %d %08x:%d -> %08x:%d\n",
+	         iph->protocol, ntohl(iph->daddr), ntohs(hp->dest),
+	         ntohl(skb->nf_tproxy.redirect_address),
+	         ntohs(skb->nf_tproxy.redirect_port));
+
+	return NF_ACCEPT;
+}

I guess this is also an old version, the current one does not look like this. Are you sure this is really up-to-date?

Signature · 1 line
 KOVACS Krisztian
#32 lore raw

Re: [PATCH 11/13] xt_TPROXY

In reply to KOVACS Krisztian

Review

Quoted 6 lines · KOVACS Krisztian
(quoted diff) +6 -0
+struct ipt_tproxy_target_info {
+	__be32 laddr;
+	__be16 lport;
+	unsigned long mark_mask;
+	unsigned long mark_value;
+};

Cannot use unsigned long, as its size is not fixed.

(other nitpicks that were already in xt_socket)

Review

Quoted 5 lines
(quoted diff) +5 -0
+	/* NOTE: assign_sock consumes our sk reference */
+	if (sk && nf_tproxy_assign_sock(skb, sk)) {
+		/* This should be in a separate target, but we don't do multiple
+		   targets on the same rule yet */
+		skb->mark = (skb->mark & ~tgi->mark_mask) ^ tgi->mark_value;

I guess you mean | instead of ^ here.

Review

Quoted 8 lines
(quoted diff) +8 -0
+#ifdef CONFIG_COMPAT
+struct compat_ipt_tproxy_target_info {
+	__be32 laddr;
+	__be16 lport;
+	__be16 __pad1;
+	compat_ulong_t mark_mask;
+	compat_ulong_t mark_value;
+};

Uhm, that's a bit cumbersome. By reordering, we can get all the alignment done without any premature compat code.

Find below a patch that makes me happy, and compiles. :)

[ xtification comes at no cost, even if it's ipv4-only.
Although it is just a guess, I suppose xt_ is going to replace ipt_ and ip6t_ even if some matches/targets are not all-protocol ]

===

The TPROXY target implements redirection of non-local TCP/UDP traffic to local sockets. Additionally, it's possible to manipulate the packet mark if and only if a socket has been found. (We need this because we cannot use multiple targets in the same iptables rule.)

(originally from: KOVACS Krisztian <[email protected]>)

A few cleanups and fixes.

---

 include/linux/netfilter/xt_TPROXY.h |   16 ++++++
 net/netfilter/Kconfig               |   12 ++++
 net/netfilter/Makefile              |    1 
 net/netfilter/xt_TPROXY.c           |   92 ++++++++++++++++++++++++++++++++++++
 4 files changed, 121 insertions(+)
include/linux/netfilter/xt_TPROXY.h new file +16 -0
Index: linux-2.6.23/include/linux/netfilter/xt_TPROXY.h
===================================================================
@@ -0,0 +1,16 @@
+#ifndef _XT_TPROXY_H
+#define _XT_TPROXY_H
+
+/*
+ * TPROXY target is capable of marking the packet to perform
+ * redirection. We can get rid of that whenever we get support for
+ * mutliple targets in the same rule.
+ */
+struct xt_tproxy_info {
+	u_int32_t mark_mask;
+	u_int32_t mark_value;
+	__be32 laddr;
+	__be16 lport;
+};
+
+#endif /* _XT_TPROXY_H */
net/netfilter/Kconfig +12 -0
Index: linux-2.6.23/net/netfilter/Kconfig
===================================================================
@@ -363,6 +363,18 @@ config NETFILTER_XT_TARGET_NOTRACK
 	  If you want to compile it as a module, say M here and read
 	  <file:Documentation/kbuild/modules.txt>.  If unsure, say `N'.
 
+config NETFILTER_XT_TARGET_TPROXY
+	tristate '"TPROXY" target support'
+	depends on NETFILTER_TPROXY
+	depends on NETFILTER_XTABLES
+	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.
+
 config NETFILTER_XT_TARGET_TRACE
 	tristate  '"TRACE" target support'
 	depends on NETFILTER_XTABLES
net/netfilter/Makefile +1 -0
Index: linux-2.6.23/net/netfilter/Makefile
===================================================================
@@ -50,6 +50,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_NFLOG) 
 obj-$(CONFIG_NETFILTER_XT_TARGET_NOTRACK) += xt_NOTRACK.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_TRACE) += xt_TRACE.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_SECMARK) += xt_SECMARK.o
+obj-$(CONFIG_NETFILTER_XT_TARGET_TPROXY) += xt_TPROXY.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_TCPMSS) += xt_TCPMSS.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o
 
net/netfilter/xt_TPROXY.c new file +92 -0

92 lines not on this page · raw message

#33 lore raw

Re: [PATCH 11/13] xt_TPROXY

Quoted 13 lines · Jan Engelhardt

include/linux/netfilter/xt_TPROXY.h line 14

Quoted 6 lines · KOVACS Krisztian
include/linux/netfilter/xt_TPROXY.h new file +6 -0
+struct ipt_tproxy_target_info {
+	__be32 laddr;
+	__be16 lport;
+	unsigned long mark_mask;
+	unsigned long mark_value;
+};

Cannot use unsigned long, as its size is not fixed.

(other nitpicks that were already in xt_socket)

Quoted 7 lines

Review

Quoted 5 lines
(quoted diff) +5 -0
+	/* NOTE: assign_sock consumes our sk reference */
+	if (sk && nf_tproxy_assign_sock(skb, sk)) {
+		/* This should be in a separate target, but we don't do multiple
+		   targets on the same rule yet */
+		skb->mark = (skb->mark & ~tgi->mark_mask) ^ tgi->mark_value;

I guess you mean | instead of ^ here.

No, ^ is intentional. The idea is that in addition to being able to _set_ the masked part of the mark to a given value, you can also flip other bits of the mark with the unmasked parts of the value. So it has slightly more expressive power, and does the right thing if you use it in a 'conventional' way.

Quoted 12 lines

Review

Quoted 9 lines
(quoted diff) +8 -0
+#ifdef CONFIG_COMPAT
+struct compat_ipt_tproxy_target_info {
+	__be32 laddr;
+	__be16 lport;
+	__be16 __pad1;
+	compat_ulong_t mark_mask;
+	compat_ulong_t mark_value;
+};

Uhm, that's a bit cumbersome. By reordering, we can get all the alignment done without any premature compat code.

Yes, given that we can go back to using 32 bit marks.

Quoted 185 lines

Find below a patch that makes me happy, and compiles. :)

[ xtification comes at no cost, even if it's ipv4-only.
Although it is just a guess, I suppose xt_ is going to replace ipt_ and ip6t_ even if some matches/targets are not all-protocol ]

===

The TPROXY target implements redirection of non-local TCP/UDP traffic to local sockets. Additionally, it's possible to manipulate the packet mark if and only if a socket has been found. (We need this because we cannot use multiple targets in the same iptables rule.)

(originally from: KOVACS Krisztian <[email protected]>)

A few cleanups and fixes.

---

 include/linux/netfilter/xt_TPROXY.h |   16 ++++++
 net/netfilter/Kconfig               |   12 ++++
 net/netfilter/Makefile              |    1
 net/netfilter/xt_TPROXY.c           |   92

++++++++++++++++++++++++++++++++++++ 4 files changed, 121 insertions(+)

Index: linux-2.6.23/include/linux/netfilter/xt_TPROXY.h
===================================================================

include/linux/netfilter/xt_TPROXY.h new file +16 -0
@@ -0,0 +1,16 @@
+#ifndef _XT_TPROXY_H
+#define _XT_TPROXY_H
+
+/*
+ * TPROXY target is capable of marking the packet to perform
+ * redirection. We can get rid of that whenever we get support for
+ * mutliple targets in the same rule.
+ */
+struct xt_tproxy_info {
+	u_int32_t mark_mask;
+	u_int32_t mark_value;
+	__be32 laddr;
+	__be16 lport;
+};
+
+#endif /* _XT_TPROXY_H */

Index: linux-2.6.23/net/netfilter/Kconfig
===================================================================

net/netfilter/Kconfig +12 -0
@@ -363,6 +363,18 @@ config NETFILTER_XT_TARGET_NOTRACK
 	  If you want to compile it as a module, say M here and read
 	  <file:Documentation/kbuild/modules.txt>.  If unsure, say `N'.
 
+config NETFILTER_XT_TARGET_TPROXY
+	tristate '"TPROXY" target support'
+	depends on NETFILTER_TPROXY
+	depends on NETFILTER_XTABLES
+	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.
+
 config NETFILTER_XT_TARGET_TRACE
 	tristate  '"TRACE" target support'
 	depends on NETFILTER_XTABLES

Index: linux-2.6.23/net/netfilter/Makefile
===================================================================

net/netfilter/Makefile +1 -0
@@ -50,6 +50,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_NFLOG)
 obj-$(CONFIG_NETFILTER_XT_TARGET_NOTRACK) += xt_NOTRACK.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_TRACE) += xt_TRACE.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_SECMARK) += xt_SECMARK.o
+obj-$(CONFIG_NETFILTER_XT_TARGET_TPROXY) += xt_TPROXY.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_TCPMSS) += xt_TCPMSS.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o
 

Index: linux-2.6.23/net/netfilter/xt_TPROXY.c
===================================================================

net/netfilter/xt_TPROXY.c new file +7 -0
@@ -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.
+ *
+ */

net/netfilter/xt_TPROXY.c new file +49 -0
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ip.h>
+#include <net/checksum.h>
+#include <net/inet_sock.h>
+#include <net/udp.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_TPROXY.h>
+#include <net/netfilter/ipv4/nf_defrag_ipv4.h>
+#include <net/netfilter/nf_tproxy_core.h>
+
+static unsigned int
+tproxy_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 xt_tproxy_info *tgi = targinfo;
+	const struct iphdr *iph = ip_hdr(*pskb);
+	struct sk_buff *skb = *pskb;
+	struct udphdr _hdr, *hp;
+	struct sock *sk;
+
+	/* TCP/UDP only */
+	if (iph->protocol != IPPROTO_TCP && iph->protocol != IPPROTO_UDP)
+		return NF_ACCEPT;
+
+	hp = skb_header_pointer(*pskb, ip_hdrlen(skb), sizeof(_hdr), &_hdr);
+	if (hp == NULL)
+		return NF_DROP;
+
+	sk = nf_tproxy_get_sock_v4(iph->protocol, iph->saddr,
+	     tgi->laddr ? tgi->laddr : iph->daddr, hp->source,
+	     tgi->lport ? tgi->lport : hp->dest, in, true);
+
+	/* NOTE: assign_sock consumes our sk reference */
+	if (sk != NULL && nf_tproxy_assign_sock(skb, sk) != 0) {
+		/*
+		 * This should be in a separate target, but we do not do
+		 * multiple targets on the same rule yet.
+		 */
+		skb->mark = (skb->mark & ~tgi->mark_mask) | tgi->mark_value;
+
+		pr_debug("redirecting: proto %u %08x:%u -> %08x:%u, mark: %x\n",
+		         iph->protocol, ntohl(iph->daddr), ntohs(hp->dest),
+		         ntohl(tgi->laddr), ntohs(tgi->lport), skb->mark);
+		return NF_ACCEPT;
+	}
+
+	pr_debug("no socket, dropping: proto %u %08x:%u -> %08x:%u, mark:

%x\n", + iph->protocol, ntohl(iph->daddr), ntohs(hp->dest),

net/netfilter/xt_TPROXY.c new file +29 -0
+	         ntohl(tgi->laddr), ntohs(tgi->lport), skb->mark);
+	return NF_DROP;
+}
+
+static struct xt_target xt_tproxy_reg = {
+	.name       = "TPROXY",
+	.family     = AF_INET,
+	.table      = "mangle",
+	.target     = tproxy_target,
+	.targetsize = sizeof(struct xt_tproxy_info),
+	.hooks      = 1 << NF_IP_PRE_ROUTING,
+	.me         = THIS_MODULE,
+};
+
+static int __init xt_tproxy_init(void)
+{
+	nf_defrag_ipv4_enable();
+	return xt_register_target(&xt_tproxy_reg);
+}
+
+static void __exit xt_tproxy_exit(void)
+{
+	xt_unregister_target(&xt_tproxy_reg);
+}
+
+module_init(xt_tproxy_init);
+module_exit(xt_tproxy_exit);
+MODULE_AUTHOR("Krisztian Kovacs");
+MODULE_DESCRIPTION("Netfilter transparent proxy (TPROXY) target

module"); +MODULE_LICENSE("GPL");

net/netfilter/xt_TPROXY.c new file +1 -1
+MODULE_ALIAS("ipt_TPROXY");
-

To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

Signature · 1 line
 KOVACS Krisztian
#34 lore raw

Re: [PATCH 11/13] iptables TPROXY target

In reply to KOVACS Krisztian
Quoted 11 lines · KOVACS Krisztian

The TPROXY target implements redirection of non-local TCP/UDP traffic to local sockets. Additionally, it's possible to manipulate the packet mark if and only if a socket has been found. (We need this because we cannot use multiple targets in the same iptables rule.)

---
+++ b/include/linux/netfilter_ipv4/ipt_TPROXY.h

include/linux/netfilter_ipv4/ipt_TPROXY.h new file +1 -0
@@ -0,0 +1,14 @@
+#ifndef _IPT_TPROXY_H_target

include/linux/netfilter_ipv4/ipt_TPROXY.h line 11

Quoted 10 lines
include/linux/netfilter_ipv4/ipt_TPROXY.h new file +10 -0
+#define _IPT_TPROXY_H_target
+
+/* TPROXY target is capable of marking the packet to perform
+ * redirection. We can get rid of that whenever we get support for
+ * mutliple targets in the same rule. */
+struct ipt_tproxy_target_info {
+	__be32 laddr;
+	__be16 lport;
+	unsigned long mark_mask;
+	unsigned long mark_value;

This should use fixed size types.

Quoted 71 lines
net/netfilter/xt_TPROXY.c new file +64 -0
new file mode 100644
index 0000000..8603421
@@ -0,0 +1,139 @@
+/*
+ * 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/x_tables.h>
+#include <linux/netfilter_ipv4/ipt_TPROXY.h>
+
+#include <net/netfilter/ipv4/nf_defrag_ipv4.h>
+#include <net/netfilter/nf_tproxy_core.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 = ip_hdr(*pskb);
+	const struct ipt_tproxy_target_info *tgi =
+		(const struct ipt_tproxy_target_info *) targinfo;
+	struct sk_buff *skb = *pskb;
+	struct udphdr _hdr, *hp;
+	struct sock *sk;
+
+	/* 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;
+
+	sk = nf_tproxy_get_sock_v4(iph->protocol,
+				   iph->saddr, tgi->laddr ? tgi->laddr : iph->daddr,
+				   hp->source, tgi->lport ? tgi->lport : hp->dest,
+				   in, true);
 
+
+	/* NOTE: assign_sock consumes our sk reference */
+	if (sk && nf_tproxy_assign_sock(skb, sk)) {
+		/* This should be in a separate target, but we don't do multiple
+		   targets on the same rule yet */
+		skb->mark = (skb->mark & ~tgi->mark_mask) ^ tgi->mark_value;
+
+		pr_debug("redirecting: proto %d %08x:%d -> %08x:%d, mark: %x\n",
+			 iph->protocol, ntohl(iph->daddr), ntohs(hp->dest),
+			 ntohl(tgi->laddr), ntohs(tgi->lport), skb->mark);
+		return NF_ACCEPT;

net/netfilter/xt_TPROXY.c line 74

Quoted 10 lines
net/netfilter/xt_TPROXY.c new file +10 -0
+	}
+	else {
+		pr_debug("no socket, dropping: proto %d %08x:%d -> %08x:%d, mark: %x\n",
+			 iph->protocol, ntohl(iph->daddr), ntohs(hp->dest),
+			 ntohl(tgi->laddr), ntohs(tgi->lport), skb->mark);
+		return NF_DROP;
+	}
+}
+
+#ifdef CONFIG_COMPAT

All this compat stuff becomes unnecessary with fixed size types.

#35 lore raw

Re: [PATCH 11/13] iptables TPROXY target

Quoted 2 lines · Patrick McHardy

All this compat stuff becomes unnecessary with fixed size types.

Fixed size types alone won't do it. Think 64-bit. You would have {32, 16, 32, 32}, and I would be pretty sure they pad it up to {32, 16, [16], 32, 32}. Well, see my version, which avoids that :)

#36 lore raw

Re: [PATCH 11/13] iptables TPROXY target

In reply to Patrick McHardy

Hi Patrick,

Quoted 15 lines · Patrick McHardy
Quoted 14 lines · KOVACS Krisztian

The TPROXY target implements redirection of non-local TCP/UDP traffic to local sockets. Additionally, it's possible to manipulate the packet mark if and only if a socket has been found. (We need this because we cannot use multiple targets in the same iptables rule.)

---
+++ b/include/linux/netfilter_ipv4/ipt_TPROXY.h

include/linux/netfilter_ipv4/ipt_TPROXY.h new file +5 -0
@@ -0,0 +1,14 @@
+#ifndef _IPT_TPROXY_H_target
+#define _IPT_TPROXY_H_target
+
+/* TPROXY target is capable of marking the packet to perform
+ * redirection. We can get rid of that whenever we get support for
Quoted 8 lines

include/linux/netfilter_ipv4/ipt_TPROXY.h line 11

Quoted 6 lines
include/linux/netfilter_ipv4/ipt_TPROXY.h new file +6 -0
+ * mutliple targets in the same rule. */
+struct ipt_tproxy_target_info {
+	__be32 laddr;
+	__be16 lport;
+	unsigned long mark_mask;
+	unsigned long mark_value;

This should use fixed size types.

Yes, but marks are unsigned longs, aren't they? So if we restrict this to say 32bit then we lose the ability to use the upper half of the mark...

Quoted 83 lines
Quoted 75 lines
net/netfilter/xt_TPROXY.c new file +7 -0
new file mode 100644
index 0000000..8603421
@@ -0,0 +1,139 @@
+/*
+ * 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.
+ *
+ */

net/netfilter/xt_TPROXY.c new file +56 -0
+
+#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/x_tables.h>
+#include <linux/netfilter_ipv4/ipt_TPROXY.h>
+
+#include <net/netfilter/ipv4/nf_defrag_ipv4.h>
+#include <net/netfilter/nf_tproxy_core.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 = ip_hdr(*pskb);
+	const struct ipt_tproxy_target_info *tgi =
+		(const struct ipt_tproxy_target_info *) targinfo;
+	struct sk_buff *skb = *pskb;
+	struct udphdr _hdr, *hp;
+	struct sock *sk;
+
+	/* 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;
+
+	sk = nf_tproxy_get_sock_v4(iph->protocol,
+				   iph->saddr, tgi->laddr ? tgi->laddr : iph->daddr,
+				   hp->source, tgi->lport ? tgi->lport : hp->dest,
+				   in, true);
 
+
+	/* NOTE: assign_sock consumes our sk reference */
+	if (sk && nf_tproxy_assign_sock(skb, sk)) {
+		/* This should be in a separate target, but we don't do multiple
+		   targets on the same rule yet */
+		skb->mark = (skb->mark & ~tgi->mark_mask) ^ tgi->mark_value;
+
+		pr_debug("redirecting: proto %d %08x:%d -> %08x:%d, mark: %x\n",
+			 iph->protocol, ntohl(iph->daddr), ntohs(hp->dest),
+			 ntohl(tgi->laddr), ntohs(tgi->lport), skb->mark);
+		return NF_ACCEPT;
+	}
+	else {
+		pr_debug("no socket, dropping: proto %d %08x:%d -> %08x:%d, mark:

%x\n", + iph->protocol, ntohl(iph->daddr), ntohs(hp->dest),

net/netfilter/xt_TPROXY.c line 74

Quoted 6 lines
net/netfilter/xt_TPROXY.c new file +6 -0
+			 ntohl(tgi->laddr), ntohs(tgi->lport), skb->mark);
+		return NF_DROP;
+	}
+}
+
+#ifdef CONFIG_COMPAT

All this compat stuff becomes unnecessary with fixed size types.

Signature · 1 line
 KOVACS Krisztian
#37 lore raw

Re: [PATCH 11/13] iptables TPROXY target

Quoted 11 lines · KOVACS Krisztian
Quoted 10 lines

include/linux/netfilter_ipv4/ipt_TPROXY.h line 11

Quoted 8 lines
include/linux/netfilter_ipv4/ipt_TPROXY.h new file +8 -0
+/* TPROXY target is capable of marking the packet to perform
+ * redirection. We can get rid of that whenever we get support for
+ * mutliple targets in the same rule. */
+struct ipt_tproxy_target_info {
+	__be32 laddr;
+	__be16 lport;
+	unsigned long mark_mask;
+	unsigned long mark_value;

This should use fixed size types.

Quoted 2 lines

Yes, but marks are unsigned longs, aren't they? So if we restrict this to say 32bit then we lose the ability to use the upper half of the mark...

longs are 32 and 64 bits, resp. A 64-bit kernel with a 32-bit userland, well it speaks for itself.

The more I am puzzled as to why xt_MARK.h, xt_mark.h, xt_CONNMARK.h, xt_connmark.h use longs, and not uint32_t! Only xt_SECMARK.h does it right...

Patrick, is this a longstanding 'bug'?

#38 lore raw

Re: [PATCH 11/13] iptables TPROXY target

Quoted 17 lines · Jan Engelhardt
Quoted 11 lines · KOVACS Krisztian
Quoted 10 lines

include/linux/netfilter_ipv4/ipt_TPROXY.h line 11

Quoted 8 lines
include/linux/netfilter_ipv4/ipt_TPROXY.h new file +8 -0
+/* TPROXY target is capable of marking the packet to perform
+ * redirection. We can get rid of that whenever we get support for
+ * mutliple targets in the same rule. */
+struct ipt_tproxy_target_info {
+	__be32 laddr;
+	__be16 lport;
+	unsigned long mark_mask;
+	unsigned long mark_value;

This should use fixed size types.

Quoted 2 lines

Yes, but marks are unsigned longs, aren't they? So if we restrict this to say 32bit then we lose the ability to use the upper half of the mark...

Quoted 7 lines

longs are 32 and 64 bits, resp. A 64-bit kernel with a 32-bit userland, well it speaks for itself.

The more I am puzzled as to why xt_MARK.h, xt_mark.h, xt_CONNMARK.h, xt_connmark.h use longs, and not uint32_t! Only xt_SECMARK.h does it right...

Patrick, is this a longstanding 'bug'?

Not a bug, compatiblity crap. skb->nfmark used to be unsigned long, but since a) it sucks to have userspace-visible stuff like this depend on the architecture and b) routing, classifiers etc. all only supported 32 bits, we've changed it.

#39 lore raw

Re: [PATCH 11/13] iptables TPROXY target

In reply to KOVACS Krisztian
Quoted 30 lines · KOVACS Krisztian

Hi Patrick,

Quoted 16 lines · Patrick McHardy
Quoted 14 lines · KOVACS Krisztian

The TPROXY target implements redirection of non-local TCP/UDP traffic to local sockets. Additionally, it's possible to manipulate the packet mark if and only if a socket has been found. (We need this because we cannot use multiple targets in the same iptables rule.)

---
+++ b/include/linux/netfilter_ipv4/ipt_TPROXY.h

include/linux/netfilter_ipv4/ipt_TPROXY.h new file +5 -0
@@ -0,0 +1,14 @@
+#ifndef _IPT_TPROXY_H_target
+#define _IPT_TPROXY_H_target
+
+/* TPROXY target is capable of marking the packet to perform
+ * redirection. We can get rid of that whenever we get support for
Quoted 9 lines

include/linux/netfilter_ipv4/ipt_TPROXY.h line 11

Quoted 7 lines
include/linux/netfilter_ipv4/ipt_TPROXY.h new file +6 -0
+ * mutliple targets in the same rule. */
+struct ipt_tproxy_target_info {
+	__be32 laddr;
+	__be16 lport;
+	unsigned long mark_mask;
+	unsigned long mark_value;

This should use fixed size types.

Quoted 2 lines

Yes, but marks are unsigned longs, aren't they? So if we restrict this to say 32bit then we lose the ability to use the upper half of the mark...

No, marks are 32 bit for a long time now. The unsigned longs in the mark target and matches are just there for compatiblity.

(BTW, going to sleep now, will continue tommorrow)

#40 lore raw

Re: [PATCH 11/13] iptables TPROXY target

Hi Patrick,

Quoted 29 lines · Patrick McHardy
Quoted 28 lines · KOVACS Krisztian

Hi Patrick,

Quoted 24 lines · Patrick McHardy
Quoted 11 lines · KOVACS Krisztian

The TPROXY target implements redirection of non-local TCP/UDP traffic to local sockets. Additionally, it's possible to manipulate the packet mark if and only if a socket has been found. (We need this because we cannot use multiple targets in the same iptables rule.)

---
+++ b/include/linux/netfilter_ipv4/ipt_TPROXY.h

include/linux/netfilter_ipv4/ipt_TPROXY.h new file +1 -0
@@ -0,0 +1,14 @@
+#ifndef _IPT_TPROXY_H_target

include/linux/netfilter_ipv4/ipt_TPROXY.h line 11

Quoted 10 lines
include/linux/netfilter_ipv4/ipt_TPROXY.h new file +10 -0
+#define _IPT_TPROXY_H_target
+
+/* TPROXY target is capable of marking the packet to perform
+ * redirection. We can get rid of that whenever we get support for
+ * mutliple targets in the same rule. */
+struct ipt_tproxy_target_info {
+	__be32 laddr;
+	__be16 lport;
+	unsigned long mark_mask;
+	unsigned long mark_value;

This should use fixed size types.

Quoted 6 lines
Quoted 3 lines

Yes, but marks are unsigned longs, aren't they? So if we restrict this to say 32bit then we lose the ability to use the upper half of the mark...

No, marks are 32 bit for a long time now. The unsigned longs in the mark target and matches are just there for compatiblity.

Indeed, I must have missed this. Obviously if this is the case then we don't need all this cruft and can simply use 32 bit mark fields (and the reordered info structure Jan suggested.)

Quoted 1 line

(BTW, going to sleep now, will continue tommorrow)

OK, me too. :)

Signature · 1 line
 KOVACS Krisztian
#41 lore raw

PATCH 12/13 Don't lookup the socket if there's a socket attached to the skb

In reply to KOVACS Krisztian

Use the socket cached in the TPROXY target if it's present.

---

 net/ipv4/tcp_ipv4.c |    8 ++++++++
 1 files changed, 8 insertions(+), 0 deletions(-)
net/ipv4/tcp_ipv4.c +8 -0
index 7ae47e6..7ebf1c7 100644
@@ -1658,6 +1658,14 @@ int tcp_v4_rcv(struct sk_buff *skb)
 	TCP_SKB_CB(skb)->flags	 = iph->tos;
 	TCP_SKB_CB(skb)->sacked	 = 0;
 
+#if defined(CONFIG_IP_NF_TPROXY) || defined (CONFIG_IP_NF_TPROXY_MODULE)
+	if (unlikely(skb->sk)) {
+		/* steal reference */
+		sk = skb->sk;
+		skb->destructor = NULL;
+		skb->sk = NULL;
+	} else
+#endif
 	sk = __inet_lookup(&tcp_hashinfo, iph->saddr, th->source,
 			   iph->daddr, th->dest, inet_iif(skb));
 	if (!sk)
#42 lore raw

PATCH 13/13 Don't lookup the socket if there's a socket attached to the skb

In reply to KOVACS Krisztian

Use the socket cached in the TPROXY target if it's present.

---

 net/ipv4/udp.c |    8 ++++++++
 1 files changed, 8 insertions(+), 0 deletions(-)
net/ipv4/udp.c +8 -0
index 2fb3b7c..2bdf034 100644
@@ -1151,6 +1151,14 @@ 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);
 
+#if defined(CONFIG_IP_NF_TPROXY) || defined (CONFIG_IP_NF_TPROXY_MODULE)
+	if (unlikely(skb->sk)) {
+		/* steal reference */
+		sk = skb->sk;
+		skb->destructor = NULL;
+		skb->sk = NULL;
+	} else
+#endif
 	sk = __udp4_lib_lookup(saddr, uh->source, daddr, uh->dest,
 			       skb->dev->ifindex, udptable        );
 
#43 lore raw
In reply to KOVACS Krisztian
Quoted 74 lines · KOVACS Krisztian

Hi Patrick,

These patches are our (Balazs, Attila and me) third try at providing Linux 2.2-like transparent proxying support for Linux 2.6. During the 5th Netfilter Workshop in Karlsruhe, Germany we tried to come up with an even more lightweight approach not requiring the modification of the IPv4 routing code at all.

The most important changes relative to the previous versions[1,2] are:
* the tproxy table is gone, TPROXY targets need to be added to the mangle table instead
* the tproxy match is gone, a new "socket" match is introduced
* instead of using a separate routing trick to divert packets to the local IP stack inside the TProxy target, we are now using stock routing decisions, and need a bit in the packet MARK field, and perform diversion by using an advanced routing rule (this hopefully makes it possible to implement IPv6 support in the future
* instead of IP_FREEBIND we are using a setsockopt named IP_TRANSPARENT which requires CAP_NET_ADMIN privilege
* in previous patches the output routing decision was commented out, it is now correctly decided whether a packet belongs to a tproxied connection or not.

Usage is a bit more complicated compared to the previous approach, but it's certainly not rocket science:

# iptables rules necessary:
# create a chain named DIVERT
iptables -t mangle -N DIVERT
# everything that matches "-m socket" should go to the local stack
iptables -t mangle -A PREROUTING -p tcp -m socket -j DIVERT
# connections to be redirected should use the TPROXY target, which sets # up redirection, and marks the packet according to its 'tproxy-mark' # argument
iptables -t mangle -A PREROUTING -p tcp --dport 80 -j TPROXY \
   --tproxy-mark 0x1/0x1 --on-port 50080
# DIVERT chain: mark packets and accept
iptables -t mangle -A DIVERT -j MARK --set-mark 1
iptables -t mangle -A DIVERT -j ACCEPT
# set up advanced routing rules to deliver our marked packets locally
ip rule add fwmark 1 lookup 100
ip route add local 0.0.0.0/0 dev lo table 100

The proxy code needs to be modified as well, but these are really lightweight:
before binding, the IP_TRANSPARENT sockopt needs to be enabled on the socket. This implies IP_FREEBIND, so after enabling this socket option non-local binds will work and if you got your iptables/iproute setup right non-local traffic will be delivered to/from the socket. A netcat patch demonstrating this is available[4] as an example.

Some word about the patches:

* output path (patches 1-5): these modifications make it possible to output IPv4 datagrams with non-local IP addresses by:
- introducing a new flowi flag (FLOWI_FLAG_ANYSRC) which disables the source address check in ip_route_output_slow() [3]
- adding the IP_TRANSPARENT socket option (setting this requires CAP_NET_ADMIN)
- setting FLOWI_FLAG_ANYSRC if IP_TRANSPARENT is enabled for the originating socket
- set FLOWI_FLAG_ANYSRC where appropriate for sending reply packets generated by the kernel; this requires extending the ip_reply_arg structure with a flags field and adding an IP_REPLY_ARG_NOSRCCHECK flag

* input patch (patches 6-13): these changes implement redirection support for TCP plus the iptables socket match and TPROXY target -- these provide the actual user interface:
- split IPv4 defragmentation into a separate module, as this is needed by both our target and match
- add a 'socket' match which does a socket lookup based on the destination tuple in the packet and matches is a socket has been found
- add a 'TPROXY' target which looks up a socket based on a modified IP/port tuple and stores the socket reference in the skb
- modifying the TCP/UDP input paths to use the stored socket reference if present

Quoted 4 lines

All kinds of comments welcome. Patrick, I'd like to ask you to review these patches and if no issues are found by you or by anyone on the list, please consider merging them.

Thanks for posting these patches. I'll gladly review them, but the patches touching things outside of netfilter need to go through netdev and Dave for merging.

#44 lore raw

Hi Patrick,

Quoted 3 lines · Patrick McHardy

Thanks for posting these patches. I'll gladly review them, but the patches touching things outside of netfilter need to go through netdev and Dave for merging.

Thanks a lot. I guess getting feedback from you and the list is very important -- we absolutely would like to hammer out as many problems as possible before posting to netdev/Dave. Not to mention the Netfilter specific parts... :)

Signature · 1 line
 KOVACS Krisztian