nebula: implement netifd support 19586/head
authorStan Grishin <stangri@melmac.ca>
Tue, 11 Oct 2022 00:07:19 +0000 (00:07 +0000)
committerStan Grishin <stangri@melmac.ca>
Thu, 13 Oct 2022 21:05:50 +0000 (21:05 +0000)
This commit contains the following:
* Update binary to version 1.6.1
* Update README URLs in the Makefile to link OpenWrt-specific info
* Separate the binary, the init script and netifd script into 3 packages:
  nebula, nebula-service and nebula-proto accordingly
* implement yml parser for init script to fetch variables from it
* add the netifd script for nebula protocol
* update test file to address all built packages
* make the PKG_VERSION variable of init/proto scripts readonly

Signed-off-by: Stan Grishin <stangri@melmac.ca>
net/nebula/Makefile
net/nebula/files/nebula.init
net/nebula/files/nebula.proto [new file with mode: 0644]
net/nebula/test.sh

index 2fba0f3f8b98fbded204eaf631e36cff4d260290..2fdac24f57450c10cf883b88d6e446d34d8863ba 100644 (file)
@@ -4,12 +4,12 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=nebula
-PKG_VERSION:=1.6.0
+PKG_VERSION:=1.6.1
 PKG_RELEASE:=1
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
 PKG_SOURCE_URL:=https://codeload.github.com/slackhq/nebula/tar.gz/v$(PKG_VERSION)?
-PKG_HASH:=b16638b99d80a4ae6373f7757a0064dc0defd3f9e165617e7b5c3be9e64d3605
+PKG_HASH:=9c343d998d2eab9473c3bf73d434b8a382d90b1f73095dd1114ecaf2e1c0970f
 
 PKG_MAINTAINER:=Stan Grishin <stangri@melmac.ca>
 PKG_LICENSE:=MIT
@@ -33,7 +33,7 @@ define Package/nebula
   SECTION:=net
   CATEGORY:=Network
   TITLE:=nebula
-  URL:=https://github.com/slackhq/nebula
+  URL:=https://docs.openwrt.melmac.net/nebula/
   DEPENDS:=$(GO_ARCH_DEPENDS) +kmod-tun
 endef
 
@@ -41,40 +41,98 @@ define Package/nebula-cert
   SECTION:=net
   CATEGORY:=Network
   TITLE:=nebula-cert
-  URL:=https://github.com/slackhq/nebula
+  URL:=https://docs.openwrt.melmac.net/nebula/
   DEPENDS:=$(GO_ARCH_DEPENDS)
 endef
 
+define Package/nebula-proto
+  SECTION:=net
+  CATEGORY:=Network
+  TITLE:=nebula-proto
+  URL:=https://docs.openwrt.melmac.net/nebula/
+  DEPENDS:=nebula
+  PKGARCH:=all
+endef
+
+define Package/nebula-service
+  SECTION:=net
+  CATEGORY:=Network
+  TITLE:=nebula-service
+  URL:=https://docs.openwrt.melmac.net/nebula/
+  DEPENDS:=nebula
+       CONFLICTS:=nebula-proto
+  PKGARCH:=all
+endef
+
+define Build/Compile
+  $(call GoPackage/Build/Compile)
+endef
+
 define Package/nebula/description
   Nebula is a scalable overlay networking tool with a focus on performance, simplicity
   and security. It lets you seamlessly connect computers anywhere in the world.
+  This package contains only nebula binary. Unless you want to start nebula manually,
+  you may want to also install *either* 'nebula-service' *or* 'nebula-proto' package.
 endef
 
 define Package/nebula-cert/description
-$(call Package/nebula/description)
+  Nebula is a scalable overlay networking tool with a focus on performance, simplicity
+  and security. It lets you seamlessly connect computers anywhere in the world.
   This package contains only nebula-cert binary.
 endef
 
+define Package/nebula-proto/description
+  Nebula is a scalable overlay networking tool with a focus on performance, simplicity
+  and security. It lets you seamlessly connect computers anywhere in the world.
+  This package contains only OpenWrt protocol/interface support for nebula.
+endef
+
+define Package/nebula-service/description
+  Nebula is a scalable overlay networking tool with a focus on performance, simplicity
+  and security. It lets you seamlessly connect computers anywhere in the world.
+  This package contains only OpenWrt-specific init.d script for nebula.
+endef
+
 define Package/nebula/install
        $(call GoPackage/Package/Install/Bin,$(PKG_INSTALL_DIR))
