Mailing List Archive

using X-Forwarded-Host as r->hostname
Hi --

It's been a remarkably long time since I had anything useful
to commit, and I'm pretty rusty, so I thought I'd throw this out for
discussion as a RTC despite the CTR rules on trunk. I promise I won't
be offended if anyone says it's a stupid hack and should never be
committed, because, well, it is arguably a very stupid hack.

I've been fighting a context where I have a new server behind
an ancient internal proxy for some transitional period of time until
we can replace the proxy too. The proxy won't send Host headers (in
httpd terms, no equivalent to ProxyPreserveHost On functionality), but
it does put the originally requested Host header into X-Forwarded-Host.

On the backend, try as I might, I could not find a way to map
the X-Forwarded-Host header on top of the Host one prior to the point
where the appropriate <VirtualHost> is determined. I hoped for
some combo of mod_headers in "early" mode + mod_setenvif, but they
run in post_read_request in the opposite order from what I needed.

Hence this patch, which adds a UseCanonicalName XHost option in
which X-Forwarded-Host is checked first, and if non-blank, is used
in place of Host to determine the server name. (The Host header is
left as-is, though.)

http://people.apache.org/~chrisd/patches/use_canonical_name_xhost/use_canonical_name_xhost-trunk.patch

Even if there's a resounding chorus of "boos", perhaps posting it
here will help others facing the same problem in the future find a bit
of a workaround if they're stuck in the same situation.

Let the torches and firebrands be set alight! Cheers,

Chris.

--
GPG Key ID: 088335A9
GPG Key Fingerprint: 86CD 3297 7493 75BC F820 6715 F54F E648 0883 35A9
Re: using X-Forwarded-Host as r->hostname [ In reply to ]
----- Chris Darroch <chrisd@pearsoncmg.com> wrote:
> Hi --
>
> It's been a remarkably long time since I had anything useful
> to commit, and I'm pretty rusty, so I thought I'd throw this out for
> discussion as a RTC despite the CTR rules on trunk. I promise I won't
> be offended if anyone says it's a stupid hack and should never be
> committed, because, well, it is arguably a very stupid hack.
>
> I've been fighting a context where I have a new server behind
> an ancient internal proxy for some transitional period of time until
> we can replace the proxy too. The proxy won't send Host headers (in
> httpd terms, no equivalent to ProxyPreserveHost On functionality), but
> it does put the originally requested Host header into X-Forwarded-Host.
>
> On the backend, try as I might, I could not find a way to map
> the X-Forwarded-Host header on top of the Host one prior to the point
> where the appropriate <VirtualHost> is determined. I hoped for
> some combo of mod_headers in "early" mode + mod_setenvif, but they
> run in post_read_request in the opposite order from what I needed.
>
> Hence this patch, which adds a UseCanonicalName XHost option in
> which X-Forwarded-Host is checked first, and if non-blank, is used
> in place of Host to determine the server name. (The Host header is
> left as-is, though.)
>
> http://people.apache.org/~chrisd/patches/use_canonical_name_xhost/use_canonical_name_xhost-trunk.patch
>
> Even if there's a resounding chorus of "boos", perhaps posting it
> here will help others facing the same problem in the future find a bit
> of a workaround if they're stuck in the same situation.
>
> Let the torches and firebrands be set alight! Cheers,

Wouldn't it be more appropriate to hack up^W^Wexpand mod_remoteip?

> Chris.
>
> --
> GPG Key ID: 088335A9
> GPG Key Fingerprint: 86CD 3297 7493 75BC F820 6715 F54F E648 0883 35A9

--
Igor Gali?

Tel: +43 (0) 664 886 22 883
Mail: i.galic@brainsware.org
URL: http://brainsware.org/
GPG: 6880 4155 74BD FD7C B515 2EA5 4B1D 9E08 A097 C9AE
Re: using X-Forwarded-Host as r->hostname [ In reply to ]
On 5/3/2012 5:57 PM, Chris Darroch wrote:
> I promise I won't
> be offended if anyone says it's a stupid hack and should never be
> committed, because, well, it is arguably a very stupid hack.

