]> git.ipfire.org Git - thirdparty/squid.git/blame - src/IPInterception.cc
Transparent flag must be done before bind().
[thirdparty/squid.git] / src / IPInterception.cc
CommitLineData
c8be6d7b 1/*
6d96c80d 2 * $Id: IPInterception.cc,v 1.20 2008/02/05 22:38:24 amosjeffries Exp $
c8be6d7b 3 *
4 * DEBUG: section 89 NAT / IP Interception
5 * AUTHOR: Robert Collins
6 *
7 * SQUID Web Proxy Cache http://www.squid-cache.org/
8 * ----------------------------------------------------------
9 *
10 * Squid is the result of efforts by numerous individuals from
11 * the Internet community; see the CONTRIBUTORS file for full
12 * details. Many organizations have provided support for Squid's
13 * development; see the SPONSORS file for full details. Squid is
14 * Copyrighted (C) 2001 by the Regents of the University of
15 * California; see the COPYRIGHT file for full details. Squid
16 * incorporates software developed and/or copyrighted by other
17 * sources; see the CREDITS file for full details.
18 *
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
23 *
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
28 *
29 * You should have received a copy of the GNU General Public License
30 * along with this program; if not, write to the Free Software
31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
32 *
33 */
34
35#include "squid.h"
36#include "clientStream.h"
68991eab 37#include "IPInterception.h"
9fed22b7 38#include "SquidTime.h"
c8be6d7b 39
40#if IPF_TRANSPARENT
41#if HAVE_SYS_IOCTL_H
42#include <sys/ioctl.h>
43#endif
e9e7c285 44#if HAVE_NETINET_TCP_H
c8be6d7b 45#include <netinet/tcp.h>
e9e7c285 46#endif
47#if HAVE_NET_IF_H
c8be6d7b 48#include <net/if.h>
e9e7c285 49#endif
dbc5782a 50#ifdef HAVE_IPL_H
51#include <ipl.h>
52#elif HAVE_NETINET_IPL_H
53#include <netinet/ipl.h>
54#endif
c8be6d7b 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>
63#endif
64#if HAVE_IP_FIL_H
65#include <ip_fil.h>
66#elif HAVE_NETINET_IP_FIL_H
67#include <netinet/ip_fil.h>
68#endif
69#if HAVE_IP_NAT_H
70#include <ip_nat.h>
71#elif HAVE_NETINET_IP_NAT_H
72#include <netinet/ip_nat.h>
73#endif
74#endif
75
76#if PF_TRANSPARENT
77#include <sys/types.h>
78#include <sys/socket.h>
79#include <sys/ioctl.h>
80#include <sys/fcntl.h>
81#include <net/if.h>
82#include <netinet/in.h>
83#include <net/pfvar.h>
84#endif
85
86#if LINUX_NETFILTER
87#include <linux/netfilter_ipv4.h>
88#endif
89
3f38a55e 90int
cc192b50 91clientNatLookup(int fd, const IPAddress &me, const IPAddress &peer, IPAddress &dst)
3f38a55e 92{
f1e0717c
AJ
93
94#if IPF_TRANSPARENT /* --enable-ipf-transparent */
95
cc192b50 96 dst = me;
97 if( !me.IsIPv4() ) return -1;
98 if( !peer.IsIPv4() ) return -1;
62e76326 99
dbc5782a 100#if defined(IPFILTER_VERSION) && (IPFILTER_VERSION >= 4000027)
101
102 struct ipfobj obj;
08a746ab 103#else
104
105 static int siocgnatl_cmd = SIOCGNATL & 0xff;
106
dbc5782a 107#endif
108
c8be6d7b 109 struct natlookup natLookup;
110 static int natfd = -1;
d6026916 111 static time_t last_reported = 0;
c8be6d7b 112 int x;
3f38a55e 113
dbc5782a 114#if defined(IPFILTER_VERSION) && (IPFILTER_VERSION >= 4000027)
115
116 obj.ipfo_rev = IPFILTER_VERSION;
117 obj.ipfo_size = sizeof(natLookup);
118 obj.ipfo_ptr = &natLookup;
119 obj.ipfo_type = IPFOBJ_NATLOOKUP;
120 obj.ipfo_offset = 0;
121#endif
122
cc192b50 123 natLookup.nl_inport = htons(me.GetPort());
124 natLookup.nl_outport = htons(peer.GetPort());
125 me.GetInAddr(natLookup.nl_inip);
126 peer.GetInAddr(natLookup.nl_outip);
c8be6d7b 127 natLookup.nl_flags = IPN_TCP;
62e76326 128
129 if (natfd < 0)
130 {
131 int save_errno;
132 enter_suid();
dbc5782a 133#ifdef IPNAT_NAME
98a3bc99 134
dbc5782a 135 natfd = open(IPNAT_NAME, O_RDONLY, 0);
98a3bc99 136#else
137
62e76326 138 natfd = open(IPL_NAT, O_RDONLY, 0);
98a3bc99 139#endif
140
62e76326 141 save_errno = errno;
142 leave_suid();
143 errno = save_errno;
c8be6d7b 144 }
62e76326 145
146 if (natfd < 0)
147 {
d6026916 148 if (squid_curtime - last_reported > 60) {
bf8fe701 149 debugs(89, 1, "clientNatLookup: NAT open failed: " << xstrerror());
d6026916 150 last_reported = squid_curtime;
151 return -1;
152 }
c8be6d7b 153 }
62e76326 154
dbc5782a 155#if defined(IPFILTER_VERSION) && (IPFILTER_VERSION >= 4000027)
156 x = ioctl(natfd, SIOCGNATL, &obj);
157
158#else
3f38a55e 159 /*
dbc5782a 160 * IP-Filter changed the type for SIOCGNATL between
161 * 3.3 and 3.4. It also changed the cmd value for
162 * SIOCGNATL, so at least we can detect it. We could
163 * put something in configure and use ifdefs here, but
164 * this seems simpler.
165 */
62e76326 166 if (63 == siocgnatl_cmd)
167 {
168
169 struct natlookup *nlp = &natLookup;
170 x = ioctl(natfd, SIOCGNATL, &nlp);
171 } else
172 {
173 x = ioctl(natfd, SIOCGNATL, &natLookup);
174 }
175
dbc5782a 176#endif
62e76326 177 if (x < 0)
178 {
179 if (errno != ESRCH) {
d6026916 180 if (squid_curtime - last_reported > 60) {
bf8fe701 181 debugs(89, 1, "clientNatLookup: NAT lookup failed: ioctl(SIOCGNATL)");
d6026916 182 last_reported = squid_curtime;
183 }
184
62e76326 185 close(natfd);
186 natfd = -1;
187 }
188
189 return -1;
190 } else
191 {
cc192b50 192 if (me != natLookup.nl_realip) {
193 dst = natLookup.nl_realip;
62e76326 194
cc192b50 195 dst.SetPort(ntohs(natLookup.nl_realport));
196 }
197 // else. we already copied it.
62e76326 198
199 return 0;
c8be6d7b 200 }
62e76326 201
f1e0717c
AJ
202
203
204#elif LINUX_NETFILTER || LINUX_TPROXY4 /* --enable-linux-netfilter OR --enable-linux-tproxy4 */
205
cc192b50 206 dst = me;
207 if( !me.IsIPv4() ) return -1;
208 if( !peer.IsIPv4() ) return -1;
209
d6026916 210 static time_t last_reported = 0;
cc192b50 211 struct addrinfo *lookup = NULL;
212
213 dst.GetAddrInfo(lookup,AF_INET);
62e76326 214
f1e0717c 215#if LINUX_NETFILTER
cc192b50 216 if (getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, lookup->ai_addr, &lookup->ai_addrlen) != 0)
f1e0717c
AJ
217#elif LINUX_TPROXY4
218 if (getsockopt(fd, SOL_IP, IP_TRANSPARENT, lookup->ai_addr, &lookup->ai_addrlen) != 0)
219#endif
d6026916 220 {
cc192b50 221 dst.FreeAddrInfo(lookup);
222
d6026916 223 if (squid_curtime - last_reported > 60) {
f1e0717c 224 debugs(89, 1, "clientNatLookup: peer " << peer << " NF getsockopt(" << (LINUX_NETFILTER?"SO_ORIGINAL_DST":"IP_TRANSPARENT") << ") failed: " << xstrerror());
d6026916 225 last_reported = squid_curtime;
226 }
227
62e76326 228 return -1;
d6026916 229 }
cc192b50 230 dst = *lookup;
3f38a55e 231
cc192b50 232 dst.FreeAddrInfo(lookup);
62e76326 233
cc192b50 234 debugs(89, 5, "clientNatLookup: addr = " << dst << "");
235
236 if (me != dst)
62e76326 237 return 0;
3f38a55e 238 else
62e76326 239 return -1;
62e76326 240
62e76326 241
f1e0717c 242#elif PF_TRANSPARENT /* --enable-pf-transparent */
62e76326 243
3f38a55e 244 struct pfioc_natlook nl;
245 static int pffd = -1;
d6026916 246 static time_t last_reported = 0;
62e76326 247
cc192b50 248 if( !me.IsIPv4() ) return -1;
249 if( !peer.IsIPv4() ) return -1;
250
62e76326 251 if (pffd < 0)
252 pffd = open("/dev/pf", O_RDWR);
253
c8be6d7b 254 if (pffd < 0)
62e76326 255 {
d6026916 256 if (squid_curtime - last_reported > 60) {
bf8fe701 257 debugs(89, 1, "clientNatLookup: PF open failed: " << xstrerror());
d6026916 258 last_reported = squid_curtime;
259 }
260
62e76326 261 return -1;
d6026916 262
c8be6d7b 263 }
62e76326 264
cc192b50 265 dst.SetEmpty();
62e76326 266
c8be6d7b 267 memset(&nl, 0, sizeof(struct pfioc_natlook));
cc192b50 268 peer.GetInAddr(nl.saddr.v4);
269 nl.sport = htons(peer.GetPort());
270
271 me.GetInAddr(nl.daddr.v4);
272 nl.dport = htons(me.GetPort());
273
c8be6d7b 274 nl.af = AF_INET;
275 nl.proto = IPPROTO_TCP;
276 nl.direction = PF_OUT;
62e76326 277
278 if (ioctl(pffd, DIOCNATLOOK, &nl))
279 {
280 if (errno != ENOENT) {
d6026916 281 if (squid_curtime - last_reported > 60) {
bf8fe701 282 debugs(89, 1, "clientNatLookup: PF lookup failed: ioctl(DIOCNATLOOK)");
d6026916 283 last_reported = squid_curtime;
284 }
285
62e76326 286 close(pffd);
287 pffd = -1;
288 }
289
290 return -1;
291 } else
292 {
cc192b50 293 int natted = (me != nl.rdaddr.v4);
294 dst = nl.rdaddr.v4;
295 dst.SetPort(ntohs(nl.rdport));
62e76326 296
297 if (natted)
298 return 0;
299 else
300 return -1;
3f38a55e 301 }
62e76326 302
f1e0717c
AJ
303
304#elif IPFW_TRANSPARENT /* --enable-ipfw-transparent */
305
cc192b50 306 int ret;
307 struct addrinfo *lookup = NULL;
308
309 if( !me.IsIPv4() ) return -1;
310 if( !peer.IsIPv4() ) return -1;
311
312 dst.GetAddrInfo(lookup,AF_INET);
313
314 ret = getsockname(fd, lookup->ai_addr, &lookup->ai_addrlen);
315
316 if (ret < 0) {
317
318 dst.FreeAddrInfo(lookup);
319
320 debugs(89, 1, "clientNatLookup: getpeername failed (fd " << fd << "), errstr " << xstrerror());
321
322 return -1;
323 }
324
325 dst = *lookup;
326
327 dst.FreeAddrInfo(lookup);
328
329 return 0;
62e76326 330
f1e0717c
AJ
331
332#else /* none of the transparent options configured */
333
cc192b50 334 debugs(89, 1, "WARNING: transparent proxying not supported");
335 return -1;
f1e0717c 336
3f38a55e 337#endif
338
f1e0717c 339}