# Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: squid3@treenet.co.nz-20080331104554-n0bgvxboeo99ej0u # target_branch: file:///src/squid/bzr/trunk/ # testament_sha1: c15fc2a03b9d847977021f33bf29cb22a5821752 # timestamp: 2008-04-01 12:16:41 +1200 # base_revision_id: henrik@henriknordstrom.net-20080328204641-\ # so853tluhwlx6qc5 # # Begin patch === modified file 'configure.in' --- configure.in 2008-03-18 11:58:16 +0000 +++ configure.in 2008-03-26 11:49:34 +0000 @@ -1219,13 +1219,26 @@ 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, 1, [Enable real Transparent Proxy support for Netfilter TPROXY.]) - LINUX_TPROXY="yes" +AC_ARG_ENABLE(linux-tproxy2, +[ --enable-linux-tproxy2 + Enable real Transparent Proxy support for Netfilter TPROXY (version 2).], +[ if test "$enableval" = "yes" ; then + echo "Linux Netfilter/TPROXY v2 enabled" + AC_DEFINE(LINUX_TPROXY2, 1, [Enable real Transparent Proxy support for Netfilter TPROXY v2.]) + LINUX_TPROXY2="yes" + if test -z "$LINUX_NETFILTER"; then + echo "Linux-Netfilter Transparent Proxy automatically enabled" + LINUX_NETFILTER="yes" + fi + fi +]) +AC_ARG_ENABLE(linux-tproxy4, +[ --enable-linux-tproxy4 + Enable real Transparent Proxy support for Netfilter TPROXY (version 4+).], +[ if test "$enableval" = "yes" ; then + echo "Linux Netfilter/TPROXY v4 enabled" + AC_DEFINE(LINUX_TPROXY4, 1, [Enable real Transparent Proxy support for Netfilter TPROXY v4.]) + LINUX_TPROXY4="yes" if test -z "$LINUX_NETFILTER"; then echo "Linux-Netfilter Transparent Proxy automatically enabled" LINUX_NETFILTER="yes" @@ -2882,25 +2895,26 @@ sleep 10 fi -dnl Linux Netfilter/TPROXY support requires some specific header files +dnl Linux Netfilter/TPROXYv2 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) +if test "$LINUX_TPROXY2" ; then + AC_MSG_CHECKING(if TPROXYv2 header files are installed) # hold on to your hats... if test "$ac_cv_header_linux_netfilter_ipv4_ip_tproxy_h" = "yes" && test "$LINUX_NETFILTER" = "yes"; then - LINUX_TPROXY="yes" - AC_DEFINE(LINUX_TPROXY, 1, [Enable real Transparent Proxy support for Netfilter TPROXY.]) + LINUX_TPROXY2="yes" + AC_DEFINE(LINUX_TPROXY2, 1, [Enable real Transparent Proxy support for Netfilter TPROXY v2.]) else - LINUX_TPROXY="no" - AC_DEFINE(LINUX_TPROXY, 0, [Enable real Transparent Proxy support for Netfilter TPROXY.]) - fi - AC_MSG_RESULT($LINUX_TPROXY) -fi -if test "$LINUX_TPROXY" = "no" && test "$LINUX_NETFILTER" = "yes"; then - echo "WARNING: Cannot find TPROXY headers, you need to install the" - echo "tproxy package from:" - echo " - lynx http://www.balabit.com/downloads/tproxy/" - sleep 10 + LINUX_TPROXY2="no" + AC_DEFINE(LINUX_TPROXY2, 0, [Enable real Transparent Proxy support for Netfilter TPROXY v2.]) + fi + AC_MSG_RESULT($LINUX_TPROXY2) + if test "$LINUX_TPROXY2" = "no" && test "$LINUX_NETFILTER" = "yes"; then + echo "WARNING: Cannot find TPROXY v2 headers, you need to install the" + echo "tproxy package from:" + echo " - lynx http://www.balabit.com/downloads/tproxy/" + echo "Or select the '--enable-linux-tproxy4' option instead." + sleep 10 + fi fi if test -z "$USE_GNUREGEX" ; then === modified file 'doc/release-notes/release-3.1.sgml' --- doc/release-notes/release-3.1.sgml 2008-01-17 17:09:05 +0000 +++ doc/release-notes/release-3.1.sgml 2008-03-29 11:23:47 +0000 @@ -298,6 +298,16 @@ but please report the bugs anyway.

