Updated TPROXY patch - squid-2.5-cttproxy-04JES.diff

From: James MacLean <macleajb@dont-contact.us>
Date: Sat, 10 Apr 2004 11:06:09 -0300 (ADT)

Hi folks,

This applies to squid-2.5.STABLE5 and adds support for Squid transparent
proxy support via http://www.balabit.com/downloads/tproxy/linux-2.4/devel/

It is based on the work of Gianni Tedesco, and changed with the help of
KOVACS Krisztian.

I have been using it to redirect traffic from two sites successfully, but
can not comment on how well it will scale :).

The intention of these patches is to proxy squid requests to servers with
the client IP as the source. Normally it is Squid's IP that is the source
of all requests.

I am not on the dev list.

Enjoy,
JES

--
These are patches based on the work of: 
Gianni Tedesco <gianni at scaramanga dot co dot uk>
and updated with the help of and many thanks to :
KOVACS Krisztian <hidden at balabit dot hu>
This patch adds a new onoff config "linux_tproxy" (if you configure with
 --enable-linux-tproxy) which, when set, will spoof the source address of
outgoing server connections to be the same as the original client
address. It now also works with persistent sever connections. To take
advantage of this code you need Linux 2.4/2.6 with netfilter enabled and the
TPROXY patches installed from:
        http://www.balabit.com/downloads/tproxy/linux-2.4/devel/
There are two small nits with the code:
 1. You must supply a tcp_outgoing_address in your squid.conf, this is
    because of some deep magic in the Linux TCP/IP stack.
 2. Squid must run as root in order to do the connection spoofing bits.
    For me (JES) this meant setting :
    cache_effective_user root root
    cache_effective_group root
NOTES:
 . You do not need to add any iptable rules to make this part work in the Linux Kernel.
 . You still need to "-j REDIRECT 3128" to get initial packets to squid. (Or use tproxy
   reidrect method - see examples in cttproxy README)
 . In squid.conf add :
   linux_tproxy on
   tcp_outgoing_address <outgoing address>
 . You do have to run autoconf to add --enable-linux-tproxy to configure.
 . Example configure:
   ./configure \
   --prefix=/usr/local/squid \
   --enable-linux-netfilter \
   --enable-linux-tproxy \
   --enable-async-io \
   --disable-http-violations \
   --enable-underscores \
   --disable-hostname-checks \
   --enable-ntlm-auth-helpers=SMB \
   --enable-auth=ntlm \
   --enable-basic-auth-helpers=NCSA \
   --enable-storeio=ufs,aufs,diskd \
   --enable-err-languages="English French"
TODO:
  o Port all changes to cvs HEAD branch.
  o Attempt to fix connect(2) problem in kernel which requires bind(2) to
    local address. (JES - did not investigate if this still stands).
  o Hack kernel space code so squid does not need to run as root.
--
JES <macleajb at ednet dot ns dot ca>
--- squid-2.5.STABLE5/acconfig.h	2002-07-01 05:55:11.000000000 -0300
+++ squid-2.5.STABLE5-tproxy/acconfig.h	2004-03-15 10:45:59.000000000 -0400
@@ -331,6 +331,11 @@
  */
 #undef LINUX_NETFILTER
 
+/* 
+ * Enable real Transparent Proxy support for Netfilter TPROXY.
+ */
+#undef LINUX_TPROXY
+
 /*
  * Do we have unix sockets? (required for the winbind ntlm helper
  */
--- squid-2.5.STABLE5/configure.in	2004-02-29 18:30:21.000000000 -0400
+++ squid-2.5.STABLE5-tproxy/configure.in	2004-03-15 10:45:59.000000000 -0400
@@ -739,6 +739,17 @@
   fi
 ])
 
