Skip to content

[2.1] Address issues with proxy lookups#9229

Open
sbulen wants to merge 2 commits into
SimpleMachines:release-2.1from
sbulen:21_proxy_ips
Open

[2.1] Address issues with proxy lookups#9229
sbulen wants to merge 2 commits into
SimpleMachines:release-2.1from
sbulen:21_proxy_ips

Conversation

@sbulen
Copy link
Copy Markdown
Contributor

@sbulen sbulen commented May 12, 2026

Fixes #9143

I took a stab at this.

Changes:

  • Improved logic for determining user IP vs proxy server IP.
  • Quite a bit stricter - doesn't touch ANYTHING unless everything validates correctly. Solves initial problem where bogus data was passed as IPs. Very short leash on 'auto' setting, no longer the default if unspecified...
  • If valid proxy servers are not specified in proxy_ip_servers, proxy server should be local/private.
  • Properly uses FIRST ip in header list, not last, for user IP, per RFC 7239.
  • Validate IPs via filter_var(), not via regex.
  • Consistent support & logic across ipv4 & ipv6.
  • Bug fix: IPs passed via headers weren't validated...
  • Bug fix: Fixed explode issue, where it would fail if there weren't spaces after commas...
  • Bug fix: Fixed CIDR checks - invalid regex pattern for cidr, caused everything to return positive...
  • Bug fix: Fixed ipv6 issue in CIDR checks - cannot use ip2long on ipv6...
  • Bug fix: Loop logic issues addressed... After exploding $_SERVER[$proxyIPheader], it kept operating on the whole thing instead of each ip...
  • Bug fix: Localhost checks were... illogical... E.g., they didn't factor in whether we'd already validated the proxy server vs proxy_ip_servers.

CONCERN:
Note that the ban check validates against BOTH the member_ip and member_ip2, i.e., both the proxy and the end user IP. Also note that the proxy may be using a valid 'localhost' IP. So... When we get this working, a ban on a user by IP can effectively ban a valid 'localhost' IP, i.e., a huge swath of (or even all...) proxy traffic.

Here:

// Check both IP addresses.

I believe we should only check the end user in the ban check, not the proxy server...

If agreed, I'll add this to this PR...

If we wish to proceed with this I'll submit the 3.0 version once approved.

@sbulen sbulen marked this pull request as draft May 12, 2026 00:37
@sbulen
Copy link
Copy Markdown
Contributor Author

sbulen commented May 12, 2026

I'm still doing testing... (I tested as best I can without actually having a proxy!)

I think we have an issue where the editor config is out of sync with the edit checks??? It's not liking my EOF, and it's not letting me fix it either...

Signed-off-by: Shawn Bulen <bulens@pacbell.net>
Signed-off-by: Shawn Bulen <bulens@pacbell.net>
@sbulen sbulen marked this pull request as ready for review May 12, 2026 17:00
@sbulen
Copy link
Copy Markdown
Contributor Author

sbulen commented May 12, 2026

Ready for review/test.

My core tests are below:

=======================================

	//Test 1: Plain user ipv4, no config
	$_SERVER['REMOTE_ADDR'] = '173.228.74.9';
	$modSettings['proxy_ip_header'] = 'autodetect';
	$modSettings['proxy_ip_servers'] = '';

	// Expected result:
	$_SERVER['REMOTE_ADDR'] = '173.228.74.9';
	$_SERVER['BAN_CHECK_IP'] = '173.228.74.9';


=======================================

	//Test 2: Plain user ipv6, no config
	$_SERVER['REMOTE_ADDR'] = '2001:5a8:4284:ed00:8007:6463:700f:f07b';
	$modSettings['proxy_ip_header'] = 'autodetect';
	$modSettings['proxy_ip_servers'] = '';

	// Expected result:
	$_SERVER['REMOTE_ADDR'] = '2001:5a8:4284:ed00:8007:6463:700f:f07b';
	$_SERVER['BAN_CHECK_IP'] = '2001:5a8:4284:ed00:8007:6463:700f:f07b';

=======================================

	//Test 3: Plain ipv6, HTTP_X_FORWARDED_FOR (should use local)
	$_SERVER['REMOTE_ADDR'] = 'fe80::';
	$_SERVER['HTTP_X_FORWARDED_FOR'] = '2001:5a8:4284:ed00:8007:6463:700f:f07b, 2405:8100::,2405:b500::';
	$modSettings['proxy_ip_header'] = 'HTTP_X_FORWARDED_FOR';
	$modSettings['proxy_ip_servers'] = '';

	// Expected result:
	$_SERVER['REMOTE_ADDR'] = '2001:5a8:4284:ed00:8007:6463:700f:f07b';
	$_SERVER['BAN_CHECK_IP'] = 'fe80::';

