PhoenixKit.Utils.IpAddress (phoenix_kit v2.22.16)

Copy Markdown View Source

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

client_address(conn)

@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"

client_address_from_socket(socket)

@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.

extract_from_conn(conn)

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/1 directly)

extract_from_socket(socket)

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/1 directly). "unknown" also covers a host endpoint that never declared :peer_data in the socket's connect_info — see that function's docs.

extract_ip_address(arg1)

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 :address key 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