Help us understand the problem. What is going on with this article?

railsにおけるremote_ipって何が嬉しいのだろうか?

grapeとか使ってアレレ?ってなったのでまとめました。

request.remote_ip method in rails

action_dispatch.remote_ip、なかったらipを引っ張る。

https://github.com/rails/rails/blob/e595d91ac2c07371b441f8b04781e7c03ac44135/actionpack/lib/action_dispatch/http/request.rb#L230

# 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側ではこんな感じで

https://github.com/rack/rack/blob/master/lib/rack/request.rb#L354

    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

  1. REMOTE_ADDRをみてlocal系を省いて、IP残ってたらそれ返す。
  2. そうじゃなかったらHTTP_X_FORWARDED_FORをみて一番最初のものをみる。

これだけなのね、シンプル。

action_dispatch.remote_ip

こっち側はちょっと複雑でこんな感じ

https://github.com/rails/rails/blob/a59a9b7f729870de6c9282bd8e2a7ed7f86fc868/actionpack/lib/action_dispatch/middleware/remote_ip.rb#L109

      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、
1. HTTP_X_FORWARDED_FORのリバース、HTTP_CLIENT_IPのリバース、REMOTE_ADDRの順で配列作って
2. rack側と同じようにtrustedなアドレスを取り除いて
- https://github.com/rails/rails/blob/a59a9b7f729870de6c9282bd8e2a7ed7f86fc868/actionpack/lib/action_dispatch/middleware/remote_ip.rb#L33
3. 最初の返す
4. REMOTE_ADDRをそのまま返す

ほとんど同じですね。

ipとremote_ipの違いは?

違いとしては二つ

  1. HTTP_CLIENT_IPをIPアドレス選択のヒエラルキーに含むことができる。
  2. trustedなアドレスリストをカスタムできる

1. HTTP_CLIENT_IP

うーむ。そもそもHTTP_CLIENT_IPとHTTP_X_FORWARDED_FORの違いってなんなの?って思って調べたらまさにそのまま。

http://stackoverflow.com/questions/7445592/what-is-the-difference-between-http-client-ip-and-http-x-forwarded-for

超意訳すると

  1. 実装の違いで同じ意味
  2. 値が違うのは、HTTP_X_FORWARDED_FORはproxyされたip全部トラッキングするけど、clinet_ipは1個しか入れないからだね。

とするとこれは別に嬉しくない気がする。

2. trustedなアドレスリストをカスタム

これがすごい嬉しいかというと、どうなのだろう。よく分からない。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away