Index: CHANGELOG.txt
===================================================================
RCS file: /cvs/drupal/drupal/CHANGELOG.txt,v
retrieving revision 1.198
diff -u -F^f -r1.198 CHANGELOG.txt
--- CHANGELOG.txt	15 May 2007 15:29:47 -0000	1.198
+++ CHANGELOG.txt	17 May 2007 13:54:19 -0000
@@ -2,6 +2,8 @@
 
 Drupal 6.0, xxxx-xx-xx (development version)
 ----------------------
+- New reverse proxy settings, allows Drupal to use the correct IP address from X-Forwarded-For headers
+  if it is being run behind a proxy (e.g. squid).
 - New watchdog as a hook functionality.
    * New hook_watchdog that can be implemented by any module to route log messages to various destinations.
    * Expands the severity levels from 3 (Error, Warning, Notice) to the 8 levels defined in RFC 3164.
Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.641
diff -u -F^f -r1.641 common.inc
--- includes/common.inc	15 May 2007 20:19:47 -0000	1.641
+++ includes/common.inc	17 May 2007 13:54:21 -0000
@@ -801,7 +801,7 @@ function valid_url($url, $absolute = FAL
  *   The name of the event.
  */
 function flood_register_event($name) {
-  db_query("INSERT INTO {flood} (event, hostname, timestamp) VALUES ('%s', '%s', %d)", $name, $_SERVER['REMOTE_ADDR'], time());
+  db_query("INSERT INTO {flood} (event, hostname, timestamp) VALUES ('%s', '%s', %d)", $name, ip_address(), time());
 }
 
 /**
@@ -817,7 +817,7 @@ function flood_register_event($name) {
  *   True if the user did not exceed the hourly threshold. False otherwise.
  */
 function flood_is_allowed($name, $threshold) {
-  $number = db_num_rows(db_query("SELECT event FROM {flood} WHERE event = '%s' AND hostname = '%s' AND timestamp > %d", $name, $_SERVER['REMOTE_ADDR'], time() - 3600));
+  $number = db_num_rows(db_query("SELECT event FROM {flood} WHERE event = '%s' AND hostname = '%s' AND timestamp > %d", $name, ip_address(), time() - 3600));
   return ($number < $threshold ? TRUE : FALSE);
 }
 
@@ -2651,3 +2651,4 @@ function watchdog_severity_levels() {
     WATCHDOG_DEBUG    => t('debug'),
   );
 }
+
Index: includes/bootstrap.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/bootstrap.inc,v
retrieving revision 1.165
diff -u -F^f -r1.165 bootstrap.inc
--- includes/bootstrap.inc	8 May 2007 16:36:55 -0000	1.165
+++ includes/bootstrap.inc	17 May 2007 13:54:21 -0000
@@ -703,7 +703,7 @@ function watchdog($type, $message, $vari
     'user'        => $user,
     'request_uri' => $base_root . request_uri(),
     'referer'     => referer_uri(),
-    'ip'          => $_SERVER['REMOTE_ADDR'],
+    'ip'          => ip_address(),
     'timestamp'   => time(),
     );
 
