diff options
Diffstat (limited to '')
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | lib/irc/connection.ex | 10 | ||||
-rw-r--r-- | lib/irc/puppet_connection.ex | 37 | ||||
-rw-r--r-- | lib/lsg/application.ex | 1 | ||||
-rw-r--r-- | lib/lsg/subnet.ex | 84 | ||||
-rw-r--r-- | mix.exs | 21 | ||||
-rw-r--r-- | mix.lock | 3 |
7 files changed, 146 insertions, 12 deletions
@@ -20,3 +20,5 @@ erl_crash.dump /priv/irc.txt* /priv/outline.txt /priv/irc/txt/__pycache__ +/Archives/ +/config/release.exs 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 @@ -4,7 +4,7 @@ defmodule LSG.Mixfile do def project do [ app: :lsg, - version: "0.2.4", + version: version("0.2.4"), elixir: "~> 1.4", elixirc_paths: elixirc_paths(Mix.env), compilers: [:phoenix, :gettext] ++ Mix.compilers, @@ -44,12 +44,12 @@ defmodule LSG.Mixfile do {:cowlib, "~> 2.9.1", override: true}, {:plug, "~> 1.7"}, {:gettext, "~> 0.11"}, - {:httpoison, "~> 1.0"}, + {:httpoison, "~> 1.8", override: true}, {:jason, "~> 1.0"}, {:poison, "~> 4.0", override: true}, {:floki, "~> 0.19.3"}, {:ecto, "~> 3.4"}, - {:exirc, git: "https://git.random.sh/ircbot/exirc.git", branch: "fix-who-nick"}, + {:exirc, path: "../exirc"}, #git: "https://git.random.sh/ircbot/exirc.git", branch: "fix-who-nick"}, {:distillery, "~> 2.0"}, {:earmark, "~> 1.2"}, {:oauther, "~> 1.1"}, @@ -75,6 +75,21 @@ defmodule LSG.Mixfile do {:sentry, "~> 8.0.5"}, {:logger_json, "~> 4.3"}, {:oauth2, "~> 2.0"}, + {:powerdnsex, git: "https://git.random.sh/ircbot/powerdnsex.git", branch: "master"}, + {:pfx, "~> 0.7.0"}, ] end + + defp version(v) do + {describe, 0} = System.cmd("git", ~w(describe --dirty --broken --all --tags --long)) + [_, rest] = String.split(describe, "/") + info = String.trim(rest) + env = cond do + Mix.env() == :prod -> "" + true -> "." <> to_string(Mix.env()) + end + + v <> "+" <> info <> env + end + end @@ -54,6 +54,7 @@ "oauth2": {:hex, :oauth2, "2.0.0", "338382079fe16c514420fa218b0903f8ad2d4bfc0ad0c9f988867dfa246731b0", [:mix], [{:hackney, "~> 1.13", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "881b8364ac7385f9fddc7949379cbe3f7081da37233a1aa7aab844670a91e7e7"}, "oauther": {:hex, :oauther, "1.1.1", "7d8b16167bb587ecbcddd3f8792beb9ec3e7b65c1f8ebd86b8dd25318d535752", [:mix], [], "hexpm", "9374f4302045321874cccdc57eb975893643bd69c3b22bf1312dab5f06e5788e"}, "parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"}, + "pfx": {:hex, :pfx, "0.7.0", "551ead4c303d6e4943d315bba349ee2a7cecf05a5311d8a8e6a2661cc9e64951", [:mix], [], "hexpm", "4497f1625c0b71d5749bebca0acf564ae60e5ea374645088c7c57079165379ae"}, "phoenix": {:hex, :phoenix, "1.6.0-rc.0", "87dc1bb400588019a878ecf32c2d229c7d7f31a520c574860a059934663ffa70", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 1.0", [hex: :phoenix_view, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "2a0d344d2a2f654a9300b2b09dbf9c3821762e1364e26fce12d76fcd498b92c0"}, "phoenix_ecto": {:hex, :phoenix_ecto, "4.4.0", "0672ed4e4808b3fbed494dded89958e22fb882de47a97634c0b13e7b0b5f7720", [:mix], [{:ecto, "~> 3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "09864e558ed31ee00bd48fcc1d4fc58ae9678c9e81649075431e69dbabb43cc1"}, "phoenix_html": {:hex, :phoenix_html, "3.0.2", "0d71bd7dfa5fad2103142206e25e16accd64f41bcbd0002af3f0da17e530968d", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "d6c6e85d9bef8d52a5a66fcccd15529651f379eaccbf10500343a17f6f814f82"}, @@ -68,6 +69,8 @@ "poison": {:hex, :poison, "4.0.1", "bcb755a16fac91cad79bfe9fc3585bb07b9331e50cfe3420a24bcc2d735709ae", [:mix], [], "hexpm", "ba8836feea4b394bb718a161fc59a288fe0109b5006d6bdf97b6badfcf6f0f25"}, "polyjuice_client": {:git, "https://git.random.sh/ircbot/polyjuice_client.git", "92c949be2def3cd0280cbc78849b109d34c8fcaa", [branch: "master"]}, "polyjuice_util": {:hex, :polyjuice_util, "0.1.0", "69901959c143245b47829c8302d0605dff6c0e1c3b116730c162982e0f512ee0", [:mix], [], "hexpm", "af5d1f614f52ce1da59a1f5a7c49249a2dbfda279d99d52d1b4e83e84c19a8d5"}, + "poolboy": {:hex, :poolboy, "1.5.2", "392b007a1693a64540cead79830443abf5762f5d30cf50bc95cb2c1aaafa006b", [:rebar3], [], "hexpm", "dad79704ce5440f3d5a3681c8590b9dc25d1a561e8f5a9c995281012860901e3"}, + "powerdnsex": {:git, "https://git.random.sh/ircbot/powerdnsex.git", "1dad0c28ac0af45f0b5b1171af2a117fc6b341bf", [branch: "master"]}, "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"}, "retry": {:hex, :retry, "0.14.1", "722d1b0cf87096b71213f5801d99fface7ca76adc83fc9dbf3e1daee952aef10", [:mix], [], "hexpm", "b3a609f286f6fe4f6b2c15f32cd4a8a60427d78d05d7b68c2dd9110981111ae0"}, "sentry": {:hex, :sentry, "8.0.5", "5ca922b9238a50c7258b52f47364b2d545beda5e436c7a43965b34577f1ef61f", [:mix], [{:hackney, "~> 1.8", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.6", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, "~> 2.3", [hex: :plug_cowboy, repo: "hexpm", optional: true]}], "hexpm", "4972839fdbf52e886d7b3e694c8adf421f764f2fa79036b88fb4742049bd4b7c"}, |