From 7b0a0d1f440d86f5971a734f6a2eebafd3848c3a Mon Sep 17 00:00:00 2001 From: Amos Jeffries Date: Thu, 10 Apr 2008 01:20:35 +1200 Subject: [PATCH] Break Netfilter and IPFW lookups out of the general either-or NAT lookup. NAT lookup was prevously detemined by configure-time settings with no possibility of two transparent options working within a single binary. This patch moves the Netfilter and IPF lookups into sub functions and builds a sequential failover sequence for them. At which point any of the four transparent/interception methods may be used simultaneoulsy on one or more listening ports. --- configure.in | 19 +---- src/IPInterception.cc | 175 +++++++++++++++++++++++++++--------------- src/IPInterception.h | 33 +++++++- 3 files changed, 150 insertions(+), 77 deletions(-) diff --git a/configure.in b/configure.in index 02da8c3dcf..400cda5368 100644 --- a/configure.in +++ b/configure.in @@ -1218,7 +1218,7 @@ dnl "-64" from LDFLAGS esac fi -dnl Enable Linux transparent proxy support +dnl Enable Linux transparent proxy support for obsolete TPROXY AC_ARG_ENABLE(linux-tproxy2, [ --enable-linux-tproxy2 Enable real Transparent Proxy support for Netfilter TPROXY (version 2).], @@ -1232,19 +1232,6 @@ AC_ARG_ENABLE(linux-tproxy2, 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" - fi - fi -]) AM_CONDITIONAL(MAKE_LEAKFINDER, false) dnl Enable Leak Finding Functions @@ -2946,7 +2933,7 @@ if test "$LINUX_NETFILTER" ; then fi if test "$LINUX_NETFILTER" = "no" ; then echo "WARNING: Cannot find necessary Linux kernel (Netfilter) header files" - echo " Linux Transparent Proxy support WILL NOT be enabled" + echo " Linux Transparent and Intercepting Proxy support WILL NOT be enabled" sleep 10 fi @@ -2967,7 +2954,7 @@ if test "$LINUX_TPROXY2" ; 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." + echo "Or select the '--enable-linux-netfilter' option instead for Netfilter support." sleep 10 fi fi diff --git a/src/IPInterception.cc b/src/IPInterception.cc index 2d952b2ce1..cd6f22fa77 100644 --- a/src/IPInterception.cc +++ b/src/IPInterception.cc @@ -37,7 +37,7 @@ #include "clientStream.h" #include "IPInterception.h" #include "SquidTime.h" - +#include "fde.h" #if IPF_TRANSPARENT @@ -115,6 +115,105 @@ IPIntercept::StopInterception(const char *str) { intercept_active = 0; } +int +IPIntercept::NetfilterInterception(int fd, const IPAddress &me, IPAddress &dst, int silent) +{ +#if LINUX_NETFILTER + static time_t last_reported = 0; + struct addrinfo *lookup = NULL; + + dst.GetAddrInfo(lookup,AF_INET); + + /** \par + * Try NAT lookup for REDIRECT or DNAT targets. */ + if( getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, lookup->ai_addr, &lookup->ai_addrlen) == 0) { + if(!silent) { + debugs(89, DBG_IMPORTANT, HERE << "peer " << peer << " NF getsockopt(SO_ORIGINAL_DST) failed: " << xstrerror()); + last_reported = squid_curtime; + } + } + else { + dst = *lookup; + } + + dst.FreeAddrInfo(lookup); + + if(me != dst) { + debugs(89, 5, HERE << "address: " << dst); + return 0; + } + +#endif + return -1; +} + +int +IPIntercept::NetfilterTransparent(int fd, const IPAddress &me, IPAddress &dst, int silent) +{ +#if LINUX_NETFILTER + static time_t last_reported = 0; + struct addrinfo *lookup = NULL; + + if( ! fd_table[fd].flags.transparent) return -1; + + dst.GetAddrInfo(lookup,AF_INET); + + /** \par + * Try lookup for TPROXY targets. BUT, only if the FD is flagged for transparent operations. */ + if(getsockopt(fd, SOL_IP, IP_TRANSPARENT, lookup->ai_addr, &lookup->ai_addrlen) != 0) { + if(!silent) { + debugs(89, DBG_IMPORTANT, HERE << "peer " << peer << " NF getsockopt(IP_TRANSPARENT) failed: " << xstrerror()); + last_reported = squid_curtime; + } + } + else { + dst = *lookup; + } + + dst.FreeAddrInfo(lookup); + + if(me != dst) { + debugs(89, 5, HERE << "address: " << dst); + return 0; + } + +#endif + return -1; +} + +int +IPIntercept::IPFWInterception(int fd, const IPAddress &me, IPAddress &dst, int silent) +{ +#if IPFW_TRANSPARENT + static time_t last_reported = 0; + struct addrinfo *lookup = NULL; + + dst.GetAddrInfo(lookup,AF_INET); + + /** \par + * Try lookup for IPFW interception. */ + if( getsockname(fd, lookup->ai_addr, &lookup->ai_addrlen) >= 0 ) { + if( !silent ) { + debugs(89, DBG_IMPORTANT, HERE << "peer " << peer << " IPFW getsockname(...) failed: " << xstrerror()); + last_reported = squid_curtime; + } + } + else { + dst = *lookup; + } + + dst.FreeAddrInfo(lookup); + + if(me != dst) { + debugs(89, 5, HERE << "address: " << dst); + return 0; + } + +#endif + return -1; +} + + // TODO split this one call into one per transparency method // with specific switching at run-time ?? @@ -230,43 +329,27 @@ IPIntercept::NatLookup(int fd, const IPAddress &me, const IPAddress &peer, IPAdd -#elif LINUX_NETFILTER || LINUX_TPROXY4 /* --enable-linux-netfilter OR --enable-linux-tproxy4 */ +#elif LINUX_NETFILTER || IPFW_TRANSPARENT /* --enable-linux-netfilter OR --enable-ipfw-transparent */ - dst = me; - if( !me.IsIPv4() ) return -1; - if( !peer.IsIPv4() ) return -1; - - static time_t last_reported = 0; - struct addrinfo *lookup = NULL; - - dst.GetAddrInfo(lookup,AF_INET); + /* Netfilter and IPFW share almost identical lookup methods for their NAT tables. + * This allows us to perform a nice clean failover sequence for them. + */ + int silent = (squid_curtime - last_reported > 60 ? 0 : 1); -#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); + dst = me; - if (squid_curtime - last_reported > 60) { - debugs(89, 1, "clientNatLookup: peer " << peer << " NF getsockopt(" << (LINUX_NETFILTER?"SO_ORIGINAL_DST":"IP_TRANSPARENT") << ") failed: " << xstrerror()); - last_reported = squid_curtime; - } + if( !me.IsIPv4() ) return -1; + if( !peer.IsIPv4() ) return -1; - return -1; + if(intercept_active) { + if( NetfilterInterception(fd, me, peer, dst, silent) == 0) return 0; + if( IPFWInterception(fd, me, peer, dst, silent) == 0) return 0; + } + if(transparent_active) { + if( NetfilterTransparent(fd, me, peer, dst) == 0) return 0; } - dst = *lookup; - - dst.FreeAddrInfo(lookup); - - debugs(89, 5, "clientNatLookup: addr = " << dst << ""); - - if (me != dst) - return 0; - else - return -1; + return -1; #elif PF_TRANSPARENT /* --enable-pf-transparent */ @@ -330,34 +413,6 @@ IPIntercept::NatLookup(int fd, const IPAddress &me, const IPAddress &peer, IPAdd } -#elif IPFW_TRANSPARENT /* --enable-ipfw-transparent */ - - int ret; - struct addrinfo *lookup = NULL; - - if( !me.IsIPv4() ) return -1; - if( !peer.IsIPv4() ) return -1; - - dst.GetAddrInfo(lookup,AF_INET); - - ret = getsockname(fd, lookup->ai_addr, &lookup->ai_addrlen); - - if (ret < 0) { - - dst.FreeAddrInfo(lookup); - - debugs(89, 1, "clientNatLookup: getpeername failed (fd " << fd << "), errstr " << xstrerror()); - - return -1; - } - - dst = *lookup; - - dst.FreeAddrInfo(lookup); - - return 0; - - #else /* none of the transparent options configured */ debugs(89, 1, "WARNING: transparent proxying not supported"); diff --git a/src/IPInterception.h b/src/IPInterception.h index cd1d6522f5..7347b0d3c3 100644 --- a/src/IPInterception.h +++ b/src/IPInterception.h @@ -25,6 +25,7 @@ public: IPIntercept() : transparent_active(0), intercept_active(0) {}; ~IPIntercept() {}; + /** Perform NAT lookups */ int NatLookup(int fd, const IPAddress &me, const IPAddress &peer, IPAddress &dst); #if LINUX_TPROXY2 @@ -75,12 +76,42 @@ public: */ inline void StopInterception(const char *str); + private: + + /** + * perform Lookups on Netfilter interception targets (REDIRECT, DNAT). + * + \param silent[in] 0 if errors are to be displayed. 1 if errors are to be hidden. + \retval 0 Successfuly located the new address. + \retval -1 An error occured during NAT lookups. + */ + int NetfilterInterception(int fd, const IPAddress &me, const IPAddress &peer, IPAddress &dst, int silent); + + /** + * perform Lookups on Netfilter fully-transparent interception targets (TPROXY). + * + \param silent[in] 0 if errors are to be displayed. 1 if errors are to be hidden. + \retval 0 Successfuly located the new address. + \retval -1 An error occured during NAT lookups. + */ + int NetfilterTransparent(int fd, const IPAddress &me, const IPAddress &peer, IPAddress &dst, int silent); + + /** + * perform Lookups on IPFW interception. + * + \param silent[in] 0 if errors are to be displayed. 1 if errors are to be hidden. + \retval 0 Successfuly located the new address. + \retval -1 An error occured during NAT lookups. + */ + int IPFWInterception(int fd, const IPAddress &me, const IPAddress &peer, IPAddress &dst, int silent); + + int transparent_active; int intercept_active; }; -#if !defined(IP_TRANSPARENT) +#if LINUX_NETFILTER && !defined(IP_TRANSPARENT) /// \ingroup IPInterceptAPI #define IP_TRANSPARENT 19 #endif -- 2.47.2