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

```rb
# 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

```rb
# 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

```rb
    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

```rb
      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なアドレスリストをカスタムできる
	- https://github.com/rails/rails/blob/a59a9b7f729870de6c9282bd8e2a7ed7f86fc868/actionpack/lib/action_dispatch/middleware/remote_ip.rb#L66

### 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は１個しか入れないからだね。

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

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

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