-       $(INSTALL_DIR) $(1)/etc/init.d $(1)/usr/sbin $(1)/usr/share/doc/nebula $(1)/lib/upgrade/keep.d 
-       $(INSTALL_BIN) ./files/nebula.init $(1)/etc/init.d/nebula
-       $(SED) "s|^\(PKG_VERSION\).*|\1='$(PKG_VERSION)-$(PKG_RELEASE)'|" $(1)/etc/init.d/nebula
-       $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/nebula $(1)/usr/sbin/nebula
+       $(INSTALL_DIR) $(1)/usr/sbin
+       $(INSTALL_DIR) $(1)/lib/upgrade/keep.d
+       $(INSTALL_DIR) $(1)/usr/share/doc/nebula
+       $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/nebula $(1)/usr/sbin/
        $(INSTALL_DATA) $(PKG_BUILD_DIR)/LICENSE $(1)/usr/share/doc/nebula/LICENSE
        $(INSTALL_DATA) ./files/nebula.upgrade $(1)/lib/upgrade/keep.d/nebula
 endef
 
 define Package/nebula-cert/install
        $(call GoPackage/Package/Install/Bin,$(PKG_INSTALL_DIR))
-       $(INSTALL_DIR) $(1)/usr/sbin $(1)/usr/share/doc/nebula-cert $(1)/lib/upgrade/keep.d
-       $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/nebula-cert $(1)/usr/sbin/nebula-cert
+       $(INSTALL_DIR) $(1)/usr/sbin
+       $(INSTALL_DIR) $(1)/lib/upgrade/keep.d
+       $(INSTALL_DIR) $(1)/usr/share/doc/nebula-cert
+       $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/nebula-cert $(1)/usr/sbin/
        $(INSTALL_DATA) $(PKG_BUILD_DIR)/LICENSE $(1)/usr/share/doc/nebula-cert/LICENSE
        $(INSTALL_DATA) ./files/nebula.upgrade $(1)/lib/upgrade/keep.d/nebula-cert
 endef
 
+define Package/nebula-proto/install
+       $(call GoPackage/Package/Install/Bin,$(PKG_INSTALL_DIR))
+       $(INSTALL_DIR) $(1)/lib/netifd/proto
+       $(INSTALL_BIN) ./files/nebula.proto $(1)/lib/netifd/proto/nebula.sh
+       $(SED) "s|^\(readonly PKG_VERSION\).*|\1='$(PKG_VERSION)-$(PKG_RELEASE)'|" $(1)/lib/netifd/proto/nebula.sh
+endef
+
+define Package/nebula-service/install
+       $(call GoPackage/Package/Install/Bin,$(PKG_INSTALL_DIR))
+       $(INSTALL_DIR) $(1)/etc/init.d
+       $(INSTALL_BIN) ./files/nebula.init $(1)/etc/init.d/nebula
+       $(SED) "s|^\(readonly PKG_VERSION\).*|\1='$(PKG_VERSION)-$(PKG_RELEASE)'|" $(1)/etc/init.d/nebula
+endef
+
 $(eval $(call GoBinPackage,nebula))
 $(eval $(call BuildPackage,nebula))
 
 $(eval $(call GoBinPackage,nebula-cert))
 $(eval $(call BuildPackage,nebula-cert))
+
+$(eval $(call BuildPackage,nebula-proto))
+
+$(eval $(call BuildPackage,nebula-service))
index 2da5a94f67f4ac6b4cba2aac6fc10dd3bb101b91..0d87111d055994f6b80493d9a65f41e1ca60019c 100755 (executable)
 #!/bin/sh /etc/rc.common
 # Copyright 2021 Stan Grishin (stangri@melmac.ca)
-# shellcheck disable=SC2039,SC3043
-PKG_VERSION='dev-test'
+# shellcheck disable=SC3043,SC3060
 
 # shellcheck disable=SC2034
 START=80
 # shellcheck disable=SC2034
 USE_PROCD=1
 
-if type extra_command 1>/dev/null 2>&1; then
-       extra_command 'version' 'Show version information'
-else
-# shellcheck disable=SC2034
-       EXTRA_COMMANDS='version'
-fi
-
+readonly PKG_VERSION='dev-test'
+readonly packageName='nebula-service'
+readonly serviceName="$packageName $PKG_VERSION"
+readonly sharedMemoryOutput="/dev/shm/$packageName-output"
 readonly PROG=/usr/sbin/nebula
+readonly _OK_='\033[0;32m\xe2\x9c\x93\033[0m'
+readonly _FAIL_='\033[0;31m\xe2\x9c\x97\033[0m'
+
+extra_command 'version' 'Show version information'
 
 version() { echo "Version: $PKG_VERSION"; }
 
