yggdrasil: Change package configuration to UCI 10547/head
authorGeorge Iv <57254463+zhoreeq@users.noreply.github.com>
Thu, 14 Nov 2019 09:16:02 +0000 (04:16 -0500)
committerGeorge Iv <57254463+zhoreeq@users.noreply.github.com>
Thu, 21 Nov 2019 16:15:29 +0000 (11:15 -0500)
Signed-off-by: George Iv <57254463+zhoreeq@users.noreply.github.com>
net/yggdrasil/Makefile
net/yggdrasil/files/yggdrasil.defaults
net/yggdrasil/files/yggdrasil.init
net/yggdrasil/files/ygguci [new file with mode: 0755]

index c2ffdbb079bba9d435b3c139b521d528f5273c92..61dc2ae5452930c01843f6b4ae9a2e6aa0ce5bf3 100644 (file)
@@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk
 
 PKG_NAME:=yggdrasil
 PKG_VERSION:=0.3.11
-PKG_RELEASE:=3
+PKG_RELEASE:=4
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
 PKG_SOURCE_URL:=https://codeload.github.com/yggdrasil-network/yggdrasil-go/tar.gz/v$(PKG_VERSION)?
@@ -33,7 +33,7 @@ define Package/yggdrasil
        SUBMENU:=Routing and Redirection
        TITLE:=Yggdrasil supports end-to-end encrypted IPv6 networks
        URL:=https://yggdrasil-network.github.io/
-       DEPENDS:=$(GO_ARCH_DEPENDS) @IPV6 +kmod-tun
+       DEPENDS:=$(GO_ARCH_DEPENDS) @IPV6 +kmod-tun +dkjson +libuci-lua
 endef
 
 define Package/yggdrasil/description
@@ -46,6 +46,10 @@ define Package/yggdrasil/description
  interfaces simultaneously with much greater throughput.
 endef
 
+define Package/yggdrasil/conffiles
+/etc/config/yggdrasil
+endef
+
 define Package/yggdrasil/install
        $(INSTALL_DIR) \
                $(1)/etc/init.d \
@@ -60,6 +64,10 @@ define Package/yggdrasil/install
                $(GO_PKG_BUILD_BIN_DIR)/yggdrasilctl \
                $(1)/usr/sbin
 
+       $(INSTALL_BIN) \
+               ./files/ygguci \
+               $(1)/usr/sbin
+
        $(INSTALL_BIN) \
                ./files/yggdrasil.defaults \
                $(1)/etc/uci-defaults/yggdrasil
index d5076cf6d3fc30307b58e79950b3b40b57243854..7f9aaf65926a5a439a13b8d78f5ae1613ccee280 100644 (file)
@@ -1,12 +1,13 @@
 #!/bin/sh
 
-yggConfig="/etc/yggdrasil.conf"
+yggConfig="/etc/config/yggdrasil"
 
 first_boot_genConfig()
 {
   . /usr/share/libubox/jshn.sh
   boardcfg=$(ubus call system board)
-  yggcfg=$(yggdrasil -genconf -json | grep NodeInfo -v)
+  touch ${yggConfig}
+  yggdrasil -genconf -json | ygguci set
 
   json_load "$boardcfg"
   json_get_var kernel     kernel
@@ -14,23 +15,22 @@ first_boot_genConfig()
   json_get_var system     system
   json_get_var model      model
   json_get_var board_name board_name
+  nodeinfo='{"kernel": "'$kernel'", "hostname":"'$hostname'", "system": "'$system'", "model": "'$model'", "board_name": "'$board_name'"}'
 
-  json_load "$yggcfg"
-  json_add_string "IfName" "ygg0"
-  json_add_object "NodeInfo"
-  json_add_string "kernel"      "$kernel"
-  json_add_string "hostname"    "$hostname"
-  json_add_string "system"      "$system"
-  json_add_string "model"       "$model"
-  json_add_string "board_name"  "$board_name"
-  json_close_object
-  json_dump
+  uci set yggdrasil.yggdrasil.IfName="ygg0"
+  uci set yggdrasil.yggdrasil.NodeInfo="$nodeinfo"
+  uci commit yggdrasil
 }
 
