Skip to contentSkip to conversation

Transparent Proxying Patches, Take 4

PATCH In review KOVACS Krisztian 3 participants 19 messages Oct 2, 2007 – Oct 23, 2007

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

cover Transparent Proxying Patches, Take 4

Hi Patrick,

Here's the next round of tproxy patches, hopefully fixing problems which came up last time I've posted these patches[1].

I'd like to thank you and Jan Engelhardt the huge help you've provided. (Jan himself did a lot of fixes/cleanups!)

The most important changes relative to the previous versions[1] are:

* the patch implementing the propagation of IP_TRANSPARENT to routing output now does not change the signature of request_sock_opt.send_ack but uses a flag in inet_request_sock itself
* TCP port redirection support patch
adds loc_port to struct inet_request_sock unconditionally
* TPROXY target is an xt_* target now and has proper 32 bit mark values in the target info structure

Additionally there are code cleanups all over the place (thanks Jan).

References:
[1] http://marc.info/?l=netfilter-devel&m=119118672703285&w=2

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;
+		}
 	}
 
 
#2 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;
#3 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

#4 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)
#5 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/inet_sock.h         |    8 +++++++-
 include/net/ip.h                |    9 +++++++++
 net/ipv4/inet_connection_sock.c |    1 +
 net/ipv4/ip_output.c            |    4 +++-
 net/ipv4/syncookies.c           |    1 +
 net/ipv4/tcp_ipv4.c             |   11 ++++++++---
 6 files changed, 29 insertions(+), 5 deletions(-)
include/net/inet_sock.h +7 -1
index e86832d..517efe7 100644
@@ -72,7 +72,8 @@ struct inet_request_sock {
 				sack_ok	   : 1,
 				wscale_ok  : 1,
 				ecn_ok	   : 1,
-				acked	   : 1;
+				acked	   : 1,
+				no_srccheck: 1;
 	struct ip_options	*opt;
 };
 
@@ -191,4 +192,9 @@ static inline int inet_sk_ehashfn(const struct sock *sk)
 	return inet_ehashfn(laddr, lport, faddr, fport);
 }
 
+static inline __u8 inet_sk_flowi_flags(const struct sock *sk)
+{
+	return inet_sk(sk)->transparent ? FLOWI_FLAG_ANYSRC : 0;
+}
+
 #endif	/* _INET_SOCK_H */
include/net/ip.h +9 -0
index abf2820..fa85f2f 100644
@@ -29,6 +29,7 @@
 
 #include <net/inet_sock.h>
 #include <net/snmp.h>
+#include <net/flow.h>
 
 struct sock;
 
@@ -140,12 +141,20 @@ static inline void ip_tr_mc_map(__be32 addr, char *buf)
 
 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 */ 
 	int	    bound_dev_if;
 }; 
 
+#define IP_REPLY_ARG_NOSRCCHECK 1
+
+static inline __u8 ip_reply_arg_flowi_flags(const struct ip_reply_arg *arg)
+{
+	return (arg->flags & IP_REPLY_ARG_NOSRCCHECK) ? FLOWI_FLAG_ANYSRC : 0;
+}
+
 void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *arg,
 		   unsigned int len); 
 
net/ipv4/inet_connection_sock.c +1 -0
index fbe7714..5c93359 100644
@@ -321,6 +321,7 @@ 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_flowi_flags(sk),
 			    .uli_u = { .ports =
 				       { .sport = inet_sk(sk)->sport,
 					 .dport = ireq->rmt_port } } };
net/ipv4/ip_output.c +3 -1
index 0f1d7be..9fa376f 100644
@@ -322,6 +322,7 @@ int ip_queue_xmit(struct sk_buff *skb, int ipfragok)
 							.saddr = inet->saddr,
 							.tos = RT_CONN_FLAGS(sk) } },
 					    .proto = sk->sk_protocol,
+					    .flags = inet_sk_flowi_flags(sk),
 					    .uli_u = { .ports =
 						       { .sport = inet->sport,
 							 .dport = inet->dport } } };
@@ -1364,7 +1365,8 @@ 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 = ip_reply_arg_flowi_flags(arg) };
 		security_skb_classify_flow(skb, &fl);
 		if (ip_route_output_key(&rt, &fl))
 			return;
net/ipv4/syncookies.c +1 -0
index 2da1be0..a0f6fdb 100644
@@ -260,6 +260,7 @@ 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_flowi_flags(sk),
 				    .uli_u = { .ports =
 					       { .sport = th->dest,
 						 .dport = th->source } } };
net/ipv4/tcp_ipv4.c +8 -3
index e089a97..12d3831 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,6 +702,7 @@ 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);
@@ -720,7 +722,8 @@ static void tcp_v4_timewait_ack(struct sock *sk, struct sk_buff *skb)
 
 	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,
