3 * $Id: tunnel.cc,v 1.86 1998/08/14 09:22:40 wessels Exp $
5 * DEBUG: section 26 Secure Sockets Layer Proxy
6 * AUTHOR: Duane Wessels
8 * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
9 * ----------------------------------------------------------
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 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.
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.
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.
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.
40 char *host
; /* either request->host or proxy host */
48 size_t *size_ptr
; /* pointer to size in an ConnStateData for logging */
52 static const char *const conn_established
= "HTTP/1.0 200 Connection established\r\n\r\n";
54 static CNCB sslConnectDone
;
55 static ERCB sslErrorComplete
;
56 static PF sslServerClosed
;
57 static PF sslClientClosed
;
58 static PF sslReadClient
;
59 static PF sslReadServer
;
61 static PF sslWriteClient
;
62 static PF sslWriteServer
;
63 static PSC sslPeerSelectComplete
;
64 static PSC sslPeerSelectFail
;
65 static void sslStateFree(SslStateData
* sslState
);
66 static void sslConnected(int fd
, void *);
67 static void sslProxyConnected(int fd
, void *);
68 static void sslSetSelect(SslStateData
* sslState
);
70 static DEFER sslDeferServerRead
;
74 sslServerClosed(int fd
, void *data
)
76 SslStateData
*sslState
= data
;
77 debug(26, 3) ("sslServerClosed: FD %d\n", fd
);
78 assert(fd
== sslState
->server
.fd
);
79 sslState
->server
.fd
= -1;
80 if (sslState
->client
.fd
== -1)
81 sslStateFree(sslState
);
85 sslClientClosed(int fd
, void *data
)
87 SslStateData
*sslState
= data
;
88 debug(26, 3) ("sslClientClosed: FD %d\n", fd
);
89 assert(fd
== sslState
->client
.fd
);
90 sslState
->client
.fd
= -1;
91 if (sslState
->server
.fd
== -1)
92 sslStateFree(sslState
);
96 sslStateFree(SslStateData
* sslState
)
98 debug(26, 3) ("sslStateFree: sslState=%p\n", sslState
);
99 assert(sslState
!= NULL
);
100 assert(sslState
->client
.fd
== -1);
101 assert(sslState
->server
.fd
== -1);
102 safe_free(sslState
->server
.buf
);
103 safe_free(sslState
->client
.buf
);
104 safe_free(sslState
->url
);
105 sslState
->host
= NULL
;
106 requestUnlink(sslState
->request
);
107 sslState
->request
= NULL
;
108 cbdataFree(sslState
);
113 sslDeferServerRead(int fdnotused
, void *data
)
116 return delayBytesWanted(r
->delay_id
, 1) == 0;
121 sslSetSelect(SslStateData
* sslState
)
123 size_t read_sz
= SQUID_TCP_SO_RCVBUF
;
124 assert(sslState
->server
.fd
> -1 || sslState
->client
.fd
> -1);
125 if (sslState
->client
.fd
> -1) {
126 if (sslState
->server
.len
> 0) {
127 commSetSelect(sslState
->client
.fd
,
133 if (sslState
->client
.len
< read_sz
) {
134 commSetSelect(sslState
->client
.fd
,
138 Config
.Timeout
.read
);
140 } else if (sslState
->client
.len
== 0) {
141 comm_close(sslState
->server
.fd
);
143 if (sslState
->server
.fd
> -1) {
144 if (sslState
->client
.len
> 0) {
145 commSetSelect(sslState
->server
.fd
,
152 read_sz
= delayBytesWanted(sslState
->request
->delay_id
, read_sz
);
155 if (sslState
->server
.len
< read_sz
) {
156 /* Have room to read more */
157 commSetSelect(sslState
->server
.fd
,
161 Config
.Timeout
.read
);
163 } else if (sslState
->client
.fd
== -1) {
164 /* client already closed, nothing more to do */
165 } else if (sslState
->server
.len
== 0) {
166 comm_close(sslState
->client
.fd
);
170 /* Read from server side and queue it for writing to the client */
172 sslReadServer(int fd
, void *data
)
174 SslStateData
*sslState
= data
;
176 size_t read_sz
= SQUID_TCP_SO_RCVBUF
- sslState
->server
.len
;
177 assert(fd
== sslState
->server
.fd
);
178 debug(26, 3) ("sslReadServer: FD %d, reading %d bytes at offset %d\n",
179 fd
, read_sz
, sslState
->server
.len
);
182 read_sz
= delayBytesWanted(sslState
->request
->delay_id
, read_sz
);
185 len
= read(fd
, sslState
->server
.buf
+ sslState
->server
.len
, read_sz
);
186 debug(26, 3) ("sslReadServer: FD %d, read %d bytes\n", fd
, len
);
188 fd_bytes(fd
, len
, FD_READ
);
190 delayBytesIn(sslState
->request
->delay_id
, len
);
192 kb_incr(&Counter
.server
.all
.kbytes_in
, len
);
193 kb_incr(&Counter
.server
.other
.kbytes_in
, len
);
194 sslState
->server
.len
+= len
;
196 cbdataLock(sslState
);
198 debug(50, 1) ("sslReadServer: FD %d: read failure: %s\n",
200 if (!ignoreErrno(errno
))
202 } else if (len
== 0) {
203 comm_close(sslState
->server
.fd
);
205 if (cbdataValid(sslState
))
206 sslSetSelect(sslState
);
207 cbdataUnlock(sslState
);
210 /* Read from client side and queue it for writing to the server */
212 sslReadClient(int fd
, void *data
)
214 SslStateData
*sslState
= data
;
216 assert(fd
== sslState
->client
.fd
);
217 debug(26, 3) ("sslReadClient: FD %d, reading %d bytes at offset %d\n",
218 fd
, SQUID_TCP_SO_RCVBUF
- sslState
->client
.len
,
219 sslState
->client
.len
);
221 sslState
->client
.buf
+ sslState
->client
.len
,
222 SQUID_TCP_SO_RCVBUF
- sslState
->client
.len
);
223 debug(26, 3) ("sslReadClient: FD %d, read %d bytes\n", fd
, len
);
225 fd_bytes(fd
, len
, FD_READ
);
226 kb_incr(&Counter
.client_http
.kbytes_in
, len
);
227 sslState
->client
.len
+= len
;
229 cbdataLock(sslState
);
231 debug(50, 1) ("sslReadClient: FD %d: read failure: %s\n",
233 if (!ignoreErrno(errno
))
235 } else if (len
== 0) {
238 if (cbdataValid(sslState
))
239 sslSetSelect(sslState
);
240 cbdataUnlock(sslState
);
243 /* Writes data from the client buffer to the server side */
245 sslWriteServer(int fd
, void *data
)
247 SslStateData
*sslState
= data
;
249 assert(fd
== sslState
->server
.fd
);
250 debug(26, 3) ("sslWriteServer: FD %d, %d bytes to write\n",
251 fd
, sslState
->client
.len
);
253 sslState
->client
.buf
,
254 sslState
->client
.len
);
255 debug(26, 3) ("sslWriteServer: FD %d, %d bytes written\n", fd
, len
);
257 fd_bytes(fd
, len
, FD_WRITE
);
258 kb_incr(&Counter
.server
.all
.kbytes_out
, len
);
259 kb_incr(&Counter
.server
.other
.kbytes_out
, len
);
260 assert(len
<= sslState
->client
.len
);
261 sslState
->client
.len
-= len
;
262 if (sslState
->client
.len
> 0) {
263 /* we didn't write the whole thing */
264 xmemmove(sslState
->client
.buf
,
265 sslState
->client
.buf
+ len
,
266 sslState
->client
.len
);
269 cbdataLock(sslState
);
271 debug(50, 1) ("sslWriteServer: FD %d: write failure: %s.\n",
273 if (!ignoreErrno(errno
))
276 if (cbdataValid(sslState
))
277 sslSetSelect(sslState
);
278 cbdataUnlock(sslState
);
281 /* Writes data from the server buffer to the client side */
283 sslWriteClient(int fd
, void *data
)
285 SslStateData
*sslState
= data
;
287 assert(fd
== sslState
->client
.fd
);
288 debug(26, 3) ("sslWriteClient: FD %d, %d bytes to write\n",
289 fd
, sslState
->server
.len
);
291 sslState
->server
.buf
,
292 sslState
->server
.len
);
293 debug(26, 3) ("sslWriteClient: FD %d, %d bytes written\n", fd
, len
);
295 fd_bytes(fd
, len
, FD_WRITE
);
296 kb_incr(&Counter
.client_http
.kbytes_out
, len
);
297 assert(len
<= sslState
->server
.len
);
298 sslState
->server
.len
-= len
;
299 /* increment total object size */
300 if (sslState
->size_ptr
)
301 *sslState
->size_ptr
+= len
;
302 if (sslState
->server
.len
> 0) {
303 /* we didn't write the whole thing */
304 xmemmove(sslState
->server
.buf
,
305 sslState
->server
.buf
+ len
,
306 sslState
->server
.len
);
309 cbdataLock(sslState
);
311 debug(50, 1) ("sslWriteClient: FD %d: write failure: %s.\n",
313 if (!ignoreErrno(errno
))
316 if (cbdataValid(sslState
))
317 sslSetSelect(sslState
);
318 cbdataUnlock(sslState
);
322 sslTimeout(int fd
, void *data
)
324 SslStateData
*sslState
= data
;
325 debug(26, 3) ("sslTimeout: FD %d\n", fd
);
326 if (sslState
->client
.fd
> -1)
327 comm_close(sslState
->client
.fd
);
328 if (sslState
->server
.fd
> -1)
329 comm_close(sslState
->server
.fd
);
333 sslConnected(int fd
, void *data
)
335 SslStateData
*sslState
= data
;
336 debug(26, 3) ("sslConnected: FD %d sslState=%p\n", fd
, sslState
);
337 xstrncpy(sslState
->server
.buf
, conn_established
, SQUID_TCP_SO_RCVBUF
);
338 sslState
->server
.len
= strlen(conn_established
);
339 sslSetSelect(sslState
);
343 sslErrorComplete(int fdnotused
, void *data
, size_t sizenotused
)
345 SslStateData
*sslState
= data
;
346 assert(sslState
!= NULL
);
347 if (sslState
->client
.fd
> -1)
348 comm_close(sslState
->client
.fd
);
349 if (sslState
->server
.fd
> -1)
350 comm_close(sslState
->server
.fd
);
355 sslConnectDone(int fdnotused
, int status
, void *data
)
357 SslStateData
*sslState
= data
;
358 request_t
*request
= sslState
->request
;
359 ErrorState
*err
= NULL
;
360 if (status
== COMM_ERR_DNS
) {
361 debug(26, 4) ("sslConnect: Unknown host: %s\n", sslState
->host
);
362 err
= errorCon(ERR_DNS_FAIL
, HTTP_NOT_FOUND
);
363 err
->request
= requestLink(request
);
364 err
->dnsserver_msg
= xstrdup(dns_error_message
);
365 err
->callback
= sslErrorComplete
;
366 err
->callback_data
= sslState
;
367 errorSend(sslState
->client
.fd
, err
);
368 } else if (status
!= COMM_OK
) {
369 err
= errorCon(ERR_CONNECT_FAIL
, HTTP_SERVICE_UNAVAILABLE
);
371 err
->host
= xstrdup(sslState
->host
);
372 err
->port
= sslState
->port
;
373 err
->request
= requestLink(request
);
374 err
->callback
= sslErrorComplete
;
375 err
->callback_data
= sslState
;
376 errorSend(sslState
->client
.fd
, err
);
378 if (sslState
->proxying
)
379 sslProxyConnected(sslState
->server
.fd
, sslState
);
381 sslConnected(sslState
->server
.fd
, sslState
);
382 commSetTimeout(sslState
->server
.fd
,
387 commSetDefer(sslState
->server
.fd
, sslDeferServerRead
, sslState
->request
);
393 sslStart(int fd
, const char *url
, request_t
* request
, size_t * size_ptr
)
395 /* Create state structure. */
396 SslStateData
*sslState
= NULL
;
398 ErrorState
*err
= NULL
;
399 debug(26, 3) ("sslStart: '%s %s'\n",
400 RequestMethodStr
[request
->method
], url
);
401 Counter
.server
.all
.requests
++;
402 Counter
.server
.other
.requests
++;
404 sock
= comm_open(SOCK_STREAM
,
406 Config
.Addrs
.tcp_outgoing
,
410 if (sock
== COMM_ERROR
) {
411 debug(26, 4) ("sslStart: Failed because we're out of sockets.\n");
412 err
= errorCon(ERR_SOCKET_FAILURE
, HTTP_INTERNAL_SERVER_ERROR
);
414 err
->request
= requestLink(request
);
418 sslState
= xcalloc(1, sizeof(SslStateData
));
419 cbdataAdd(sslState
, MEM_NONE
);
420 sslState
->url
= xstrdup(url
);
421 sslState
->request
= requestLink(request
);
422 sslState
->size_ptr
= size_ptr
;
423 sslState
->client
.fd
= fd
;
424 sslState
->server
.fd
= sock
;
425 sslState
->server
.buf
= xmalloc(SQUID_TCP_SO_RCVBUF
);
426 sslState
->client
.buf
= xmalloc(SQUID_TCP_SO_RCVBUF
);
427 comm_add_close_handler(sslState
->server
.fd
,
430 comm_add_close_handler(sslState
->client
.fd
,
433 commSetTimeout(sslState
->client
.fd
,
434 Config
.Timeout
.lifetime
,
437 commSetTimeout(sslState
->server
.fd
,
438 Config
.Timeout
.connect
,
443 sslPeerSelectComplete
,
447 * Disable the client read handler until peer selection is complete
448 * Take control away from client_side.c.
450 commSetSelect(sslState
->client
.fd
, COMM_SELECT_READ
, NULL
, NULL
, 0);
454 sslProxyConnected(int fd
, void *data
)
456 SslStateData
*sslState
= data
;
460 debug(26, 3) ("sslProxyConnected: FD %d sslState=%p\n", fd
, sslState
);
462 memBufPrintf(&mb
, "CONNECT %s HTTP/1.0\r\n", sslState
->url
);
463 httpBuildRequestHeader(sslState
->request
,
465 NULL
, /* StoreEntry */
469 packerToMemInit(&p
, &mb
);
470 httpHeaderPackInto(&hdr_out
, &p
);
471 httpHeaderClean(&hdr_out
);
473 memBufAppend(&mb
, "\r\n", 2);
474 xstrncpy(sslState
->client
.buf
, mb
.buf
, SQUID_TCP_SO_RCVBUF
);
475 debug(26, 3) ("sslProxyConnected: Sending {%s}\n", sslState
->client
.buf
);
476 sslState
->client
.len
= mb
.size
;
478 commSetTimeout(sslState
->server
.fd
,
482 sslSetSelect(sslState
);
486 sslPeerSelectComplete(peer
* p
, void *data
)
488 SslStateData
*sslState
= data
;
489 request_t
*request
= sslState
->request
;
491 sslState
->proxying
= p
? 1 : 0;
492 sslState
->host
= p
? p
->host
: request
->host
;
494 sslState
->port
= request
->port
;
495 } else if (p
->http_port
!= 0) {
496 sslState
->port
= p
->http_port
;
497 } else if ((g
= peerFindByName(p
->host
))) {
498 sslState
->port
= g
->http_port
;
500 sslState
->port
= CACHE_HTTP_PORT
;
502 commConnectStart(sslState
->server
.fd
,
510 sslPeerSelectFail(peer
* peernotused
, void *data
)
512 SslStateData
*sslState
= data
;
514 err
= errorCon(ERR_CANNOT_FORWARD
, HTTP_SERVICE_UNAVAILABLE
);
515 err
->request
= requestLink(sslState
->request
);
516 err
->callback
= sslErrorComplete
;
517 err
->callback_data
= sslState
;
518 errorSend(sslState
->client
.fd
, err
);