-if [ ! -e ${yggConfig} ]; then
+if [ -e /etc/yggdrasil.conf ]; then
+  echo "config: import config from /etc/yggdrasil.conf to /etc/config/yggdrasil" | logger -t yggdrasil 
+  touch ${yggConfig}
+  cat /etc/yggdrasil.conf | ygguci set
+  mv /etc/yggdrasil.conf /etc/yggdrasil.conf.bak 
+elif [ ! -e ${yggConfig} ]; then
   echo "first_boot: adding system board details to NodeInfo[] in NEW config: ${yggConfig}" | logger -t yggdrasil
 
-  first_boot_genConfig > ${yggConfig}
+  first_boot_genConfig
 
   # create the network interface
   uci -q batch <<-EOF >/dev/null
index 6ad3f6583bb5b64842d0140d5ebde6195f33daba..d981834bd5de8bc91969f5980dabf2d310c00b68 100755 (executable)
@@ -12,7 +12,7 @@ start_service()
        procd_open_instance
        procd_set_param respawn
 
-       procd_set_param command /usr/sbin/yggdrasil -useconffile /etc/yggdrasil.conf
+       procd_set_param command /bin/ash -c "ygguci get | yggdrasil -useconf -normaliseconf -json | yggdrasil -useconf"
        procd_set_param stdout 1
        procd_set_param stderr 1
        procd_close_instance
