]> git.ipfire.org Git - thirdparty/squid.git/blame - src/tunnel.cc
update
[thirdparty/squid.git] / src / tunnel.cc
CommitLineData
95d659f0 1
983061ed 2/*
db1cd23c 3 * $Id: tunnel.cc,v 1.91 1998/12/05 00:54:40 wessels Exp $
983061ed 4 *
30a4f2a8 5 * DEBUG: section 26 Secure Sockets Layer Proxy
6 * AUTHOR: Duane Wessels
7 *
42c04c16 8 * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
e25c139f 9 * ----------------------------------------------------------
30a4f2a8 10 *
11 * Squid is the result of efforts by numerous individuals from the
12 * Internet community. Development is led by Duane Wessels of the
e25c139f 13 * National Laboratory for Applied Network Research and funded by the
14 * National Science Foundation. Squid is Copyrighted (C) 1998 by
15 * Duane Wessels and the University of California San Diego. Please
16 * see the COPYRIGHT file for full details. Squid incorporates
17 * software developed and/or copyrighted by other sources. Please see
18 * the CREDITS file for full details.
30a4f2a8 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
cbdec147 32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
e25c139f 33 *
983061ed 34 */
983061ed 35
30a4f2a8 36#include "squid.h"
983061ed 37
38typedef struct {
39 char *url;
98ffb7e4 40 char *host; /* either request->host or proxy host */
41 u_short port;
983061ed 42 request_t *request;
983061ed 43 struct {
44 int fd;
45 int len;
983061ed 46 char *buf;
47 } client, server;
88738790 48 size_t *size_ptr; /* pointer to size in an ConnStateData for logging */
93868820 49 int proxying;
983061ed 50} SslStateData;
51
0ee4272b 52static const char *const conn_established = "HTTP/1.0 200 Connection established\r\n\r\n";
983061ed 53
54cff85f 54static CNCB sslConnectDone;
55static ERCB sslErrorComplete;
adb78bd4 56static PF sslServerClosed;
54cff85f 57static PF sslClientClosed;
58static PF sslReadClient;
59static PF sslReadServer;
5c5783a2 60static PF sslTimeout;
54cff85f 61static PF sslWriteClient;
62static PF sslWriteServer;
63static PSC sslPeerSelectComplete;
adb78bd4 64static void sslStateFree(SslStateData * sslState);
f5b8bbc4 65static void sslConnected(int fd, void *);
66static void sslProxyConnected(int fd, void *);
adb78bd4 67static void sslSetSelect(SslStateData * sslState);
447e176b 68#if DELAY_POOLS
69static DEFER sslDeferServerRead;
70#endif
30a4f2a8 71
b8d8561b 72static void
adb78bd4 73sslServerClosed(int fd, void *data)
30a4f2a8 74{
adb78bd4 75 SslStateData *sslState = data;
76 debug(26, 3) ("sslServerClosed: FD %d\n", fd);
77 assert(fd == sslState->server.fd);
78 sslState->server.fd = -1;
79 if (sslState->client.fd == -1)
80 sslStateFree(sslState);
30a4f2a8 81}
82
b177367b 83static void
84sslClientClosed(int fd, void *data)
30a4f2a8 85{
b177367b 86 SslStateData *sslState = data;
a3d5953d 87 debug(26, 3) ("sslClientClosed: FD %d\n", fd);
adb78bd4 88 assert(fd == sslState->client.fd);
89 sslState->client.fd = -1;
90 if (sslState->server.fd == -1)
91 sslStateFree(sslState);
30a4f2a8 92}
983061ed 93
b177367b 94static void
adb78bd4 95sslStateFree(SslStateData * sslState)
983061ed 96{
adb78bd4 97 debug(26, 3) ("sslStateFree: sslState=%p\n", sslState);
98 assert(sslState != NULL);
99 assert(sslState->client.fd == -1);
100 assert(sslState->server.fd == -1);
983061ed 101 safe_free(sslState->server.buf);
102 safe_free(sslState->client.buf);
adb78bd4 103 safe_free(sslState->url);
104 sslState->host = NULL;
30a4f2a8 105 requestUnlink(sslState->request);
7dd44885 106 sslState->request = NULL;
107 cbdataFree(sslState);
983061ed 108}
109
447e176b 110#if DELAY_POOLS
111static int
112sslDeferServerRead(int fdnotused, void *data)
113{
114 request_t *r = data;
56e64999 115 return delayBytesWanted(r->delay_id, 0, 1) == 0;
447e176b 116}
117#endif
118
adb78bd4 119static void
120sslSetSelect(SslStateData * sslState)
121{
447e176b 122 size_t read_sz = SQUID_TCP_SO_RCVBUF;
adb78bd4 123 assert(sslState->server.fd > -1 || sslState->client.fd > -1);
124 if (sslState->client.fd > -1) {
125 if (sslState->server.len > 0) {
126 commSetSelect(sslState->client.fd,
127 COMM_SELECT_WRITE,
128 sslWriteClient,
129 sslState,
130 0);
131 }
447e176b 132 if (sslState->client.len < read_sz) {
adb78bd4 133 commSetSelect(sslState->client.fd,
134 COMM_SELECT_READ,
135 sslReadClient,
136 sslState,
137 Config.Timeout.read);
138 }
139 } else if (sslState->client.len == 0) {
140 comm_close(sslState->server.fd);
141 }
142 if (sslState->server.fd > -1) {
143 if (sslState->client.len > 0) {
144 commSetSelect(sslState->server.fd,
145 COMM_SELECT_WRITE,
146 sslWriteServer,
147 sslState,
148 0);
149 }
447e176b 150#if DELAY_POOLS
56e64999 151 /* If this was allowed to return 0, there would be a possibility
e82d6d21 152 * of the socket becoming "hung" with data accumulating but no
153 * write handler (server.len==0) and no read handler (!(0<0)) and
154 * no data flowing in the other direction. Hence the argument of
155 * 1 as min.
156 */
56e64999 157 read_sz = delayBytesWanted(sslState->request->delay_id, 1, read_sz);
447e176b 158#endif
159 if (sslState->server.len < read_sz) {
adb78bd4 160 /* Have room to read more */
161 commSetSelect(sslState->server.fd,
162 COMM_SELECT_READ,
163 sslReadServer,
164 sslState,
165 Config.Timeout.read);
166 }
167 } else if (sslState->client.fd == -1) {
168 /* client already closed, nothing more to do */
169 } else if (sslState->server.len == 0) {
170 comm_close(sslState->client.fd);
171 }
172}
173
983061ed 174/* Read from server side and queue it for writing to the client */
b8d8561b 175static void
b177367b 176sslReadServer(int fd, void *data)
983061ed 177{
b177367b 178 SslStateData *sslState = data;
983061ed 179 int len;
447e176b 180 size_t read_sz = SQUID_TCP_SO_RCVBUF - sslState->server.len;
adb78bd4 181 assert(fd == sslState->server.fd);
182 debug(26, 3) ("sslReadServer: FD %d, reading %d bytes at offset %d\n",
447e176b 183 fd, read_sz, sslState->server.len);
184 errno = 0;
185#if DELAY_POOLS
56e64999 186 read_sz = delayBytesWanted(sslState->request->delay_id, 1, read_sz);
447e176b 187#endif
886f2785 188 Counter.syscalls.sock.reads++;
447e176b 189 len = read(fd, sslState->server.buf + sslState->server.len, read_sz);
adb78bd4 190 debug(26, 3) ("sslReadServer: FD %d, read %d bytes\n", fd, len);
ee1679df 191 if (len > 0) {
adb78bd4 192 fd_bytes(fd, len, FD_READ);
447e176b 193#if DELAY_POOLS
194 delayBytesIn(sslState->request->delay_id, len);
195#endif
a0f32775 196 kb_incr(&Counter.server.all.kbytes_in, len);
197 kb_incr(&Counter.server.other.kbytes_in, len);
adb78bd4 198 sslState->server.len += len;
ee1679df 199 }
adb78bd4 200 cbdataLock(sslState);
983061ed 201 if (len < 0) {
a3d5953d 202 debug(50, 1) ("sslReadServer: FD %d: read failure: %s\n",
adb78bd4 203 fd, xstrerror());
204 if (!ignoreErrno(errno))
205 comm_close(fd);
983061ed 206 } else if (len == 0) {
adb78bd4 207 comm_close(sslState->server.fd);
983061ed 208 }
adb78bd4 209 if (cbdataValid(sslState))
210 sslSetSelect(sslState);
211 cbdataUnlock(sslState);
983061ed 212}
213
214/* Read from client side and queue it for writing to the server */
b8d8561b 215static void
b177367b 216sslReadClient(int fd, void *data)
983061ed 217{
b177367b 218 SslStateData *sslState = data;
983061ed 219 int len;
adb78bd4 220 assert(fd == sslState->client.fd);
221 debug(26, 3) ("sslReadClient: FD %d, reading %d bytes at offset %d\n",
222 fd, SQUID_TCP_SO_RCVBUF - sslState->client.len,
223 sslState->client.len);
886f2785 224 Counter.syscalls.sock.reads++;
adb78bd4 225 len = read(fd,
226 sslState->client.buf + sslState->client.len,
227 SQUID_TCP_SO_RCVBUF - sslState->client.len);
228 debug(26, 3) ("sslReadClient: FD %d, read %d bytes\n", fd, len);
ee1679df 229 if (len > 0) {
adb78bd4 230 fd_bytes(fd, len, FD_READ);
ee1679df 231 kb_incr(&Counter.client_http.kbytes_in, len);
adb78bd4 232 sslState->client.len += len;
ee1679df 233 }
adb78bd4 234 cbdataLock(sslState);
983061ed 235 if (len < 0) {
a3d5953d 236 debug(50, 1) ("sslReadClient: FD %d: read failure: %s\n",
983061ed 237 fd, xstrerror());
adb78bd4 238 if (!ignoreErrno(errno))
239 comm_close(fd);
983061ed 240 } else if (len == 0) {
adb78bd4 241 comm_close(fd);
983061ed 242 }
adb78bd4 243 if (cbdataValid(sslState))
244 sslSetSelect(sslState);
245 cbdataUnlock(sslState);
983061ed 246}
247
248/* Writes data from the client buffer to the server side */
b8d8561b 249static void
b177367b 250sslWriteServer(int fd, void *data)
983061ed 251{
b177367b 252 SslStateData *sslState = data;
983061ed 253 int len;
adb78bd4 254 assert(fd == sslState->server.fd);
255 debug(26, 3) ("sslWriteServer: FD %d, %d bytes to write\n",
256 fd, sslState->client.len);
886f2785 257 Counter.syscalls.sock.writes++;
adb78bd4 258 len = write(fd,
259 sslState->client.buf,
260 sslState->client.len);
261 debug(26, 3) ("sslWriteServer: FD %d, %d bytes written\n", fd, len);
ee1679df 262 if (len > 0) {
adb78bd4 263 fd_bytes(fd, len, FD_WRITE);
a0f32775 264 kb_incr(&Counter.server.all.kbytes_out, len);
265 kb_incr(&Counter.server.other.kbytes_out, len);
adb78bd4 266 assert(len <= sslState->client.len);
267 sslState->client.len -= len;
268 if (sslState->client.len > 0) {
269 /* we didn't write the whole thing */
270 xmemmove(sslState->client.buf,
271 sslState->client.buf + len,
272 sslState->client.len);
0a0bf5db 273 }
983061ed 274 }
adb78bd4 275 cbdataLock(sslState);
276 if (len < 0) {
277 debug(50, 1) ("sslWriteServer: FD %d: write failure: %s.\n",
278 fd, xstrerror());
279 if (!ignoreErrno(errno))
280 comm_close(fd);
983061ed 281 }
adb78bd4 282 if (cbdataValid(sslState))
283 sslSetSelect(sslState);
284 cbdataUnlock(sslState);
983061ed 285}
286
287/* Writes data from the server buffer to the client side */
b8d8561b 288static void
b177367b 289sslWriteClient(int fd, void *data)
983061ed 290{
b177367b 291 SslStateData *sslState = data;
983061ed 292 int len;
adb78bd4 293 assert(fd == sslState->client.fd);
294 debug(26, 3) ("sslWriteClient: FD %d, %d bytes to write\n",
295 fd, sslState->server.len);
886f2785 296 Counter.syscalls.sock.writes++;
adb78bd4 297 len = write(fd,
298 sslState->server.buf,
299 sslState->server.len);
300 debug(26, 3) ("sslWriteClient: FD %d, %d bytes written\n", fd, len);
ee1679df 301 if (len > 0) {
adb78bd4 302 fd_bytes(fd, len, FD_WRITE);
ee1679df 303 kb_incr(&Counter.client_http.kbytes_out, len);
adb78bd4 304 assert(len <= sslState->server.len);
305 sslState->server.len -= len;
306 /* increment total object size */
307 if (sslState->size_ptr)
308 *sslState->size_ptr += len;
309 if (sslState->server.len > 0) {
310 /* we didn't write the whole thing */
311 xmemmove(sslState->server.buf,
312 sslState->server.buf + len,
313 sslState->server.len);
0a0bf5db 314 }
983061ed 315 }
adb78bd4 316 cbdataLock(sslState);
317 if (len < 0) {
318 debug(50, 1) ("sslWriteClient: FD %d: write failure: %s.\n",
319 fd, xstrerror());
320 if (!ignoreErrno(errno))
321 comm_close(fd);
983061ed 322 }
adb78bd4 323 if (cbdataValid(sslState))
324 sslSetSelect(sslState);
325 cbdataUnlock(sslState);
983061ed 326}
327
b8d8561b 328static void
5c5783a2 329sslTimeout(int fd, void *data)
983061ed 330{
b177367b 331 SslStateData *sslState = data;
a3d5953d 332 debug(26, 3) ("sslTimeout: FD %d\n", fd);
adb78bd4 333 if (sslState->client.fd > -1)
334 comm_close(sslState->client.fd);
335 if (sslState->server.fd > -1)
336 comm_close(sslState->server.fd);
983061ed 337}
338
b8d8561b 339static void
b177367b 340sslConnected(int fd, void *data)
983061ed 341{
b177367b 342 SslStateData *sslState = data;
a3d5953d 343 debug(26, 3) ("sslConnected: FD %d sslState=%p\n", fd, sslState);
54cff85f 344 xstrncpy(sslState->server.buf, conn_established, SQUID_TCP_SO_RCVBUF);
983061ed 345 sslState->server.len = strlen(conn_established);
adb78bd4 346 sslSetSelect(sslState);
983061ed 347}
348
b8d8561b 349static void
adb78bd4 350sslErrorComplete(int fdnotused, void *data, size_t sizenotused)
30a4f2a8 351{
adb78bd4 352 SslStateData *sslState = data;
9b312a19 353 assert(sslState != NULL);
adb78bd4 354 if (sslState->client.fd > -1)
355 comm_close(sslState->client.fd);
356 if (sslState->server.fd > -1)
357 comm_close(sslState->server.fd);
30a4f2a8 358}
359
983061ed 360
b8d8561b 361static void
79d39a72 362sslConnectDone(int fdnotused, int status, void *data)
983061ed 363{
b15fe823 364 SslStateData *sslState = data;
30a4f2a8 365 request_t *request = sslState->request;
9b312a19 366 ErrorState *err = NULL;
edeb28fd 367 if (status == COMM_ERR_DNS) {
a3d5953d 368 debug(26, 4) ("sslConnect: Unknown host: %s\n", sslState->host);
fe40a877 369 err = errorCon(ERR_DNS_FAIL, HTTP_NOT_FOUND);
9b312a19 370 err->request = requestLink(request);
371 err->dnsserver_msg = xstrdup(dns_error_message);
372 err->callback = sslErrorComplete;
373 err->callback_data = sslState;
374 errorSend(sslState->client.fd, err);
edeb28fd 375 } else if (status != COMM_OK) {
fe40a877 376 err = errorCon(ERR_CONNECT_FAIL, HTTP_SERVICE_UNAVAILABLE);
c45ed9ad 377 err->xerrno = errno;
9b312a19 378 err->host = xstrdup(sslState->host);
379 err->port = sslState->port;
380 err->request = requestLink(request);
381 err->callback = sslErrorComplete;
382 err->callback_data = sslState;
383 errorSend(sslState->client.fd, err);
fe40a877 384 } else {
385 if (sslState->proxying)
386 sslProxyConnected(sslState->server.fd, sslState);
4e3f29eb 387 else
fe40a877 388 sslConnected(sslState->server.fd, sslState);
1afe05c5 389 commSetTimeout(sslState->server.fd,
390 Config.Timeout.read,
391 sslTimeout,
392 sslState);
447e176b 393#if DELAY_POOLS
394 commSetDefer(sslState->server.fd, sslDeferServerRead, sslState->request);
395#endif
983061ed 396 }
983061ed 397}
30a4f2a8 398
770f051d 399void
9b312a19 400sslStart(int fd, const char *url, request_t * request, size_t * size_ptr)
30a4f2a8 401{
402 /* Create state structure. */
403 SslStateData *sslState = NULL;
404 int sock;
9b312a19 405 ErrorState *err = NULL;
a3d5953d 406 debug(26, 3) ("sslStart: '%s %s'\n",
30a4f2a8 407 RequestMethodStr[request->method], url);
a0f32775 408 Counter.server.all.requests++;
409 Counter.server.other.requests++;
30a4f2a8 410 /* Create socket. */
16b204c4 411 sock = comm_open(SOCK_STREAM,
412 0,
413 Config.Addrs.tcp_outgoing,
414 0,
415 COMM_NONBLOCKING,
416 url);
30a4f2a8 417 if (sock == COMM_ERROR) {
a3d5953d 418 debug(26, 4) ("sslStart: Failed because we're out of sockets.\n");
fe40a877 419 err = errorCon(ERR_SOCKET_FAILURE, HTTP_INTERNAL_SERVER_ERROR);
c45ed9ad 420 err->xerrno = errno;
9b312a19 421 err->request = requestLink(request);
422 errorSend(fd, err);
770f051d 423 return;
30a4f2a8 424 }
425 sslState = xcalloc(1, sizeof(SslStateData));
db1cd23c 426 cbdataAdd(sslState, cbdataXfree, 0);
30a4f2a8 427 sslState->url = xstrdup(url);
428 sslState->request = requestLink(request);
30a4f2a8 429 sslState->size_ptr = size_ptr;
430 sslState->client.fd = fd;
431 sslState->server.fd = sock;
432 sslState->server.buf = xmalloc(SQUID_TCP_SO_RCVBUF);
433 sslState->client.buf = xmalloc(SQUID_TCP_SO_RCVBUF);
434 comm_add_close_handler(sslState->server.fd,
adb78bd4 435 sslServerClosed,
cd1fb0eb 436 sslState);
30a4f2a8 437 comm_add_close_handler(sslState->client.fd,
b177367b 438 sslClientClosed,
cd1fb0eb 439 sslState);
5c5783a2 440 commSetTimeout(sslState->client.fd,
4f92c80c 441 Config.Timeout.lifetime,
442 sslTimeout,
443 sslState);
cf1edeae 444 commSetTimeout(sslState->server.fd,
445 Config.Timeout.connect,
446 sslTimeout,
447 sslState);
b6c0e933 448 peerSelect(request,
641941c0 449 NULL,
b6c0e933 450 sslPeerSelectComplete,
b6c0e933 451 sslState);
adb78bd4 452 /*
453 * Disable the client read handler until peer selection is complete
454 * Take control away from client_side.c.
455 */
456 commSetSelect(sslState->client.fd, COMM_SELECT_READ, NULL, NULL, 0);
30a4f2a8 457}
98ffb7e4 458
b8d8561b 459static void
b177367b 460sslProxyConnected(int fd, void *data)
98ffb7e4 461{
b177367b 462 SslStateData *sslState = data;
e1e72f06 463 MemBuf mb;
464 HttpHeader hdr_out;
465 Packer p;
b4b5fd95 466 http_state_flags flags;
a3d5953d 467 debug(26, 3) ("sslProxyConnected: FD %d sslState=%p\n", fd, sslState);
b4b5fd95 468 memset(&flags, '\0', sizeof(flags));
e1e72f06 469 memBufDefInit(&mb);
470 memBufPrintf(&mb, "CONNECT %s HTTP/1.0\r\n", sslState->url);
471 httpBuildRequestHeader(sslState->request,
472 sslState->request,
5999b776 473 NULL, /* StoreEntry */
e1e72f06 474 &hdr_out,
475 sslState->client.fd,
b4b5fd95 476 flags); /* flags */
e1e72f06 477 packerToMemInit(&p, &mb);
478 httpHeaderPackInto(&hdr_out, &p);
479 httpHeaderClean(&hdr_out);
480 packerClean(&p);
481 memBufAppend(&mb, "\r\n", 2);
482 xstrncpy(sslState->client.buf, mb.buf, SQUID_TCP_SO_RCVBUF);
483 debug(26, 3) ("sslProxyConnected: Sending {%s}\n", sslState->client.buf);
484 sslState->client.len = mb.size;
e1e72f06 485 memBufClean(&mb);
86cf9987 486 commSetTimeout(sslState->server.fd,
487 Config.Timeout.read,
488 sslTimeout,
489 sslState);
adb78bd4 490 sslSetSelect(sslState);
98ffb7e4 491}
33ea9fff 492
33ea9fff 493static void
db1cd23c 494sslPeerSelectComplete(FwdServer * fs, void *data)
33ea9fff 495{
496 SslStateData *sslState = data;
497 request_t *request = sslState->request;
deb79f06 498 peer *g = NULL;
db1cd23c 499
500 if (fs == NULL) {
501 ErrorState *err;
502 err = errorCon(ERR_CANNOT_FORWARD, HTTP_SERVICE_UNAVAILABLE);
503 err->request = requestLink(sslState->request);
504 err->callback = sslErrorComplete;
505 err->callback_data = sslState;
506 errorSend(sslState->client.fd, err);
507 return;
508 }
509 sslState->proxying = fs->peer ? 1 : 0;
510 sslState->host = fs->peer ? fs->peer->host : request->host;
511 if (fs->peer == NULL) {
b3b64e58 512 sslState->port = request->port;
db1cd23c 513 } else if (fs->peer->http_port != 0) {
514 sslState->port = fs->peer->http_port;
515 } else if ((g = peerFindByName(fs->peer->host))) {
b3b64e58 516 sslState->port = g->http_port;
33ea9fff 517 } else {
b3b64e58 518 sslState->port = CACHE_HTTP_PORT;
33ea9fff 519 }
edeb28fd 520 commConnectStart(sslState->server.fd,
521 sslState->host,
522 sslState->port,
523 sslConnectDone,
33ea9fff 524 sslState);
525}