defmodule LSG.Subnet do
use Agent
def start_link(_) do
Agent.start_link(&setup/0, name: __MODULE__)
end
def assignations() do
:dets.select(dets(), [{{:"$1", :"$2"}, [is_binary: :"$2"], [{{:"$1", :"$2"}}]}])
end
def find_subnet_for(binary) when is_binary(binary) do
case :dets.select(dets(), [{{:"$1", :"$2"}, [{:==, :"$2", binary}], [{{:"$1", :"$2"}}]}]) do
[{subnet, _}] -> subnet
_ -> nil
end
end
def assign(binary) when is_binary(binary) do
result = if subnet = find_subnet_for(binary) do
{:ok, subnet}
else
Agent.get_and_update(__MODULE__, fn(dets) ->
{subnet, _} = available_select(dets)
:dets.insert(dets, {subnet, binary})
:dets.sync(dets)
{{:new, subnet}, dets}
end)
end
case result do
{:new, subnet} ->
ip = Pfx.host(subnet, 1)
set_reverse(binary, ip)
subnet
{:ok, subnet} ->
subnet
end
end
def set_reverse(name, ip, value \\ nil)
def set_reverse(name, ip, nil) do
set_reverse(name, ip, "#{name}.users.goulag.org")
end
def set_reverse(_, ip, value) do
ptr_zone = "3.0.0.2.d.f.0.a.2.ip6.arpa"
ip_fqdn = Pfx.dns_ptr(ip)
ip_local = String.replace(ip_fqdn, ".#{ptr_zone}", "")
rev? = String.ends_with?(value, ".users.goulag.org")
if rev? do
{:ok, rev_zone} = PowerDNSex.show_zone("users.goulag.org")
rev_update? = Enum.any?(rev_zone.rrsets, fn(rr) -> rr.name == "#{ip_fqdn}." end)
record = %{name: "#{value}.", type: "AAAA", ttl: 8600, records: [%{content: ip, disabled: false}]}
if(rev_update?, do: PowerDNSex.update_record(rev_zone, record), else: PowerDNSex.create_record(rev_zone, record))
end
{:ok, zone} = PowerDNSex.show_zone(ptr_zone)
update? = Enum.any?(zone.rrsets, fn(rr) -> rr.name == "#{ip_fqdn}." end)
record = %{name: "#{ip_fqdn}.", type: "PTR", ttl: 3600, records: [%{content: "#{value}.", disabled: false}]}
pdns = if(update?, do: PowerDNSex.update_record(zone, record), else: PowerDNSex.create_record(zone, record))
:ok
end
@doc false
def dets() do
(LSG.data_path() <> "/subnets.dets") |> String.to_charlist()
end
@doc false
def setup() do
{:ok, dets} = :dets.open_file(dets(), [])
dets
end
defp available_select(dets) do
spec = [{{:"$1", :"$2"}, [is_integer: :"$2"], [{{:"$1", :"$2"}}]}]
{subnets, _} = :dets.select(dets, spec, 20)
subnet = subnets
|> Enum.sort_by(fn({_, last}) -> last end)
|> List.first()
end
end