+dnl Enable Linux transparent proxy support
+AC_ARG_ENABLE(linux-tproxy,
+[  --enable-linux-tproxy
+                          Enable real Transparent Proxy support for Netfilter TPROXY.],
+[ if test "$enableval" = "yes" ; then
+	echo "Linux Netfilter/TPROXY enabled"
+	AC_DEFINE(LINUX_TPROXY)
+	LINUX_TPROXY="yes"
+  fi
+])
+
 AM_CONDITIONAL(MAKE_LEAKFINDER, false)
 dnl Enable Leak Finding Functions
 AC_ARG_ENABLE(leakfinder,
@@ -1181,6 +1192,7 @@
 	libc.h \
 	limits.h \
 	linux/netfilter_ipv4.h \
+	linux/netfilter_ipv4/ip_tproxy.h \
 	malloc.h \
 	math.h \
 	memory.h \
@@ -1814,6 +1826,27 @@
     sleep 10
 fi
 
+dnl Linux Netfilter/TPROXY support requires some specific header files
+dnl Shamelessly copied from shamelessly copied from above
+if test "$LINUX_TPROXY" ; then
+    AC_MSG_CHECKING(if TPROXY header files are installed)
+    # hold on to your hats...
+    if test "$ac_cv_header_linux_netfilter_ipv4_ip_tproxy_h" = "yes"; then
+        LINUX_TPROXY="yes"
+        AC_DEFINE(LINUX_TPROXY, 1)
+    else
+        LINUX_TPROXY="no"
+        AC_DEFINE(LINUX_TPROXY, 0)
+    fi
+    AC_MSG_RESULT($LINUX_TPROXY)
+fi
+if test "$LINUX_TPROXY" = "no" ; then
+    echo "WARNING: Cannot find TPROXY headers, you need to install the"
+    echo "tproxy package from:"
+    echo " - lynx http://www.balabit.com/downloads/tproxy/linux-2.4/"
+    sleep 10
+fi
+
 if test -z "$USE_GNUREGEX" ; then
     case "$host" in
     *-sun-solaris2.[[0-4]])
--- squid-2.5.STABLE5/include/autoconf.h.in	2003-01-17 21:46:33.000000000 -0400
+++ squid-2.5.STABLE5-tproxy/include/autoconf.h.in	2004-03-15 10:45:59.000000000 -0400
@@ -350,6 +350,11 @@
  */
 #undef LINUX_NETFILTER
 
+/* 
+ * Enable real Transparent Proxy support for Netfilter TPROXY.
+ */
+#undef LINUX_TPROXY
+
 /*
  * Do we have unix sockets? (required for the winbind ntlm helper
  */
@@ -648,6 +653,9 @@
 /* Define if you have the <linux/netfilter_ipv4.h> header file.  */
 #undef HAVE_LINUX_NETFILTER_IPV4_H
 
+/* Define if you have the <linux/netfilter_ipv4/ip_tproxy.h> header file.  */
+#undef HAVE_LINUX_NETFILTER_IPV4_IP_TPROXY_H
+
 /* Define if you have the <malloc.h> header file.  */
 #undef HAVE_MALLOC_H
 
--- squid-2.5.STABLE5/src/cf.data.pre	2004-02-10 17:01:21.000000000 -0400
+++ squid-2.5.STABLE5-tproxy/src/cf.data.pre	2004-03-15 10:45:59.000000000 -0400
@@ -3960,4 +3960,20 @@
 	until all the child processes have been started.
 DOC_END
 
+NAME: linux_tproxy
+IFDEF: LINUX_TPROXY
+COMMENT: on|off
+TYPE: onoff
+LOC: Config.onoff.linux_tproxy
+DEFAULT: off
+DOC_START
+	If you have Linux 2.4 with netfilter and TPROXY support and you
+	have compiled squid with the correct options then you can enable
+	this option to allow squid to spoof the source address of
+	outgoing connections to servers so that they see connections from
+	the original client IP addresses. Enable this only if you know
+	what you are doing. You will need to set a valid
+	tcp_outgoing_address.
+DOC_END
+
 EOF
--- squid-2.5.STABLE5/src/client_side.c	2004-02-18 14:51:16.000000000 -0400
+++ squid-2.5.STABLE5-tproxy/src/client_side.c	2004-03-15 10:45:59.000000000 -0400
@@ -353,6 +353,7 @@
 	new_request->http_ver = old_request->http_ver;
 	httpHeaderAppend(&new_request->header, &old_request->header);
 	new_request->client_addr = old_request->client_addr;
