]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Bug 4253: ssl_bump prevents from accessing some web contents (#304) M-staged-PR304
authorChristos Tsantilas <christos@chtsanti.net>
Mon, 15 Oct 2018 12:03:06 +0000 (12:03 +0000)
committerSquid Anubis <squid-anubis@squid-cache.org>
Sun, 21 Oct 2018 14:57:44 +0000 (14:57 +0000)
Surrogate-Capability should only be sent on accel traffic, not
on bumped traffic.

This is a Measurement Factory project

src/client_side.cc
src/client_side.h

index a503eaa7d52aca8bece396a06552ee7c7db0c1ac..b95b68d1560824719a4305130ab44e3c7a847e05 100644 (file)
@@ -1082,20 +1082,18 @@ findTrailingHTTPVersion(const char *uriAndHTTPVersion, const char *end)
     return NULL;
 }
 
-static void
-prepareAcceleratedURL(ConnStateData * conn, ClientHttpRequest *http, const Http1::RequestParserPointer &hp)
+static char *
+prepareAcceleratedURL(ConnStateData * conn, const Http1::RequestParserPointer &hp)
 {
     int vhost = conn->port->vhost;
     int vport = conn->port->vport;
     static char ipbuf[MAX_IPSTRLEN];
 
-    http->flags.accel = true;
-
     /* BUG: Squid cannot deal with '*' URLs (RFC2616 5.1.2) */
 
     static const SBuf cache_object("cache_object://");
     if (hp->requestUri().startsWith(cache_object))
-        return; /* already in good shape */
+        return nullptr; /* already in good shape */
 
     // XXX: re-use proper URL parser for this
     SBuf url = hp->requestUri(); // use full provided URI if we abort
@@ -1105,7 +1103,7 @@ prepareAcceleratedURL(ConnStateData * conn, ClientHttpRequest *http, const Http1
             break;
 
         if (conn->port->vhost)
-            return; /* already in good shape */
+            return nullptr; /* already in good shape */
 
         // skip the URI scheme
         static const CharacterSet uriScheme = CharacterSet("URI-scheme","+-.") + CharacterSet::ALPHA + CharacterSet::DIGIT;
@@ -1142,18 +1140,16 @@ prepareAcceleratedURL(ConnStateData * conn, ClientHttpRequest *http, const Http1
 #endif
 
     if (vport < 0)
-        vport = http->getConn()->clientConnection->local.port();
+        vport = conn->clientConnection->local.port();
 
-    const bool switchedToHttps = conn->switchedToHttps();
-    const bool tryHostHeader = vhost || switchedToHttps;
     char *host = NULL;
-    if (tryHostHeader && (host = hp->getHeaderField("Host"))) {
+    if (vhost && (host = hp->getHeaderField("Host"))) {
         debugs(33, 5, "ACCEL VHOST REWRITE: vhost=" << host << " + vport=" << vport);
         char thost[256];
         if (vport > 0) {
             thost[0] = '\0';
             char *t = NULL;
-            if (host[strlen(host)] != ']' && (t = strrchr(host,':')) != NULL) {
+            if (host[strlen(host) - 1] != ']' && (t = strrchr(host,':')) != NULL) {
                 strncpy(thost, host, (t-host));
                 snprintf(thost+(t-host), sizeof(thost)-(t-host), ":%d", vport);
                 host = thost;
@@ -1162,67 +1158,116 @@ prepareAcceleratedURL(ConnStateData * conn, ClientHttpRequest *http, const Http1
                 host = thost;
             }
         } // else nothing to alter port-wise.
-        const int url_sz = hp->requestUri().length() + 32 + Config.appendDomainLen + strlen(host);
-        http->uri = (char *)xcalloc(url_sz, 1);
         const SBuf &scheme = AnyP::UriScheme(conn->transferProtocol.protocol).image();
-        snprintf(http->uri, url_sz, SQUIDSBUFPH "://%s" SQUIDSBUFPH, SQUIDSBUFPRINT(scheme), host, SQUIDSBUFPRINT(url));
-        debugs(33, 5, "ACCEL VHOST REWRITE: " << http->uri);
+        const int url_sz = scheme.length() + strlen(host) + url.length() + 32;
+        char *uri = (char *)xcalloc(url_sz, 1);
+        snprintf(uri, url_sz, SQUIDSBUFPH "://%s" SQUIDSBUFPH, SQUIDSBUFPRINT(scheme), host, SQUIDSBUFPRINT(url));
+        debugs(33, 5, "ACCEL VHOST REWRITE: " << uri);
+        return uri;
     } else if (conn->port->defaultsite /* && !vhost */) {
         debugs(33, 5, "ACCEL DEFAULTSITE REWRITE: defaultsite=" << conn->port->defaultsite << " + vport=" << vport);
-        const int url_sz = hp->requestUri().length() + 32 + Config.appendDomainLen +
-                           strlen(conn->port->defaultsite);
-        http->uri = (char *)xcalloc(url_sz, 1);
         char vportStr[32];
         vportStr[0] = '\0';
         if (vport > 0) {
             snprintf(vportStr, sizeof(vportStr),":%d",vport);
         }
         const SBuf &scheme = AnyP::UriScheme(conn->transferProtocol.protocol).image();
-        snprintf(http->uri, url_sz, SQUIDSBUFPH "://%s%s" SQUIDSBUFPH,
+        const int url_sz = scheme.length() + strlen(conn->port->defaultsite) + sizeof(vportStr) + url.length() + 32;
+        char *uri = (char *)xcalloc(url_sz, 1);
+        snprintf(uri, url_sz, SQUIDSBUFPH "://%s%s" SQUIDSBUFPH,
                  SQUIDSBUFPRINT(scheme), conn->port->defaultsite, vportStr, SQUIDSBUFPRINT(url));
-        debugs(33, 5, "ACCEL DEFAULTSITE REWRITE: " << http->uri);
+        debugs(33, 5, "ACCEL DEFAULTSITE REWRITE: " << uri);
+        return uri;
     } else if (vport > 0 /* && (!vhost || no Host:) */) {
         debugs(33, 5, "ACCEL VPORT REWRITE: *_port IP + vport=" << vport);
         /* Put the local socket IP address as the hostname, with whatever vport we found  */
-        const int url_sz = hp->requestUri().length() + 32 + Config.appendDomainLen;
-        http->uri = (char *)xcalloc(url_sz, 1);
-        http->getConn()->clientConnection->local.toHostStr(ipbuf,MAX_IPSTRLEN);
+        conn->clientConnection->local.toHostStr(ipbuf,MAX_IPSTRLEN);
         const SBuf &scheme = AnyP::UriScheme(conn->transferProtocol.protocol).image();
-        snprintf(http->uri, url_sz, SQUIDSBUFPH "://%s:%d" SQUIDSBUFPH,
+        const int url_sz = scheme.length() + sizeof(ipbuf) + url.length() + 32;
+        char *uri = (char *)xcalloc(url_sz, 1);
+        snprintf(uri, url_sz, SQUIDSBUFPH "://%s:%d" SQUIDSBUFPH,
                  SQUIDSBUFPRINT(scheme), ipbuf, vport, SQUIDSBUFPRINT(url));
-        debugs(33, 5, "ACCEL VPORT REWRITE: " << http->uri);
+        debugs(33, 5, "ACCEL VPORT REWRITE: " << uri);
+        return uri;
     }
+
+    return nullptr;
 }
 
-static void
-prepareTransparentURL(ConnStateData * conn, ClientHttpRequest *http, const Http1::RequestParserPointer &hp)
+static char *
+buildUrlFromHost(ConnStateData * conn, const Http1::RequestParserPointer &hp)
 {
-    // TODO Must() on URI !empty when the parser supports throw. For now avoid assert().
-    if (!hp->requestUri().isEmpty() && hp->requestUri()[0] != '/')
-        return; /* already in good shape */
-
+    char *uri = nullptr;
     /* BUG: Squid cannot deal with '*' URLs (RFC2616 5.1.2) */
-
     if (const char *host = hp->getHeaderField("Host")) {
-        const int url_sz = hp->requestUri().length() + 32 + Config.appendDomainLen +
-                           strlen(host);
-        http->uri = (char *)xcalloc(url_sz, 1);
         const SBuf &scheme = AnyP::UriScheme(conn->transferProtocol.protocol).image();
-        snprintf(http->uri, url_sz, SQUIDSBUFPH "://%s" SQUIDSBUFPH,
-                 SQUIDSBUFPRINT(scheme), host, SQUIDSBUFPRINT(hp->requestUri()));
-        debugs(33, 5, "TRANSPARENT HOST REWRITE: " << http->uri);
-    } else {
+        const int url_sz = scheme.length() + strlen(host) + hp->requestUri().length() + 32;
+        uri = (char *)xcalloc(url_sz, 1);
+        snprintf(uri, url_sz, SQUIDSBUFPH "://%s" SQUIDSBUFPH,
+                 SQUIDSBUFPRINT(scheme),
+                 host,
+                 SQUIDSBUFPRINT(hp->requestUri()));
+    }
+    return uri;
+}
+
+char *
+ConnStateData::prepareTlsSwitchingURL(const Http1::RequestParserPointer &hp)
+{
+    Must(switchedToHttps());
+
+    if (!hp->requestUri().isEmpty() && hp->requestUri()[0] != '/')
+        return nullptr; /* already in good shape */
+
+    char *uri = buildUrlFromHost(this, hp);
+#if USE_OPENSSL
+    if (!uri) {
+        Must(tlsConnectPort);
+        Must(sslConnectHostOrIp.size());
+        SBuf useHost;
+        if (!tlsClientSni().isEmpty())
+            useHost = tlsClientSni();
+        else
+            useHost.assign(sslConnectHostOrIp.rawBuf(), sslConnectHostOrIp.size());
+
+        const SBuf &scheme = AnyP::UriScheme(transferProtocol.protocol).image();
+        const int url_sz = scheme.length() + useHost.length() + hp->requestUri().length() + 32;
+        uri = (char *)xcalloc(url_sz, 1);
+        snprintf(uri, url_sz, SQUIDSBUFPH "://" SQUIDSBUFPH ":%d" SQUIDSBUFPH,
+                 SQUIDSBUFPRINT(scheme),
+                 SQUIDSBUFPRINT(useHost),
+                 tlsConnectPort,
+                 SQUIDSBUFPRINT(hp->requestUri()));
+    }
+#endif
+    if (uri)
+        debugs(33, 5, "TLS switching host rewrite: " << uri);
+    return uri;
+}
+
+static char *
+prepareTransparentURL(ConnStateData * conn, const Http1::RequestParserPointer &hp)
+{
+    // TODO Must() on URI !empty when the parser supports throw. For now avoid assert().
+    if (!hp->requestUri().isEmpty() && hp->requestUri()[0] != '/')
+        return nullptr; /* already in good shape */
+
+    char *uri = buildUrlFromHost(conn, hp);
+    if (!uri){
         /* Put the local socket IP address as the hostname.  */
-        const int url_sz = hp->requestUri().length() + 32 + Config.appendDomainLen;
-        http->uri = (char *)xcalloc(url_sz, 1);
         static char ipbuf[MAX_IPSTRLEN];
-        http->getConn()->clientConnection->local.toHostStr(ipbuf,MAX_IPSTRLEN);
-        const SBuf &scheme = AnyP::UriScheme(http->getConn()->transferProtocol.protocol).image();
-        snprintf(http->uri, url_sz, SQUIDSBUFPH "://%s:%d" SQUIDSBUFPH,
+        conn->clientConnection->local.toHostStr(ipbuf,MAX_IPSTRLEN);
+        const SBuf &scheme = AnyP::UriScheme(conn->transferProtocol.protocol).image();
+        const int url_sz = sizeof(ipbuf) + hp->requestUri().length() + 32;
+        uri = (char *)xcalloc(url_sz, 1);
+        snprintf(uri, url_sz, SQUIDSBUFPH "://%s:%d" SQUIDSBUFPH,
                  SQUIDSBUFPRINT(scheme),
-                 ipbuf, http->getConn()->clientConnection->local.port(), SQUIDSBUFPRINT(hp->requestUri()));
-        debugs(33, 5, "TRANSPARENT REWRITE: " << http->uri);
+                 ipbuf, conn->clientConnection->local.port(), SQUIDSBUFPRINT(hp->requestUri()));
     }
+
+    if (uri)
+        debugs(33, 5, "TRANSPARENT REWRITE: " << uri);
+    return uri;
 }
 
 /** Parse an HTTP request
@@ -1342,9 +1387,11 @@ parseHttpRequest(ConnStateData *csd, const Http1::RequestParserPointer &hp)
      *  - remote interception with PROXY protocol
      *  - remote reverse-proxy with PROXY protocol
      */
-    if (csd->transparent()) {
+    if (csd->switchedToHttps()) {
+        http->uri = csd->prepareTlsSwitchingURL(hp);
+    } else if (csd->transparent() || csd->switchedToHttps()) {
         /* intercept or transparent mode, properly working with no failures */
-        prepareTransparentURL(csd, http, hp);
+        http->uri = prepareTransparentURL(csd, hp);
 
     } else if (internalCheck(hp->requestUri())) { // NP: only matches relative-URI
         /* internal URL mode */
@@ -1354,9 +1401,10 @@ parseHttpRequest(ConnStateData *csd, const Http1::RequestParserPointer &hp)
         //  But have not parsed there yet!! flag for local-only handling.
         http->flags.internal = true;
 
-    } else if (csd->port->flags.accelSurrogate || csd->switchedToHttps()) {
+    } else if (csd->port->flags.accelSurrogate) {
         /* accelerator mode */
-        prepareAcceleratedURL(csd, http, hp);
+        http->uri = prepareAcceleratedURL(csd, hp);
+        http->flags.accel = true;
     }
 
     if (!http->uri) {
@@ -2316,6 +2364,7 @@ ConnStateData::ConnStateData(const MasterXaction::Pointer &xact) :
 #if USE_OPENSSL
     switchedToHttps_(false),
     parsingTlsHandshake(false),
+    tlsConnectPort(0),
     sslServerBump(NULL),
     signAlgorithm(Ssl::algSignTrusted),
 #endif
@@ -3051,6 +3100,7 @@ ConnStateData::switchToHttps(HttpRequest *request, Ssl::BumpMode bumpServerMode)
     assert(!switchedToHttps_);
 
     sslConnectHostOrIp = request->url.host();
+    tlsConnectPort =  request->url.port();
     resetSslCommonName(request->url.host());
 
     // We are going to read new request
index 459b66567ea2b1c1e0312d22e608931f929ea8c1..b61bb922ca51c40de78a70cdfa7a41d05965f560 100644 (file)
@@ -277,6 +277,7 @@ public:
 #else
     bool switchedToHttps() const { return false; }
 #endif
+    char *prepareTlsSwitchingURL(const Http1::RequestParserPointer &hp);
 
     /// handle a control message received by context from a peer and call back
     virtual bool writeControlMsgAndCall(HttpReply *rep, AsyncCall::Pointer &call) = 0;
@@ -397,6 +398,7 @@ private:
 
     /// The SSL server host name appears in CONNECT request or the server ip address for the intercepted requests
     String sslConnectHostOrIp; ///< The SSL server host name as passed in the CONNECT request
+    unsigned short tlsConnectPort; ///< The TLS server port name as passed in the CONNECT request
     SBuf sslCommonName_; ///< CN name for SSL certificate generation
 
     /// TLS client delivered SNI value. Empty string if none has been received.