From 86969f07ca4a76c5b981fec1062cc2280d7f0248 Mon Sep 17 00:00:00 2001
From: Hristo Venev <hristo@venev.name>
Date: Sun, 10 Nov 2019 13:24:27 +0000
Subject: Add netifd protocol script.

---
 dist/netifd/wgconfd.sh | 213 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 213 insertions(+)
 create mode 100755 dist/netifd/wgconfd.sh

(limited to 'dist')

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
+}
-- 
cgit