+			tw->tw_transparent ? IP_REPLY_ARG_NOSRCCHECK : 0);
 
 	inet_twsk_put(tw);
 }
@@ -730,7 +733,8 @@ static void tcp_v4_reqsk_send_ack(struct sk_buff *skb,
 {
 	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,
+			inet_rsk(req)->no_srccheck ? IP_REPLY_ARG_NOSRCCHECK : 0);
 }
 
 /*
@@ -1332,6 +1336,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
 	ireq = inet_rsk(req);
 	ireq->loc_addr = daddr;
 	ireq->rmt_addr = saddr;
+	ireq->no_srccheck = inet_sk(sk)->transparent;
 	ireq->opt = tcp_v4_save_options(sk, skb);
 	if (!want_cookie)
 		TCP_ECN_create_request(req, tcp_hdr(skb));
#6 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         |    2 +-
 include/net/tcp.h               |    1 +
 net/ipv4/inet_connection_sock.c |    2 ++
 net/ipv4/syncookies.c           |    1 +
 net/ipv4/tcp_output.c           |    2 +-
 5 files changed, 6 insertions(+), 2 deletions(-)
include/net/inet_sock.h +1 -1
index 517efe7..d7e2a52 100644
@@ -61,8 +61,8 @@ struct inet_request_sock {
 	struct request_sock	req;
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 	u16			inet6_rsk_offset;
-	/* 2 bytes hole, try to pack */
 #endif
+	__be16			loc_port;
 	__be32			loc_addr;
 	__be32			rmt_addr;
 	__be16			rmt_port;
include/net/tcp.h +1 -0
index 54053de..6271023 100644
@@ -980,6 +980,7 @@ static inline void tcp_openreq_init(struct request_sock *req,
 	ireq->acked = 0;
 	ireq->ecn_ok = 0;
 	ireq->rmt_port = tcp_hdr(skb)->source;
+	ireq->loc_port = tcp_hdr(skb)->dest;
 }
 
 extern void tcp_enter_memory_pressure(void);
net/ipv4/inet_connection_sock.c +2 -0
index 5c93359..43c37bf 100644
@@ -501,6 +501,8 @@ struct sock *inet_csk_clone(struct sock *sk, const struct request_sock *req,
 		newicsk->icsk_bind_hash = NULL;
 
 		inet_sk(newsk)->dport = inet_rsk(req)->rmt_port;
+		inet_sk(newsk)->num = ntohs(inet_rsk(req)->loc_port);
+		inet_sk(newsk)->sport = inet_rsk(req)->loc_port;
 		newsk->sk_write_space = sk_stream_write_space;
 
 		newicsk->icsk_retransmits = 0;
net/ipv4/syncookies.c +1 -0
index a0f6fdb..6e84243 100644
@@ -223,6 +223,7 @@ 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;
+	ireq->loc_port		= th->dest;
 	ireq->rmt_port		= th->source;
 	ireq->loc_addr		= ip_hdr(skb)->daddr;
 	ireq->rmt_addr		= ip_hdr(skb)->saddr;
net/ipv4/tcp_output.c +1 -1
index 666d8a5..06f26af 100644
@@ -2153,7 +2153,7 @@ struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst,
 	th->syn = 1;
 	th->ack = 1;
 	TCP_ECN_make_synack(req, th);
-	th->source = inet_sk(sk)->sport;
+	th->source = ireq->loc_port;
 	th->dest = ireq->rmt_port;
 	TCP_SKB_CB(skb)->seq = tcp_rsk(req)->snt_isn;
 	TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(skb)->seq + 1;
#7 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,
#8 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

#9 lore raw

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

net/ipv4/netfilter/nf_defrag_ipv4.c line 89

Quoted 4 lines · KOVACS Krisztian
net/ipv4/netfilter/nf_defrag_ipv4.c new file +4 -0
+void nf_defrag_ipv4_enable(void)
+{
+}
+EXPORT_SYMBOL(nf_defrag_ipv4_enable);

A bit pointless for this function, but I'd prefer
EXPORT_SYMBOL_GPL for consistenty :)

#10 lore raw

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

In reply to KOVACS Krisztian

Hello,

Quoted 3 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.

With this patch taken from:
http://people.netfilter.org/hidden/tproxy/tproxy4-2.6.23-200710090922.tar.bz2
with:
# CONFIG_NF_CONNTRACK_ENABLED is not set
# CONFIG_NF_CONNTRACK is not set

I get:

net/ipv4/netfilter/nf_defrag_ipv4.c: In function 'ipv4_conntrack_defrag':
net/ipv4/netfilter/nf_defrag_ipv4.c:44: error: 'struct sk_buff' has no member named 'nfct' make[3]: *** [net/ipv4/netfilter/nf_defrag_ipv4.o] Error 1
make[2]: *** [net/ipv4/netfilter] Error 2
make[1]: *** [net/ipv4] Error 2

