Current OpenBSD implementation of PF divert-to works similarly to TPROXY and only requires a getsockname() lookup to locate the TCP packet original destination.

The work by Marios with some additional tweaks discovered in recent testing has now gone into 3.HEAD providing Squid with working http_port tproxy option.

We can use the same PF configuration to preform "intercept" option but the old PF transparent code does lookups on /dev/pf which fails badly on the new PF versions. getsockname() is what is really required and already performed by TcpAcceptor on all incoming connections, so there is no need for a special PF lookup code now.

This patch adds a new ./configure option --with-nat-devpf to enable the old /dev/pf NAT lookup code in a backward-compatible way for older OS versions and OpenBSD based distros which have not yet ported the new PF code. The option is disabled by default since the systems requiring it are fairly old now.


This also removes the getsockname() lookup in the IPFW lookup implementation which is redundant behind TcpAcceptor.


NP: we still do not support the new PF "rdr-to" which is doing more NAT-like operations that TPROXY-like ones. However nobody has been able to supply any information on how we would lookup those details. So until that appears we support both http(s)_port intercept and tproxy options using only the PF divert-to syntax.

Amos
=== modified file 'configure.ac'
--- configure.ac        2013-01-22 06:29:59 +0000
+++ configure.ac        2013-04-01 12:04:25 +0000
@@ -1459,7 +1459,17 @@
               [unrecognized argument to --enable-pf-transparent: $enableval])
 ])
 #will be AC_DEFINEd later, after checking for appropriate infrastructure
-AC_MSG_NOTICE([PF-based transparent proxying requested: 
${enable_pf_transparent:=auto}])
+AC_MSG_NOTICE([PF-based transparent proxying requested: 
${enable_pf_transparent:=no}])
+
+dnl Enable /dev/pf support for older PF Transparent Proxy systems (OpenBSD 4.x 
and older)
+AC_ARG_WITH(nat-devpf,
+  AS_HELP_STRING([--with-nat-devpf],
+    [Enable /dev/pf support for NAT on older OpenBSD and FreeBSD kernels.]), [
+  SQUID_YESNO([$enableval],
+              [unrecognized argument to --with-nat-devpf: $enableval])
+])
+#will be AC_DEFINEd later, after checking for appropriate infrastructure
+AC_MSG_NOTICE([NAT lookups via /dev/pf: ${with_nat_devpf:=no}])
 
 # Linux Netfilter Transparent Proxy
 AC_ARG_ENABLE(linux-netfilter,
@@ -3349,22 +3359,24 @@
   CXXFLAGS="-DSOLARIS2=$solrev $CXXFLAGS" 
 fi
 
-dnl PF support requires a header file.
-if test "x$enable_pf_transparent" != "xno" ; then
+dnl PF /dev/pf support requires a header file.
+if test "x$with_nat_devpf" != "xno" ; then
   if test "x$ac_cv_header_net_pfvar_h" = "xyes" -o \
     "x$ac_cv_header_net_pf_pfvar_h" = "xyes"; then
-    if test "x$enable_pf_transparent" = "xauto" ; then
-      enable_pf_transparent="yes"
+    if test "x$with_nat_devpf" = "xauto" ; then
+      with_nat_devpf="no"
     fi
   else
-    if test "x$enable_pf_transparent" = "xyes" ; then
-      AC_MSG_ERROR([PF-based transparent proxy requested but needed header not 
found])
+    if test "x$with_nat_devpf" = "xyes" ; then
+      AC_MSG_ERROR([PF /dev/pf based NAT requested but needed header not 
found])
     fi
-    enable_pf_transparent="no"
+    with_nat_devpf="no"
   fi
 fi
-SQUID_DEFINE_BOOL(PF_TRANSPARENT,$enable_pf_transparent,
+SQUID_DEFINE_BOOL(PF_TRANSPARENT,${enable_pf_transparent:=no},
   [Enable support for PF-style transparent proxying])
+SQUID_DEFINE_BOOL(USE_NAT_DEVPF,${with_nat_devpf:no},
+  [Enable support for /dev/pf NAT lookups])
 
 if test "x$enable_linux_netfilter" != "xno" ; then
   if test "x$ac_cv_header_linux_netfilter_ipv4_h" = "xyes"; then

=== modified file 'src/ip/Intercept.cc'
--- src/ip/Intercept.cc 2013-04-01 09:54:22 +0000
+++ src/ip/Intercept.cc 2013-04-01 11:27:20 +0000
@@ -164,26 +164,15 @@
 Ip::Intercept::IpfwInterception(const Comm::ConnectionPointer &newConn, int 
silent)
 {
 #if IPFW_TRANSPARENT
-    struct sockaddr_storage lookup;
-    socklen_t len = sizeof(struct sockaddr_storage);
-    newConn->local.GetSockAddr(lookup, AF_INET);
-
-    /** \par
-     * Try lookup for IPFW interception. */
-    if ( getsockname(newConn->fd, (struct sockaddr*)&lookup, &len) != 0 ) {
-        if ( !silent ) {
-            debugs(89, DBG_IMPORTANT, HERE << " IPFW getsockname(...) failed: 
" << xstrerror());
-            lastReported_ = squid_curtime;
-        }
-        debugs(89, 9, HERE << "address: " << newConn);
-        return false;
-    } else {
-        newConn->local = lookup;
-        debugs(89, 5, HERE << "address NAT: " << newConn);
-        return true;
-    }
+    /* The getsockname() call performed already provided the TCP packet 
details.
+     * There is no way to identify whether they came from NAT or not.
+     * Trust the user configured properly.
+     */
+    debugs(89, 5, HERE << "address NAT: " << newConn);
+    return true;
+#else
+    return false;
 #endif
-    return false;
 }
 
 bool
@@ -286,9 +275,8 @@
     newConn->remote.SetPort(0); // allow random outgoing port to prevent 
address clashes
     debugs(89, 5, HERE << "address DIVERT: " << newConn);
     return true;
-#else
+#endif
     return false;
-#endif
 }
 
 bool
@@ -296,6 +284,18 @@
 {
 #if PF_TRANSPARENT  /* --enable-pf-transparent */
 
+#if !USE_NAT_DEVPF
+    /* On recent PF versions the getsockname() call performed already provided
+     * the required TCP packet details.
+     * There is no way to identify whether they came from NAT or not.
+     *
+     * Trust the user configured properly.
+     */
+    debugs(89, 5, HERE << "address NAT divert-to: " << newConn);
+    return true;
+
+#else /* USE_NAT_DEVPF / --with-nat-devpf */
+
     struct pfioc_natlook nl;
     static int pffd = -1;
 

Reply via email to