# `Macaw.Plug.ClientIp`
[🔗](https://github.com/dcoai/macaw_plug/blob/v0.1.4/lib/macaw/plug/client_ip.ex#L1)

The client's address behind trusted proxies.

When the connection's peer is a trusted proxy, the client is the right-most
`X-Forwarded-For` entry that is not itself a trusted proxy; entries to its
left could have been written by the client. Otherwise the client is the
peer, and the header is ignored. The plug sets `conn.remote_ip` to the
client, so logging, rate limits and everything downstream key on the right
address, and keeps the socket peer in `conn.private.macaw_plug_peer`.

    plug Macaw.Plug.ClientIp, trusted_proxies: ["10.0.0.0/8", "fd00::/8"]

**Trusted proxies default to none.** With none trusted, every client is its
peer: behind a reverse proxy that means every visitor looks like the
proxy, which is wrong but never spoofable. The `:trusted_proxies` option
takes CIDRs or single addresses, or `{module, function, args}` returning
them, called on every request, for a list that changes at runtime. A
malformed entry raises at `init/1`, naming it.

**A forwarded request from an untrusted peer** (it sent `X-Forwarded-For`,
but its address isn't trusted) is served as usual, with the header
ignored, and emits the telemetry event
`[:macaw_plug, :client_ip, :untrusted_forward]` with the peer in its
metadata. It usually means a proxy in front of the app is missing from
the trusted list. `attach_default_logger/1` logs it at most once per
interval.

# `attach_default_logger`

```elixir
@spec attach_default_logger(pos_integer()) :: :ok | {:error, :already_exists}
```

Logs an untrusted forward, and a bad entry in a dynamic trusted-proxy
list, each at most once per `interval_ms` (default one minute) on this
node. Returns the telemetry handler's attach result.

# `forwarded_for`

```elixir
@spec forwarded_for(Plug.Conn.t()) :: [String.t()]
```

The `X-Forwarded-For` entries of a request, left to right.

# `peer`

```elixir
@spec peer(Plug.Conn.t()) :: Macaw.Plug.Ip.ip()
```

The socket peer of a request this plug has run on, else its `remote_ip`.

# `resolve`

```elixir
@spec resolve(Macaw.Plug.Ip.ip(), [String.t()], [Macaw.Plug.Ip.cidr()]) ::
  Macaw.Plug.Ip.ip()
```

The client address for a peer, its `X-Forwarded-For` entries (left to
right, as sent) and the trusted CIDRs.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
