Limen.IP (limen v0.2.1)

Copy Markdown View Source

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

cidr_set()

@type cidr_set() :: %{
  lengths: %{optional(version()) => [0..128]},
  members: %{
    optional({version(), 0..128}) => %{optional(non_neg_integer()) => true}
  }
}

prefix()

@type prefix() :: {version(), non_neg_integer(), 0..128}

version()

@type version() :: 4 | 6

Functions

cidr_set(ranges)

@spec cidr_set([String.t() | prefix()]) :: cidr_set()

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.

from_integer(arg)

@spec from_integer({version(), non_neg_integer()}) :: :inet.ip_address()

Converts {version, integer} back to an address tuple.

is_ip(ip)

(macro)

Whether a value looks like an address tuple.

member?(arg1, ip)

@spec member?(cidr_set(), :inet.ip_address() | nil) :: boolean()

Returns whether ip falls within any range of a cidr_set/1.

parse(string)

@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

parse_cidr(string)

@spec parse_cidr(String.t()) :: {:ok, prefix()} | :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

prefix(ip, v4_length, v6_length)

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

prefix_to_binary(arg1)

@spec prefix_to_binary(prefix() | nil) :: binary()

A compact binary encoding of a prefix, used when binding tokens to a client.

prefix_to_string(arg)

@spec prefix_to_string(prefix()) :: String.t()

Renders a prefix in CIDR notation.

iex> Limen.IP.prefix_to_string({4, 3221225984, 24})
"192.0.2.0/24"

to_integer(arg)

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