/*
- * $Id: cache_cf.cc,v 1.393 2001/10/17 19:43:39 hno Exp $
+ * $Id: cache_cf.cc,v 1.394 2001/10/19 22:34:48 hno Exp $
*
* DEBUG: section 3 Configuration File Parsing
* AUTHOR: Harvest Derived
} else if (strncmp(token, "key=", 4) == 0) {
safe_free(s->key);
s->key = xstrdup(token + 4);
+ } else if (strncmp(token, "version=", 8) == 0) {
+ s->version = atoi(token + 8);
+ } else if (strncmp(token, "options=", 8) == 0) {
+ safe_free(s->options);
+ s->options = xstrdup(token + 8);
+ } else if (strncmp(token, "cipher=", 7) == 0) {
+ safe_free(s->cipher);
+ s->cipher = xstrdup(token + 7);
} else {
self_destruct();
}
dump_https_port_list(StoreEntry * e, const char *n, const https_port_list * s)
{
while (s) {
- storeAppendPrintf(e, "%s %s:%d cert=\"%s\" key=\"%s\"\n",
+ storeAppendPrintf(e, "%s %s:%d cert=\"%s\" key=\"%s\"",
n,
inet_ntoa(s->s.sin_addr),
ntohs(s->s.sin_port),
s->cert,
s->key);
+ if (s->version)
+ storeAppendPrintf(e, " version=%d", s->version);
+ if (s->options)
+ storeAppendPrintf(e, " options=%s", s->options);
+ if (s->cipher)
+ storeAppendPrintf(e, " cipher=%s", s->cipher);
+ storeAppendPrintf(e, "\n");
s = s->next;
}
}
#
-# $Id: cf.data.pre,v 1.232 2001/10/10 15:17:40 adrian Exp $
+# $Id: cf.data.pre,v 1.233 2001/10/19 22:34:48 hno Exp $
#
#
# SQUID Web Proxy Cache http://www.squid-cache.org/
DEFAULT: none
LOC: Config.Sockaddr.https
DOC_START
- Usage: [ip:]port cert=certificate.pem [key=key.pem]
+ Usage: [ip:]port cert=certificate.pem [key=key.pem] [...]
The socket address where Squid will listen for HTTPS client
requests.
If key is not specified then the given certificate is assumed to be a
combined certificate and key file.
+ Other options:
+
+ version= The version of SSL/TLS supported
+ 1 automatic (default)
+ 2 SSLv2 only
+ 3 SSLv3 only
+ 4 TLSv1 only
+
+ cipher= Colon separated list of supported ciphers
+
+ options= Varions SSL engine options. The most important being:
+ NO_SSLv2 Disallow the use of SSLv2
+ NO_SSLv3 Disallow the use of SSLv3
+ NO_TLSv1 Disallow the use of TLSv1
+ See src/ssl_support.c or OpenSSL documentation for
+ a more complete list.
+
You may specify multiple socket addresses on multiple lines,
each with their own SSL certificate.
DOC_END
-NAME: ssl_version
-IFDEF: USE_SSL
-TYPE: int
-DEFAULT: 1
-LOC: Config.SSL.version
+NAME: ssl_unclean_shutdown
+TYPE: onoff
+DEFAULT: off
+LOC: Config.SSL.unclean_shutdown
DOC_START
- Determines the version of SSL/TLS used.
- 1: SSLv2/SSLv3
- 2: SSLv2 only
- 3: SSLv3 only
- 4: TLSv1
+ Some browsers (especially MSIE) bugs out on SSL shutdown
+ messages.
DOC_END
-
NAME: icp_port udp_port
TYPE: ushort
DEFAULT: 3130
/*
- * $Id: client_side.cc,v 1.548 2001/10/17 20:25:01 hno Exp $
+ * $Id: client_side.cc,v 1.549 2001/10/19 22:34:48 hno Exp $
*
* DEBUG: section 33 Client-side Routines
* AUTHOR: Duane Wessels
continue;
CBDATA_INIT_TYPE(https_port_data);
https_port = cbdataAlloc(https_port_data);
- https_port->sslContext = sslLoadCert(s->cert, s->key);
+ https_port->sslContext = sslCreateContext(s->cert, s->key, s->version, s->cipher, s->options);
comm_listen(fd);
commSetSelect(fd, COMM_SELECT_READ, httpsAccept, https_port, 0);
commSetDefer(fd, httpAcceptDefer, NULL);
/*
- * $Id: comm.cc,v 1.322 2001/10/17 20:25:01 hno Exp $
+ * $Id: comm.cc,v 1.323 2001/10/19 22:34:49 hno Exp $
*
* DEBUG: section 5 Socket Functions
* AUTHOR: Harvest Derived
{
#if USE_SSL
if (fd_table[fd].ssl)
- SSL_shutdown(fd_table[fd].ssl);
+ ssl_shutdown_method(fd);
#endif
if (shutdown(fd, 1) < 0) {
comm_close(fd);
F->flags.closing = 1;
#if USE_SSL
if (F->ssl)
- SSL_shutdown(F->ssl);
+ ssl_shutdown_method(fd);
#endif
CommWriteStateCallbackAndFree(fd, COMM_ERR_CLOSING);
commCallCloseHandlers(fd);
/*
- * $Id: comm_select.cc,v 1.50 2001/05/04 13:37:42 hno Exp $
+ * $Id: comm_select.cc,v 1.51 2001/10/19 22:34:49 hno Exp $
*
* DEBUG: section 5 Socket Functions
*
int i;
int maxfd;
unsigned long nfds;
+ unsigned long npending;
int num;
int callicp = 0, callhttp = 0;
int calldns = 0;
comm_poll_http_incoming();
callicp = calldns = callhttp = 0;
nfds = 0;
+ npending = 0;
maxfd = Biggest_FD + 1;
for (i = 0; i < maxfd; i++) {
int events;
pfds[nfds].events = events;
pfds[nfds].revents = 0;
nfds++;
+ if ((events & POLLRDNORM) && fd_table[i].flags.read_pending)
+ npending++;
}
}
if (nfds == 0) {
assert(shutting_down);
return COMM_SHUTDOWN;
}
+ if (npending)
+ msec = 0;
if (msec > MAX_POLL_TIME)
msec = MAX_POLL_TIME;
for (;;) {
statCounter.syscalls.polls++;
num = poll(pfds, nfds, msec);
statCounter.select_loops++;
- if (num >= 0)
+ if (num >= 0 || npending >= 0)
break;
if (ignoreErrno(errno))
continue;
return COMM_ERROR;
/* NOTREACHED */
}
- debug(5, num ? 5 : 8) ("comm_poll: %d FDs ready\n", num);
+ debug(5, num ? 5 : 8) ("comm_poll: %d+%d FDs ready\n", num, npending);
statHistCount(&statCounter.select_fds_hist, num);
/* Check timeout handlers ONCE each second. */
if (squid_curtime > last_timeout) {
last_timeout = squid_curtime;
checkTimeouts();
}
- if (num == 0)
+ if (num == 0 && npending == 0)
continue;
/* scan each socket but the accept socket. Poll this
* more frequently to minimize losses due to the 5 connect
* limit in SunOS */
for (i = 0; i < nfds; i++) {
fde *F;
- int revents;
- if (((revents = pfds[i].revents) == 0) || ((fd = pfds[i].fd) == -1))
+ int revents = pfds[i].revents;
+ fd = pfds[i].fd;
+ if (fd == -1)
+ continue;
+ if (fd_table[fd].flags.read_pending)
+ revents |= POLLIN;
+ if (revents == 0)
continue;
if (fdIsIcp(fd)) {
callicp = 1;
comm_select(int msec)
{
fd_set readfds;
+ fd_set pendingfds;
fd_set writefds;
#if DELAY_POOLS
fd_set slowfds;
int fd;
int maxfd;
int num;
+ int pending;
int callicp = 0, callhttp = 0;
int calldns = 0;
int maxindex;
int i;
#endif
fd_mask *fdsp;
+ fd_mask *pfdsp;
fd_mask tmask;
static time_t last_timeout = 0;
struct timeval poll_time;
howmany(maxfd, FD_MASK_BITS) * FD_MASK_BYTES);
xmemcpy(&writefds, &global_writefds,
howmany(maxfd, FD_MASK_BITS) * FD_MASK_BYTES);
- /* remove stalled FDs */
+ /* remove stalled FDs, and deal with pending descriptors */
+ pending = 0;
maxindex = howmany(maxfd, FD_MASK_BITS);
fdsp = (fd_mask *) & readfds;
for (j = 0; j < maxindex; j++) {
default:
fatalf("bad return value from commDeferRead(FD %d)\n", fd);
}
+ if (FD_ISSET(fd, &readfds) && fd_table[fd].flags.read_pending) {
+ FD_SET(fd, &pendingfds);
+ pending++;
+ }
}
}
#if DEBUG_FDBITS
if (msec < 0)
msec = MAX_POLL_TIME;
#endif
+ if (pending)
+ msec = 0;
for (;;) {
poll_time.tv_sec = msec / 1000;
poll_time.tv_usec = (msec % 1000) * 1000;
statCounter.syscalls.selects++;
num = select(maxfd, &readfds, &writefds, NULL, &poll_time);
statCounter.select_loops++;
- if (num >= 0)
+ if (num >= 0 || pending > 0)
break;
if (ignoreErrno(errno))
break;
return COMM_ERROR;
/* NOTREACHED */
}
- if (num < 0)
+ if (num < 0 && !pending)
continue;
- debug(5, num ? 5 : 8) ("comm_select: %d FDs ready at %d\n",
- num, (int) squid_curtime);
+ debug(5, num ? 5 : 8) ("comm_select: %d+%d FDs ready at %d\n",
+ num, pending, (int) squid_curtime);
statHistCount(&statCounter.select_fds_hist, num);
/* Check lifetime and timeout handlers ONCE each second.
* Replaces brain-dead check every time through the loop! */
last_timeout = squid_curtime;
checkTimeouts();
}
- if (num == 0)
+ if (num == 0 && pending == 0)
continue;
/* Scan return fd masks for ready descriptors */
fdsp = (fd_mask *) & readfds;
+ pfdsp = (fd_mask *) & pendingfds;
maxindex = howmany(maxfd, FD_MASK_BITS);
for (j = 0; j < maxindex; j++) {
- if ((tmask = fdsp[j]) == 0)
+ if ((tmask = (fdsp[j] | pfdsp[j])) == 0)
continue; /* no bits here */
for (k = 0; k < FD_MASK_BITS; k++) {
if (tmask == 0)
/*
- * $Id: ssl_support.cc,v 1.3 2001/08/26 22:02:19 hno Exp $
+ * $Id: ssl_support.cc,v 1.4 2001/10/19 22:34:49 hno Exp $
*
* AUTHOR: Benno Rice
* DEBUG: section 81 SSL accelerator support
return ok;
}
+static struct ssl_option {
+ const char *name;
+ long value;
+} ssl_options[] = {
+
+ {
+ "MICROSOFT_SESS_ID_BUG", SSL_OP_MICROSOFT_SESS_ID_BUG
+ },
+ {
+ "NETSCAPE_CHALLENGE_BUG", SSL_OP_NETSCAPE_CHALLENGE_BUG
+ },
+ {
+ "NETSCAPE_REUSE_CIPHER_CHANGE_BUG", SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG
+ },
+ {
+ "SSLREF2_REUSE_CERT_TYPE_BUG", SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG
+ },
+ {
+ "MICROSOFT_BIG_SSLV3_BUFFER", SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER
+ },
+ {
+ "MSIE_SSLV2_RSA_PADDING", SSL_OP_MSIE_SSLV2_RSA_PADDING
+ },
+ {
+ "SSLEAY_080_CLIENT_DH_BUG", SSL_OP_SSLEAY_080_CLIENT_DH_BUG
+ },
+ {
+ "TLS_D5_BUG", SSL_OP_TLS_D5_BUG
+ },
+ {
+ "TLS_BLOCK_PADDING_BUG", SSL_OP_TLS_BLOCK_PADDING_BUG
+ },
+ {
+ "TLS_ROLLBACK_BUG", SSL_OP_TLS_ROLLBACK_BUG
+ },
+ {
+ "SINGLE_DH_USE", SSL_OP_SINGLE_DH_USE
+ },
+ {
+ "EPHEMERAL_RSA", SSL_OP_EPHEMERAL_RSA
+ },
+ {
+ "PKCS1_CHECK_1", SSL_OP_PKCS1_CHECK_1
+ },
+ {
+ "PKCS1_CHECK_2", SSL_OP_PKCS1_CHECK_2
+ },
+ {
+ "NETSCAPE_CA_DN_BUG", SSL_OP_NETSCAPE_CA_DN_BUG
+ },
+ {
+ "NON_EXPORT_FIRST", SSL_OP_NON_EXPORT_FIRST
+ },
+ {
+ "NETSCAPE_DEMO_CIPHER_CHANGE_BUG", SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG
+ },
+ {
+ "ALL", SSL_OP_ALL
+ },
+ {
+ "NO_SSLv2", SSL_OP_NO_SSLv2
+ },
+ {
+ "NO_SSLv3", SSL_OP_NO_SSLv3
+ },
+ {
+ "NO_TLSv1", SSL_OP_NO_TLSv1
+ },
+ {
+ "", 0
+ },
+ {
+ NULL, 0
+ }
+};
+
+static long
+ssl_parse_options(const char *options)
+{
+ long op = SSL_OP_ALL;
+ char *tmp;
+ char *option;
+
+ if (!options)
+ goto no_options;
+
+ tmp = xstrdup(options);
+ option = strtok(tmp, ":,");
+ while (option) {
+ struct ssl_option *opt = NULL, *opttmp;
+ long value = 0;
+ enum {
+ MODE_ADD, MODE_REMOVE
+ } mode;
+ switch (*option) {
+ case '!':
+ case '-':
+ mode = MODE_REMOVE;
+ option++;
+ break;
+ case '+':
+ mode = MODE_ADD;
+ option++;
+ break;
+ default:
+ mode = MODE_ADD;
+ break;
+ }
+ for (opttmp = ssl_options; opttmp->name; opttmp++) {
+ if (strcmp(opttmp->name, option) == 0) {
+ opt = opttmp;
+ break;
+ }
+ }
+ if (opt)
+ value = opt->value;
+ else if (strncmp(option, "0x", 2) == 0) {
+ /* Special case.. hex specification */
+ value = strtol(option + 2, NULL, 16);
+ } else {
+ fatalf("Unknown SSL option '%s'", option);
+ value = 0; /* Keep GCC happy */
+ }
+ switch (mode) {
+ case MODE_ADD:
+ op |= value;
+ break;
+ case MODE_REMOVE:
+ op &= ~value;
+ break;
+ }
+ option = strtok(NULL, ":,");
+ }
+
+ safe_free(tmp);
+ no_options:
+ return op;
+}
+
SSL_CTX *
-sslLoadCert(const char *certfile, const char *keyfile)
+sslCreateContext(const char *certfile, const char *keyfile, int version, const char *cipher, const char *options)
{
int ssl_error;
SSL_METHOD *method;
certfile = keyfile;
debug(81, 1) ("Initialising SSL.\n");
- switch (Config.SSL.version) {
+ switch (version) {
case 2:
debug(81, 5) ("Using SSLv2.\n");
method = SSLv2_server_method();
fatalf("Failed to allocate SSL context: %s\n",
ERR_error_string(ssl_error, NULL));
}
- SSL_CTX_set_options(sslContext, SSL_OP_ALL);
+ SSL_CTX_set_options(sslContext, ssl_parse_options(options));
+ if (cipher) {
+ debug(81, 5) ("Using chiper suite %s.\n", cipher);
+ if (!SSL_CTX_set_cipher_list(sslContext, cipher)) {
+ ssl_error = ERR_get_error();
+ fatalf("Failed to set SSL cipher suite: %s\n",
+ ERR_error_string(ssl_error, NULL));
+ }
+ }
debug(81, 1) ("Using certificate in %s\n", certfile);
if (!SSL_CTX_use_certificate_file(sslContext, certfile, SSL_FILETYPE_PEM)) {
ssl_error = ERR_get_error();
char *buf;
int len;
{
- return (SSL_read(fd_table[fd].ssl, buf, len));
+ int i;
+
+ i = SSL_read(fd_table[fd].ssl, buf, len);
+
+ if (i > 0 && SSL_pending(fd_table[fd].ssl) > 0) {
+ debug(81, 2) ("SSL fd %d is pending\n", fd);
+ fd_table[fd].flags.read_pending = 1;
+ } else
+ fd_table[fd].flags.read_pending = 0;
+
+ return i;
}
int
{
return (SSL_write(fd_table[fd].ssl, buf, len));
}
+
+void
+ssl_shutdown_method(fd)
+{
+ SSL *ssl = fd_table[fd].ssl;
+ if (!fd_table[fd].ssl_shutdown) {
+ fd_table[fd].ssl_shutdown = 1;
+ if (Config.SSL.unclean_shutdown)
+ SSL_set_shutdown(ssl, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN);
+ else
+ SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
+ }
+ SSL_shutdown(ssl);
+}
/*
- * $Id: ssl_support.h,v 1.3 2001/10/08 16:18:33 hno Exp $
+ * $Id: ssl_support.h,v 1.4 2001/10/19 22:34:49 hno Exp $
*
* AUTHOR: Benno Rice
*
#include <openssl/err.h>
#endif
-SSL_CTX *sslLoadCert(const char *certfile, const char *keyfile);
+SSL_CTX *sslCreateContext(const char *certfile, const char *keyfile, int version, const char *cipher, const char *options);
int ssl_read_method(int, char *, int);
int ssl_write_method(int, const char *, int);
+void ssl_shutdown_method(int);
#endif /* SQUID_SSL_SUPPORT_H */
/*
- * $Id: structs.h,v 1.405 2001/10/17 20:25:03 hno Exp $
+ * $Id: structs.h,v 1.406 2001/10/19 22:34:49 hno Exp $
*
*
* SQUID Web Proxy Cache http://www.squid-cache.org/
struct sockaddr_in s;
char *cert;
char *key;
+ int version;
+ char *cipher;
+ char *options;
};
#endif
#endif
#if USE_SSL
struct {
- char *certificate;
- char *key;
- int version;
+ int unclean_shutdown;
} SSL;
#endif
wordlist *ext_methods;
unsigned int called_connect:1;
unsigned int nodelay:1;
unsigned int close_on_exec:1;
+ unsigned int read_pending:1;
} flags;
int bytes_read;
int bytes_written;
WRITE_HANDLER *write_method;
#if USE_SSL
SSL *ssl;
+ int ssl_shutdown:1;
#endif
};
+
/*
- * $Id: win32.cc,v 1.2 2001/08/16 00:16:19 hno Exp $
+ * $Id: win32.cc,v 1.3 2001/10/19 22:34:49 hno Exp $
*
* * * * * * * * Legal stuff * * * * * * *
*