=== modified file 'src/client_side.cc' --- src/client_side.cc 2011-12-06 14:06:38 +0000 +++ src/client_side.cc 2011-12-08 13:22:33 +0000 @@ -1986,6 +1986,7 @@ } } +/// Convert a partial-URL into an absolute URL when it has been received on a reverse-proxy (accel) configured port static void prepareAcceleratedURL(ConnStateData * conn, ClientHttpRequest *http, char *url, const char *req_hdr) { @@ -1994,8 +1995,6 @@ char *host; char ipbuf[MAX_IPSTRLEN]; - http->flags.accel = 1; - /* BUG: Squid cannot deal with '*' URLs (RFC2616 5.1.2) */ if (strncasecmp(url, "cache_object://", 15) == 0) @@ -2035,9 +2034,7 @@ if (vport < 0) vport = http->getConn()->clientConnection->local.GetPort(); - const bool switchedToHttps = conn->switchedToHttps(); - const bool tryHostHeader = vhost || switchedToHttps; - if (tryHostHeader && (host = mime_get_header(req_hdr, "Host")) != NULL) { + if (vhost && (host = mime_get_header(req_hdr, "Host")) != NULL) { debugs(33, 5, "ACCEL VHOST REWRITE: vhost=" << host << " + vport=" << vport); char thost[256]; if (vport > 0) { @@ -2055,9 +2052,7 @@ int url_sz = strlen(url) + 32 + Config.appendDomainLen + strlen(host); http->uri = (char *)xcalloc(url_sz, 1); - const char *protocol = switchedToHttps ? - "https" : conn->port->protocol; - snprintf(http->uri, url_sz, "%s://%s%s", protocol, host, url); + snprintf(http->uri, url_sz, "%s://%s%s", conn->port->protocol, host, url); debugs(33, 5, "ACCEL VHOST REWRITE: '" << http->uri << "'"); } else if (conn->port->defaultsite /* && !vhost */) { debugs(33, 5, "ACCEL DEFAULTSITE REWRITE: defaultsite=" << conn->port->defaultsite << " + vport=" << vport); @@ -2085,8 +2080,9 @@ } } +/// Convert a partial-URL into an absolute http:// URL when it has been intercepted from port 80 static void -prepareTransparentURL(ConnStateData * conn, ClientHttpRequest *http, char *url, const char *req_hdr) +prepareInterceptedHttpURL(ConnStateData * conn, ClientHttpRequest *http, char *url, const char *req_hdr) { char *host; char ipbuf[MAX_IPSTRLEN]; @@ -2095,13 +2091,13 @@ return; /* already in good shape */ /* BUG: Squid cannot deal with '*' URLs (RFC2616 5.1.2) */ - // BUG 2976: Squid only accepts intercepted HTTP. + // BUG 2976: Assume http:// scheme if it gets here. if ((host = mime_get_header(req_hdr, "Host")) != NULL) { int url_sz = strlen(url) + 32 + Config.appendDomainLen + strlen(host); http->uri = (char *)xcalloc(url_sz, 1); - snprintf(http->uri, url_sz, "http://%s%s", /*conn->port->protocol,*/ host, url); + snprintf(http->uri, url_sz, "http://%s%s", host, url); debugs(33, 5, "TRANSPARENT HOST REWRITE: '" << http->uri <<"'"); } else { /* Put the local socket IP address as the hostname. */ @@ -2109,12 +2105,57 @@ http->uri = (char *)xcalloc(url_sz, 1); http->getConn()->clientConnection->local.ToHostname(ipbuf,MAX_IPSTRLEN), snprintf(http->uri, url_sz, "http://%s:%d%s", - // http->getConn()->port->protocol, ipbuf, http->getConn()->clientConnection->local.GetPort(), url); debugs(33, 5, "TRANSPARENT REWRITE: '" << http->uri << "'"); } } +/// Convert a partial-URL into an absolute https:// URL when it has been intercepted from port 443 or a decrypted CONNECT request +static void +prepareInterceptedHttpsURL(ConnStateData * conn, ClientHttpRequest *http, char *url, const char *req_hdr) +{ + if (*url != '/') + return; /* already in good shape */ + + /* BUG: Squid cannot deal with '*' URLs (RFC2616 5.1.2) */ + // BUG 2976: Assume https:// scheme if it gets here. + + const char *host; + if ((host = mime_get_header(req_hdr, "Host")) != NULL) { + int url_sz = strlen(url) + 32 + Config.appendDomainLen + strlen(host); + http->uri = (char *)xcalloc(url_sz, 1); + snprintf(http->uri, url_sz, "https://%s%s", host, url); + debugs(33, 5, "SSL INTERCEPT HOST REWRITE: '" << http->uri << "'"); + + } else if(conn->sslHostName.size()>0) { + // Put the CONNECT request authority details (host:port) as the hostname. + int url_sz = strlen(url) + 32 + Config.appendDomainLen + conn->sslHostName.size(); + http->uri = (char *)xcalloc(url_sz, 1); + snprintf(http->uri, url_sz, "https://" SQUIDSTRINGPH "%s", SQUIDSTRINGPRINT(conn->sslHostName), url); + debugs(33, 5, "SSL INTERCEPT REWRITE: '" << http->uri << "'"); + + } else { + // Intercepted traffic with no Host: is unable to be safely repaired (yet, maybe use SNI later). + // RFC 2616 section 14.32 'MUST respond with a 400' + clientStreamNode *node = (clientStreamNode *)http->client_stream.tail->prev->data; + clientReplyContext *repContext = dynamic_cast(node->data.getRaw()); + assert(repContext); + repContext->setReplyToError(ERR_INVALID_REQ, HTTP_BAD_REQUEST, + http->request->method, NULL, + http->getConn()->clientConnection->remote, + http->request, + NULL, +#if USE_AUTH + http->getConn() != NULL && http->getConn()->auth_user_request != NULL ? + http->getConn()->auth_user_request : http->request->auth_user_request); +#else + NULL); +#endif + node = (clientStreamNode *)http->client_stream.tail->data; + clientStreamRead(node, http, node->readBuffer); + } +} + /** * parseHttpRequest() * @@ -2264,25 +2305,48 @@ #endif - debugs(33,5, HERE << "repare absolute URL from " << (csd->transparent()?"intercept":(csd->port->accel ? "accel":""))); + debugs(33, 5, "parseHttpRequest: Complete request received"); + + // XXX: crop this dump at the end of headers. No need for extras + debugs(11, 2, "HTTP Client " << csd->clientConnection); + debugs(11, 2, "HTTP Client REQUEST:\n---------\n" << (hp->buf) + hp->req.m_start << "\n----------"); + + + debugs(33,5, HERE << "Repair absolute URL from " << (csd->switchedToHttps()?"SSL ":"") << + (csd->transparent()?"intercept":(csd->port->accel ? "accel":""))); /* Rewrite the URL in transparent or accelerator mode */ /* NP: there are several cases to traverse here: * - standard mode (forward proxy) - * - transparent mode (TPROXY) + * - transparent mode (TPROXY port 80) + * - transparent mode (TPROXY port 443) * - transparent mode with failures - * - intercept mode (NAT) + * - intercept mode (NAT port 80) + * - intercept mode (NAT port 443) + * - intercept mode (SSL CONNECT requests) * - intercept mode with failures * - accelerator mode (reverse proxy) * - internal URL * - mixed combos of the above with internal URL */ if (csd->transparent()) { - /* intercept or transparent mode, properly working with no failures */ - prepareTransparentURL(csd, http, url, req_hdr); - - } else if (csd->port->accel || csd->switchedToHttps()) { + /* NAT intercept or TPROXY mode, properly working with no failures */ + unsigned short port = http->getConn()->clientConnection->local.GetPort(); + if (port == 80) + prepareInterceptedHttpURL(csd, http, url, req_hdr); + else if (port == 443) + prepareInterceptedHttpsURL(csd, http, url, req_hdr); + else { + debugs(33, 4, HERE << "Intercepted port " << port << ". Assuming its HTTP."); + prepareInterceptedHttpURL(csd, http, url, req_hdr); + } + } else if (csd->port->accel) { /* accelerator mode */ prepareAcceleratedURL(csd, http, url, req_hdr); + http->flags.accel = 1; + + } else if (csd->switchedToHttps()) { + /* CONNECT 'ssl-bump' interception mode */ + prepareInterceptedHttpsURL(csd, http, url, req_hdr); } else if (internalCheck(url)) { /* internal URL mode */ @@ -2299,12 +2363,6 @@ strcpy(http->uri, url); } - debugs(33, 5, "parseHttpRequest: Complete request received"); - - // XXX: crop this dump at the end of headers. No need for extras - debugs(11, 2, "HTTP Client " << csd->clientConnection); - debugs(11, 2, "HTTP Client REQUEST:\n---------\n" << (hp->buf) + hp->req.m_start << "\n----------"); - result->flags.parsed_ok = 1; xfree(url); return result; @@ -3593,7 +3651,7 @@ // We are going to read new request flags.readMore = true; - debugs(33, 5, HERE << "converting " << clientConnection << " to SSL"); + debugs(33, 5, HERE << "converting " << clientConnection << " (for " << sslHostName << ") to SSL"); return getSslContextStart(); }