# `PhoenixKit.Utils.PublicAddress`
[🔗](https://github.com/BeamLabEU/phoenix_kit/blob/v2.55.1/lib/phoenix_kit/utils/public_address.ex#L1)

Whether an IP address is a globally routable unicast address — the only
kind a server-side fetch of a user-supplied URL may connect to.

Everything in the IANA special-purpose registries is refused: loopback,
private (RFC 1918 and unique-local), link-local (which includes the cloud
metadata address 169.254.169.254), carrier-grade NAT, "this network",
documentation and benchmarking ranges, multicast, reserved space, and the
IPv6 forms that smuggle an IPv4 address (IPv4-mapped, IPv4-compatible,
NAT64, 6to4, Teredo). Listing what is *not* public is how the registries
themselves are organised; an address in none of these ranges is public.

A network can add its own: an IPv6-only host behind a NAT64 gateway with a
network-specific prefix (not `64:ff9b::/96`) sees every IPv4 address,
internal ones included, as a global-looking IPv6 address under that
prefix. List it, and anything else local to the network, in

    config :phoenix_kit, :blocked_ip_ranges, ["2a00:abcd:1234:5678::/96"]

(CIDR strings; an unparsable entry is ignored).

# `ip`

```elixir
@type ip() :: :inet.ip_address()
```

# `public?`

```elixir
@spec public?(ip() | String.t()) :: boolean()
```

Whether `ip` (a tuple or a string) is a public unicast address.

# `resolve_public`

```elixir
@spec resolve_public(String.t()) :: {:ok, ip()} | {:error, :blocked_host | :nxdomain}
```

Resolves `host` and returns `{:ok, ip}` — an address to connect to — only
when EVERY address it resolves to is public, so a name with one public
and one internal record cannot be used to reach the internal one.
A literal IP is checked as it is.

---

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