remote_ip v0.2.1 RemoteIp View Source
A plug to overwrite the Plug.Conn's remote_ip based on request headers.
To use, add the RemoteIp plug to your app's plug pipeline:
defmodule MyApp do
use Plug.Builder
plug RemoteIp
end
Keep in mind the order of plugs in your pipeline and place RemoteIp as
early as possible. For example, if you were to add RemoteIp afterthe
Plug Router, your route
action's logic would be executed before the remote_ip actually gets
modified - not very useful!
There are 3 options that can be passed in:
:headers- A list of strings naming thereq_headersto use when deriving theremote_ip. Order does not matter. Defaults to~w[forwarded x-forwarded-for x-client-ip x-real-ip].:proxies- A list of strings in CIDR notation specifying the IPs of known proxies. Defaults to[].Loopback and private IPs are always appended to this list:
- 127.0.0.0/8
- ::1/128
- fc00::/7
- 10.0.0.0/8
- 172.16.0.0/12
192.168.0.0/16
Since these IPs are internal, they often are not the actual client address in production, so we add them by default. To override this behavior, whitelist known client IPs using the
:clientsoption.
:clients- A list of strings in CIDR notation specifying the IPs of known clients. Defaults to[].An IP in any of the ranges listed here will never be considered a proxy. This takes precedence over the
:proxiesoption, including loopback/private addresses. Any IP that is not covered by:clientsor:proxiesis assumed to be a client IP.
For example, suppose you know:
- you are behind proxies in the 1.2.x.x block
- the proxies use the
X-Foo,X-Bar, andX-Bazheaders - but the IP 1.2.3.4 is actually a client, not one of the proxies
Then you could say
defmodule MyApp do
use Plug.Builder
plug RemoteIp,
headers: ~w[x-foo x-bar x-baz],
proxies: ~w[1.2.0.0/16],
clients: ~w[1.2.3.4/32]
end
Note that, due to limitations in the
inet_cidr library used to parse
them, :proxies and :clients 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".
For more details, refer to the README on GitHub.
Link to this section Summary
Functions
Callback implementation for Plug.call/2.
Standalone function to extract the remote IP from a list of headers.
Callback implementation for Plug.init/1.
Link to this section Functions
Callback implementation for Plug.call/2.
from(req_headers, opts \\ [])
View Sourcefrom([{String.t(), String.t()}], keyword()) :: :inet.ip_address() | nil
Standalone function to extract the remote IP from a list of headers.
It's possible to get a subset of headers without access to a full Plug.Conn
struct. For instance, when using Phoenix
sockets, your socket's
connect/3 callback may only be receiving :x_headers in the
connect_info. Such situations make it inconvenient to use RemoteIp
outside of a plug pipeline.
Therefore, this function will fetch the remote IP from a plain list of header
key-value pairs (just as you'd have in the req_headers of a Plug.Conn).
You may optionally specify the same options as if you were using RemoteIp
as a plug: they'll be processed by RemoteIp.init/1 each time you call this
function.
If a remote IP cannot be parsed from the given headers (e.g., if the list is
empty), this function will return nil.
Examples
iex> RemoteIp.from([{"x-forwarded-for", "1.2.3.4"}])
{1, 2, 3, 4}
iex> [{"x-foo", "1.2.3.4"}, {"x-bar", "2.3.4.5"}]
...> |> RemoteIp.from(headers: ~w[x-foo])
{1, 2, 3, 4}
iex> [{"x-foo", "1.2.3.4"}, {"x-bar", "2.3.4.5"}]
...> |> RemoteIp.from(headers: ~w[x-bar])
{2, 3, 4, 5}
iex> [{"x-foo", "1.2.3.4"}, {"x-bar", "2.3.4.5"}]
...> |> RemoteIp.from(headers: ~w[x-baz])
nil
Callback implementation for Plug.init/1.