]>
Commit | Line | Data |
---|---|---|
c8be6d7b | 1 | /* |
26ac0430 | 2 | * DEBUG: section 89 NAT / IP Interception |
c8be6d7b | 3 | * AUTHOR: Robert Collins |
04f87469 | 4 | * AUTHOR: Amos Jeffries |
c8be6d7b | 5 | * |
6 | * SQUID Web Proxy Cache http://www.squid-cache.org/ | |
7 | * ---------------------------------------------------------- | |
8 | * | |
9 | * Squid is the result of efforts by numerous individuals from | |
10 | * the Internet community; see the CONTRIBUTORS file for full | |
11 | * details. Many organizations have provided support for Squid's | |
12 | * development; see the SPONSORS file for full details. Squid is | |
13 | * Copyrighted (C) 2001 by the Regents of the University of | |
14 | * California; see the COPYRIGHT file for full details. Squid | |
15 | * incorporates software developed and/or copyrighted by other | |
16 | * sources; see the CREDITS file for full details. | |
17 | * | |
18 | * This program is free software; you can redistribute it and/or modify | |
19 | * it under the terms of the GNU General Public License as published by | |
20 | * the Free Software Foundation; either version 2 of the License, or | |
21 | * (at your option) any later version. | |
26ac0430 | 22 | * |
c8be6d7b | 23 | * This program is distributed in the hope that it will be useful, |
24 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
25 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
26 | * GNU General Public License for more details. | |
26ac0430 | 27 | * |
c8be6d7b | 28 | * You should have received a copy of the GNU General Public License |
29 | * along with this program; if not, write to the Free Software | |
30 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. | |
31 | * | |
32 | */ | |
a74968c2 | 33 | #include "config.h" |
b0dfd10b | 34 | #include "ip/IpIntercept.h" |
b3166404 | 35 | #include "fde.h" |
fc27cd70 | 36 | |
c8be6d7b | 37 | #if IPF_TRANSPARENT |
34ec5c62 | 38 | |
c8be6d7b | 39 | #if HAVE_SYS_IOCTL_H |
40 | #include <sys/ioctl.h> | |
41 | #endif | |
e9e7c285 | 42 | #if HAVE_NETINET_TCP_H |
c8be6d7b | 43 | #include <netinet/tcp.h> |
e9e7c285 | 44 | #endif |
45 | #if HAVE_NET_IF_H | |
c8be6d7b | 46 | #include <net/if.h> |
e9e7c285 | 47 | #endif |
b0dfd10b | 48 | #if HAVE_IPL_H |
dbc5782a | 49 | #include <ipl.h> |
50 | #elif HAVE_NETINET_IPL_H | |
51 | #include <netinet/ipl.h> | |
52 | #endif | |
c8be6d7b | 53 | #if HAVE_IP_FIL_COMPAT_H |
54 | #include <ip_fil_compat.h> | |
55 | #elif HAVE_NETINET_IP_FIL_COMPAT_H | |
56 | #include <netinet/ip_fil_compat.h> | |
57 | #elif HAVE_IP_COMPAT_H | |
58 | #include <ip_compat.h> | |
59 | #elif HAVE_NETINET_IP_COMPAT_H | |
60 | #include <netinet/ip_compat.h> | |
61 | #endif | |
62 | #if HAVE_IP_FIL_H | |
63 | #include <ip_fil.h> | |
64 | #elif HAVE_NETINET_IP_FIL_H | |
65 | #include <netinet/ip_fil.h> | |
66 | #endif | |
67 | #if HAVE_IP_NAT_H | |
68 | #include <ip_nat.h> | |
69 | #elif HAVE_NETINET_IP_NAT_H | |
70 | #include <netinet/ip_nat.h> | |
71 | #endif | |
34ec5c62 AJ |
72 | |
73 | #endif /* IPF_TRANSPARENT required headers */ | |
c8be6d7b | 74 | |
75 | #if PF_TRANSPARENT | |
c8be6d7b | 76 | #include <sys/socket.h> |
77 | #include <sys/ioctl.h> | |
78 | #include <sys/fcntl.h> | |
79 | #include <net/if.h> | |
80 | #include <netinet/in.h> | |
b0dfd10b | 81 | #if HAVE_NET_PF_PFVAR_H |
ec9909b0 AJ |
82 | #include <net/pf/pfvar.h> |
83 | #endif /* HAVE_NET_PF_PFVAR_H */ | |
b0dfd10b | 84 | #if HAVE_NET_PFVAR_H |
c8be6d7b | 85 | #include <net/pfvar.h> |
ec9909b0 | 86 | #endif /* HAVE_NET_PFVAR_H */ |
34ec5c62 | 87 | #endif /* PF_TRANSPARENT required headers */ |
c8be6d7b | 88 | |
89 | #if LINUX_NETFILTER | |
90 | #include <linux/netfilter_ipv4.h> | |
91 | #endif | |
92 | ||
34ec5c62 | 93 | #if LINUX_TPROXY2 |
b0dfd10b | 94 | #if HAVE_LINUX_NETFILTER_IPV4_IP_TPROXY_H |
34ec5c62 AJ |
95 | #include <linux/netfilter_ipv4/ip_tproxy.h> |
96 | #else | |
97 | #error " TPROXY v2 Header file missing: linux/netfilter_ipv4/ip_tproxy.h. Perhapse you meant to use TPROXY v4 ? " | |
98 | #endif | |
99 | #endif | |
100 | ||
0fc2952e AJ |
101 | |
102 | // single global instance for access by other components. | |
85944c1c | 103 | IpIntercept IpInterceptor; |
0fc2952e | 104 | |
04f87469 | 105 | void |
85944c1c | 106 | IpIntercept::StopTransparency(const char *str) |
26ac0430 AJ |
107 | { |
108 | if (transparent_active) { | |
788625af AJ |
109 | debugs(89, DBG_IMPORTANT, "Stopping full transparency: " << str); |
110 | transparent_active = 0; | |
111 | } | |
04f87469 AJ |
112 | } |
113 | ||
114 | void | |
85944c1c | 115 | IpIntercept::StopInterception(const char *str) |
26ac0430 AJ |
116 | { |
117 | if (intercept_active) { | |
788625af AJ |
118 | debugs(89, DBG_IMPORTANT, "Stopping IP interception: " << str); |
119 | intercept_active = 0; | |
120 | } | |
04f87469 | 121 | } |
0fc2952e | 122 | |
7b0a0d1f | 123 | int |
23f6a720 | 124 | IpIntercept::NetfilterInterception(int fd, const IpAddress &me, IpAddress &dst, int silent) |
7b0a0d1f AJ |
125 | { |
126 | #if LINUX_NETFILTER | |
7b0a0d1f AJ |
127 | struct addrinfo *lookup = NULL; |
128 | ||
129 | dst.GetAddrInfo(lookup,AF_INET); | |
130 | ||
131 | /** \par | |
132 | * Try NAT lookup for REDIRECT or DNAT targets. */ | |
fa71b867 | 133 | if ( getsockopt(fd, IPPROTO_IP, SO_ORIGINAL_DST, lookup->ai_addr, &lookup->ai_addrlen) != 0) { |
26ac0430 | 134 | if (!silent) { |
d6ae5979 | 135 | debugs(89, DBG_IMPORTANT, HERE << " NF getsockopt(SO_ORIGINAL_DST) failed on FD " << fd << ": " << xstrerror()); |
7b0a0d1f AJ |
136 | last_reported = squid_curtime; |
137 | } | |
26ac0430 | 138 | } else { |
7b0a0d1f AJ |
139 | dst = *lookup; |
140 | } | |
141 | ||
142 | dst.FreeAddrInfo(lookup); | |
143 | ||
26ac0430 | 144 | if (me != dst) { |
e9172f79 | 145 | debugs(89, 5, HERE << "address NAT: me= " << me << ", dst= " << dst); |
7b0a0d1f AJ |
146 | return 0; |
147 | } | |
148 | ||
83707d8a | 149 | debugs(89, 9, HERE << "address: me= " << me << ", dst= " << dst); |
7b0a0d1f AJ |
150 | #endif |
151 | return -1; | |
152 | } | |
153 | ||
154 | int | |
23f6a720 | 155 | IpIntercept::NetfilterTransparent(int fd, const IpAddress &me, IpAddress &client, int silent) |
7b0a0d1f AJ |
156 | { |
157 | #if LINUX_NETFILTER | |
7b0a0d1f | 158 | |
acaa7194 AJ |
159 | /* Trust the user configured properly. If not no harm done. |
160 | * We will simply attempt a bind outgoing on our own IP. | |
acaa7194 | 161 | */ |
26ac0430 | 162 | if (fd_table[fd].flags.transparent) { |
482a5c64 | 163 | client.SetPort(0); // allow random outgoing port to prevent address clashes |
e9172f79 | 164 | debugs(89, 5, HERE << "address TPROXY: me= " << me << ", client= " << client); |
68d57d84 AJ |
165 | return 0; |
166 | } | |
219f8edb | 167 | |
e9172f79 | 168 | debugs(89, 9, HERE << "address: me= " << me << ", client= " << client); |
acaa7194 | 169 | #endif |
68d57d84 | 170 | return -1; |
7b0a0d1f AJ |
171 | } |
172 | ||
d8b5bcbc | 173 | int |
23f6a720 | 174 | IpIntercept::IpfwInterception(int fd, const IpAddress &me, IpAddress &dst, int silent) |
d8b5bcbc AJ |
175 | { |
176 | #if IPFW_TRANSPARENT | |
177 | struct addrinfo *lookup = NULL; | |
178 | ||
179 | dst.GetAddrInfo(lookup,AF_INET); | |
180 | ||
181 | /** \par | |
182 | * Try lookup for IPFW interception. */ | |
26ac0430 AJ |
183 | if ( getsockname(fd, lookup->ai_addr, &lookup->ai_addrlen) != 0 ) { |
184 | if ( !silent ) { | |
d8b5bcbc AJ |
185 | debugs(89, DBG_IMPORTANT, HERE << " IPFW getsockname(...) failed: " << xstrerror()); |
186 | last_reported = squid_curtime; | |
187 | } | |
26ac0430 | 188 | } else { |
d8b5bcbc AJ |
189 | dst = *lookup; |
190 | } | |
191 | ||
192 | dst.FreeAddrInfo(lookup); | |
193 | ||
26ac0430 | 194 | if (me != dst) { |
e9172f79 | 195 | debugs(89, 5, HERE << "address NAT: me= " << me << ", dst= " << dst); |
d8b5bcbc AJ |
196 | return 0; |
197 | } | |
198 | ||
199 | debugs(89, 9, HERE << "address: me= " << me << ", dst= " << dst); | |
200 | #endif | |
201 | return -1; | |
202 | } | |
0fc2952e | 203 | |
3f38a55e | 204 | int |
e9172f79 | 205 | IpIntercept::IpfInterception(int fd, const IpAddress &me, IpAddress &client, IpAddress &dst, int silent) |
3f38a55e | 206 | { |
f1e0717c | 207 | #if IPF_TRANSPARENT /* --enable-ipf-transparent */ |
62e76326 | 208 | |
dbc5782a | 209 | #if defined(IPFILTER_VERSION) && (IPFILTER_VERSION >= 4000027) |
dbc5782a | 210 | struct ipfobj obj; |
08a746ab | 211 | #else |
08a746ab | 212 | static int siocgnatl_cmd = SIOCGNATL & 0xff; |
dbc5782a | 213 | #endif |
c8be6d7b | 214 | struct natlookup natLookup; |
215 | static int natfd = -1; | |
c8be6d7b | 216 | int x; |
3f38a55e | 217 | |
dbc5782a | 218 | #if defined(IPFILTER_VERSION) && (IPFILTER_VERSION >= 4000027) |
219 | ||
220 | obj.ipfo_rev = IPFILTER_VERSION; | |
221 | obj.ipfo_size = sizeof(natLookup); | |
222 | obj.ipfo_ptr = &natLookup; | |
223 | obj.ipfo_type = IPFOBJ_NATLOOKUP; | |
224 | obj.ipfo_offset = 0; | |
225 | #endif | |
226 | ||
cc192b50 | 227 | natLookup.nl_inport = htons(me.GetPort()); |
219f8edb | 228 | natLookup.nl_outport = htons(dst.GetPort()); |
cc192b50 | 229 | me.GetInAddr(natLookup.nl_inip); |
f24fa88d | 230 | dst.GetInAddr(natLookup.nl_outip); |
c8be6d7b | 231 | natLookup.nl_flags = IPN_TCP; |
62e76326 | 232 | |
26ac0430 | 233 | if (natfd < 0) { |
62e76326 | 234 | int save_errno; |
235 | enter_suid(); | |
dbc5782a | 236 | #ifdef IPNAT_NAME |
dbc5782a | 237 | natfd = open(IPNAT_NAME, O_RDONLY, 0); |
98a3bc99 | 238 | #else |
62e76326 | 239 | natfd = open(IPL_NAT, O_RDONLY, 0); |
98a3bc99 | 240 | #endif |
62e76326 | 241 | save_errno = errno; |
242 | leave_suid(); | |
243 | errno = save_errno; | |
c8be6d7b | 244 | } |
62e76326 | 245 | |
26ac0430 | 246 | if (natfd < 0) { |
219f8edb | 247 | if (!silent) { |
e9172f79 | 248 | debugs(89, DBG_IMPORTANT, HERE << "NAT open failed: " << xstrerror()); |
d6026916 | 249 | last_reported = squid_curtime; |
250 | return -1; | |
251 | } | |
c8be6d7b | 252 | } |
62e76326 | 253 | |
dbc5782a | 254 | #if defined(IPFILTER_VERSION) && (IPFILTER_VERSION >= 4000027) |
255 | x = ioctl(natfd, SIOCGNATL, &obj); | |
dbc5782a | 256 | #else |
3f38a55e | 257 | /* |
dbc5782a | 258 | * IP-Filter changed the type for SIOCGNATL between |
259 | * 3.3 and 3.4. It also changed the cmd value for | |
260 | * SIOCGNATL, so at least we can detect it. We could | |
261 | * put something in configure and use ifdefs here, but | |
262 | * this seems simpler. | |
263 | */ | |
26ac0430 | 264 | if (63 == siocgnatl_cmd) { |
62e76326 | 265 | struct natlookup *nlp = &natLookup; |
266 | x = ioctl(natfd, SIOCGNATL, &nlp); | |
26ac0430 | 267 | } else { |
62e76326 | 268 | x = ioctl(natfd, SIOCGNATL, &natLookup); |
269 | } | |
270 | ||
dbc5782a | 271 | #endif |
26ac0430 | 272 | if (x < 0) { |
62e76326 | 273 | if (errno != ESRCH) { |
219f8edb | 274 | if (!silent) { |
e9172f79 | 275 | debugs(89, DBG_IMPORTANT, HERE << "NAT lookup failed: ioctl(SIOCGNATL)"); |
d6026916 | 276 | last_reported = squid_curtime; |
277 | } | |
278 | ||
62e76326 | 279 | close(natfd); |
280 | natfd = -1; | |
281 | } | |
282 | ||
283 | return -1; | |
26ac0430 | 284 | } else { |
e9172f79 AJ |
285 | if (client != natLookup.nl_realip) { |
286 | client = natLookup.nl_realip; | |
287 | client.SetPort(ntohs(natLookup.nl_realport)); | |
cc192b50 | 288 | } |
289 | // else. we already copied it. | |
62e76326 | 290 | |
e9172f79 | 291 | debugs(89, 5, HERE << "address NAT: me= " << me << ", client= " << client << ", dst= " << dst); |
62e76326 | 292 | return 0; |
c8be6d7b | 293 | } |
62e76326 | 294 | |
e9172f79 | 295 | debugs(89, 9, HERE << "address: me= " << me << ", client= " << client << ", dst= " << dst); |
219f8edb AJ |
296 | |
297 | #endif /* --enable-ipf-transparent */ | |
298 | return -1; | |
299 | } | |
f1e0717c | 300 | |
219f8edb | 301 | int |
e9172f79 | 302 | IpIntercept::PfInterception(int fd, const IpAddress &me, IpAddress &client, IpAddress &dst, int silent) |
219f8edb | 303 | { |
51f4d36b | 304 | #if PF_TRANSPARENT /* --enable-pf-transparent */ |
62e76326 | 305 | |
3f38a55e | 306 | struct pfioc_natlook nl; |
307 | static int pffd = -1; | |
62e76326 | 308 | |
309 | if (pffd < 0) | |
d14c6ef2 | 310 | pffd = open("/dev/pf", O_RDONLY); |
62e76326 | 311 | |
26ac0430 | 312 | if (pffd < 0) { |
51f4d36b | 313 | if (!silent) { |
e9172f79 | 314 | debugs(89, DBG_IMPORTANT, HERE << "PF open failed: " << xstrerror()); |
d6026916 | 315 | last_reported = squid_curtime; |
316 | } | |
62e76326 | 317 | return -1; |
c8be6d7b | 318 | } |
62e76326 | 319 | |
c8be6d7b | 320 | memset(&nl, 0, sizeof(struct pfioc_natlook)); |
51f4d36b AJ |
321 | dst.GetInAddr(nl.saddr.v4); |
322 | nl.sport = htons(dst.GetPort()); | |
cc192b50 | 323 | |
e9172f79 AJ |
324 | me.GetInAddr(nl.daddr.v4); |
325 | nl.dport = htons(me.GetPort()); | |
cc192b50 | 326 | |
c8be6d7b | 327 | nl.af = AF_INET; |
328 | nl.proto = IPPROTO_TCP; | |
329 | nl.direction = PF_OUT; | |
62e76326 | 330 | |
26ac0430 | 331 | if (ioctl(pffd, DIOCNATLOOK, &nl)) { |
62e76326 | 332 | if (errno != ENOENT) { |
51f4d36b | 333 | if (!silent) { |
e9172f79 | 334 | debugs(89, DBG_IMPORTANT, HERE << "PF lookup failed: ioctl(DIOCNATLOOK)"); |
d6026916 | 335 | last_reported = squid_curtime; |
336 | } | |
62e76326 | 337 | close(pffd); |
338 | pffd = -1; | |
339 | } | |
26ac0430 | 340 | } else { |
51f4d36b | 341 | int natted = (client != nl.rdaddr.v4); |
482a5c64 AJ |
342 | client = nl.rdaddr.v4; |
343 | client.SetPort(ntohs(nl.rdport)); | |
62e76326 | 344 | |
e9172f79 AJ |
345 | if (natted) { |
346 | debugs(89, 5, HERE << "address NAT: me= " << me << ", client= " << client << ", dst= " << dst); | |
62e76326 | 347 | return 0; |
e9172f79 | 348 | } |
3f38a55e | 349 | } |
62e76326 | 350 | |
e9172f79 | 351 | debugs(89, 9, HERE << "address: me= " << me << ", client= " << client << ", dst= " << dst); |
f1e0717c | 352 | |
51f4d36b | 353 | #endif /* --enable-pf-transparent */ |
cc192b50 | 354 | return -1; |
51f4d36b AJ |
355 | } |
356 | ||
357 | ||
358 | int | |
359 | IpIntercept::NatLookup(int fd, const IpAddress &me, const IpAddress &peer, IpAddress &client, IpAddress &dst) | |
360 | { | |
af6a12ee AJ |
361 | /* --enable-linux-netfilter */ |
362 | /* --enable-ipfw-transparent */ | |
363 | /* --enable-ipf-transparent */ | |
364 | /* --enable-pf-transparent */ | |
51f4d36b AJ |
365 | #if IPF_TRANSPARENT || LINUX_NETFILTER || IPFW_TRANSPARENT || PF_TRANSPARENT |
366 | ||
51f4d36b AJ |
367 | client = me; |
368 | dst = peer; | |
369 | ||
51f4d36b AJ |
370 | #if 0 |
371 | // Crop interception errors down to one per minute. | |
372 | int silent = (squid_curtime - last_reported > 60 ? 0 : 1); | |
373 | #else | |
374 | // Show all interception errors. | |
375 | int silent = 0; | |
376 | #endif | |
377 | ||
e9172f79 AJ |
378 | debugs(89, 5, HERE << "address BEGIN: me= " << me << ", client= " << client << |
379 | ", dst= " << dst << ", peer= " << peer); | |
380 | ||
9bad3e09 AJ |
381 | /* NP: try TPROXY first, its much quieter than NAT when non-matching */ |
382 | if (transparent_active) { | |
383 | if ( NetfilterTransparent(fd, me, dst, silent) == 0) return 0; | |
384 | } | |
385 | ||
b9420956 | 386 | /* NAT is only available in IPv4 */ |
11298d0d AJ |
387 | if ( !me.IsIPv4() ) return -1; |
388 | if ( !peer.IsIPv4() ) return -1; | |
389 | ||
51f4d36b | 390 | if (intercept_active) { |
e9172f79 | 391 | /* NAT methods that use sock-opts to return client address */ |
51f4d36b AJ |
392 | if ( NetfilterInterception(fd, me, client, silent) == 0) return 0; |
393 | if ( IpfwInterception(fd, me, client, silent) == 0) return 0; | |
e9172f79 AJ |
394 | |
395 | /* NAT methods that use ioctl to return client address AND destination address */ | |
396 | if ( PfInterception(fd, me, client, dst, silent) == 0) return 0; | |
397 | if ( IpfInterception(fd, me, client, dst, silent) == 0) return 0; | |
51f4d36b | 398 | } |
f1e0717c | 399 | |
51f4d36b | 400 | #else /* none of the transparent options configured */ |
e9172f79 | 401 | debugs(89, DBG_IMPORTANT, "WARNING: transparent proxying not supported"); |
3f38a55e | 402 | #endif |
403 | ||
51f4d36b | 404 | return -1; |
f1e0717c | 405 | } |
34ec5c62 AJ |
406 | |
407 | #if LINUX_TPROXY2 | |
f8c3e85e | 408 | int |
565b233e | 409 | IpIntercept::SetTproxy2OutgoingAddr(int fd, const IpAddress &src) |
34ec5c62 | 410 | { |
565b233e | 411 | IpAddress addr; |
34ec5c62 AJ |
412 | struct in_tproxy itp; |
413 | ||
414 | src.GetInAddr(itp.v.addr.faddr); | |
415 | itp.v.addr.fport = 0; | |
416 | ||
417 | /* If these syscalls fail then we just fallback to connecting | |
418 | * normally by simply ignoring the errors... | |
419 | */ | |
420 | itp.op = TPROXY_ASSIGN; | |
421 | ||
422 | addr = (struct in_addr)itp.v.addr.faddr; | |
423 | addr.SetPort(itp.v.addr.fport); | |
424 | ||
425 | if (setsockopt(fd, SOL_IP, IP_TPROXY, &itp, sizeof(itp)) == -1) { | |
426 | debugs(20, 1, "tproxy ip=" << addr << " ERROR ASSIGN"); | |
427 | return -1; | |
428 | } else { | |
429 | itp.op = TPROXY_FLAGS; | |
430 | itp.v.flags = ITP_CONNECT; | |
431 | ||
432 | if (setsockopt(fd, SOL_IP, IP_TPROXY, &itp, sizeof(itp)) == -1) { | |
433 | debugs(20, 1, "tproxy ip=" << addr << " ERROR CONNECT"); | |
434 | return -1; | |
435 | } | |
436 | } | |
437 | ||
438 | return 0; | |
439 | } | |
440 | #endif | |
263f84f0 AJ |
441 | |
442 | bool | |
443 | IpIntercept::ProbeForTproxy(IpAddress &test) | |
444 | { | |
445 | debugs(3, 3, "Detect TPROXY support on port " << test); | |
446 | #if LINUX_TPROXY2 | |
447 | ||
448 | #if USE_IPV6 | |
f54f527e AJ |
449 | /* TPROXYv2 is not IPv6 capable. Force wildcard sockets to IPv4. Die on IPv6 IPs */ |
450 | debugs(3, DBG_IMPORTANT, "Disabling IPv6 on port " << test << " (TPROXYv2 interception enabled)"); | |
451 | if ( test.IsIPv6() && !test.SetIPv4() ) { | |
452 | debugs(3, DBG_CRITICAL, "IPv6 requires TPROXYv4 support. You only have TPROXYv2 for " << test ); | |
453 | return false; | |
454 | } | |
263f84f0 AJ |
455 | #endif /* USE_IPV6 */ |
456 | return true; | |
457 | ||
458 | #else /* not LINUX_TPROXY2 */ | |
459 | ||
460 | #if defined(IP_TRANSPARENT) | |
461 | ||
462 | int tos = 1; | |
463 | int tmp_sock = -1; | |
464 | ||
465 | #if USE_IPV6 | |
466 | /* Probe to see if the Kernel TPROXY support is IPv6-enabled */ | |
467 | if (test.IsIPv6()) { | |
468 | debugs(3, 3, "...Probing for IPv6 TPROXY support."); | |
469 | ||
470 | struct sockaddr_in6 tmp_ip6; | |
471 | IpAddress tmp = "::2"; | |
472 | tmp.SetPort(0); | |
473 | tmp.GetSockAddr(tmp_ip6); | |
474 | ||
475 | if ( (tmp_sock = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP)) >= 0 && | |
f54f527e AJ |
476 | setsockopt(tmp_sock, SOL_IP, IP_TRANSPARENT, (char *)&tos, sizeof(int)) == 0 && |
477 | bind(tmp_sock, (struct sockaddr*)&tmp_ip6, sizeof(struct sockaddr_in6)) == 0 ) { | |
263f84f0 AJ |
478 | |
479 | debugs(3, 3, "IPv6 TPROXY support detected. Using."); | |
fb5bffa3 | 480 | close(tmp_sock); |
263f84f0 AJ |
481 | return true; |
482 | } | |
483 | if (tmp_sock >= 0) { | |
fb5bffa3 | 484 | close(tmp_sock); |
263f84f0 AJ |
485 | tmp_sock = -1; |
486 | } | |
487 | } | |
488 | ||
489 | if ( test.IsIPv6() && !test.SetIPv4() ) { | |
490 | debugs(3, DBG_CRITICAL, "TPROXY lacks IPv6 support for " << test ); | |
491 | return false; | |
492 | } | |
493 | #endif | |
494 | ||
495 | /* Probe to see if the Kernel TPROXY support is IPv4-enabled (aka present) */ | |
496 | if (test.IsIPv4()) { | |
497 | debugs(3, 3, "...Probing for IPv4 TPROXY support."); | |
498 | ||
499 | struct sockaddr_in tmp_ip4; | |
500 | IpAddress tmp = "127.0.0.2"; | |
501 | tmp.SetPort(0); | |
502 | tmp.GetSockAddr(tmp_ip4); | |
503 | ||
504 | if ( (tmp_sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) >= 0 && | |
f54f527e AJ |
505 | setsockopt(tmp_sock, SOL_IP, IP_TRANSPARENT, (char *)&tos, sizeof(int)) == 0 && |
506 | bind(tmp_sock, (struct sockaddr*)&tmp_ip4, sizeof(struct sockaddr_in)) == 0 ) { | |
263f84f0 AJ |
507 | |
508 | debugs(3, 3, "IPv4 TPROXY support detected. Using."); | |
fb5bffa3 | 509 | close(tmp_sock); |
263f84f0 AJ |
510 | return true; |
511 | } | |
512 | if (tmp_sock >= 0) { | |
fb5bffa3 | 513 | close(tmp_sock); |
263f84f0 AJ |
514 | } |
515 | } | |
516 | ||
517 | #else /* undefined IP_TRANSPARENT */ | |
518 | debugs(3, 3, "setsockopt(IP_TRANSPARENT) not supported on this platform. Disabling TPROXYv4."); | |
519 | #endif | |
520 | #endif /* LINUX_TPROXY2 */ | |
521 | return false; | |
522 | } |