Suscriber IP address

Rob

Active Member
Hi

I have MW installed beehind a load balancer which uses the X-FORWARDED-FOR Header to pass on the real IP of any traffic.

This is working fine in my apache logs.

However in my customer/lists/xxxxx/subscribers area the IP displayed is the load balancer IP for all subscribers. Where in the code does MW pick up the IP and can it be changed?

Thanks

Rob
 

twisted1919

Administrator
Staff member
Hey Rob,

Have a look in apps/common/components/helpers/AppInitHelper.php in the fixRemoteAddress() method.

Thanks.
 
  • Like
Reactions: Rob

Rob

Active Member
Hi

Having searched around to find the best way to do this I came across this article http://stackoverflow.com/questions/...to-retrieve-a-users-correct-ip-address-in-php


I've tried to get this to work within the file you mention but with no luck, how would you insert it if it is possible?
PHP:
/**
  * Retrieves the best guess of the client's actual IP address.
  * Takes into account numerous HTTP proxy headers due to variations
  * in how different ISPs handle IP addresses in headers between hops.
  */
public function get_ip_address() {
  // Check for shared internet/ISP IP
  if (!empty($_SERVER['HTTP_CLIENT_IP']) && $this->validate_ip($_SERVER['HTTP_CLIENT_IP']))
   return $_SERVER['HTTP_CLIENT_IP'];

  // Check for IPs passing through proxies
  if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
   // Check if multiple IP addresses exist in var
    $iplist = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
    foreach ($iplist as $ip) {
     if ($this->validate_ip($ip))
      return $ip;
    }
   }
  }
  if (!empty($_SERVER['HTTP_X_FORWARDED']) && $this->validate_ip($_SERVER['HTTP_X_FORWARDED']))
   return $_SERVER['HTTP_X_FORWARDED'];
  if (!empty($_SERVER['HTTP_X_CLUSTER_CLIENT_IP']) && $this->validate_ip($_SERVER['HTTP_X_CLUSTER_CLIENT_IP']))
   return $_SERVER['HTTP_X_CLUSTER_CLIENT_IP'];
  if (!empty($_SERVER['HTTP_FORWARDED_FOR']) && $this->validate_ip($_SERVER['HTTP_FORWARDED_FOR']))
   return $_SERVER['HTTP_FORWARDED_FOR'];
  if (!empty($_SERVER['HTTP_FORWARDED']) && $this->validate_ip($_SERVER['HTTP_FORWARDED']))
   return $_SERVER['HTTP_FORWARDED'];

  // Return unreliable IP address since all else failed
  return $_SERVER['REMOTE_ADDR'];
}

/**
  * Ensures an IP address is both a valid IP address and does not fall within
  * a private network range.
  *
  * @access public
  * @param string $ip
  */
public function validate_ip($ip) {
     if (filter_var($ip, FILTER_VALIDATE_IP,
                         FILTER_FLAG_IPV4 |
                         FILTER_FLAG_IPV6 |
                         FILTER_FLAG_NO_PRIV_RANGE |
                         FILTER_FLAG_NO_RES_RANGE) === false)
         return false;
     self::$ip = $ip;
     return true;
}
Cheers

Rob
 
Last edited by a moderator:

twisted1919

Administrator
Staff member
How about you try:
PHP:
/**
     * AppInitHelper::fixRemoteAddress()
     *
     * @return
     */
    public static function fixRemoteAddress()
    {
        static $hasRan = false;
        if ($hasRan) {
            return;
        }
        $hasRan = true;
      
        // keep a reference
        $_SERVER['ORIGINAL_REMOTE_ADDR'] = $_SERVER['REMOTE_ADDR'];
      
        $keys = array(
            'HTTP_CF_CONNECTING_IP', 'HTTP_CLIENT_IP', 'HTTP_X_REAL_IP', 'HTTP_X_FORWARDED_FOR',
            'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED'
        );
      
        foreach ($keys as $key) {
            if (empty($_SERVER[$key])) {
                continue;
            }
            $ips = explode(',', $_SERVER[$key]);
            foreach ($ips as $ip) {
                if (self::isValidIp($ip)) {
                    return $_SERVER['REMOTE_ADDR'] = $ip;
                }
            }
        }
    }
  
    /**
     * AppInitHelper::isValidIp()
     *
     * @param string $ip
     * @return bool
     */
    public static function isValidIp($ip)
    {
        return filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE);
    }
 
  • Like
