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).],
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
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
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
#include "clientStream.h"
#include "IPInterception.h"
#include "SquidTime.h"
-
+#include "fde.h"
#if IPF_TRANSPARENT
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 ??
-#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 */
}
-#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");
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
*/
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