]> git.ipfire.org Git - thirdparty/squid.git/blame - src/ssl.cc
move bunch of options to Config.onoff
[thirdparty/squid.git] / src / ssl.cc
CommitLineData
95d659f0 1
983061ed 2/*
78f1250a 3 * $Id: ssl.cc,v 1.59 1997/07/21 07:21:01 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/
30a4f2a8 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;
98ffb7e4 36 char *host; /* either request->host or proxy host */
37 u_short port;
983061ed 38 request_t *request;
983061ed 39 struct {
40 int fd;
41 int len;
42 int offset;
43 char *buf;
44 } client, server;
88738790 45 size_t *size_ptr; /* pointer to size in an ConnStateData for logging */
93868820 46 int proxying;
983061ed 47} SslStateData;
48
0ee4272b 49static const char *const conn_established = "HTTP/1.0 200 Connection established\r\n\r\n";
983061ed 50
5c5783a2 51static PF sslTimeout;
b177367b 52static void sslReadServer _PARAMS((int fd, void *));
53static void sslReadClient _PARAMS((int fd, void *));
54static void sslWriteServer _PARAMS((int fd, void *));
55static void sslWriteClient _PARAMS((int fd, void *));
56static void sslConnected _PARAMS((int fd, void *));
57static void sslProxyConnected _PARAMS((int fd, void *));
67508012 58static void sslErrorComplete _PARAMS((int, char *, int, int, void *));
59static void sslClose _PARAMS((SslStateData * sslState));
b177367b 60static void sslClientClosed _PARAMS((int fd, void *));
e5f6c5c2 61static void sslConnectDone _PARAMS((int fd, int status, void *data));
b177367b 62static void sslStateFree _PARAMS((int fd, void *data));
b6c0e933 63static void sslPeerSelectComplete _PARAMS((peer * p, void *data));
64static void sslPeerSelectFail _PARAMS((peer * p, void *data));
30a4f2a8 65
b8d8561b 66static void
67sslClose(SslStateData * sslState)
30a4f2a8 68{
69 if (sslState->client.fd > -1) {
70 /* remove the "unexpected" client close handler */
71 comm_remove_close_handler(sslState->client.fd,
b177367b 72 sslClientClosed,
cd1fb0eb 73 sslState);
30a4f2a8 74 comm_close(sslState->client.fd);
75 sslState->client.fd = -1;
76 }
77 if (sslState->server.fd > -1) {
78 comm_close(sslState->server.fd);
79 }
80}
81
82/* This is called only if the client connect closes unexpectedly,
83 * ie from icpDetectClientClose() */
b177367b 84static void
85sslClientClosed(int fd, void *data)
30a4f2a8 86{
b177367b 87 SslStateData *sslState = data;
a3d5953d 88 debug(26, 3) ("sslClientClosed: FD %d\n", fd);
30a4f2a8 89 /* we have been called from comm_close for the client side, so
90 * just need to clean up the server side */
f990cccc 91 protoUnregister(NULL, sslState->request, no_addr);
30a4f2a8 92 comm_close(sslState->server.fd);
30a4f2a8 93}
983061ed 94
b177367b 95static void
96sslStateFree(int fd, void *data)
983061ed 97{
b177367b 98 SslStateData *sslState = data;
a3d5953d 99 debug(26, 3) ("sslStateFree: FD %d, sslState=%p\n", fd, sslState);
983061ed 100 if (sslState == NULL)
b177367b 101 return;
983061ed 102 if (fd != sslState->server.fd)
103 fatal_dump("sslStateFree: FD mismatch!\n");
983061ed 104 safe_free(sslState->server.buf);
105 safe_free(sslState->client.buf);
106 xfree(sslState->url);
30a4f2a8 107 requestUnlink(sslState->request);
7dd44885 108 sslState->request = NULL;
109 cbdataFree(sslState);
983061ed 110}
111
983061ed 112/* Read from server side and queue it for writing to the client */
b8d8561b 113static void
b177367b 114sslReadServer(int fd, void *data)
983061ed 115{
b177367b 116 SslStateData *sslState = data;
983061ed 117 int len;
30a4f2a8 118 len = read(sslState->server.fd, sslState->server.buf, SQUID_TCP_SO_RCVBUF);
4f92c80c 119 fd_bytes(sslState->server.fd, len, FD_READ);
a3d5953d 120 debug(26, 5) ("sslReadServer FD %d, read %d bytes\n", fd, len);
983061ed 121 if (len < 0) {
a3d5953d 122 debug(50, 1) ("sslReadServer: FD %d: read failure: %s\n",
983061ed 123 sslState->server.fd, xstrerror());
0a0bf5db 124 if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
983061ed 125 /* reinstall handlers */
126 /* XXX This may loop forever */
b177367b 127 commSetSelect(sslState->server.fd,
983061ed 128 COMM_SELECT_READ,
b177367b 129 sslReadServer,
cd1fb0eb 130 sslState, 0);
88738790 131 commSetTimeout(sslState->server.fd,
132 Config.Timeout.read,
133 NULL,
134 NULL);
983061ed 135 } else {
30a4f2a8 136 sslClose(sslState);
983061ed 137 }
138 } else if (len == 0) {
139 /* Connection closed; retrieval done. */
30a4f2a8 140 sslClose(sslState);
983061ed 141 } else {
142 sslState->server.offset = 0;
143 sslState->server.len = len;
4f92c80c 144 /* extend server read timeout */
145 commSetTimeout(sslState->server.fd, Config.Timeout.read, NULL, NULL);
b177367b 146 commSetSelect(sslState->client.fd,
983061ed 147 COMM_SELECT_WRITE,
b177367b 148 sslWriteClient,
cd1fb0eb 149 sslState, 0);
983061ed 150 }
151}
152
153/* Read from client side and queue it for writing to the server */
b8d8561b 154static void
b177367b 155sslReadClient(int fd, void *data)
983061ed 156{
b177367b 157 SslStateData *sslState = data;
983061ed 158 int len;
30a4f2a8 159 len = read(sslState->client.fd, sslState->client.buf, SQUID_TCP_SO_RCVBUF);
4f92c80c 160 fd_bytes(sslState->client.fd, len, FD_READ);
a3d5953d 161 debug(26, 5) ("sslReadClient FD %d, read %d bytes\n",
983061ed 162 sslState->client.fd, len);
163 if (len < 0) {
a3d5953d 164 debug(50, 1) ("sslReadClient: FD %d: read failure: %s\n",
983061ed 165 fd, xstrerror());
0a0bf5db 166 if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
983061ed 167 /* reinstall handlers */
168 /* XXX This may loop forever */
b177367b 169 commSetSelect(sslState->client.fd,
983061ed 170 COMM_SELECT_READ,
b177367b 171 sslReadClient,
cd1fb0eb 172 sslState, 0);
983061ed 173 } else {
30a4f2a8 174 sslClose(sslState);
983061ed 175 }
176 } else if (len == 0) {
177 /* Connection closed; retrieval done. */
30a4f2a8 178 sslClose(sslState);
983061ed 179 } else {
180 sslState->client.offset = 0;
181 sslState->client.len = len;
b177367b 182 commSetSelect(sslState->server.fd,
983061ed 183 COMM_SELECT_WRITE,
b177367b 184 sslWriteServer,
cd1fb0eb 185 sslState, 0);
983061ed 186 }
187}
188
189/* Writes data from the client buffer to the server side */
b8d8561b 190static void
b177367b 191sslWriteServer(int fd, void *data)
983061ed 192{
b177367b 193 SslStateData *sslState = data;
983061ed 194 int len;
195 len = write(sslState->server.fd,
196 sslState->client.buf + sslState->client.offset,
197 sslState->client.len - sslState->client.offset);
b69f7771 198 fd_bytes(fd, len, FD_WRITE);
a3d5953d 199 debug(26, 5) ("sslWriteServer FD %d, wrote %d bytes\n", fd, len);
983061ed 200 if (len < 0) {
0a0bf5db 201 if (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK) {
202 commSetSelect(sslState->server.fd,
203 COMM_SELECT_WRITE,
204 sslWriteServer,
cd1fb0eb 205 sslState, 0);
0a0bf5db 206 return;
207 }
a3d5953d 208 debug(50, 2) ("sslWriteServer: FD %d: write failure: %s.\n",
983061ed 209 sslState->server.fd, xstrerror());
30a4f2a8 210 sslClose(sslState);
983061ed 211 return;
212 }
213 if ((sslState->client.offset += len) >= sslState->client.len) {
214 /* Done writing, read more */
b177367b 215 commSetSelect(sslState->client.fd,
983061ed 216 COMM_SELECT_READ,
b177367b 217 sslReadClient,
cd1fb0eb 218 sslState, 0);
88738790 219 commSetTimeout(sslState->server.fd,
220 Config.Timeout.read,
221 NULL,
222 NULL);
983061ed 223 } else {
224 /* still have more to write */
b177367b 225 commSetSelect(sslState->server.fd,
983061ed 226 COMM_SELECT_WRITE,
b177367b 227 sslWriteServer,
cd1fb0eb 228 sslState, 0);
983061ed 229 }
230}
231
232/* Writes data from the server buffer to the client side */
b8d8561b 233static void
b177367b 234sslWriteClient(int fd, void *data)
983061ed 235{
b177367b 236 SslStateData *sslState = data;
983061ed 237 int len;
a3d5953d 238 debug(26, 5) ("sslWriteClient FD %d len=%d offset=%d\n",
983061ed 239 fd,
240 sslState->server.len,
241 sslState->server.offset);
242 len = write(sslState->client.fd,
243 sslState->server.buf + sslState->server.offset,
244 sslState->server.len - sslState->server.offset);
b69f7771 245 fd_bytes(fd, len, FD_WRITE);
a3d5953d 246 debug(26, 5) ("sslWriteClient FD %d, wrote %d bytes\n", fd, len);
983061ed 247 if (len < 0) {
0a0bf5db 248 if (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK) {
249 commSetSelect(sslState->client.fd,
250 COMM_SELECT_WRITE,
251 sslWriteClient,
cd1fb0eb 252 sslState, 0);
0a0bf5db 253 return;
254 }
a3d5953d 255 debug(50, 2) ("sslWriteClient: FD %d: write failure: %s.\n",
983061ed 256 sslState->client.fd, xstrerror());
30a4f2a8 257 sslClose(sslState);
983061ed 258 return;
259 }
260 if (sslState->size_ptr)
261 *sslState->size_ptr += len; /* increment total object size */
262 if ((sslState->server.offset += len) >= sslState->server.len) {
263 /* Done writing, read more */
b177367b 264 commSetSelect(sslState->server.fd,
983061ed 265 COMM_SELECT_READ,
b177367b 266 sslReadServer,
cd1fb0eb 267 sslState, 0);
88738790 268 commSetTimeout(sslState->server.fd,
269 Config.Timeout.read,
270 NULL,
271 NULL);
983061ed 272 } else {
273 /* still have more to write */
b177367b 274 commSetSelect(sslState->client.fd,
983061ed 275 COMM_SELECT_WRITE,
b177367b 276 sslWriteClient,
cd1fb0eb 277 sslState, 0);
983061ed 278 }
279}
280
b8d8561b 281static void
5c5783a2 282sslTimeout(int fd, void *data)
983061ed 283{
b177367b 284 SslStateData *sslState = data;
a3d5953d 285 debug(26, 3) ("sslTimeout: FD %d\n", fd);
30a4f2a8 286 sslClose(sslState);
983061ed 287}
288
b8d8561b 289static void
b177367b 290sslConnected(int fd, void *data)
983061ed 291{
b177367b 292 SslStateData *sslState = data;
a3d5953d 293 debug(26, 3) ("sslConnected: FD %d sslState=%p\n", fd, sslState);
983061ed 294 strcpy(sslState->server.buf, conn_established);
295 sslState->server.len = strlen(conn_established);
296 sslState->server.offset = 0;
5c5783a2 297 commSetTimeout(sslState->server.fd, Config.Timeout.read, NULL, NULL);
b177367b 298 commSetSelect(sslState->client.fd,
983061ed 299 COMM_SELECT_WRITE,
b177367b 300 sslWriteClient,
cd1fb0eb 301 sslState, 0);
b177367b 302 commSetSelect(sslState->client.fd,
983061ed 303 COMM_SELECT_READ,
b177367b 304 sslReadClient,
cd1fb0eb 305 sslState, 0);
983061ed 306}
307
b8d8561b 308static void
309sslErrorComplete(int fd, char *buf, int size, int errflag, void *sslState)
30a4f2a8 310{
311 safe_free(buf);
b2186d32 312 if (sslState == NULL) {
313 debug_trap("sslErrorComplete: NULL sslState\n");
314 return;
315 }
30a4f2a8 316 sslClose(sslState);
317}
318
983061ed 319
b8d8561b 320static void
edeb28fd 321sslConnectDone(int fd, int status, void *data)
983061ed 322{
b15fe823 323 SslStateData *sslState = data;
30a4f2a8 324 request_t *request = sslState->request;
30a4f2a8 325 char *buf = NULL;
edeb28fd 326 if (status == COMM_ERR_DNS) {
a3d5953d 327 debug(26, 4) ("sslConnect: Unknown host: %s\n", sslState->host);
30a4f2a8 328 buf = squid_error_url(sslState->url,
983061ed 329 request->method,
330 ERR_DNS_FAIL,
331 fd_table[fd].ipaddr,
332 500,
333 dns_error_message);
30a4f2a8 334 comm_write(sslState->client.fd,
335 xstrdup(buf),
336 strlen(buf),
30a4f2a8 337 sslErrorComplete,
cd1fb0eb 338 sslState,
4a63c85f 339 xfree);
b15fe823 340 return;
edeb28fd 341 } else if (status != COMM_OK) {
e5f6c5c2 342 buf = squid_error_url(sslState->url,
343 sslState->request->method,
344 ERR_CONNECT_FAIL,
345 fd_table[fd].ipaddr,
346 500,
347 xstrerror());
348 comm_write(sslState->client.fd,
349 xstrdup(buf),
350 strlen(buf),
e5f6c5c2 351 sslErrorComplete,
cd1fb0eb 352 sslState,
e5f6c5c2 353 xfree);
354 return;
983061ed 355 }
93868820 356 if (sslState->proxying)
98ffb7e4 357 sslProxyConnected(sslState->server.fd, sslState);
358 else
359 sslConnected(sslState->server.fd, sslState);
983061ed 360}
30a4f2a8 361
770f051d 362void
78f1250a 363sslStart(int fd, const char *url, request_t * request, size_t *size_ptr)
30a4f2a8 364{
365 /* Create state structure. */
366 SslStateData *sslState = NULL;
367 int sock;
368 char *buf = NULL;
a3d5953d 369 debug(26, 3) ("sslStart: '%s %s'\n",
30a4f2a8 370 RequestMethodStr[request->method], url);
30a4f2a8 371 /* Create socket. */
16b204c4 372 sock = comm_open(SOCK_STREAM,
373 0,
374 Config.Addrs.tcp_outgoing,
375 0,
376 COMM_NONBLOCKING,
377 url);
30a4f2a8 378 if (sock == COMM_ERROR) {
a3d5953d 379 debug(26, 4) ("sslStart: Failed because we're out of sockets.\n");
30a4f2a8 380 buf = squid_error_url(url,
381 request->method,
382 ERR_NO_FDS,
383 fd_table[fd].ipaddr,
384 500,
385 xstrerror());
b2186d32 386 comm_write(fd,
30a4f2a8 387 xstrdup(buf),
388 strlen(buf),
b2186d32 389 NULL,
390 NULL,
4a63c85f 391 xfree);
770f051d 392 return;
30a4f2a8 393 }
394 sslState = xcalloc(1, sizeof(SslStateData));
7dd44885 395 cbdataAdd(sslState);
30a4f2a8 396 sslState->url = xstrdup(url);
397 sslState->request = requestLink(request);
30a4f2a8 398 sslState->size_ptr = size_ptr;
399 sslState->client.fd = fd;
400 sslState->server.fd = sock;
401 sslState->server.buf = xmalloc(SQUID_TCP_SO_RCVBUF);
402 sslState->client.buf = xmalloc(SQUID_TCP_SO_RCVBUF);
403 comm_add_close_handler(sslState->server.fd,
b177367b 404 sslStateFree,
cd1fb0eb 405 sslState);
30a4f2a8 406 comm_add_close_handler(sslState->client.fd,
b177367b 407 sslClientClosed,
cd1fb0eb 408 sslState);
5c5783a2 409 commSetTimeout(sslState->client.fd,
4f92c80c 410 Config.Timeout.lifetime,
411 sslTimeout,
412 sslState);
b6c0e933 413 peerSelect(request,
641941c0 414 NULL,
b6c0e933 415 sslPeerSelectComplete,
416 sslPeerSelectFail,
417 sslState);
30a4f2a8 418}
98ffb7e4 419
b8d8561b 420static void
b177367b 421sslProxyConnected(int fd, void *data)
98ffb7e4 422{
b177367b 423 SslStateData *sslState = data;
a3d5953d 424 debug(26, 3) ("sslProxyConnected: FD %d sslState=%p\n", fd, sslState);
98ffb7e4 425 sprintf(sslState->client.buf, "CONNECT %s HTTP/1.0\r\n\r\n", sslState->url);
a3d5953d 426 debug(26, 3) ("sslProxyConnected: Sending 'CONNECT %s HTTP/1.0'\n", sslState->url);
98ffb7e4 427 sslState->client.len = strlen(sslState->client.buf);
428 sslState->client.offset = 0;
b177367b 429 commSetSelect(sslState->server.fd,
98ffb7e4 430 COMM_SELECT_WRITE,
b177367b 431 sslWriteServer,
cd1fb0eb 432 sslState, 0);
5c5783a2 433 commSetTimeout(fd, Config.Timeout.read, NULL, NULL);
b177367b 434 commSetSelect(sslState->server.fd,
98ffb7e4 435 COMM_SELECT_READ,
b177367b 436 sslReadServer,
cd1fb0eb 437 sslState, 0);
88738790 438 commSetTimeout(sslState->server.fd,
439 Config.Timeout.read,
440 NULL,
441 NULL);
98ffb7e4 442}
33ea9fff 443
33ea9fff 444static void
641941c0 445sslPeerSelectComplete(peer * p, void *data)
33ea9fff 446{
447 SslStateData *sslState = data;
448 request_t *request = sslState->request;
deb79f06 449 peer *g = NULL;
b6c0e933 450 sslState->proxying = p ? 1 : 0;
451 sslState->host = p ? p->host : request->host;
452 if (p == NULL) {
b3b64e58 453 sslState->port = request->port;
b6c0e933 454 } else if (p->http_port != 0) {
455 sslState->port = p->http_port;
40a1495e 456 } else if ((g = peerFindByName(p->host))) {
b3b64e58 457 sslState->port = g->http_port;
33ea9fff 458 } else {
b3b64e58 459 sslState->port = CACHE_HTTP_PORT;
33ea9fff 460 }
edeb28fd 461 commConnectStart(sslState->server.fd,
462 sslState->host,
463 sslState->port,
464 sslConnectDone,
33ea9fff 465 sslState);
466}
b6c0e933 467
468static void
641941c0 469sslPeerSelectFail(peer * p, void *data)
b6c0e933 470{
471 SslStateData *sslState = data;
472 squid_error_request(sslState->url, ERR_CANNOT_FETCH, 400);
473 sslClose(sslState);
474}