]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Bug 3243: Fix cases: raw-IPv6, case variant FQDN, internal request
authorAmos Jeffries <squid3@treenet.co.nz>
Thu, 1 Sep 2011 05:52:59 +0000 (17:52 +1200)
committerAmos Jeffries <squid3@treenet.co.nz>
Thu, 1 Sep 2011 05:52:59 +0000 (17:52 +1200)
* 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.

src/client_side.cc
src/client_side_request.cc

index 0c14993c46f3effb38058230d6a93e1165dade28..7c9b33b02422a9cbbda27cae9eca349091277759 100644 (file)
@@ -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;
     }
 
index 2dfaa1897f0deebef95204977ad91442dc513679..9a86d469a7879e7372a395cc49a10fc23b727b0a 100644 (file)
@@ -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());