Actually, I think one could make the argument that all of the headers
set by mod_proxy should be just as configurable as any other header. I
have also faced situations with reverse proxies where a little
manipulation of the headers would save a lot of hassle.

I'm +1 to the idea of making something more configurable but -1 to the
idea of proceeding with an implementation for just this one case. I've
thought on several occasions that it would be quite valuable if
mod_headers could be run on the output headers of mod_proxy, but haven't
looked into the idea.


FWIW, this recipe seems to do the trick in my test case. Definitely not
"compliant" since it goobers up the other X-Forwarded-* headers, but
seems to accomplish your goal. It would also be fragile if multiple
X-Forwarded-For servers are prestend... you could tweak the regex to get
past that, though... ([^,\s]+) or something like that.

RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-For} (.+)
RewriteRule .* - [E=XFWD:%1]

ProxyPreserveHost On
RequestHeader set Host %{XFWD}e env=XFWD



Sample request1:

HEAD /XFwdTest/ HTTP/1.1
Host: whatever.com
X-Forwarded-Host: somethingElse.com
Connection: close


And what showed up downstream:

HEAD /XFwdTest/ HTTP/1.1
Host: somethingElse.com
X-Forwarded-Host: somethingElse.com, somethingElse.com
X-Forwarded-For: 192.168.0.2
X-Forwarded-Server: testbed.com
Connection: Keep-Alive



Sample request2:

HEAD /XFwdTest/ HTTP/1.1
Host: whatever.com
Connection: close


And what showed up downstream:

HEAD /XFwdTest/ HTTP/1.1
Host: whatever.com
X-Forwarded-For: 192.168.0.2
X-Forwarded-Host: whatever.com
X-Forwarded-Server: testbed.com
Connection: Keep-Alive


--
Daniel Ruggeri
Re: using X-Forwarded-Host as r->hostname [ In reply to ]
On 5/3/2012 5:57 PM, Chris Darroch wrote:
>
> Hence this patch, which adds a UseCanonicalName XHost option in
> which X-Forwarded-Host is checked first, and if non-blank, is used
> in place of Host to determine the server name. (The Host header is
> left as-is, though.)

That describes your use case, but let's presume this behavior doesn't use
a consistent header name. UseCanonicalName On|Off|{header-name} seems much
more appropriate.

What is the fallback for missing {header-name} values? On, or off? How would
we make this configurable?
Re: using X-Forwarded-Host as r->hostname [ In reply to ]
On 5/3/2012 6:14 PM, Igor Gali? wrote:
>
> ----- Chris Darroch <chrisd@pearsoncmg.com> wrote:
>>
>> Hence this patch, which adds a UseCanonicalName XHost option in
>> which X-Forwarded-Host is checked first, and if non-blank, is used
>> in place of Host to determine the server name. (The Host header is
>> left as-is, though.)
>
> Wouldn't it be more appropriate to hack up^W^Wexpand mod_remoteip?

That answer seems sensible to me, too.
Re: using X-Forwarded-Host as r->hostname [ In reply to ]
William A. Rowe Jr. wrote:

> On 5/3/2012 6:14 PM, Igor Gali? wrote:

>> Wouldn't it be more appropriate to hack up^W^Wexpand mod_remoteip?
>
> That answer seems sensible to me, too.

Thanks, guys, for pointing me at mod_remoteip; I agree it's a more
logical place for this kind of thing.

The challenge for me personally is that in ap_read_request(),
ap_update_vhost_from_headers() is called before
ap_run_post_read_request(). So even the first-out-of-the-gate
behaviour of mod_remoteip, which uses APR_HOOK_FIRST in post_read_request,
is too late because the choice of <VirtualHost> has already been made.
That's why I ended up with a hack on UseCanonicalName instead of something
more obviously module-based.