+	new_request->client_port = old_request->client_port;
 	new_request->my_addr = old_request->my_addr;
 	new_request->my_port = old_request->my_port;
 	new_request->flags.redirected = 1;
@@ -3073,6 +3074,7 @@
 	    safe_free(http->log_uri);
 	    http->log_uri = xstrdup(urlCanonicalClean(request));
 	    request->client_addr = conn->peer.sin_addr;
+	    request->client_port = conn->peer.sin_port;
 	    request->my_addr = conn->me.sin_addr;
 	    request->my_port = ntohs(conn->me.sin_port);
 	    request->http_ver = http->http_ver;
--- squid-2.5.STABLE5/src/forward.c	2004-02-18 09:44:55.000000000 -0400
+++ squid-2.5.STABLE5-tproxy/src/forward.c	2004-04-09 13:23:26.281275096 -0300
@@ -36,6 +36,13 @@
 
 #include "squid.h"
 
+#if LINUX_NETFILTER
+#include <linux/netfilter_ipv4.h>
+#endif
+#if LINUX_TPROXY
+#include <linux/netfilter_ipv4/ip_tproxy.h>
+#endif
+
 static PSC fwdStartComplete;
 static void fwdDispatch(FwdState *);
 static void fwdConnectStart(void *);	/* should be same as EVH */
@@ -361,6 +368,14 @@
     int ftimeout = Config.Timeout.forward - (squid_curtime - fwdState->start);
     struct in_addr outgoing;
     unsigned short tos;
+    struct in_addr *local=NULL;
+#if LINUX_TPROXY
+    struct in_tproxy itp;
+
+    if ( Config.onoff.linux_tproxy )
+        local=&fwdState->src.sin_addr;
+#endif
+
     assert(fs);
     assert(fwdState->server_fd == -1);
     debug(17, 3) ("fwdConnectStart: %s\n", url);
@@ -383,7 +398,7 @@
 	ftimeout = 5;
     if (ftimeout < ctimeout)
 	ctimeout = ftimeout;
