mirror of
https://github.com/outbackdingo/firezone.git
synced 2026-01-27 10:18:54 +00:00
Rework how fg_vpn handles interfacing with the OS
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
elixir 1.11.3-otp-23
|
||||
erlang 23.2.1
|
||||
erlang 23.2.3
|
||||
nodejs 14.15.4
|
||||
python 3.7.9
|
||||
|
||||
@@ -4,9 +4,7 @@ defmodule FgHttp.Devices do
|
||||
"""
|
||||
|
||||
import Ecto.Query, warn: false
|
||||
alias FgHttp.Repo
|
||||
|
||||
alias FgHttp.Devices.Device
|
||||
alias FgHttp.{Devices.Device, Repo}
|
||||
|
||||
def list_devices(user_id) do
|
||||
Repo.all(from d in Device, where: d.user_id == ^user_id)
|
||||
@@ -49,4 +47,14 @@ defmodule FgHttp.Devices do
|
||||
def change_device(%Device{} = device) do
|
||||
Device.changeset(device, %{})
|
||||
end
|
||||
|
||||
def to_peer_list do
|
||||
for device <- Repo.all(Device) do
|
||||
%{
|
||||
public_key: device.public_key,
|
||||
allowed_ips: device.allowed_ips,
|
||||
preshared_key: device.preshared_key
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -11,6 +11,8 @@ defmodule FgHttp.Devices.Device do
|
||||
schema "devices" do
|
||||
field :name, :string
|
||||
field :public_key, :string
|
||||
field :allowed_ips, :string
|
||||
field :preshared_key, :string
|
||||
field :server_pubkey, :string, virtual: true
|
||||
field :private_key, :string, virtual: true
|
||||
field :ifname, :string
|
||||
|
||||
@@ -2,4 +2,12 @@ defmodule FgHttp.Repo do
|
||||
use Ecto.Repo,
|
||||
otp_app: :fg_http,
|
||||
adapter: Ecto.Adapters.Postgres
|
||||
|
||||
alias FgHttp.Devices
|
||||
alias Phoenix.PubSub
|
||||
|
||||
def init(_) do
|
||||
# Notify FgVpn.Server the config has been loaded
|
||||
PubSub.broadcast(:fg_http_pub_sub, "server", {:set_config, Devices.to_peer_list()})
|
||||
end
|
||||
end
|
||||
|
||||
@@ -31,7 +31,11 @@ defmodule FgHttpWeb.DeviceController do
|
||||
|
||||
case Devices.create_device(all_params) do
|
||||
{:ok, device} ->
|
||||
PubSub.broadcast(:fg_http_pub_sub, "config", {:commit_device, device.public_key})
|
||||
PubSub.broadcast(:fg_http_pub_sub, "server", {
|
||||
:commit_peer,
|
||||
Map.take(device, [:public_key, :allowed_ips, :preshared_key])
|
||||
})
|
||||
|
||||
redirect(conn, to: Routes.device_path(conn, :index))
|
||||
|
||||
{:error, %Ecto.Changeset{} = changeset} ->
|
||||
|
||||
@@ -25,7 +25,7 @@ defmodule FgHttpWeb.NewDeviceLive do
|
||||
end
|
||||
|
||||
# Fire off event to generate private key, psk, and add device to config
|
||||
PubSub.broadcast(:fg_http_pub_sub, "config", {:new_device})
|
||||
PubSub.broadcast(:fg_http_pub_sub, "server", {:new_peer})
|
||||
|
||||
device = %Device{user_id: user_id}
|
||||
|
||||
@@ -36,7 +36,7 @@ defmodule FgHttpWeb.NewDeviceLive do
|
||||
Handles device added.
|
||||
"""
|
||||
@impl true
|
||||
def handle_info({:peer_generated, privkey, pubkey, server_pubkey}, socket) do
|
||||
def handle_info({:device_generated, privkey, pubkey, server_pubkey}, socket) do
|
||||
device = %{
|
||||
socket.assigns.device
|
||||
| public_key: pubkey,
|
||||
|
||||
@@ -5,6 +5,8 @@ defmodule FgHttp.Repo.Migrations.CreateDevices do
|
||||
create table(:devices) do
|
||||
add :name, :string, null: false
|
||||
add :public_key, :string, null: false
|
||||
add :allowed_ips, :string
|
||||
add :preshared_key, :string
|
||||
add :ifname, :string, null: false
|
||||
add :last_ip, :inet
|
||||
add :user_id, references(:users, on_delete: :delete_all), null: false
|
||||
|
||||
@@ -12,8 +12,8 @@ defmodule FgHttpWeb.NewDeviceLiveTest do
|
||||
test "mount and handle_info/2", %{authed_conn: conn} do
|
||||
{:ok, view, html} = live_isolated(conn, FgHttpWeb.NewDeviceLive)
|
||||
assert html =~ "Adding new peer to WireGuard server..."
|
||||
assert render(view) =~ "Adding new peer to WireGuard server..."
|
||||
send(view.pid, {:peer_generated, "test-privkey", "test-pubkey", "server-pubkey"})
|
||||
assert render(view) =~ "Add the following to your WireGuard"
|
||||
send(view.pid, {:device_generated, "test-privkey", "test-pubkey", "server-pubkey"})
|
||||
result = render(view)
|
||||
assert result =~ "test-pubkey"
|
||||
assert result =~ "server-pubkey"
|
||||
|
||||
@@ -7,7 +7,7 @@ defmodule FgVpn.Application do
|
||||
|
||||
def start(_type, _args) do
|
||||
children = [
|
||||
FgVpn.Config
|
||||
FgVpn.Server
|
||||
]
|
||||
|
||||
# See https://hexdocs.pm/elixir/Supervisor.html
|
||||
|
||||
@@ -1,77 +1,9 @@
|
||||
defmodule FgVpn.CLI do
|
||||
@moduledoc """
|
||||
Wraps command-line functionality of WireGuard for our purposes.
|
||||
|
||||
Application startup:
|
||||
- wg syncconf
|
||||
|
||||
Consumed events:
|
||||
- add device:
|
||||
1. start listening for new connections
|
||||
2. send pubkey when device connects
|
||||
3. when verification received from fg_http, add config entry
|
||||
|
||||
- remove device:
|
||||
1. disconnect device if connected
|
||||
2. remove configuration entry
|
||||
|
||||
Produced events:
|
||||
- client connects:
|
||||
1. send IP, connection time to FgHttp
|
||||
- change config
|
||||
|
||||
Helpers:
|
||||
- render_conf: re-renders configuration file (peer configurations specifically)
|
||||
- sync_conf: calls "wg syncconf"
|
||||
Determines adapter to use for CLI commands.
|
||||
"""
|
||||
|
||||
@default_interface_cmd "route | grep '^default' | grep -o '[^ ]*$'"
|
||||
|
||||
# Outputs the privkey, then pubkey on the next line
|
||||
@genkey_cmd "wg genkey | tee >(wg pubkey)"
|
||||
|
||||
@doc """
|
||||
Finds default egress interface on a Linux box.
|
||||
"""
|
||||
def default_interface do
|
||||
case :os.type() do
|
||||
{:unix, :linux} ->
|
||||
exec(@default_interface_cmd)
|
||||
|> String.split()
|
||||
|> List.first()
|
||||
|
||||
{:unix, :darwin} ->
|
||||
# XXX: Figure out what it means to have macOS as a host?
|
||||
"en0"
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Calls wg genkey
|
||||
"""
|
||||
def genkey do
|
||||
[privkey, pubkey] =
|
||||
exec(@genkey_cmd)
|
||||
|> String.trim()
|
||||
|> String.split("\n")
|
||||
|
||||
{privkey, pubkey}
|
||||
end
|
||||
|
||||
def pubkey(privkey) when is_nil(privkey), do: nil
|
||||
|
||||
def pubkey(privkey) when is_binary(privkey) do
|
||||
exec("echo #{privkey} | wg pubkey")
|
||||
|> String.trim()
|
||||
end
|
||||
|
||||
defp exec(cmd) do
|
||||
case System.cmd("bash", ["-c", cmd]) do
|
||||
{result, 0} ->
|
||||
result
|
||||
|
||||
{error, _} ->
|
||||
raise "Error executing command: #{error}"
|
||||
end
|
||||
def cli do
|
||||
Application.get_env(:fg_vpn, :cli)
|
||||
end
|
||||
end
|
||||
|
||||
138
apps/fg_vpn/lib/fg_vpn/cli/live.ex
Normal file
138
apps/fg_vpn/lib/fg_vpn/cli/live.ex
Normal file
@@ -0,0 +1,138 @@
|
||||
defmodule FgVpn.CLI.Live do
|
||||
@moduledoc """
|
||||
A low-level module that wraps common WireGuard CLI operations.
|
||||
Currently, these are very Linux-specific. In the future,
|
||||
this could be generalized to any *nix platform that supports a WireGuard
|
||||
client.
|
||||
|
||||
See FgVpn.Server for higher-level functionality.
|
||||
"""
|
||||
|
||||
@egress_interface_cmd "route | grep '^default' | grep -o '[^ ]*$'"
|
||||
|
||||
# Outputs the privkey, then pubkey on the next line
|
||||
@genkey_cmd "wg genkey | tee >(wg pubkey)"
|
||||
|
||||
@iface_name "wg-fireguard"
|
||||
|
||||
def setup do
|
||||
create_interface()
|
||||
setup_iptables()
|
||||
up_interface()
|
||||
end
|
||||
|
||||
def teardown do
|
||||
down_interface()
|
||||
teardown_iptables()
|
||||
delete_interface()
|
||||
end
|
||||
|
||||
@doc """
|
||||
Calls wg genkey
|
||||
"""
|
||||
def genkey do
|
||||
[privkey, pubkey] =
|
||||
exec!(@genkey_cmd)
|
||||
|> String.trim()
|
||||
|> String.split("\n")
|
||||
|
||||
{privkey, pubkey}
|
||||
end
|
||||
|
||||
def pubkey(privkey) when is_nil(privkey), do: nil
|
||||
|
||||
def pubkey(privkey) when is_binary(privkey) do
|
||||
exec!("echo #{privkey} | wg pubkey")
|
||||
|> String.trim()
|
||||
end
|
||||
|
||||
def set(config_str) do
|
||||
exec!("wg set #{@iface_name} #{config_str}")
|
||||
end
|
||||
|
||||
def show_latest_handshakes do
|
||||
show("latest-handshakes")
|
||||
end
|
||||
|
||||
def show_persistent_keepalives do
|
||||
show("persistent-keepalives")
|
||||
end
|
||||
|
||||
def show_transfer do
|
||||
show("transfer")
|
||||
end
|
||||
|
||||
defp egress_interface do
|
||||
case :os.type() do
|
||||
{:unix, :linux} ->
|
||||
exec!(@egress_interface_cmd)
|
||||
|> String.split()
|
||||
|> List.first()
|
||||
|
||||
{:unix, :darwin} ->
|
||||
# XXX: Figure out what it means to have macOS as a host?
|
||||
"en0"
|
||||
end
|
||||
end
|
||||
|
||||
def exec!(cmd) do
|
||||
case bash(cmd) do
|
||||
{result, 0} ->
|
||||
result
|
||||
|
||||
{error, _} ->
|
||||
raise "Error executing command: #{error}. FireGuard cannot recover from this error."
|
||||
end
|
||||
end
|
||||
|
||||
defp show(subcommand) do
|
||||
exec!("wg show #{@iface_name} #{subcommand}")
|
||||
end
|
||||
|
||||
defp interface_exists do
|
||||
case bash("ifconfig -a | grep #{@iface_name}") do
|
||||
{_result, 0} -> true
|
||||
{_error, 1} -> false
|
||||
end
|
||||
end
|
||||
|
||||
defp create_interface do
|
||||
unless interface_exists() do
|
||||
exec!("ip link add dev #{@iface_name} type wireguard")
|
||||
end
|
||||
end
|
||||
|
||||
defp delete_interface do
|
||||
if interface_exists() do
|
||||
exec!("ip link dev delete #{@iface_name}")
|
||||
end
|
||||
end
|
||||
|
||||
defp setup_iptables do
|
||||
exec!(
|
||||
"iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o #{
|
||||
egress_interface()
|
||||
} -j MASQUERADE"
|
||||
)
|
||||
end
|
||||
|
||||
defp teardown_iptables do
|
||||
exec!(
|
||||
"iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o #{
|
||||
egress_interface()
|
||||
} -j MASQUERADE"
|
||||
)
|
||||
end
|
||||
|
||||
defp up_interface do
|
||||
exec!("ifconfig #{@iface_name} up")
|
||||
end
|
||||
|
||||
defp down_interface do
|
||||
exec!("ifconfig #{@iface_name} down")
|
||||
end
|
||||
|
||||
defp bash(cmd) do
|
||||
System.cmd("bash", ["-c", cmd])
|
||||
end
|
||||
end
|
||||
24
apps/fg_vpn/lib/fg_vpn/cli/sandbox.ex
Normal file
24
apps/fg_vpn/lib/fg_vpn/cli/sandbox.ex
Normal file
@@ -0,0 +1,24 @@
|
||||
defmodule FgVpn.CLI.Sandbox do
|
||||
@moduledoc """
|
||||
Sandbox CLI environment for WireGuard CLI operations.
|
||||
"""
|
||||
|
||||
@show_latest_handshakes "4 seconds ago"
|
||||
@show_persistent_keepalives "every 25 seconds"
|
||||
@show_transfer "4.60 MiB received, 59.21 MiB sent"
|
||||
@default_returned ""
|
||||
|
||||
def egress_interface, do: "eth0"
|
||||
def setup, do: @default_returned
|
||||
def teardown, do: @default_returned
|
||||
def genkey, do: {rand_key(), rand_key()}
|
||||
def pubkey(_privkey), do: rand_key()
|
||||
def exec!(_cmd), do: @default_returned
|
||||
def set(_conf_str), do: @default_returned
|
||||
def show_latest_handshakes, do: @show_latest_handshakes
|
||||
def show_persistent_keepalives, do: @show_persistent_keepalives
|
||||
def show_transfer, do: @show_transfer
|
||||
|
||||
# Generate extremely fake keys in Sandbox mode
|
||||
defp rand_key, do: :crypto.strong_rand_bytes(32) |> Base.encode64()
|
||||
end
|
||||
@@ -1,198 +1,34 @@
|
||||
defmodule FgVpn.Config do
|
||||
@moduledoc """
|
||||
Functions for reading / writing the WireGuard config
|
||||
Functions for managing the FireGuard configuration.
|
||||
"""
|
||||
|
||||
alias FgVpn.CLI
|
||||
alias Phoenix.PubSub
|
||||
use GenServer
|
||||
@default_interface_ip "172.16.59.1"
|
||||
|
||||
@config_header """
|
||||
# This file is being managed by the fireguard systemd service. Any changes
|
||||
# will be overwritten eventually.
|
||||
import FgVpn.CLI
|
||||
|
||||
"""
|
||||
defstruct interface_ip: @default_interface_ip,
|
||||
listen_port: 51_820,
|
||||
peers: MapSet.new([]),
|
||||
uncommitted_peers: MapSet.new([])
|
||||
|
||||
def start_link(_) do
|
||||
# Load existing config from file then write it so we start with a clean slate.
|
||||
config = read_and_rewrite_config()
|
||||
GenServer.start_link(__MODULE__, config)
|
||||
end
|
||||
|
||||
@impl true
|
||||
def init(config) do
|
||||
# Subscribe to PubSub from FgHttp application
|
||||
{PubSub.subscribe(:fg_http_pub_sub, "config"), config}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_info({:new_device}, config) do
|
||||
{_server_privkey, server_pubkey} = read_privkey()
|
||||
{privkey, pubkey} = CLI.genkey()
|
||||
uncommitted_peers = MapSet.put(config[:uncommitted_peers], pubkey)
|
||||
new_config = Map.put(config, :uncommitted_peers, uncommitted_peers)
|
||||
|
||||
PubSub.broadcast(
|
||||
:fg_http_pub_sub,
|
||||
"view",
|
||||
{:peer_generated, privkey, pubkey, server_pubkey}
|
||||
)
|
||||
|
||||
{:noreply, new_config}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_info({:commit_device, pubkey}, config) do
|
||||
new_config =
|
||||
if MapSet.member?(config[:uncommitted_peers], pubkey) do
|
||||
new_peers = MapSet.put(config[:peers], pubkey)
|
||||
new_uncommitted_peers = MapSet.delete(config[:uncommitted_peers], pubkey)
|
||||
|
||||
config
|
||||
|> Map.put(:uncommitted_peers, new_uncommitted_peers)
|
||||
|> Map.put(:peers, new_peers)
|
||||
else
|
||||
config
|
||||
end
|
||||
|
||||
write!(new_config)
|
||||
|
||||
{:noreply, new_config}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_info({:remove_device, pubkey}, config) do
|
||||
new_peers = MapSet.delete(config[:peers], pubkey)
|
||||
new_config = %{config | peers: new_peers}
|
||||
write!(new_config)
|
||||
{:noreply, new_config}
|
||||
end
|
||||
|
||||
@doc """
|
||||
Writes configuration file.
|
||||
"""
|
||||
def write!(config) do
|
||||
Application.get_env(:fg_vpn, :wireguard_conf_path)
|
||||
|> File.write!(render(config))
|
||||
end
|
||||
|
||||
@doc """
|
||||
Reads PrivateKey from configuration file
|
||||
|
||||
Returns a {privkey, pubkey} tuple
|
||||
"""
|
||||
def read_privkey do
|
||||
read_config_file()
|
||||
|> extract_privkey()
|
||||
|> (&{&1, CLI.pubkey(&1)}).()
|
||||
end
|
||||
|
||||
defp extract_privkey(config_str) do
|
||||
~r/PrivateKey = (.*)/
|
||||
|> Regex.scan(config_str || "")
|
||||
|> List.flatten()
|
||||
|> List.last()
|
||||
end
|
||||
|
||||
@doc """
|
||||
Reads configuration file and generates a list of pubkeys
|
||||
"""
|
||||
def read_peers do
|
||||
read_config_file()
|
||||
|> extract_pubkeys()
|
||||
end
|
||||
|
||||
@doc """
|
||||
Extracts pubkeys from a configuration file snippet
|
||||
"""
|
||||
def extract_pubkeys(config_str) do
|
||||
case config_str do
|
||||
nil ->
|
||||
nil
|
||||
|
||||
_ ->
|
||||
~r/PublicKey = (.*)/
|
||||
|> Regex.scan(config_str)
|
||||
|> Enum.map(fn match_list -> List.last(match_list) end)
|
||||
|> MapSet.new()
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Renders WireGuard config in a deterministic way.
|
||||
"""
|
||||
def render(config) do
|
||||
@config_header <> interface_to_config(config) <> peers_to_config(config)
|
||||
"private-key #{private_key()} listen-port #{config.listen_port} " <>
|
||||
Enum.join(
|
||||
for peer <- config.peers do
|
||||
"peer #{peer.public_key} allowed-ips #{peer.allowed_ips} preshared-key #{
|
||||
peer.preshared_key
|
||||
}"
|
||||
end,
|
||||
" "
|
||||
)
|
||||
end
|
||||
|
||||
defp listen_port do
|
||||
Application.get_env(:fg_http, :vpn_endpoint)
|
||||
|> String.split(":")
|
||||
|> List.last()
|
||||
def private_key do
|
||||
Application.get_env(:fg_vpn, :private_key)
|
||||
end
|
||||
|
||||
defp interface_to_config(config) do
|
||||
~s"""
|
||||
[Interface]
|
||||
ListenPort = #{listen_port()}
|
||||
PrivateKey = #{config[:privkey]}
|
||||
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o #{
|
||||
config[:default_int]
|
||||
} -j MASQUERADE
|
||||
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o #{
|
||||
config[:default_int]
|
||||
} -j MASQUERADE
|
||||
|
||||
"""
|
||||
end
|
||||
|
||||
defp read_config_file do
|
||||
path = Application.get_env(:fg_vpn, :wireguard_conf_path)
|
||||
|
||||
case File.read(path) do
|
||||
{:ok, str} ->
|
||||
str
|
||||
|
||||
{:error, reason} ->
|
||||
IO.puts(:stderr, "Could not read config: #{reason}")
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
defp peers_to_config(config) do
|
||||
Enum.map_join(config[:peers], fn pubkey ->
|
||||
~s"""
|
||||
# BEGIN PEER #{pubkey}
|
||||
[Peer]
|
||||
PublicKey = #{pubkey}
|
||||
AllowedIPs = 0.0.0.0/0, ::/0
|
||||
# END PEER #{pubkey}
|
||||
"""
|
||||
end)
|
||||
end
|
||||
|
||||
defp get_server_keys do
|
||||
{privkey, pubkey} = read_privkey()
|
||||
|
||||
if is_nil(privkey) do
|
||||
CLI.genkey()
|
||||
else
|
||||
{privkey, pubkey}
|
||||
end
|
||||
end
|
||||
|
||||
defp read_and_rewrite_config do
|
||||
{privkey, _pubkey} = get_server_keys()
|
||||
|
||||
config = %{
|
||||
default_int: CLI.default_interface(),
|
||||
privkey: privkey,
|
||||
peers: read_peers() || MapSet.new([]),
|
||||
uncommitted_peers: MapSet.new([])
|
||||
}
|
||||
|
||||
write!(config)
|
||||
|
||||
config
|
||||
def public_key do
|
||||
cli().pubkey(private_key())
|
||||
end
|
||||
end
|
||||
|
||||
9
apps/fg_vpn/lib/fg_vpn/peer.ex
Normal file
9
apps/fg_vpn/lib/fg_vpn/peer.ex
Normal file
@@ -0,0 +1,9 @@
|
||||
defmodule FgVpn.Peer do
|
||||
@moduledoc """
|
||||
Represents a WireGuard peer.
|
||||
"""
|
||||
|
||||
defstruct public_key: nil,
|
||||
allowed_ips: "0.0.0.0/0,::/0",
|
||||
preshared_key: nil
|
||||
end
|
||||
@@ -1,9 +1,86 @@
|
||||
defmodule FgVpn.Server do
|
||||
@moduledoc """
|
||||
Module to load boringtun lib as a server
|
||||
Functions for reading / writing the WireGuard config
|
||||
|
||||
Startup:
|
||||
Set empty config
|
||||
|
||||
Received events:
|
||||
- start: set config and apply it
|
||||
- new_peer: gen peer pubkey, return it, but don't apply config
|
||||
- commit_peer: commit pending peer to config
|
||||
- remove_peer: remove peer
|
||||
"""
|
||||
|
||||
use Rustler, otp_app: :fg_vpn, crate: :fgvpn_server
|
||||
alias FgVpn.{Config, Peer}
|
||||
alias Phoenix.PubSub
|
||||
use GenServer
|
||||
import FgVpn.CLI
|
||||
|
||||
def add(_arg1, _arg2), do: :erlang.nif_error(:nif_not_loaded)
|
||||
def start_link(_) do
|
||||
cli().setup()
|
||||
GenServer.start_link(__MODULE__, %Config{})
|
||||
end
|
||||
|
||||
@impl true
|
||||
def init(config) do
|
||||
# Subscribe to PubSub from FgHttp application
|
||||
{PubSub.subscribe(:fg_http_pub_sub, "server"), config}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_info({:new_peer}, config) do
|
||||
server_pubkey = Config.public_key()
|
||||
{privkey, pubkey} = cli().genkey()
|
||||
uncommitted_peers = MapSet.put(config.uncommitted_peers, pubkey)
|
||||
new_config = Map.put(config, :uncommitted_peers, uncommitted_peers)
|
||||
|
||||
PubSub.broadcast(
|
||||
:fg_http_pub_sub,
|
||||
"view",
|
||||
{:device_generated, privkey, pubkey, server_pubkey}
|
||||
)
|
||||
|
||||
{:noreply, new_config}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_info({:commit_peer, %{} = attrs}, config) do
|
||||
new_config =
|
||||
if MapSet.member?(config.uncommitted_peers, attrs[:public_key]) do
|
||||
new_peer = Map.merge(%Peer{}, attrs)
|
||||
new_peers = MapSet.put(config.peers, new_peer)
|
||||
new_uncommitted_peers = MapSet.delete(config.uncommitted_peers, attrs[:public_key])
|
||||
|
||||
config
|
||||
|> Map.put(:uncommitted_peers, new_uncommitted_peers)
|
||||
|> Map.put(:peers, new_peers)
|
||||
else
|
||||
config
|
||||
end
|
||||
|
||||
apply(new_config)
|
||||
|
||||
{:noreply, new_config}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_info({:remove_peer, pubkey}, config) do
|
||||
new_peers = MapSet.delete(config.peers, %Peer{public_key: pubkey})
|
||||
new_config = %{config | peers: new_peers}
|
||||
apply(new_config)
|
||||
{:noreply, new_config}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_cast({:set_config, new_config}, _config) do
|
||||
{:noreply, new_config}
|
||||
end
|
||||
|
||||
@doc """
|
||||
Apply configuration to interface.
|
||||
"""
|
||||
def apply(config) do
|
||||
cli().set(Config.render(config))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -6,19 +6,12 @@ defmodule FgVpn.MixProject do
|
||||
app: :fg_vpn,
|
||||
version: "0.1.7",
|
||||
build_path: "../../_build",
|
||||
compilers: [:rustler] ++ Mix.compilers(),
|
||||
config_path: "../../config/config.exs",
|
||||
deps_path: "../../deps",
|
||||
lockfile: "../../mix.lock",
|
||||
elixir: "~> 1.11",
|
||||
start_permanent: Mix.env() == :prod,
|
||||
test_coverage: [tool: ExCoveralls],
|
||||
rustler_crates: [
|
||||
fgvpn_server: [
|
||||
cargo: {:rustup, "stable"},
|
||||
mode: :release
|
||||
]
|
||||
],
|
||||
preferred_cli_env: [
|
||||
coveralls: :test,
|
||||
"coveralls.detail": :test,
|
||||
@@ -41,7 +34,6 @@ defmodule FgVpn.MixProject do
|
||||
defp deps do
|
||||
[
|
||||
{:fg_http, in_umbrella: true},
|
||||
{:rustler, "~> 0.22.0-rc.0"},
|
||||
{:phoenix_pubsub, "~> 2.0"},
|
||||
{:credo, "~> 1.4", only: [:dev, :test], runtime: false},
|
||||
{:excoveralls, "~> 0.13", only: :test}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
[target.x86_64-apple-darwin]
|
||||
rustflags = [
|
||||
"-C", "link-arg=-undefined",
|
||||
"-C", "link-arg=dynamic_lookup",
|
||||
]
|
||||
584
apps/fg_vpn/native/fgvpn_server/Cargo.lock
generated
584
apps/fg_vpn/native/fgvpn_server/Cargo.lock
generated
@@ -1,584 +0,0 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.14.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a55f82cfe485775d02112886f4169bde0c5894d75e79ead7eafe7e40a25e45f7"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "adler"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e"
|
||||
|
||||
[[package]]
|
||||
name = "ascii"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eab1c04a571841102f5345a8fc0f6bb3d31c315dec879b5c6e42e40ce7ffa34e"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.55"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef5140344c85b01f9bbb4d4b7288a8aa4b3287ccef913a14bcc78a1063623598"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
"object",
|
||||
"rustc-demangle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
|
||||
[[package]]
|
||||
name = "boringtun"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d62ad6ff2f841f576887ffd3e94a4ae438784dc566c44b3fbd783e5d31e04c99"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"chrono",
|
||||
"clap",
|
||||
"daemonize",
|
||||
"hex",
|
||||
"jni",
|
||||
"libc",
|
||||
"ring",
|
||||
"spin",
|
||||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "boxfnonce"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5988cb1d626264ac94100be357308f29ff7cbdd3b36bda27f450a4ee3f713426"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.66"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48"
|
||||
|
||||
[[package]]
|
||||
name = "cesu8"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"time",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.33.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"strsim",
|
||||
"textwrap",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "combine"
|
||||
version = "3.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da3da6baa321ec19e1cc41d31bf599f00c783d0517095cdaf0332e3fe8d20680"
|
||||
dependencies = [
|
||||
"ascii",
|
||||
"byteorder",
|
||||
"either",
|
||||
"memchr",
|
||||
"unreachable",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "daemonize"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70c24513e34f53b640819f0ac9f705b673fcf4006d7aab8778bee72ebfc89815"
|
||||
dependencies = [
|
||||
"boxfnonce",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
|
||||
|
||||
[[package]]
|
||||
name = "error-chain"
|
||||
version = "0.12.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fgvpn_server"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"boringtun",
|
||||
"rustler",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.23.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87cbf45460356b7deeb5e3415b5563308c0a9b057c85e12b06ad551f98d0a6ac"
|
||||
dependencies = [
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35"
|
||||
|
||||
[[package]]
|
||||
name = "jni"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ecfa3b81afc64d9a6539c4eece96ac9a93c551c713a313800dade8e33d7b5c1"
|
||||
dependencies = [
|
||||
"cesu8",
|
||||
"combine",
|
||||
"error-chain",
|
||||
"jni-sys",
|
||||
"log",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jni-sys"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.46"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf3d7383929f7c9c7c2d0fa596f325832df98c3704f2c60553080f7127a58175"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.82"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89203f3fba0a3795506acaad8ebce3c80c0af93f994d5a1d7a0b1eeb23271929"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fcf3805d4480bb5b86070dcfeb9e2cb2ebc148adb753c5cca5f884d1d65a42b2"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0f2d26ec3309788e423cfbf68ad1800f061638098d76a83681af979dc4eda19d"
|
||||
dependencies = [
|
||||
"adler",
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.22.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
version = "0.16.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "024a1e66fea74c66c66624ee5622a7ff0e4b73a13b4f5c326ddb50c708944226"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"spin",
|
||||
"untrusted",
|
||||
"web-sys",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e3bad0ee36814ca07d7968269dd4b7ec89ec2da10c4bb613928d3077083c232"
|
||||
|
||||
[[package]]
|
||||
name = "rustler"
|
||||
version = "0.22.0-rc.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6627953c4983f7808f569d4df17d7de55893ed1e1a85ca4ef5ab95569b83832e"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"rustler_codegen",
|
||||
"rustler_sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustler_codegen"
|
||||
version = "0.22.0-rc.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b10e7791e788906c4394c980022210fbbeb75e75f7d9166b7bd0169e194ed4d"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustler_sys"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9fb96034ff33723615fd19223d58c987c1f6476342e83557a6e467ef95f83bda"
|
||||
dependencies = [
|
||||
"unreachable",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.58"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc60a3d73ea6594cd712d830cc1f0390fd71542d8c8cd24e70cc54cdfd5e05d5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||
dependencies = [
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"wasi",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
|
||||
|
||||
[[package]]
|
||||
name = "unreachable"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
|
||||
dependencies = [
|
||||
"void",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "untrusted"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
|
||||
|
||||
[[package]]
|
||||
name = "void"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d"
|
||||
dependencies = [
|
||||
"same-file",
|
||||
"winapi",
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.10.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3cd364751395ca0f68cafb17666eee36b63077fb5ecd972bbcd74c90c4bf736e"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1114f89ab1f4106e5b55e688b828c0ab0ea593a1ea7c094b141b14cbaaec2d62"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a6ac8995ead1f084a8dea1e65f194d0973800c7f571f6edd70adf06ecf77084"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5a48c72f299d80557c7c62e37e7225369ecc0c963964059509fbafe917c7549"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e7811dd7f9398f14cc76efd356f98f03aa30419dea46aa810d71e819fc97158"
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.46"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "222b1ef9334f92a21d3fb53dc3fd80f30836959a90f9274a626d7e06315ba3c3"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
@@ -1,14 +0,0 @@
|
||||
[package]
|
||||
name = "fgvpn_server"
|
||||
version = "0.1.0"
|
||||
authors = []
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
name = "fgvpn_server"
|
||||
path = "src/lib.rs"
|
||||
crate-type = ["dylib"]
|
||||
|
||||
[dependencies]
|
||||
rustler = "0.22.0-rc.0"
|
||||
boringtun = "0.3.0"
|
||||
@@ -1,22 +0,0 @@
|
||||
# NIF for Elixir.FgVpn.Server
|
||||
|
||||
## To build the NIF module:
|
||||
|
||||
- Make sure your projects `mix.exs` has the `:rustler` compiler listed in the `project` function: `compilers: [:rustler] ++ Mix.compilers()` If there already is a `:compilers` list, you should append `:rustler` to it.
|
||||
- Add your crate to the `rustler_crates` attribute in the `project function. [See here](https://hexdocs.pm/rustler/basics.html#crate-configuration).
|
||||
- Your NIF will now build along with your project.
|
||||
|
||||
## To load the NIF:
|
||||
|
||||
```elixir
|
||||
defmodule FgVpn.Server do
|
||||
use Rustler, otp_app: :fg_vpn, crate: "fgvpn_server"
|
||||
|
||||
# When your NIF is loaded, it will override this function.
|
||||
def add(_a, _b), do: :erlang.nif_error(:nif_not_loaded)
|
||||
end
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
[This](https://github.com/hansihe/NifIo) is a complete example of a NIF written in Rust.
|
||||
@@ -1,6 +0,0 @@
|
||||
#[rustler::nif]
|
||||
fn add(a: i64, b: i64) -> i64 {
|
||||
a + b
|
||||
}
|
||||
|
||||
rustler::init!("Elixir.FgVpn.Server", [add]);
|
||||
54
apps/fg_vpn/test/fg_vpn/cli/sandbox_test.exs
Normal file
54
apps/fg_vpn/test/fg_vpn/cli/sandbox_test.exs
Normal file
@@ -0,0 +1,54 @@
|
||||
defmodule FgVpn.CLI.SandboxTest do
|
||||
use ExUnit.Case, async: true
|
||||
|
||||
import FgVpn.CLI
|
||||
|
||||
@expected_returned ""
|
||||
|
||||
test "egress_interface" do
|
||||
assert is_binary(cli().egress_interface())
|
||||
end
|
||||
|
||||
test "setup" do
|
||||
assert cli().setup() == @expected_returned
|
||||
end
|
||||
|
||||
test "teardown" do
|
||||
assert cli().teardown() == @expected_returned
|
||||
end
|
||||
|
||||
test "genkey" do
|
||||
{privkey, pubkey} = cli().genkey()
|
||||
|
||||
assert is_binary(privkey)
|
||||
assert is_binary(pubkey)
|
||||
end
|
||||
|
||||
test "pubkey" do
|
||||
{privkey, _pubkey} = cli().genkey()
|
||||
pubkey = cli().pubkey(privkey)
|
||||
|
||||
assert is_binary(pubkey)
|
||||
assert String.length(pubkey) == 44
|
||||
end
|
||||
|
||||
test "exec!" do
|
||||
assert cli().exec!("dummy") == @expected_returned
|
||||
end
|
||||
|
||||
test "set" do
|
||||
assert cli().set("dummy") == @expected_returned
|
||||
end
|
||||
|
||||
test "show_latest_handshakes" do
|
||||
assert cli().show_latest_handshakes() == "4 seconds ago"
|
||||
end
|
||||
|
||||
test "show_persistent_keepalives" do
|
||||
assert cli().show_persistent_keepalives() == "every 25 seconds"
|
||||
end
|
||||
|
||||
test "show_transfer" do
|
||||
assert cli().show_transfer() == "4.60 MiB received, 59.21 MiB sent"
|
||||
end
|
||||
end
|
||||
@@ -1,22 +0,0 @@
|
||||
defmodule FgVpn.CLITest do
|
||||
use ExUnit.Case, async: true
|
||||
|
||||
alias FgVpn.CLI
|
||||
|
||||
test "default_interface" do
|
||||
assert is_binary(CLI.default_interface())
|
||||
end
|
||||
|
||||
test "genkey" do
|
||||
{privkey, pubkey} = CLI.genkey()
|
||||
|
||||
assert is_binary(privkey)
|
||||
assert is_binary(pubkey)
|
||||
end
|
||||
|
||||
test "pubkey" do
|
||||
{privkey, pubkey} = CLI.genkey()
|
||||
|
||||
assert pubkey == CLI.pubkey(privkey)
|
||||
end
|
||||
end
|
||||
@@ -1,128 +1,32 @@
|
||||
defmodule FgVpn.ConfigTest do
|
||||
use ExUnit.Case, async: true
|
||||
alias FgVpn.Config
|
||||
alias FgVpn.{Config, Peer}
|
||||
|
||||
@test_privkey "GMqk2P3deotcQqgqJHfLGB1JtU//f1FgX868bfPKSVc="
|
||||
@default_config "private-key UAeZoaY95pKZE1Glq28sI2GJDfGGRFtlb4KC6rjY2Gs= listen-port 51820 "
|
||||
@populated_config "private-key UAeZoaY95pKZE1Glq28sI2GJDfGGRFtlb4KC6rjY2Gs= listen-port 1 peer test-pubkey allowed-ips test-allowed-ips preshared-key test-preshared-key"
|
||||
|
||||
@empty """
|
||||
"""
|
||||
describe "render" do
|
||||
test "renders default config" do
|
||||
config = %Config{}
|
||||
|
||||
@single_peer """
|
||||
# BEGIN PEER test-pubkey
|
||||
[Peer]
|
||||
PublicKey = test-pubkey
|
||||
AllowedIPs = 0.0.0.0/0, ::/0
|
||||
# END PEER test-pubkey
|
||||
"""
|
||||
|
||||
@privkey """
|
||||
[Interface]
|
||||
ListenPort = 51820
|
||||
PrivateKey = GMqk2P3deotcQqgqJHfLGB1JtU//f1FgX868bfPKSVc=
|
||||
"""
|
||||
|
||||
@rendered_privkey "kPCNOTbBoHC/j5daxhMHcZ+PeNr6oaA8qIWcBuFlM0s="
|
||||
|
||||
@rendered_config """
|
||||
# This file is being managed by the fireguard systemd service. Any changes
|
||||
# will be overwritten eventually.
|
||||
|
||||
[Interface]
|
||||
ListenPort = 51820
|
||||
PrivateKey = kPCNOTbBoHC/j5daxhMHcZ+PeNr6oaA8qIWcBuFlM0s=
|
||||
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o noop -j MASQUERADE
|
||||
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o noop -j MASQUERADE
|
||||
|
||||
# BEGIN PEER test-pubkey
|
||||
[Peer]
|
||||
PublicKey = test-pubkey
|
||||
AllowedIPs = 0.0.0.0/0, ::/0
|
||||
# END PEER test-pubkey
|
||||
"""
|
||||
|
||||
def write_config(config) do
|
||||
Application.get_env(:fg_vpn, :wireguard_conf_path)
|
||||
|> File.write!(config)
|
||||
end
|
||||
|
||||
describe "state" do
|
||||
setup %{stubbed_config: config} do
|
||||
write_config(config)
|
||||
test_pid = start_supervised!(Config)
|
||||
|
||||
on_exit(fn ->
|
||||
Application.get_env(:fg_vpn, :wireguard_conf_path)
|
||||
|> File.rm!()
|
||||
end)
|
||||
|
||||
%{test_pid: test_pid}
|
||||
assert Config.render(config) == @default_config
|
||||
end
|
||||
|
||||
@tag stubbed_config: @privkey
|
||||
test "parses PrivateKey from config file", %{test_pid: test_pid} do
|
||||
assert %{
|
||||
uncommitted_peers: %MapSet{},
|
||||
peers: %MapSet{},
|
||||
default_int: _,
|
||||
privkey: @test_privkey
|
||||
} = :sys.get_state(test_pid)
|
||||
end
|
||||
test "renders populated config" do
|
||||
config = %Config{
|
||||
listen_port: 1,
|
||||
peers:
|
||||
MapSet.new([
|
||||
%Peer{
|
||||
public_key: "test-pubkey",
|
||||
allowed_ips: "test-allowed-ips",
|
||||
preshared_key: "test-preshared-key"
|
||||
}
|
||||
]),
|
||||
uncommitted_peers: MapSet.new(["uncommitted-pubkey"])
|
||||
}
|
||||
|
||||
@tag stubbed_config: @single_peer
|
||||
test "parses peers from config file", %{test_pid: test_pid} do
|
||||
assert %{
|
||||
uncommitted_peers: %MapSet{},
|
||||
peers: %MapSet{},
|
||||
default_int: _,
|
||||
privkey: _
|
||||
} = :sys.get_state(test_pid)
|
||||
end
|
||||
|
||||
@tag stubbed_config: @empty
|
||||
test "generates new peer when requested", %{test_pid: test_pid} do
|
||||
send(test_pid, {:new_device})
|
||||
|
||||
# XXX: Avoid sleeping
|
||||
Process.sleep(100)
|
||||
|
||||
assert [_] = MapSet.to_list(:sys.get_state(test_pid)[:uncommitted_peers])
|
||||
assert [] = MapSet.to_list(:sys.get_state(test_pid)[:peers])
|
||||
end
|
||||
|
||||
@tag stubbed_config: @empty
|
||||
test "writes peers to config when device is verified", %{test_pid: test_pid} do
|
||||
send(test_pid, {:new_device})
|
||||
Process.sleep(100)
|
||||
|
||||
[pubkey | _tail] = MapSet.to_list(:sys.get_state(test_pid)[:uncommitted_peers])
|
||||
|
||||
send(test_pid, {:commit_device, pubkey})
|
||||
|
||||
# XXX: Avoid sleeping
|
||||
Process.sleep(100)
|
||||
|
||||
assert MapSet.to_list(:sys.get_state(test_pid)[:peers]) == [pubkey]
|
||||
end
|
||||
|
||||
@tag stubbed_config: @single_peer
|
||||
test "removes peers from config when device is removed", %{test_pid: test_pid} do
|
||||
send(test_pid, {:remove_device, "test-pubkey"})
|
||||
|
||||
# XXX: Avoid sleeping
|
||||
Process.sleep(100)
|
||||
|
||||
assert MapSet.to_list(:sys.get_state(test_pid)[:peers]) == []
|
||||
end
|
||||
end
|
||||
|
||||
describe "loading / rendering" do
|
||||
test "renders config" do
|
||||
assert Config.render(%{
|
||||
default_int: "noop",
|
||||
privkey: @rendered_privkey,
|
||||
peers: MapSet.new(["test-pubkey"]),
|
||||
uncommitted_peers: MapSet.new([])
|
||||
}) == @rendered_config
|
||||
assert Config.render(config) == @populated_config
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
56
apps/fg_vpn/test/fg_vpn/server_test.exs
Normal file
56
apps/fg_vpn/test/fg_vpn/server_test.exs
Normal file
@@ -0,0 +1,56 @@
|
||||
defmodule FgVpn.ServerTest do
|
||||
use ExUnit.Case, async: true
|
||||
alias FgVpn.{Config, Peer, Server}
|
||||
import FgVpn.CLI
|
||||
|
||||
@empty %Config{}
|
||||
@single_peer %Config{peers: MapSet.new([%Peer{public_key: "test-pubkey"}])}
|
||||
|
||||
describe "state" do
|
||||
setup %{stubbed_config: config} do
|
||||
test_pid = start_supervised!(Server)
|
||||
|
||||
GenServer.cast(test_pid, {:set_config, config})
|
||||
|
||||
on_exit(fn -> cli().teardown() end)
|
||||
|
||||
%{test_pid: test_pid}
|
||||
end
|
||||
|
||||
@tag stubbed_config: @empty
|
||||
test "generates new peer when requested", %{test_pid: test_pid} do
|
||||
send(test_pid, {:new_peer})
|
||||
|
||||
# XXX: Avoid sleeping
|
||||
Process.sleep(100)
|
||||
|
||||
assert [_peer] = MapSet.to_list(:sys.get_state(test_pid).uncommitted_peers)
|
||||
assert [] = MapSet.to_list(:sys.get_state(test_pid).peers)
|
||||
end
|
||||
|
||||
@tag stubbed_config: @empty
|
||||
test "writes peers to config when device is verified", %{test_pid: test_pid} do
|
||||
send(test_pid, {:new_peer})
|
||||
Process.sleep(100)
|
||||
|
||||
[pubkey | _tail] = MapSet.to_list(:sys.get_state(test_pid).uncommitted_peers)
|
||||
|
||||
send(test_pid, {:commit_peer, %{public_key: pubkey}})
|
||||
|
||||
# XXX: Avoid sleeping
|
||||
Process.sleep(100)
|
||||
|
||||
assert MapSet.to_list(:sys.get_state(test_pid).peers) == [%Peer{public_key: pubkey}]
|
||||
end
|
||||
|
||||
@tag stubbed_config: @single_peer
|
||||
test "removes peers from config when removed", %{test_pid: test_pid} do
|
||||
send(test_pid, {:remove_peer, "test-pubkey"})
|
||||
|
||||
# XXX: Avoid sleeping
|
||||
Process.sleep(100)
|
||||
|
||||
assert MapSet.to_list(:sys.get_state(test_pid).peers) == []
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -29,11 +29,12 @@ config :fg_http,
|
||||
|
||||
# This will be changed per-env
|
||||
config :fg_vpn,
|
||||
wireguard_conf_path: "/opt/fireguard/wg-fireguard.conf"
|
||||
private_key: "UAeZoaY95pKZE1Glq28sI2GJDfGGRFtlb4KC6rjY2Gs=",
|
||||
cli: FgVpn.CLI.Sandbox
|
||||
|
||||
# This will be changed per-env by ENV vars
|
||||
config :fg_http,
|
||||
vpn_endpoint: "localhost:51820"
|
||||
vpn_endpoint: "127.0.0.1:51820"
|
||||
|
||||
# Configures the endpoint
|
||||
# These will be overridden at runtime in production by config/releases.exs
|
||||
|
||||
@@ -71,9 +71,6 @@ config :fg_http, FgHttpWeb.Endpoint,
|
||||
]
|
||||
]
|
||||
|
||||
config :fg_vpn,
|
||||
wireguard_conf_path: Path.expand("~/.wg-fireguard.conf")
|
||||
|
||||
config :fg_http,
|
||||
disable_signup:
|
||||
(case System.get_env("DISABLE_SIGNUP") do
|
||||
|
||||
@@ -70,7 +70,8 @@ config :fg_http, FgHttpWeb.Endpoint,
|
||||
server: true,
|
||||
force_ssl: [rewrite_on: [:x_forwarded_proto], hsts: true, host: nil]
|
||||
|
||||
config :fg_vpn, wireguard_conf_path: "/opt/fireguard/wg-fireguard.conf"
|
||||
config :fg_vpn,
|
||||
cli: FgVpn.CLI.Live
|
||||
|
||||
# Do not print debug messages in production
|
||||
config :logger, level: :info
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
# remember to add this file to your .gitignore.
|
||||
import Config
|
||||
|
||||
@default_egress_address_cmd "ip route get 8.8.8.8 | grep -oP 'src \\K\\S+'"
|
||||
|
||||
# Required environment variables
|
||||
database_url =
|
||||
System.get_env("DATABASE_URL") ||
|
||||
@@ -52,11 +54,16 @@ ssl_ca_cert_file =
|
||||
s = _ -> s
|
||||
end
|
||||
|
||||
def default_egress_address do
|
||||
FgVpn.CLI.Live.exec!(@default_egress_address_cmd)
|
||||
|> String.trim()
|
||||
end
|
||||
|
||||
# Optional environment variables
|
||||
pool_size = String.to_integer(System.get_env("POOL_SIZE") || "10")
|
||||
https_listen_port = String.to_integer(System.get_env("HTTPS_LISTEN_PORT") || "8800")
|
||||
wg_listen_port = System.get_env("WG_LISTEN_PORT" || "51820")
|
||||
wg_listen_address = System.get_env("WG_LISTEN_ADDRESS") || "localhost"
|
||||
wg_endpoint_address = System.get_env("WG_ENDPOINT_ADDRESS") || default_egress_address()
|
||||
url_host = System.get_env("URL_HOST") || "localhost"
|
||||
|
||||
config :fg_http, disable_signup: disable_signup
|
||||
@@ -86,7 +93,8 @@ config :fg_http, FgHttpWeb.Endpoint,
|
||||
]
|
||||
|
||||
config :fg_vpn,
|
||||
vpn_endpoint: wg_listen_address <> ":" <> wg_listen_port
|
||||
vpn_endpoint: wg_endpoint_address <> ":" <> wg_listen_port,
|
||||
private_key: File.read!("/opt/fireguard/server.key") |> String.trim()
|
||||
|
||||
# ## Using releases (Elixir v1.9+)
|
||||
#
|
||||
|
||||
@@ -25,9 +25,6 @@ config :fg_http, FgHttp.Repo, DBConfig.config(db_url)
|
||||
|
||||
config :fg_http, FgHttp.Mailer, adapter: Bamboo.TestAdapter
|
||||
|
||||
config :fg_vpn,
|
||||
wireguard_conf_path: Path.expand("#{__DIR__}/../apps/fg_vpn/test/fixtures/wg-fireguard.conf")
|
||||
|
||||
# We don't run a server during test. If one is required,
|
||||
# you can enable the server option below.
|
||||
config :fg_http, FgHttpWeb.Endpoint,
|
||||
@@ -40,3 +37,6 @@ config :fg_http, FgHttpWeb.Endpoint,
|
||||
|
||||
# Print only warnings and errors during test
|
||||
config :logger, level: :warn
|
||||
|
||||
config :fg_vpn,
|
||||
execute_iface_cmds: System.get_env("CI") === "true"
|
||||
|
||||
@@ -12,7 +12,7 @@ if id fireguard &>/dev/null; then
|
||||
echo "fireguard user exists... not creating."
|
||||
else
|
||||
echo "creating system user fireguard"
|
||||
useradd --system -G netdev fireguard
|
||||
useradd --system fireguard
|
||||
fi
|
||||
|
||||
# Generate app secrets
|
||||
@@ -29,9 +29,6 @@ sudo -i -u postgres psql -c "CREATE ROLE ${db_user} WITH LOGIN PASSWORD '${db_pa
|
||||
sudo -i -u postgres psql -c "CREATE DATABASE fireguard;" || true
|
||||
sudo -i -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE fireguard to ${db_user};" || true
|
||||
|
||||
# Generate WireGuard privkey
|
||||
privkey=$(wg genkey)
|
||||
|
||||
# Write FireGuard SSL files
|
||||
mkdir -p /opt/fireguard/ssl
|
||||
chown -R fireguard:root /opt/fireguard/ssl
|
||||
@@ -45,9 +42,7 @@ chmod 0644 /opt/fireguard/ssl/cert.pem
|
||||
|
||||
# Write FireGuard config files
|
||||
touch /opt/fireguard/config.env
|
||||
touch /opt/fireguard/wg-fireguard.conf
|
||||
chmod 0600 /opt/fireguard/config.env
|
||||
chmod 0660 /opt/fireguard/wg-fireguard.conf
|
||||
chown -R fireguard:root /opt/fireguard
|
||||
cat <<EOT >> /opt/fireguard/config.env
|
||||
# This file is loaded into FireGuard's Environment upon launch to configure it.
|
||||
@@ -69,14 +64,15 @@ DATABASE_URL="ecto://${db_user}:${db_password}@127.0.0.1/fireguard"
|
||||
# The HTTPS port to listen on. Defaults to 8800.
|
||||
HTTPS_LISTEN_PORT=8800
|
||||
|
||||
# The address to bind the HTTPS server to. Defaults to "0.0.0.0"
|
||||
HTTPS_LISTEN_ADDRESS=0.0.0.0
|
||||
# The address to bind the HTTPS server to. Defaults to "127.0.0.1"
|
||||
HTTPS_LISTEN_ADDRESS=127.0.0.1
|
||||
|
||||
# The WireGuard port to listen on. Defaults to 51820.
|
||||
WG_LISTEN_PORT=51820
|
||||
|
||||
# The address to bind the WireGuard service to. Defaults to "0.0.0.0"
|
||||
WG_LISTEN_ADDRESS=0.0.0.0
|
||||
# The address for the WireGuard endpoint. Defaults to the address of the
|
||||
# default egress interface if not set.
|
||||
WG_ENDPOINT_ADDRESS=
|
||||
|
||||
# SSL certificate file and key path. Self-signed certs are generated for you on
|
||||
# install, but it's highly recommended to replace these with valid certs.
|
||||
@@ -94,3 +90,6 @@ URL_HOST=${hostname}
|
||||
# For public-facing sites, it's recommended to leave signups disabled.
|
||||
DISABLE_SIGNUP=yes
|
||||
EOT
|
||||
|
||||
umask 077
|
||||
wg genkey > /opt/fireguard/server.key
|
||||
|
||||
@@ -7,6 +7,7 @@ After=postgresql.service
|
||||
Restart=on-failure
|
||||
RestartSec=1
|
||||
User=fireguard
|
||||
CapabilityBindingSet=CAP_NET_ADMIN
|
||||
EnvironmentFile=/opt/fireguard/config.env
|
||||
ExecStartPre=/opt/fireguard/bin/fireguard eval "FgHttp.Release.migrate"
|
||||
ExecStart=/opt/fireguard/bin/fireguard start
|
||||
|
||||
10
scripts/generate_keypairs.sh
Executable file
10
scripts/generate_keypairs.sh
Executable file
@@ -0,0 +1,10 @@
|
||||
#!/usr/bin/env zsh
|
||||
set -e
|
||||
|
||||
# Generates 10 WireGuard keypairs for use in Dev/Test environments.
|
||||
# Do not use in Prod.
|
||||
repeat 10 {
|
||||
key=$(wg genkey | tee >(wg pubkey))
|
||||
parts=("${(f)key}")
|
||||
echo $parts
|
||||
}
|
||||
Reference in New Issue
Block a user