Utilities for extracting and formatting IP addresses.
Supports both IPv4 and IPv6 addresses with proper error handling. Prevents Protocol.UndefinedError when working with IPv6 tuples.
Usage
Extract from LiveView socket:
ip = PhoenixKit.Utils.IpAddress.extract_from_socket(socket)Extract from Plug.Conn:
ip = PhoenixKit.Utils.IpAddress.extract_from_conn(conn)Extract from peer_data directly:
ip = PhoenixKit.Utils.IpAddress.extract_ip_address(%{address: {192, 168, 1, 1}})Examples
iex> PhoenixKit.Utils.IpAddress.extract_ip_address(%{address: {192, 168, 1, 1}})
"192.168.1.1"
iex> PhoenixKit.Utils.IpAddress.extract_ip_address(%{address: {8193, 3512, 1, 0, 0, 0, 0, 1}})
"8193:3512:1:0:0:0:0:1"
iex> PhoenixKit.Utils.IpAddress.extract_ip_address(nil)
"unknown"
iex> PhoenixKit.Utils.IpAddress.extract_ip_address(%{})
"unknown"
Summary
Functions
The visitor's address as best a site behind a reverse proxy can tell.
The visitor's address as a LiveView socket knows it — or nil when the socket cannot tell.
Extracts the visitor's IP address from a Plug.Conn.
Extracts the visitor's IP address from a Phoenix.LiveView socket.
Extracts IP address from peer_data map.
Functions
@spec client_address(Plug.Conn.t()) :: String.t() | nil
The visitor's address as best a site behind a reverse proxy can tell.
extract_from_conn/1 answers the TCP peer, which behind nginx (or in a
container) is the proxy's own address for every visitor. This one takes
conn.remote_ip (which a host's RemoteIp plug already rewrites) and, when
that is a loopback or private address — a proxy on the same box or the
same network — the LAST entry of x-forwarded-for, the one that proxy
appended (a visitor can send their own header; they cannot control what
nginx appends after it), then x-real-ip. A public remote_ip is trusted
as is. Returns nil when nothing is known.
iex> conn = %Plug.Conn{remote_ip: {127, 0, 0, 1}, req_headers: [{"x-forwarded-for", "9.9.9.9, 203.0.113.7"}]}
iex> PhoenixKit.Utils.IpAddress.client_address(conn)
"203.0.113.7"
@spec client_address_from_socket(Phoenix.LiveView.Socket.t()) :: String.t() | nil
The visitor's address as a LiveView socket knows it — or nil when the socket cannot tell.
From the connect info the endpoint passes: a public :peer_data address
is the visitor; a loopback or private one is a proxy, and only the
forwarded address in :x_headers (x-forwarded-for, x-real-ip) names
the visitor then. An endpoint that passes no :x_headers — core's
installed endpoint passes :peer_data only — leaves a proxied socket
with no answer, and nil is that answer: the caller must not treat the
proxy as the visitor.
Extracts the visitor's IP address from a Plug.Conn.
Proxy-aware: delegates to client_address/1, which reads x-forwarded-for
/ x-real-ip when conn.remote_ip is a loopback or private address (a
reverse proxy on the same box or network), and trusts a public
conn.remote_ip as-is.
Parameters
conn: Plug.Conn struct
Returns
- IP address string or "unknown" (never nil — callers that need to tell
"known" apart from "unknown" should call
client_address/1directly)
Extracts the visitor's IP address from a Phoenix.LiveView socket.
Proxy-aware: delegates to client_address_from_socket/1, which reads the
connect info's :x_headers when the socket's :peer_data is a loopback
or private address, and trusts a public :peer_data address as-is.
Parameters
socket: Phoenix.LiveView.Socket struct
Returns
- IP address string or "unknown" (never nil — callers that need to tell
"known" apart from "unknown" should call
client_address_from_socket/1directly). "unknown" also covers a host endpoint that never declared:peer_datain the socket'sconnect_info— see that function's docs.
Extracts IP address from peer_data map.
Handles both IPv4 (4-tuple) and IPv6 (8-tuple) addresses. Returns "unknown" for nil, invalid, or missing data.
Parameters
peer_data: Map with:addresskey containing IP tuple, or nil
Returns
- IPv4 as "a.b.c.d" string
- IPv6 as "a:b:c:d:e:f:g:h" string
- "unknown" for invalid or missing data