defcalculate_ip # Set by the Rack web server, this is a single value. remote_addr = ips_from('REMOTE_ADDR').last
# Could be a CSV list and/or repeated headers that were concatenated. client_ips = ips_from('HTTP_CLIENT_IP').reverse forwarded_ips = ips_from('HTTP_X_FORWARDED_FOR').reverse
# +Client-Ip+ and +X-Forwarded-For+ should not, generally, both be set. # If they are both set, it means that this request passed through two # proxies with incompatible IP header conventions, and there is no way # for us to determine which header is the right one after the fact. # Since we have no idea, we give up and explode. should_check_ip = @check_ip && client_ips.last if should_check_ip && !forwarded_ips.include?(client_ips.last) # We don't know which came from the proxy, and which from the user raise IpSpoofAttackError, IP spoofing attack?! + HTTP_CLIENT_IP=#{@env['HTTP_CLIENT_IP'].inspect} + HTTP_X_FORWARDED_FOR=#{@env['HTTP_X_FORWARDED_FOR'].inspect} end
# We assume these things about the IP headers: # # - X-Forwarded-For will be a list of IPs, one per proxy, or blank # - Client-Ip is propagated from the outermost proxy, or is blank # - REMOTE_ADDR will be the IP that made the request to Rack ips = [forwarded_ips, client_ips, remote_addr].flatten.compact
# If every single IP option is in the trusted list, just return REMOTE_ADDR filter_proxies(ips).first || remote_addr end