12 #define BUILDING_SQUID_IP_INTERCEPT_CC 1
25 #if !defined(IPFILTER_VERSION)
26 #define IPFILTER_VERSION 5000004
30 #include <sys/param.h>
33 #include <sys/ioccom.h>
36 #include <sys/ioctl.h>
38 #if HAVE_NETINET_IP6_H
39 #include <netinet/ip6.h>
41 #if HAVE_NETINET_TCP_H
42 #include <netinet/tcp.h>
49 #elif HAVE_NETINET_IPL_H
50 #include <netinet/ipl.h>
52 #if USE_SOLARIS_IPFILTER_MINOR_T_HACK
55 #if HAVE_IP_FIL_COMPAT_H
56 #include <ip_fil_compat.h>
57 #elif HAVE_NETINET_IP_FIL_COMPAT_H
58 #include <netinet/ip_fil_compat.h>
59 #elif HAVE_IP_COMPAT_H
60 #include <ip_compat.h>
61 #elif HAVE_NETINET_IP_COMPAT_H
62 #include <netinet/ip_compat.h>
66 #elif HAVE_NETINET_IP_FIL_H
67 #include <netinet/ip_fil.h>
71 #elif HAVE_NETINET_IP_NAT_H
72 #include <netinet/ip_nat.h>
78 #include <sys/socket.h>
79 #include <sys/ioctl.h>
80 #include <sys/fcntl.h>
82 #include <netinet/in.h>
83 #if HAVE_NET_PF_PFVAR_H
84 #include <net/pf/pfvar.h>
87 #include <net/pfvar.h>
95 #include <linux/netfilter_ipv4.h>
96 #if HAVE_LINUX_NETFILTER_IPV6_IP6_TABLES_H
104 #include <linux/netfilter_ipv6/ip6_tables.h>
106 #if !defined(IP6T_SO_ORIGINAL_DST)
107 #define IP6T_SO_ORIGINAL_DST 80 // stolen with prejudice from the above file.
127 struct sockaddr_storage lookup;
133 if ( getsockopt(newConn->
fd,
134 newConn->
local.
isIPv6() ? IPPROTO_IPV6 : IPPROTO_IP,
138 const auto xerrno = errno;
142 newConn->
local = lookup;
143 debugs(89, 5,
"address NAT: " << newConn);
158 #if (LINUX_NETFILTER && defined(IP_TRANSPARENT)) || \
159 (PF_TRANSPARENT && defined(SO_BINDANY)) || \
160 (IPFW_TRANSPARENT && defined(IP_BINDANY))
161 transparentActive_ = 1;
163 throw TextException(
"requires TPROXY feature to be enabled by ./configure",
Here());
174 #if IPF_TRANSPARENT || LINUX_NETFILTER || IPFW_TRANSPARENT || PF_TRANSPARENT
175 interceptActive_ = 1;
177 throw TextException(
"requires NAT Interception feature to be enabled by ./configure",
Here());
185 return UseInterceptionAddressesLookedUpEarlier(__FUNCTION__, newConn);
199 #if LINUX_NETFILTER && PF_TRANSPARENT && !USE_NAT_DEVPF
200 static_assert(!
"--enable-linux-netfilter is incompatible with --enable-pf-transparent --without-nat-devpf");
202 #if LINUX_NETFILTER && IPFW_TRANSPARENT
203 static_assert(!
"--enable-linux-netfilter is incompatible with --enable-ipfw-transparent");
207 debugs(89, 5, caller <<
" uses " << newConn);
216 struct natlookup natLookup;
217 static int natfd = -1;
221 memset(&natLookup, 0,
sizeof(natLookup));
224 #if HAVE_STRUCT_NATLOOKUP_NL_INIPADDR_IN6
237 debugs(89, warningLevel,
"Your IPF (IPFilter) NAT does not support IPv6. Please upgrade it.");
238 warningLevel = (warningLevel + 1) % 10;
241 newConn->local.getInAddr(natLookup.nl_inip);
242 newConn->remote.getInAddr(natLookup.nl_outip);
244 natLookup.nl_inport = htons(newConn->local.port());
245 natLookup.nl_outport = htons(newConn->remote.port());
247 natLookup.nl_flags = IPN_TCP;
253 natfd = open(IPNAT_NAME, O_RDONLY, 0);
255 natfd = open(IPL_NAT, O_RDONLY, 0);
263 const auto xerrno = errno;
268 #if defined(IPFILTER_VERSION) && (IPFILTER_VERSION >= 4000027)
270 memset(&obj, 0,
sizeof(obj));
271 obj.ipfo_rev = IPFILTER_VERSION;
272 obj.ipfo_size =
sizeof(natLookup);
273 obj.ipfo_ptr = &natLookup;
274 obj.ipfo_type = IPFOBJ_NATLOOKUP;
276 x = ioctl(natfd, SIOCGNATL, &obj);
285 static int siocgnatl_cmd = SIOCGNATL & 0xff;
286 if (63 == siocgnatl_cmd) {
287 struct natlookup *nlp = &natLookup;
288 x = ioctl(natfd, SIOCGNATL, &nlp);
290 x = ioctl(natfd, SIOCGNATL, &natLookup);
295 const auto xerrno = errno;
296 if (xerrno != ESRCH) {
297 debugs(89,
DBG_IMPORTANT,
"ERROR: IPF (IPFilter) NAT lookup failed: ioctl(SIOCGNATL) (v=" << IPFILTER_VERSION <<
"): " <<
xstrerr(xerrno));
302 debugs(89, 9,
"address: " << newConn);
305 #if HAVE_STRUCT_NATLOOKUP_NL_REALIPADDR_IN6
306 if (newConn->remote.isIPv6())
307 newConn->local = natLookup.nl_realipaddr.in6;
309 newConn->local = natLookup.nl_realipaddr.in4;
311 newConn->local = natLookup.nl_realip;
313 newConn->local.port(ntohs(natLookup.nl_realport));
314 debugs(89, 5,
"address NAT: " << newConn);
330 return UseInterceptionAddressesLookedUpEarlier(
"recent PF version", newConn);
334 struct pfioc_natlook nl;
335 static int pffd = -1;
338 pffd = open(
"/dev/pf", O_RDONLY);
341 const auto xerrno = errno;
346 memset(&nl, 0,
sizeof(
struct pfioc_natlook));
361 nl.proto = IPPROTO_TCP;
362 nl.direction = PF_OUT;
364 if (ioctl(pffd, DIOCNATLOOK, &nl)) {
365 const auto xerrno = errno;
366 if (xerrno != ENOENT) {
371 debugs(89, 9,
"address: " << newConn);
375 newConn->
local = nl.rdaddr.v6;
377 newConn->
local = nl.rdaddr.v4;
379 debugs(89, 5,
"address NAT: " << newConn);
392 debugs(89, 5,
"address BEGIN: me/client= " << aConn.
local <<
", destination/me= " << aConn.
remote);
396 return NetfilterInterception(newConn) || IpfwInterception(newConn) ||
397 PfInterception(newConn) || IpfInterception(newConn);
403 bool doneSuid =
false;
405 #if _SQUID_LINUX_ && defined(IP_TRANSPARENT) // Linux
406 # define soLevel SOL_IP
407 # define soFlag IP_TRANSPARENT
409 #elif defined(SO_BINDANY) // OpenBSD 4.7+ and NetBSD with PF
410 # define soLevel SOL_SOCKET
411 # define soFlag SO_BINDANY
415 #elif defined(IP_BINDANY) // FreeBSD with IPFW
416 # define soLevel IPPROTO_IP
417 # define soFlag IP_BINDANY
423 #if defined(soLevel) && defined(soFlag)
425 debugs(3, 3,
"Detect TPROXY support on port " << test);
428 debugs(3,
DBG_CRITICAL,
"Cannot use TPROXY for " << test <<
" because IPv6 support is disabled");
439 debugs(3, 3,
"...Probing for IPv6 TPROXY support.");
441 struct sockaddr_in6 tmp_ip6;
444 tmp.getSockAddr(tmp_ip6);
446 if ( (tmp_sock = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP)) >= 0 &&
447 setsockopt(tmp_sock, soLevel, soFlag, (
char *)&tos,
sizeof(
int)) == 0 &&
448 bind(tmp_sock, (
struct sockaddr*)&tmp_ip6,
sizeof(
struct sockaddr_in6)) == 0 ) {
450 debugs(3, 3,
"IPv6 TPROXY support detected. Using.");
471 debugs(3, 3,
"...Probing for IPv4 TPROXY support.");
473 struct sockaddr_in tmp_ip4;
476 tmp.getSockAddr(tmp_ip4);
478 if ( (tmp_sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) >= 0 &&
479 setsockopt(tmp_sock, soLevel, soFlag, (
char *)&tos,
sizeof(
int)) == 0 &&
480 bind(tmp_sock, (
struct sockaddr*)&tmp_ip4,
sizeof(
struct sockaddr_in)) == 0 ) {
482 debugs(3, 3,
"IPv4 TPROXY support detected. Using.");
494 debugs(3, 3,
"TPROXY setsockopt() not supported on this platform. Disabling TPROXY on port " << test);