=======================================

	//Test 4: ipv4, CF
	$_SERVER['REMOTE_ADDR'] = '103.31.6.1';
	$_SERVER['HTTP_CF_CONNECTING_IP'] = '173.228.74.9,2405:8100::,2405:b500::';
	$modSettings['proxy_ip_header'] = 'HTTP_CF_CONNECTING_IP';
	$modSettings['proxy_ip_servers'] = '173.245.48.0/20,103.21.244.0/22,103.22.200.0/22,103.31.4.0/22,141.101.64.0/18,108.162.192.0/18,190.93.240.0/20,188.114.96.0/20,197.234.240.0/22,198.41.128.0/17,162.158.0.0/15,104.16.0.0/13,104.24.0.0/14,172.64.0.0/13,131.0.72.0/22,2400:cb00::/32,2606:4700::/32,2803:f800::/32,2405:b500::/32,2405:8100::/32,2a06:98c0::/29,2c0f:f248::/32';

	// Expected result:
	$_SERVER['REMOTE_ADDR'] = '173.228.74.9';
	$_SERVER['BAN_CHECK_IP'] = '103.31.6.1';

=======================================

	//Test 5: ipv6, CF
	$_SERVER['REMOTE_ADDR'] = '2c0f:f248::aaaa:111';
	$_SERVER['HTTP_CF_CONNECTING_IP'] = '2001:5a8:4284:ed00:8007:6463:700f:f07b,2405:8100::,2405:b500::';
	$modSettings['proxy_ip_header'] = 'HTTP_CF_CONNECTING_IP';
	$modSettings['proxy_ip_servers'] = '173.245.48.0/20,103.21.244.0/22,103.22.200.0/22,103.31.4.0/22,141.101.64.0/18,108.162.192.0/18,190.93.240.0/20,188.114.96.0/20,197.234.240.0/22,198.41.128.0/17,162.158.0.0/15,104.16.0.0/13,104.24.0.0/14,172.64.0.0/13,131.0.72.0/22,2400:cb00::/32,2606:4700::/32,2803:f800::/32,2405:b500::/32,2405:8100::/32,2a06:98c0::/29,2c0f:f248::/32';

	// Expected result:
	$_SERVER['REMOTE_ADDR'] = '2001:5a8:4284:ed00:8007:6463:700f:f07b';
	$_SERVER['BAN_CHECK_IP'] = '2c0f:f248::aaaa:111';

=======================================

	//Test 6: ipv6 ::ffff
	$_SERVER['REMOTE_ADDR'] = '::ffff:173.228.74.9';
	$modSettings['proxy_ip_header'] = 'autodetect';
	$modSettings['proxy_ip_servers'] = '';

	// Expected result:
	$_SERVER['REMOTE_ADDR'] = '173.228.74.9';
	$_SERVER['BAN_CHECK_IP'] = '173.228.74.9';

=======================================

	//Test 7: ipv6 with brackets ::ffff
	$_SERVER['REMOTE_ADDR'] = '2405:b500::4';
	$_SERVER['HTTP_CF_CONNECTING_IP'] = '[::ffff:173.228.74.9],2405:8100::,2405:b500::';
	$modSettings['proxy_ip_header'] = 'autodetect';
	$modSettings['proxy_ip_servers'] = '[2405:b500::1], [2405:b500::3], [2405:b500::4]';

	// Expected result:
	$_SERVER['REMOTE_ADDR'] = '173.228.74.9';
	$_SERVER['BAN_CHECK_IP'] = '2405:b500::4';

=======================================

	//Test 8: ipv4, CF, whitespaces & tabs
	$_SERVER['REMOTE_ADDR'] = '103.31.7.255';
	$_SERVER['HTTP_CF_CONNECTING_IP'] = '173.228.74.9, 2405:8100:: , 	2405:b500::		';
	$modSettings['proxy_ip_header'] = 'HTTP_CF_CONNECTING_IP';
	$modSettings['proxy_ip_servers'] = '173.245.48.0/20,	103.21.244.0/22,103.22.200.0/22,	103.31.4.0/22,141.101.64.0/18,108.162.192.0/18,190.93.240.0/20,188.114.96.0/20,197.234.240.0/22,198.41.128.0/17,162.158.0.0/15,104.16.0.0/13,104.24.0.0/14,172.64.0.0/13,131.0.72.0/22,2400:cb00::/32,2606:4700::/32,2803:f800::/32,2405:b500::/32,2405:8100::/32,2a06:98c0::/29,	2c0f:f248::/32';

	// Expected result:
	$_SERVER['REMOTE_ADDR'] = '173.228.74.9';
	$_SERVER['BAN_CHECK_IP'] = '103.31.7.255';

