]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Break Netfilter and IPFW lookups out of the general either-or NAT lookup.
authorAmos Jeffries <squid3@treenet.co.nz>
Wed, 9 Apr 2008 13:20:35 +0000 (01:20 +1200)
committerAmos Jeffries <squid3@treenet.co.nz>
Wed, 9 Apr 2008 13:20:35 +0000 (01:20 +1200)
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
src/IPInterception.cc
src/IPInterception.h

index 02da8c3dcfd61d043e48431bbfe74131d8aef1d4..400cda5368ef20be2628b05a4db602f03f70f6d3 100644 (file)
@@ -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
index 2d952b2ce16eff12962f68c53597b064e0ba89a1..cd6f22fa77726370a175c922517ae41cc244a309 100644 (file)
@@ -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");
index cd1d6522f5ca2d0248aafc7aeb4b29fafb47552a..7347b0d3c341d9257750534fa2313a3d56887af3 100644 (file)
@@ -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