From: Amos Jeffries Date: Wed, 16 Sep 2009 08:21:27 +0000 (+1200) Subject: Auto-detect the amount of TPROXY support available. X-Git-Tag: SQUID_3_1_0_14~29 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=1f1f1b2b6f82f3c17edfc392b7b00c31bacd19c9;p=thirdparty%2Fsquid.git Auto-detect the amount of TPROXY support available. 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. --- diff --git a/src/cache_cf.cc b/src/cache_cf.cc index 2040b2872a..5b4999aba3 100644 --- a/src/cache_cf.cc +++ b/src/cache_cf.cc @@ -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 diff --git a/src/ip/IpIntercept.cc b/src/ip/IpIntercept.cc index cdb8f01c34..9f2edeb2cb 100644 --- a/src/ip/IpIntercept.cc +++ b/src/ip/IpIntercept.cc @@ -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; +} diff --git a/src/ip/IpIntercept.h b/src/ip/IpIntercept.h index 0ab24e23aa..0121194fa7 100644 --- a/src/ip/IpIntercept.h +++ b/src/ip/IpIntercept.h @@ -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.