I am also attaching the patch for squid-3.5.
The patch for trunk does not apply to 3.5
On 11/09/2015 06:25 PM, Christos Tsantilas wrote:
Patch applied to trunk as r14390.
On 11/06/2015 08:39 PM, Amos Jeffries wrote:
On 7/11/2015 7:17 a.m., Christos Tsantilas wrote:
Project description:
- Squid receives SSL Hello from the client (TCP connection A).
- Squid successfully negotiates an SSL connection with the origin
server (TCP connection B).
- Squid successfully negotiates an SSL connection with the client
(TCP connection A).
- Squid marks connection B as "idle" and waits an HTTP request from
connection A.
- The origin server continues talking to Squid (TCP connection B).
Squid detects a network read on an idle connection and closes TCP
connection B (and then the associated TCP connection A as well).
This patch:
- When squid detects a network read on server idle connection do an
SSL_read to:
a) see if application data received from server and abort in
this case
b) detect possible SSL error, or SSL shutdown message from server
c) or ignore if only SSL protocol related packets received.
This is a Measurement Factory project
in src/client_side.cc:
* Please use "TLS" in debugs messages instead of "SSL".
* Please use "Tls" instead of "Ssl" in new symbol names such as the
handleIdleClientPinned***Read() method being added.
* Missing whitespace; "if(!ssl)" should be "if (!ssl)"
* Please use nullptr instead of NULL on new and altered lines.
* Please debug output the full pinning.serverConnection instead of just
the FD on debugs with levels higher than 1 / IMPORTANT.
in src/client_side.h:
* Please use "\returns" instead if "Returns" in the doxygen comment.
Since those are all cosmetic I dont think it needs another audit.
+1. Please apply once the polishing edits are done.
Amos
Handshake Problem during Renegotiation
Here is what happens:
- Squid receives TLS Hello from the client (TCP connection A).
- Squid successfully negotiates an TLS connection with the origin server
(TCP connection B).
- Squid successfully negotiates an TLS connection with the client
(TCP connection A).
- Squid marks connection B as "idle" and waits an HTTP request from
connection A.
- The origin server continues talking to Squid (TCP connection B).
Squid detects a network read on an idle connection and closes TCP
connection B (and then the associated TCP connection A as well).
This patch:
- When squid detects a network read on server idle connection do an
SSL_read to:
a) see if application data received from server and abort in this case
b) detect possible TLS error, or TLS shutdown message from server
c) or ignore if only TLS protocol related packets received.
This is a Measurement Factory project
=== modified file 'src/client_side.cc'
--- src/client_side.cc 2015-09-17 05:40:34 +0000
+++ src/client_side.cc 2015-11-09 16:36:22 +0000
@@ -4976,57 +4976,103 @@
ConnStateData::startPinnedConnectionMonitoring()
{
if (pinning.readHandler != NULL)
return; // already monitoring
typedef CommCbMemFunT<ConnStateData, CommIoCbParams> Dialer;
pinning.readHandler = JobCallback(33, 3,
Dialer, this, ConnStateData::clientPinnedConnectionRead);
Comm::Read(pinning.serverConnection, pinning.readHandler);
}
void
ConnStateData::stopPinnedConnectionMonitoring()
{
if (pinning.readHandler != NULL) {
Comm::ReadCancel(pinning.serverConnection->fd, pinning.readHandler);
pinning.readHandler = NULL;
}
}
+#if USE_OPENSSL
+bool
+ConnStateData::handleIdleClientPinnedTlsRead()
+{
+ // A ready-for-reading connection means that the TLS server either closed
+ // the connection, sent us some unexpected HTTP data, or started TLS
+ // renegotiations. We should close the connection except for the last case.
+
+ Must(pinning.serverConnection != nullptr);
+ SSL *ssl = fd_table[pinning.serverConnection->fd].ssl;
+ if (!ssl)
+ return false;
+
+ char buf[1];
+ const int readResult = SSL_read(ssl, buf, sizeof(buf));
+
+ if (readResult > 0 || SSL_pending(ssl) > 0) {
+ debugs(83, 2, pinning.serverConnection << " TLS application data read");
+ return false;
+ }
+
+ switch(const int error = SSL_get_error(ssl, readResult)) {
+ case SSL_ERROR_WANT_WRITE:
+ debugs(83, DBG_IMPORTANT, pinning.serverConnection << " TLS SSL_ERROR_WANT_WRITE request for idle pinned connection");
+ // fall through to restart monitoring, for now
+ case SSL_ERROR_NONE:
+ case SSL_ERROR_WANT_READ:
+ startPinnedConnectionMonitoring();
+ return true;
+
+ default:
+ debugs(83, 2, pinning.serverConnection << " TLS error: " << error);
+ return false;
+ }
+
+ // not reached
+ return true;
+}
+#endif
+
/// Our read handler called by Comm when the server either closes an idle pinned connection or
/// perhaps unexpectedly sends something on that idle (from Squid p.o.v.) connection.
void
ConnStateData::clientPinnedConnectionRead(const CommIoCbParams &io)
{
pinning.readHandler = NULL; // Comm unregisters handlers before calling
if (io.flag == Comm::ERR_CLOSING)
return; // close handler will clean up
+ Must(pinning.serverConnection == io.conn);
+
+#if USE_OPENSSL
+ if (handleIdleClientPinnedTlsRead())
+ return;
+#endif
+
// We could use getConcurrentRequestCount(), but this may be faster.
const bool clientIsIdle = !getCurrentContext();
debugs(33, 3, "idle pinned " << pinning.serverConnection << " read " <<
io.size << (clientIsIdle ? " with idle client" : ""));
- assert(pinning.serverConnection == io.conn);
pinning.serverConnection->close();
// If we are still sending data to the client, do not close now. When we are done sending,
// ClientSocketContext::keepaliveNextRequest() checks pinning.serverConnection and will close.
// However, if we are idle, then we must close to inform the idle client and minimize races.
if (clientIsIdle && clientConnection != NULL)
clientConnection->close();
}
const Comm::ConnectionPointer
ConnStateData::validatePinnedConnection(HttpRequest *request, const CachePeer *aPeer)
{
debugs(33, 7, HERE << pinning.serverConnection);
bool valid = true;
if (!Comm::IsConnOpen(pinning.serverConnection))
valid = false;
else if (pinning.auth && pinning.host && request && strcasecmp(pinning.host, request->GetHost()) != 0)
valid = false;
else if (request && pinning.port != request->port)
=== modified file 'src/client_side.h'
--- src/client_side.h 2015-08-08 04:04:45 +0000
+++ src/client_side.h 2015-11-09 16:36:22 +0000
@@ -399,40 +399,46 @@
/// stop parsing the request and create context for relaying error info
ClientSocketContext *abortRequestParsing(const char *const errUri);
/// generate a fake CONNECT request with the given payload
/// at the beginning of the client I/O buffer
void fakeAConnectRequest(const char *reason, const SBuf &payload);
/* Registered Runner API */
virtual void startShutdown();
virtual void endingShutdown();
protected:
void startDechunkingRequest();
void finishDechunkingRequest(bool withSuccess);
void abortChunkedRequestBody(const err_type error);
err_type handleChunkedRequestBody(size_t &putSize);
void startPinnedConnectionMonitoring();
void clientPinnedConnectionRead(const CommIoCbParams &io);
+#if USE_OPENSSL
+ /// Handles a ready-for-reading TLS squid-to-server connection that
+ /// we thought was idle.
+ /// Returns false if and only if the connection should be closed.
+ bool handleIdleClientPinnedTlsRead();
+#endif
/// parse input buffer prefix into a single transfer protocol request
/// return NULL to request more header bytes (after checking any limits)
/// use abortRequestParsing() to handle parsing errors w/o creating request
virtual ClientSocketContext *parseOneRequest(Http::ProtocolVersion &ver) = 0;
/// start processing a freshly parsed request
virtual void processParsedRequest(ClientSocketContext *context, const Http::ProtocolVersion &ver) = 0;
/// returning N allows a pipeline of 1+N requests (see pipeline_prefetch)
virtual int pipelinePrefetchMax() const;
/// timeout to use when waiting for the next request
virtual time_t idleTimeout() const = 0;
BodyPipe::Pointer bodyPipe; ///< set when we are reading request body
private:
int connFinishedWithConn(int size);
void clientAfterReadingRequests();
_______________________________________________
squid-dev mailing list
[email protected]
http://lists.squid-cache.org/listinfo/squid-dev