grapeとか使ってアレレ?ってなったのでまとめました。
request.remote_ip method in rails
action_dispatch.remote_ip、なかったらipを引っ張る。
# File actionpack/lib/action_dispatch/http/request.rb, line 230
def remote_ip
@remote_ip ||= (@env["action_dispatch.remote_ip"] || ip).to_s
end
grapeとか組み合わせる時以外はaction_dispatch.remote_ipが無いなんてことはないんじゃないだろうか。
とりあえずip側から調べます。
request#ip
# File actionpack/lib/action_dispatch/http/request.rb, line 225
def ip
@ip ||= super
end
rackのipをcallするだけ。rack側ではこんな感じで
def ip
remote_addrs = split_ip_addresses(@env['REMOTE_ADDR'])
remote_addrs = reject_trusted_ip_addresses(remote_addrs)
return remote_addrs.first if remote_addrs.any?
forwarded_ips = split_ip_addresses(@env['HTTP_X_FORWARDED_FOR'])
return reject_trusted_ip_addresses(forwarded_ips).last || @env["REMOTE_ADDR"]
end
def trusted_proxy?(ip)
ip =~ /\A127\.0\.0\.1\Z|\A(10|172\.(1[6-9]|2[0-9]|30|31)|192\.168)\.|\A::1\Z|\Afd[0-9a-f]{2}:.+|\Alocalhost\Z|\Aunix\Z|\Aunix:/i
end
protected
def reject_trusted_ip_addresses(ip_addresses)
ip_addresses.reject { |ip| trusted_proxy?(ip) }
end
- REMOTE_ADDRをみてlocal系を省いて、IP残ってたらそれ返す。
- そうじゃなかったらHTTP_X_FORWARDED_FORをみて一番最初のものをみる。
これだけなのね、シンプル。
action_dispatch.remote_ip
こっち側はちょっと複雑でこんな感じ
def calculate_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 && forwarded_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
REMOTE_ADDR、
- HTTP_X_FORWARDED_FORのリバース、HTTP_CLIENT_IPのリバース、REMOTE_ADDRの順で配列作って
- rack側と同じようにtrustedなアドレスを取り除いて
- 最初の返す
- REMOTE_ADDRをそのまま返す
ほとんど同じですね。
ipとremote_ipの違いは?
違いとしては二つ
- HTTP_CLIENT_IPをIPアドレス選択のヒエラルキーに含むことができる。
- trustedなアドレスリストをカスタムできる
1. HTTP_CLIENT_IP
うーむ。そもそもHTTP_CLIENT_IPとHTTP_X_FORWARDED_FORの違いってなんなの?って思って調べたらまさにそのまま。
超意訳すると
- 実装の違いで同じ意味
- 値が違うのは、HTTP_X_FORWARDED_FORはproxyされたip全部トラッキングするけど、clinet_ipは1個しか入れないからだね。
とするとこれは別に嬉しくない気がする。
2. trustedなアドレスリストをカスタム
これがすごい嬉しいかというと、どうなのだろう。よく分からない。