IP address helpers: parsing, prefix aggregation and CIDR matching.
A prefix is the unit Limen keys state on. IPv4 addresses are aggregated to
/32 by default and IPv6 addresses to /64, since a single IPv6 subscriber
usually controls at least a /64. IPv4-mapped IPv6 addresses
(::ffff:a.b.c.d) are treated as IPv4.
Prefixes are represented as {version, masked_integer, length} tuples, which
are cheap to hash, compare and use as ETS keys.
Summary
Functions
Builds a set of CIDR ranges for fast membership checks.
Converts {version, integer} back to an address tuple.
Whether a value looks like an address tuple.
Returns whether ip falls within any range of a cidr_set/1.
Parses a textual IP address.
Parses CIDR notation. A bare address is a host prefix.
Aggregates an address into its prefix.
A compact binary encoding of a prefix, used when binding tokens to a client.
Renders a prefix in CIDR notation.
Converts an address tuple to {version, integer}.
Types
@type cidr_set() :: %{ lengths: %{optional(version()) => [0..128]}, members: %{ optional({version(), 0..128}) => %{optional(non_neg_integer()) => true} } }
@type prefix() :: {version(), non_neg_integer(), 0..128}
@type version() :: 4 | 6
Functions
Builds a set of CIDR ranges for fast membership checks.
Lookups cost one map probe per distinct prefix length in the set, so they
stay cheap for the handful of lengths real allow- and deny-lists contain.
Raises ArgumentError on an invalid range.
@spec from_integer({version(), non_neg_integer()}) :: :inet.ip_address()
Converts {version, integer} back to an address tuple.
Whether a value looks like an address tuple.
@spec member?(cidr_set(), :inet.ip_address() | nil) :: boolean()
Returns whether ip falls within any range of a cidr_set/1.
@spec parse(String.t()) :: {:ok, :inet.ip_address()} | :error
Parses a textual IP address.
iex> Limen.IP.parse("192.0.2.1")
{:ok, {192, 0, 2, 1}}
iex> Limen.IP.parse("not an ip")
:error
Parses CIDR notation. A bare address is a host prefix.
iex> Limen.IP.parse_cidr("10.0.0.0/8")
{:ok, {4, 167772160, 8}}
iex> Limen.IP.parse_cidr("10.0.0.0/33")
:error
@spec prefix(:inet.ip_address(), 0..32, 0..128) :: prefix()
Aggregates an address into its prefix.
iex> Limen.IP.prefix({192, 0, 2, 77}, 24, 64)
{4, 3221225984, 24}
iex> Limen.IP.prefix({0x2001, 0xDB8, 1, 2, 3, 4, 5, 6}, 32, 48)
{6, 42540766411283801782723599580828532736, 48}
A compact binary encoding of a prefix, used when binding tokens to a client.
Renders a prefix in CIDR notation.
iex> Limen.IP.prefix_to_string({4, 3221225984, 24})
"192.0.2.0/24"
@spec to_integer(:inet.ip_address()) :: {version(), non_neg_integer()}
Converts an address tuple to {version, integer}.
IPv4-mapped IPv6 addresses are converted to their IPv4 form.