=======================================

	//Test 9: ipv6, CF, whitespaces & tabs
	$_SERVER['REMOTE_ADDR'] = '2C0F:F248:FFFF:FFFF:FFFF:FFFF:FFFF:FFFE';
	$_SERVER['HTTP_CF_CONNECTING_IP'] = '2001:5a8:4284:ed00:8007:6463:700f:f07b   , 2405:8100::, 2405:b500::';
	$modSettings['proxy_ip_header'] = 'HTTP_CF_CONNECTING_IP';
	$modSettings['proxy_ip_servers'] = '173.245.48.0/20,103.21.244.0/22,103.22.200.0/22,103.31.4.0/22,141.101.64.0/18,108.162.192.0/18,190.93.240.0/20,188.114.96.0/20,197.234.240.0/22,198.41.128.0/17,162.158.0.0/15,104.16.0.0/13,104.24.0.0/14,172.64.0.0/13,131.0.72.0/22,2400:cb00::/32,2606:4700::/32,2803:f800::/32,2405:b500::/32,  2405:8100::/32,  2a06:98c0::/29,  2c0f:f248::/32  ';

	// Expected result:
	$_SERVER['REMOTE_ADDR'] = '2001:5a8:4284:ed00:8007:6463:700f:f07b';
	$_SERVER['BAN_CHECK_IP'] = '2C0F:F248:FFFF:FFFF:FFFF:FFFF:FFFF:FFFE';

=======================================

	//Test 10: ipv6, CF, wrong header specified
	$_SERVER['REMOTE_ADDR'] = '2c0f:f248::';
	$_SERVER['HTTP_CF_CONNECTING_IP'] = '2001:5a8:4284:ed00:8007:6463:700f:f07b   , 2405:8100::, 2405:b500::';
	$modSettings['proxy_ip_header'] = 'HTTP_X_FORWARDED_FOR';
	$modSettings['proxy_ip_servers'] = '173.245.48.0/20,103.21.244.0/22,103.22.200.0/22,103.31.4.0/22,141.101.64.0/18,108.162.192.0/18,190.93.240.0/20,188.114.96.0/20,197.234.240.0/22,198.41.128.0/17,162.158.0.0/15,104.16.0.0/13,104.24.0.0/14,172.64.0.0/13,131.0.72.0/22,2400:cb00::/32,2606:4700::/32,2803:f800::/32,2405:b500::/32,  2405:8100::/32,  2a06:98c0::/29,  2c0f:f248::/32  ';

	// Expected result:
	$_SERVER['REMOTE_ADDR'] = '2c0f:f248::';
	$_SERVER['BAN_CHECK_IP'] = '2c0f:f248::';

=======================================

	//Test 11: ipv6, CF, JUNK kiddie scripter....
	$_SERVER['REMOTE_ADDR'] = '2c0f:f248::';
	$_SERVER['HTTP_CF_CONNECTING_IP'] = 'why   <>;[;]];];[;)\<\>(."<">", oh why,  would I ever';
	$modSettings['proxy_ip_header'] = 'HTTP_CF_CONNECTING_IP';
	$modSettings['proxy_ip_servers'] = '173.245.48.0/20,103.21.244.0/22,103.22.200.0/22,103.31.4.0/22,141.101.64.0/18,108.162.192.0/18,190.93.240.0/20,188.114.96.0/20,197.234.240.0/22,198.41.128.0/17,162.158.0.0/15,104.16.0.0/13,104.24.0.0/14,172.64.0.0/13,131.0.72.0/22,2400:cb00::/32,2606:4700::/32,2803:f800::/32,2405:b500::/32,  2405:8100::/32,  2a06:98c0::/29,  2c0f:f248::/32  ';

	// Expected result:
	$_SERVER['REMOTE_ADDR'] = '2c0f:f248::';
	$_SERVER['BAN_CHECK_IP'] = '2c0f:f248::';

=======================================

@sbulen
Copy link
Copy Markdown
Contributor Author

sbulen commented May 12, 2026

Note on the UI... I was initially a little concerned about defaulting to 'disable', where the current logic defaulted to 'autodetect' but...

If you install 2.1.7 today, $modSettings['proxy_ip_header'] is not set. BUT... SMF displays the setting as: "Do not allow Proxy IP Headers"... Blank/empty is just displaying the first value in the list...

So in fact, defaulting to 'autodetect' was out of sync with what was displayed in the UI. 'disable' is more accurate.

In fact, the only way to fix that in 2.1.7, to bring the setting in sync with the behavior, is to modify the field to another value, then change it back...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant