Added the ability to trust XFF (X-Forwarded-For) headers.
authorDan
Sun, 16 May 2010 21:35:43 -0400
changeset 1251 d543689ed2eb
parent 1250 d2db9f3628ab
child 1252 e34c23a35dc9
Added the ability to trust XFF (X-Forwarded-For) headers.
includes/common.php
includes/functions.php
language/english/admin.json
plugins/SpecialAdmin.php
--- a/includes/common.php	Sat May 15 03:05:43 2010 -0400
+++ b/includes/common.php	Sun May 16 21:35:43 2010 -0400
@@ -256,6 +256,8 @@
 
 profiler_log('Config fetched');
 
+do_xff_check();
+
 if ( defined('ENANO_EXIT_AFTER_CONFIG') )
 {
 	return true;
--- a/includes/functions.php	Sat May 15 03:05:43 2010 -0400
+++ b/includes/functions.php	Sun May 16 21:35:43 2010 -0400
@@ -2874,14 +2874,32 @@
 
 function is_valid_ip($ip)
 {
+	return is_valid_ipv4($ip) || is_valid_ipv6($ip);
+}
+
+/**
+ * Test validity of IPv4 address
+ * @param string
+ * @return bool
+ */
+
+function is_valid_ipv4($ip)
+{
 	// This next one came from phpBB3.
 	$ipv4 = '(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])';
+	return preg_match("/^{$ipv4}$/", $ip) ? true : false;
+}
+
+/**
+ * Test validity of IPv6 address
+ * @param string
+ * @return bool
+ */
+
+function is_valid_ipv6($ip)
+{
 	$ipv6 = '(?:[a-f0-9]{0,4}):(?:[a-f0-9]{0,4}):(?:[a-f0-9]{0,4}:|:)?(?:[a-f0-9]{0,4}:|:)?(?:[a-f0-9]{0,4}:|:)?(?:[a-f0-9]{0,4}:|:)?(?:[a-f0-9]{0,4}:|:)?(?:[a-f0-9]{1,4})';
-
-	if ( preg_match("/^{$ipv4}$/", $ip) || preg_match("/^{$ipv6}$/", $ip) )
-		return true;
-	else
-		return false;
+	return preg_match("/^{$ipv6}$/", $ip) ? true : false;
 }
 
 /**
@@ -5339,3 +5357,28 @@
 	return $crypto_backend;
 }
 
+/**
+ * Perform X-Forwarded-For check and apply it as the REMOTE_ADDR if the settings tell us to
+ */
+
+function do_xff_check()
+{
+	if ( isset($_SERVER['HTTP_X_FORWARDED_FOR']) && getConfig('trust_xff', 'none') != 'none' )
+	{
+		switch(getConfig('trust_xff', 'none'))
+		{
+			case 'both':
+				if ( is_valid_ip($_SERVER['HTTP_X_FORWARDED_FOR']) )
+					$_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_FORWARDED_FOR'];
+				break;
+			case 'ipv4':
+				if ( is_valid_ip($_SERVER['HTTP_X_FORWARDED_FOR']) && is_valid_ipv4($_SERVER['REMOTE_ADDR']) )
+					$_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_FORWARDED_FOR'];
+				break;
+			case 'ipv6':
+				if ( is_valid_ip($_SERVER['HTTP_X_FORWARDED_FOR']) && is_valid_ipv6($_SERVER['REMOTE_ADDR']) )
+					$_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_FORWARDED_FOR'];
+				break;
+		}
+	}
+}
--- a/language/english/admin.json	Sat May 15 03:05:43 2010 -0400
+++ b/language/english/admin.json	Sun May 16 21:35:43 2010 -0400
@@ -344,6 +344,8 @@
 			field_breadcrumb_mode_always: 'Always',
 			field_breadcrumb_mode_never: 'Never',
 			
+			heading_server_settings: 'Server settings',
+			
 			// Section: CDN
 			field_cdn_path: 'URL to <acronym title="Content Delivery Network">CDN</acronym> server:',
 			field_cdn_path_hint: 'A CDN, or Content Delivery Network, allows downloading of shared Enano components from a server designed to serve out only images, CSS, and script files. Since a browser can open separate connections for the page and for images and scripts, the page loads faster. Leave this blank to just use Enano\'s local files (default).',
@@ -361,6 +363,14 @@
 			field_gzip_check_msg_success: 'Success - all server checks passed. You can enable gzip support.',
 			field_gzip_check_msg_failure: 'Server check failed. Unless you think Enano is wrong, don\'t enable gzip below.',
 			
+			// Section: Trust XFF
+			field_xff: 'Trust X-Forwarded-For header:',
+			field_xff_hint: 'If your server is behind a proxying cache such as Squid or Varnish, turn this on to trust the IP addresses sent from the proxy. The remote address reported by your webserver, not the value of X-Forwarded-For, is the source address used to decide whether to trust the header or not.',
+			field_xff_checkbox: 'Trust XFF header',
+			field_xff_radio_both: 'Both IPv4 and IPv6 (default)',
+			field_xff_radio_ipv4: 'IPv4 source addresses only',
+			field_xff_radio_ipv6: 'IPv6 source addresses only',
+			
 			// Main section: users and communication
 			heading_users: 'Users and communication',
 			
--- a/plugins/SpecialAdmin.php	Sat May 15 03:05:43 2010 -0400
+++ b/plugins/SpecialAdmin.php	Sun May 16 21:35:43 2010 -0400
@@ -273,6 +273,15 @@
 		setConfig('userpage_grant_acl', ( isset($_POST['userpage_grant_acl']) ? '1' : '0' ));
 		setConfig('gzip_output', ( isset($_POST['gzip_output']) ? '1' : '0' ));
 		
+		if ( isset($_POST['trust_xff']) )
+		{
+			setConfig('trust_xff', $_POST['trust_xff_type']);
+		}
+		else
+		{
+			setConfig('trust_xff', 'none');
+		}
+		
 		// Allow plugins to save their changes
 		$code = $plugins->setHook('acp_general_save');
 		foreach ( $code as $cmd )
@@ -572,7 +581,9 @@
 				</td>
 			</tr>
 		
-		<!-- CDN settings -->
+		<!-- CDN URL -->
+		
+			<tr><th class="subhead" colspan="2"><?php echo $lang->get('acpgc_heading_server_settings'); ?></th></tr>
 		
 			<tr>
 				<td class="row2">
@@ -607,6 +618,37 @@
 				</td>
 			</tr>
 			
+		<!-- XFF -->
+		
+			<tr>
+				<td class="row2">
+					<b><?php echo $lang->get('acpgc_field_xff'); ?></b><br />
+					<small><?php echo $lang->get('acpgc_field_xff_hint'); ?></small>
+				</td>
+				<td class="row2">
+					<label>
+						<input type="checkbox" name="trust_xff" onclick="$('#trust_xff_body').toggle('blind');"<?php if ( in_array(getConfig('trust_xff', 'none'), array('ipv4', 'ipv6', 'both'))) echo ' checked="checked"'; ?> />
+						<?php echo $lang->get('acpgc_field_xff_checkbox'); ?>
+					</label>
+					<div id="trust_xff_body" style="margin: 5px 0 0 10px; display: <?php echo ( in_array(getConfig('trust_xff', 'none'), array('ipv4', 'ipv6', 'both')) ) ? "block" : "none"; ?>;">
+						<label>
+							<input type="radio" name="trust_xff_type" value="both"<?php if ( getConfig('trust_xff', 'none') == 'both' || getConfig('trust_xff', 'none') == 'none' ) echo ' checked="checked"'; ?> />
+							<?php echo $lang->get('acpgc_field_xff_radio_both'); ?>
+						</label>
+						<br />
+						<label>
+							<input type="radio" name="trust_xff_type" value="ipv4"<?php if ( getConfig('trust_xff', 'none') == 'ipv4' ) echo ' checked="checked"'; ?> />
+							<?php echo $lang->get('acpgc_field_xff_radio_ipv4'); ?>
+						</label>
+						<br />
+						<label>
+							<input type="radio" name="trust_xff_type" value="ipv6"<?php if ( getConfig('trust_xff', 'none') == 'ipv6' ) echo ' checked="checked"'; ?> />
+							<?php echo $lang->get('acpgc_field_xff_radio_ipv6'); ?>
+						</label>
+					</div>
+				</td>
+			</tr>
+			
 		<!-- Allow plugins to add code -->
 			<?php
 			$code = $plugins->setHook('acp_general_basic');