uci.lua 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. common = require("cjdns/common")
  2. uci = require("uci")
  3. UCI = {}
  4. common.uci = UCI
  5. --- Return the configuration defaults as a table suitable for JSON output
  6. --
  7. -- Mostly taken from cjdroute --genconf
  8. -- @return table with configuration defaults
  9. function UCI.defaults()
  10. return {
  11. security = {
  12. { setuser = "nobody", keepNetAdmin = 1 },
  13. { chroot = "/var/run/" },
  14. { nofiles = 0 },
  15. { noforks = 1 },
  16. { seccomp = 0 },
  17. { setupComplete = 1 }
  18. },
  19. router = {
  20. ipTunnel = { outgoingConnections = {}, allowedConnections = {} },
  21. interface = { type = "TUNInterface" }
  22. },
  23. interfaces = { UDPInterface = {}, ETHInterface = {} },
  24. authorizedPasswords = {},
  25. logging = { logTo = "stdout" }
  26. }
  27. end
  28. --- Return the cjdns configuration as a table suitable for JSON output
  29. --
  30. -- Iterates over cjdns, eth_interface, udp_interface, eth_peer, udp_peer,
  31. -- and password sections. Doesn't include IPTunnel related options yet.
  32. -- @return table with cjdns configuration
  33. function UCI.get()
  34. local obj = UCI.defaults()
  35. local cursor = uci.cursor()
  36. local config = cursor:get_all("cjdns", "cjdns")
  37. if not config then return obj end
  38. obj.ipv6 = config.ipv6
  39. obj.publicKey = config.public_key
  40. obj.privateKey = config.private_key
  41. obj.admin = {
  42. bind = config.admin_address .. ":" .. config.admin_port,
  43. password = config.admin_password }
  44. if config.tun_device and string.len(config.tun_device) > 0 then
  45. obj.router.interface.tunDevice = config.tun_device
  46. end
  47. for i,section in pairs(obj.security) do
  48. if type(section.seccomp) == "number" then
  49. obj.security[i].seccomp = tonumber(config.seccomp)
  50. end
  51. end
  52. cursor:foreach("cjdns", "iptunnel_outgoing", function(outgoing)
  53. table.insert(obj.router.ipTunnel.outgoingConnections, outgoing.public_key)
  54. end)
  55. cursor:foreach("cjdns", "iptunnel_allowed", function(allowed)
  56. entry = { publicKey = allowed.public_key }
  57. if allowed.ipv4 then
  58. entry["ip4Address"] = allowed.ipv4
  59. end
  60. if allowed.ipv6 then
  61. entry["ip6Address"] = allowed.ipv6
  62. end
  63. table.insert(obj.router.ipTunnel.allowedConnections, entry)
  64. end)
  65. cursor:foreach("cjdns", "eth_interface", function(eth_interface)
  66. table.insert(obj.interfaces.ETHInterface, {
  67. bind = eth_interface.bind,
  68. beacon = tonumber(eth_interface.beacon),
  69. connectTo = {}
  70. })
  71. end)
  72. cursor:foreach("cjdns", "udp_interface", function(udp_interface)
  73. table.insert(obj.interfaces.UDPInterface, {
  74. bind = udp_interface.address .. ":" .. udp_interface.port,
  75. connectTo = {}
  76. })
  77. end)
  78. cursor:foreach("cjdns", "eth_peer", function(eth_peer)
  79. if not eth_peer.address == "" then
  80. local i = tonumber(eth_peer.interface)
  81. obj.interfaces.ETHInterface[i].connectTo[eth_peer.address] = {
  82. publicKey = eth_peer.public_key,
  83. password = eth_peer.password
  84. }
  85. end
  86. end)
  87. cursor:foreach("cjdns", "udp_peer", function(udp_peer)
  88. local bind = udp_peer.address .. ":" .. udp_peer.port
  89. local i = tonumber(udp_peer.interface)
  90. obj.interfaces.UDPInterface[i].connectTo[bind] = {
  91. user = udp_peer.user,
  92. publicKey = udp_peer.public_key,
  93. password = udp_peer.password
  94. }
  95. end)
  96. cursor:foreach("cjdns", "password", function(password)
  97. table.insert(obj.authorizedPasswords, {
  98. password = password.password,
  99. user = password.user,
  100. contact = password.contact
  101. })
  102. end)
  103. return obj
  104. end
  105. --- Parse and save updated configuration from JSON input
  106. --
  107. -- Transforms general settings, ETHInterface, UDPInterface, connectTo, and
  108. -- authorizedPasswords fields into UCI sections, and replaces the UCI config's
  109. -- contents with them.
  110. -- @param table JSON input
  111. -- @return Boolean whether saving succeeded
  112. function UCI.set(obj)
  113. local cursor = uci.cursor()
  114. for i, section in pairs(cursor:get_all("cjdns")) do
  115. cursor:delete("cjdns", section[".name"])
  116. end
  117. local admin_address, admin_port = string.match(obj.admin.bind, "^(.*):(.*)$")
  118. UCI.cursor_section(cursor, "cjdns", "cjdns", "cjdns", {
  119. ipv6 = obj.ipv6,
  120. public_key = obj.publicKey,
  121. private_key = obj.privateKey,
  122. admin_password = obj.admin.password,
  123. admin_address = admin_address,
  124. admin_port = admin_port
  125. })
  126. if obj.router.interface.tunDevice then
  127. UCI.cursor_section(cursor, "cjdns", "cjdns", "cjdns", {
  128. tun_device = tostring(obj.router.interface.tunDevice)
  129. })
  130. end
  131. if obj.security then
  132. for i,section in pairs(obj.security) do
  133. for key,value in pairs(section) do
  134. if key == "seccomp" then
  135. UCI.cursor_section(cursor, "cjdns", "cjdns", "cjdns", {
  136. seccomp = tonumber(value)
  137. })
  138. end
  139. end
  140. end
  141. end
  142. if obj.router.ipTunnel.outgoingConnections then
  143. for i,public_key in pairs(obj.router.ipTunnel.outgoingConnections) do
  144. UCI.cursor_section(cursor, "cjdns", "iptunnel_outgoing", nil, {
  145. public_key = public_key
  146. })
  147. end
  148. end
  149. if obj.router.ipTunnel.allowedConnections then
  150. for i,allowed in pairs(obj.router.ipTunnel.allowedConnections) do
  151. entry = { public_key = allowed.publicKey }
  152. if allowed.ip4Address then
  153. entry["ipv4"] = allowed.ip4Address
  154. end
  155. if allowed.ip6Address then
  156. entry["ipv6"] = allowed.ip6Address
  157. end
  158. UCI.cursor_section(cursor, "cjdns", "iptunnel_allowed", nil, entry)
  159. end
  160. end
  161. if obj.interfaces.ETHInterface then
  162. for i,interface in pairs(obj.interfaces.ETHInterface) do
  163. UCI.cursor_section(cursor, "cjdns", "eth_interface", nil, {
  164. bind = interface.bind,
  165. beacon = tostring(interface.beacon)
  166. })
  167. if interface.connectTo then
  168. for peer_address,peer in pairs(interface.connectTo) do
  169. UCI.cursor_section(cursor, "cjdns", "eth_peer", nil, {
  170. interface = i,
  171. address = peer_address,
  172. public_key = peer.publicKey,
  173. password = peer.password
  174. })
  175. end
  176. end
  177. end
  178. end
  179. if obj.interfaces.UDPInterface then
  180. for i,interface in pairs(obj.interfaces.UDPInterface) do
  181. local address, port = string.match(interface.bind, "^(.*):(.*)$")
  182. UCI.cursor_section(cursor, "cjdns", "udp_interface", nil, {
  183. address = address,
  184. port = port
  185. })
  186. if interface.connectTo then
  187. for peer_bind,peer in pairs(interface.connectTo) do
  188. local peer_address, peer_port = string.match(peer_bind, "^(.*):(.*)$")
  189. UCI.cursor_section(cursor, "cjdns", "udp_peer", nil, {
  190. interface = i,
  191. address = peer_address,
  192. port = peer_port,
  193. user = peer.user,
  194. public_key = peer.publicKey,
  195. password = peer.password
  196. })
  197. end
  198. end
  199. end
  200. end
  201. if obj.authorizedPasswords then
  202. for i,password in pairs(obj.authorizedPasswords) do
  203. local user = password.user
  204. if not user or string.len(user) == 0 then
  205. user = "user-" .. UCI.random_string(6)
  206. end
  207. UCI.cursor_section(cursor, "cjdns", "password", nil, {
  208. password = password.password,
  209. user = user,
  210. contact = password.contact
  211. })
  212. end
  213. end
  214. return cursor:save("cjdns")
  215. end
  216. --- Simple backport of Cursor:section from luci.model.uci
  217. --
  218. -- Backport reason: we don't wanna depend on LuCI.
  219. -- @param Cursor the UCI cursor to operate on
  220. -- @param string name of the config
  221. -- @param string type of the section
  222. -- @param string name of the section (optional)
  223. -- @param table config values
  224. function UCI.cursor_section(cursor, config, type, section, values)
  225. if section then
  226. cursor:set(config, section, type)
  227. else
  228. section = cursor:add("cjdns", type)
  229. end
  230. for k,v in pairs(values) do
  231. cursor:set(config, section, k, v)
  232. end
  233. end
  234. function UCI.makeInterface()
  235. local cursor = uci.cursor()
  236. local config = cursor:get_all("cjdns", "cjdns")
  237. if not config then return nil end
  238. return common.AdminInterface.new({
  239. host = config.admin_address,
  240. port = config.admin_port,
  241. password = config.admin_password,
  242. config = UCI.get(),
  243. timeout = 2
  244. })
  245. end
  246. function UCI.random_string(length)
  247. -- tr -cd 'A-Za-z0-9' < /dev/urandom
  248. local urandom = io.popen("tr -cd 'A-Za-z0-9' 2> /dev/null < /dev/urandom", "r")
  249. local string = urandom:read(length)
  250. urandom:close()
  251. return string
  252. end