+ --enable-linux-tproxy2 +

New option to enable TPROXY version 2 support in squid (previously known as --enable-linux-tproxy). + Linux Kernel patches from Balabit are required before building squid with this option. +

+ + --enable-linux-tproxy4 +

New option to enable TPROXY version 4+ support in squid. + This options requires a linux kernel 2.6.25 or later for embeded netfilter TPROXY targets. +

+

@@ -308,7 +318,7 @@ --disable-internl-dns

Better support for Linux using the external DNS helper. The helper will compile and work with dns_nameservers on more variants of Linux than previously.

- +

@@ -334,6 +344,8 @@

The following configure options have been removed. + --enable-linux-tproxy +

Replaced by --enable-linux-tproxy2 to make way for differences in TPROXY v2 and v4 support.

=== modified file 'include/autoconf.h.in' --- include/autoconf.h.in 2008-02-17 16:24:48 +0000 +++ include/autoconf.h.in 2008-03-26 11:49:34 +0000 @@ -792,8 +792,11 @@ /* Enable support for Transparent Proxy on Linux (Netfilter) systems */ #undef LINUX_NETFILTER -/* Enable real Transparent Proxy support for Netfilter TPROXY. */ -#undef LINUX_TPROXY +/* Enable real Transparent Proxy support for Netfilter TPROXY v2. */ +#undef LINUX_TPROXY2 + +/* Enable real Transparent Proxy support for Netfilter TPROXY v4. */ +#undef LINUX_TPROXY4 /* If we need to declare sys_errlist[] as external */ #undef NEED_SYS_ERRLIST === modified file 'src/IPInterception.cc' --- src/IPInterception.cc 2008-02-06 05:38:24 +0000 +++ src/IPInterception.cc 2008-03-26 11:49:34 +0000 @@ -1,4 +1,3 @@ - /* * $Id: IPInterception.cc,v 1.20 2008/02/05 22:38:24 amosjeffries Exp $ * @@ -88,11 +87,12 @@ #include #endif -#if IPF_TRANSPARENT int - clientNatLookup(int fd, const IPAddress &me, const IPAddress &peer, IPAddress &dst) { + +#if IPF_TRANSPARENT /* --enable-ipf-transparent */ + dst = me; if( !me.IsIPv4() ) return -1; if( !peer.IsIPv4() ) return -1; @@ -198,12 +198,11 @@ return 0; } -} - -#elif LINUX_NETFILTER -int -clientNatLookup(int fd, const IPAddress &me, const IPAddress &peer, IPAddress &dst) -{ + + + +#elif LINUX_NETFILTER || LINUX_TPROXY4 /* --enable-linux-netfilter OR --enable-linux-tproxy4 */ + dst = me; if( !me.IsIPv4() ) return -1; if( !peer.IsIPv4() ) return -1; @@ -213,12 +212,16 @@ dst.GetAddrInfo(lookup,AF_INET); +#if LINUX_NETFILTER if (getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, lookup->ai_addr, &lookup->ai_addrlen) != 0) +#elif LINUX_TPROXY4 + if (getsockopt(fd, SOL_IP, IP_TRANSPARENT, lookup->ai_addr, &lookup->ai_addrlen) != 0) +#endif { dst.FreeAddrInfo(lookup); if (squid_curtime - last_reported > 60) { - debugs(89, 1, "clientNatLookup: peer " << peer << " NF getsockopt(SO_ORIGINAL_DST) failed: " << xstrerror()); + debugs(89, 1, "clientNatLookup: peer " << peer << " NF getsockopt(" << (LINUX_NETFILTER?"SO_ORIGINAL_DST":"IP_TRANSPARENT") << ") failed: " << xstrerror()); last_reported = squid_curtime; } @@ -234,13 +237,9 @@ return 0; else return -1; -} - -#elif PF_TRANSPARENT -int - -clientNatLookup(int fd, const IPAddress &me, const IPAddress &peer, IPAddress dst) -{ + + +#elif PF_TRANSPARENT /* --enable-pf-transparent */ struct pfioc_natlook nl; static int pffd = -1; @@ -300,12 +299,10 @@ else return -1; } -} - -#elif IPFW_TRANSPARENT -int -clientNatLookup(int fd, const IPAddress &me, const IPAddress &peer, IPAddress &dst) -{ + + +#elif IPFW_TRANSPARENT /* --enable-ipfw-transparent */ + int ret; struct addrinfo *lookup = NULL; @@ -330,14 +327,13 @@ dst.FreeAddrInfo(lookup); return 0; -} - -#else -int -clientNatLookup(int fd, const IPAddress &me, const IPAddress &peer, IPAddress &dst) -{ + + +#else /* none of the transparent options configured */ + debugs(89, 1, "WARNING: transparent proxying not supported"); return -1; + +#endif + } -#endif - === modified file 'src/IPInterception.h' --- src/IPInterception.h 2007-12-15 06:11:41 +0000 +++ src/IPInterception.h 2008-03-26 11:49:34 +0000 @@ -1,4 +1,3 @@ - /* * $Id: IPInterception.h,v 1.7 2007/12/14 23:11:45 amosjeffries Exp $ * @@ -30,13 +29,15 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. * */ - #ifndef SQUID_IPINTERCEPTION_H #define SQUID_IPINTERCEPTION_H #include "IPAddress.h" -SQUIDCEXTERN int -clientNatLookup(int fd, const IPAddress &me, const IPAddress &peer, IPAddress &dst); +#if LINUX_TPROXY4 && !defined(IP_TRANSPARENT) +#define IP_TRANSPARENT 19 +#endif + +SQUIDCEXTERN int clientNatLookup(int fd, const IPAddress &me, const IPAddress &peer, IPAddress &dst); #endif /* SQUID_IPINTERCEPTION_H */ === modified file 'src/ProtoPort.h' --- src/ProtoPort.h 2008-03-16 21:48:45 +0000 +++ src/ProtoPort.h 2008-03-26 11:49:34 +0000 @@ -31,7 +31,8 @@ int vport; /* virtual port support, -1 for dynamic, >0 static*/ int disable_pmtu_discovery; -#if LINUX_TPROXY + +#if LINUX_TPROXY2 || LINUX_TPROXY4 unsigned int tproxy:1; /* spoof client ip using tproxy */ #endif === modified file 'src/cache_cf.cc' --- src/cache_cf.cc 2008-03-20 23:20:58 +0000 +++ src/cache_cf.cc 2008-03-31 10:45:54 +0000 @@ -1,4 +1,3 @@ - /* * $Id: cache_cf.cc,v 1.544 2008/03/04 12:00:36 amosjeffries Exp $ * @@ -2928,10 +2927,11 @@ else self_destruct(); -#if LINUX_TPROXY +#if LINUX_TPROXY2 || LINUX_TPROXY4 } else if (strcmp(token, "tproxy") == 0) { s->tproxy = 1; + s->transparent = 1; need_linux_tproxy = 1; #if USE_IPV6 /* INET6: until transparent REDIRECT works on IPv6 SOCKET, force wildcard to IPv4 */ @@ -2941,6 +2941,7 @@ } #endif #endif + } else if (strcmp(token, "ipv4") == 0) { #if USE_IPV6 if( !s->s.SetIPv4() ) { === modified file 'src/client_side.cc' --- src/client_side.cc 2008-03-16 21:48:45 +0000 +++ src/client_side.cc 2008-03-26 11:49:34 +0000 @@ -2213,8 +2213,7 @@ request->flags.transparent = http->flags.transparent; -#if LINUX_TPROXY - +#if LINUX_TPROXY2 || LINUX_TPROXY4 request->flags.tproxy = conn->port->tproxy && need_linux_tproxy; #endif @@ -3118,6 +3117,13 @@ if (fd < 0) continue; +#if LINUX_TPROXY4 + /* because the transparent/non-transparent port info is only known here. + * we have to set the IP_TRANSPARENT option here. */ + if(s->transparent) + comm_set_transparent(fd,0); +#endif + comm_listen(fd); comm_accept(fd, httpAccept, s); === modified file 'src/comm.cc' --- src/comm.cc 2008-03-25 15:40:36 +0000 +++ src/comm.cc 2008-03-31 10:45:54 +0000 @@ -48,6 +48,7 @@ #include "SquidTime.h" #include "CommCalls.h" #include "IPAddress.h" +#include "IPInterception.h" #if defined(_SQUID_CYGWIN_) #include @@ -627,6 +628,23 @@ #endif /* sockopt */ } +void +comm_set_transparent(int fd) +{ +#if LINUX_TPROXY4 + int tos = 1; + if (setsockopt(fd, SOL_IP, IP_TRANSPARENT, (char *) &tos, sizeof(int)) < 0) { + debugs(50, DBG_IMPORTANT, "comm_open: setsockopt(IP_TRANSPARENT) on FD " << fd << ": " << xstrerror()); + } + else { + /* mark the socket as having transparent options */ + fd_table[fd].flags.transparent = 1; + } +#else + debugs(50, DBG_CRITICAL, "WARNING: comm_open: setsockopt(IP_TRANSPARENT) not supported on this platform"); +#endif /* sockopt */ +} + /** * Create a socket. Default is blocking, stream (TCP) socket. IO_TYPE * is OR of flags specified in defines.h:COMM_* @@ -1307,6 +1325,14 @@ commSetNonBlocking(sock); +#if LINUX_TPROXY4 + /* AYJ: do we need to set this again on every accept? */ + if(fd_table[fd].flags.transparent == 1) { + comm_set_transparent(sock, 0); + F->flags.transparent = 1; + } +#endif + PROF_stop(comm_accept); return sock; } === modified file 'src/comm.h' --- src/comm.h 2008-02-13 05:58:29 +0000 +++ src/comm.h 2008-03-26 12:02:56 +0000 @@ -56,6 +56,11 @@ SQUIDCEXTERN u_short comm_local_port(int fd); SQUIDCEXTERN int comm_set_tos(int fd, int tos); +/** + * Set the socket IP_TRANSPARENT option for Linux TPROXY v4 support. + */ +SQUIDCEXTERN void comm_set_transparent(int fd, int tos); + SQUIDCEXTERN void commSetSelect(int, unsigned int, PF *, void *, time_t); SQUIDCEXTERN void commResetSelect(int); === modified file 'src/fde.h' --- src/fde.h 2008-02-13 06:22:13 +0000 +++ src/fde.h 2008-03-31 04:01:31 +0000 @@ -82,6 +82,9 @@ unsigned int close_on_exec:1; unsigned int read_pending:1; unsigned int write_pending:1; +#if LINUX_TPROXY4 + unsigned int transparent:1; +#endif } flags; int64_t bytes_read; === modified file 'src/forward.cc' --- src/forward.cc 2008-03-16 21:48:45 +0000 +++ src/forward.cc 2008-03-26 11:49:34 +0000 @@ -49,8 +49,12 @@ #include "SquidTime.h" #include "Store.h" -#if LINUX_TPROXY +#if LINUX_TPROXY2 +#ifdef HAVE_LINUX_NETFILTER_IPV4_IP_TPROXY_H #include +#else +#error " TPROXY v2 Header file missing: linux/netfilter_ipv4/ip_tproxy.h. Perhapse you meant to use TPROXY v4 ? " +#endif #endif static PSC fwdStartCompleteWrapper; === modified file 'src/forward.h' --- src/forward.h 2008-03-16 22:10:18 +0000 +++ src/forward.h 2008-03-26 11:49:34 +0000 @@ -99,7 +99,7 @@ unsigned int ftp_pasv_failed:1; unsigned int forward_completed:1; } flags; -#if LINUX_NETFILTER +#if LINUX_NETFILTER || LINUX_TPROXY2 || LINUX_TPROXY4 IPAddress src; #endif === modified file 'src/globals.h' --- src/globals.h 2008-03-20 11:30:19 +0000 +++ src/globals.h 2008-03-26 11:49:34 +0000 @@ -185,7 +185,7 @@ extern const char *external_acl_message; /* NULL */ extern int opt_send_signal; /* -1 */ extern int opt_no_daemon; /* 0 */ -#if LINUX_TPROXY +#if LINUX_TPROXY2 || LINUX_TPROXY4 extern int need_linux_tproxy; /* 0 */ #endif === modified file 'src/http.cc' --- src/http.cc 2008-02-13 06:55:26 +0000 +++ src/http.cc 2008-03-26 11:49:34 +0000 @@ -1229,7 +1229,8 @@ comm_remove_close_handler(fd, closeHandler); closeHandler = NULL; fwd->unregister(fd); -#if LINUX_TPROXY + +#if LINUX_TPROXY2 || LINUX_TPROXY4 if (orig_request->flags.tproxy) client_addr = orig_request->client_addr; === modified file 'src/structs.h' --- src/structs.h 2008-03-20 23:20:58 +0000 +++ src/structs.h 2008-03-26 11:49:34 +0000 @@ -1029,7 +1029,7 @@ #if HTTP_VIOLATIONS nocache_hack = 0; #endif -#if LINUX_TPROXY +#if LINUX_TPROXY2 || LINUX_TPROXY4 tproxy = 0; #endif } @@ -1051,7 +1051,7 @@ #endif unsigned int accelerated:1; unsigned int transparent:1; -#if LINUX_TPROXY +#if LINUX_TPROXY2 || LINUX_TPROXY4 unsigned int tproxy:1; /* spoof client ip using tproxy */ #endif unsigned int internal:1; === modified file 'src/tools.cc' --- src/tools.cc 2008-03-20 23:20:58 +0000 +++ src/tools.cc 2008-03-26 11:49:34 +0000 @@ -1236,7 +1236,7 @@ if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) { /* Silent failure unless TPROXY is required. Maybe not started as root */ -#if LINUX_TPROXY +#if LINUX_TPROXY2 || LINUX_TPROXY4 if (need_linux_tproxy) debugs(1, 1, "Error - tproxy support requires capability setting which has failed. Continuing without tproxy support"); @@ -1246,7 +1246,6 @@ #endif } - #endif } @@ -1273,10 +1272,13 @@ cap->inheritable = 0; cap->effective = (1 << CAP_NET_BIND_SERVICE); -#if LINUX_TPROXY +#if LINUX_TPROXY2 if (need_linux_tproxy) cap->effective |= (1 << CAP_NET_ADMIN) | (1 << CAP_NET_BROADCAST); +#elif LINUX_TPROXY4 + if (need_linux_tproxy) + cap->effective |= (1 << CAP_NET_ADMIN); #endif @@ -1285,7 +1287,7 @@ if (capset(head, cap) != 0) { /* Silent failure unless TPROXY is required */ -#if LINUX_TPROXY +#if LINUX_TPROXY2 || LINUX_TPROXY4 if (need_linux_tproxy) debugs(50, 1, "Error enabling needed capabilities. Will continue without tproxy support"); @@ -1299,14 +1301,14 @@ nocap: xfree(head); xfree(cap); -#else -#if LINUX_TPROXY +#else /* not defined(_SQUID_LINUX_) && HAVE_SYS_CAPABILITY_H */ + +#if LINUX_TPROXY2 || LINUX_TPROXY4 if (need_linux_tproxy) debugs(50, 1, "Missing needed capability support. Will continue without tproxy support"); need_linux_tproxy = 0; - #endif #endif # Begin bundle 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 apcA