]> git.ipfire.org Git - thirdparty/squid.git/blame - src/IPInterception.cc
Extended the Squid -> Rewriter interface with key=value pairs
[thirdparty/squid.git] / src / IPInterception.cc
CommitLineData
c8be6d7b 1
2/*
68075fad 3 * $Id: IPInterception.cc,v 1.17 2007/05/20 04:22:45 adrian 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
45#include <netinet/tcp.h>
46#include <net/if.h>
dbc5782a 47#ifdef HAVE_IPL_H
48#include <ipl.h>
49#elif HAVE_NETINET_IPL_H
50#include <netinet/ipl.h>
51#endif
c8be6d7b 52#if HAVE_IP_FIL_COMPAT_H
53#include <ip_fil_compat.h>
54#elif HAVE_NETINET_IP_FIL_COMPAT_H
55#include <netinet/ip_fil_compat.h>
56#elif HAVE_IP_COMPAT_H
57#include <ip_compat.h>
58#elif HAVE_NETINET_IP_COMPAT_H
59#include <netinet/ip_compat.h>
60#endif
61#if HAVE_IP_FIL_H
62#include <ip_fil.h>
63#elif HAVE_NETINET_IP_FIL_H
64#include <netinet/ip_fil.h>
65#endif
66#if HAVE_IP_NAT_H
67#include <ip_nat.h>
68#elif HAVE_NETINET_IP_NAT_H
69#include <netinet/ip_nat.h>
70#endif
71#endif
72
73#if PF_TRANSPARENT
74#include <sys/types.h>
75#include <sys/socket.h>
76#include <sys/ioctl.h>
77#include <sys/fcntl.h>
78#include <net/if.h>
79#include <netinet/in.h>
80#include <net/pfvar.h>
81#endif
82
83#if LINUX_NETFILTER
84#include <linux/netfilter_ipv4.h>
85#endif
86
c8be6d7b 87#if IPF_TRANSPARENT
3f38a55e 88int
62e76326 89
3f38a55e 90clientNatLookup(int fd, struct sockaddr_in me, struct sockaddr_in peer, struct sockaddr_in *dst)
91{
62e76326 92
dbc5782a 93#if defined(IPFILTER_VERSION) && (IPFILTER_VERSION >= 4000027)
94
95 struct ipfobj obj;
08a746ab 96#else
97
98 static int siocgnatl_cmd = SIOCGNATL & 0xff;
99
dbc5782a 100#endif
101
c8be6d7b 102 struct natlookup natLookup;
103 static int natfd = -1;
d6026916 104 static time_t last_reported = 0;
c8be6d7b 105 int x;
3f38a55e 106
dbc5782a 107#if defined(IPFILTER_VERSION) && (IPFILTER_VERSION >= 4000027)
108
109 obj.ipfo_rev = IPFILTER_VERSION;
110 obj.ipfo_size = sizeof(natLookup);
111 obj.ipfo_ptr = &natLookup;
112 obj.ipfo_type = IPFOBJ_NATLOOKUP;
113 obj.ipfo_offset = 0;
114#endif
115
c8be6d7b 116 natLookup.nl_inport = me.sin_port;
117 natLookup.nl_outport = peer.sin_port;
118 natLookup.nl_inip = me.sin_addr;
119 natLookup.nl_outip = peer.sin_addr;
120 natLookup.nl_flags = IPN_TCP;
62e76326 121
122 if (natfd < 0)
123 {
124 int save_errno;
125 enter_suid();
dbc5782a 126#ifdef IPNAT_NAME
98a3bc99 127
dbc5782a 128 natfd = open(IPNAT_NAME, O_RDONLY, 0);
98a3bc99 129#else
130
62e76326 131 natfd = open(IPL_NAT, O_RDONLY, 0);
98a3bc99 132#endif
133
62e76326 134 save_errno = errno;
135 leave_suid();
136 errno = save_errno;
c8be6d7b 137 }
62e76326 138
139 if (natfd < 0)
140 {
d6026916 141 if (squid_curtime - last_reported > 60) {
bf8fe701 142 debugs(89, 1, "clientNatLookup: NAT open failed: " << xstrerror());
d6026916 143 last_reported = squid_curtime;
144 return -1;
145 }
c8be6d7b 146 }
62e76326 147
dbc5782a 148#if defined(IPFILTER_VERSION) && (IPFILTER_VERSION >= 4000027)
149 x = ioctl(natfd, SIOCGNATL, &obj);
150
151#else
3f38a55e 152 /*
dbc5782a 153 * IP-Filter changed the type for SIOCGNATL between
154 * 3.3 and 3.4. It also changed the cmd value for
155 * SIOCGNATL, so at least we can detect it. We could
156 * put something in configure and use ifdefs here, but
157 * this seems simpler.
158 */
62e76326 159 if (63 == siocgnatl_cmd)
160 {
161
162 struct natlookup *nlp = &natLookup;
163 x = ioctl(natfd, SIOCGNATL, &nlp);
164 } else
165 {
166 x = ioctl(natfd, SIOCGNATL, &natLookup);
167 }
168
dbc5782a 169#endif
62e76326 170 if (x < 0)
171 {
172 if (errno != ESRCH) {
d6026916 173 if (squid_curtime - last_reported > 60) {
bf8fe701 174 debugs(89, 1, "clientNatLookup: NAT lookup failed: ioctl(SIOCGNATL)");
d6026916 175 last_reported = squid_curtime;
176 }
177
62e76326 178 close(natfd);
179 natfd = -1;
180 }
181
182 return -1;
183 } else
184 {
185 if (me.sin_addr.s_addr != natLookup.nl_realip.s_addr)
186 dst->sin_family = AF_INET;
187
188 dst->sin_port = natLookup.nl_realport;
189
190 dst->sin_addr = natLookup.nl_realip;
191
192 return 0;
c8be6d7b 193 }
62e76326 194}
195
3f38a55e 196#elif LINUX_NETFILTER
197int
62e76326 198
3f38a55e 199clientNatLookup(int fd, struct sockaddr_in me, struct sockaddr_in peer, struct sockaddr_in *dst)
200{
d6026916 201 static time_t last_reported = 0;
138ec663 202 socklen_t sock_sz = sizeof(*dst);
3f38a55e 203 memcpy(dst, &me, sizeof(*dst));
62e76326 204
3f38a55e 205 if (getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, dst, &sock_sz) != 0)
d6026916 206 {
207 if (squid_curtime - last_reported > 60) {
bf8fe701 208 debugs(89, 1, "clientNatLookup: NF getsockopt(SO_ORIGINAL_DST) failed: " << xstrerror());
d6026916 209 last_reported = squid_curtime;
210 }
211
62e76326 212 return -1;
d6026916 213 }
3f38a55e 214
bf8fe701 215 debugs(89, 5, "clientNatLookup: addr = " << inet_ntoa(dst->sin_addr) << "");
62e76326 216
3f38a55e 217 if (me.sin_addr.s_addr != dst->sin_addr.s_addr)
62e76326 218 return 0;
3f38a55e 219 else
62e76326 220 return -1;
3f38a55e 221}
62e76326 222
c8be6d7b 223#elif PF_TRANSPARENT
3f38a55e 224int
62e76326 225
3f38a55e 226clientNatLookup(int fd, struct sockaddr_in me, struct sockaddr_in peer, struct sockaddr_in *dst)
227{
62e76326 228
3f38a55e 229 struct pfioc_natlook nl;
230 static int pffd = -1;
d6026916 231 static time_t last_reported = 0;
62e76326 232
233 if (pffd < 0)
234 pffd = open("/dev/pf", O_RDWR);
235
c8be6d7b 236 if (pffd < 0)
62e76326 237 {
d6026916 238 if (squid_curtime - last_reported > 60) {
bf8fe701 239 debugs(89, 1, "clientNatLookup: PF open failed: " << xstrerror());
d6026916 240 last_reported = squid_curtime;
241 }
242
62e76326 243 return -1;
d6026916 244
c8be6d7b 245 }
62e76326 246
3f38a55e 247 memset(dst, 0, sizeof(*dst));
62e76326 248
c8be6d7b 249 memset(&nl, 0, sizeof(struct pfioc_natlook));
250 nl.saddr.v4.s_addr = peer.sin_addr.s_addr;
251 nl.sport = peer.sin_port;
252 nl.daddr.v4.s_addr = me.sin_addr.s_addr;
253 nl.dport = me.sin_port;
254 nl.af = AF_INET;
255 nl.proto = IPPROTO_TCP;
256 nl.direction = PF_OUT;
62e76326 257
258 if (ioctl(pffd, DIOCNATLOOK, &nl))
259 {
260 if (errno != ENOENT) {
d6026916 261 if (squid_curtime - last_reported > 60) {
bf8fe701 262 debugs(89, 1, "clientNatLookup: PF lookup failed: ioctl(DIOCNATLOOK)");
d6026916 263 last_reported = squid_curtime;
264 }
265
62e76326 266 close(pffd);
267 pffd = -1;
268 }
269
270 return -1;
271 } else
272 {
482aa790 273 int natted = me.sin_addr.s_addr != nl.rdaddr.v4.s_addr;
62e76326 274 dst->sin_family = AF_INET;
275 dst->sin_port = nl.rdport;
276 dst->sin_addr = nl.rdaddr.v4;
277
278 if (natted)
279 return 0;
280 else
281 return -1;
3f38a55e 282 }
283}
62e76326 284
68075fad 285#elif IPFW_TRANSPARENT
3f38a55e 286int
287clientNatLookup(int fd, struct sockaddr_in me, struct sockaddr_in peer, struct sockaddr_in *dst)
288{
68075fad 289 int ret;
290 struct sockaddr_in s;
291 int slen = sizeof(struct sockaddr_in);
292
293 ret = getsockname(fd, (struct sockaddr *) &s, (socklen_t * )&slen);
294 if (ret < 0) {
295 debugs(89, 1, "clientNatLookup: getpeername failed (fd " << fd << "), errstr " << xstrerror());
296 return -1;
297 }
298 *dst = s;
299 return 0;
c8be6d7b 300}
62e76326 301
68075fad 302#else
303int
304clientNatLookup(int fd, struct sockaddr_in me, struct sockaddr_in peer, struct sockaddr_in *dst)
305{
306 debugs(89, 1, "WARNING: transparent proxying not supported");
307 return -1;
308}
3f38a55e 309#endif
310