Reactions: Rob

twisted1919

Administrator
Staff member
P.S: In same file, just replace the existing fixRemoteAddress() method with these block of code (this is actually two separate methods)
 

Rob

Active Member
Hi

Thanks for the code, when I use that code I get the following error when going to /customer/campaigns/index

Cheers

Rob

17:23:51.962543 error php
reset() expects parameter 1 to be array, string given
(/var/www/html/apps/common/framework/db/schema/CDbCriteria.php:321)
Stack trace:
#0 /var/www/html/apps/customer/views/campaigns/index.php(95):
Campaign->getGroupsDropDownArray()
#1 /var/www/html/apps/common/framework/web/CBaseController.php(126):
require()
#2 /var/www/html/apps/common/components/web/BaseController.php(245):
CampaignsController->renderInternal()
#3 /var/www/html/apps/common/framework/web/CBaseController.php(95):
CampaignsController->renderInternal()
#4 /var/www/html/apps/common/framework/web/CController.php(869):
CampaignsController->renderFile()
#5 /var/www/html/apps/common/framework/web/CController.php(782):
CampaignsController->renderPartial()
#6 /var/www/html/apps/customer/controllers/CampaignsController.php(66):
CampaignsController->render()
#7 /var/www/html/apps/common/framework/web/actions/CInlineAction.php(49):
CampaignsController->actionIndex()
#8 /var/www/html/apps/common/framework/web/CController.php(308):
CInlineAction->runWithParams()
#9 /var/www/html/apps/common/framework/web/filters/CFilterChain.php(133):
CampaignsController->runAction()
#10 /var/www/html/apps/common/framework/web/CController.php(291):
CFilterChain->run()
#11 /var/www/html/apps/common/framework/web/CController.php(265):
CampaignsController->runActionWithFilters()
#12 /var/www/html/apps/common/framework/web/CWebApplication.php(282):
CampaignsController->run()
#13 /var/www/html/apps/common/framework/web/CWebApplication.php(141):
CWebApplication->runController()
#14 /var/www/html/apps/common/framework/base/CApplication.php(184):
CWebApplication->processRequest()
#15 /var/www/html/apps/init.php(196): CWebApplication->run()
#16 /var/www/html/customer/index.php(18): require_once()
REQUEST_URI=/customer/campaigns/index
in /var/www/html/apps/common/models/Campaign.php (706)
in /var/www/html/apps/customer/views/campaigns/index.php (95)
in /var/www/html/apps/common/components/web/BaseController.php (245)
 

twisted1919

Administrator
Staff member
That error isn't actually related to our changes, it's a bug.
here's how that method inside apps/common/models/Campaign.php should look like:
PHP:
public function getGroupsDropDownArray()
    {
        static $_options = array();
        if (!empty($_options)) {
            return $_options;
        }
       
        $criteria = new CDbCriteria();
        $criteria->compare('customer_id', (int)$this->customer_id);
        $criteria->order = 'group_id DESC';
        $models = CampaignGroup::model()->findAll($criteria);
       
        foreach ($models as $model) {
            $criteria = new CDbCriteria();
            $criteria->compare('group_id', (int)$model->group_id);
            $criteria->addNotInCondition('status', array(self::STATUS_PENDING_DELETE));
            $count = Campaign::model()->count($criteria);
           
            $_options[$model->group_id] = $model->name . ' ('. Yii::t('campaigns', '{campaignsCount} campaigns', array(
                '{campaignsCount}' => Yii::app()->format->formatNumber($count)
            )).')';
        }
       
        return $_options;
    }
 
  • Like
Reactions: Rob

Rob

Active Member
Cheers @twisted1919 all sorted. The code for fixRemoteaddress() has now made the locatorhq extension work correctly as well.

Cheers

Rob
 
Top