3 * $Id: ssl.cc,v 1.122 2002/09/15 06:40:57 robertc Exp $
5 * DEBUG: section 26 Secure Sockets Layer Proxy
6 * AUTHOR: Duane Wessels
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
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.
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 */
49 size_t *size_ptr
; /* pointer to size in an ConnStateData for logging */
50 int *status_ptr
; /* pointer to status for logging */
56 static const char *const conn_established
= "HTTP/1.0 200 Connection established\r\n\r\n";
58 static CNCB sslConnectDone
;
59 static ERCB sslErrorComplete
;
60 static PF sslServerClosed
;
61 static PF sslClientClosed
;
62 static PF sslReadClient
;
63 static PF sslReadServer
;
65 static PF sslWriteClient
;
66 static PF sslWriteServer
;
67 static PSC sslPeerSelectComplete
;
68 static void sslStateFree(SslStateData
* sslState
);
69 static void sslConnected(int fd
, void *);
70 static void sslProxyConnected(int fd
, void *);
71 static void sslSetSelect(SslStateData
* sslState
);
73 static DEFER sslDeferServerRead
;
77 sslServerClosed(int fd
, void *data
)
79 SslStateData
*sslState
= data
;
80 debug(26, 3) ("sslServerClosed: FD %d\n", fd
);
81 assert(fd
== sslState
->server
.fd
);
82 sslState
->server
.fd
= -1;
83 if (sslState
->client
.fd
== -1)
84 sslStateFree(sslState
);
88 sslClientClosed(int fd
, void *data
)
90 SslStateData
*sslState
= data
;
91 debug(26, 3) ("sslClientClosed: FD %d\n", fd
);
92 assert(fd
== sslState
->client
.fd
);
93 sslState
->client
.fd
= -1;
94 if (sslState
->server
.fd
== -1)
95 sslStateFree(sslState
);
99 sslStateFree(SslStateData
* sslState
)
101 debug(26, 3) ("sslStateFree: sslState=%p\n", sslState
);
102 assert(sslState
!= NULL
);
103 assert(sslState
->client
.fd
== -1);
104 assert(sslState
->server
.fd
== -1);
105 safe_free(sslState
->server
.buf
);
106 safe_free(sslState
->client
.buf
);
107 safe_free(sslState
->url
);
108 fwdServersFree(&sslState
->servers
);
109 sslState
->host
= NULL
;
110 requestUnlink(sslState
->request
);
111 sslState
->request
= NULL
;
113 delayUnregisterDelayIdPtr(&sslState
->delay_id
);
115 cbdataFree(sslState
);
120 sslDeferServerRead(int fdnotused
, void *data
)
122 SslStateData
*s
= data
;
123 int i
= delayBytesWanted(s
->delay_id
, 0, INT_MAX
);
133 sslSetSelect(SslStateData
* sslState
)
135 size_t read_sz
= SQUID_TCP_SO_RCVBUF
;
136 assert(sslState
->server
.fd
> -1 || sslState
->client
.fd
> -1);
137 if (sslState
->client
.fd
> -1) {
138 if (sslState
->server
.len
> 0) {
139 commSetSelect(sslState
->client
.fd
,
145 if (sslState
->client
.len
< read_sz
) {
146 commSetSelect(sslState
->client
.fd
,
150 Config
.Timeout
.read
);
152 } else if (sslState
->client
.len
== 0) {
153 comm_close(sslState
->server
.fd
);
155 if (sslState
->server
.fd
> -1) {
156 if (sslState
->client
.len
> 0) {
157 commSetSelect(sslState
->server
.fd
,
165 * If this was allowed to return 0, there would be a possibility
166 * of the socket becoming "hung" with data accumulating but no
167 * write handler (server.len==0) and no read handler (!(0<0)) and
168 * no data flowing in the other direction. Hence the argument of
171 read_sz
= delayBytesWanted(sslState
->delay_id
, 1, read_sz
);
173 if (sslState
->server
.len
< read_sz
) {
174 /* Have room to read more */
175 commSetSelect(sslState
->server
.fd
,
179 Config
.Timeout
.read
);
181 } else if (sslState
->client
.fd
== -1) {
182 /* client already closed, nothing more to do */
183 } else if (sslState
->server
.len
== 0) {
184 comm_close(sslState
->client
.fd
);
188 /* Read from server side and queue it for writing to the client */
190 sslReadServer(int fd
, void *data
)
192 SslStateData
*sslState
= data
;
194 size_t read_sz
= SQUID_TCP_SO_RCVBUF
- sslState
->server
.len
;
195 assert(fd
== sslState
->server
.fd
);
196 debug(26, 3) ("sslReadServer: FD %d, reading %d bytes at offset %d\n",
197 fd
, (int) read_sz
, sslState
->server
.len
);
200 read_sz
= delayBytesWanted(sslState
->delay_id
, 1, read_sz
);
202 statCounter
.syscalls
.sock
.reads
++;
203 len
= FD_READ_METHOD(fd
, sslState
->server
.buf
+ sslState
->server
.len
, read_sz
);
204 debug(26, 3) ("sslReadServer: FD %d, read %d bytes\n", fd
, len
);
206 fd_bytes(fd
, len
, FD_READ
);
208 delayBytesIn(sslState
->delay_id
, len
);
210 kb_incr(&statCounter
.server
.all
.kbytes_in
, len
);
211 kb_incr(&statCounter
.server
.other
.kbytes_in
, len
);
212 sslState
->server
.len
+= len
;
214 cbdataInternalLock(sslState
); /* ??? should be locked by the caller... */
216 debug(50, ignoreErrno(errno
) ? 3 : 1)
217 ("sslReadServer: FD %d: read failure: %s\n", fd
, xstrerror());
218 if (!ignoreErrno(errno
))
220 } else if (len
== 0) {
221 comm_close(sslState
->server
.fd
);
223 if (cbdataReferenceValid(sslState
))
224 sslSetSelect(sslState
);
225 cbdataInternalUnlock(sslState
); /* ??? */
228 /* Read from client side and queue it for writing to the server */
230 sslReadClient(int fd
, void *data
)
232 SslStateData
*sslState
= data
;
234 assert(fd
== sslState
->client
.fd
);
235 debug(26, 3) ("sslReadClient: FD %d, reading %d bytes at offset %d\n",
236 fd
, SQUID_TCP_SO_RCVBUF
- sslState
->client
.len
,
237 sslState
->client
.len
);
238 statCounter
.syscalls
.sock
.reads
++;
239 len
= FD_READ_METHOD(fd
,
240 sslState
->client
.buf
+ sslState
->client
.len
,
241 SQUID_TCP_SO_RCVBUF
- sslState
->client
.len
);
242 debug(26, 3) ("sslReadClient: FD %d, read %d bytes\n", fd
, len
);
244 fd_bytes(fd
, len
, FD_READ
);
245 kb_incr(&statCounter
.client_http
.kbytes_in
, len
);
246 sslState
->client
.len
+= len
;
248 cbdataInternalLock(sslState
); /* ??? should be locked by the caller... */
252 if (errno
== ECONNRESET
)
255 if (ignoreErrno(errno
))
257 debug(50, level
) ("sslReadClient: FD %d: read failure: %s\n",
259 if (!ignoreErrno(errno
))
261 } else if (len
== 0) {
264 if (cbdataReferenceValid(sslState
))
265 sslSetSelect(sslState
);
266 cbdataInternalUnlock(sslState
); /* ??? */
269 /* Writes data from the client buffer to the server side */
271 sslWriteServer(int fd
, void *data
)
273 SslStateData
*sslState
= data
;
275 assert(fd
== sslState
->server
.fd
);
276 debug(26, 3) ("sslWriteServer: FD %d, %d bytes to write\n",
277 fd
, sslState
->client
.len
);
278 statCounter
.syscalls
.sock
.writes
++;
279 len
= FD_WRITE_METHOD(fd
,
280 sslState
->client
.buf
,
281 sslState
->client
.len
);
282 debug(26, 3) ("sslWriteServer: FD %d, %d bytes written\n", fd
, len
);
284 fd_bytes(fd
, len
, FD_WRITE
);
285 kb_incr(&statCounter
.server
.all
.kbytes_out
, len
);
286 kb_incr(&statCounter
.server
.other
.kbytes_out
, len
);
287 assert(len
<= sslState
->client
.len
);
288 sslState
->client
.len
-= len
;
289 if (sslState
->client
.len
> 0) {
290 /* we didn't write the whole thing */
291 xmemmove(sslState
->client
.buf
,
292 sslState
->client
.buf
+ len
,
293 sslState
->client
.len
);
296 cbdataInternalLock(sslState
); /* ??? should be locked by the caller... */
298 debug(50, ignoreErrno(errno
) ? 3 : 1)
299 ("sslWriteServer: FD %d: write failure: %s.\n", fd
, xstrerror());
300 if (!ignoreErrno(errno
))
303 if (cbdataReferenceValid(sslState
))
304 sslSetSelect(sslState
);
305 cbdataInternalUnlock(sslState
); /* ??? */
308 /* Writes data from the server buffer to the client side */
310 sslWriteClient(int fd
, void *data
)
312 SslStateData
*sslState
= data
;
314 assert(fd
== sslState
->client
.fd
);
315 debug(26, 3) ("sslWriteClient: FD %d, %d bytes to write\n",
316 fd
, sslState
->server
.len
);
317 statCounter
.syscalls
.sock
.writes
++;
318 len
= FD_WRITE_METHOD(fd
,
319 sslState
->server
.buf
,
320 sslState
->server
.len
);
321 debug(26, 3) ("sslWriteClient: FD %d, %d bytes written\n", fd
, len
);
323 fd_bytes(fd
, len
, FD_WRITE
);
324 kb_incr(&statCounter
.client_http
.kbytes_out
, len
);
325 assert(len
<= sslState
->server
.len
);
326 sslState
->server
.len
-= len
;
327 /* increment total object size */
328 if (sslState
->size_ptr
)
329 *sslState
->size_ptr
+= len
;
330 if (sslState
->server
.len
> 0) {
331 /* we didn't write the whole thing */
332 xmemmove(sslState
->server
.buf
,
333 sslState
->server
.buf
+ len
,
334 sslState
->server
.len
);
337 cbdataInternalLock(sslState
); /* ??? should be locked by the caller... */
339 debug(50, ignoreErrno(errno
) ? 3 : 1)
340 ("sslWriteClient: FD %d: write failure: %s.\n", fd
, xstrerror());
341 if (!ignoreErrno(errno
))
344 if (cbdataReferenceValid(sslState
))
345 sslSetSelect(sslState
);
346 cbdataInternalUnlock(sslState
); /* ??? */
350 sslTimeout(int fd
, void *data
)
352 SslStateData
*sslState
= data
;
353 debug(26, 3) ("sslTimeout: FD %d\n", fd
);
354 if (sslState
->client
.fd
> -1)
355 comm_close(sslState
->client
.fd
);
356 if (sslState
->server
.fd
> -1)
357 comm_close(sslState
->server
.fd
);
361 sslConnected(int fd
, void *data
)
363 SslStateData
*sslState
= data
;
364 debug(26, 3) ("sslConnected: FD %d sslState=%p\n", fd
, sslState
);
365 *sslState
->status_ptr
= HTTP_OK
;
366 xstrncpy(sslState
->server
.buf
, conn_established
, SQUID_TCP_SO_RCVBUF
);
367 sslState
->server
.len
= strlen(conn_established
);
368 sslSetSelect(sslState
);
372 sslErrorComplete(int fdnotused
, void *data
, size_t sizenotused
)
374 SslStateData
*sslState
= data
;
375 assert(sslState
!= NULL
);
376 if (sslState
->client
.fd
> -1)
377 comm_close(sslState
->client
.fd
);
378 if (sslState
->server
.fd
> -1)
379 comm_close(sslState
->server
.fd
);
384 sslConnectDone(int fdnotused
, comm_err_t status
, void *data
)
386 SslStateData
*sslState
= data
;
387 request_t
*request
= sslState
->request
;
388 ErrorState
*err
= NULL
;
389 if (sslState
->servers
->_peer
)
390 hierarchyNote(&sslState
->request
->hier
, sslState
->servers
->code
,
391 sslState
->servers
->_peer
->host
);
392 else if (Config
.onoff
.log_ip_on_direct
)
393 hierarchyNote(&sslState
->request
->hier
, sslState
->servers
->code
,
394 fd_table
[sslState
->server
.fd
].ipaddr
);
396 hierarchyNote(&sslState
->request
->hier
, sslState
->servers
->code
,
398 if (status
== COMM_ERR_DNS
) {
399 debug(26, 4) ("sslConnect: Unknown host: %s\n", sslState
->host
);
400 err
= errorCon(ERR_DNS_FAIL
, HTTP_NOT_FOUND
);
401 *sslState
->status_ptr
= HTTP_NOT_FOUND
;
402 err
->request
= requestLink(request
);
403 err
->dnsserver_msg
= xstrdup(dns_error_message
);
404 err
->callback
= sslErrorComplete
;
405 err
->callback_data
= sslState
;
406 errorSend(sslState
->client
.fd
, err
);
407 } else if (status
!= COMM_OK
) {
408 err
= errorCon(ERR_CONNECT_FAIL
, HTTP_SERVICE_UNAVAILABLE
);
409 *sslState
->status_ptr
= HTTP_SERVICE_UNAVAILABLE
;
411 err
->host
= xstrdup(sslState
->host
);
412 err
->port
= sslState
->port
;
413 err
->request
= requestLink(request
);
414 err
->callback
= sslErrorComplete
;
415 err
->callback_data
= sslState
;
416 errorSend(sslState
->client
.fd
, err
);
418 if (sslState
->servers
->_peer
)
419 sslProxyConnected(sslState
->server
.fd
, sslState
);
421 sslConnected(sslState
->server
.fd
, sslState
);
422 commSetTimeout(sslState
->server
.fd
,
427 commSetDefer(sslState
->server
.fd
, sslDeferServerRead
, sslState
);
432 CBDATA_TYPE(SslStateData
);
434 sslStart(clientHttpRequest
* http
, size_t * size_ptr
, int *status_ptr
)
436 /* Create state structure. */
437 SslStateData
*sslState
= NULL
;
439 ErrorState
*err
= NULL
;
442 int fd
= http
->conn
->fd
;
443 request_t
*request
= http
->request
;
444 char *url
= http
->uri
;
446 * client_addr == no_addr indicates this is an "internal" request
447 * from peer_digest.c, asn.c, netdb.c, etc and should always
448 * be allowed. yuck, I know.
450 if (request
->client_addr
.s_addr
!= no_addr
.s_addr
) {
452 * Check if this host is allowed to fetch MISSES from us (miss_access)
454 memset(&ch
, '\0', sizeof(aclCheck_t
));
455 ch
.src_addr
= request
->client_addr
;
456 ch
.my_addr
= request
->my_addr
;
457 ch
.my_port
= request
->my_port
;
458 ch
.request
= request
;
459 answer
= aclCheckFast(Config
.accessList
.miss
, &ch
);
461 err
= errorCon(ERR_FORWARDING_DENIED
, HTTP_FORBIDDEN
);
462 *status_ptr
= HTTP_FORBIDDEN
;
463 err
->request
= requestLink(request
);
464 err
->src_addr
= request
->client_addr
;
469 debug(26, 3) ("sslStart: '%s %s'\n",
470 RequestMethodStr
[request
->method
], url
);
471 statCounter
.server
.all
.requests
++;
472 statCounter
.server
.other
.requests
++;
474 sock
= comm_openex(SOCK_STREAM
,
476 getOutgoingAddr(request
),
479 getOutgoingTOS(request
),
481 if (sock
== COMM_ERROR
) {
482 debug(26, 4) ("sslStart: Failed because we're out of sockets.\n");
483 err
= errorCon(ERR_SOCKET_FAILURE
, HTTP_INTERNAL_SERVER_ERROR
);
484 *status_ptr
= HTTP_INTERNAL_SERVER_ERROR
;
486 err
->request
= requestLink(request
);
490 CBDATA_INIT_TYPE(SslStateData
);
491 sslState
= cbdataAlloc(SslStateData
);
493 sslState
->delay_id
= delayClient(http
);
494 delayRegisterDelayIdPtr(&sslState
->delay_id
);
496 sslState
->url
= xstrdup(url
);
497 sslState
->request
= requestLink(request
);
498 sslState
->size_ptr
= size_ptr
;
499 sslState
->status_ptr
= status_ptr
;
500 sslState
->client
.fd
= fd
;
501 sslState
->server
.fd
= sock
;
502 sslState
->server
.buf
= xmalloc(SQUID_TCP_SO_RCVBUF
);
503 sslState
->client
.buf
= xmalloc(SQUID_TCP_SO_RCVBUF
);
504 comm_add_close_handler(sslState
->server
.fd
,
507 comm_add_close_handler(sslState
->client
.fd
,
510 commSetTimeout(sslState
->client
.fd
,
511 Config
.Timeout
.lifetime
,
514 commSetTimeout(sslState
->server
.fd
,
515 Config
.Timeout
.connect
,
520 sslPeerSelectComplete
,
523 * Disable the client read handler until peer selection is complete
524 * Take control away from client_side.c.
526 commSetSelect(sslState
->client
.fd
, COMM_SELECT_READ
, NULL
, NULL
, 0);
530 sslProxyConnected(int fd
, void *data
)
532 SslStateData
*sslState
= data
;
536 http_state_flags flags
;
537 debug(26, 3) ("sslProxyConnected: FD %d sslState=%p\n", fd
, sslState
);
538 memset(&flags
, '\0', sizeof(flags
));
539 flags
.proxying
= sslState
->request
->flags
.proxying
;
541 memBufPrintf(&mb
, "CONNECT %s HTTP/1.0\r\n", sslState
->url
);
542 httpBuildRequestHeader(sslState
->request
,
544 NULL
, /* StoreEntry */
548 packerToMemInit(&p
, &mb
);
549 httpHeaderPackInto(&hdr_out
, &p
);
550 httpHeaderClean(&hdr_out
);
552 memBufAppend(&mb
, "\r\n", 2);
553 xstrncpy(sslState
->client
.buf
, mb
.buf
, SQUID_TCP_SO_RCVBUF
);
554 debug(26, 3) ("sslProxyConnected: Sending {%s}\n", sslState
->client
.buf
);
555 sslState
->client
.len
= mb
.size
;
557 commSetTimeout(sslState
->server
.fd
,
561 sslSetSelect(sslState
);
565 sslPeerSelectComplete(FwdServer
* fs
, void *data
)
567 SslStateData
*sslState
= data
;
568 request_t
*request
= sslState
->request
;
572 err
= errorCon(ERR_CANNOT_FORWARD
, HTTP_SERVICE_UNAVAILABLE
);
573 *sslState
->status_ptr
= HTTP_SERVICE_UNAVAILABLE
;
574 err
->request
= requestLink(sslState
->request
);
575 err
->callback
= sslErrorComplete
;
576 err
->callback_data
= sslState
;
577 errorSend(sslState
->client
.fd
, err
);
580 sslState
->servers
= fs
;
581 sslState
->host
= fs
->_peer
? fs
->_peer
->host
: request
->host
;
582 if (fs
->_peer
== NULL
) {
583 sslState
->port
= request
->port
;
584 } else if (fs
->_peer
->http_port
!= 0) {
585 sslState
->port
= fs
->_peer
->http_port
;
586 } else if ((g
= peerFindByName(fs
->_peer
->host
))) {
587 sslState
->port
= g
->http_port
;
589 sslState
->port
= CACHE_HTTP_PORT
;
592 sslState
->request
->peer_login
= fs
->_peer
->login
;
593 sslState
->request
->flags
.proxying
= 1;
595 sslState
->request
->peer_login
= NULL
;
596 sslState
->request
->flags
.proxying
= 0;
599 /* no point using the delayIsNoDelay stuff since ssl is nice and simple */
600 if (g
&& g
->options
.no_delay
&& sslState
->delay_id
) {
601 delayUnregisterDelayIdPtr(&sslState
->delay_id
);
602 sslState
->delay_id
= 0;
605 commConnectStart(sslState
->server
.fd
,