ddns.lua 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. -- Copyright 2008 Steven Barth <steven@midlink.org>
  2. -- Copyright 2008 Jo-Philipp Wich <jow@openwrt.org>
  3. -- Copyright 2013 Manuel Munz <freifunk at somakoma dot de>
  4. -- Copyright 2014 Christian Schoenebeck <christian dot schoenebeck at gmail dot com>
  5. -- Licensed to the public under the Apache License 2.0.
  6. module("luci.controller.ddns", package.seeall)
  7. local NX = require "nixio"
  8. local NXFS = require "nixio.fs"
  9. local DISP = require "luci.dispatcher"
  10. local HTTP = require "luci.http"
  11. local UCI = require "luci.model.uci"
  12. local SYS = require "luci.sys"
  13. local DDNS = require "luci.tools.ddns" -- ddns multiused functions
  14. local UTIL = require "luci.util"
  15. DDNS_MIN = "2.4.2-1" -- minimum version of service required
  16. function index()
  17. local nxfs = require "nixio.fs" -- global definitions not available
  18. local sys = require "luci.sys" -- in function index()
  19. local ddns = require "luci.tools.ddns" -- ddns multiused functions
  20. local verinst = ddns.ipkg_ver_installed("ddns-scripts")
  21. local verok = ddns.ipkg_ver_compare(verinst, ">=", "2.0.0-0")
  22. -- do NOT start it not ddns-scripts version 2.x
  23. if not verok then
  24. return
  25. end
  26. -- no config create an empty one
  27. if not nxfs.access("/etc/config/ddns") then
  28. nxfs.writefile("/etc/config/ddns", "")
  29. end
  30. entry( {"admin", "services", "ddns"}, cbi("ddns/overview"), _("Dynamic DNS"), 59)
  31. entry( {"admin", "services", "ddns", "detail"}, cbi("ddns/detail"), nil ).leaf = true
  32. entry( {"admin", "services", "ddns", "hints"}, cbi("ddns/hints",
  33. {hideapplybtn=true, hidesavebtn=true, hideresetbtn=true}), nil ).leaf = true
  34. entry( {"admin", "services", "ddns", "global"}, cbi("ddns/global"), nil ).leaf = true
  35. entry( {"admin", "services", "ddns", "logview"}, call("logread") ).leaf = true
  36. entry( {"admin", "services", "ddns", "startstop"}, call("startstop") ).leaf = true
  37. entry( {"admin", "services", "ddns", "status"}, call("status") ).leaf = true
  38. end
  39. -- function to read all sections status and return data array
  40. local function _get_status()
  41. local uci = UCI.cursor()
  42. local service = SYS.init.enabled("ddns") and 1 or 0
  43. local url_start = DISP.build_url("admin", "system", "startup")
  44. local data = {} -- Array to transfer data to javascript
  45. data[#data+1] = {
  46. enabled = service, -- service enabled
  47. url_up = url_start, -- link to enable DDS (System-Startup)
  48. }
  49. uci:foreach("ddns", "service", function (s)
  50. -- Get section we are looking at
  51. -- and enabled state
  52. local section = s[".name"]
  53. local enabled = tonumber(s["enabled"]) or 0
  54. local datelast = "_empty_" -- formatted date of last update
  55. local datenext = "_empty_" -- formatted date of next update
  56. -- get force seconds
  57. local force_seconds = DDNS.calc_seconds(
  58. tonumber(s["force_interval"]) or 72 ,
  59. s["force_unit"] or "hours" )
  60. -- get/validate pid and last update
  61. local pid = DDNS.get_pid(section)
  62. local uptime = SYS.uptime()
  63. local lasttime = DDNS.get_lastupd(section)
  64. if lasttime > uptime then -- /var might not be linked to /tmp
  65. lasttime = 0 -- and/or not cleared on reboot
  66. end
  67. -- no last update happen
  68. if lasttime == 0 then
  69. datelast = "_never_"
  70. -- we read last update
  71. else
  72. -- calc last update
  73. -- sys.epoch - sys uptime + lastupdate(uptime)
  74. local epoch = os.time() - uptime + lasttime
  75. -- use linux date to convert epoch
  76. datelast = DDNS.epoch2date(epoch)
  77. -- calc and fill next update
  78. datenext = DDNS.epoch2date(epoch + force_seconds)
  79. end
  80. -- process running but update needs to happen
  81. -- problems if force_seconds > uptime
  82. force_seconds = (force_seconds > uptime) and uptime or force_seconds
  83. if pid > 0 and ( lasttime + force_seconds - uptime ) <= 0 then
  84. datenext = "_verify_"
  85. -- run once
  86. elseif force_seconds == 0 then
  87. datenext = "_runonce_"
  88. -- no process running and NOT enabled
  89. elseif pid == 0 and enabled == 0 then
  90. datenext = "_disabled_"
  91. -- no process running and enabled
  92. elseif pid == 0 and enabled ~= 0 then
  93. datenext = "_stopped_"
  94. end
  95. -- get/set monitored interface and IP version
  96. local iface = s["interface"] or "_nonet_"
  97. local use_ipv6 = tonumber(s["use_ipv6"]) or 0
  98. if iface ~= "_nonet_" then
  99. local ipv = (use_ipv6 == 1) and "IPv6" or "IPv4"
  100. iface = ipv .. " / " .. iface
  101. end
  102. -- try to get registered IP
  103. local domain = s["domain"] or "_nodomain_"
  104. local dnsserver = s["dns_server"] or ""
  105. local force_ipversion = tonumber(s["force_ipversion"] or 0)
  106. local force_dnstcp = tonumber(s["force_dnstcp"] or 0)
  107. local command = [[/usr/lib/ddns/dynamic_dns_lucihelper.sh]]
  108. command = command .. [[ get_registered_ip ]] .. domain .. [[ ]] .. use_ipv6 ..
  109. [[ ]] .. force_ipversion .. [[ ]] .. force_dnstcp .. [[ ]] .. dnsserver
  110. local reg_ip = SYS.exec(command)
  111. if reg_ip == "" then
  112. reg_ip = "_nodata_"
  113. end
  114. -- fill transfer array
  115. data[#data+1] = {
  116. section = section,
  117. enabled = enabled,
  118. iface = iface,
  119. domain = domain,
  120. reg_ip = reg_ip,
  121. pid = pid,
  122. datelast = datelast,
  123. datenext = datenext
  124. }
  125. end)
  126. uci:unload("ddns")
  127. return data
  128. end
  129. -- called by XHR.get from detail_logview.htm
  130. function logread(section)
  131. -- read application settings
  132. local uci = UCI.cursor()
  133. local log_dir = uci:get("ddns", "global", "log_dir") or "/var/log/ddns"
  134. local lfile = log_dir .. "/" .. section .. ".log"
  135. local ldata = NXFS.readfile(lfile)
  136. if not ldata or #ldata == 0 then
  137. ldata="_nodata_"
  138. end
  139. uci:unload("ddns")
  140. HTTP.write(ldata)
  141. end
  142. -- called by XHR.get from overview_status.htm
  143. function startstop(section, enabled)
  144. local uci = UCI.cursor()
  145. local pid = DDNS.get_pid(section)
  146. local data = {} -- Array to transfer data to javascript
  147. -- if process running we want to stop and return
  148. if pid > 0 then
  149. local tmp = NX.kill(pid, 15) -- terminate
  150. NX.nanosleep(2) -- 2 second "show time"
  151. -- status changed so return full status
  152. data = _get_status()
  153. HTTP.prepare_content("application/json")
  154. HTTP.write_json(data)
  155. return
  156. end
  157. -- read uncommitted changes
  158. -- we don't save and commit data from other section or other options
  159. -- only enabled will be done
  160. local exec = true
  161. local changed = uci:changes("ddns")
  162. for k_config, v_section in pairs(changed) do
  163. -- security check because uci.changes only gets our config
  164. if k_config ~= "ddns" then
  165. exec = false
  166. break
  167. end
  168. for k_section, v_option in pairs(v_section) do
  169. -- check if only section of button was changed
  170. if k_section ~= section then
  171. exec = false
  172. break
  173. end
  174. for k_option, v_value in pairs(v_option) do
  175. -- check if only enabled was changed
  176. if k_option ~= "enabled" then
  177. exec = false
  178. break
  179. end
  180. end
  181. end
  182. end
  183. -- we can not execute because other
  184. -- uncommitted changes pending, so exit here
  185. if not exec then
  186. HTTP.write("_uncommitted_")
  187. return
  188. end
  189. -- save enable state
  190. uci:set("ddns", section, "enabled", ( (enabled == "true") and "1" or "0") )
  191. uci:save("ddns")
  192. uci:commit("ddns")
  193. uci:unload("ddns")
  194. -- start dynamic_dns_updater.sh script
  195. os.execute ([[/usr/lib/ddns/dynamic_dns_updater.sh %s 0 > /dev/null 2>&1 &]] % section)
  196. NX.nanosleep(3) -- 3 seconds "show time"
  197. -- status changed so return full status
  198. data = _get_status()
  199. HTTP.prepare_content("application/json")
  200. HTTP.write_json(data)
  201. end
  202. -- called by XHR.poll from overview_status.htm
  203. function status()
  204. local data = _get_status()
  205. HTTP.prepare_content("application/json")
  206. HTTP.write_json(data)
  207. end