Shun.Rule.Target (Shun v1.0.2) View Source

Encapsulates target classification logic used by Shun.Rule to interpret target patterns.

All Rules are built with Targets, which are usually quoted patterns when the relevant generator functions are being used from macros, such as ones in Shun.Builder. These can represent URIs, IPv4 or IPv6 addresses, CIDR blocks, or single IP addresses.

Unquoted 4-arity / 8-arity tuples, String literals, and URI structs are also valid. This is to aid creation of Preset modules, which implement Shun.Preset and must return valid lists of Shun.Rule.t/0.

The following forms of Targets, for example, are valid:

  • {192, 168, 1, 1}, which represents an IPv4 Address at 192.168.1.1.
  • {10, _, _, _}, which represents an IPv4 Address at 10.x.x.x.
  • {_, _, _, _}, which represents any IPv4 Address.

IPv6 addresses, represented as 8-arity tuples, are also valid:

  • {0, 0, 0, 0, 0, 0, 0, 1}, which represents an IPv6 loopback address.
  • {0x8bad, 0xf00d, _, _, _, _, _, _}, which represents another IPv6 address.
  • {_, _, _, _, _, _, _, _}, which represents any IPv6 address.

Patterns that match URI structs can also be used as Targets:

  • %URI{scheme: "https"}
  • %URI{scheme: "https", host: "example.com", path: "/admin"}
  • %URI{scheme: "https", host: "example.com", path: "/books/" <> _}

Lastly, Strings that represent IP Addresses or CIDR blocks can be used as Targets:

  • 192.168.1.1
  • 192.168.100.14/24
  • 2002::1234:abcd:ffff:c0a8:101/64

Strings that are URLs are not accepted; for these purposes you should build URI patterns. This is to ensure that whenever a string literal is used, it represents an IPv4 or IPv6 address, or IPv4 / IPv6 CIDR literal.

Alternatively, for example when building a new Preset, you can pass an URI struct as a Target, which will be compiled down to a pattern that matches the non-nil keys of that URI struct.

Specifically:

iex(1)> lhs = Shun.Rule.reject(%URI{host: "169.254.169.254"}).pattern
iex(2)> {:%, [], [{:__aliases__, _, [:URI]}, {:%{}, [], [host: "169.254.169.254"]}]} = lhs

iex(1)> rhs = quote do: %URI{host: "169.254.169.254"}
iex(2)> {:%, [], [{:__aliases__, _, [:URI]}, {:%{}, [], [host: "169.254.169.254"]}]} = rhs

Guards

When the Rule is given a Target in the form of an Elixir pattern, guards can be used.

For Rules based on URIs, this is a great way to enforce hosts or schemes; for Rules based on IPv4 or IPv6 patterns, this is an alternative to specifying CIDR ranges.

The following Target forms with guard clauses, for example, are valid:

  • {a, _, _, _} when a == 10
  • {a, b, _, _} when a < b
  • {a, b, _, _} when (a * (b + c)) > 10
  • {a, _, _, _, _, _, _, _} when a >= 0xfe80 and a <= 0xfebf
  • %URI{host: "example.com", path: "/books/" <> _} when scheme != "ftp"

Link to this section Summary

Types

Represents an AST fragment to be reintegrated as guard.

Represents an AST fragment to be reintegrated as match pattern.

t()

Represents a Target which can be used with one of the functions that builds a Rule.

Link to this section Types

Specs

guard() :: Macro.t()

Represents an AST fragment to be reintegrated as guard.

Specs

pattern() :: Macro.t()

Represents an AST fragment to be reintegrated as match pattern.

Specs

result() ::
  {:pattern, type :: :ipv4 | :ipv6 | :uri}
  | {:pattern, type :: :ipv4 | :ipv6 | :uri, pattern()}
  | {:pattern, type :: :ipv4 | :ipv6 | :uri, pattern(), guard()}
  | {:range, :ipv4, from :: Shun.Address.value_ipv4(),
     to :: Shun.Address.value_ipv4()}
  | {:range, :ipv6, from :: Shun.Address.value_ipv6(),
     to :: Shun.Address.value_ipv6()}

Specs

t() :: String.t() | URI.t() | Macro.t()

Represents a Target which can be used with one of the functions that builds a Rule.

Link to this section Functions