Bug 47177

Summary: mod_proxy rewrites incorrectly IPv6 literal addresses
Product: Apache httpd-2 Reporter: Carlos Garcia Braschi <cgbraschi>
Component: mod_proxy_httpAssignee: Apache HTTPD Bugs Mailing List <bugs>
Status: RESOLVED FIXED    
Severity: normal CC: chaz
Priority: P2 Keywords: FixedInTrunk
Version: 2.2.9   
Target Milestone: ---   
Hardware: PC   
OS: Linux   

Description Carlos Garcia Braschi 2009-05-09 06:48:19 UTC
mod_proxy rewrites a received request of 
GET http://[2001:4860:a005::84]/search?q=cache:KD9mYbWwEgkJ:www.apache.org/+apache&cd=1&hl=en&ct=clnk HTTP/1.1
Host: [2001:4860:a005::84]

into 

GET /search?q=cache:KD9mYbWwEgkJ:www.apache.org/+apache&cd=1&hl=en&ct=clnk HTTP/1.1
Host: 2001:4860:a005::84

Which is incorrect, loosely according to RFC 3986 (for URI syntax), (http://tools.ietf.org/html/rfc3986), that says "A host identified by an Internet Protocol literal address, version 6 [RFC3513] or later, is distinguished by enclosing the IP literal within square brackets ("[" and "]")".

The right way to do it would be to use
GET /search?q=cache:KD9mYbWwEgkJ:www.apache.org/+apache&cd=1&hl=en&ct=clnk HTTP/1.1
Host: [2001:4860:a005::84]

This behaviour can be worked around by using "ProxyPreserveHost On", but that should be the default behaviours. 

This behaviour leads to infinite redirection in servers that detect the error and redirect to http://[2001:4860:a005::84]/search... (like Google Web Server when used for caching)
Comment 1 Carlos Garcia Braschi 2009-05-09 06:50:22 UTC
I don't mean to say ProxyPreserveHost On" should be the default behaviour, is that not stripping brackets should be the default behaviour
Comment 2 Carlos Garcia Braschi 2009-05-10 23:24:06 UTC
Referring to the HTTP/1.1 spec, it is clear that a Host: IPv6 field cannot be sent without brackets, as it would be then ambiguous if it contains or not a :port part.
http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.23
Comment 3 Carlos Garcia Braschi 2009-05-11 00:17:43 UTC
mod_proxy_http.c

A naive and untested fix (I'm sorry, but I don't have a developer environment to test it), borrowing from the proxy_http_canon function, would be to change function ap_proxy_http_request in this way. 

from:
    if (conf->preserve_host == 0) {
        if (uri->port_str && uri->port != DEFAULT_HTTP_PORT) {
            buf = apr_pstrcat(p, "Host: ", uri->hostname, ":", uri->port_str,
                              CRLF, NULL);
        } else {
            buf = apr_pstrcat(p, "Host: ", uri->hostname, CRLF, NULL);
        }
    }

to 
    if (conf->preserve_host == 0) {
        if (ap_strchr_c(uri->hostname, ':')) { /* if literal IPv6 address */
            if (uri->port_str && uri->port != DEFAULT_HTTP_PORT) {
                buf = apr_pstrcat(p, "Host: [", uri->hostname, "]:", 
                                  uri->port_str, CRLF, NULL);
            } else {
                buf = apr_pstrcat(p, "Host: [", uri->hostname, "]", CRLF, NULL);
            }
        } else {
            if (uri->port_str && uri->port != DEFAULT_HTTP_PORT) {
                buf = apr_pstrcat(p, "Host: ", uri->hostname, ":", 
                                  uri->port_str, CRLF, NULL);
            } else {
                buf = apr_pstrcat(p, "Host: ", uri->hostname, CRLF, NULL);
            }
        }
    }

I'm not sure if a more architectural fix having apr_uri_parse function leaving the brackets for IPv6 hostnames would be better, as they are always required to be there in URIs... but that means apr_uri and all of the code depending on apr_uri to be fixed....
Comment 4 Nick Kew 2009-05-25 16:22:12 UTC
Your patch looks fine to me.  Fixed in trunk in r778531.

There may be a similar issue with ProxyRemote and literal ipv6 addresses: I haven't checked for it.
Comment 5 Nick Kew 2009-12-26 14:41:52 UTC
Changelog shows fixed in 2.2.12
Comment 6 Nick Kew 2010-02-12 08:08:50 UTC
*** Bug 46195 has been marked as a duplicate of this bug. ***