diff -urN squid-3.0-DEVEL-20030310/configure.in squid-3.0-DEVEL-tproxy/configure.in --- squid-3.0-DEVEL-20030310/configure.in 2003-03-10 01:11:12.000000000 +0000 +++ squid-3.0-DEVEL-tproxy/configure.in 2003-03-12 15:26:01.000000000 +0000 @@ -880,6 +880,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 +]) + dnl Enable Large file support AC_ARG_ENABLE(large-files, [ --enable-large-files Enable support for large files (>2GB). Still @@ -1435,6 +1446,7 @@ utime.h \ varargs.h \ byteswap.h \ + linux/netfilter_ipv4/ip_tproxy.h \ glib.h \ stdint.h \ inttypes.h \ @@ -2031,6 +2043,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]]) diff -urN squid-3.0-DEVEL-20030310/src/cf.data.pre squid-3.0-DEVEL-tproxy/src/cf.data.pre --- squid-3.0-DEVEL-20030310/src/cf.data.pre 2003-02-22 14:59:33.000000000 +0000 +++ squid-3.0-DEVEL-tproxy/src/cf.data.pre 2003-03-12 15:27:16.000000000 +0000 @@ -4096,4 +4096,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 diff -urN squid-3.0-DEVEL-20030310/src/client_side.cc squid-3.0-DEVEL-tproxy/src/client_side.cc --- squid-3.0-DEVEL-20030310/src/client_side.cc 2003-03-07 04:40:59.000000000 +0000 +++ squid-3.0-DEVEL-tproxy/src/client_side.cc 2003-03-12 15:27:57.000000000 +0000 @@ -2086,6 +2086,7 @@ request->flags.internal = http->flags.internal; setLogUri (http, 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; diff -urN squid-3.0-DEVEL-20030310/src/forward.cc squid-3.0-DEVEL-tproxy/src/forward.cc --- squid-3.0-DEVEL-20030310/src/forward.cc 2003-03-02 23:13:49.000000000 +0000 +++ squid-3.0-DEVEL-tproxy/src/forward.cc 2003-03-12 15:32:31.000000000 +0000 @@ -42,6 +42,10 @@ #include "ACLChecklist.h" #include "ACL.h" +#if LINUX_TPROXY +#include +#endif + static PSC fwdStartComplete; static void fwdDispatch(FwdState *); static void fwdConnectStart(void *); /* should be same as EVH */ @@ -522,6 +526,15 @@ struct in_addr outgoing; unsigned short tos; + struct in_addr *local=NULL; +#if LINUX_TPROXY + int f=ITP_CONNECT; + 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); @@ -537,7 +550,7 @@ ctimeout = Config.Timeout.connect; } - if ((fd = pconnPop(host, port)) >= 0) { + if ((fd = pconnPop(host, port, local)) >= 0) { debug(17, 3) ("fwdConnectStart: reusing pconn FD %d\n", fd); fwdState->server_fd = fd; fwdState->n_tries++; @@ -595,6 +608,18 @@ fwdConnectTimeout, fwdState); +#if LINUX_TPROXY + if ( Config.onoff.linux_tproxy ) { + itp.itp_faddr.s_addr = fwdState->src.sin_addr.s_addr; + itp.itp_fport = fwdState->src.sin_port; + + /* If these syscalls fail then we just fallback to connecting + * normally by simply ignoring the errors... + */ + setsockopt(fd, SOL_IP, IP_TPROXY_ASSIGN, &itp, sizeof(itp)); + setsockopt(fd, SOL_IP, IP_TPROXY_FLAGS, &f, sizeof(f)); + } +#endif commConnectStart(fd, host, port, fwdConnectDone, fwdState); } @@ -867,6 +892,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); diff -urN squid-3.0-DEVEL-20030310/src/http.cc squid-3.0-DEVEL-tproxy/src/http.cc --- squid-3.0-DEVEL-20030310/src/http.cc 2003-03-06 06:21:38.000000000 +0000 +++ squid-3.0-DEVEL-tproxy/src/http.cc 2003-03-12 15:34:37.000000000 +0000 @@ -902,6 +902,12 @@ void HttpStateData::processReplyData(const char *buf, size_t len) { + struct in_addr *local=NULL; +#if LINUX_TPROXY + if ( Config.onoff.linux_tproxy ) + local=&request->client_addr; +#endif + if (reply_hdr_state < 2) { do_next_read = 1; maybeReadData(); @@ -957,7 +963,7 @@ comm_remove_close_handler(fd, httpStateFree, this); fwdUnregister(fd, fwd); - pconnPush(fd, request->host, request->port); + pconnPush(fd, request->host, request->port, local); fwdComplete(fwd); fd = -1; httpStateFree(fd, this); diff -urN squid-3.0-DEVEL-20030310/src/main.cc squid-3.0-DEVEL-tproxy/src/main.cc --- squid-3.0-DEVEL-20030310/src/main.cc 2003-02-25 12:24:35.000000000 +0000 +++ squid-3.0-DEVEL-tproxy/src/main.cc 2003-03-12 15:35:17.000000000 +0000 @@ -509,6 +509,15 @@ 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"); diff -urN squid-3.0-DEVEL-20030310/src/pconn.cc squid-3.0-DEVEL-tproxy/src/pconn.cc --- squid-3.0-DEVEL-20030310/src/pconn.cc 2003-02-21 22:50:10.000000000 +0000 +++ squid-3.0-DEVEL-tproxy/src/pconn.cc 2003-03-12 15:39:02.000000000 +0000 @@ -55,7 +55,6 @@ static IOCB 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); @@ -67,14 +66,17 @@ static MemPool *pconn_fds_pool = NULL; CBDATA_TYPE(pconn); +#define PCONN_KEYLEN (SQUIDHOSTNAMELEN + 24) - -static const char * -pconnKey(const char *host, u_short port) +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 * @@ -238,12 +240,12 @@ } 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 (fdNFree() < (RESERVED_FD << 1)) { @@ -256,7 +258,7 @@ } assert(table != NULL); - strcpy(key, pconnKey(host, port)); + pconnkey(key, peer, port, local); p = (struct _pconn *) hash_lookup(table, key); @@ -279,7 +281,7 @@ p->fds[p->nfds++] = fd; comm_read(fd, p->buf, BUFSIZ, pconnRead, p); 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); } @@ -295,15 +297,15 @@ * quite a bit of CPU. Just keep it in mind. */ 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_link *)hash_lookup(table, key); if (hptr != NULL) { diff -urN squid-3.0-DEVEL-20030310/src/protos.h squid-3.0-DEVEL-tproxy/src/protos.h --- squid-3.0-DEVEL-20030310/src/protos.h 2003-03-08 09:35:15.000000000 +0000 +++ squid-3.0-DEVEL-tproxy/src/protos.h 2003-03-12 15:39:34.000000000 +0000 @@ -907,8 +907,8 @@ SQUIDCEXTERN err_type errorReservePageId(const char *page_name); SQUIDCEXTERN ErrorState *errorCon(err_type type, http_status); -SQUIDCEXTERN void pconnPush(int, const char *host, u_short port); -SQUIDCEXTERN int pconnPop(const char *host, u_short port); +SQUIDCEXTERN void pconnPush(int, const char *peer, u_short port, struct in_addr *local); +SQUIDCEXTERN int pconnPop(const char *peer, u_short port, struct in_addr *local); SQUIDCEXTERN void pconnInit(void); /* tools.c */ diff -urN squid-3.0-DEVEL-20030310/src/structs.h squid-3.0-DEVEL-tproxy/src/structs.h --- squid-3.0-DEVEL-20030310/src/structs.h 2003-03-08 09:35:16.000000000 +0000 +++ squid-3.0-DEVEL-tproxy/src/structs.h 2003-03-12 15:41:24.000000000 +0000 @@ -538,6 +538,9 @@ int check_hostnames; int via; int emailErrData; +#if LINUX_NETFILTER + int linux_tproxy; +#endif } onoff; @@ -1645,6 +1648,7 @@ /* these in_addr's could probably be sockaddr_in's */ struct in_addr client_addr; + in_port_t client_port; struct in_addr my_addr; unsigned short my_port; @@ -2047,6 +2051,9 @@ } flags; +#if LINUX_NETFILTER + struct sockaddr_in src; +#endif }; #if USE_HTCP