summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorhref <href@random.sh>2021-09-08 15:39:01 +0200
committerhref <href@random.sh>2021-09-08 15:39:01 +0200
commitf7c3f34ad3cd63e92c2952a3ce6c34bd98ce2175 (patch)
tree335ae98acc40d17be143fc9fbfd32854e548bc1f /lib
parentassets: build (diff)
;o custom subnets
Diffstat (limited to 'lib')
-rw-r--r--lib/irc/connection.ex10
-rw-r--r--lib/irc/puppet_connection.ex37
-rw-r--r--lib/lsg/application.ex1
-rw-r--r--lib/lsg/subnet.ex84
4 files changed, 123 insertions, 9 deletions
diff --git a/lib/irc/connection.ex b/lib/irc/connection.ex
index a0cdc27..52910ac 100644
--- a/lib/irc/connection.ex
+++ b/lib/irc/connection.ex
@@ -222,11 +222,11 @@ defmodule IRC.Connection do
ExIRC.Client.add_handler(client, self())
client
end
- if state.conn.tls do
- ExIRC.Client.connect_ssl!(client, state.conn.host, state.conn.port, [])#[{:ifaddr, {45,150,150,33}}])
- else
- ExIRC.Client.connect!(client, state.conn.host, state.conn.port, [])#[{:ifaddr, {45,150,150,33}}])
- end
+
+ opts = [{:nodelay, true}]
+ conn_fun = if state.conn.tls, do: :connect_ssl!, else: :connect!
+ apply(ExIRC.Client, conn_fun, [client, to_charlist(state.conn.host), state.conn.port, opts])
+
{:noreply, %{state | client: client}}
end
diff --git a/lib/irc/puppet_connection.ex b/lib/irc/puppet_connection.ex
index da6cc93..b92ef2b 100644
--- a/lib/irc/puppet_connection.ex
+++ b/lib/irc/puppet_connection.ex
@@ -3,6 +3,7 @@ defmodule IRC.PuppetConnection do
@min_backoff :timer.seconds(5)
@max_backoff :timer.seconds(2*60)
@max_idle :timer.hours(12)
+ @env Mix.env
defmodule Supervisor do
use DynamicSupervisor
@@ -75,6 +76,15 @@ defmodule IRC.PuppetConnection do
end
def handle_continue(:connect, state) do
+ ipv6 = if @env == :prod do
+ subnet = LSG.Subnet.assign(state.account_id)
+ IRC.Account.put_meta(IRC.Account.get(state.account_id), "subnet", subnet)
+ ip = Pfx.host(subnet, 1)
+ {:ok, ipv6} = :inet_parse.ipv6_address(to_charlist(ip))
+ System.cmd("add-ip6", [ip])
+ ipv6
+ end
+
conn = IRC.Connection.lookup(state.connection_id)
client_opts = []
|> Keyword.put(:network, conn.network)
@@ -87,11 +97,30 @@ defmodule IRC.PuppetConnection do
ExIRC.Client.add_handler(client, self())
client
end
- if conn.tls do
- ExIRC.Client.connect_ssl!(client, conn.host, conn.port, [])#[{:ifaddr, {45,150,150,33}}])
- else
- ExIRC.Client.connect!(client, conn.host, conn.port, [])#[{:ifaddr, {45,150,150,33}}])
+
+ base_opts = [
+ {:nodelay, true}
+ ]
+
+ {ip, opts} = case {@env == :prod && ipv6, :inet_res.resolve(to_charlist(conn.host), :in, :aaaa)} do
+ {true, {:ok, {:dns_rec, _dns_header, _query, rrs = [{:dns_rr, _, _, _, _, _, _, _, _, _} | _], _, _}}} ->
+ ip = rrs
+ |> Enum.map(fn({:dns_rr, _, :aaaa, :in, _, _, ipv6, _, _, _}) -> ipv6 end)
+ |> Enum.shuffle()
+ |> List.first()
+
+ opts = [
+ :inet6,
+ {:ifaddr, ipv6}
+ ]
+ {ip, opts}
+ _ ->
+ {to_charlist(conn.host), []}
end
+
+ conn_fun = if conn.tls, do: :connect_ssl!, else: :connect!
+ apply(ExIRC.Client, conn_fun, [client, ip, conn.port, base_opts ++ opts])
+
{:noreply, %{state | client: client}}
end
diff --git a/lib/lsg/application.ex b/lib/lsg/application.ex
index 5b62dcd..0d29668 100644
--- a/lib/lsg/application.ex
+++ b/lib/lsg/application.ex
@@ -20,6 +20,7 @@ defmodule LSG.Application do
worker(LSG.IcecastAgent, []),
worker(LSG.Token, []),
worker(LSG.AuthToken, []),
+ LSG.Subnet,
{GenMagic.Pool, [name: LSG.GenMagic, pool_size: 2]},
#worker(LSG.Icecast, []),
] ++ LSG.IRC.application_childs
diff --git a/lib/lsg/subnet.ex b/lib/lsg/subnet.ex
new file mode 100644
index 0000000..81bd862
--- /dev/null
+++ b/lib/lsg/subnet.ex
@@ -0,0 +1,84 @@
+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