[squid-dev] RFC: make FOLLOW_X_FORWARDED_FOR unconditional
Amos Jeffries
squid3 at treenet.co.nz
Wed Oct 11 07:15:50 UTC 2023
On 11/10/23 08:19, Alex Rousskov wrote:
> On 2023-10-10 12:17, Francesco Chemolli wrote:
>
>> what if we removed the configure option for FOLLOW_X_FORWARDED_FOR, and
>> made it unconditionally part of Squid?
>
> Some Squid deployments will silently break AFAICT.
>
In what way specifically?
>
>> It is on by default,
>
> Here, "it" should be viewed as a combination of FOLLOW_X_FORWARDED_FOR
> and the directives that macro enables (by default). Unfortunately, some
> of those directives are on by default[1]. This implies that, after we
> remove FOLLOW_X_FORWARDED_FOR, a Squid built with
> --disable-follow-x-forwarded-for will start doing something it was not
> doing before, and the behavior changes should be assumed to be
> significant until you can prove otherwise.
>
The Proof is in cf.data.pre:
"
NAME: follow_x_forwarded_for
...
DEFAULT_IF_NONE: deny all
DEFAULT_DOC: X-Forwarded-For header will be ignored.
"
Removing FOLLOW_X_FORWARDED_FOR will make installations which previously
were not able to run with follow_x_forwarded_for configured would begin
behaving as if "follow_x_forwarded_for deny all" was configured.
That is behaviorally the same as --disable-follow-x-forwarded-for.
>
>> and it is controlled by runtime configuration,
>
> ... but not in a good way: Squid code cannot tell whether
> follow_x_forwarded_for is "enabled" beyond checking
> FOLLOW_X_FORWARDED_FOR. It is possible to change that, but changing that
> (and adjusting how other related directives are checked!) requires
> non-trivial work. See (B) below.
>
I do not see a transition problem here.
As per the above cf.data.pre contents, only installations which already
were using --enable-follow-x-forwarded-for were able to set the related
configuration options. They would not see any change.
>
>> removing the compile-time option would ensure we have better testing
>> coverage.
>
> Indeed. I support removal of this and similar unnecessary compile-time
> options, but because related directives[1] are _on_ by default (in
> --enable-follow-x-forwarded-for and equivalent builds), we should not
> just enable this feature, screwing up folks that disabled it explicitly
> in their builds.
IMO that is easily resolved. Just drop the DEFAULT_IF_NONE stanza from
cf.data.pre and modify the if-statement in
ClientRequestContext::clientAccessCheck() to set
http->request->indirect_client_addr whenever
"!Config.accessList.followXFF".
That will avoid any "screwing over" because the "indirect" IP would be
the same as the "direct" IP under the above default
follow_x_forwarded_for behavior.
Even if admin has misconfigured one of those *_indirect_client settings
the implicit/default "follow_x_forwarded_for deny all" makes the correct
IP be used.
>
> Also, the current implementation of XFF code is fairly expensive -- it
> requires slow ACL checks. If we just remove that FOLLOW_X_FORWARDED_FOR
> guard, we will be adding quite a few wasted CPU cycles to all Squid
> builds that (used to) disable that feature.
>
Dropping the "DEFAULT_IF_NONE" stanza entirely avoids all the ACL costs
by default, without changing the above behavior analysis that proves IMO
this feature as safe to enable.
Bonus: it would also avoid the ACL cycles currently wasted on
installations where the feature is already enabled but not configured.
Extra bonus: any logic which specifically relies on testing
(!)FOLLOW_X_FORWARDED_FOR can switch to checking
(!)Config.accessList.followXFF instead.
>
> [1] squid.conf directives that are enabled by default in
> --enable-follow-x-forwarded-for and equivalent builds include:
> log_uses_indirect_client, adaptation_uses_indirect_client,
> acl_uses_indirect_client, delay_pool_uses_indirect_client.
>
>
> I see a few possible strategies here:
>
> A) Make ./configure --disable-follow-x-forwarded-for fail. Easy to
> implement but kind of goes against ./configure tradition and leaves a
> backward compatibility hack in Squid code. It also forces admins that do
> _not_ want this feature to disable 4+ directives they do not care about
> -- bad UX. I am against this option.
Unnecessary. For reasons detailed above.
>
> B) Make all *_uses_indirect_client and similar directives default to off
> unless the configuration contains an explicit follow_x_forwarded_for
> rule.
> Warn if one of those directives is explicitly on when there are no
> explicit follow_x_forwarded_for rules. This requires non-trivial work.
IMO this is optional. A "nice to have" UI behaviour that a lot of
squid.conf settings could do, but do not (yet).
The future ConfigParser redesign project changes are likely to make this
type of check a lot easier to implement in an entirely different way
than it would have to be done right now. So IMO there is no hurry to
rush/require this change.
> That work will probably fix a few existing bugs. I support this option.
>
C) Just drop the DEFAULT_IF_NONE stanza from cf.data.pre and modify the
if-statement in ClientRequestContext::clientAccessCheck() like so:
"
if (!http->request->flags.doneFollowXff()) {
/* we always trust the direct client address for actual use */
http->request->indirect_client_addr = http->request->client_addr;
http->request->indirect_client_addr.port(0);
if (Config.accessList.followXFF &&
http->request->header.has(Http::HdrType::X_FORWARDED_FOR)) {
... current logic except above indirect_client_addr lines ...
}
return;
}
"
HTH
Amos
More information about the squid-dev
mailing list