diff --git a/net/yggdrasil/files/ygguci b/net/yggdrasil/files/ygguci
new file mode 100755 (executable)
index 0000000..29751c4
--- /dev/null
@@ -0,0 +1,237 @@
+#!/usr/bin/env lua
+
+dkjson = require("dkjson")
+uci    = require("uci")
+
+UCI = {}
+
+--- Return the configuration defaults as a table suitable for JSON output
+--
+-- Mostly taken from yggdrasil -genconf -json
+-- @return table with configuration defaults
+function UCI.defaults()
+       return { 
+               AdminListen = "unix:///var/run/yggdrasil.sock", IfName = "ygg0", 
+               NodeInfoPrivacy = false, IfTAPMode = false,
+               LinkLocalTCPPort = 0, IfMTU = 65535,
+
+               Peers = { }, Listen = { }, MulticastInterfaces = { }, AllowedEncryptionPublicKeys = { },
+               InterfacePeers = setmetatable({ }, {__jsontype = "object"}),
+               NodeInfo = setmetatable({ }, {__jsontype = "object"}),
+
+               SessionFirewall = {
+                       Enable = false,
+                       AllowFromDirect = true,
+                       AllowFromRemote = true,
+                       AlwaysAllowOutbound = true,
+                       WhitelistEncryptionPublicKeys = { },
+                       BlacklistEncryptionPublicKeys = { }
+               },
+               TunnelRouting = {
+                       Enable = false,
+                       IPv6RemoteSubnets = setmetatable({ }, {__jsontype = "object"}),
+                       IPv6LocalSubnets = { },
+                       IPv4RemoteSubnets = setmetatable({ }, {__jsontype = "object"}),
+                       IPv4LocalSubnets = { }
+               },
+               SwitchOptions = { MaxTotalQueueSize = 4194304 }
+       }
+end
+
+--- Return the yggdrasil configuration as a table suitable for JSON output
+--
+-- @return table with yggdrasil configuration
+function UCI.get()
+       local obj = UCI.defaults()
+
+       local cursor = uci.cursor()
+       local config = cursor:get_all("yggdrasil", "yggdrasil")
+       if not config then return obj end
+
+       obj.EncryptionPublicKey = config.EncryptionPublicKey
+       obj.EncryptionPrivateKey = config.EncryptionPrivateKey
+       obj.SigningPublicKey = config.SigningPublicKey
+       obj.SigningPrivateKey = config.SigningPrivateKey
+       obj.AdminListen = config.AdminListen or obj.AdminListen
+       obj.IfName = config.IfName or obj.IfName
+       obj.NodeInfo = dkjson.decode(config.NodeInfo) or obj.NodeInfo
+       for _, v in pairs({ "NodeInfoPrivacy", "IfTAPMode" }) do
+               if config[v] ~= nil then obj[v] = to_bool(config[v]) end
+       end
+       for _, v in pairs({ "LinkLocalTCPPort", "IfMTU" }) do
+               if config[v] ~= nil then obj[v] = tonumber(config[v]) end
+       end
+
+       cursor:foreach("yggdrasil", "peer", function (s) 
+               table.insert(obj.Peers, s.uri)
+       end)
+       cursor:foreach("yggdrasil", "listen_address", function (s) 
+               table.insert(obj.Listen, s.uri)
+       end)
+       cursor:foreach("yggdrasil", "multicast_interface", function (s) 
+               table.insert(obj.MulticastInterfaces, s.name)
+       end)
+       cursor:foreach("yggdrasil", "allowed_encryption_public_key", function (s) 
+               table.insert(obj.AllowedEncryptionPublicKeys, s.key)
+       end)
+
+       cursor:foreach("yggdrasil", "interface_peer", function (s) 
+               if obj.InterfacePeers[s.interface] == nil then
+                       obj.InterfacePeers[s.interface] = {}
+               end
+               table.insert(obj.InterfacePeers[s["interface"]], s.uri)
+       end)
+
+       -- session firewall config
+       local session_firewall_config = { "Enable", "AllowFromDirect", "AllowFromRemote", "AlwaysAllowOutbound" }
+       for _, v in pairs(session_firewall_config) do
+               if config["SessionFirewall_"..v] ~= nil then
+                       obj.SessionFirewall[v] = to_bool(config["SessionFirewall_"..v])
+               end
+       end
+       cursor:foreach("yggdrasil", "whitelisted_encryption_public_key", function (s) 
+               table.insert(obj.SessionFirewall.WhitelistEncryptionPublicKeys, s.key)
+       end)
+       cursor:foreach("yggdrasil", "blacklisted_encryption_public_key", function (s) 
+               table.insert(obj.SessionFirewall.BlacklistEncryptionPublicKeys, s.key)
+       end)
+       -- /session firewall config
+
+       -- tunnel routing config
+       if config.TunnelRouting_Enable ~= nil then
+               obj.TunnelRouting.Enable = to_bool(config.TunnelRouting_Enable)
+       end
+       cursor:foreach("yggdrasil", "ipv6_remote_subnet", function (s) 
+               obj.TunnelRouting.IPv6RemoteSubnets[s.subnet] = s.key
+       end)
+       cursor:foreach("yggdrasil", "ipv6_local_subnet", function (s) 
+               table.insert(obj.TunnelRouting.IPv6LocalSubnets, s.subnet)
+       end)
+       cursor:foreach("yggdrasil", "ipv4_remote_subnet", function (s) 
+               obj.TunnelRouting.IPv4RemoteSubnets[s.subnet] = s.key
+       end)
+       cursor:foreach("yggdrasil", "ipv4_local_subnet", function (s) 
+               table.insert(obj.TunnelRouting.IPv4LocalSubnets, s.subnet)
+       end)
+       -- /tunnel routing config
+
+       if config.SwitchOptions_MaxTotalQueueSize ~= nil then
+               obj.SwitchOptions.MaxTotalQueueSize = tonumber(config.SwitchOptions_MaxTotalQueueSize)
+       end
+
+       return obj
+end
+
+--- Parse and save updated configuration from JSON input
+--
+-- Transforms general settings into UCI sections, and replaces the UCI config's
+-- contents with them.
+-- @param table JSON input
+-- @return Boolean whether saving succeeded
+function UCI.set(obj)
+       local cursor = uci.cursor()
+
+       for i, section in pairs(cursor:get_all("yggdrasil")) do
+               cursor:delete("yggdrasil", section[".name"])
+       end
+
+
+       cursor:set("yggdrasil", "yggdrasil", "yggdrasil")
+       cursor:set("yggdrasil", "yggdrasil", "EncryptionPublicKey", obj.EncryptionPublicKey) 
+       cursor:set("yggdrasil", "yggdrasil", "EncryptionPrivateKey", obj.EncryptionPrivateKey) 
+       cursor:set("yggdrasil", "yggdrasil", "SigningPublicKey", obj.SigningPublicKey) 
+       cursor:set("yggdrasil", "yggdrasil", "SigningPrivateKey", obj.SigningPrivateKey)
+       cursor:set("yggdrasil", "yggdrasil", "AdminListen", obj.AdminListen) 
+       cursor:set("yggdrasil", "yggdrasil", "IfName", obj.IfName) 
+       cursor:set("yggdrasil", "yggdrasil", "NodeInfoPrivacy", to_int(obj.NodeInfoPrivacy)) 
+       cursor:set("yggdrasil", "yggdrasil", "NodeInfo", dkjson.encode(obj.NodeInfo)) 
+       cursor:set("yggdrasil", "yggdrasil", "IfTAPMode", to_int(obj.IfTAPMode)) 
+       cursor:set("yggdrasil", "yggdrasil", "LinkLocalTCPPort", obj.LinkLocalTCPPort)
+       cursor:set("yggdrasil", "yggdrasil", "IfMTU", obj.IfMTU)
+
+       set_values(cursor, "peer", "uri", obj.Peers)
+       set_values(cursor, "listen_address", "uri", obj.Listen)
+       set_values(cursor, "multicast_interface", "name", obj.MulticastInterfaces)
+       set_values(cursor, "allowed_encryption_public_key", "key", obj.AllowedEncryptionPublicKeys)
+
+       for interface, peers in pairs(obj.InterfacePeers) do
+               for _, v in pairs(peers) do
+                       local name = cursor:add("yggdrasil", "interface_peer")
+                       cursor:set("yggdrasil", name, "interface", interface)
+                       cursor:set("yggdrasil", name, "uri", v)
+               end
+       end
+
+       -- session firewall config
+       cursor:set("yggdrasil", "yggdrasil", "SessionFirewall_Enable", to_int(obj.SessionFirewall.Enable)) 
+       cursor:set("yggdrasil", "yggdrasil", "SessionFirewall_AllowFromDirect", to_int(obj.SessionFirewall.AllowFromDirect)) 
+       cursor:set("yggdrasil", "yggdrasil", "SessionFirewall_AllowFromRemote", to_int(obj.SessionFirewall.AllowFromRemote)) 
+       cursor:set("yggdrasil", "yggdrasil", "SessionFirewall_AlwaysAllowOutbound", to_int(obj.SessionFirewall.AlwaysAllowOutbound)) 
+       set_values(cursor, "whitelisted_encryption_public_key", "key", obj.SessionFirewall.WhitelistEncryptionPublicKeys)
+       set_values(cursor, "blacklisted_encryption_public_key", "key", obj.SessionFirewall.BlacklistEncryptionPublicKeys)
+       -- /session firewall config
+
+       -- tunnel routing config
+       cursor:set("yggdrasil", "yggdrasil", "TunnelRouting_Enable", to_int(obj.TunnelRouting.Enable)) 
+       if obj.TunnelRouting.IPv6RemoteSubnets ~= nil then
+               for subnet, key in pairs(obj.TunnelRouting.IPv6RemoteSubnets) do
+                       local name = cursor:add("yggdrasil", "ipv6_remote_subnet")
+                       cursor:set("yggdrasil", name, "subnet", subnet)
+                       cursor:set("yggdrasil", name, "key", key)
+               end
+       end
+       set_values(cursor, "ipv6_local_subnet", "subnet", obj.TunnelRouting.IPv6LocalSubnets)
+       if obj.TunnelRouting.IPv4RemoteSubnets ~= nil then
+               for subnet, key in pairs(obj.TunnelRouting.IPv4RemoteSubnets) do
+                       local name = cursor:add("yggdrasil", "ipv4_remote_subnet")
+                       cursor:set("yggdrasil", name, "subnet", subnet)
+                       cursor:set("yggdrasil", name, "key", key)
+               end
+       end
+       set_values(cursor, "ipv4_local_subnet", "subnet", obj.TunnelRouting.IPv4LocalSubnets)
+       -- /tunnel routing config
+
+       cursor:set("yggdrasil", "yggdrasil", "SwitchOptions_MaxTotalQueueSize", obj.SwitchOptions.MaxTotalQueueSize) 
+
+       return cursor:commit("yggdrasil")
+end
+
+function set_values(cursor, section_name, parameter, values) 
+       if values == nil then return false end
+
+       for k, v in pairs(values) do
+               local name = cursor:add("yggdrasil", section_name)
+               cursor:set("yggdrasil", name, parameter, v)
+       end
+end
+
+function to_int(bool) return bool and '1' or '0' end
+
+function to_bool(int) return int ~= '0' end
+
+function help()
+       print("JSON interface to /etc/config/yggdrasil\n\nExamples: \
+       ygguci get > /tmp/etc/yggdrasil.conf \
+       cat /tmp/etc/yggdrasil.conf | ygguci set \
+       uci changes \
+       ygguci get | yggdrasil -useconf")
+end
+
+-- main 
+
+if arg[1] == "get" then
+       local json = dkjson.encode(UCI.get(), { indent = true })
+       print(json)
+elseif arg[1] == "set" then
+       local json = io.stdin:read("*a")
+       local obj, pos, err = dkjson.decode(json, 1, nil)
+
+       if obj then
+               UCI.set(obj)
+       else
+               print("dkjson: " .. err)
+               os.exit(1)
+       end
+else
+       help()
+end