]> git.ipfire.org Git - thirdparty/squid.git/blame - src/tunnel.cc
removed {http,ftp,gopher}_stop stoplists
[thirdparty/squid.git] / src / tunnel.cc
CommitLineData
95d659f0 1
983061ed 2/*
b6f794d6 3 * $Id: tunnel.cc,v 1.9 1996/07/25 07:10:41 wessels Exp $
983061ed 4 *
30a4f2a8 5 * DEBUG: section 26 Secure Sockets Layer Proxy
6 * AUTHOR: Duane Wessels
7 *
8 * SQUID Internet Object Cache http://www.nlanr.net/Squid/
9 * --------------------------------------------------------
10 *
11 * Squid is the result of efforts by numerous individuals from the
12 * Internet community. Development is led by Duane Wessels of the
13 * National Laboratory for Applied Network Research and funded by
14 * the National Science Foundation.
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 *
983061ed 30 */
983061ed 31
30a4f2a8 32#include "squid.h"
983061ed 33
34typedef struct {
35 char *url;
36 request_t *request;
37 char *mime_hdr;
38 struct {
39 int fd;
40 int len;
41 int offset;
42 char *buf;
43 } client, server;
44 time_t timeout;
45 int *size_ptr; /* pointer to size in an icpStateData for logging */
46} SslStateData;
47
48static char conn_established[] = "HTTP/1.0 200 Connection established\r\n\r\n";
49
50static void sslLifetimeExpire _PARAMS((int fd, SslStateData * sslState));
51static void sslReadTimeout _PARAMS((int fd, SslStateData * sslState));
52static void sslReadServer _PARAMS((int fd, SslStateData * sslState));
53static void sslReadClient _PARAMS((int fd, SslStateData * sslState));
54static void sslWriteServer _PARAMS((int fd, SslStateData * sslState));
55static void sslWriteClient _PARAMS((int fd, SslStateData * sslState));
56static void sslConnected _PARAMS((int fd, SslStateData * sslState));
30a4f2a8 57static int sslConnect _PARAMS((int fd, struct hostent *, SslStateData *));
983061ed 58static void sslConnInProgress _PARAMS((int fd, SslStateData * sslState));
30a4f2a8 59static void sslErrorComplete _PARAMS((int, char *, int, int, void *));
60static void sslClose _PARAMS((SslStateData * sslState));
61static int sslClientClosed _PARAMS((int fd, SslStateData * sslState));
62
63static void sslClose(sslState)
64 SslStateData *sslState;
65{
66 if (sslState->client.fd > -1) {
67 /* remove the "unexpected" client close handler */
68 comm_remove_close_handler(sslState->client.fd,
69 (PF) sslClientClosed,
70 (void *) sslState);
71 comm_close(sslState->client.fd);
72 sslState->client.fd = -1;
73 }
74 if (sslState->server.fd > -1) {
75 comm_close(sslState->server.fd);
76 }
77}
78
79/* This is called only if the client connect closes unexpectedly,
80 * ie from icpDetectClientClose() */
81static int sslClientClosed(fd, sslState)
82 int fd;
83 SslStateData *sslState;
84{
85 debug(26, 3, "sslClientClosed: FD %d\n", fd);
86 /* we have been called from comm_close for the client side, so
87 * just need to clean up the server side */
88 comm_close(sslState->server.fd);
89 return 0;
90}
983061ed 91
92static int sslStateFree(fd, sslState)
93 int fd;
94 SslStateData *sslState;
95{
96 debug(26, 3, "sslStateFree: FD %d, sslState=%p\n", fd, sslState);
97 if (sslState == NULL)
98 return 1;
99 if (fd != sslState->server.fd)
100 fatal_dump("sslStateFree: FD mismatch!\n");
101 comm_set_select_handler(sslState->client.fd,
102 COMM_SELECT_READ,
103 NULL,
104 NULL);
105 safe_free(sslState->server.buf);
106 safe_free(sslState->client.buf);
107 xfree(sslState->url);
30a4f2a8 108 requestUnlink(sslState->request);
983061ed 109 memset(sslState, '\0', sizeof(SslStateData));
110 safe_free(sslState);
111 return 0;
112}
113
114/* This will be called when the server lifetime is expired. */
115static void sslLifetimeExpire(fd, sslState)
116 int fd;
117 SslStateData *sslState;
118{
119 debug(26, 4, "sslLifeTimeExpire: FD %d: URL '%s'>\n",
120 fd, sslState->url);
30a4f2a8 121 sslClose(sslState);
983061ed 122}
123
124/* Read from server side and queue it for writing to the client */
125static void sslReadServer(fd, sslState)
126 int fd;
127 SslStateData *sslState;
128{
129 int len;
30a4f2a8 130 len = read(sslState->server.fd, sslState->server.buf, SQUID_TCP_SO_RCVBUF);
983061ed 131 debug(26, 5, "sslReadServer FD %d, read %d bytes\n", fd, len);
132 if (len < 0) {
133 debug(26, 1, "sslReadServer: FD %d: read failure: %s\n",
134 sslState->server.fd, xstrerror());
135 if (errno == EAGAIN || errno == EWOULDBLOCK) {
136 /* reinstall handlers */
137 /* XXX This may loop forever */
138 comm_set_select_handler(sslState->server.fd,
139 COMM_SELECT_READ,
140 (PF) sslReadServer,
141 (void *) sslState);
142 comm_set_select_handler_plus_timeout(sslState->server.fd,
143 COMM_SELECT_TIMEOUT,
144 (PF) sslReadTimeout,
145 (void *) sslState,
146 sslState->timeout);
147 } else {
30a4f2a8 148 sslClose(sslState);
983061ed 149 }
150 } else if (len == 0) {
151 /* Connection closed; retrieval done. */
30a4f2a8 152 sslClose(sslState);
983061ed 153 } else {
154 sslState->server.offset = 0;
155 sslState->server.len = len;
156 comm_set_select_handler(sslState->client.fd,
157 COMM_SELECT_WRITE,
158 (PF) sslWriteClient,
159 (void *) sslState);
983061ed 160 }
161}
162
163/* Read from client side and queue it for writing to the server */
164static void sslReadClient(fd, sslState)
165 int fd;
166 SslStateData *sslState;
167{
168 int len;
30a4f2a8 169 len = read(sslState->client.fd, sslState->client.buf, SQUID_TCP_SO_RCVBUF);
983061ed 170 debug(26, 5, "sslReadClient FD %d, read %d bytes\n",
171 sslState->client.fd, len);
172 if (len < 0) {
173 debug(26, 1, "sslReadClient: FD %d: read failure: %s\n",
174 fd, xstrerror());
175 if (errno == EAGAIN || errno == EWOULDBLOCK) {
176 /* reinstall handlers */
177 /* XXX This may loop forever */
178 comm_set_select_handler(sslState->client.fd,
179 COMM_SELECT_READ,
85d8f397 180 (PF) sslReadClient,
983061ed 181 (void *) sslState);
983061ed 182 } else {
30a4f2a8 183 sslClose(sslState);
983061ed 184 }
185 } else if (len == 0) {
186 /* Connection closed; retrieval done. */
30a4f2a8 187 sslClose(sslState);
983061ed 188 } else {
189 sslState->client.offset = 0;
190 sslState->client.len = len;
191 comm_set_select_handler(sslState->server.fd,
192 COMM_SELECT_WRITE,
193 (PF) sslWriteServer,
194 (void *) sslState);
983061ed 195 }
196}
197
198/* Writes data from the client buffer to the server side */
199static void sslWriteServer(fd, sslState)
200 int fd;
201 SslStateData *sslState;
202{
203 int len;
204 len = write(sslState->server.fd,
205 sslState->client.buf + sslState->client.offset,
206 sslState->client.len - sslState->client.offset);
207 debug(26, 5, "sslWriteServer FD %d, wrote %d bytes\n", fd, len);
208 if (len < 0) {
209 debug(26, 2, "sslWriteServer: FD %d: write failure: %s.\n",
210 sslState->server.fd, xstrerror());
30a4f2a8 211 sslClose(sslState);
983061ed 212 return;
213 }
214 if ((sslState->client.offset += len) >= sslState->client.len) {
215 /* Done writing, read more */
216 comm_set_select_handler(sslState->client.fd,
217 COMM_SELECT_READ,
218 (PF) sslReadClient,
219 (void *) sslState);
d2af9477 220 comm_set_select_handler_plus_timeout(sslState->server.fd,
221 COMM_SELECT_TIMEOUT,
222 (PF) sslReadTimeout,
223 (void *) sslState,
224 sslState->timeout);
983061ed 225 } else {
226 /* still have more to write */
227 comm_set_select_handler(sslState->server.fd,
228 COMM_SELECT_WRITE,
229 (PF) sslWriteServer,
230 (void *) sslState);
231 }
232}
233
234/* Writes data from the server buffer to the client side */
235static void sslWriteClient(fd, sslState)
236 int fd;
237 SslStateData *sslState;
238{
239 int len;
240 debug(26, 5, "sslWriteClient FD %d len=%d offset=%d\n",
241 fd,
242 sslState->server.len,
243 sslState->server.offset);
244 len = write(sslState->client.fd,
245 sslState->server.buf + sslState->server.offset,
246 sslState->server.len - sslState->server.offset);
247 debug(26, 5, "sslWriteClient FD %d, wrote %d bytes\n", fd, len);
248 if (len < 0) {
249 debug(26, 2, "sslWriteClient: FD %d: write failure: %s.\n",
250 sslState->client.fd, xstrerror());
30a4f2a8 251 sslClose(sslState);
983061ed 252 return;
253 }
254 if (sslState->size_ptr)
255 *sslState->size_ptr += len; /* increment total object size */
256 if ((sslState->server.offset += len) >= sslState->server.len) {
257 /* Done writing, read more */
258 comm_set_select_handler(sslState->server.fd,
259 COMM_SELECT_READ,
260 (PF) sslReadServer,
261 (void *) sslState);
262 } else {
263 /* still have more to write */
264 comm_set_select_handler(sslState->client.fd,
265 COMM_SELECT_WRITE,
266 (PF) sslWriteClient,
267 (void *) sslState);
268 }
269}
270
271static void sslReadTimeout(fd, sslState)
272 int fd;
273 SslStateData *sslState;
274{
983061ed 275 debug(26, 3, "sslReadTimeout: FD %d\n", fd);
30a4f2a8 276 sslClose(sslState);
983061ed 277}
278
279static void sslConnected(fd, sslState)
280 int fd;
281 SslStateData *sslState;
282{
283 debug(26, 3, "sslConnected: FD %d sslState=%p\n", fd, sslState);
284 strcpy(sslState->server.buf, conn_established);
285 sslState->server.len = strlen(conn_established);
286 sslState->server.offset = 0;
287 comm_set_select_handler(sslState->client.fd,
288 COMM_SELECT_WRITE,
289 (PF) sslWriteClient,
290 (void *) sslState);
30a4f2a8 291 comm_set_fd_lifetime(fd, 86400); /* extend lifetime */
983061ed 292 comm_set_select_handler(sslState->client.fd,
293 COMM_SELECT_READ,
294 (PF) sslReadClient,
295 (void *) sslState);
296}
297
30a4f2a8 298static void sslErrorComplete(fd, buf, size, errflag, sslState)
299 int fd;
300 char *buf;
301 int size;
302 int errflag;
303 void *sslState;
304{
305 safe_free(buf);
306 sslClose(sslState);
307}
308
983061ed 309
310static void sslConnInProgress(fd, sslState)
311 int fd;
312 SslStateData *sslState;
313{
314 request_t *req = sslState->request;
30a4f2a8 315 char *buf = NULL;
983061ed 316 debug(26, 5, "sslConnInProgress: FD %d sslState=%p\n", fd, sslState);
317
318 if (comm_connect(fd, req->host, req->port) != COMM_OK) {
30a4f2a8 319 debug(26, 5, "sslConnInProgress: FD %d: %s\n", fd, xstrerror());
983061ed 320 switch (errno) {
321#if EINPROGRESS != EALREADY
322 case EINPROGRESS:
323#endif
324 case EALREADY:
325 /* We are not connected yet. schedule this handler again */
326 comm_set_select_handler(fd, COMM_SELECT_WRITE,
327 (PF) sslConnInProgress,
328 (void *) sslState);
329 return;
330 default:
30a4f2a8 331 buf = squid_error_url(sslState->url,
332 METHOD_CONNECT,
333 ERR_CONNECT_FAIL,
334 NULL,
335 500,
336 xstrerror());
337 comm_write(sslState->client.fd,
338 xstrdup(buf),
339 strlen(buf),
340 30,
341 sslErrorComplete,
9864ee44 342 sslState,
343 xfree);
983061ed 344 return;
345 }
346 }
347 /* We are now fully connected */
348 sslConnected(fd, sslState);
349 return;
350}
351
30a4f2a8 352static int sslConnect(fd, hp, sslState)
983061ed 353 int fd;
30a4f2a8 354 struct hostent *hp;
355 SslStateData *sslState;
983061ed 356{
30a4f2a8 357 request_t *request = sslState->request;
358 int status;
359 char *buf = NULL;
360 if (!ipcache_gethostbyname(request->host, 0)) {
361 debug(26, 4, "sslConnect: Unknown host: %s\n", request->host);
362 buf = squid_error_url(sslState->url,
983061ed 363 request->method,
364 ERR_DNS_FAIL,
365 fd_table[fd].ipaddr,
366 500,
367 dns_error_message);
30a4f2a8 368 comm_write(sslState->client.fd,
369 xstrdup(buf),
370 strlen(buf),
371 30,
372 sslErrorComplete,
9864ee44 373 (void *) sslState,
4a63c85f 374 xfree);
983061ed 375 return COMM_ERROR;
376 }
30a4f2a8 377 debug(26, 5, "sslConnect: client=%d server=%d\n",
983061ed 378 sslState->client.fd,
379 sslState->server.fd);
380 /* Install lifetime handler */
381 comm_set_select_handler(sslState->server.fd,
382 COMM_SELECT_LIFETIME,
383 (PF) sslLifetimeExpire,
384 (void *) sslState);
385 /* NOTE this changes the lifetime handler for the client side.
386 * It used to be asciiConnLifetimeHandle, but it does funny things
387 * like looking for read handlers and assuming it was still reading
388 * the HTTP request. sigh... */
389 comm_set_select_handler(sslState->client.fd,
390 COMM_SELECT_LIFETIME,
391 (PF) sslLifetimeExpire,
392 (void *) sslState);
393 /* Open connection. */
30a4f2a8 394 if ((status = comm_connect(fd, request->host, request->port))) {
983061ed 395 if (status != EINPROGRESS) {
30a4f2a8 396 buf = squid_error_url(sslState->url,
983061ed 397 request->method,
398 ERR_CONNECT_FAIL,
399 fd_table[fd].ipaddr,
400 500,
401 xstrerror());
30a4f2a8 402 comm_write(sslState->client.fd,
403 xstrdup(buf),
404 strlen(buf),
405 30,
406 sslErrorComplete,
9864ee44 407 (void *) sslState,
408 xfree);
983061ed 409 return COMM_ERROR;
410 } else {
30a4f2a8 411 debug(26, 5, "sslConnect: conn %d EINPROGRESS\n", fd);
983061ed 412 /* The connection is in progress, install ssl handler */
413 comm_set_select_handler(sslState->server.fd,
414 COMM_SELECT_WRITE,
415 (PF) sslConnInProgress,
416 (void *) sslState);
417 return COMM_OK;
418 }
419 }
983061ed 420 sslConnected(sslState->server.fd, sslState);
421 return COMM_OK;
422}
30a4f2a8 423
424int sslStart(fd, url, request, mime_hdr, size_ptr)
425 int fd;
426 char *url;
427 request_t *request;
428 char *mime_hdr;
429 int *size_ptr;
430{
431 /* Create state structure. */
432 SslStateData *sslState = NULL;
433 int sock;
434 char *buf = NULL;
435
436 debug(26, 3, "sslStart: '%s %s'\n",
437 RequestMethodStr[request->method], url);
438
439 /* Create socket. */
b6f794d6 440 sock = comm_open(COMM_NONBLOCKING, Config.Addrs.tcp_outgoing, 0, url);
30a4f2a8 441 if (sock == COMM_ERROR) {
442 debug(26, 4, "sslStart: Failed because we're out of sockets.\n");
443 buf = squid_error_url(url,
444 request->method,
445 ERR_NO_FDS,
446 fd_table[fd].ipaddr,
447 500,
448 xstrerror());
449 comm_write(sslState->client.fd,
450 xstrdup(buf),
451 strlen(buf),
452 30,
453 sslErrorComplete,
9864ee44 454 (void *) sslState,
4a63c85f 455 xfree);
30a4f2a8 456 return COMM_ERROR;
457 }
458 sslState = xcalloc(1, sizeof(SslStateData));
459 sslState->url = xstrdup(url);
460 sslState->request = requestLink(request);
461 sslState->mime_hdr = mime_hdr;
b6f794d6 462 sslState->timeout = Config.readTimeout;
30a4f2a8 463 sslState->size_ptr = size_ptr;
464 sslState->client.fd = fd;
465 sslState->server.fd = sock;
466 sslState->server.buf = xmalloc(SQUID_TCP_SO_RCVBUF);
467 sslState->client.buf = xmalloc(SQUID_TCP_SO_RCVBUF);
468 comm_add_close_handler(sslState->server.fd,
469 (PF) sslStateFree,
470 (void *) sslState);
471 comm_add_close_handler(sslState->client.fd,
472 (PF) sslClientClosed,
473 (void *) sslState);
474 ipcache_nbgethostbyname(request->host,
475 sslState->server.fd,
476 (IPH) sslConnect,
477 sslState);
478 return COMM_OK;
479}