2 LuCI - Lua Configuration Interface
4 Copyright 2008 Steven Barth <steven@midlink.org>
5 Copyright 2008 Jo-Philipp Wich <xm@leipzig.freifunk.net>
6 Copyright 2013 Manuel Munz <freifunk at somakoma dot de>
7 Copyright 2014 Christian Schoenebeck <christian dot schoenebeck at gmail dot com>
9 Licensed under the Apache License, Version 2.0 (the "License");
10 you may not use this file except in compliance with the License.
11 You may obtain a copy of the License at
13 http://www.apache.org/licenses/LICENSE-2.0
18 module("luci.controller.ddns", package.seeall)
20 local NX = require "nixio"
21 local NXFS = require "nixio.fs"
22 local DISP = require "luci.dispatcher"
23 local HTTP = require "luci.http"
24 local UCI = require "luci.model.uci"
25 local SYS = require "luci.sys"
26 local DDNS = require "luci.tools.ddns" -- ddns multiused functions
27 local UTIL = require "luci.util"
29 local luci_ddns_version = "2.1.0-4" -- luci-app-ddns / openwrt Makefile compatible version
30 local ddns_scripts_min = "2.1.0-3" -- minimum version of ddns-scripts required
33 -- no services_ipv6 file or no dynamic_dns_lucihelper.sh
35 if not nixio.fs.access("/usr/lib/ddns/services_ipv6")
36 or not nixio.fs.access("/usr/lib/ddns/dynamic_dns_lucihelper.sh") then
39 -- no config create an empty one
40 if not nixio.fs.access("/etc/config/ddns") then
41 nixio.fs.writefile("/etc/config/ddns", "")
44 entry( {"admin", "services", "ddns"}, cbi("ddns/overview"), _("Dynamic DNS"), 59)
45 entry( {"admin", "services", "ddns", "detail"}, cbi("ddns/detail"), nil ).leaf = true
46 entry( {"admin", "services", "ddns", "hints"}, cbi("ddns/hints",
47 {hideapplybtn=true, hidesavebtn=true, hideresetbtn=true}), nil ).leaf = true
48 entry( {"admin", "services", "ddns", "logview"}, call("logread") ).leaf = true
49 entry( {"admin", "services", "ddns", "startstop"}, call("startstop") ).leaf = true
50 entry( {"admin", "services", "ddns", "status"}, call("status") ).leaf = true
53 -- function to read all sections status and return data array
54 local function _get_status()
55 local uci = UCI.cursor()
56 local service = SYS.init.enabled("ddns") and 1 or 0
57 local url_start = DISP.build_url("admin", "system", "startup")
58 local luci_build = DDNS.ipkg_version("luci-app-ddns").version
59 local ddns_act = DDNS.ipkg_version("ddns-scripts").version
60 local data = {} -- Array to transfer data to javascript
63 enabled = service, -- service enabled
64 url_up = url_start, -- link to enable DDS (System-Startup)
65 luci_ver = luci_ddns_version, -- luci-app-ddns / openwrt Makefile compatible version
66 luci_build = luci_build, -- installed luci build
67 script_min = ddns_scripts_min, -- minimum version of ddns-scripts needed
68 script_ver = ddns_act -- installed ddns-scripts
71 uci:foreach("ddns", "service", function (s)
73 -- Get section we are looking at
75 local section = s[".name"]
76 local enabled = tonumber(s["enabled"]) or 0
77 local datelast = "_empty_" -- formated date of last update
78 local datenext = "_empty_" -- formated date of next update
81 local force_seconds = DDNS.calc_seconds(
82 tonumber(s["force_interval"]) or 72 ,
83 s["force_unit"] or "hours" )
84 -- get/validate pid and last update
85 local pid = DDNS.get_pid(section)
86 local uptime = SYS.uptime()
87 local lasttime = DDNS.get_lastupd(section)
88 if lasttime > uptime then -- /var might not be linked to /tmp
89 lasttime = 0 -- and/or not cleared on reboot
92 -- no last update happen
96 -- we read last update
99 -- sys.epoch - sys uptime + lastupdate(uptime)
100 local epoch = os.time() - uptime + lasttime
101 -- use linux date to convert epoch
102 datelast = DDNS.epoch2date(epoch)
103 -- calc and fill next update
104 datenext = DDNS.epoch2date(epoch + force_seconds)
107 -- process running but update needs to happen
108 -- problems it force_seconds > uptime
109 force_seconds = (force_seconds > uptime) and uptime or force_seconds
110 if pid > 0 and ( lasttime + force_seconds - uptime ) <= 0 then
111 datenext = "_verify_"
114 elseif force_seconds == 0 then
115 datenext = "_runonce_"
117 -- no process running and NOT enabled
118 elseif pid == 0 and enabled == 0 then
119 datenext = "_disabled_"
121 -- no process running and NOT
122 elseif pid == 0 and enabled ~= 0 then
123 datenext = "_stopped_"
126 -- get/set monitored interface and IP version
127 local iface = s["interface"] or "_nonet_"
128 local use_ipv6 = tonumber(s["use_ipv6"]) or 0
129 if iface ~= "_nonet_" then
130 local ipv = (use_ipv6 == 1) and "IPv6" or "IPv4"
131 iface = ipv .. " / " .. iface
134 -- try to get registered IP
135 local domain = s["domain"] or "_nodomain_"
136 local dnsserver = s["dns_server"] or ""
137 local force_ipversion = tonumber(s["force_ipversion"] or 0)
138 local force_dnstcp = tonumber(s["force_dnstcp"] or 0)
139 local command = [[/usr/lib/ddns/dynamic_dns_lucihelper.sh]]
140 command = command .. [[ get_registered_ip ]] .. domain .. [[ ]] .. use_ipv6 ..
141 [[ ]] .. force_ipversion .. [[ ]] .. force_dnstcp .. [[ ]] .. dnsserver
142 local reg_ip = SYS.exec(command)
147 -- fill transfer array
164 -- called by XHR.get from detail_logview.htm
165 function logread(section)
166 -- read application settings
167 local uci = UCI.cursor()
168 local log_dir = uci:get("ddns", "global", "log_dir") or "/var/log/ddns"
169 local lfile=log_dir .. "/" .. section .. ".log"
171 local ldata=NXFS.readfile(lfile)
172 if not ldata or #ldata == 0 then
179 -- called by XHR.get from overview_status.htm
180 function startstop(section, enabled)
181 local uci = UCI.cursor()
182 local data = {} -- Array to transfer data to javascript
184 -- if process running we want to stop and return
185 local pid = DDNS.get_pid(section)
187 local tmp = NX.kill(pid, 15) -- terminate
188 NX.nanosleep(2) -- 2 second "show time"
189 -- status changed so return full status
191 HTTP.prepare_content("application/json")
192 HTTP.write_json(data)
196 -- read uncommited changes
197 -- we don't save and commit data from other section or other options
198 -- only enabled will be done
200 local changed = uci:changes("ddns")
201 for k_config, v_section in pairs(changed) do
202 -- security check because uci.changes only gets our config
203 if k_config ~= "ddns" then
207 for k_section, v_option in pairs(v_section) do
208 -- check if only section of button was changed
209 if k_section ~= section then
213 for k_option, v_value in pairs(v_option) do
214 -- check if only enabled was changed
215 if k_option ~= "enabled" then
223 -- we can not execute because other
224 -- uncommited changes pending, so exit here
226 HTTP.write("_uncommited_")
231 uci:set("ddns", section, "enabled", ( (enabled == "true") and "1" or "0") )
236 -- start dynamic_dns_updater.sh script
237 os.execute ([[/usr/lib/ddns/dynamic_dns_updater.sh %s 0 > /dev/null 2>&1 &]] % section)
238 NX.nanosleep(3) -- 3 seconds "show time"
240 -- status changed so return full status
242 HTTP.prepare_content("application/json")
243 HTTP.write_json(data)
246 -- called by XHR.poll from overview_status.htm
248 local data = _get_status()
249 HTTP.prepare_content("application/json")
250 HTTP.write_json(data)
253 -- check if installed ddns-scripts version < required version
254 function update_needed()
255 local sver = DDNS.ipkg_version("ddns-scripts")
256 local rver = UTIL.split(ddns_scripts_min, "[%.%-]", nil, true)
257 return (sver.major < (tonumber(rver[1]) or 0))
258 or (sver.minor < (tonumber(rver[2]) or 0))
259 or (sver.patch < (tonumber(rver[3]) or 0))
260 or (sver.build < (tonumber(rver[4]) or 0))