@@ -819,7 +819,7 @@ function drupal_is_denied($type, $mask) 
 function drupal_anonymous_user($session = '') {
   $user = new stdClass();
   $user->uid = 0;
-  $user->hostname = $_SERVER['REMOTE_ADDR'];
+  $user->hostname = ip_address();
   $user->roles = array();
   $user->roles[DRUPAL_ANONYMOUS_RID] = 'anonymous user';
   $user->session = $session;
@@ -881,9 +881,9 @@ function _drupal_bootstrap($phase) {
 
     case DRUPAL_BOOTSTRAP_ACCESS:
       // Deny access to hosts which were banned - t() is not yet available.
-      if (drupal_is_denied('host', $_SERVER['REMOTE_ADDR'])) {
+      if (drupal_is_denied('host', ip_address())) {
         header('HTTP/1.1 403 Forbidden');
-        print 'Sorry, '. $_SERVER['REMOTE_ADDR'] .' has been banned.';
+        print 'Sorry, '. ip_address() .' has been banned.';
         exit();
       }
       break;
@@ -1056,3 +1056,22 @@ function language_list($field = 'languag
 function language_default() {
   return variable_get('language_default', (object) array('language' => 'en', 'name' => 'English', 'native' => 'English', 'direction' => 0, 'enabled' => 1, 'plurals' => 0, 'formula' => '', 'domain' => '', 'prefix' => '', 'weight' => 0));
 }
+
+
+/**
+ * If Drupal is behind a reverse proxy, we use the X-Forwarded-For header
+ * instead of $_SERVER['REMOTE_ADDR'], which would be the IP address
+ * of the proxy server, and not the client's.
+ *
+ * @return
+ *   IP address of client machine, adjusted for reverse proxy.
+ */
+function ip_address() {
+  $ip = $_SERVER['REMOTE_ADDR'];
+  if (variable_get('reverse_proxy', FALSE)) {
+    if (array_key_exists('HTTP_X_FORWARDED_FOR', $_SERVER)) {
+      $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
+    }
+  }
+  return $ip;
+}
Index: includes/session.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/session.inc,v
retrieving revision 1.39
diff -u -F^f -r1.39 session.inc
--- includes/session.inc	27 Apr 2007 07:47:38 -0000	1.39
+++ includes/session.inc	17 May 2007 13:54:21 -0000
@@ -69,11 +69,11 @@ function sess_write($key, $value) {
     // and gives more useful statistics. We can't eliminate anonymous session
     // table rows without breaking throttle module and "Who's Online" block.
     if ($user->uid || $value || count($_COOKIE)) {
-      db_query("INSERT INTO {sessions} (sid, uid, cache, hostname, session, timestamp) VALUES ('%s', %d, %d, '%s', '%s', %d)", $key, $user->uid, isset($user->cache) ? $user->cache : '', $_SERVER["REMOTE_ADDR"], $value, time());
+      db_query("INSERT INTO {sessions} (sid, uid, cache, hostname, session, timestamp) VALUES ('%s', %d, %d, '%s', '%s', %d)", $key, $user->uid, isset($user->cache) ? $user->cache : '', ip_address(), $value, time());
     }
   }
   else {
-    db_query("UPDATE {sessions} SET uid = %d, cache = %d, hostname = '%s', session = '%s', timestamp = %d WHERE sid = '%s'", $user->uid, isset($user->cache) ? $user->cache : '', $_SERVER["REMOTE_ADDR"], $value, time(), $key);
+    db_query("UPDATE {sessions} SET uid = %d, cache = %d, hostname = '%s', session = '%s', timestamp = %d WHERE sid = '%s'", $user->uid, isset($user->cache) ? $user->cache : '', ip_address(), $value, time(), $key);
 
     // TODO: this can be an expensive query. Perhaps only execute it every x minutes. Requires investigation into cache expiration.
     if ($user->uid) {
Index: modules/comment/comment.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/comment/comment.module,v
retrieving revision 1.542
diff -u -F^f -r1.542 comment.module
--- modules/comment/comment.module	14 May 2007 13:43:35 -0000	1.542
+++ modules/comment/comment.module	17 May 2007 13:54:22 -0000
@@ -820,7 +820,7 @@ function comment_save($edit) {
         }
 
         $edit += array('mail' => '', 'homepage' => '');
-        db_query("INSERT INTO {comments} (cid, nid, pid, uid, subject, comment, format, hostname, timestamp, status, score, users, thread, name, mail, homepage) VALUES (%d, %d, %d, %d, '%s', '%s', %d, '%s', %d, %d, %d, '%s', '%s', '%s', '%s', '%s')", $edit['cid'], $edit['nid'], $edit['pid'], $edit['uid'], $edit['subject'], $edit['comment'], $edit['format'], $_SERVER['REMOTE_ADDR'], $edit['timestamp'], $status, $score, $users, $thread, $edit['name'], $edit['mail'], $edit['homepage']);
+        db_query("INSERT INTO {comments} (cid, nid, pid, uid, subject, comment, format, hostname, timestamp, status, score, users, thread, name, mail, homepage) VALUES (%d, %d, %d, %d, '%s', '%s', %d, '%s', %d, %d, %d, '%s', '%s', '%s', '%s', '%s')", $edit['cid'], $edit['nid'], $edit['pid'], $edit['uid'], $edit['subject'], $edit['comment'], $edit['format'], ip_address(), $edit['timestamp'], $status, $score, $users, $thread, $edit['name'], $edit['mail'], $edit['homepage']);
 
         _comment_update_node_statistics($edit['nid']);
 
Index: modules/poll/poll.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/poll/poll.module,v
retrieving revision 1.228
diff -u -F^f -r1.228 poll.module
--- modules/poll/poll.module	14 May 2007 13:43:36 -0000	1.228
+++ modules/poll/poll.module	17 May 2007 13:54:23 -0000
@@ -308,7 +308,7 @@ function poll_load($node) {
       $result = db_fetch_object(db_query('SELECT chorder FROM {poll_votes} WHERE nid = %d AND uid = %d', $node->nid, $user->uid));
     }
     else {
-      $result = db_fetch_object(db_query("SELECT chorder FROM {poll_votes} WHERE nid = %d AND hostname = '%s'", $node->nid, $_SERVER['REMOTE_ADDR']));
+      $result = db_fetch_object(db_query("SELECT chorder FROM {poll_votes} WHERE nid = %d AND hostname = '%s'", $node->nid, ip_address()));
     }
     if (isset($result->chorder)) {
       $poll->vote = $result->chorder;
@@ -534,7 +534,7 @@ function poll_vote(&$node) {
           db_query('INSERT INTO {poll_votes} (nid, chorder, uid) VALUES (%d, %d, %d)', $node->nid, $choice, $user->uid);
         }
         else {
-          db_query("INSERT INTO {poll_votes} (nid, chorder, hostname) VALUES (%d, %d, '%s')", $node->nid, $choice, $_SERVER['REMOTE_ADDR']);
+          db_query("INSERT INTO {poll_votes} (nid, chorder, hostname) VALUES (%d, %d, '%s')", $node->nid, $choice, ip_address());
         }
 
         // Add one to the votes.
@@ -573,7 +573,7 @@ function poll_cancel(&$node) {
         db_query('DELETE FROM {poll_votes} WHERE nid = %d and uid = %d', $node->nid, $user->uid);
       }
       else {
-        db_query("DELETE FROM {poll_votes} WHERE nid = %d and hostname = '%s'", $node->nid, $_SERVER['REMOTE_ADDR']);
+        db_query("DELETE FROM {poll_votes} WHERE nid = %d and hostname = '%s'", $node->nid, ip_address());
       }
 
       // Subtract from the votes.
Index: modules/statistics/statistics.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/statistics/statistics.module,v
retrieving revision 1.258
diff -u -F^f -r1.258 statistics.module
--- modules/statistics/statistics.module	30 Apr 2007 17:03:27 -0000	1.258
+++ modules/statistics/statistics.module	17 May 2007 13:54:23 -0000
@@ -68,7 +68,7 @@ function statistics_exit() {
   }
   if ((variable_get('statistics_enable_access_log', 0)) && (module_invoke('throttle', 'status') == 0)) {
     // Log this page access.
-    db_query("INSERT INTO {accesslog} (title, path, url, hostname, uid, sid, timer, timestamp) values('%s', '%s', '%s', '%s', %d, '%s', %d, %d)", strip_tags(drupal_get_title()), $_GET['q'], referer_uri(), $_SERVER['REMOTE_ADDR'], $user->uid, session_id(), timer_read('page'), time());
+    db_query("INSERT INTO {accesslog} (title, path, url, hostname, uid, sid, timer, timestamp) values('%s', '%s', '%s', '%s', %d, '%s', %d, %d)", strip_tags(drupal_get_title()), $_GET['q'], referer_uri(), ip_address(), $user->uid, session_id(), timer_read('page'), time());
   }
 }
 
Index: modules/system/system.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.module,v
retrieving revision 1.478
diff -u -F^f -r1.478 system.module
--- modules/system/system.module	17 May 2007 07:28:42 -0000	1.478
+++ modules/system/system.module	17 May 2007 13:54:25 -0000
@@ -757,6 +757,19 @@ function system_performance_settings() {
     '#description' => t("Some Drupal modules include their own CSS files. When these modules are enabled, each module's CSS file adds an additional HTTP request to the page, which can increase the load time of each page. These HTTP requests can also slightly increase server load. It is recommended to only turn this option on when your site is in production, as it can interfere with theme development. This option is disabled if you have not set up your files directory, or if your download method is set to private."),
   );
 
+  $form['reverse_proxy'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Reverse proxy'),
+    '#description' => t('Is Drupal running behind a reverse proxy?')
+  );
+
+  $form['reverse_proxy']['reverse_proxy'] = array(
+    '#type' => 'radios',
+    '#title' => t('Reverse proxy'),
+    '#default_value' => variable_get('reverse_proxy', FALSE),
+    '#options' => array(t('Disabled'), t('Enabled')),
+    '#description' => t('If Drupal is running to be behind a reverse proxy, enabled this setting. For example, if you have Squid installed, the IP addresses will not be correct in many part of Drupal, including watchdog, poll, statistics and comments. Enabling this setting will cause Drupal to use the X-Forwarded-For headers provided by the reverse proxy.'),
+  );
   $form['#submit'][] = 'system_settings_form_submit';
   $form['#submit'][] = 'drupal_clear_css_cache';
 
