]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Auto-detect the amount of TPROXY support available.
authorAmos Jeffries <squid3@treenet.co.nz>
Wed, 16 Sep 2009 08:21:27 +0000 (20:21 +1200)
committerAmos Jeffries <squid3@treenet.co.nz>
Wed, 16 Sep 2009 08:21:27 +0000 (20:21 +1200)
Uses the configured port address type to determine the level of testing
done. Systems with IPv4-only TPROXY (kernel 2.6.28 to 2.6.3*) will have
their ports reduced to IPv4-only, and those with IPv6 support will see
the port open as IPv6. This is done at run-time to cater for patched
kernels and kernel upgrades underneath Squid.

src/cache_cf.cc
src/ip/IpIntercept.cc
src/ip/IpIntercept.h

index 2040b2872a8343636811d57eb81e1eb67a25855f..5b4999aba30a114c50a13a1d86f4cf95b4b16260 100644 (file)
@@ -3044,16 +3044,12 @@ parse_http_port_option(http_port_list * s, char *token)
         IpInterceptor.StartTransparency();
         /* Log information regarding the port modes under transparency. */
         debugs(3, DBG_IMPORTANT, "Starting IP Spoofing on port " << s->s);
-        debugs(3, DBG_IMPORTANT, "Disabling Authentication on port " << s->s << " (Ip spoofing enabled)");
+        debugs(3, DBG_IMPORTANT, "Disabling Authentication on port " << s->s << " (IP spoofing enabled)");
 
-#if USE_IPV6
-        /* INET6: until target TPROXY is known to work on IPv6 SOCKET, force wildcard to IPv4 */
-        debugs(3, DBG_IMPORTANT, "Disabling IPv6 on port " << s->s << " (interception enabled)");
-        if ( s->s.IsIPv6() && !s->s.SetIPv4() ) {
-            debugs(3, DBG_CRITICAL, "http(s)_port: IPv6 addresses cannot be transparent (protocol does not provide NAT)" << s->s );
+        if (!IpInterceptor.ProbeForTproxy(s->s)) {
+            debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: TPROXY support in the system does not work.");
             self_destruct();
         }
-#endif
 
     } else if (strcmp(token, "ipv4") == 0) {
 #if USE_IPV6
index cdb8f01c346ed02619a529ee67dd83742a854c0b..9f2edeb2cbd944f1dae6f2f9ee3715073f9ef9a1 100644 (file)
@@ -438,3 +438,85 @@ IpIntercept::SetTproxy2OutgoingAddr(int fd, const IpAddress &src)
     return 0;
 }
 #endif
+
+bool
+IpIntercept::ProbeForTproxy(IpAddress &test)
+{
+    debugs(3, 3, "Detect TPROXY support on port " << test);
+#if LINUX_TPROXY2
+
+#if USE_IPV6
+        /* TPROXYv2 is not IPv6 capable. Force wildcard sockets to IPv4. Die on IPv6 IPs */
+        debugs(3, DBG_IMPORTANT, "Disabling IPv6 on port " << test << " (TPROXYv2 interception enabled)");
+        if ( test.IsIPv6() && !test.SetIPv4() ) {
+            debugs(3, DBG_CRITICAL, "IPv6 requires TPROXYv4 support. You only have TPROXYv2 for " << test );
+            return false;
+        }
+#endif /* USE_IPV6 */
+    return true;
+
+#else /* not LINUX_TPROXY2 */
+
+#if defined(IP_TRANSPARENT)
+
+    int tos = 1;
+    int tmp_sock = -1;
+
+#if USE_IPV6
+    /* Probe to see if the Kernel TPROXY support is IPv6-enabled */
+    if (test.IsIPv6()) {
+        debugs(3, 3, "...Probing for IPv6 TPROXY support.");
+
+        struct sockaddr_in6 tmp_ip6;
+        IpAddress tmp = "::2";
+        tmp.SetPort(0);
+        tmp.GetSockAddr(tmp_ip6);
+
+        if ( (tmp_sock = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP)) >= 0 &&
+            setsockopt(tmp_sock, SOL_IP, IP_TRANSPARENT, (char *)&tos, sizeof(int)) == 0 &&
+            bind(tmp_sock, (struct sockaddr*)&tmp_ip6, sizeof(struct sockaddr_in6)) == 0 ) {
+
+            debugs(3, 3, "IPv6 TPROXY support detected. Using.");
+            close(tmp_sock);
+            return true;
+        }
+        if (tmp_sock >= 0) {
+            close(tmp_sock);
+            tmp_sock = -1;
+        }
+    }
+
+    if ( test.IsIPv6() && !test.SetIPv4() ) {
+        debugs(3, DBG_CRITICAL, "TPROXY lacks IPv6 support for " << test );
+        return false;
+    }
+#endif
+
+    /* Probe to see if the Kernel TPROXY support is IPv4-enabled (aka present) */
+    if (test.IsIPv4()) {
+        debugs(3, 3, "...Probing for IPv4 TPROXY support.");
+
+        struct sockaddr_in tmp_ip4;
+        IpAddress tmp = "127.0.0.2";
+        tmp.SetPort(0);
+        tmp.GetSockAddr(tmp_ip4);
+
+        if ( (tmp_sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) >= 0 &&
+            setsockopt(tmp_sock, SOL_IP, IP_TRANSPARENT, (char *)&tos, sizeof(int)) == 0 &&
+            bind(tmp_sock, (struct sockaddr*)&tmp_ip4, sizeof(struct sockaddr_in)) == 0 ) {
+
+            debugs(3, 3, "IPv4 TPROXY support detected. Using.");
+            close(tmp_sock);
+            return true;
+        }
+        if (tmp_sock >= 0) {
+            close(tmp_sock);
+        }
+    }
+
+#else /* undefined IP_TRANSPARENT */
+    debugs(3, 3, "setsockopt(IP_TRANSPARENT) not supported on this platform. Disabling TPROXYv4.");
+#endif
+#endif /* LINUX_TPROXY2 */
+    return false;
+}
index 0ab24e23aab9bdb55d07616f2b964f29eec59d6c..0121194fa70ed7f26550c65aed51e873f8dba7f6 100644 (file)
@@ -35,6 +35,17 @@ public:
     int SetTproxy2OutgoingAddr(int fd, const IpAddress &src);
 #endif
 
+    /**
+     * Test system networking calls for TPROXY support.
+     * Detects IPv6 and IPv4 level of support matches the address being listened on
+     * and if the compiled v2/v4 is usable as far down as a bind()ing.
+     * 
+     * \param test    Address set on the http(s)_port being checked.
+     * \retval true   TPROXY is available.
+     * \retval false  TPROXY is not available.
+     */
+    bool ProbeForTproxy(IpAddress &test);
+
     /**
      \retval 0 Full transparency is disabled.
      \retval 1  Full transparency is enabled and active.