aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xdist/netifd/wgconfd.sh213
1 files changed, 213 insertions, 0 deletions
diff --git a/dist/netifd/wgconfd.sh b/dist/netifd/wgconfd.sh
new file mode 100755
index 0000000..1fa6aba
--- /dev/null
+++ b/dist/netifd/wgconfd.sh
@@ -0,0 +1,213 @@
+#!/bin/sh
+
+WG=/usr/bin/wg
+if [ ! -x "$WG" ]; then
+ logger -t "wgconfd" "error: missing wgconfd (${WG})"
+ exit 1
+fi
+
+CURL=/usr/bin/curl
+if [ ! -x "$CURL" ]; then
+ logger -t "wgconfd" "error: missing curl (${CURL})"
+ exit 1
+fi
+
+WGCONFD=/usr/bin/wgconfd
+if [ ! -x "$WGCONFD" ]; then
+ logger -t "wgconfd" "error: missing wgconfd (${WGCONFD})"
+ exit 1
+fi
+
+[ -n "$INCLUDE_ONLY" ] || {
+ . /lib/functions.sh
+ . ../netifd-proto.sh
+ init_proto "$@"
+}
+
+proto_wgconfd_init_config() {
+ proto_config_add_array 'ipaddr:ipaddr'
+ proto_config_add_array 'ip6addr:ip6addr'
+ proto_config_add_int 'mtu'
+
+ proto_config_add_string 'private_key'
+ proto_config_add_int 'listen_port'
+ proto_config_add_string 'fwmark'
+
+ proto_config_add_int 'refresh_sec'
+ proto_config_add_int 'min_keepalive'
+ proto_config_add_int 'max_keepalive'
+
+ available=1
+}
+
+proto_wgconfd_setup__print() {
+ local i
+ for i; do
+ # TODO: escape
+ echo -n "$i "
+ done
+}
+
+proto_wgconfd_setup__source() {
+ local name val
+
+ config_get name "$1" name
+ [ -z "$name" ] && return
+ config_get val "$1" url
+ [ -z "$val" ] && return
+ proto_wgconfd_setup__print source "$name" "$val"
+
+ config_get val "$1" psk
+ [ -n "$val" ] && proto_wgconfd_setup__print psk "$val"
+
+ config_get_bool val "$1" required 0
+ [ "$val" -eq 1 ] && proto_wgconfd_setup__print required
+
+ config_list_foreach "$1" ipv4 proto_wgconfd_setup__source_route ipv4 32
+
+ config_list_foreach "$1" ipv6 proto_wgconfd_setup__source_route ipv6 128
+}
+
+proto_wgconfd_setup__source_route() {
+ local p="$2"
+ local maxlen="$3"
+ local route=1
+ set -- $1
+ local r="$1"
+ shift 1
+ local i
+ for i; do case "$i" in
+ no-route)
+ route=0
+ ;;
+ *)
+ true
+ ;;
+ esac; done
+ proto_wgconfd_setup__print "$p" "$r"
+ if [ "$route" -eq 1 ]; then
+ case "$r" in
+ '')
+ true
+ ;;
+ */*)
+ echo "${p}_route ${r%/*} ${r##*/}" >> "$dir/update"
+ ;;
+ *)
+ echo "${p}_route $r $maxlen" >> "$dir/update"
+ ;;
+ esac
+ fi
+}
+
+proto_wgconfd_setup__peer() {
+ local val
+
+ config_get val "$1" key
+ [ -z "$val" ] && return
+ proto_wgconfd_setup__print public_key "$val"
+
+ config_get val "$1" psk
+ [ -n "$val" ] && proto_wgconfd_setup__print psk "$val"
+
+ config_get val "$1" source
+ [ -n "$val" ] && proto_wgconfd_setup__print source "$val"
+}
+
+proto_wgconfd__echo_addr() {
+ case "$1" in
+ '')
+ true
+ ;;
+ */*)
+ echo "${3}_address ${1%/*} ${1##*/}" >> "$dir/update"
+ ;;
+ *)
+ echo "${3}_address $1 $4" >> "$dir/update"
+ ;;
+ esac
+}
+
+proto_wgconfd_setup() {
+ local interface="$1" ifname="$2" i r
+ if [ -z "$ifname" ]; then
+ ifname="$interface"
+ fi
+
+ local mtu
+ local private_key listen_port fwmark
+ local refresh_sec min_keepalive max_keepalive
+ json_get_vars mtu private_key listen_port fwmark refresh_sec min_keepalive max_keepalive
+
+ if [ -z "$private_key" ]; then
+ proto_notify_error "$interface" NO_PRIVATE_KEY
+ proto_block_restart "$interface"
+ exit
+ fi
+
+ [ -n "$fwmark" ] && fwmark="fwmark $fwmark"
+
+ dir="/tmp/wgconfd/$interface"
+ if [ -d "$dir" ]; then
+ rm -rf "$dir"
+ fi
+ mkdir -p /tmp/wgconfd
+ if ! mkdir -m 0700 "$dir" || ! mkdir "$dir/cache" || ! echo "$private_key" > "$dir/private" || ! true > "$dir/update" ; then
+ proto_notify_error "$interface" FS_ERROR
+ return 1
+ fi
+
+ json_for_each_item proto_wgconfd__echo_addr ipaddr ipv4 32
+ json_for_each_item proto_wgconfd__echo_addr ip6addr ipv6 128
+
+ wgconfd_command="$(
+ proto_wgconfd_setup__print "$WGCONFD" --cmdline "$ifname"
+ config_load network
+ config_foreach proto_wgconfd_setup__source wgconfd_source_"$interface"
+ config_foreach proto_wgconfd_setup__peer wgconfd_peer_"$interface"
+ )"
+
+ ip link del dev "$ifname" 2>/dev/null
+ if ! ip link add dev "$ifname" mtu "${mtu:-1420}" type wireguard; then
+ proto_notify_error "$interface" IFACE_ERROR
+ exit
+ fi
+
+ "$WG" set "$ifname" private-key "$dir/private" listen-port "${listen_port:-656}" $fwmark
+ r="$?"
+ rm -f "$dir/private"
+ if [ "$r" != 0 ]; then
+ ip link del dev "$ifname" 2>/dev/null
+ proto_notify_error "$interface" WG_ERROR
+ exit
+ fi
+
+ proto_init_update "$ifname" 1 0
+ proto_set_keep 0
+ while read i r; do
+ proto_add_"$i" $r
+ done < "$dir/update"
+ # rm -f "$dir/update"
+ proto_send_update "$interface"
+
+
+ proto_export "WG=$WG"
+ proto_export "CURL=$CURL"
+ proto_export "RUNTIME_DIRECTORY=$dir"
+ proto_export "CACHE_DIRECTORY=$dir/cache"
+ proto_run_command "$interface" $wgconfd_command
+}
+
+proto_wgconfd_teardown() {
+ local interface="$1" ifname="$2" i r
+ if [ -z "$ifname" ]; then
+ ifname="$interface"
+ fi
+
+ proto_kill_command "$interface"
+ ip link del dev "$ifname" 2>/dev/null
+}
+
+[ -n "$INCLUDE_ONLY" ] || {
+ add_protocol wgconfd
+}