From: Amos Jeffries Date: Thu, 1 Sep 2011 05:52:59 +0000 (+1200) Subject: Bug 3243: Fix cases: raw-IPv6, case variant FQDN, internal request X-Git-Tag: take08~33^2~5 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=8f489ad70a9c90ac7b87e19d31960e4ec9bd6349;p=thirdparty%2Fsquid.git Bug 3243: Fix cases: raw-IPv6, case variant FQDN, internal request * do not unwrap the Host header IPv6. URL is not unwrapped for the test. They should be identical regardless of wrapping choice. Also ipcache happily unwraps for the intercept resolution cases * use matchDomainName() algorithm instead of strcmp(). It is tuned for fast case-less domain comparisons. But does support wildcard matches so add a check of domain string length first. * bypass for requests about to be serviced internally. We have some nasty code of our own re-writing the URL without updating the Host: header. Thanks to Sergey Merzlikin and Jenny Lee for detecting these. --- diff --git a/src/client_side.cc b/src/client_side.cc index 0c14993c46..7c9b33b024 100644 --- a/src/client_side.cc +++ b/src/client_side.cc @@ -2011,6 +2011,9 @@ prepareAcceleratedURL(ConnStateData * conn, ClientHttpRequest *http, char *url, if (internalCheck(url)) { /* prepend our name & port */ http->uri = xstrdup(internalLocalUri(NULL, url)); + // We just re-wrote the URL. Must replace the Host: header. + // But have not parsed there yet!! flag for local-only handling. + http->flags.internal = 1; return; } diff --git a/src/client_side_request.cc b/src/client_side_request.cc index 2dfaa1897f..9a86d469a7 100644 --- a/src/client_side_request.cc +++ b/src/client_side_request.cc @@ -552,8 +552,10 @@ ClientRequestContext::hostHeaderIpVerify(const ipcache_addrs* ia, const DnsLooku void ClientRequestContext::hostHeaderVerifyFailed(const char *A, const char *B) { - debugs(85, 1, "SECURITY ALERT: Host: header forgery detected from " << http->getConn()->clientConnection << - " (" << A << " does not match " << B << ")"); + debugs(85, DBG_IMPORTANT, "SECURITY ALERT: Host header forgery detected on " << + http->getConn()->clientConnection << " (" << A << " does not match " << B << ")"); + debugs(85, DBG_IMPORTANT, "SECURITY ALERT: By user agent: " << http->request->header.getStr(HDR_USER_AGENT)); + debugs(85, DBG_IMPORTANT, "SECURITY ALERT: on URL: " << urlCanonical(http->request)); // IP address validation for Host: failed. reject the connection. clientStreamNode *node = (clientStreamNode *)http->client_stream.tail->prev->data; @@ -589,25 +591,30 @@ ClientRequestContext::hostHeaderVerify() return; } + if (http->request->flags.internal) { + // TODO: kill this when URL handling allows partial URLs out of accel mode + // and we no longer screw with the URL just to add our internal host there + debugs(85, 6, HERE << "validate skipped due to internal composite URL."); + http->doCallouts(); + return; + } + // Locate if there is a port attached, strip ready for IP lookup char *portStr = NULL; uint16_t port = 0; if (host[0] == '[') { // IPv6 literal. - // check for a port? - hostB = xstrdup(host+1); + hostB = xstrdup(host); portStr = strchr(hostB, ']'); - if (!portStr) { - safe_free(hostB); // well, that wasn't an IPv6 literal. - } else { - *portStr = '\0'; - if (*(++portStr) == ':') + if (portStr) { + if (*(++portStr) == ':') { + *portStr = '\0'; port = xatoi(++portStr); - else + } else { portStr=NULL; // no port to check. + } } - if (hostB) - host = hostB; // point host at the local version for lookup + host = hostB; // point host at the local version for lookup } else if (strrchr(host, ':') != NULL) { // Domain or IPv4 literal with port hostB = xstrdup(host); @@ -630,7 +637,11 @@ ClientRequestContext::hostHeaderVerify() // verify the destination DNS is one of the Host: headers IPs ipcache_nbgethostbyname(host, hostHeaderIpVerifyWrapper, this); } - } else if (strcmp(host, http->request->GetHost()) != 0) { + } else if (strlen(host) != strlen(http->request->GetHost())) { + // Verify forward-proxy requested URL domain matches the Host: header + debugs(85, 3, HERE << "FAIL on validate URL domain length " << http->request->GetHost() << " matches Host: " << host); + hostHeaderVerifyFailed(host, http->request->GetHost()); + } else if (matchDomainName(host, http->request->GetHost()) != 0) { // Verify forward-proxy requested URL domain matches the Host: header debugs(85, 3, HERE << "FAIL on validate URL domain " << http->request->GetHost() << " matches Host: " << host); hostHeaderVerifyFailed(host, http->request->GetHost());