From: Christos Tsantilas Date: Wed, 6 Aug 2014 10:26:14 +0000 (+0300) Subject: merge from trunk r13526 X-Git-Tag: SQUID_3_5_0_1~89^2~7 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=d1f3d8f885784c89a822c35ddf6537aab3a3b925;p=thirdparty%2Fsquid.git merge from trunk r13526 --- d1f3d8f885784c89a822c35ddf6537aab3a3b925 diff --cc src/FwdState.cc index 07aa7166fa,bbedfe63bc..1a455e72ae --- a/src/FwdState.cc +++ b/src/FwdState.cc @@@ -710,8 -709,10 +709,10 @@@ FwdState::connectDone(const Comm::Conne AsyncCall::Pointer callback = asyncCall(17,4, "FwdState::ConnectedToPeer", FwdStatePeerAnswerDialer(&FwdState::connectedToPeer, this)); + // Use positive timeout when less than one second is left. + const time_t sslNegotiationTimeout = max(static_cast(1), timeLeft()); Ssl::PeerConnector *connector = - new Ssl::PeerConnector(requestPointer, serverConnection(), clientConn, callback); - new Ssl::PeerConnector(requestPointer, serverConnection(), callback, sslNegotiationTimeout); ++ new Ssl::PeerConnector(requestPointer, serverConnection(), clientConn, callback, sslNegotiationTimeout); AsyncJob::Start(connector); // will call our callback return; } diff --cc src/PeerPoolMgr.cc index 14b99683e9,d96a787c2e..6cb98f334a --- a/src/PeerPoolMgr.cc +++ b/src/PeerPoolMgr.cc @@@ -112,8 -113,14 +113,14 @@@ PeerPoolMgr::handleOpenedConnection(con securer = asyncCall(48, 4, "PeerPoolMgr::handleSecuredPeer", MyAnswerDialer(this, &PeerPoolMgr::handleSecuredPeer)); + + const int peerTimeout = peer->connect_timeout > 0 ? + peer->connect_timeout : Config.Timeout.peer_connect; + const int timeUsed = squid_curtime - params.conn->startTime(); + // Use positive timeout when less than one second is left for conn. + const int timeLeft = max(1, (peerTimeout - timeUsed)); Ssl::PeerConnector *connector = - new Ssl::PeerConnector(request, params.conn, NULL, securer); - new Ssl::PeerConnector(request, params.conn, securer, timeLeft); ++ new Ssl::PeerConnector(request, params.conn, NULL, securer, timeLeft); AsyncJob::Start(connector); // will call our callback return; } diff --cc src/cf.data.pre index b5c9a8fd18,15c97ebcd8..157c43e030 --- a/src/cf.data.pre +++ b/src/cf.data.pre @@@ -739,10 -675,7 +675,10 @@@ DOC_STAR %USER_CERT SSL User certificate in PEM format %USER_CERTCHAIN SSL User certificate chain in PEM format %USER_CERT_xx SSL User certificate subject attribute xx - %USER_CA_xx SSL User certificate issuer attribute xx + %USER_CA_CERT_xx SSL User certificate issuer attribute xx + %ssl::>sni SSL client SNI sent to Squid + %ssl::{Header} HTTP request header "Header" %>{Hdr:member} diff --cc src/client_side.cc index 9d8c3bbe07,65344d0a72..81865e5cda --- a/src/client_side.cc +++ b/src/client_side.cc @@@ -3987,149 -3955,6 +3981,149 @@@ ConnStateData::switchToHttps(HttpReques getSslContextStart(); } +/** negotiate an SSL connection */ +static void +clientPeekAndSpliceSSL(int fd, void *data) +{ + ConnStateData *conn = (ConnStateData *)data; + SSL *ssl = fd_table[fd].ssl; + + debugs(83, 2, "Start peek and splice on " << fd); + + if (!Squid_SSL_accept(conn, clientPeekAndSpliceSSL)) + debugs(83, 2, "SSL_accept failed."); + + BIO *b = SSL_get_rbio(ssl); + assert(b); + Ssl::ClientBio *bio = static_cast(b->ptr); + if (bio->gotHello()) { + if (conn->serverBump()) { + Ssl::Bio::sslFeatures const &features = bio->getFeatures(); + if (!features.serverName.empty()) + conn->serverBump()->clientSni = features.serverName.c_str(); + } + + debugs(83, 2, "I got hello. Start forwarding the request!!! "); + Comm::SetSelect(fd, COMM_SELECT_READ, NULL, NULL, 0); + Comm::SetSelect(fd, COMM_SELECT_WRITE, NULL, NULL, 0); + conn->startPeekAndSpliceDone(); + return; + } +} + +void ConnStateData::startPeekAndSplice() +{ + // will call httpsPeeked() with certificate and connection, eventually + SSL_CTX *unConfiguredCTX = Ssl::createSSLContext(port->signingCert, port->signPkey, *port); + fd_table[clientConnection->fd].dynamicSslContext = unConfiguredCTX; + + if (!httpsCreate(clientConnection, unConfiguredCTX)) + return; + + // commSetConnTimeout() was called for this request before we switched. + + // Disable the client read handler until CachePeer selection is complete + Comm::SetSelect(clientConnection->fd, COMM_SELECT_READ, NULL, NULL, 0); + Comm::SetSelect(clientConnection->fd, COMM_SELECT_READ, clientPeekAndSpliceSSL, this, 0); + switchedToHttps_ = true; + + SSL *ssl = fd_table[clientConnection->fd].ssl; + BIO *b = SSL_get_rbio(ssl); + Ssl::ClientBio *bio = static_cast(b->ptr); + bio->hold(true); +} + +int default_read_method(int, char *, int); +int default_write_method(int, const char *, int); +void httpsSslBumpStep2AccessCheckDone(allow_t answer, void *data) +{ + ConnStateData *connState = (ConnStateData *) data; + + // if the connection is closed or closing, just return. + if (!connState->isOpen()) + return; + + debugs(33, 5, HERE << "Answer: " << answer << " kind:" << answer.kind); + if (answer == ACCESS_ALLOWED && answer.kind != Ssl::bumpNone && answer.kind != Ssl::bumpSplice) { + if (answer.kind == Ssl::bumpTerminate || answer.kind == Ssl::bumpErr) + comm_close(connState->clientConnection->fd); + else { + if (answer.kind != Ssl::bumpPeek && answer.kind != Ssl::bumpStare) + connState->sslBumpMode = Ssl::bumpBump; + else + connState->sslBumpMode = (Ssl::BumpMode)answer.kind; + connState->startPeekAndSpliceDone(); + } + } else { + //Normally we can splice here, because we just got client hello message + SSL *ssl = fd_table[connState->clientConnection->fd].ssl; + BIO *b = SSL_get_rbio(ssl); + Ssl::ClientBio *bio = static_cast(b->ptr); + MemBuf const &rbuf = bio->rBufData(); + debugs(83,5, "Bio for " << connState->clientConnection->fd << " read " << rbuf.contentSize() << " helo bytes"); + // Do splice: + + connState->sslBumpMode = Ssl::bumpSplice; + fd_table[connState->clientConnection->fd].read_method = &default_read_method; + fd_table[connState->clientConnection->fd].write_method = &default_write_method; + + if (connState->transparent()) { + // fake a CONNECT request to force connState to tunnel + static char ip[MAX_IPSTRLEN]; + connState->clientConnection->local.toUrl(ip, sizeof(ip)); + connState->in.buf.assign("CONNECT ").append(ip).append(" HTTP/1.1\r\nHost: ").append(ip).append("\r\n\r\n").append(rbuf.content(), rbuf.contentSize()); - bool ret = connState->handleReadData(&connState->in.buf); ++ bool ret = connState->handleReadData(); + if (ret) + ret = connState->clientParseRequests(); + + if (!ret) { + debugs(33, 2, HERE << "Failed to start fake CONNECT request for ssl spliced connection: " << connState->clientConnection); + connState->clientConnection->close(); + } + } else { + // in.buf still has the "CONNECT ..." request data, reset it to SSL hello message + connState->in.buf.append(rbuf.content(), rbuf.contentSize()); + ClientSocketContext::Pointer context = connState->getCurrentContext(); + ClientHttpRequest *http = context->http; + tunnelStart(http, &http->out.size, &http->al->http.code, http->al); + } + } +} + +void +ConnStateData::startPeekAndSpliceDone() +{ + // This is the Step2 of the SSL bumping + assert(sslServerBump); + if (sslServerBump->step == Ssl::bumpStep1) { + sslServerBump->step = Ssl::bumpStep2; + // Run a accessList check to check if want to splice or continue bumping + + ACLFilledChecklist *acl_checklist = new ACLFilledChecklist(Config.accessList.ssl_bump, sslServerBump->request.getRaw(), NULL); + //acl_checklist->src_addr = params.conn->remote; + //acl_checklist->my_addr = s->s; + acl_checklist->nonBlockingCheck(httpsSslBumpStep2AccessCheckDone, this); + return; + } + + FwdState::fwdStart(clientConnection, sslServerBump->entry, sslServerBump->request.getRaw()); +} + +void +ConnStateData::doPeekAndSpliceStep() +{ + SSL *ssl = fd_table[clientConnection->fd].ssl; + BIO *b = SSL_get_rbio(ssl); + assert(b); + Ssl::ClientBio *bio = static_cast(b->ptr); + + debugs(33, 5, HERE << "PeekAndSplice mode, proceed with client negotiation. Currrent state:" << SSL_state_string_long(ssl)); + bio->hold(false); + + Comm::SetSelect(clientConnection->fd, COMM_SELECT_WRITE, clientNegotiateSSL, this, 0); + switchedToHttps_ = true; +} + void ConnStateData::httpsPeeked(Comm::ConnectionPointer serverConnection) { diff --cc src/external_acl.cc index ba9296c5f4,5cf944b76d..e70b1295f0 --- a/src/external_acl.cc +++ b/src/external_acl.cc @@@ -417,19 -416,14 +417,19 @@@ parse_externalAclHelper(external_acl * else if (strncmp(token, "%USER_CERT_", 11) == 0) { format->type = Format::LFT_EXT_ACL_USER_CERT; format->header = xstrdup(token + 11); - } else if (strncmp(token, "%USER_CA_CERT_", 11) == 0) { + } else if (strncmp(token, "%USER_CA_CERT_", 14) == 0) { format->type = Format::LFT_EXT_ACL_USER_CA_CERT; - format->header = xstrdup(token + 11); - } else if (strncmp(token, "%CA_CERT_", 11) == 0) { + format->header = xstrdup(token + 14); + } else if (strncmp(token, "%CA_CERT_", 9) == 0) { debugs(82, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: external_acl_type %CA_CERT_* code is obsolete. Use %USER_CA_CERT_* instead"); format->type = Format::LFT_EXT_ACL_USER_CA_CERT; - format->header = xstrdup(token + 11); + format->header = xstrdup(token + 9); - } + } else if (strcmp(token, "%ssl::>sni") == 0) + format->type = Format::LFT_SSL_CLIENT_SNI; + else if (strcmp(token, "%ssl::type = Format::LFT_SSL_SERVER_CERT_SUBJECT; + else if (strcmp(token, "%ssl::type = Format::LFT_SSL_SERVER_CERT_ISSUER; #endif #if USE_AUTH else if (strcmp(token, "%EXT_USER") == 0 || strcmp(token, "%ue") == 0) diff --cc src/ssl/PeerConnector.cc index fb504bf43e,2f78a05b21..d6b2e0135a --- a/src/ssl/PeerConnector.cc +++ b/src/ssl/PeerConnector.cc @@@ -29,13 -28,14 +29,16 @@@ CBDATA_NAMESPACED_CLASS_INIT(Ssl, PeerC Ssl::PeerConnector::PeerConnector( HttpRequestPointer &aRequest, const Comm::ConnectionPointer &aServerConn, + const Comm::ConnectionPointer &aClientConn, - AsyncCall::Pointer &aCallback): + AsyncCall::Pointer &aCallback, + const time_t timeout): AsyncJob("Ssl::PeerConnector"), request(aRequest), serverConn(aServerConn), + clientConn(aClientConn), - callback(aCallback) + callback(aCallback), + negotiationTimeout(timeout), + startTime(squid_curtime) { // if this throws, the caller's cb dialer is not our CbDialer Must(dynamic_cast(callback->getDialer())); @@@ -201,8 -174,26 +204,22 @@@ Ssl::PeerConnector::initializeSsl( CRYPTO_add(&(peeked_cert->references),1,CRYPTO_LOCK_X509); SSL_set_ex_data(ssl, ssl_ex_index_ssl_peeked_cert, peeked_cert); } - - fd_table[fd].ssl = ssl; - fd_table[fd].read_method = &ssl_read_method; - fd_table[fd].write_method = &ssl_write_method; } + void + Ssl::PeerConnector::setReadTimeout() + { + int timeToRead; + if (negotiationTimeout) { + const int timeUsed = squid_curtime - startTime; + const int timeLeft = max(0, static_cast(negotiationTimeout - timeUsed)); + timeToRead = min(static_cast(::Config.Timeout.read), timeLeft); + } else + timeToRead = ::Config.Timeout.read; + AsyncCall::Pointer nil; + commSetConnTimeout(serverConnection(), timeToRead, nil); + } + void Ssl::PeerConnector::negotiateSsl() { diff --cc src/ssl/PeerConnector.h index 6d1f671529,4607e025e3..0a62ae4900 --- a/src/ssl/PeerConnector.h +++ b/src/ssl/PeerConnector.h @@@ -101,8 -103,7 +104,8 @@@ public public: PeerConnector(HttpRequestPointer &aRequest, const Comm::ConnectionPointer &aServerConn, + const Comm::ConnectionPointer &aClientConn, - AsyncCall::Pointer &aCallback); + AsyncCall::Pointer &aCallback, const time_t timeout = 0); virtual ~PeerConnector(); protected: @@@ -162,14 -165,12 +169,16 @@@ private /// A wrapper function for negotiateSsl for use with Comm::SetSelect static void NegotiateSsl(int fd, void *data); + /// A wrapper function for checkForPeekAndSplice for use with acl + static void cbCheckForPeekAndSplice(allow_t answer, void *data); + HttpRequestPointer request; ///< peer connection trigger or cause Comm::ConnectionPointer serverConn; ///< TCP connection to the peer + Comm::ConnectionPointer clientConn; ///< TCP connection to the client AsyncCall::Pointer callback; ///< we call this with the results AsyncCall::Pointer closeHandler; ///< we call this when the connection closed + time_t negotiationTimeout; ///< the ssl connection timeout to use + time_t startTime; ///< when the peer connector negotiation started CBDATA_CLASS2(PeerConnector); };