-
-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
215 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
defmodule VintageNet.IP.DnsdConfig do | ||
@moduledoc """ | ||
This is a helper module for VintageNet.Technology implementations that use | ||
the Busybox DNS server. | ||
DNS functionality is only supported for IPv4 configurations using static IP | ||
addresses. | ||
DNS server parameters are: | ||
* `:port` - The port to use (defaults to 53) | ||
* `:ttl` - DNS record TTL in seconds (defaults to 120) | ||
* `:records` - DNS A records (required) | ||
The `:records` option is a list of name/IP address tuples. For example: | ||
``` | ||
[{"example.com", {1, 2, 3, 4}}] | ||
``` | ||
Only IPv4 addresses are supported. Addresses may be specified as strings or | ||
tuples, but will be normalized to tuple form before being applied. | ||
""" | ||
|
||
alias VintageNet.{Command, IP} | ||
alias VintageNet.Interface.RawConfig | ||
|
||
@doc """ | ||
Normalize the DNSD parameters in a configuration. | ||
""" | ||
@spec normalize(map()) :: map() | ||
def normalize(%{ipv4: %{method: :static}, dnsd: dnsd} = config) do | ||
# Normalize IP addresses | ||
new_dnsd = | ||
dnsd | ||
|> Map.update(:records, [], &normalize_records/1) | ||
|> Map.take([ | ||
:records, | ||
:port, | ||
:ttl | ||
]) | ||
|
||
%{config | dnsd: new_dnsd} | ||
end | ||
|
||
def normalize(%{dnsd: _something_else} = config) do | ||
# DNSD won't be started if not an IPv4 static configuration | ||
Map.drop(config, [:dnsd]) | ||
end | ||
|
||
def normalize(config), do: config | ||
|
||
defp normalize_records(records) do | ||
Enum.map(records, &normalize_record/1) | ||
end | ||
|
||
defp normalize_record({name, ipa}) do | ||
{name, IP.ip_to_tuple!(ipa)} | ||
end | ||
|
||
@doc """ | ||
Add dnsd configuration commands for running a DNSD server | ||
""" | ||
@spec add_config(RawConfig.t(), map(), keyword()) :: RawConfig.t() | ||
def add_config( | ||
%RawConfig{ | ||
ifname: ifname, | ||
files: files, | ||
child_specs: child_specs | ||
} = raw_config, | ||
%{ipv4: %{method: :static, address: address}, dnsd: dnsd_config}, | ||
opts | ||
) do | ||
tmpdir = Keyword.fetch!(opts, :tmpdir) | ||
dnsd = Keyword.fetch!(opts, :bin_dnsd) | ||
dnsd_conf_path = Path.join(tmpdir, "dnsd.conf.#{ifname}") | ||
|
||
new_files = [{dnsd_conf_path, dnsd_contents(dnsd_config)} | files] | ||
|
||
dnsd_args = | ||
[ | ||
"-c", | ||
dnsd_conf_path, | ||
"-i", | ||
IP.ip_to_string(address) | ||
] | ||
|> add_port(dnsd_config) | ||
|> add_ttl(dnsd_config) | ||
|
||
new_child_specs = | ||
child_specs ++ | ||
[ | ||
Supervisor.child_spec( | ||
{MuonTrap.Daemon, | ||
[ | ||
dnsd, | ||
dnsd_args, | ||
Command.add_muon_options(stderr_to_stdout: true, log_output: :debug) | ||
]}, | ||
id: :dnsd | ||
) | ||
] | ||
|
||
%RawConfig{raw_config | files: new_files, child_specs: new_child_specs} | ||
end | ||
|
||
def add_config(raw_config, _config_without_dhcpd, _opts), do: raw_config | ||
|
||
defp dnsd_contents(%{records: records}) do | ||
Enum.map(records, &record_to_string/1) | ||
|> IO.iodata_to_binary() | ||
end | ||
|
||
defp record_to_string({name, ipa}) do | ||
"#{name} #{IP.ip_to_string(ipa)}\n" | ||
end | ||
|
||
defp add_port(dnsd_args, %{port: port}) do | ||
["-p", to_string(port) | dnsd_args] | ||
end | ||
|
||
defp add_port(dnsd_args, _dnsd_config), do: dnsd_args | ||
|
||
defp add_ttl(dnsd_args, %{ttl: ttl}) do | ||
["-t", to_string(ttl) | dnsd_args] | ||
end | ||
|
||
defp add_ttl(dnsd_args, _dnsd_config), do: dnsd_args | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
defmodule VintageNet.IP.DnsdConfigTest do | ||
use ExUnit.Case | ||
|
||
alias VintageNet.IP.DnsdConfig | ||
|
||
test "dnsd normalizes" do | ||
config = %{ | ||
ipv4: %{method: :static, address: {192, 168, 1, 1}, prefix_length: 24}, | ||
dnsd: %{ | ||
records: [ | ||
{"sample.com", "192.168.1.4"}, | ||
{"another.com", "192.168.1.5"} | ||
] | ||
} | ||
} | ||
|
||
normalized_config = %{ | ||
ipv4: %{method: :static, address: {192, 168, 1, 1}, prefix_length: 24}, | ||
dnsd: %{ | ||
records: [ | ||
{"sample.com", {192, 168, 1, 4}}, | ||
{"another.com", {192, 168, 1, 5}} | ||
] | ||
} | ||
} | ||
|
||
assert normalized_config == DnsdConfig.normalize(config) | ||
end | ||
|
||
test "Dnsd converts configs" do | ||
input = %{ | ||
ipv4: %{method: :static, address: {192, 168, 1, 1}, prefix_length: 24}, | ||
dnsd: %{ | ||
records: [ | ||
{"sample.com", "192.168.1.4"}, | ||
{"another.com", "192.168.1.5"} | ||
] | ||
} | ||
} | ||
|
||
initial_raw_config = %VintageNet.Interface.RawConfig{ | ||
ifname: "eth0", | ||
source_config: input, | ||
type: UnitTest | ||
} | ||
|
||
opts = [tmpdir: "tmpdir", bin_dnsd: "dnsd"] | ||
|
||
result = DnsdConfig.add_config(initial_raw_config, input, opts) | ||
|
||
expected = %VintageNet.Interface.RawConfig{ | ||
child_specs: [ | ||
%{ | ||
id: :dnsd, | ||
restart: :permanent, | ||
shutdown: 500, | ||
start: | ||
{MuonTrap.Daemon, :start_link, | ||
[ | ||
"dnsd", | ||
["-c", "tmpdir/dnsd.conf.eth0", "-i", "192.168.1.1"], | ||
[stderr_to_stdout: true, log_output: :debug] | ||
]}, | ||
type: :worker | ||
} | ||
], | ||
files: [ | ||
{"tmpdir/dnsd.conf.eth0", | ||
""" | ||
sample.com 192.168.1.4 | ||
another.com 192.168.1.5 | ||
"""} | ||
], | ||
ifname: "eth0", | ||
source_config: input, | ||
type: UnitTest | ||
} | ||
|
||
assert expected == result | ||
end | ||
end |