gluon-mesh-vpn-wireguard: initial support
This commit is contained in:
parent
b7e8ad33a4
commit
81b728b704
@ -65,6 +65,7 @@ Several Freifunk communities in Germany use Gluon as the foundation of their Fre
|
|||||||
package/gluon-ebtables-source-filter
|
package/gluon-ebtables-source-filter
|
||||||
package/gluon-hoodselector
|
package/gluon-hoodselector
|
||||||
package/gluon-mesh-batman-adv
|
package/gluon-mesh-batman-adv
|
||||||
|
package/gluon-mesh-vpn-wireguard
|
||||||
package/gluon-radv-filterd
|
package/gluon-radv-filterd
|
||||||
package/gluon-scheduled-domain-switch
|
package/gluon-scheduled-domain-switch
|
||||||
package/gluon-web-admin
|
package/gluon-web-admin
|
||||||
|
53
docs/package/gluon-mesh-vpn-wireguard.rst
Executable file
53
docs/package/gluon-mesh-vpn-wireguard.rst
Executable file
@ -0,0 +1,53 @@
|
|||||||
|
gluon-mesh-vpn-wireguard
|
||||||
|
========================
|
||||||
|
|
||||||
|
This package allows WireGuard [1] to be used in Gluon. WireGuard establishes
|
||||||
|
VPN connections on OSI layer 3 allowing increased throughput in comparison with
|
||||||
|
fastd for mesh protocols that operate on layer 3 too.
|
||||||
|
|
||||||
|
When starting WireGuard, the system requires some entropy. It is recommended to
|
||||||
|
use haveged to avoid long startup times.
|
||||||
|
|
||||||
|
[1] https://wireguard.io
|
||||||
|
|
||||||
|
site.conf
|
||||||
|
---------
|
||||||
|
This is similar to the fastd-based mesh_vpn structure.
|
||||||
|
|
||||||
|
Example::
|
||||||
|
|
||||||
|
mesh_vpn = {
|
||||||
|
mtu = 1374,
|
||||||
|
wireguard = {
|
||||||
|
enabled = true,
|
||||||
|
groups = {
|
||||||
|
backbone = {
|
||||||
|
limit = 2,
|
||||||
|
peers = {
|
||||||
|
gw02 = {
|
||||||
|
enabled = true,
|
||||||
|
key = 'bog2DzyiC0Os7y1GloEw0afb8bLdZ9SzVQCd44Eock4=',
|
||||||
|
remote = 'gw02.babel.ffm.freifunk.net',
|
||||||
|
broker_port = 40000,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
Server Side Configuration
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
* The wireguard private key must be deployed, and the derived Public Key has to be in site.conf
|
||||||
|
* The wg-broker-server script must be running on the server and be listening on
|
||||||
|
the broker_port
|
||||||
|
* The node must be able to reach the server using TCP-Port broker_port and it
|
||||||
|
must be able to communicate with the server using one UDP port between 40000
|
||||||
|
and 41000.
|
||||||
|
|
||||||
|
On dockerhub there is an image klausdieter371/wg-docker integrating the
|
||||||
|
server-side components. Please refer to its documentation to set up the server
|
||||||
|
part. The Code and Documentation are kept here:
|
||||||
|
https://github.com/FreifunkMD/wg-docker
|
||||||
|
|
@ -9,7 +9,7 @@ packages 'web-wizard' \
|
|||||||
packages 'web-wizard & autoupdater' \
|
packages 'web-wizard & autoupdater' \
|
||||||
'gluon-config-mode-autoupdater'
|
'gluon-config-mode-autoupdater'
|
||||||
|
|
||||||
packages 'web-wizard & (mesh-vpn-fastd | mesh-vpn-tunneldigger)' \
|
packages 'web-wizard & (mesh-vpn-fastd | mesh-vpn-tunneldigger | mesh-vpn-wireguard)' \
|
||||||
'gluon-config-mode-mesh-vpn'
|
'gluon-config-mode-mesh-vpn'
|
||||||
|
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ elseif has_fastd then
|
|||||||
elseif has_wireguard then
|
elseif has_wireguard then
|
||||||
local wireguard_enabled = uci:get_bool("wireguard", "mesh_vpn", "enabled")
|
local wireguard_enabled = uci:get_bool("wireguard", "mesh_vpn", "enabled")
|
||||||
if wireguard_enabled then
|
if wireguard_enabled then
|
||||||
local secret = util.trim(util.exec("/usr/bin/gluon-mesh-vpn-wireguard-get-or-create-secret"))
|
local secret = uci:get("wireguard", "mesh_vpn", "secret")
|
||||||
pubkey = util.trim(util.exec("/usr/bin/wg pubkey < " .. secret))
|
pubkey = util.trim(util.exec("/usr/bin/wg pubkey < " .. secret))
|
||||||
msg = site_i18n._translate('gluon-config-mode:pubkey')
|
msg = site_i18n._translate('gluon-config-mode:pubkey')
|
||||||
else
|
else
|
||||||
|
19
package/gluon-mesh-vpn-wireguard/Makefile
Executable file
19
package/gluon-mesh-vpn-wireguard/Makefile
Executable file
@ -0,0 +1,19 @@
|
|||||||
|
include $(TOPDIR)/rules.mk
|
||||||
|
|
||||||
|
PKG_NAME:=gluon-mesh-vpn-wireguard
|
||||||
|
PKG_VERSION:=3
|
||||||
|
|
||||||
|
include ../gluon.mk
|
||||||
|
|
||||||
|
PKG_CONFIG_DEPENDS += $(GLUON_I18N_CONFIG)
|
||||||
|
|
||||||
|
define Package/gluon-mesh-vpn-wireguard
|
||||||
|
TITLE:=WireGuard Mesh VPN Support
|
||||||
|
DEPENDS:=+gluon-core +gluon-mesh-vpn-core +kmod-wireguard +jsonfilter +wireguard-tools +micrond +@BUSYBOX_CONFIG_TIMEOUT
|
||||||
|
endef
|
||||||
|
|
||||||
|
define Package/gluon-mesh-vpn-wireguard/description
|
||||||
|
Support layer 3 mesh-vpn connection using wireguard. This can be used by mesh-protocols working on OSI layer 3.
|
||||||
|
endef
|
||||||
|
|
||||||
|
$(eval $(call BuildPackageGluon,gluon-mesh-vpn-wireguard))
|
17
package/gluon-mesh-vpn-wireguard/check_site.lua
Normal file
17
package/gluon-mesh-vpn-wireguard/check_site.lua
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
local function check_peer(k)
|
||||||
|
need_alphanumeric_key(k)
|
||||||
|
|
||||||
|
need_string_match(in_domain(extend(k, {'key'})), '[%w]+=*')
|
||||||
|
need_string_match(in_domain(extend(k, {'remote'})), '[%w_-.]')
|
||||||
|
need_number(in_domain(extend(k, {'broker_port'})), false)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function check_group(k)
|
||||||
|
need_alphanumeric_key(k)
|
||||||
|
|
||||||
|
need_number(extend(k, {'limit'}), false)
|
||||||
|
need_table(extend(k, {'peers'}), check_peer, false)
|
||||||
|
need_table(extend(k, {'groups'}), check_group, false)
|
||||||
|
end
|
||||||
|
|
||||||
|
need_table({'mesh_vpn', 'wireguard', 'groups'}, check_group)
|
@ -0,0 +1,7 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
touch /etc/config/gluon_mesh_vpn_wireguard
|
||||||
|
uci set gluon_mesh_vpn_wireguard.mesh_vpn="backbone"
|
||||||
|
|
||||||
|
if ! uci get gluon_mesh_vpn_wireguard.mesh_vpn.secret 2>/dev/null| wg pubkey 2>/dev/null; then
|
||||||
|
uci set gluon_mesh_vpn_wireguard.mesh_vpn.secret="generate"
|
||||||
|
fi
|
94
package/gluon-mesh-vpn-wireguard/files/lib/netifd/proto/gluon_wireguard.sh
Executable file
94
package/gluon-mesh-vpn-wireguard/files/lib/netifd/proto/gluon_wireguard.sh
Executable file
@ -0,0 +1,94 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Copyright 2016-2017 Christof Schulze <christof@christofschulze.com>
|
||||||
|
# Licensed to the public under the Apache License 2.0.
|
||||||
|
|
||||||
|
. /lib/functions.sh
|
||||||
|
. ../netifd-proto.sh
|
||||||
|
init_proto "$@"
|
||||||
|
|
||||||
|
proto_gluon_wireguard_init_config() {
|
||||||
|
no_device=1
|
||||||
|
available=1
|
||||||
|
renew_handler=1
|
||||||
|
}
|
||||||
|
|
||||||
|
proto_gluon_wireguard_renew() {
|
||||||
|
local config="$1"
|
||||||
|
echo "wireguard RENEW: $*"
|
||||||
|
ifdown "$config"
|
||||||
|
ifup "$config"
|
||||||
|
}
|
||||||
|
|
||||||
|
proto_gluon_wireguard_setup() {
|
||||||
|
local config="$1"
|
||||||
|
ifname="$(uci get "network.$config.ifname")" # we need uci here because nodevice=1 means the device is not part of the ubus structure
|
||||||
|
|
||||||
|
local peer_limit=$(gluon-show-site |jsonfilter -e $.mesh_vpn.wireguard.groups.backbone.limit)
|
||||||
|
if [[ $(wg show all latest-handshakes |wc -l) -ge "$peer_limit" ]]; then
|
||||||
|
echo "not establishing another connection, we already have $peer_limit connections." >&2
|
||||||
|
ip link del "$ifname"
|
||||||
|
ifdown "$config"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
(
|
||||||
|
flock -n 9
|
||||||
|
|
||||||
|
if [[ $(uci get gluon.mesh_vpn.enabled) -eq 1 ]]; then
|
||||||
|
ip link del "$ifname"
|
||||||
|
ip link add dev "$ifname" type wireguard
|
||||||
|
ip link set mtu "$(gluon-show-site | jsonfilter -e $.mesh_vpn.mtu)" dev "$ifname"
|
||||||
|
ip link set multicast on dev "$ifname"
|
||||||
|
|
||||||
|
mkdir -p /var/gluon/mesh-vpn-wireguard
|
||||||
|
secretfile=/var/gluon/mesh-vpn-wireguard/secret
|
||||||
|
secret=$(gluon-mesh-vpn-wireguard-get-or-create-secret)
|
||||||
|
|
||||||
|
echo "$secret" > "$secretfile"
|
||||||
|
pubkey=$(echo "$secret"| wg pubkey)
|
||||||
|
|
||||||
|
gwname=${config##*_}
|
||||||
|
peer=${gwname%?}
|
||||||
|
|
||||||
|
peer_config=$(gluon-show-site |jsonfilter -e "$.mesh_vpn.wireguard.groups.backbone.peers.$peer")
|
||||||
|
remote=$(jsonfilter -s "$peer_config" -e "$.remote")
|
||||||
|
brokerport=$(jsonfilter -s "$peer_config" -e "$.broker_port")
|
||||||
|
peer_key=$(jsonfilter -s "$peer_config" -e "$.key")
|
||||||
|
remoteport=$(/usr/bin/wg-broker-client "$ifname" "$pubkey" "$remote" "$brokerport")
|
||||||
|
|
||||||
|
if [[ "$remoteport" == "FULL" ]]; then
|
||||||
|
echo "wireguard server $remote is not accepting additional connections. Closing this interface" >&2
|
||||||
|
ip link del "$ifname"
|
||||||
|
exit 1
|
||||||
|
elif [[ "$remoteport" == "ERROR" ]]; then
|
||||||
|
echo "error when setting up wireguard connection for $ifname" >&2
|
||||||
|
ip link del "$ifname"
|
||||||
|
exit 1
|
||||||
|
elif [[ -z "$remoteport" ]]; then
|
||||||
|
echo "error when setting up wireguard connection for $ifname - no response from broker: $remote" >&2
|
||||||
|
ip link del "$ifname"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
gluon-wan wg set "$ifname" private-key "$secretfile" peer "$peer_key" endpoint "$remote:$remoteport" allowed-ips ::/0 persistent-keepalive 25
|
||||||
|
|
||||||
|
ip link set dev "$ifname" up
|
||||||
|
ip -6 route add fe80::/64 dev "$ifname" proto kernel metric 256 pref medium table local
|
||||||
|
|
||||||
|
proto_init_update "$ifname" 1
|
||||||
|
proto_send_update "$config"
|
||||||
|
fi
|
||||||
|
) 9>"/var/lock/wireguard_proto_${ifname}.lock" || ifdown "$config"
|
||||||
|
}
|
||||||
|
|
||||||
|
proto_gluon_wireguard_teardown() {
|
||||||
|
local config="$1"
|
||||||
|
echo teardown config: "$config"
|
||||||
|
ifname=$(uci get "network.$config.ifname") # we need uci here because nodevice=1 means the device is not part of the ubus structure
|
||||||
|
|
||||||
|
ip link del "$ifname"
|
||||||
|
}
|
||||||
|
|
||||||
|
[[ -n "$INCLUDE_ONLY" ]] || {
|
||||||
|
add_protocol gluon_wireguard
|
||||||
|
}
|
19
package/gluon-mesh-vpn-wireguard/files/usr/bin/enable-all-wg-interfaces
Executable file
19
package/gluon-mesh-vpn-wireguard/files/usr/bin/enable-all-wg-interfaces
Executable file
@ -0,0 +1,19 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
get_down_wg_backbone_interfaces() {
|
||||||
|
ubus -S call network.interface dump | jsonfilter -e '@.interface[@.up=false && @.proto="gluon_wireguard"].interface'
|
||||||
|
}
|
||||||
|
|
||||||
|
is_wan_up() {
|
||||||
|
ubus -S call network.interface dump | jsonfilter -e '@.interface[@.up=true && @.interface="wan"].up'
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_wan_up >/dev/null; then
|
||||||
|
if [[ $(uci get gluon.mesh_vpn.enabled) == "1" ]]; then
|
||||||
|
for i in $(get_down_wg_backbone_interfaces)
|
||||||
|
do
|
||||||
|
ifup "$i"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
@ -0,0 +1,9 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
secret=$(uci get gluon_mesh_vpn_wireguard.mesh_vpn.secret)
|
||||||
|
if [[ "$secret" = "generate" ]]; then
|
||||||
|
secret="$(wg genkey)"
|
||||||
|
uci set gluon_mesh_vpn_wireguard.mesh_vpn.secret="$secret"
|
||||||
|
uci commit gluon_mesh_vpn_wireguard
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "$secret"
|
61
package/gluon-mesh-vpn-wireguard/files/usr/bin/wg-broker-client
Executable file
61
package/gluon-mesh-vpn-wireguard/files/usr/bin/wg-broker-client
Executable file
@ -0,0 +1,61 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
timeout=10
|
||||||
|
run_broker() {
|
||||||
|
local interface="$1"
|
||||||
|
local pubkey="$2"
|
||||||
|
local remote="$3"
|
||||||
|
local brokerport="$4"
|
||||||
|
local port
|
||||||
|
local interval=5
|
||||||
|
|
||||||
|
localtime=$(date +%s)
|
||||||
|
|
||||||
|
# sleeping on stdin keeps the sockets open in nc, allowing us to receive a
|
||||||
|
# reply. Unfortunately this means all requests take $timeout seconds even
|
||||||
|
# if the server is faster
|
||||||
|
peer_reply="$( { echo '{"version":1, "pubkey":"'"$pubkey"'"}'; sleep $timeout; } | gluon-wan timeout $timeout nc "$remote" "$brokerport" | tail -n1)"
|
||||||
|
|
||||||
|
if [[ "x$peer_reply" != "x" ]]; then
|
||||||
|
port=$(jsonfilter -s "$peer_reply" -e "@.port")
|
||||||
|
peer_time=$(jsonfilter -s "$peer_reply" -e "@.time")
|
||||||
|
|
||||||
|
difference=0
|
||||||
|
if [[ $peer_time -gt $localtime ]]; then
|
||||||
|
difference=$((peer_time - localtime))
|
||||||
|
else
|
||||||
|
difference=$((localtime - peer_time))
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "x$peer_time" != "x" && $difference -gt 240 ]]; then
|
||||||
|
# local clock differs a lot from the peer clock.
|
||||||
|
# assuming ntp is working only when a tunnel is established we need to
|
||||||
|
# set the clock to something in the proximity of the correct time.
|
||||||
|
# Let's assume peer_time for now. ntpd will handle the rest
|
||||||
|
formatted_time=$(date -d "@$peer_time" +%Y%m%d%H%M.%S)
|
||||||
|
date -s "$formatted_time" >/dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z $port ]]; then
|
||||||
|
error=$(jsonfilter -s "$peer_reply" -e "@.error")
|
||||||
|
if [[ -n $error ]]; then
|
||||||
|
reason=$(jsonfilter -s "$peer_reply" -e "@.error.reason")
|
||||||
|
ecode=$(jsonfilter -s "$peer_reply" -e "@.error.code")
|
||||||
|
echo "received error [$ecode] from host $remote: $reason" >&2
|
||||||
|
|
||||||
|
if [[ "$ecode" == "1" ]]; then
|
||||||
|
echo FULL
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
echo "$port"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
echo "Received no reply from peer $remote" >&2
|
||||||
|
echo "ERROR"
|
||||||
|
return 255
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
run_broker "$1" "$2" "$3" "$4"
|
40
package/gluon-mesh-vpn-wireguard/files/usr/bin/wgcheck
Executable file
40
package/gluon-mesh-vpn-wireguard/files/usr/bin/wgcheck
Executable file
@ -0,0 +1,40 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
curtime=$(date +%s)
|
||||||
|
|
||||||
|
get_wg_interfaces() {
|
||||||
|
ubus -S call network.interface dump | jsonfilter -e '@.interface[@.up=true && @.proto="gluon_wireguard"].l3_device'
|
||||||
|
}
|
||||||
|
|
||||||
|
get_connection_count() {
|
||||||
|
ubus -S call network.interface dump | jsonfilter -e '@.interface[@.up=true && @.proto="gluon_wireguard" && @].l3_device' | wc -l
|
||||||
|
}
|
||||||
|
|
||||||
|
get_interface_from_ifname() {
|
||||||
|
ubus -S call network.interface dump | jsonfilter -e "@.interface[@.proto=\"gluon_wireguard\" && @.l3_device=\"$1\"].interface"
|
||||||
|
}
|
||||||
|
|
||||||
|
# purge wg interface that have terminated
|
||||||
|
for i in $(get_wg_interfaces)
|
||||||
|
do
|
||||||
|
line=$(wg show "$i" latest-handshakes)
|
||||||
|
if [[ -n "${line}" ]]; then
|
||||||
|
latest=$(echo "${line}"| awk '{print $2}')
|
||||||
|
diff=$((curtime-latest))
|
||||||
|
if [[ $diff -gt 600 ]]; then
|
||||||
|
ifdown "$(get_interface_from_ifname "${i}")"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
ifdown "$(get_interface_from_ifname "${i}")"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# in case less than our peer-limit connections is "up", start all wg interfaces that are currently down
|
||||||
|
if [[ "$(uci get gluon.mesh_vpn.enabled)" == "1" ]] &&
|
||||||
|
[[ $(get_connection_count) -lt $(gluon-show-site |jsonfilter -e $.mesh_vpn.wireguard.groups.backbone.limit) ]]; then
|
||||||
|
if [[ $(get_connection_count) -gt 0 ]]; then
|
||||||
|
# it is ok to wait for a backup vpn connection. This sleep spreads the load for the servers
|
||||||
|
sleep "$(awk 'BEGIN{srand();print int(rand()*180)}')"
|
||||||
|
fi
|
||||||
|
/usr/bin/enable-all-wg-interfaces
|
||||||
|
fi
|
@ -0,0 +1 @@
|
|||||||
|
*/5 * * * * /usr/bin/wgcheck
|
61
package/gluon-mesh-vpn-wireguard/luasrc/lib/gluon/upgrade/405-wireguard
Executable file
61
package/gluon-mesh-vpn-wireguard/luasrc/lib/gluon/upgrade/405-wireguard
Executable file
@ -0,0 +1,61 @@
|
|||||||
|
#!/usr/bin/lua
|
||||||
|
local site = require 'gluon.site'
|
||||||
|
local uci = require('simple-uci').cursor()
|
||||||
|
local iputil = require 'gluon.iputil'
|
||||||
|
local sysconfig = require 'gluon.sysconfig'
|
||||||
|
|
||||||
|
local add_groups
|
||||||
|
|
||||||
|
local function generate_section_name(peer)
|
||||||
|
return "mesh_vpn_wg_" .. peer
|
||||||
|
end
|
||||||
|
|
||||||
|
local function generate_wg_iface_name(peer)
|
||||||
|
return "mesh-vpn-" .. peer
|
||||||
|
end
|
||||||
|
|
||||||
|
local function add_peer(name, count)
|
||||||
|
local ip = iputil.mac_to_ip("fe80::/64", sysconfig.primary_mac, 0x00, count)
|
||||||
|
|
||||||
|
uci:section('network', 'interface', generate_section_name(name) .. 'm', {
|
||||||
|
type = 'wireguard',
|
||||||
|
ifname = generate_wg_iface_name(count),
|
||||||
|
proto = 'gluon_mesh',
|
||||||
|
})
|
||||||
|
|
||||||
|
uci:section('network', 'interface', generate_section_name(name) .. 's', {
|
||||||
|
ip6addr = ip,
|
||||||
|
ifname = generate_wg_iface_name(count),
|
||||||
|
proto = 'static',
|
||||||
|
})
|
||||||
|
|
||||||
|
uci:section('network', 'interface', generate_section_name(name) .. 'w', {
|
||||||
|
ifname = generate_wg_iface_name(count),
|
||||||
|
proto = 'gluon_wireguard',
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
local function add_group(name, config)
|
||||||
|
local count=0
|
||||||
|
if config.peers then
|
||||||
|
for peername, _ in pairs(config.peers) do
|
||||||
|
add_peer(peername, count)
|
||||||
|
count = count + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
add_groups(name, config.groups)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- declared local above
|
||||||
|
function add_groups(prefix, groups)
|
||||||
|
if groups then
|
||||||
|
for name, group in pairs(groups) do
|
||||||
|
add_group(prefix .. '_' .. name, group)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
add_groups('mesh_vpn', site.mesh_vpn.wireguard.groups())
|
||||||
|
|
||||||
|
uci:save('network')
|
@ -18,6 +18,13 @@
|
|||||||
pubkey = nil
|
pubkey = nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
local wg_meshvpn_enabled = uci:get_bool("wireguard", "mesh_vpn_backbone", "enabled")
|
||||||
|
if wg_meshvpn_enabled then
|
||||||
|
pubkey = util.trim(util.exec('/usr/bin/wg pubkey < $(uci get wireguard.mesh_vpn.secret)'))
|
||||||
|
if pubkey == '' then
|
||||||
|
pubkey = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local values = {
|
local values = {
|
||||||
{ _('Hostname'), pretty_hostname.get(uci) },
|
{ _('Hostname'), pretty_hostname.get(uci) },
|
||||||
|
Loading…
Reference in New Issue
Block a user