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