]> git.ipfire.org Git - thirdparty/squid.git/blame - src/IPInterception.cc
Compile errors in auto-testing.
[thirdparty/squid.git] / src / IPInterception.cc
CommitLineData
c8be6d7b 1
2/*
6d96c80d 3 * $Id: IPInterception.cc,v 1.20 2008/02/05 22:38:24 amosjeffries Exp $
c8be6d7b 4 *
5 * DEBUG: section 89 NAT / IP Interception
6 * AUTHOR: Robert Collins
7 *
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
10 *
11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
33 *
34 */
35
36#include "squid.h"
37#include "clientStream.h"
68991eab 38#include "IPInterception.h"
9fed22b7 39#include "SquidTime.h"
c8be6d7b 40
41#if IPF_TRANSPARENT
42#if HAVE_SYS_IOCTL_H
43#include <sys/ioctl.h>
44#endif
e9e7c285 45#if HAVE_NETINET_TCP_H
c8be6d7b 46#include <netinet/tcp.h>
e9e7c285 47#endif
48#if HAVE_NET_IF_H
c8be6d7b 49#include <net/if.h>
e9e7c285 50#endif
dbc5782a 51#ifdef HAVE_IPL_H
52#include <ipl.h>
53#elif HAVE_NETINET_IPL_H
54#include <netinet/ipl.h>
55#endif
c8be6d7b 56#if HAVE_IP_FIL_COMPAT_H
57#include <ip_fil_compat.h>
58#elif HAVE_NETINET_IP_FIL_COMPAT_H
59#include <netinet/ip_fil_compat.h>
60#elif HAVE_IP_COMPAT_H
61#include <ip_compat.h>
62#elif HAVE_NETINET_IP_COMPAT_H
63#include <netinet/ip_compat.h>
64#endif
65#if HAVE_IP_FIL_H
66#include <ip_fil.h>
67#elif HAVE_NETINET_IP_FIL_H
68#include <netinet/ip_fil.h>
69#endif
70#if HAVE_IP_NAT_H
71#include <ip_nat.h>
72#elif HAVE_NETINET_IP_NAT_H
73#include <netinet/ip_nat.h>
74#endif
75#endif
76
77#if PF_TRANSPARENT
78#include <sys/types.h>
79#include <sys/socket.h>
80#include <sys/ioctl.h>
81#include <sys/fcntl.h>
82#include <net/if.h>
83#include <netinet/in.h>
84#include <net/pfvar.h>
85#endif
86
87#if LINUX_NETFILTER
88#include <linux/netfilter_ipv4.h>
89#endif
90
c8be6d7b 91#if IPF_TRANSPARENT
3f38a55e 92int
62e76326 93
cc192b50 94clientNatLookup(int fd, const IPAddress &me, const IPAddress &peer, IPAddress &dst)
3f38a55e 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}
202
3f38a55e 203#elif LINUX_NETFILTER
204int
cc192b50 205clientNatLookup(int fd, const IPAddress &me, const IPAddress &peer, IPAddress &dst)
3f38a55e 206{
cc192b50 207 dst = me;
208 if( !me.IsIPv4() ) return -1;
209 if( !peer.IsIPv4() ) return -1;
210
d6026916 211 static time_t last_reported = 0;
cc192b50 212 struct addrinfo *lookup = NULL;
213
214 dst.GetAddrInfo(lookup,AF_INET);
62e76326 215
cc192b50 216 if (getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, lookup->ai_addr, &lookup->ai_addrlen) != 0)
d6026916 217 {
cc192b50 218 dst.FreeAddrInfo(lookup);
219
d6026916 220 if (squid_curtime - last_reported > 60) {
6d96c80d 221 debugs(89, 1, "clientNatLookup: peer " << peer << " NF getsockopt(SO_ORIGINAL_DST) failed: " << xstrerror());
d6026916 222 last_reported = squid_curtime;
223 }
224
62e76326 225 return -1;
d6026916 226 }
cc192b50 227 dst = *lookup;
3f38a55e 228
cc192b50 229 dst.FreeAddrInfo(lookup);
62e76326 230
cc192b50 231 debugs(89, 5, "clientNatLookup: addr = " << dst << "");
232
233 if (me != dst)
62e76326 234 return 0;
3f38a55e 235 else
62e76326 236 return -1;
3f38a55e 237}
62e76326 238
c8be6d7b 239#elif PF_TRANSPARENT
3f38a55e 240int
62e76326 241
cc192b50 242clientNatLookup(int fd, const IPAddress &me, const IPAddress &peer, IPAddress dst)
3f38a55e 243{
62e76326 244
3f38a55e 245 struct pfioc_natlook nl;
246 static int pffd = -1;
d6026916 247 static time_t last_reported = 0;
62e76326 248
cc192b50 249 if( !me.IsIPv4() ) return -1;
250 if( !peer.IsIPv4() ) return -1;
251
62e76326 252 if (pffd < 0)
253 pffd = open("/dev/pf", O_RDWR);
254
c8be6d7b 255 if (pffd < 0)
62e76326 256 {
d6026916 257 if (squid_curtime - last_reported > 60) {
bf8fe701 258 debugs(89, 1, "clientNatLookup: PF open failed: " << xstrerror());
d6026916 259 last_reported = squid_curtime;
260 }
261
62e76326 262 return -1;
d6026916 263
c8be6d7b 264 }
62e76326 265
cc192b50 266 dst.SetEmpty();
62e76326 267
c8be6d7b 268 memset(&nl, 0, sizeof(struct pfioc_natlook));
cc192b50 269 peer.GetInAddr(nl.saddr.v4);
270 nl.sport = htons(peer.GetPort());
271
272 me.GetInAddr(nl.daddr.v4);
273 nl.dport = htons(me.GetPort());
274
c8be6d7b 275 nl.af = AF_INET;
276 nl.proto = IPPROTO_TCP;
277 nl.direction = PF_OUT;
62e76326 278
279 if (ioctl(pffd, DIOCNATLOOK, &nl))
280 {
281 if (errno != ENOENT) {
d6026916 282 if (squid_curtime - last_reported > 60) {
bf8fe701 283 debugs(89, 1, "clientNatLookup: PF lookup failed: ioctl(DIOCNATLOOK)");
d6026916 284 last_reported = squid_curtime;
285 }
286
62e76326 287 close(pffd);
288 pffd = -1;
289 }
290
291 return -1;
292 } else
293 {
cc192b50 294 int natted = (me != nl.rdaddr.v4);
295 dst = nl.rdaddr.v4;
296 dst.SetPort(ntohs(nl.rdport));
62e76326 297
298 if (natted)
299 return 0;
300 else
301 return -1;
3f38a55e 302 }
303}
62e76326 304
68075fad 305#elif IPFW_TRANSPARENT
3f38a55e 306int
cc192b50 307clientNatLookup(int fd, const IPAddress &me, const IPAddress &peer, IPAddress &dst)
3f38a55e 308{
cc192b50 309 int ret;
310 struct addrinfo *lookup = NULL;
311
312 if( !me.IsIPv4() ) return -1;
313 if( !peer.IsIPv4() ) return -1;
314
315 dst.GetAddrInfo(lookup,AF_INET);
316
317 ret = getsockname(fd, lookup->ai_addr, &lookup->ai_addrlen);
318
319 if (ret < 0) {
320
321 dst.FreeAddrInfo(lookup);
322
323 debugs(89, 1, "clientNatLookup: getpeername failed (fd " << fd << "), errstr " << xstrerror());
324
325 return -1;
326 }
327
328 dst = *lookup;
329
330 dst.FreeAddrInfo(lookup);
331
332 return 0;
c8be6d7b 333}
62e76326 334
68075fad 335#else
336int
cc192b50 337clientNatLookup(int fd, const IPAddress &me, const IPAddress &peer, IPAddress &dst)
68075fad 338{
cc192b50 339 debugs(89, 1, "WARNING: transparent proxying not supported");
340 return -1;
68075fad 341}
3f38a55e 342#endif
343