class Sentry::Utils::RealIp

def calculate_ip

def calculate_ip
  # CGI environment variable set by Rack
  remote_addr = ips_from(@remote_addr).last
  # Could be a CSV list and/or repeated headers that were concatenated.
  client_ips    = ips_from(@client_ip)
  real_ips      = ips_from(@real_ip)
  # The first address in this list is the original client, followed by
  # the IPs of successive proxies. We want to search starting from the end
  # until we find the first proxy that we do not trust.
  forwarded_ips = ips_from(@forwarded_for).reverse
  ips = [client_ips, real_ips, forwarded_ips, remote_addr].flatten.compact
  # If every single IP option is in the trusted list, just return REMOTE_ADDR
  @ip = filter_trusted_proxy_addresses(ips).first || remote_addr
end

def filter_trusted_proxy_addresses(ips)

def filter_trusted_proxy_addresses(ips)
  ips.reject { |ip| @trusted_proxies.any? { |proxy| proxy === ip } }
end

def initialize(

def initialize(
  remote_addr: nil,
  client_ip: nil,
  real_ip: nil,
  forwarded_for: nil,
  trusted_proxies: []
)
  @remote_addr = remote_addr
  @client_ip = client_ip
  @real_ip = real_ip
  @forwarded_for = forwarded_for
  @trusted_proxies = (LOCAL_ADDRESSES + Array(trusted_proxies)).map do |proxy|
    if proxy.is_a?(IPAddr)
      proxy
    else
      IPAddr.new(proxy.to_s)
    end
  end.uniq
end

def ips_from(header)

def ips_from(header)
  # Split the comma-separated list into an array of strings
  ips = header ? header.strip.split(/[,\s]+/) : []
  ips.select do |ip|
    begin
      # Only return IPs that are valid according to the IPAddr#new method
      range = IPAddr.new(ip).to_range
      # we want to make sure nobody is sneaking a netmask in
      range.begin == range.end
    rescue ArgumentError
      nil
    end
  end
end