If others can find a tidier solution for that (or prove me wrong --
I didn't spend ages tracing the control flow), that would be great.

In the meantime I uploaded a further hack, which borrows some of
the nice logic in mod_remoteip for handling multiple values in the
X-Forwarded-Host header.

http://people.apache.org/~chrisd/patches/use_canonical_name_xhost/


> That describes your use case, but let's presume this behavior doesn't use
> a consistent header name. UseCanonicalName On|Off|{header-name} seems much
> more appropriate.
>
> What is the fallback for missing {header-name} values? On, or off? How would
> we make this configurable?

Hmm. Looking at the code in mod_remoteip, it would perhaps be
useful to align better with that module's directives (RemoteHostHeader,
perhaps?)

One of the several things I'm uncertain about, though,
is how to distinguish the case of just wanting to override, say,
the Host header *after* the <VirtualHost> has been selected (perhaps
this is the default case, to work like RemoteIPHeader), from the
"extra" case of using the inserted new value before <VirtualHost>
selection, which is more in UseCanonicalHost's territory.

Thoughts, anyone? And thanks very much for the feedback!

Chris.

--
GPG Key ID: 088335A9
GPG Key Fingerprint: 86CD 3297 7493 75BC F820 6715 F54F E648 0883 35A9
Re: using X-Forwarded-Host as r->hostname [ In reply to ]
> One of the several things I'm uncertain about, though,
> is how to distinguish the case of just wanting to override, say,
> the Host header *after* the <VirtualHost> has been selected (perhaps
> this is the default case, to work like RemoteIPHeader), from the
> "extra" case of using the inserted new value before <VirtualHost>
> selection, which is more in UseCanonicalHost's territory.

So, essentially, setting it as ServerAlias? But that doesn't make
it canonical, so UseCanonicalHost seems… inappropriate - or am I
misunderstanding your intent?

> Thoughts, anyone? And thanks very much for the feedback!
>
> Chris.
>
> --
> GPG Key ID: 088335A9
> GPG Key Fingerprint: 86CD 3297 7493 75BC F820 6715 F54F E648 0883
> 35A9

i

--
Igor Galić

Tel: +43 (0) 664 886 22 883
Mail: i.galic@brainsware.org
URL: http://brainsware.org/
GPG: 6880 4155 74BD FD7C B515 2EA5 4B1D 9E08 A097 C9AE
Re: using X-Forwarded-Host as r->hostname [ In reply to ]
Igor Galić wrote:

>> One of the several things I'm uncertain about, though,
>> is how to distinguish the case of just wanting to override, say,
>> the Host header *after* the <VirtualHost> has been selected (perhaps
>> this is the default case, to work like RemoteIPHeader), from the
>> "extra" case of using the inserted new value before <VirtualHost>
>> selection, which is more in UseCanonicalHost's territory.
>
> So, essentially, setting it as ServerAlias? But that doesn't make
> it canonical, so UseCanonicalHost seems… inappropriate - or am I
> misunderstanding your intent?

I didn't mean to cause confusion; it was a poor choice of words.
I just meant that the actual code which performs the selection of the
applicable <VirtualHost> is "in the neighbourhood of" the code that
implements UseCanonicalHost (i.e., not in a module but in the core),
not that there was any particular sense in which this would be a
"canonical" choice of hostname.

In short, I ended up patching core.c and vhost.c in order to
ensure that the value from X-Forwarded-Host was used everywhere
in place of the usual value for r->hostname, etc. It's a hack
and should, I agree, move into a module like mod_remoteip --
along with some nice configs so one could say, "always use the
2nd-last hostname in X-Forwarded-Host, as that's from my trusted
front-end proxy" and such like.

All I really meant in the previous note was that it would
be handy to have a further config flag which said either "use
this value *after* choosing <VirtualHost> the normal way" or
"use this value to choose your <VirtualHost>". And that latter
action probably requires some workaround to get the module's
code to run ahead of the vhost selection in server/vhost.c.

Chris.

--
GPG Key ID: 088335A9
GPG Key Fingerprint: 86CD 3297 7493 75BC F820 6715 F54F E648 0883 35A9