View Source SafeURL.DNSResolver behaviour (SafeURL v0.3.1)
In some cases you might want to use a custom strategy
for DNS resolution. You can do so by passing your own
implementation of SafeURL.DNSResolver
in the global
or local config.
By default, the DNS
package is used for resolution,
but you can replace it with a wrapper that uses
different configuration or a completely different
implementation altogether.
Use-cases
- Using a specific DNS server
- Avoiding network access in specific environments
- Mocking DNS resolution in tests
Usage
Start by creating a module that implements the
DNSResolver
behaviour. Currently, this means adding
only one resolve/1
callback that takes a host and
returns a list of resolved IPs.
As an example, suppose you wanted to use
Cloudflare's DNS, you can do
that by wrapping DNS
with your own settings in a new
module:
defmodule CloudflareDNS do
@behaviour SafeURL.DNSResolver
@impl true
def resolve(domain) do
DNS.resolve(domain, :a, {"1.1.1.1", 53}, :udp)
end
end
To use it, simply pass it in the global config:
config :safeurl, dns_module: CloudflareDNS
You can also directly set the :dns_module
in method options:
SafeURL.allowed?("https://example.com", dns_module: CloudflareDNS)
Testing
This is especially useful in tests where you want to
ensure your HTTP Client wrapper with SafeURL
is
working as expected.
You can override the :dns_module
config to ensure
a specific IP is resolved for a domain or no network
requests are made:
defmodule TestDNSResolver do
@behaviour SafeURL.DNSResolver
@impl true
def resolve("google.com"), do: {:ok, [{192, 168, 1, 10}]}
def resolve("github.com"), do: {:ok, [{192, 168, 1, 20}]}
def resolve(_domain), do: {:ok, [{192, 168, 1, 99}]}
end
Summary
Types
@type resolution() :: :inet.ip() | [:inet.ip()]
Callbacks
@callback resolve(host :: binary()) :: {:ok, resolution()} | {:error, atom()}