+output() {
+       local msg memmsg logmsg
+       [ -t 1 ] && printf "%b" "$@"
+       msg="${1//$serviceName /service }";
+       if [ "$(printf "%b" "$msg" | wc -l)" -gt 0 ]; then
+               [ -s "$sharedMemoryOutput" ] && memmsg="$(cat "$sharedMemoryOutput")"
+               logmsg="$(printf "%b" "${memmsg}${msg}" | sed 's/\x1b\[[0-9;]*m//g')"
+               logger -t "$packageName" "$(printf "%b" "$logmsg")"
+               rm -f "$sharedMemoryOutput"
+       else
+               printf "%b" "$msg" >> "$sharedMemoryOutput"
+       fi
+}
+output_ok() { output "$_OK_"; }
+output_okn() { output "${_OK_}\\n"; }
+output_fail() { output "$_FAIL_"; }
+output_failn() { output "${_FAIL_}\\n"; }
+
+# https://gist.github.com/pkuczynski/8665367
+# shellcheck disable=SC2086,SC2155
+parse_yaml() {
+       local prefix=$2
+       local s='[[:space:]]*' w='[a-zA-Z0-9_-]*' fs="$(echo @|tr @ '\034'|tr -d '\015')"
+       sed -ne "s|^\($s\)\($w\)$s:$s\"\(.*\)\"$s\$|\1$fs\2$fs\3|p" \
+       -e "s|^\($s\)\($w\)$s:$s\(.*\)$s\$|\1$fs\2$fs\3|p" "$1" |
+       awk "-F$fs" '{
+               indent = length($1)/2;
+               vname[indent] = $2;
+               for (i in vname) {if (i > indent) {delete vname[i]}}
+               if (length($3) > 0) {
+                       vn=""; for (i=0; i<indent; i++) {vn=(vn)(vname[i])("_")}
+                       printf("%s%s%s=\"%s\"\n", "'$prefix'", vn, $2, $3);
+               }
+       }'
+}
+
 start_instance() {
-       local cfg="$1" port name="${1##*/}"
-       port="$(grep -A2 "^listen:" "$cfg" | grep "port: " | awk '{print $2}')"
-       procd_open_instance
-       procd_set_param command ${PROG} -config "${cfg}"
-       procd_set_param stderr 1
-       procd_set_param stdout 1
-       procd_set_param respawn
-       procd_open_data
-       json_add_array firewall
-               json_add_object ''
-               json_add_string type 'rule'
-               json_add_string name "Allow-$name"
-               json_add_string src 'wan'
-               json_add_string dest_port "$port"
-               json_add_string proto 'udp'
-               json_add_string target 'ACCEPT'
-               json_close_object
-       json_close_array
-       procd_close_data
-       procd_close_instance
+       local config_file="$1"
+       local yaml_listen_host yaml_listen_port
+       if [ ! -x "$PROG" ]; then
+               echo "Nebula binary not found! Please install 'nebula' package."
+               output_fail
+               return 1
+       fi
+       if [ ! -s "$config_file" ]; then
+               output_fail
+               return 1
+       fi
+       if ! eval "$(parse_yaml "$config_file" "yaml_")"; then
+               output_fail
+               return 1
+       else
+               procd_open_instance
+               procd_set_param command ${PROG} -config "${config_file}"
+               procd_set_param stderr 1
+               procd_set_param stdout 1
+               procd_set_param respawn
+               procd_open_data
+               json_add_array firewall
+                       json_add_object ""
+                       json_add_string type rule
+                       json_add_string name "${config_file##*/}"
+                       json_add_string src "*"
+                       json_add_string dest_ip "${yaml_listen_host:-0.0.0.0}"
+                       json_add_string dest_port "${yaml_listen_port:-4242}"
+                       json_add_string proto udp
+                       json_add_string target ACCEPT
+                       json_close_object
+               json_close_array
+               procd_close_data
+               procd_close_instance
+       output_ok
+       fi
 }
 
 start_service() {
        local f
+       output "Starting $packageName instances "
        for f in /etc/nebula/*.yml; do
-               [ -s "$f" ] && start_instance "$f"
+               start_instance "$f"
        done
+       output '\n'
 }
 
 service_started() { procd_set_config_changed firewall; }
diff --git a/net/nebula/files/nebula.proto b/net/nebula/files/nebula.proto
new file mode 100644 (file)
index 0000000..39bd68b
--- /dev/null
@@ -0,0 +1,99 @@
+#!/bin/sh
+# Copyright 2021 Stan Grishin (stangri@melmac.ca)
+# shellcheck disable=SC1091,SC2039,SC2034,SC3043
+readonly PKG_VERSION='dev-test'
+readonly PROG=/usr/sbin/nebula
+readonly packageName='nebula-proto'
+
+[ -x "$PROG" ] || { log "Main nebula executable '/usr/sbin/nebula' not found"; exit 1; }
+
+[ -n "$INCLUDE_ONLY" ] || {
+       . /lib/functions.sh
+       . /lib/functions/network.sh
+       . ../netifd-proto.sh
+       init_proto "$@"
+}
+
+log() { logger -t "$packageName" "$*"; }
+# https://gist.github.com/pkuczynski/8665367
+# shellcheck disable=SC2086,SC2155
+parse_yaml() {
+       local prefix=$2
+       local s='[[:space:]]*' w='[a-zA-Z0-9_-]*' fs="$(echo @|tr @ '\034'|tr -d '\015')"
+       sed -ne "s|^\($s\)\($w\)$s:$s\"\(.*\)\"$s\$|\1$fs\2$fs\3|p" \
+       -e "s|^\($s\)\($w\)$s:$s\(.*\)$s\$|\1$fs\2$fs\3|p" "$1" |
+       awk "-F$fs" '{
+               indent = length($1)/2;
+               vname[indent] = $2;
+               for (i in vname) {if (i > indent) {delete vname[i]}}
+               if (length($3) > 0) {
+                       vn=""; for (i=0; i<indent; i++) {vn=(vn)(vname[i])("_")}
+                       printf("%s%s%s=\"%s\"\n", "'$prefix'", vn, $2, $3);
+               }
+       }'
+}
+
+proto_nebula_init_config() {
+       available=1
+       no_device=1
+       proto_config_add_string "config_file"
+}
+
+proto_nebula_setup() {
+       local interface="$1" config_file address addresses
+       local yaml_listen_host yaml_listen_port yaml_tun_dev
+
+       config_load network
+       config_get config_file "${interface}" "config_file"
+       proto_init_update "${interface}" 1
+
+       [ -s "$config_file" ] || { log "Config file not found or empty!"; return 1; }
+       eval "$(parse_yaml "$config_file" "yaml_")"
+       [ "$yaml_tun_dev" = "$interface" ] || { log "Tunnel device in config file (${yaml_tun_dev}) doesn't match interface name (${interface})!"; return 1; }
+
+       log "Setting up ${interface} from $(basename "$config_file")."
+       proto_run_command "$interface" "$PROG" -config "$config_file"
+       proto_add_data
+       json_add_array firewall
+               json_add_object ""
+               json_add_string type rule
+               json_add_string name "$interface"
+               json_add_string src "*"
+               json_add_string dest_ip "${yaml_listen_host:-0.0.0.0}"
+               json_add_string dest_port "${yaml_listen_port:-4242}"
+               json_add_string proto udp
+               json_add_string target ACCEPT
+               json_close_object
+       json_close_array
+       proto_close_data
+       addresses="$(ip -4 a list dev "$interface" 2>/dev/null | grep inet | awk '{print $2}' | awk -F "/" '{print $1}')"
+       log "Running ${interface} from $(basename "$config_file") with addresses: ${addresses}."
+       for address in ${addresses}; do
+               case "${address}" in
+                       *:*/*)
+                               proto_add_ipv6_address "${address%%/*}" "${address##*/}"
+                               ;;
+                       *.*/*)
+                               proto_add_ipv4_address "${address%%/*}" "${address##*/}"
+                               ;;
+                       *:*)
+                               proto_add_ipv6_address "${address%%/*}" "128"
+                               ;;
+                       *.*)
+                               proto_add_ipv4_address "${address%%/*}" "32"
+                               ;;
+               esac
+       done
+
+       proto_send_update "$interface"
+}
+
+proto_nebula_teardown() {
+       local interface="$1"
+       proto_kill_command "${interface}"
+       log "Killed interface ${interface}."
+}
+
+[ -n "$INCLUDE_ONLY" ] || {
+       add_protocol nebula
+}
index 847e507da4f0fc867d94c9db99dd8631016d9846..8acfa8346406477ab7991a581345a80ca34fe15c 100644 (file)
@@ -1,4 +1,8 @@
 #!/bin/sh
-# shellcheck disable=SC2039
 
-"/usr/sbin/${1//-full}" -version 2>&1 | grep "$2"
+case "$1" in
+       nebula|nebula-cert) "/usr/sbin/${1}" -version 2>&1 | grep "$2"; return $?;;
+       nebula-proto) grep 'readonly PKG_VERSION=' /lib/netifd/proto/nebula.sh 2>&1 | grep "$2"; return $?;;
+#      nebula-service) "/etc/init.d/nebula" version 2>&1 | grep "$2"; return $?;;
+       nebula-service) return 0;;
+esac