This is not a surprise since:
--- cut here ---

#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
        struct nf_conntrack     *nfct;
        struct sk_buff          *nfct_reasm;

#endif
--- cut here ---

Best regards,

Krzysztof Olędzki

#11 lore raw

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

Hi Krzysztof,

Quoted 22 lines · Krzysztof Oledzki
Quoted 4 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.

With this patch taken from:

http://people.netfilter.org/hidden/tproxy/tproxy4-2.6.23-200710090922.t
ar.bz2 with:
# CONFIG_NF_CONNTRACK_ENABLED is not set
# CONFIG_NF_CONNTRACK is not set

I get:

net/ipv4/netfilter/nf_defrag_ipv4.c: In function 'ipv4_conntrack_defrag': net/ipv4/netfilter/nf_defrag_ipv4.c:44: error:
'struct sk_buff' has no member named 'nfct' make[3]: *** [net/ipv4/netfilter/nf_defrag_ipv4.o] Error 1
make[2]: *** [net/ipv4/netfilter] Error 2
make[1]: *** [net/ipv4] Error 2

Quoted 7 lines

This is not a surprise since:
--- cut here ---

#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
         struct nf_conntrack     *nfct;
         struct sk_buff          *nfct_reasm;

#endif
--- cut here ---

Thanks for spotting this, indeed, this was an oversight from my part... The latest tree at http://people.netfilter.org/hidden/tproxy/ should fix this compilation problem.

Signature · 1 line
KOVACS Krisztian
#12 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

#13 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 |   83 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 96 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 +83 -0

83 lines not on this page · raw message

#14 lore raw

Re: [PATCH 10/13] iptables socket match

net/netfilter/Kconfig config NETFILTER_XT_MATCH_SCTP · line 638

Quoted 4 lines · KOVACS Krisztian
net/netfilter/Kconfig +4 -0
+config NETFILTER_XT_MATCH_SOCKET
+	tristate '"socket" match support'
+	depends on NETFILTER_TPROXY
+	depends on NETFILTER_XTABLES

EXPERIMENTAL please.

Quoted 7 lines
net/netfilter/xt_socket.c new file +7 -0
+static bool
+socket_match(const struct sk_buff *skb,
+	     const struct net_device *in,
+	     const struct net_device *out,
+	     const struct xt_match *match,
+	     const void *matchinfo,
+	     int offset,

net/netfilter/xt_socket.c line 39

Quoted 10 lines
net/netfilter/xt_socket.c new file +10 -0
+	     unsigned int protoff,
+	     bool *hotdrop)
+{
+	const struct iphdr *iph = ip_hdr(skb);
+	struct udphdr _hdr, *hp;
+	struct sock *sk;
+
+	/* TCP/UDP only */
+	if (iph->protocol != IPPROTO_TCP && iph->protocol != IPPROTO_UDP)
+		return false;

How about making sure that its only used in a -p udp or -p tcp rule in ->checkentry() instead?

#15 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/xt_TPROXY.h |   14 +++++
 net/netfilter/Kconfig               |   13 +++++
 net/netfilter/Makefile              |    1 
 net/netfilter/xt_TPROXY.c           |   97 +++++++++++++++++++++++++++++++++++
 4 files changed, 125 insertions(+), 0 deletions(-)
include/linux/netfilter/xt_TPROXY.h new file +14 -0
new file mode 100644
index 0000000..152e8f9
@@ -0,0 +1,14 @@
+#ifndef _XT_TPROXY_H_target
+#define _XT_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 xt_tproxy_target_info {
+	u_int32_t mark_mask;
+	u_int32_t mark_value;
+	__be32 laddr;
+	__be16 lport;
+};
+
+#endif /* _XT_TPROXY_H_target */
net/netfilter/Kconfig +13 -0
index 899fdde..441e46f 100644
@@ -363,6 +363,19 @@ 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
+	select NF_DEFRAG_IPV4
+	help
+	  This option adds a `TPROXY' target, which is somewhat similar to
+	  REDIRECT.  It can only be used in the mangle table and is useful
+	  to redirect traffic to a transparent proxy.  It does _not_ depend
+	  on Netfilter connection tracking and NAT, unlike REDIRECT.
+
+	  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 +97 -0

97 lines not on this page · raw message

#16 lore raw

Re: [PATCH 11/13] iptables 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.)

Same suggestions as for the socket match (EXPERIMENTAL and TCP/UDP check in ->checkentry).

#17 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 12d3831..f3e3c5e 100644
@@ -1661,6 +1661,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_NETFILTER_TPROXY) || defined (CONFIG_NETFILTER_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)
#18 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..d1fefb6 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_NETFILTER_TPROXY) || defined (CONFIG_NETFILTER_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        );