A[plug](https://github.com/elixir-lang/plug) to overwrite the [`Conn`'s](https://hexdocs.pm/plug/Plug.Conn.html) `remote_ip` based on headers such as `X-Forwarded-For`.
IPsareprocessedlast-to-firsttopreventIPspoofing,asthoroughlyexplainedin[ablogpost](http://blog.gingerlime.com/2012/rails-ip-spoofing-vulnerabilities-and-protection/) by [@gingerlime](https://github.com/gingerlime). Loopback/private IPs are always ignored and known proxies are configurable, so neither type will be erroneously treated as the original client IP. You can configure any number of arbitrary forwarding headers to use. If there's a special way to parse your particular header, the architecture of this project should [make it easy](#contributing) to open a pull request so `RemoteIp` can accommodate.
Notethat,duetolimitationsinthe[inet_cidr](https://github.com/Cobenian/inet_cidr) library used to parse them, `:proxies` **must** be written in full CIDR notation, even if specifying just a single IP. So instead of `"127.0.0.1"` and `"a:b::c:d"`, you would use `"127.0.0.1/32"` and `"a:b::c:d/128"`.
[Proxies](https://en.wikipedia.org/wiki/Proxy_server) are pervasive for some purpose or another in modern HTTP infrastructure: encryption, load balancing, caching, compression, and more can be done via proxies. But a proxy makes HTTP requests appear to your app as if they came from the proxy's IP address. How is your app to know the "actual" requesting IP address (e.g., so you can geolocate a user)?
**Solution:**ManyproxiespreventthisinformationlossbyaddingHTTPheaderstocommunicatetherequestingclient'sIPaddress.Thereisnosingle,universalheader.Though[`X-Forwarded-For`](https://en.wikipedia.org/wiki/X-Forwarded-For) is common, options include [`X-Real-IP`](http://nginx.org/en/docs/http/ngx_http_realip_module.html), [`X-Client-IP`](http://httpd.apache.org/docs/trunk/mod/mod_remoteip.html), and [others](http://stackoverflow.com/a/916157). Due to this lack of standardization, [RFC 7239](https://tools.ietf.org/html/rfc7239) defines the `Forwarded` header, fulfilling a [relevant XKCD truism](https://xkcd.com/927).
Notethatthefieldis_meant_tobeoverwritten.Plugdoesnotactuallydoanyoverwritingitself.The[Cowboychangelog](https://github.com/ninenines/cowboy/blob/master/CHANGELOG.md#084) espouses a similar platform of non-involvement:
**Solution:**Asdefinitivelyverifiedin[elixir-lang/plug#319](https://github.com/elixir-lang/plug/issues/319), users are intended to hand-roll their own header parsers.
###Problem:Ain'tnobodygottimeforthat.
**Solution:**Thereareahandfulofplugsavailableon[Hex](https://hex.pm). There are also the comments left in the [elixir-lang/plug#319](https://github.com/elixir-lang/plug/issues/319) thread that may give you some ideas, but I consider them to be non-starters - copying/pasting code from github comments isn't much better than hand-rolling an implementation.
|[plug_cloudflare](https://hex.pm/packages/plug_cloudflare) | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_minus_sign: | Just for `CF-Connecting-IP`, not really a general purpose library |
|[plug_forwarded_peer](https://hex.pm/packages/plug_forwarded_peer) | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | Only parses `Forwarded` and `X-Forwarded-For`, `X-Forwarded-For` takes precedence over `Forwarded`, does not parse all of RFC 7239's supported syntax correctly, vulnerable to IP spoofing |
|[plug_x_forwarded_for](https://hex.pm/packages/plug_x_forwarded_for) | :heavy_minus_sign: | :heavy_multiplication_x: | :heavy_multiplication_x: | Can only configure one header, all headers parsed the same as `X-Forwarded-For`, vulnerable to IP spoofing |
|[remote_ip_rewriter](https://hex.pm/packages/remote_ip_rewriter) | :heavy_multiplication_x: | :heavy_minus_sign: | :heavy_check_mark: | Only parses `X-Forwarded-For`, recognizes private/loopback IPs but known proxies are not configurable |
Afterselectingtheallowedheaders,eachstringisparsedforitsIPaddresses(eachIPaddressbeingthe[tuplereturnedby`:inet`functions](http://erlang.org/doc/man/inet.html#type-ip_address)). Each type of header may be parsed in a different way. For instance, `Forwarded` has a key-value pair format specified by RFC 7239, whereas `X-Forwarded-For` contains a comma-separate list of IPs.
To[preventIPspoofing](http://blog.gingerlime.com/2012/rails-ip-spoofing-vulnerabilities-and-protection/), IPs are processed right-to-left. You can think of it as working backwards through the chain of hops:
Notonlyareknownproxies'headerstrusted,butalsorequestsforwardedfor[loopback](https://en.wikipedia.org/wiki/Loopback) and [private](https://en.wikipedia.org/wiki/Private_network) IPs, namely:
3.Inthisnewmodule,exportthefunction`parse/1`thattakesinthestringvalueofasingleheaderandreturnsalistof0ormoreIPaddressesparsedfromthatvalue.Youshoulduse[`:inet.parse_strict_address/1`](http://erlang.org/doc/man/inet.html#parse_strict_address-1) or related functions to do the "dirty work" of parsing the actual IP values. The `parse/1` function is just to find the IPs buried within the string.