-    if ((fd = pconnPop(host, port)) >= 0) {
+    if ((fd = pconnPop(host, port, local)) >= 0) {
 	if (fwdCheckRetriable(fwdState)) {
 	    debug(17, 3) ("fwdConnectStart: reusing pconn FD %d\n", fd);
 	    fwdState->server_fd = fd;
@@ -444,6 +459,34 @@
 	ctimeout,
 	fwdConnectTimeout,
 	fwdState);
+#if LINUX_TPROXY
+    if ( Config.onoff.linux_tproxy ) {
+        itp.v.addr.faddr.s_addr = fwdState->src.sin_addr.s_addr;
+	itp.v.addr.fport = 0;
+
+        /* If these syscalls fail then we just fallback to connecting
+         * normally by simply ignoring the errors...
+         */
+	itp.op = TPROXY_ASSIGN;
+  	if (setsockopt(fd, SOL_IP, IP_TPROXY, &itp, sizeof(itp)) == -1)
+    	{
+		debug(20, 1)("tproxy ip=%s,0x%x,port=%d ERROR ASSIGN\n",
+			inet_ntoa(itp.v.addr.faddr),
+			itp.v.addr.faddr.s_addr,
+			itp.v.addr.fport);
+    	} else {
+
+		itp.op = TPROXY_FLAGS;
+		itp.v.flags = ITP_CONNECT;
+		if (setsockopt(fd, SOL_IP, IP_TPROXY, &itp, sizeof(itp)) == -1)
+		{
+			debug(20, 1)("tproxy ip=%x,port=%d ERROR CONNECT\n",
+				itp.v.addr.faddr.s_addr,
+				itp.v.addr.fport);
+		}
+	}
+    }
+#endif
     commConnectStart(fd, host, port, fwdConnectDone, fwdState);
 }
 
@@ -658,6 +701,15 @@
     fwdState->server_fd = -1;
     fwdState->request = requestLink(r);
     fwdState->start = squid_curtime;
+
+#if LINUX_TPROXY
+    /* If we need to transparently proxy the request
+     * then we need the client source address and port */
+    fwdState->src.sin_family = AF_INET;
+    fwdState->src.sin_addr = r->client_addr;
+    fwdState->src.sin_port = r->client_port;
+#endif
+    
     storeLockObject(e);
     EBIT_SET(e->flags, ENTRY_FWD_HDR_WAIT);
     storeRegisterAbort(e, fwdAbort, fwdState);
--- squid-2.5.STABLE5/src/http.c	2004-01-30 19:09:12.000000000 -0400
+++ squid-2.5.STABLE5-tproxy/src/http.c	2004-03-15 10:45:59.000000000 -0400
@@ -556,6 +556,7 @@
     int bin;
     int clen;
     size_t read_sz;
+    struct in_addr *local=NULL;
 #if DELAY_POOLS
     delay_id delay_id;
 
@@ -565,6 +566,12 @@
     else
 	delay_id = delayMostBytesAllowed(entry->mem_obj);
 #endif
+
+#if LINUX_TPROXY
+    if ( Config.onoff.linux_tproxy )
+        local=&httpState->request->client_addr;
+#endif
+
     if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
 	comm_close(fd);
 	return;
@@ -671,7 +678,7 @@
 #endif
 	    comm_remove_close_handler(fd, httpStateFree, httpState);
 	    fwdUnregister(fd, httpState->fwd);
-	    pconnPush(fd, request->host, request->port);
+	    pconnPush(fd, request->host, request->port, local);
 	    fwdComplete(httpState->fwd);
 	    httpState->fd = -1;
 	    httpStateFree(fd, httpState);
--- squid-2.5.STABLE5/src/main.c	2003-12-17 17:10:30.000000000 -0400
+++ squid-2.5.STABLE5-tproxy/src/main.c	2004-03-15 10:45:59.000000000 -0400
@@ -430,6 +430,16 @@
 #ifdef _SQUID_OS2_
     return;
 #endif
+
+    /* Transparent proxy support requires squid to run as root which
+     * kinda sucks. I will look towards implementing a solution in
+     * kernel space to combat this, perhaps a sysctl to set a certain
+     * GID to be able to use the TPROXY stuff */
+#if LINUX_TPROXY
+    if ( Config.onoff.linux_tproxy )
+        return;
+#endif
+
     if (geteuid() == 0) {
 	debug(0, 0) ("Squid is not safe to run as root!  If you must\n");
 	debug(0, 0) ("start Squid as root, then you must configure\n");
--- squid-2.5.STABLE5/src/pconn.c	2003-12-15 19:38:43.000000000 -0400
+++ squid-2.5.STABLE5-tproxy/src/pconn.c	2004-03-15 10:45:59.000000000 -0400
@@ -49,7 +49,6 @@
 
 static PF pconnRead;
 static PF pconnTimeout;
-static const char *pconnKey(const char *host, u_short port);
 static hash_table *table = NULL;
 static struct _pconn *pconnNew(const char *key);
 static void pconnDelete(struct _pconn *p);
@@ -58,12 +57,17 @@
 static MemPool *pconn_data_pool = NULL;
 static MemPool *pconn_fds_pool = NULL;
 
-static const char *
-pconnKey(const char *host, u_short port)
+#define PCONN_KEYLEN (SQUIDHOSTNAMELEN + 24)
+
+static inline const int
+pconnKey(char *buf, const char *peer, u_short port, struct in_addr *local)
 {
-    LOCAL_ARRAY(char, buf, SQUIDHOSTNAMELEN + 10);
-    snprintf(buf, SQUIDHOSTNAMELEN + 10, "%s.%d", host, (int) port);
-    return buf;
+    if ( local == NULL ) {
+        return snprintf(buf, PCONN_KEYLEN, "%s.%d", peer, (int) port);
+    }else{
+        return snprintf(buf, PCONN_KEYLEN, "%s.%d.%s",
+		peer, (int) port, inet_ntoa(*local));
+    }
 }
 
 static struct _pconn *
@@ -184,11 +188,11 @@
 }
 
 void
-pconnPush(int fd, const char *host, u_short port)
+pconnPush(int fd, const char *peer, u_short port, struct in_addr *local)
 {
     struct _pconn *p;
     int *old;
-    LOCAL_ARRAY(char, key, SQUIDHOSTNAMELEN + 10);
+    LOCAL_ARRAY(char, key, PCONN_KEYLEN);
     LOCAL_ARRAY(char, desc, FD_DESC_SZ);
     if (fdUsageHigh()) {
 	debug(48, 3) ("pconnPush: Not many unused FDs\n");
@@ -199,7 +203,7 @@
 	return;
     }
     assert(table != NULL);
-    strcpy(key, pconnKey(host, port));
+    pconnKey(key, peer, port, local);
     p = (struct _pconn *) hash_lookup(table, key);
     if (p == NULL)
 	p = pconnNew(key);
@@ -217,20 +221,20 @@
     p->fds[p->nfds++] = fd;
     commSetSelect(fd, COMM_SELECT_READ, pconnRead, p, 0);
     commSetTimeout(fd, Config.Timeout.pconn, pconnTimeout, p);
-    snprintf(desc, FD_DESC_SZ, "%s idle connection", host);
+    snprintf(desc, FD_DESC_SZ, "%s idle connection", peer);
     fd_note(fd, desc);
     debug(48, 3) ("pconnPush: pushed FD %d for %s\n", fd, key);
 }
 
 int
-pconnPop(const char *host, u_short port)
+pconnPop(const char *peer, u_short port, struct in_addr *local)
 {
     struct _pconn *p;
     hash_link *hptr;
     int fd = -1;
-    LOCAL_ARRAY(char, key, SQUIDHOSTNAMELEN + 10);
+    LOCAL_ARRAY(char, key, PCONN_KEYLEN);
     assert(table != NULL);
-    strcpy(key, pconnKey(host, port));
+    pconnKey(key, peer, port, local);
     hptr = hash_lookup(table, key);
     if (hptr != NULL) {
 	p = (struct _pconn *) hptr;
--- squid-2.5.STABLE5/src/protos.h	2004-02-04 13:42:28.000000000 -0400
+++ squid-2.5.STABLE5-tproxy/src/protos.h	2004-03-15 10:45:59.000000000 -0400
@@ -1139,8 +1139,8 @@
 extern int errorReservePageId(const char *page_name);
 extern ErrorState *errorCon(err_type type, http_status);
 
-extern void pconnPush(int, const char *host, u_short port);
-extern int pconnPop(const char *host, u_short port);
+extern void pconnPush(int, const char *peer, u_short port, struct in_addr *local);
+extern int pconnPop(const char *peer, u_short port, struct in_addr *local);
 extern void pconnInit(void);
 
 extern int asnMatchIp(void *, struct in_addr);
--- squid-2.5.STABLE5/src/structs.h	2004-02-04 13:42:28.000000000 -0400
+++ squid-2.5.STABLE5-tproxy/src/structs.h	2004-03-15 10:47:09.000000000 -0400
@@ -594,6 +594,9 @@
 	int pipeline_prefetch;
 	int request_entities;
 	int detect_broken_server_pconns;
+#if LINUX_NETFILTER
+        int linux_tproxy;
+#endif
     } onoff;
     acl *aclList;
     struct {
@@ -1656,6 +1659,7 @@
     int imslen;
     int max_forwards;
     /* these in_addr's could probably be sockaddr_in's */
+    in_port_t client_port;
     struct in_addr client_addr;
     struct in_addr my_addr;
     unsigned short my_port;
@@ -1974,6 +1978,9 @@
 	unsigned int dont_retry:1;
 	unsigned int ftp_pasv_failed:1;
     } flags;
+#if LINUX_NETFILTER
+    struct sockaddr_in src;
+#endif
 };
 
 #if USE_HTCP
     

Received on Mon Apr 12 2004 - 09:22:34 MDT

This archive was generated by hypermail pre-2.1.9 : Thu Apr 29 2004 - 12:00:03 MDT