1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
|
#!/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,
IfMTU = 65535,
Peers = { }, Listen = { }, MulticastInterfaces = { }, AllowedPublicKeys = { },
InterfacePeers = setmetatable({ }, {__jsontype = "object"}),
NodeInfo = setmetatable({ }, {__jsontype = "object"})
}
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.PublicKey = config.PublicKey
obj.PrivateKey = config.PrivateKey
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" }) do
if config[v] ~= nil then obj[v] = to_bool(config[v]) end
end
if config["IfMTU"] ~= nil then obj["IfMTU"] = tonumber(config["IfMTU"]) 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, {
Beacon = to_bool(s.beacon), Listen = to_bool(s.listen),
Port = tonumber(s.port), Regex = s.regex
})
end)
cursor:foreach("yggdrasil", "allowed_public_key", function (s)
table.insert(obj.AllowedPublicKeys, 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)
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", "PublicKey", obj.PublicKey)
cursor:set("yggdrasil", "yggdrasil", "PrivateKey", obj.PrivateKey)
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", "IfMTU", obj.IfMTU)
set_values(cursor, "peer", "uri", obj.Peers)
set_values(cursor, "listen_address", "uri", obj.Listen)
for _, interface in pairs(obj.MulticastInterfaces) do
local name = cursor:add("yggdrasil", "multicast_interface")
cursor:set("yggdrasil", name, "beacon", to_int(interface.Beacon))
cursor:set("yggdrasil", name, "listen", to_int(interface.Listen))
cursor:set("yggdrasil", name, "port", interface.Port)
cursor:set("yggdrasil", name, "regex", interface.Regex)
end
set_values(cursor, "allowed_public_key", "key", obj.AllowedPublicKeys)
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
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
|