Merge pull request #248 from chris5560/master

luci-app-ddns: Update to support ddns-scripts 2.1.0-1
This commit is contained in:
Jo-Philipp Wich 2014-11-14 17:17:14 +01:00
commit 559bf9126c
13 changed files with 820 additions and 526 deletions

View file

@ -0,0 +1,25 @@
Version: 2.1.0-1
Date: 2014-11-09
ddns-scripts: 2.1.0-1 or greater needed
fix verify of entry for DNS server Issue #244
https://github.com/openwrt/luci/issues/244
add support for option 'update_script'
add display of version information when click on "Dynamic DNS" on overview page
add verify of installed ddns-scripts version and show as hint if not correct version
modified epoch to date conversation
cbi object Flag did not set section.changed state, fixed in tools.flag_parse function
ucitrack entry no longer needed and removed
minor fixes
--------------------------------------------------------------------------------
Version: 2.0.1-1
Date: 2014-09-21
ddns-scripts: 2.0.1-1 up to 2.0.1-9
New DDNS status in System->Status overview
New Overview page with option to start/stop a section
New Detail page with tabbed view incl. logfile viewer
Extended verify of all entries before save to config
incl. connect test to DNS- and Proxy-server
Support for all available options of ddns-scripts 1.x and 2.x

View file

@ -1,8 +1,3 @@
# supports ddns-scripts 1.0.0-23 and ddns-scripts starting
# PKG_VERSION:=2.0.1
# PKG_RELEASE:=8
# PKG_MAINTAINER:=Christian Schoenebeck <christian.schoenebeck@gmail.com>
PO = ddns PO = ddns
include ../../build/config.mk include ../../build/config.mk

View file

@ -16,15 +16,22 @@ $Id$
module("luci.controller.ddns", package.seeall) module("luci.controller.ddns", package.seeall)
require "nixio" local NX = require "nixio"
require "nixio.fs" local NXFS = require "nixio.fs"
require "luci.sys" local DISP = require "luci.dispatcher"
require "luci.http" local HTTP = require "luci.http"
require "luci.model.uci" local UCI = require "luci.model.uci"
require "luci.dispatcher" local SYS = require "luci.sys"
require "luci.tools.ddns" local DDNS = require "luci.tools.ddns" -- ddns multiused functions
local UTIL = require "luci.util"
local luci_ddns_version = "2.1.0-1" -- luci-app-ddns / openwrt Makefile compatible version
local ddns_scripts_min = "2.1.0-1" -- minimum version of ddns-scripts required
function index() function index()
-- above 'require "mod"' definitions are not recognized
-- inside index() during initialisation
-- no configuration file, don't start -- no configuration file, don't start
if not nixio.fs.access("/etc/config/ddns") then if not nixio.fs.access("/etc/config/ddns") then
return return
@ -44,25 +51,27 @@ function index()
entry( {"admin", "services", "ddns", "hints"}, cbi("ddns/hints", entry( {"admin", "services", "ddns", "hints"}, cbi("ddns/hints",
{hideapplybtn=true, hidesavebtn=true, hideresetbtn=true}), nil ).leaf = true {hideapplybtn=true, hidesavebtn=true, hideresetbtn=true}), nil ).leaf = true
entry( {"admin", "services", "ddns", "logview"}, call("logread") ).leaf = true entry( {"admin", "services", "ddns", "logview"}, call("logread") ).leaf = true
entry( {"admin", "services", "ddns", "status"}, call("status") ).leaf = true
entry( {"admin", "services", "ddns", "startstop"}, call("startstop") ).leaf = true entry( {"admin", "services", "ddns", "startstop"}, call("startstop") ).leaf = true
entry( {"admin", "services", "ddns", "status"}, call("status") ).leaf = true
end end
end end
-- function to read all sections status and return data array -- function to read all sections status and return data array
function _get_status() local function _get_status()
local uci = luci.model.uci.cursor() local uci = UCI.cursor()
local service = luci.sys.init.enabled("ddns") and 1 or 0 local service = SYS.init.enabled("ddns") and 1 or 0
local url_start = luci.dispatcher.build_url("admin", "system", "startup") local url_start = DISP.build_url("admin", "system", "startup")
local data = {} -- Array to transfer data to javascript local luci_build = DDNS.ipkg_version("luci-app-ddns").version
local ddns_act = DDNS.ipkg_version("ddns-scripts").version
-- read application settings local data = {} -- Array to transfer data to javascript
local date_format = uci:get("ddns", "global", "date_format") or "%F %R"
local run_dir = uci:get("ddns", "global", "run_dir") or "/var/run/ddns"
data[#data+1] = { data[#data+1] = {
enabled = service, -- service enabled enabled = service, -- service enabled
url_up = url_start -- link to enable DDS (System-Startup) url_up = url_start, -- link to enable DDS (System-Startup)
luci_ver = luci_ddns_version, -- luci-app-ddns / openwrt Makefile compatible version
luci_build = luci_build, -- installed luci build
script_min = ddns_scripts_min, -- minimum version of ddns-scripts needed
script_ver = ddns_act -- installed ddns-scripts
} }
uci:foreach("ddns", "service", function (s) uci:foreach("ddns", "service", function (s)
@ -75,13 +84,13 @@ function _get_status()
local datenext = "_empty_" -- formated date of next update local datenext = "_empty_" -- formated date of next update
-- get force seconds -- get force seconds
local force_seconds = luci.tools.ddns.calc_seconds( local force_seconds = DDNS.calc_seconds(
tonumber(s["force_interval"]) or 72 , tonumber(s["force_interval"]) or 72 ,
s["force_unit"] or "hours" ) s["force_unit"] or "hours" )
-- get/validate pid and last update -- get/validate pid and last update
local pid = luci.tools.ddns.get_pid(section, run_dir) local pid = DDNS.get_pid(section)
local uptime = luci.sys.uptime() local uptime = SYS.uptime()
local lasttime = tonumber(nixio.fs.readfile("%s/%s.update" % { run_dir, section } ) or 0 ) local lasttime = DDNS.get_lastupd(section)
if lasttime > uptime then -- /var might not be linked to /tmp if lasttime > uptime then -- /var might not be linked to /tmp
lasttime = 0 -- and/or not cleared on reboot lasttime = 0 -- and/or not cleared on reboot
end end
@ -96,10 +105,9 @@ function _get_status()
-- sys.epoch - sys uptime + lastupdate(uptime) -- sys.epoch - sys uptime + lastupdate(uptime)
local epoch = os.time() - uptime + lasttime local epoch = os.time() - uptime + lasttime
-- use linux date to convert epoch -- use linux date to convert epoch
datelast = luci.sys.exec([[/bin/date -d @]] .. epoch .. [[ +']] .. date_format .. [[']]) datelast = DDNS.epoch2date(epoch)
-- calc and fill next update -- calc and fill next update
datenext = luci.sys.exec([[/bin/date -d @]] .. (epoch + force_seconds) .. datenext = DDNS.epoch2date(epoch + force_seconds)
[[ +']] .. date_format .. [[']])
end end
-- process running but update needs to happen -- process running but update needs to happen
@ -137,7 +145,7 @@ function _get_status()
local command = [[/usr/lib/ddns/dynamic_dns_lucihelper.sh]] local command = [[/usr/lib/ddns/dynamic_dns_lucihelper.sh]]
command = command .. [[ get_registered_ip ]] .. domain .. [[ ]] .. use_ipv6 .. command = command .. [[ get_registered_ip ]] .. domain .. [[ ]] .. use_ipv6 ..
[[ ]] .. force_ipversion .. [[ ]] .. force_dnstcp .. [[ ]] .. dnsserver [[ ]] .. force_ipversion .. [[ ]] .. force_dnstcp .. [[ ]] .. dnsserver
local reg_ip = luci.sys.exec(command) local reg_ip = SYS.exec(command)
if reg_ip == "" then if reg_ip == "" then
reg_ip = "_nodata_" reg_ip = "_nodata_"
end end
@ -156,41 +164,38 @@ function _get_status()
end) end)
uci:unload("ddns") uci:unload("ddns")
return data return data
end end
-- called by XHR.get from detail_logview.htm -- called by XHR.get from detail_logview.htm
function logread(section) function logread(section)
-- read application settings -- read application settings
local uci = luci.model.uci.cursor() local uci = UCI.cursor()
local log_dir = uci:get("ddns", "global", "log_dir") or "/var/log/ddns" local log_dir = uci:get("ddns", "global", "log_dir") or "/var/log/ddns"
local lfile=log_dir .. "/" .. section .. ".log" local lfile=log_dir .. "/" .. section .. ".log"
local ldata=nixio.fs.readfile(lfile) local ldata=NXFS.readfile(lfile)
if not ldata or #ldata == 0 then if not ldata or #ldata == 0 then
ldata="_nodata_" ldata="_nodata_"
end end
luci.http.write(ldata) uci:unload("ddns")
HTTP.write(ldata)
end end
-- called by XHR.get from overview_status.htm -- called by XHR.get from overview_status.htm
function startstop(section, enabled) function startstop(section, enabled)
-- Array to transfer data to javascript local uci = UCI.cursor()
local data = {} local data = {} -- Array to transfer data to javascript
-- read application settings
local uci = luci.model.uci.cursor()
local run_dir = uci:get("ddns", "global", "run_dir") or "/var/run/ddns"
-- if process running we want to stop and return -- if process running we want to stop and return
local pid = luci.tools.ddns.get_pid(section, run_dir) local pid = DDNS.get_pid(section)
if pid > 0 then if pid > 0 then
os.execute ([[kill -9 %s]] % pid) local tmp = NX.kill(pid, 15) -- terminate
nixio.nanosleep(2) -- 2 second "show time" NX.nanosleep(2) -- 2 second "show time"
-- status changed so return full status -- status changed so return full status
data = _get_status() data = _get_status()
luci.http.prepare_content("application/json") HTTP.prepare_content("application/json")
luci.http.write_json(data) HTTP.write_json(data)
return return
end end
@ -219,13 +224,12 @@ function startstop(section, enabled)
end end
end end
end end
end end
-- we can not execute because other -- we can not execute because other
-- uncommited changes pending, so exit here -- uncommited changes pending, so exit here
if not exec then if not exec then
luci.http.write("_uncommited_") HTTP.write("_uncommited_")
return return
end end
@ -237,17 +241,28 @@ function startstop(section, enabled)
-- start dynamic_dns_updater.sh script -- start dynamic_dns_updater.sh script
os.execute ([[/usr/lib/ddns/dynamic_dns_updater.sh %s 0 > /dev/null 2>&1 &]] % section) os.execute ([[/usr/lib/ddns/dynamic_dns_updater.sh %s 0 > /dev/null 2>&1 &]] % section)
nixio.nanosleep(3) -- 3 seconds "show time" NX.nanosleep(3) -- 3 seconds "show time"
-- status changed so return full status -- status changed so return full status
data = _get_status() data = _get_status()
luci.http.prepare_content("application/json") HTTP.prepare_content("application/json")
luci.http.write_json(data) HTTP.write_json(data)
end end
-- called by XHR.poll from overview_status.htm -- called by XHR.poll from overview_status.htm
function status() function status()
local data = _get_status() local data = _get_status()
luci.http.prepare_content("application/json") HTTP.prepare_content("application/json")
luci.http.write_json(data) HTTP.write_json(data)
end end
-- check if installed ddns-scripts version < required version
function update_needed()
local sver = DDNS.ipkg_version("ddns-scripts")
local rver = UTIL.split(ddns_scripts_min, "[%.%-]", nil, true)
return (sver.major < (tonumber(rver[1]) or 0))
or (sver.minor < (tonumber(rver[2]) or 0))
or (sver.patch < (tonumber(rver[3]) or 0))
or (sver.build < (tonumber(rver[4]) or 0))
end

View file

@ -21,50 +21,52 @@ You may obtain a copy of the License at
$Id$ $Id$
]]-- ]]--
require "luci.dispatcher" local NX = require "nixio"
require "nixio.fs" local FS = require "nixio.fs"
require "luci.sys" local SYS = require "luci.sys"
require "luci.tools.webadmin" local UTIL = require "luci.util"
require "luci.cbi.datatypes" local DISP = require "luci.dispatcher"
require "luci.tools.ddns" -- ddns multiused functions local WADM = require "luci.tools.webadmin"
local DTYP = require "luci.cbi.datatypes"
local DDNS = require "luci.tools.ddns" -- ddns multiused functions
-- takeover arguments -- takeover arguments -- #######################################################
section = arg[1] section = arg[1]
-- check supported options -- check supported options -- ##################################################
-- saved to local vars here because doing multiple os calls slow down the system -- saved to local vars here because doing multiple os calls slow down the system
has_ipv6 = luci.tools.ddns.check_ipv6() -- IPv6 support has_ipv6 = DDNS.check_ipv6() -- IPv6 support
has_ssl = luci.tools.ddns.check_ssl() -- HTTPS support has_ssl = DDNS.check_ssl() -- HTTPS support
has_proxy = luci.tools.ddns.check_proxy() -- Proxy support has_proxy = DDNS.check_proxy() -- Proxy support
has_dnstcp = luci.tools.ddns.check_bind_host() -- DNS TCP support has_dnstcp = DDNS.check_bind_host() -- DNS TCP support
has_force = has_ssl and has_dnstcp -- Force IP Protocoll has_force = has_ssl and has_dnstcp -- Force IP Protocoll
-- html constants -- html constants -- ###########################################################
font_red = "<font color='red'>" font_red = "<font color='red'>"
font_off = "</font>" font_off = "</font>"
bold_on = "<strong>" bold_on = "<strong>"
bold_off = "</strong>" bold_off = "</strong>"
-- error text constants -- error text constants -- #####################################################
err_ipv6_plain = translate("IPv6 not supported") .. " - " .. err_ipv6_plain = translate("IPv6 not supported") .. " - " ..
translate("please select 'IPv4' address version") translate("please select 'IPv4' address version")
err_ipv6_basic = bold_on .. err_ipv6_basic = bold_on ..
font_red .. font_red ..
translate("IPv6 not supported") .. translate("IPv6 not supported") ..
font_off .. font_off ..
"<br />" .. translate("please select 'IPv4' address version") .. "<br />" .. translate("please select 'IPv4' address version") ..
bold_off bold_off
err_ipv6_other = bold_on .. err_ipv6_other = bold_on ..
font_red .. font_red ..
translate("IPv6 not supported") .. translate("IPv6 not supported") ..
font_off .. font_off ..
"<br />" .. translate("please select 'IPv4' address version in") .. " " .. "<br />" .. translate("please select 'IPv4' address version in") .. " " ..
[[<a href="]] .. [[<a href="]] ..
luci.dispatcher.build_url("admin", "services", "ddns", "detail", section) .. DISP.build_url("admin", "services", "ddns", "detail", section) ..
"?tab.dns." .. section .. "=basic" .. "?tab.dns." .. section .. "=basic" ..
[[">]] .. [[">]] ..
translate("Basic Settings") .. translate("Basic Settings") ..
[[</a>]] .. [[</a>]] ..
bold_off bold_off
function err_tab_basic(self) function err_tab_basic(self)
@ -108,10 +110,10 @@ local function _verify_ip_source()
_script = ips:formvalue(section) _script = ips:formvalue(section)
end end
local command = [[/usr/lib/ddns/dynamic_dns_lucihelper.sh get_local_ip ]] .. local command = [[/usr/lib/ddns/dynamic_dns_lucihelper.sh get_local_ip ]] ..
_ipv6 .. [[ ]] .. _source .. [[ ]] .. _network .. [[ ]] .. _ipv6 .. [[ ]] .. _source .. [[ ]] .. _network .. [[ ]] ..
_url .. [[ ]] .. _interface .. [[ ]] .. _script.. [[ ]] .. _proxy _url .. [[ ]] .. _interface .. [[ ]] .. _script.. [[ ]] .. _proxy
local ret = luci.sys.call(command) local ret = SYS.call(command)
if ret == 0 then if ret == 0 then
return true -- valid return true -- valid
@ -120,26 +122,36 @@ local function _verify_ip_source()
end end
end end
-- cbi-map definition -- cbi-map definition -- #######################################################
m = Map("ddns") m = Map("ddns")
m.title = [[<a href="]] .. luci.dispatcher.build_url("admin", "services", "ddns") .. [[">]] .. -- first need to close <a> from cbi map template our <a> closed by template
translate("Dynamic DNS") .. [[</a>]] m.title = [[</a><a href="]] .. DISP.build_url("admin", "services", "ddns") .. [[">]] ..
translate("Dynamic DNS")
m.description = translate("Dynamic DNS allows that your router can be reached with " .. m.description = translate("Dynamic DNS allows that your router can be reached with " ..
"a fixed hostname while having a dynamically changing " .. "a fixed hostname while having a dynamically changing " ..
"IP address.") "IP address.")
m.redirect = luci.dispatcher.build_url("admin", "services", "ddns") m.redirect = DISP.build_url("admin", "services", "ddns")
-- read application settings m.on_after_commit = function(self)
if self.changed then -- changes ?
local pid = DDNS.get_pid(section)
if pid > 0 then -- running ?
local tmp = NX.kill(pid, 1) -- send SIGHUP
end
end
end
-- read application settings -- ################################################
-- date format; if not set use ISO format -- date format; if not set use ISO format
date_format = m.uci:get(m.config, "global", "date_format") or "%F %R" date_format = m.uci:get(m.config, "global", "date_format") or "%F %R"
-- log directory -- log directory
log_dir = m.uci:get(m.config, "global", "log_dir") or "/var/log/ddns" log_dir = m.uci:get(m.config, "global", "log_dir") or "/var/log/ddns"
-- cbi-section definition -- cbi-section definition -- ###################################################
ns = m:section( NamedSection, section, "service", ns = m:section( NamedSection, section, "service",
translate("Details for") .. ([[: <strong>%s</strong>]] % section), translate("Details for") .. ([[: <strong>%s</strong>]] % section),
translate("Configure here the details for selected Dynamic DNS service") ) translate("Configure here the details for selected Dynamic DNS service") )
ns.instance = section -- arg [1] ns.instance = section -- arg [1]
@ -148,16 +160,19 @@ ns:tab("advanced", translate("Advanced Settings"), nil )
ns:tab("timer", translate("Timer Settings"), nil ) ns:tab("timer", translate("Timer Settings"), nil )
ns:tab("logview", translate("Log File Viewer"), nil ) ns:tab("logview", translate("Log File Viewer"), nil )
-- TAB: Basic ################################################################## -- TAB: Basic #####################################################################################
-- enabled -- enabled -- #################################################################
en = ns:taboption("basic", Flag, "enabled", en = ns:taboption("basic", Flag, "enabled",
translate("Enabled"), translate("Enabled"),
translate("If this service section is disabled it could not be started." .. "<br />" .. translate("If this service section is disabled it could not be started." .. "<br />" ..
"Neither from LuCI interface nor from console") ) "Neither from LuCI interface nor from console") )
en.orientation = "horizontal" en.orientation = "horizontal"
function en.parse(self, section)
DDNS.flag_parse(self, section)
end
-- use_ipv6 (NEW) -- use_ipv6 (NEW) -- ##########################################################
usev6 = ns:taboption("basic", ListValue, "use_ipv6", usev6 = ns:taboption("basic", ListValue, "use_ipv6",
translate("IP address version"), translate("IP address version"),
translate("Defines which IP address 'IPv4/IPv6' is send to the DDNS provider") ) translate("Defines which IP address 'IPv4/IPv6' is send to the DDNS provider") )
usev6.widget = "radio" usev6.widget = "radio"
@ -187,8 +202,8 @@ function usev6.write(self, section, value)
end end
end end
-- IPv4 - service_name -- IPv4 - service_name -- ######################################################
svc4 = ns:taboption("basic", ListValue, "ipv4_service_name", svc4 = ns:taboption("basic", ListValue, "ipv4_service_name",
translate("DDNS Service provider") .. " [IPv4]" ) translate("DDNS Service provider") .. " [IPv4]" )
svc4.default = "-" svc4.default = "-"
svc4:depends("use_ipv6", "0") -- only show on IPv4 svc4:depends("use_ipv6", "0") -- only show on IPv4
@ -206,11 +221,11 @@ if fd4 then
fd4:close() fd4:close()
end end
for _, v in luci.util.vspairs(services4) do svc4:value(v) end for _, v in UTIL.vspairs(services4) do svc4:value(v) end
svc4:value("-", translate("-- custom --") ) svc4:value("-", translate("-- custom --") )
function svc4.cfgvalue(self, section) function svc4.cfgvalue(self, section)
local v = luci.tools.ddns.read_value(self, section, "service_name") local v = DDNS.read_value(self, section, "service_name")
if not v or #v == 0 then if not v or #v == 0 then
return "-" return "-"
else else
@ -236,8 +251,8 @@ function svc4.write(self, section, value)
end end
end end
-- IPv6 - service_name -- IPv6 - service_name -- ######################################################
svc6 = ns:taboption("basic", ListValue, "ipv6_service_name", svc6 = ns:taboption("basic", ListValue, "ipv6_service_name",
translate("DDNS Service provider") .. " [IPv6]" ) translate("DDNS Service provider") .. " [IPv6]" )
svc6.default = "-" svc6.default = "-"
svc6:depends("use_ipv6", "1") -- only show on IPv6 svc6:depends("use_ipv6", "1") -- only show on IPv6
@ -258,11 +273,11 @@ if fd6 then
fd6:close() fd6:close()
end end
for _, v in luci.util.vspairs(services6) do svc6:value(v) end for _, v in UTIL.vspairs(services6) do svc6:value(v) end
svc6:value("-", translate("-- custom --") ) svc6:value("-", translate("-- custom --") )
function svc6.cfgvalue(self, section) function svc6.cfgvalue(self, section)
local v = luci.tools.ddns.read_value(self, section, "service_name") local v = DDNS.read_value(self, section, "service_name")
if not v or #v == 0 then if not v or #v == 0 then
return "-" return "-"
else else
@ -289,8 +304,8 @@ function svc6.write(self, section, value)
end end
end end
-- IPv4/IPv6 - update_url -- IPv4/IPv6 - update_url -- ###################################################
uurl = ns:taboption("basic", Value, "update_url", uurl = ns:taboption("basic", Value, "update_url",
translate("Custom update-URL"), translate("Custom update-URL"),
translate("Update URL to be used for updating your DDNS Provider." .. "<br />" .. translate("Update URL to be used for updating your DDNS Provider." .. "<br />" ..
"Follow instructions you will find on their WEB page.") ) "Follow instructions you will find on their WEB page.") )
@ -312,22 +327,22 @@ function uurl.validate(self, value)
return nil, err_tab_basic(self) .. translate("either url or script could be set") return nil, err_tab_basic(self) .. translate("either url or script could be set")
end end
local url = luci.tools.ddns.parse_url(value) local url = DDNS.parse_url(value)
if not url.scheme == "http" then if not url.scheme == "http" then
return nil, err_tab_basic(self) .. translate("must start with 'http://'") return nil, err_tab_basic(self) .. translate("must start with 'http://'")
elseif not url.query then elseif not url.query then
return nil, err_tab_basic(self) .. "<QUERY> " .. translate("missing / required") return nil, err_tab_basic(self) .. "<QUERY> " .. translate("missing / required")
elseif not url.host then elseif not url.host then
return nil, err_tab_basic(self) .. "<HOST> " .. translate("missing / required") return nil, err_tab_basic(self) .. "<HOST> " .. translate("missing / required")
elseif luci.sys.call([[nslookup ]] .. url.host .. [[ >/dev/null 2>&1]]) ~= 0 then elseif SYS.call([[nslookup ]] .. url.host .. [[ >/dev/null 2>&1]]) ~= 0 then
return nil, err_tab_basic(self) .. translate("can not resolve host: ") .. url.host return nil, err_tab_basic(self) .. translate("can not resolve host: ") .. url.host
end end
return value return value
end end
-- IPv4/IPv6 - update_script -- IPv4/IPv6 - update_script -- ################################################
ush = ns:taboption("basic", Value, "update_script", ush = ns:taboption("basic", Value, "update_script",
translate("Custom update-script"), translate("Custom update-script"),
translate("Custom update script to be used for updating your DDNS Provider.") ) translate("Custom update script to be used for updating your DDNS Provider.") )
ush:depends("ipv4_service_name", "-") ush:depends("ipv4_service_name", "-")
@ -346,29 +361,29 @@ function ush.validate(self, value)
end end
elseif (#url > 0) then elseif (#url > 0) then
return nil, err_tab_basic(self) .. translate("either url or script could be set") return nil, err_tab_basic(self) .. translate("either url or script could be set")
elseif not nixio.fs.access(value) then elseif not FS.access(value) then
return nil, err_tab_basic(self) .. translate("File not found") return nil, err_tab_basic(self) .. translate("File not found")
end end
return value return value
end end
-- IPv4/IPv6 - domain -- IPv4/IPv6 - domain -- #######################################################
dom = ns:taboption("basic", Value, "domain", dom = ns:taboption("basic", Value, "domain",
translate("Hostname/Domain"), translate("Hostname/Domain"),
translate("Replaces [DOMAIN] in Update-URL") ) translate("Replaces [DOMAIN] in Update-URL") )
dom.rmempty = false dom.rmempty = false
dom.placeholder = "mypersonaldomain.dyndns.org" dom.placeholder = "mypersonaldomain.dyndns.org"
function dom.validate(self, value) function dom.validate(self, value)
if not value if not value
or not (#value > 0) or not (#value > 0)
or not luci.cbi.datatypes.hostname(value) then or not DTYP.hostname(value) then
return nil, err_tab_basic(self) .. translate("invalid - Sample") .. ": 'mypersonaldomain.dyndns.org'" return nil, err_tab_basic(self) .. translate("invalid - Sample") .. ": 'mypersonaldomain.dyndns.org'"
else else
return value return value
end end
end end
-- IPv4/IPv6 - username -- IPv4/IPv6 - username -- #####################################################
user = ns:taboption("basic", Value, "username", user = ns:taboption("basic", Value, "username",
translate("Username"), translate("Username"),
translate("Replaces [USERNAME] in Update-URL") ) translate("Replaces [USERNAME] in Update-URL") )
@ -380,7 +395,7 @@ function user.validate(self, value)
return value return value
end end
-- IPv4/IPv6 - password -- IPv4/IPv6 - password -- #####################################################
pw = ns:taboption("basic", Value, "password", pw = ns:taboption("basic", Value, "password",
translate("Password"), translate("Password"),
translate("Replaces [PASSWORD] in Update-URL") ) translate("Replaces [PASSWORD] in Update-URL") )
@ -393,9 +408,9 @@ function pw.validate(self, value)
return value return value
end end
-- IPv4/IPv6 - use_https (NEW) -- IPv4/IPv6 - use_https (NEW) -- ##############################################
if has_ssl or ( ( m:get(section, "use_https") or "0" ) == "1" ) then if has_ssl or ( ( m:get(section, "use_https") or "0" ) == "1" ) then
https = ns:taboption("basic", Flag, "use_https", https = ns:taboption("basic", Flag, "use_https",
translate("Use HTTP Secure") ) translate("Use HTTP Secure") )
https.orientation = "horizontal" https.orientation = "horizontal"
https.rmempty = false -- force validate function https.rmempty = false -- force validate function
@ -410,6 +425,9 @@ if has_ssl or ( ( m:get(section, "use_https") or "0" ) == "1" ) then
end end
return value return value
end end
function https.parse(self, section)
DDNS.flag_parse(self, section)
end
function https.validate(self, value) function https.validate(self, value)
if (value == "1" and has_ssl ) or value == "0" then return value end if (value == "1" and has_ssl ) or value == "0" then return value end
return nil, err_tab_basic(self) .. translate("HTTPS not supported") .. " !" return nil, err_tab_basic(self) .. translate("HTTPS not supported") .. " !"
@ -424,10 +442,10 @@ if has_ssl or ( ( m:get(section, "use_https") or "0" ) == "1" ) then
end end
end end
-- IPv4/IPv6 - cacert (NEW) -- IPv4/IPv6 - cacert (NEW) -- #################################################
if has_ssl then if has_ssl then
cert = ns:taboption("basic", Value, "cacert", cert = ns:taboption("basic", Value, "cacert",
translate("Path to CA-Certificate"), translate("Path to CA-Certificate"),
translate("directory or path/file") .. "<br />" .. translate("directory or path/file") .. "<br />" ..
translate("or") .. bold_on .. " IGNORE " .. bold_off .. translate("or") .. bold_on .. " IGNORE " .. bold_off ..
translate("to run HTTPS without verification of server certificates (insecure)") ) translate("to run HTTPS without verification of server certificates (insecure)") )
@ -439,8 +457,8 @@ if has_ssl then
return "" -- supress validate error if NOT https return "" -- supress validate error if NOT https
end end
if value then -- otherwise errors in datatype check if value then -- otherwise errors in datatype check
if luci.cbi.datatypes.directory(value) if DTYP.directory(value)
or luci.cbi.datatypes.file(value) or DTYP.file(value)
or value == "IGNORE" then or value == "IGNORE" then
return value return value
end end
@ -450,8 +468,8 @@ if has_ssl then
end end
end end
-- use_syslog -- use_syslog -- ###############################################################
slog = ns:taboption("basic", ListValue, "use_syslog", slog = ns:taboption("basic", ListValue, "use_syslog",
translate("Log to syslog"), translate("Log to syslog"),
translate("Writes log messages to syslog. Critical Errors will always be written to syslog.") ) translate("Writes log messages to syslog. Critical Errors will always be written to syslog.") )
slog.default = "0" slog.default = "0"
@ -461,18 +479,21 @@ slog:value("2", translate("Notice"))
slog:value("3", translate("Warning")) slog:value("3", translate("Warning"))
slog:value("4", translate("Error")) slog:value("4", translate("Error"))
-- use_logfile (NEW) -- use_logfile (NEW) -- ########################################################
logf = ns:taboption("basic", Flag, "use_logfile", logf = ns:taboption("basic", Flag, "use_logfile",
translate("Log to file"), translate("Log to file"),
translate("Writes detailed messages to log file. File will be truncated automatically.") .. "<br />" .. translate("Writes detailed messages to log file. File will be truncated automatically.") .. "<br />" ..
translate("File") .. [[: "]] .. log_dir .. [[/]] .. section .. [[.log"]] ) translate("File") .. [[: "]] .. log_dir .. [[/]] .. section .. [[.log"]] )
logf.orientation = "horizontal" logf.orientation = "horizontal"
logf.rmempty = false -- we want to save in /etc/config/ddns file on "0" because logf.rmempty = false -- we want to save in /etc/config/ddns file on "0" because
logf.default = "1" -- if not defined write to log by default logf.default = "1" -- if not defined write to log by default
function logf.parse(self, section)
DDNS.flag_parse(self, section)
end
-- TAB: Advanced ############################################################## -- TAB: Advanced ##################################################################################
-- IPv4 - ip_source -- IPv4 - ip_source -- #########################################################
src4 = ns:taboption("advanced", ListValue, "ipv4_source", src4 = ns:taboption("advanced", ListValue, "ipv4_source",
translate("IP address source") .. " [IPv4]", translate("IP address source") .. " [IPv4]",
translate("Defines the source to read systems IPv4-Address from, that will be send to the DDNS provider") ) translate("Defines the source to read systems IPv4-Address from, that will be send to the DDNS provider") )
src4:depends("use_ipv6", "0") -- IPv4 selected src4:depends("use_ipv6", "0") -- IPv4 selected
@ -481,11 +502,11 @@ src4:value("network", translate("Network"))
src4:value("web", translate("URL")) src4:value("web", translate("URL"))
src4:value("interface", translate("Interface")) src4:value("interface", translate("Interface"))
src4:value("script", translate("Script")) src4:value("script", translate("Script"))
function src4.cfgvalue(self, section) function src4.cfgvalue(self, section)
return luci.tools.ddns.read_value(self, section, "ip_source") return DDNS.read_value(self, section, "ip_source")
end end
function src4.validate(self, value) function src4.validate(self, value)
if usev6:formvalue(section) == "1" then if usev6:formvalue(section) == "1" then
return "" -- ignore on IPv6 selected return "" -- ignore on IPv6 selected
elseif not _verify_ip_source() then elseif not _verify_ip_source() then
return nil, err_tab_adv(self) .. return nil, err_tab_adv(self) ..
@ -495,7 +516,7 @@ function src4.validate(self, value)
end end
end end
function src4.write(self, section, value) function src4.write(self, section, value)
if usev6:formvalue(section) == "1" then if usev6:formvalue(section) == "1" then
return true -- ignore on IPv6 selected return true -- ignore on IPv6 selected
elseif value == "network" then elseif value == "network" then
self.map:del(section, "ip_url") -- delete not need parameters self.map:del(section, "ip_url") -- delete not need parameters
@ -514,12 +535,12 @@ function src4.write(self, section, value)
self.map:del(section, "ip_url") -- delete not need parameters self.map:del(section, "ip_url") -- delete not need parameters
self.map:del(section, "ip_interface") self.map:del(section, "ip_interface")
end end
self.map:del(section, self.option) -- delete "ipv4_source" helper self.map:del(section, self.option) -- delete "ipv4_source" helper
return self.map:set(section, "ip_source", value) -- and write "ip_source return self.map:set(section, "ip_source", value) -- and write "ip_source
end end
-- IPv6 - ip_source -- IPv6 - ip_source -- #########################################################
src6 = ns:taboption("advanced", ListValue, "ipv6_source", src6 = ns:taboption("advanced", ListValue, "ipv6_source",
translate("IP address source") .. " [IPv6]", translate("IP address source") .. " [IPv6]",
translate("Defines the source to read systems IPv6-Address from, that will be send to the DDNS provider") ) translate("Defines the source to read systems IPv6-Address from, that will be send to the DDNS provider") )
src6:depends("use_ipv6", 1) -- IPv6 selected src6:depends("use_ipv6", 1) -- IPv6 selected
@ -528,14 +549,14 @@ src6:value("network", translate("Network"))
src6:value("web", translate("URL")) src6:value("web", translate("URL"))
src6:value("interface", translate("Interface")) src6:value("interface", translate("Interface"))
src6:value("script", translate("Script")) src6:value("script", translate("Script"))
if not has_ipv6 then if not has_ipv6 then
src6.description = err_ipv6_other src6.description = err_ipv6_other
end end
function src6.cfgvalue(self, section) function src6.cfgvalue(self, section)
return luci.tools.ddns.read_value(self, section, "ip_source") return DDNS.read_value(self, section, "ip_source")
end end
function src6.validate(self, value) function src6.validate(self, value)
if usev6:formvalue(section) == "0" then if usev6:formvalue(section) == "0" then
return "" -- ignore on IPv4 selected return "" -- ignore on IPv4 selected
elseif not has_ipv6 then elseif not has_ipv6 then
return nil, err_tab_adv(self) .. err_ipv6_plain return nil, err_tab_adv(self) .. err_ipv6_plain
@ -547,7 +568,7 @@ function src6.validate(self, value)
end end
end end
function src6.write(self, section, value) function src6.write(self, section, value)
if usev6:formvalue(section) == "0" then if usev6:formvalue(section) == "0" then
return true -- ignore on IPv4 selected return true -- ignore on IPv4 selected
elseif value == "network" then elseif value == "network" then
self.map:del(section, "ip_url") -- delete not need parameters self.map:del(section, "ip_url") -- delete not need parameters
@ -566,19 +587,19 @@ function src6.write(self, section, value)
self.map:del(section, "ip_url") -- delete not need parameters self.map:del(section, "ip_url") -- delete not need parameters
self.map:del(section, "ip_interface") self.map:del(section, "ip_interface")
end end
self.map:del(section, self.option) -- delete "ipv4_source" helper self.map:del(section, self.option) -- delete "ipv4_source" helper
return self.map:set(section, "ip_source", value) -- and write "ip_source return self.map:set(section, "ip_source", value) -- and write "ip_source
end end
-- IPv4 - ip_network (default "wan") -- IPv4 - ip_network (default "wan") -- ########################################
ipn4 = ns:taboption("advanced", ListValue, "ipv4_network", ipn4 = ns:taboption("advanced", ListValue, "ipv4_network",
translate("Network") .. " [IPv4]", translate("Network") .. " [IPv4]",
translate("Defines the network to read systems IPv4-Address from") ) translate("Defines the network to read systems IPv4-Address from") )
ipn4:depends("ipv4_source", "network") ipn4:depends("ipv4_source", "network")
ipn4.default = "wan" ipn4.default = "wan"
luci.tools.webadmin.cbi_add_networks(ipn4) WADM.cbi_add_networks(ipn4)
function ipn4.cfgvalue(self, section) function ipn4.cfgvalue(self, section)
return luci.tools.ddns.read_value(self, section, "ip_network") return DDNS.read_value(self, section, "ip_network")
end end
function ipn4.validate(self, value) function ipn4.validate(self, value)
if usev6:formvalue(section) == "1" if usev6:formvalue(section) == "1"
@ -599,24 +620,24 @@ function ipn4.write(self, section, value)
else else
-- set also as "interface" for monitoring events changes/hot-plug -- set also as "interface" for monitoring events changes/hot-plug
self.map:set(section, "interface", value) self.map:set(section, "interface", value)
self.map:del(section, self.option) -- delete "ipv4_network" helper self.map:del(section, self.option) -- delete "ipv4_network" helper
return self.map:set(section, "ip_network", value) -- and write "ip_network" return self.map:set(section, "ip_network", value) -- and write "ip_network"
end end
end end
-- IPv6 - ip_network (default "wan6") -- IPv6 - ip_network (default "wan6") -- #######################################
ipn6 = ns:taboption("advanced", ListValue, "ipv6_network", ipn6 = ns:taboption("advanced", ListValue, "ipv6_network",
translate("Network") .. " [IPv6]" ) translate("Network") .. " [IPv6]" )
ipn6:depends("ipv6_source", "network") ipn6:depends("ipv6_source", "network")
ipn6.default = "wan6" ipn6.default = "wan6"
luci.tools.webadmin.cbi_add_networks(ipn6) WADM.cbi_add_networks(ipn6)
if has_ipv6 then if has_ipv6 then
ipn6.description = translate("Defines the network to read systems IPv6-Address from") ipn6.description = translate("Defines the network to read systems IPv6-Address from")
else else
ipn6.description = err_ipv6_other ipn6.description = err_ipv6_other
end end
function ipn6.cfgvalue(self, section) function ipn6.cfgvalue(self, section)
return luci.tools.ddns.read_value(self, section, "ip_network") return DDNS.read_value(self, section, "ip_network")
end end
function ipn6.validate(self, value) function ipn6.validate(self, value)
if usev6:formvalue(section) == "0" if usev6:formvalue(section) == "0"
@ -639,19 +660,19 @@ function ipn6.write(self, section, value)
else else
-- set also as "interface" for monitoring events changes/hotplug -- set also as "interface" for monitoring events changes/hotplug
self.map:set(section, "interface", value) self.map:set(section, "interface", value)
self.map:del(section, self.option) -- delete "ipv6_network" helper self.map:del(section, self.option) -- delete "ipv6_network" helper
return self.map:set(section, "ip_network", value) -- and write "ip_network" return self.map:set(section, "ip_network", value) -- and write "ip_network"
end end
end end
-- IPv4 - ip_url (default "checkip.dyndns.com") -- IPv4 - ip_url (default "checkip.dyndns.com") -- #############################
iurl4 = ns:taboption("advanced", Value, "ipv4_url", iurl4 = ns:taboption("advanced", Value, "ipv4_url",
translate("URL to detect") .. " [IPv4]", translate("URL to detect") .. " [IPv4]",
translate("Defines the Web page to read systems IPv4-Address from") ) translate("Defines the Web page to read systems IPv4-Address from") )
iurl4:depends("ipv4_source", "web") iurl4:depends("ipv4_source", "web")
iurl4.default = "http://checkip.dyndns.com" iurl4.default = "http://checkip.dyndns.com"
function iurl4.cfgvalue(self, section) function iurl4.cfgvalue(self, section)
return luci.tools.ddns.read_value(self, section, "ip_url") return DDNS.read_value(self, section, "ip_url")
end end
function iurl4.validate(self, value) function iurl4.validate(self, value)
if usev6:formvalue(section) == "1" if usev6:formvalue(section) == "1"
@ -663,14 +684,12 @@ function iurl4.validate(self, value)
return nil, err_tab_adv(self) .. translate("missing / required") return nil, err_tab_adv(self) .. translate("missing / required")
end end
local url = luci.tools.ddns.parse_url(value) local url = DDNS.parse_url(value)
if not (url.scheme == "http" or url.scheme == "https") then if not (url.scheme == "http" or url.scheme == "https") then
return nil, err_tab_adv(self) .. translate("must start with 'http://'") return nil, err_tab_adv(self) .. translate("must start with 'http://'")
elseif not url.host then elseif not url.host then
return nil, err_tab_adv(self) .. "<HOST> " .. translate("missing / required") return nil, err_tab_adv(self) .. "<HOST> " .. translate("missing / required")
elseif luci.sys.call([[nslookup ]] .. elseif SYS.call([[nslookup ]] .. url.host .. [[>/dev/null 2>&1]]) ~= 0 then
url.host ..
[[>/dev/null 2>&1]]) ~= 0 then
return nil, err_tab_adv(self) .. translate("can not resolve host: ") .. url.host return nil, err_tab_adv(self) .. translate("can not resolve host: ") .. url.host
else else
return value return value
@ -688,8 +707,8 @@ function iurl4.write(self, section, value)
end end
end end
-- IPv6 - ip_url (default "checkipv6.dyndns.com") -- IPv6 - ip_url (default "checkipv6.dyndns.com") -- ###########################
iurl6 = ns:taboption("advanced", Value, "ipv6_url", iurl6 = ns:taboption("advanced", Value, "ipv6_url",
translate("URL to detect") .. " [IPv6]" ) translate("URL to detect") .. " [IPv6]" )
iurl6:depends("ipv6_source", "web") iurl6:depends("ipv6_source", "web")
iurl6.default = "http://checkipv6.dyndns.com" iurl6.default = "http://checkipv6.dyndns.com"
@ -699,7 +718,7 @@ else
iurl6.description = err_ipv6_other iurl6.description = err_ipv6_other
end end
function iurl6.cfgvalue(self, section) function iurl6.cfgvalue(self, section)
return luci.tools.ddns.read_value(self, section, "ip_url") return DDNS.read_value(self, section, "ip_url")
end end
function iurl6.validate(self, value) function iurl6.validate(self, value)
if usev6:formvalue(section) == "0" if usev6:formvalue(section) == "0"
@ -713,14 +732,12 @@ function iurl6.validate(self, value)
return nil, err_tab_adv(self) .. translate("missing / required") return nil, err_tab_adv(self) .. translate("missing / required")
end end
local url = luci.tools.ddns.parse_url(value) local url = DDNS.parse_url(value)
if not (url.scheme == "http" or url.scheme == "https") then if not (url.scheme == "http" or url.scheme == "https") then
return nil, err_tab_adv(self) .. translate("must start with 'http://'") return nil, err_tab_adv(self) .. translate("must start with 'http://'")
elseif not url.host then elseif not url.host then
return nil, err_tab_adv(self) .. "<HOST> " .. translate("missing / required") return nil, err_tab_adv(self) .. "<HOST> " .. translate("missing / required")
elseif luci.sys.call([[nslookup ]] .. elseif SYS.call([[nslookup ]] .. url.host .. [[>/dev/null 2>&1]]) ~= 0 then
url.host ..
[[>/dev/null 2>&1]]) ~= 0 then
return nil, err_tab_adv(self) .. translate("can not resolve host: ") .. url.host return nil, err_tab_adv(self) .. translate("can not resolve host: ") .. url.host
else else
return value return value
@ -738,17 +755,17 @@ function iurl6.write(self, section, value)
end end
end end
-- IPv4 + IPv6 - ip_interface -- IPv4 + IPv6 - ip_interface -- ###############################################
ipi = ns:taboption("advanced", ListValue, "ip_interface", ipi = ns:taboption("advanced", ListValue, "ip_interface",
translate("Interface"), translate("Interface"),
translate("Defines the interface to read systems IP-Address from") ) translate("Defines the interface to read systems IP-Address from") )
ipi:depends("ipv4_source", "interface") -- IPv4 ipi:depends("ipv4_source", "interface") -- IPv4
ipi:depends("ipv6_source", "interface") -- or IPv6 ipi:depends("ipv6_source", "interface") -- or IPv6
for _, v in pairs(luci.sys.net.devices()) do for _, v in pairs(SYS.net.devices()) do
-- show only interface set to a network -- show only interface set to a network
-- and ignore loopback -- and ignore loopback
net = luci.tools.webadmin.iface_get_network(v) net = WADM.iface_get_network(v)
if net and net ~= "loopback" then if net and net ~= "loopback" then
ipi:value(v) ipi:value(v)
end end
end end
@ -767,14 +784,14 @@ function ipi.write(self, section, value)
else else
-- get network from device to -- get network from device to
-- set also as "interface" for monitoring events changes/hotplug -- set also as "interface" for monitoring events changes/hotplug
local net = luci.tools.webadmin.iface_get_network(value) local net = WADM.iface_get_network(value)
self.map:set(section, "interface", net) self.map:set(section, "interface", net)
return self.map:set(section, self.option, value) return self.map:set(section, self.option, value)
end end
end end
-- IPv4 + IPv6 - ip_script (NEW) -- IPv4 + IPv6 - ip_script (NEW) -- ############################################
ips = ns:taboption("advanced", Value, "ip_script", ips = ns:taboption("advanced", Value, "ip_script",
translate("Script"), translate("Script"),
translate("User defined script to read systems IP-Address") ) translate("User defined script to read systems IP-Address") )
ips:depends("ipv4_source", "script") -- IPv4 ips:depends("ipv4_source", "script") -- IPv4
@ -784,8 +801,8 @@ function ips.validate(self, value)
if (usev6:formvalue(section) == "0" and src4:formvalue(section) ~= "script") if (usev6:formvalue(section) == "0" and src4:formvalue(section) ~= "script")
or (usev6:formvalue(section) == "1" and src6:formvalue(section) ~= "script") then or (usev6:formvalue(section) == "1" and src6:formvalue(section) ~= "script") then
return "" return ""
elseif not value or not nixio.fs.access(value, "x") then elseif not value or not FS.access(value, "x") then
return nil, err_tab_adv(self) .. return nil, err_tab_adv(self) ..
translate("not found or not executable - Sample: '/path/to/script.sh'") translate("not found or not executable - Sample: '/path/to/script.sh'")
else else
return value return value
@ -800,19 +817,19 @@ function ips.write(self, section, value)
end end
end end
-- IPv4 - interface - default "wan" -- IPv4 - interface - default "wan" -- #########################################
-- event network to monitor changes/hotplug/dynamic_dns_updater.sh -- event network to monitor changes/hotplug/dynamic_dns_updater.sh
-- only needs to be set if "ip_source"="web" or "script" -- only needs to be set if "ip_source"="web" or "script"
-- if "ip_source"="network" or "interface" we use their network -- if "ip_source"="network" or "interface" we use their network
eif4 = ns:taboption("advanced", ListValue, "ipv4_interface", eif4 = ns:taboption("advanced", ListValue, "ipv4_interface",
translate("Event Network") .. " [IPv4]", translate("Event Network") .. " [IPv4]",
translate("Network on which the ddns-updater scripts will be started") ) translate("Network on which the ddns-updater scripts will be started") )
eif4:depends("ipv4_source", "web") eif4:depends("ipv4_source", "web")
eif4:depends("ipv4_source", "script") eif4:depends("ipv4_source", "script")
eif4.default = "wan" eif4.default = "wan"
luci.tools.webadmin.cbi_add_networks(eif4) WADM.cbi_add_networks(eif4)
function eif4.cfgvalue(self, section) function eif4.cfgvalue(self, section)
return luci.tools.ddns.read_value(self, section, "interface") return DDNS.read_value(self, section, "interface")
end end
function eif4.validate(self, value) function eif4.validate(self, value)
if usev6:formvalue(section) == "1" if usev6:formvalue(section) == "1"
@ -829,35 +846,35 @@ function eif4.write(self, section, value)
or src4:formvalue(section) == "interface" then or src4:formvalue(section) == "interface" then
return true -- ignore IPv6, network, interface return true -- ignore IPv6, network, interface
else else
self.map:del(section, self.option) -- delete "ipv4_interface" helper self.map:del(section, self.option) -- delete "ipv4_interface" helper
return self.map:set(section, "interface", value) -- and write "interface" return self.map:set(section, "interface", value) -- and write "interface"
end end
end end
-- IPv6 - interface (NEW) - default "wan6" -- IPv6 - interface (NEW) - default "wan6" -- ##################################
-- event network to monitor changes/hotplug (NEW) -- event network to monitor changes/hotplug (NEW)
-- only needs to be set if "ip_source"="web" or "script" -- only needs to be set if "ip_source"="web" or "script"
-- if "ip_source"="network" or "interface" we use their network -- if "ip_source"="network" or "interface" we use their network
eif6 = ns:taboption("advanced", ListValue, "ipv6_interface", eif6 = ns:taboption("advanced", ListValue, "ipv6_interface",
translate("Event Network") .. " [IPv6]" ) translate("Event Network") .. " [IPv6]" )
eif6:depends("ipv6_source", "web") eif6:depends("ipv6_source", "web")
eif6:depends("ipv6_source", "script") eif6:depends("ipv6_source", "script")
eif6.default = "wan6" eif6.default = "wan6"
luci.tools.webadmin.cbi_add_networks(eif6) WADM.cbi_add_networks(eif6)
if not has_ipv6 then if not has_ipv6 then
eif6.description = err_ipv6_other eif6.description = err_ipv6_other
else else
eif6.description = translate("Network on which the ddns-updater scripts will be started") eif6.description = translate("Network on which the ddns-updater scripts will be started")
end end
function eif6.cfgvalue(self, section) function eif6.cfgvalue(self, section)
return luci.tools.ddns.read_value(self, section, "interface") return DDNS.read_value(self, section, "interface")
end end
function eif6.validate(self, value) function eif6.validate(self, value)
if usev6:formvalue(section) == "0" if usev6:formvalue(section) == "0"
or src4:formvalue(section) == "network" or src4:formvalue(section) == "network"
or src4:formvalue(section) == "interface" then or src4:formvalue(section) == "interface" then
return "" -- ignore IPv4, network, interface return "" -- ignore IPv4, network, interface
elseif not has_ipv6 then elseif not has_ipv6 then
return nil, err_tab_adv(self) .. err_ipv6_plain return nil, err_tab_adv(self) .. err_ipv6_plain
else else
return value return value
@ -869,12 +886,12 @@ function eif6.write(self, section, value)
or src4:formvalue(section) == "interface" then or src4:formvalue(section) == "interface" then
return true -- ignore IPv4, network, interface return true -- ignore IPv4, network, interface
else else
self.map:del(section, self.option) -- delete "ipv6_interface" helper self.map:del(section, self.option) -- delete "ipv6_interface" helper
return self.map:set(section, "interface", value) -- and write "interface" return self.map:set(section, "interface", value) -- and write "interface"
end end
end end
-- IPv4 + IPv6 - force_ipversion (NEW) -- IPv4 + IPv6 - force_ipversion (NEW) -- ######################################
-- optional to force wget/curl and host to use only selected IP version -- optional to force wget/curl and host to use only selected IP version
-- command parameter "-4" or "-6" -- command parameter "-4" or "-6"
if has_force or ( ( m:get(section, "force_ipversion") or "0" ) ~= "0" ) then if has_force or ( ( m:get(section, "force_ipversion") or "0" ) ~= "0" ) then
@ -896,6 +913,9 @@ if has_force or ( ( m:get(section, "force_ipversion") or "0" ) ~= "0" ) then
if (value == "1" and has_force) or value == "0" then return value end if (value == "1" and has_force) or value == "0" then return value end
return nil, err_tab_adv(self) .. translate("Force IP Version not supported") return nil, err_tab_adv(self) .. translate("Force IP Version not supported")
end end
function fipv.parse(self, section)
DDNS.flag_parse(self, section)
end
function fipv.write(self, section, value) function fipv.write(self, section, value)
if value == "1" then if value == "1" then
return self.map:set(section, self.option, value) return self.map:set(section, self.option, value)
@ -905,9 +925,9 @@ if has_force or ( ( m:get(section, "force_ipversion") or "0" ) ~= "0" ) then
end end
end end
-- IPv4 + IPv6 - dns_server (NEW) -- IPv4 + IPv6 - dns_server (NEW) -- ###########################################
-- optional DNS Server to use resolving my IP if "ip_source"="web" -- optional DNS Server to use resolving my IP if "ip_source"="web"
dns = ns:taboption("advanced", Value, "dns_server", dns = ns:taboption("advanced", Value, "dns_server",
translate("DNS-Server"), translate("DNS-Server"),
translate("OPTIONAL: Use non-default DNS-Server to detect 'Registered IP'.") .. "<br />" .. translate("OPTIONAL: Use non-default DNS-Server to detect 'Registered IP'.") .. "<br />" ..
translate("Format: IP or FQDN")) translate("Format: IP or FQDN"))
@ -916,14 +936,14 @@ function dns.validate(self, value)
-- if .datatype is set, then it is checked before calling this function -- if .datatype is set, then it is checked before calling this function
if not value then if not value then
return "" -- ignore on empty return "" -- ignore on empty
elseif not luci.cbi.datatypes.hostname(value) then elseif not DTYP.host(value) then
return nil, err .. translate("use hostname, FQDN, IPv4- or IPv6-Address") return nil, err_tab_adv(self) .. translate("use hostname, FQDN, IPv4- or IPv6-Address")
else else
local ipv6 = usev6:formvalue(section) local ipv6 = usev6:formvalue(section)
local force = (fipv) and fipv:formvalue(section) or "0" local force = (fipv) and fipv:formvalue(section) or "0"
local command = [[/usr/lib/ddns/dynamic_dns_lucihelper.sh verify_dns ]] .. local command = [[/usr/lib/ddns/dynamic_dns_lucihelper.sh verify_dns ]] ..
value .. [[ ]] .. ipv6 .. [[ ]] .. force value .. [[ ]] .. ipv6 .. [[ ]] .. force
local ret = luci.sys.call(command) local ret = SYS.call(command)
if ret == 0 then return value -- everything OK if ret == 0 then return value -- everything OK
elseif ret == 2 then return nil, err_tab_adv(self) .. translate("nslookup can not resolve host") elseif ret == 2 then return nil, err_tab_adv(self) .. translate("nslookup can not resolve host")
elseif ret == 3 then return nil, err_tab_adv(self) .. translate("nc (netcat) can not connect") elseif ret == 3 then return nil, err_tab_adv(self) .. translate("nc (netcat) can not connect")
@ -933,7 +953,7 @@ function dns.validate(self, value)
end end
end end
-- IPv4 + IPv6 - force_dnstcp (NEW) -- IPv4 + IPv6 - force_dnstcp (NEW) -- #########################################
if has_dnstcp or ( ( m:get(section, "force_dnstcp") or "0" ) ~= "0" ) then if has_dnstcp or ( ( m:get(section, "force_dnstcp") or "0" ) ~= "0" ) then
tcp = ns:taboption("advanced", Flag, "force_dnstcp", tcp = ns:taboption("advanced", Flag, "force_dnstcp",
translate("Force TCP on DNS") ) translate("Force TCP on DNS") )
@ -955,12 +975,15 @@ if has_dnstcp or ( ( m:get(section, "force_dnstcp") or "0" ) ~= "0" ) then
end end
return nil, err_tab_adv(self) .. translate("DNS requests via TCP not supported") return nil, err_tab_adv(self) .. translate("DNS requests via TCP not supported")
end end
function tcp.parse(self, section)
DDNS.flag_parse(self, section)
end
end end
-- IPv4 + IPv6 - proxy (NEW) -- IPv4 + IPv6 - proxy (NEW) -- ################################################
-- optional Proxy to use for http/https requests [user:password@]proxyhost[:port] -- optional Proxy to use for http/https requests [user:password@]proxyhost[:port]
if has_proxy or ( ( m:get(section, "proxy") or "" ) ~= "" ) then if has_proxy or ( ( m:get(section, "proxy") or "" ) ~= "" ) then
pxy = ns:taboption("advanced", Value, "proxy", pxy = ns:taboption("advanced", Value, "proxy",
translate("PROXY-Server") ) translate("PROXY-Server") )
pxy.placeholder="user:password@myproxy.lan:8080" pxy.placeholder="user:password@myproxy.lan:8080"
function pxy.cfgvalue(self, section) function pxy.cfgvalue(self, section)
@ -972,8 +995,8 @@ if has_proxy or ( ( m:get(section, "proxy") or "" ) ~= "" ) then
else else
self.description = translate("OPTIONAL: Proxy-Server for detection and updates.") .. "<br />" .. self.description = translate("OPTIONAL: Proxy-Server for detection and updates.") .. "<br />" ..
translate("Format") .. ": " .. bold_on .. "[user:password@]proxyhost:port" .. bold_off .. "<br />" .. translate("Format") .. ": " .. bold_on .. "[user:password@]proxyhost:port" .. bold_off .. "<br />" ..
translate("IPv6 address must be given in square brackets") .. ": " .. translate("IPv6 address must be given in square brackets") .. ": " ..
bold_on .. " [2001:db8::1]:8080" .. bold_off bold_on .. " [2001:db8::1]:8080" .. bold_off
end end
return value return value
end end
@ -981,12 +1004,12 @@ if has_proxy or ( ( m:get(section, "proxy") or "" ) ~= "" ) then
-- if .datatype is set, then it is checked before calling this function -- if .datatype is set, then it is checked before calling this function
if not value then if not value then
return "" -- ignore on empty return "" -- ignore on empty
elseif has_proxy then elseif has_proxy then
local ipv6 = usev6:formvalue(section) or "0" local ipv6 = usev6:formvalue(section) or "0"
local force = (fipv) and fipv:formvalue(section) or "0" local force = (fipv) and fipv:formvalue(section) or "0"
local command = [[/usr/lib/ddns/dynamic_dns_lucihelper.sh verify_proxy ]] .. local command = [[/usr/lib/ddns/dynamic_dns_lucihelper.sh verify_proxy ]] ..
value .. [[ ]] .. ipv6 .. [[ ]] .. force value .. [[ ]] .. ipv6 .. [[ ]] .. force
local ret = luci.sys.call(command) local ret = SYS.call(command)
if ret == 0 then return value if ret == 0 then return value
elseif ret == 2 then return nil, err_tab_adv(self) .. translate("nslookup can not resolve host") elseif ret == 2 then return nil, err_tab_adv(self) .. translate("nslookup can not resolve host")
elseif ret == 3 then return nil, err_tab_adv(self) .. translate("nc (netcat) can not connect") elseif ret == 3 then return nil, err_tab_adv(self) .. translate("nc (netcat) can not connect")
@ -1000,21 +1023,21 @@ if has_proxy or ( ( m:get(section, "proxy") or "" ) ~= "" ) then
end end
end end
-- TAB: Timer ################################################################# -- TAB: Timer #####################################################################################
-- check_interval -- check_interval -- ###########################################################
ci = ns:taboption("timer", Value, "check_interval", ci = ns:taboption("timer", Value, "check_interval",
translate("Check Interval") ) translate("Check Interval") )
ci.template = "ddns/detail_value" ci.template = "ddns/detail_value"
ci.default = 10 ci.default = 10
ci.rmempty = false -- validate ourselves for translatable error messages ci.rmempty = false -- validate ourselves for translatable error messages
function ci.validate(self, value) function ci.validate(self, value)
if not luci.cbi.datatypes.uinteger(value) if not DTYP.uinteger(value)
or tonumber(value) < 1 then or tonumber(value) < 1 then
return nil, err_tab_timer(self) .. translate("minimum value 5 minutes == 300 seconds") return nil, err_tab_timer(self) .. translate("minimum value 5 minutes == 300 seconds")
end end
local secs = luci.tools.ddns.calc_seconds(value, cu:formvalue(section)) local secs = DDNS.calc_seconds(value, cu:formvalue(section))
if secs >= 300 then if secs >= 300 then
return value return value
else else
return nil, err_tab_timer(self) .. translate("minimum value 5 minutes == 300 seconds") return nil, err_tab_timer(self) .. translate("minimum value 5 minutes == 300 seconds")
@ -1022,7 +1045,7 @@ function ci.validate(self, value)
end end
function ci.write(self, section, value) function ci.write(self, section, value)
-- simulate rmempty=true remove default -- simulate rmempty=true remove default
local secs = luci.tools.ddns.calc_seconds(value, cu:formvalue(section)) local secs = DDNS.calc_seconds(value, cu:formvalue(section))
if secs ~= 600 then --default 10 minutes if secs ~= 600 then --default 10 minutes
return self.map:set(section, self.option, value) return self.map:set(section, self.option, value)
else else
@ -1031,9 +1054,9 @@ function ci.write(self, section, value)
end end
end end
-- check_unit -- check_unit -- ###############################################################
cu = ns:taboption("timer", ListValue, "check_unit", "not displayed, but needed otherwise error", cu = ns:taboption("timer", ListValue, "check_unit", "not displayed, but needed otherwise error",
translate("Interval to check for changed IP" .. "<br />" .. translate("Interval to check for changed IP" .. "<br />" ..
"Values below 5 minutes == 300 seconds are not supported") ) "Values below 5 minutes == 300 seconds are not supported") )
cu.template = "ddns/detail_lvalue" cu.template = "ddns/detail_lvalue"
cu.default = "minutes" cu.default = "minutes"
@ -1044,7 +1067,7 @@ cu:value("hours", translate("hours"))
--cu:value("days", translate("days")) --cu:value("days", translate("days"))
function cu.write(self, section, value) function cu.write(self, section, value)
-- simulate rmempty=true remove default -- simulate rmempty=true remove default
local secs = luci.tools.ddns.calc_seconds(ci:formvalue(section), value) local secs = DDNS.calc_seconds(ci:formvalue(section), value)
if secs ~= 600 then --default 10 minutes if secs ~= 600 then --default 10 minutes
return self.map:set(section, self.option, value) return self.map:set(section, self.option, value)
else else
@ -1052,29 +1075,29 @@ function cu.write(self, section, value)
end end
end end
-- force_interval (modified) -- force_interval (modified) -- ################################################
fi = ns:taboption("timer", Value, "force_interval", fi = ns:taboption("timer", Value, "force_interval",
translate("Force Interval") ) translate("Force Interval") )
fi.template = "ddns/detail_value" fi.template = "ddns/detail_value"
fi.default = 72 -- see dynamic_dns_updater.sh script fi.default = 72 -- see dynamic_dns_updater.sh script
fi.rmempty = false -- validate ourselves for translatable error messages fi.rmempty = false -- validate ourselves for translatable error messages
function fi.validate(self, value) function fi.validate(self, value)
if not luci.cbi.datatypes.uinteger(value) if not DTYP.uinteger(value)
or tonumber(value) < 0 then or tonumber(value) < 0 then
return nil, err_tab_timer(self) .. translate("minimum value '0'") return nil, err_tab_timer(self) .. translate("minimum value '0'")
end end
local force_s = luci.tools.ddns.calc_seconds(value, fu:formvalue(section)) local force_s = DDNS.calc_seconds(value, fu:formvalue(section))
if force_s == 0 then if force_s == 0 then
return value return value
end end
local ci_value = ci:formvalue(section) local ci_value = ci:formvalue(section)
if not luci.cbi.datatypes.uinteger(ci_value) then if not DTYP.uinteger(ci_value) then
return "" -- ignore because error in check_interval above return "" -- ignore because error in check_interval above
end end
local check_s = luci.tools.ddns.calc_seconds(ci_value, cu:formvalue(section)) local check_s = DDNS.calc_seconds(ci_value, cu:formvalue(section))
if force_s >= check_s then if force_s >= check_s then
return value return value
end end
@ -1083,7 +1106,7 @@ function fi.validate(self, value)
end end
function fi.write(self, section, value) function fi.write(self, section, value)
-- simulate rmempty=true remove default -- simulate rmempty=true remove default
local secs = luci.tools.ddns.calc_seconds(value, fu:formvalue(section)) local secs = DDNS.calc_seconds(value, fu:formvalue(section))
if secs ~= 259200 then --default 72 hours == 3 days if secs ~= 259200 then --default 72 hours == 3 days
return self.map:set(section, self.option, value) return self.map:set(section, self.option, value)
else else
@ -1092,7 +1115,7 @@ function fi.write(self, section, value)
end end
end end
-- force_unit -- force_unit -- ###############################################################
fu = ns:taboption("timer", ListValue, "force_unit", "not displayed, but needed otherwise error", fu = ns:taboption("timer", ListValue, "force_unit", "not displayed, but needed otherwise error",
translate("Interval to force updates send to DDNS Provider" .. "<br />" .. translate("Interval to force updates send to DDNS Provider" .. "<br />" ..
"Setting this parameter to 0 will force the script to only run once" .. "<br />" .. "Setting this parameter to 0 will force the script to only run once" .. "<br />" ..
@ -1106,7 +1129,7 @@ fu:value("hours", translate("hours"))
fu:value("days", translate("days")) fu:value("days", translate("days"))
function fu.write(self, section, value) function fu.write(self, section, value)
-- simulate rmempty=true remove default -- simulate rmempty=true remove default
local secs = luci.tools.ddns.calc_seconds(fi:formvalue(section), value) local secs = DDNS.calc_seconds(fi:formvalue(section), value)
if secs ~= 259200 and secs ~= 0 then --default 72 hours == 3 days if secs ~= 259200 and secs ~= 0 then --default 72 hours == 3 days
return self.map:set(section, self.option, value) return self.map:set(section, self.option, value)
else else
@ -1114,14 +1137,14 @@ function fu.write(self, section, value)
end end
end end
-- retry_count (NEW) -- retry_count (NEW) -- ########################################################
rc = ns:taboption("timer", Value, "retry_count", rc = ns:taboption("timer", Value, "retry_count",
translate("Error Retry Counter"), translate("Error Retry Counter"),
translate("On Error the script will stop execution after given number of retrys") ) translate("On Error the script will stop execution after given number of retrys") )
rc.default = 5 rc.default = 5
rc.rmempty = false -- validate ourselves for translatable error messages rc.rmempty = false -- validate ourselves for translatable error messages
function rc.validate(self, value) function rc.validate(self, value)
if not luci.cbi.datatypes.uinteger(value) if not DTYP.uinteger(value)
or tonumber(value) < 1 then or tonumber(value) < 1 then
return nil, err_tab_timer(self) .. translate("minimum value '1'") return nil, err_tab_timer(self) .. translate("minimum value '1'")
else else
@ -1137,14 +1160,14 @@ function rc.write(self, section, value)
end end
end end
-- retry_interval -- retry_interval -- ###########################################################
ri = ns:taboption("timer", Value, "retry_interval", ri = ns:taboption("timer", Value, "retry_interval",
translate("Error Retry Interval") ) translate("Error Retry Interval") )
ri.template = "ddns/detail_value" ri.template = "ddns/detail_value"
ri.default = 60 ri.default = 60
ri.rmempty = false -- validate ourselves for translatable error messages ri.rmempty = false -- validate ourselves for translatable error messages
function ri.validate(self, value) function ri.validate(self, value)
if not luci.cbi.datatypes.uinteger(value) if not DTYP.uinteger(value)
or tonumber(value) < 1 then or tonumber(value) < 1 then
return nil, err_tab_timer(self) .. translate("minimum value '1'") return nil, err_tab_timer(self) .. translate("minimum value '1'")
else else
@ -1153,7 +1176,7 @@ function ri.validate(self, value)
end end
function ri.write(self, section, value) function ri.write(self, section, value)
-- simulate rmempty=true remove default -- simulate rmempty=true remove default
local secs = luci.tools.ddns.calc_seconds(value, ru:formvalue(section)) local secs = DDNS.calc_seconds(value, ru:formvalue(section))
if secs ~= 60 then --default 60seconds if secs ~= 60 then --default 60seconds
return self.map:set(section, self.option, value) return self.map:set(section, self.option, value)
else else
@ -1162,7 +1185,7 @@ function ri.write(self, section, value)
end end
end end
-- retry_unit -- retry_unit -- ###############################################################
ru = ns:taboption("timer", ListValue, "retry_unit", "not displayed, but needed otherwise error", ru = ns:taboption("timer", ListValue, "retry_unit", "not displayed, but needed otherwise error",
translate("On Error the script will retry the failed action after given time") ) translate("On Error the script will retry the failed action after given time") )
ru.template = "ddns/detail_lvalue" ru.template = "ddns/detail_lvalue"
@ -1174,7 +1197,7 @@ ru:value("minutes", translate("minutes"))
--ru:value("days", translate("days")) --ru:value("days", translate("days"))
function ru.write(self, section, value) function ru.write(self, section, value)
-- simulate rmempty=true remove default -- simulate rmempty=true remove default
local secs = luci.tools.ddns.calc_seconds(ri:formvalue(section), value) local secs = DDNS.calc_seconds(ri:formvalue(section), value)
if secs ~= 60 then --default 60seconds if secs ~= 60 then --default 60seconds
return self.map:set(section, self.option, value) return self.map:set(section, self.option, value)
else else
@ -1189,7 +1212,7 @@ lv.inputtitle = translate("Read / Reread log file")
lv.rows = 50 lv.rows = 50
function lv.cfgvalue(self, section) function lv.cfgvalue(self, section)
local lfile=log_dir .. "/" .. section .. ".log" local lfile=log_dir .. "/" .. section .. ".log"
if nixio.fs.access(lfile) then if FS.access(lfile) then
return lfile .. "\n" .. translate("Please press [Read] button") return lfile .. "\n" .. translate("Please press [Read] button")
end end
return lfile .. "\n" .. translate("File not found or empty") return lfile .. "\n" .. translate("File not found or empty")

View file

@ -12,56 +12,74 @@ You may obtain a copy of the License at
$Id$ $Id$
]]-- ]]--
require "luci.sys" local CTRL = require "luci.controller.ddns" -- this application's controller
require "luci.dispatcher" local DISP = require "luci.dispatcher"
require "luci.tools.ddns" local SYS = require "luci.sys"
local DDNS = require "luci.tools.ddns" -- ddns multiused functions
-- check supported options -- check supported options -- ##################################################
-- saved to local vars here because doing multiple os calls slow down the system -- saved to local vars here because doing multiple os calls slow down the system
has_ssl = luci.tools.ddns.check_ssl() -- HTTPS support has_ssl = DDNS.check_ssl() -- HTTPS support
has_proxy = luci.tools.ddns.check_proxy() -- Proxy support has_proxy = DDNS.check_proxy() -- Proxy support
has_dnstcp = luci.tools.ddns.check_bind_host() -- DNS TCP support has_dnstcp = DDNS.check_bind_host() -- DNS TCP support
need_update = CTRL.update_needed() -- correct ddns-scripts version
-- html constants -- html constants
font_red = [[<font color="red">]]
font_off = [[</font>]]
bold_on = [[<strong>]] bold_on = [[<strong>]]
bold_off = [[</strong>]] bold_off = [[</strong>]]
-- cbi-map definition -- cbi-map definition -- #######################################################
m = Map("ddns") m = Map("ddns")
m.title = [[<a href="]] .. luci.dispatcher.build_url("admin", "services", "ddns") .. [[">]] .. -- first need to close <a> from cbi map template our <a> closed by template
translate("Dynamic DNS") .. [[</a>]] m.title = [[</a><a href="]] .. DISP.build_url("admin", "services", "ddns") .. [[">]] ..
translate("Dynamic DNS")
m.description = translate("Dynamic DNS allows that your router can be reached with " .. m.description = translate("Dynamic DNS allows that your router can be reached with " ..
"a fixed hostname while having a dynamically changing " .. "a fixed hostname while having a dynamically changing " ..
"IP address.") "IP address.")
m.redirect = luci.dispatcher.build_url("admin", "services", "ddns") m.redirect = DISP.build_url("admin", "services", "ddns")
-- SimpleSection definition -- SimpleSection definition -- #################################################
-- show Hints to optimize installation and script usage -- show Hints to optimize installation and script usage
s = m:section( SimpleSection, s = m:section( SimpleSection,
translate("Hints"), translate("Hints"),
translate("Below a list of configuration tips for your system to run Dynamic DNS updates without limitations") ) translate("Below a list of configuration tips for your system to run Dynamic DNS updates without limitations") )
-- DDNS Service disabled
if not luci.sys.init.enabled("ddns") then -- ddns_scripts needs to be updated for full functionality
local dv = s:option(DummyValue, "_not_enabled") if need_update then
dv.titleref = luci.dispatcher.build_url("admin", "system", "startup") local dv = s:option(DummyValue, "_update_needed")
dv.titleref = DISP.build_url("admin", "system", "packages")
dv.rawhtml = true dv.rawhtml = true
dv.title = bold_on .. dv.title = font_red .. bold_on ..
translate("Software update required") .. bold_off .. font_off
dv.value = translate("The currently installed 'ddns-scripts' package did not support all available settings.") ..
"<br />" ..
translate("Please update to the current version!")
end
-- DDNS Service disabled
if not SYS.init.enabled("ddns") then
local dv = s:option(DummyValue, "_not_enabled")
dv.titleref = DISP.build_url("admin", "system", "startup")
dv.rawhtml = true
dv.title = bold_on ..
translate("DDNS Autostart disabled") .. bold_off translate("DDNS Autostart disabled") .. bold_off
dv.value = translate("Currently DDNS updates are not started at boot or on interface events." .. "<br />" .. dv.value = translate("Currently DDNS updates are not started at boot or on interface events." .. "<br />" ..
"This is the default if you run DDNS scripts by yourself (i.e. via cron with force_interval set to '0')" ) "This is the default if you run DDNS scripts by yourself (i.e. via cron with force_interval set to '0')" )
end end
-- No IPv6 support -- No IPv6 support
if not luci.tools.ddns.check_ipv6() then if not DDNS.check_ipv6() then
local dv = s:option(DummyValue, "_no_ipv6") local dv = s:option(DummyValue, "_no_ipv6")
dv.titleref = 'http://www.openwrt.org" target="_blank' dv.titleref = 'http://www.openwrt.org" target="_blank'
dv.rawhtml = true dv.rawhtml = true
dv.title = bold_on .. dv.title = bold_on ..
translate("IPv6 not supported") .. bold_off translate("IPv6 not supported") .. bold_off
dv.value = translate("IPv6 is currently not (fully) supported by this system" .. "<br />" .. dv.value = translate("IPv6 is currently not (fully) supported by this system" .. "<br />" ..
"Please follow the instructions on OpenWrt's homepage to enable IPv6 support" .. "<br />" .. "Please follow the instructions on OpenWrt's homepage to enable IPv6 support" .. "<br />" ..
"or update your system to the latest OpenWrt Release") "or update your system to the latest OpenWrt Release")
end end
@ -69,13 +87,13 @@ end
-- No HTTPS support -- No HTTPS support
if not has_ssl then if not has_ssl then
local dv = s:option(DummyValue, "_no_https") local dv = s:option(DummyValue, "_no_https")
dv.titleref = luci.dispatcher.build_url("admin", "system", "packages") dv.titleref = DISP.build_url("admin", "system", "packages")
dv.rawhtml = true dv.rawhtml = true
dv.title = bold_on .. dv.title = bold_on ..
translate("HTTPS not supported") .. bold_off translate("HTTPS not supported") .. bold_off
dv.value = translate("Neither GNU Wget with SSL nor cURL installed to support updates via HTTPS protocol.") .. dv.value = translate("Neither GNU Wget with SSL nor cURL installed to support updates via HTTPS protocol.") ..
"<br />- " .. "<br />- " ..
translate("You should install GNU Wget with SSL (prefered) or cURL package.") .. translate("You should install GNU Wget with SSL (prefered) or cURL package.") ..
"<br />- " .. "<br />- " ..
translate("In some versions cURL/libcurl in OpenWrt is compiled without proxy support.") translate("In some versions cURL/libcurl in OpenWrt is compiled without proxy support.")
end end
@ -83,13 +101,13 @@ end
-- cURL without proxy support -- cURL without proxy support
if has_ssl and not has_proxy then if has_ssl and not has_proxy then
local dv = s:option(DummyValue, "_no_proxy") local dv = s:option(DummyValue, "_no_proxy")
dv.titleref = luci.dispatcher.build_url("admin", "system", "packages") dv.titleref = DISP.build_url("admin", "system", "packages")
dv.rawhtml = true dv.rawhtml = true
dv.title = bold_on .. dv.title = bold_on ..
translate("cURL without Proxy Support") .. bold_off translate("cURL without Proxy Support") .. bold_off
dv.value = translate("cURL is installed, but libcurl was compiled without proxy support.") .. dv.value = translate("cURL is installed, but libcurl was compiled without proxy support.") ..
"<br />- " .. "<br />- " ..
translate("You should install GNU Wget with SSL or replace libcurl.") .. translate("You should install GNU Wget with SSL or replace libcurl.") ..
"<br />- " .. "<br />- " ..
translate("In some versions cURL/libcurl in OpenWrt is compiled without proxy support.") translate("In some versions cURL/libcurl in OpenWrt is compiled without proxy support.")
end end
@ -97,12 +115,12 @@ end
-- "Force IP Version not supported" -- "Force IP Version not supported"
if not (has_ssl and has_dnstcp) then if not (has_ssl and has_dnstcp) then
local dv = s:option(DummyValue, "_no_force_ip") local dv = s:option(DummyValue, "_no_force_ip")
dv.titleref = luci.dispatcher.build_url("admin", "system", "packages") dv.titleref = DISP.build_url("admin", "system", "packages")
dv.rawhtml = true dv.rawhtml = true
dv.title = bold_on .. dv.title = bold_on ..
translate("Force IP Version not supported") .. bold_off translate("Force IP Version not supported") .. bold_off
local value = translate("BusyBox's nslookup and Wget do not support to specify " .. local value = translate("BusyBox's nslookup and Wget do not support to specify " ..
"the IP version to use for communication with DDNS Provider.") "the IP version to use for communication with DDNS Provider.")
if not has_ssl then if not has_ssl then
value = value .. "<br />- " .. value = value .. "<br />- " ..
translate("You should install GNU Wget with SSL (prefered) or cURL package.") translate("You should install GNU Wget with SSL (prefered) or cURL package.")
@ -117,11 +135,11 @@ end
-- "DNS requests via TCP not supported" -- "DNS requests via TCP not supported"
if not has_dnstcp then if not has_dnstcp then
local dv = s:option(DummyValue, "_no_dnstcp") local dv = s:option(DummyValue, "_no_dnstcp")
dv.titleref = luci.dispatcher.build_url("admin", "system", "packages") dv.titleref = DISP.build_url("admin", "system", "packages")
dv.rawhtml = true dv.rawhtml = true
dv.title = bold_on .. dv.title = bold_on ..
translate("DNS requests via TCP not supported") .. bold_off translate("DNS requests via TCP not supported") .. bold_off
dv.value = translate("BusyBox's nslookup does not support to specify to use TCP instead of default UDP when requesting DNS server") .. dv.value = translate("BusyBox's nslookup does not support to specify to use TCP instead of default UDP when requesting DNS server") ..
"<br />- " .. "<br />- " ..
translate("You should install BIND host package for DNS requests.") translate("You should install BIND host package for DNS requests.")
end end

View file

@ -12,17 +12,20 @@ You may obtain a copy of the License at
$Id$ $Id$
]]-- ]]--
require "nixio.fs" local NXFS = require "nixio.fs"
require "luci.sys" local CTRL = require "luci.controller.ddns" -- this application's controller
require "luci.dispatcher" local DISP = require "luci.dispatcher"
require "luci.tools.ddns" local HTTP = require "luci.http"
local SYS = require "luci.sys"
local DDNS = require "luci.tools.ddns" -- ddns multiused functions
-- show hints ? -- show hints ?
show_hints = not (luci.tools.ddns.check_ipv6() -- IPv6 support show_hints = not (DDNS.check_ipv6() -- IPv6 support
and luci.tools.ddns.check_ssl() -- HTTPS support and DDNS.check_ssl() -- HTTPS support
and luci.tools.ddns.check_proxy() -- Proxy support and DDNS.check_proxy() -- Proxy support
and luci.tools.ddns.check_bind_host() -- DNS TCP support and DDNS.check_bind_host() -- DNS TCP support
) )
need_update = CTRL.update_needed() -- correct ddns-scripts version
-- html constants -- html constants
font_red = [[<font color="red">]] font_red = [[<font color="red">]]
@ -30,70 +33,96 @@ font_off = [[</font>]]
bold_on = [[<strong>]] bold_on = [[<strong>]]
bold_off = [[</strong>]] bold_off = [[</strong>]]
-- cbi-map definition -- cbi-map definition -- #######################################################
m = Map("ddns", m = Map("ddns")
translate("Dynamic DNS"),
translate("Dynamic DNS allows that your router can be reached with " ..
"a fixed hostname while having a dynamically changing " ..
"IP address."))
-- read application settings -- first need to close <a> from cbi map template our <a> closed by template
date_format = m.uci:get(m.config, "global", "date_format") or "%F %R" --m.title = [[</a><a href="javascript:alert(']] .. CTRL.show_versions() ..[[')">]] ..
run_dir = m.uci:get(m.config, "global", "run_dir") or "/var/run/ddns" -- translate("Dynamic DNS")
m.title = [[</a><a href="#" onclick="onclick_maptitle();">]] ..
translate("Dynamic DNS")
-- SimpleSection definition m.description = translate("Dynamic DNS allows that your router can be reached with " ..
"a fixed hostname while having a dynamically changing " ..
"IP address.")
m.on_after_commit = function(self)
if self.changed then -- changes ?
if SYS.init.enabled("ddns") then -- ddns service enabled, restart all
os.execute("/etc/init.d/ddns restart")
else -- ddns service disabled, send SIGHUP to running
os.execute("killall -1 dynamic_dns_updater.sh")
end
end
end
-- SimpleSection definiton -- ##################################################
-- with all the JavaScripts we need for "a good Show"
a = m:section( SimpleSection )
a.template = "ddns/overview_status"
-- SimpleSection definition -- #################################################
-- show Hints to optimize installation and script usage -- show Hints to optimize installation and script usage
-- only show if service not enabled -- only show if service not enabled
-- or no IPv6 support -- or no IPv6 support
-- or not GNU Wget and not cURL (for https support) -- or not GNU Wget and not cURL (for https support)
-- or not GNU Wget but cURL without proxy support -- or not GNU Wget but cURL without proxy support
-- or not BIND's host -- or not BIND's host
if show_hints or not luci.sys.init.enabled("ddns") then -- or ddns-scripts package need update
if show_hints or need_update or not SYS.init.enabled("ddns") then
s = m:section( SimpleSection, translate("Hints") ) s = m:section( SimpleSection, translate("Hints") )
-- DDNS Service disabled
if not luci.sys.init.enabled("ddns") then -- ddns_scripts needs to be updated for full functionality
local dv = s:option(DummyValue, "_not_enabled") if need_update then
dv.titleref = luci.dispatcher.build_url("admin", "system", "startup") local dv = s:option(DummyValue, "_update_needed")
dv.titleref = DISP.build_url("admin", "system", "packages")
dv.rawhtml = true dv.rawhtml = true
dv.title = bold_on .. dv.title = font_red .. bold_on ..
translate("Software update required") .. bold_off .. font_off
dv.value = translate("The currently installed 'ddns-scripts' package did not support all available settings.") ..
"<br />" ..
translate("Please update to the current version!")
end
-- DDNS Service disabled
if not SYS.init.enabled("ddns") then
local dv = s:option(DummyValue, "_not_enabled")
dv.titleref = DISP.build_url("admin", "system", "startup")
dv.rawhtml = true
dv.title = bold_on ..
translate("DDNS Autostart disabled") .. bold_off translate("DDNS Autostart disabled") .. bold_off
dv.value = translate("Currently DDNS updates are not started at boot or on interface events." .. "<br />" .. dv.value = translate("Currently DDNS updates are not started at boot or on interface events." .. "<br />" ..
"You can start/stop each configuration here. It will run until next reboot.") "You can start/stop each configuration here. It will run until next reboot.")
end end
-- Show more hints on a separate page -- Show more hints on a separate page
if show_hints then if show_hints then
local dv = s:option(DummyValue, "_separate") local dv = s:option(DummyValue, "_separate")
dv.titleref = luci.dispatcher.build_url("admin", "services", "ddns", "hints") dv.titleref = DISP.build_url("admin", "services", "ddns", "hints")
dv.rawhtml = true dv.rawhtml = true
dv.title = bold_on .. dv.title = bold_on ..
translate("Show more") .. bold_off translate("Show more") .. bold_off
dv.value = translate("Follow this link" .. "<br />" .. dv.value = translate("Follow this link" .. "<br />" ..
"You will find more hints to optimize your system to run DDNS scripts with all options") "You will find more hints to optimize your system to run DDNS scripts with all options")
end end
end end
-- SimpleSection definiton -- TableSection definition -- ##################################################
-- with all the JavaScripts we need for "a good Show" ts = m:section( TypedSection, "service",
a = m:section( SimpleSection ) translate("Overview"),
a.template = "ddns/overview_status"
-- TableSection definition
ts = m:section( TypedSection, "service",
translate("Overview"),
translate("Below is a list of configured DDNS configurations and their current state." .. "<br />" .. translate("Below is a list of configured DDNS configurations and their current state." .. "<br />" ..
"If you want to send updates for IPv4 and IPv6 you need to define two separate Configurations " .. "If you want to send updates for IPv4 and IPv6 you need to define two separate Configurations " ..
"i.e. 'myddns_ipv4' and 'myddns_ipv6'") ) "i.e. 'myddns_ipv4' and 'myddns_ipv6'") )
ts.sectionhead = translate("Configuration") ts.sectionhead = translate("Configuration")
ts.template = "cbi/tblsection" ts.template = "cbi/tblsection"
ts.addremove = true ts.addremove = true
ts.extedit = luci.dispatcher.build_url("admin", "services", "ddns", "detail", "%s") ts.extedit = DISP.build_url("admin", "services", "ddns", "detail", "%s")
function ts.create(self, name) function ts.create(self, name)
AbstractSection.create(self, name) AbstractSection.create(self, name)
luci.http.redirect( self.extedit:format(name) ) HTTP.redirect( self.extedit:format(name) )
end end
-- Domain and registered IP -- Domain and registered IP -- #################################################
dom = ts:option(DummyValue, "_domainIP", dom = ts:option(DummyValue, "_domainIP",
translate("Hostname/Domain") .. "<br />" .. translate("Registered IP") ) translate("Hostname/Domain") .. "<br />" .. translate("Registered IP") )
dom.template = "ddns/overview_doubleline" dom.template = "ddns/overview_doubleline"
@ -113,32 +142,35 @@ function dom.set_two(self, section)
local force_ipversion = tonumber(self.map:get(section, "force_ipversion") or 0) local force_ipversion = tonumber(self.map:get(section, "force_ipversion") or 0)
local force_dnstcp = tonumber(self.map:get(section, "force_dnstcp") or 0) local force_dnstcp = tonumber(self.map:get(section, "force_dnstcp") or 0)
local command = [[/usr/lib/ddns/dynamic_dns_lucihelper.sh]] local command = [[/usr/lib/ddns/dynamic_dns_lucihelper.sh]]
if not nixio.fs.access(command, "rwx", "rx", "rx") then if not NXFS.access(command, "rwx", "rx", "rx") then
nixio.fs.chmod(command, 755) NXFS.chmod(command, 755)
end end
command = command .. [[ get_registered_ip ]] .. domain .. [[ ]] .. use_ipv6 .. command = command .. [[ get_registered_ip ]] .. domain .. [[ ]] .. use_ipv6 ..
[[ ]] .. force_ipversion .. [[ ]] .. force_dnstcp .. [[ ]] .. dnsserver [[ ]] .. force_ipversion .. [[ ]] .. force_dnstcp .. [[ ]] .. dnsserver
local ip = luci.sys.exec(command) local ip = SYS.exec(command)
if ip == "" then ip = translate("no data") end if ip == "" then ip = translate("no data") end
return ip return ip
end end
-- enabled -- enabled
ena = ts:option( Flag, "enabled", ena = ts:option( Flag, "enabled",
translate("Enabled")) translate("Enabled"))
ena.template = "ddns/overview_enabled" ena.template = "ddns/overview_enabled"
ena.rmempty = false ena.rmempty = false
function ena.parse(self, section)
DDNS.flag_parse(self, section)
end
-- show PID and next update -- show PID and next update
upd = ts:option( DummyValue, "_update", upd = ts:option( DummyValue, "_update",
translate("Last Update") .. "<br />" .. translate("Next Update")) translate("Last Update") .. "<br />" .. translate("Next Update"))
upd.template = "ddns/overview_doubleline" upd.template = "ddns/overview_doubleline"
function upd.set_one(self, section) -- fill Last Update function upd.set_one(self, section) -- fill Last Update
-- get/validate last update -- get/validate last update
local uptime = luci.sys.uptime() local uptime = SYS.uptime()
local lasttime = tonumber(nixio.fs.readfile("%s/%s.update" % { run_dir, section } ) or 0 ) local lasttime = DDNS.get_lastupd(section)
if lasttime > uptime then -- /var might not be linked to /tmp and cleared on reboot if lasttime > uptime then -- /var might not be linked to /tmp and cleared on reboot
lasttime = 0 lasttime = 0
end end
-- no last update happen -- no last update happen
@ -151,7 +183,7 @@ function upd.set_one(self, section) -- fill Last Update
-- os.epoch - sys.uptime + lastupdate(uptime) -- os.epoch - sys.uptime + lastupdate(uptime)
local epoch = os.time() - uptime + lasttime local epoch = os.time() - uptime + lasttime
-- use linux date to convert epoch -- use linux date to convert epoch
return luci.sys.exec([[/bin/date -d @]] .. epoch .. [[ +']] .. date_format .. [[']]) return DDNS.epoch2date(epoch)
end end
end end
function upd.set_two(self, section) -- fill Next Update function upd.set_two(self, section) -- fill Next Update
@ -162,28 +194,28 @@ function upd.set_two(self, section) -- fill Next Update
-- get force seconds -- get force seconds
local force_interval = tonumber(self.map:get(section, "force_interval") or 72) local force_interval = tonumber(self.map:get(section, "force_interval") or 72)
local force_unit = self.map:get(section, "force_unit") or "hours" local force_unit = self.map:get(section, "force_unit") or "hours"
local force_seconds = luci.tools.ddns.calc_seconds(force_interval, force_unit) local force_seconds = DDNS.calc_seconds(force_interval, force_unit)
-- get last update and get/validate PID -- get last update and get/validate PID
local uptime = luci.sys.uptime() local uptime = SYS.uptime()
local lasttime = tonumber(nixio.fs.readfile("%s/%s.update" % { run_dir, section } ) or 0 ) local lasttime = DDNS.get_lastupd(section)
if lasttime > uptime then -- /var might not be linked to /tmp and cleared on reboot if lasttime > uptime then -- /var might not be linked to /tmp and cleared on reboot
lasttime = 0 lasttime = 0
end end
local pid = luci.tools.ddns.get_pid(section, run_dir) local pid = DDNS.get_pid(section)
-- calc next update -- calc next update
if lasttime > 0 then if lasttime > 0 then
local epoch = os.time() - uptime + lasttime + force_seconds local epoch = os.time() - uptime + lasttime + force_seconds
-- use linux date to convert epoch -- use linux date to convert epoch
datelast = luci.sys.exec([[/bin/date -d @]] .. epoch .. [[ +']] .. date_format .. [[']]) datelast = DDNS.epoch2date(epoch)
end end
-- process running but update needs to happen -- process running but update needs to happen
if pid > 0 and ( lasttime + force_seconds - uptime ) < 0 then if pid > 0 and ( lasttime + force_seconds - uptime ) < 0 then
datenext = translate("Verify") datenext = translate("Verify")
-- run once -- run once
elseif force_seconds == 0 then elseif force_seconds == 0 then
datenext = translate("Run once") datenext = translate("Run once")
@ -191,7 +223,7 @@ function upd.set_two(self, section) -- fill Next Update
elseif pid == 0 and enabled == 0 then elseif pid == 0 and enabled == 0 then
datenext = translate("Disabled") datenext = translate("Disabled")
-- no process running and NOT -- no process running and NOT
elseif pid == 0 and enabled ~= 0 then elseif pid == 0 and enabled ~= 0 then
datenext = translate("Stopped") datenext = translate("Stopped")
end end
@ -200,11 +232,11 @@ function upd.set_two(self, section) -- fill Next Update
end end
-- start/stop button -- start/stop button
btn = ts:option( Button, "_startstop", btn = ts:option( Button, "_startstop",
translate("Process ID") .. "<br />" .. translate("Start / Stop") ) translate("Process ID") .. "<br />" .. translate("Start / Stop") )
btn.template = "ddns/overview_startstop" btn.template = "ddns/overview_startstop"
function btn.cfgvalue(self, section) function btn.cfgvalue(self, section)
local pid = luci.tools.ddns.get_pid(section, run_dir) local pid = DDNS.get_pid(section)
if pid > 0 then if pid > 0 then
btn.inputtitle = "PID: " .. pid btn.inputtitle = "PID: " .. pid
btn.inputstyle = "reset" btn.inputstyle = "reset"

View file

@ -1,7 +1,7 @@
--[[ --[[
LuCI - Lua Configuration Interface LuCI - Lua Configuration Interface
shared module for luci-app-ddns-v2 shared module for luci-app-ddns
Copyright 2014 Christian Schoenebeck <christian dot schoenebeck at gmail dot com> Copyright 2014 Christian Schoenebeck <christian dot schoenebeck at gmail dot com>
function parse_url copied from https://svn.nmap.org/nmap/nselib/url.lua function parse_url copied from https://svn.nmap.org/nmap/nselib/url.lua
@ -18,40 +18,12 @@ You may obtain a copy of the License at
module("luci.tools.ddns", package.seeall) module("luci.tools.ddns", package.seeall)
require "luci.sys" local NX = require "nixio"
require "nixio.fs" local NXFS = require "nixio.fs"
local OPKG = require "luci.model.ipkg"
function check_ipv6() local UCI = require "luci.model.uci"
return nixio.fs.access("/proc/net/ipv6_route") local SYS = require "luci.sys"
and nixio.fs.access("/usr/sbin/ip6tables") local UTIL = require "luci.util"
end
function check_ssl()
if (luci.sys.call([[ grep -iq "\+ssl" /usr/bin/wget 2>/dev/null ]]) == 0) then
return true
else
return nixio.fs.access("/usr/bin/curl")
end
end
function check_proxy()
-- we prefere GNU Wget for communication
if (luci.sys.call([[ grep -iq "\+ssl" /usr/bin/wget 2>/dev/null ]]) == 0) then
return true
-- if not installed cURL must support proxy
elseif nixio.fs.access("/usr/bin/curl") then
return (luci.sys.call([[ grep -iq all_proxy /usr/lib/libcurl.so* 2>/dev/null ]]) == 0)
-- only BusyBox Wget is installed
else
return nixio.fs.access("/usr/bin/wget")
end
end
function check_bind_host()
return nixio.fs.access("/usr/bin/host")
end
-- function to calculate seconds from given interval and unit -- function to calculate seconds from given interval and unit
function calc_seconds(interval, unit) function calc_seconds(interval, unit)
@ -70,15 +42,104 @@ function calc_seconds(interval, unit)
end end
end end
-- check if IPv6 supported by OpenWrt
function check_ipv6()
return NXFS.access("/proc/net/ipv6_route")
and NXFS.access("/usr/sbin/ip6tables")
end
-- check if Wget with SSL support or cURL installed
function check_ssl()
if (SYS.call([[ grep -iq "\+ssl" /usr/bin/wget 2>/dev/null ]]) == 0) then
return true
else
return NXFS.access("/usr/bin/curl")
end
end
-- check if Wget with SSL or cURL with proxy support installed
function check_proxy()
-- we prefere GNU Wget for communication
if (SYS.call([[ grep -iq "\+ssl" /usr/bin/wget 2>/dev/null ]]) == 0) then
return true
-- if not installed cURL must support proxy
elseif NXFS.access("/usr/bin/curl") then
return (SYS.call([[ grep -iq all_proxy /usr/lib/libcurl.so* 2>/dev/null ]]) == 0)
-- only BusyBox Wget is installed
else
return NXFS.access("/usr/bin/wget")
end
end
-- check if BIND host installed
function check_bind_host()
return NXFS.access("/usr/bin/host")
end
-- convert epoch date to given format
function epoch2date(epoch, format)
if not format or #format < 2 then
local uci = UCI.cursor()
format = uci:get("ddns", "global", "date_format") or "%F %R"
uci:unload("ddns")
end
format = format:gsub("%%n", "<br />") -- replace newline
format = format:gsub("%%t", " ") -- replace tab
return os.date(format, epoch)
end
-- read lastupdate from [section].update file
function get_lastupd(section)
local uci = UCI.cursor()
local run_dir = uci:get("ddns", "global", "run_dir") or "/var/run/ddns"
local etime = tonumber(NXFS.readfile("%s/%s.update" % { run_dir, section } ) or 0 )
uci:unload("ddns")
return etime
end
-- read PID from run file and verify if still running -- read PID from run file and verify if still running
function get_pid(section, run_dir) function get_pid(section)
local pid = tonumber(nixio.fs.readfile("%s/%s.pid" % { run_dir, section } ) or 0 ) local uci = UCI.cursor()
if pid > 0 and not luci.sys.process.signal(pid, 0) then local run_dir = uci:get("ddns", "global", "run_dir") or "/var/run/ddns"
local pid = tonumber(NXFS.readfile("%s/%s.pid" % { run_dir, section } ) or 0 )
if pid > 0 and not NX.kill(pid, 0) then
pid = 0 pid = 0
end end
uci:unload("ddns")
return pid return pid
end end
-- read version information for given package if installed
function ipkg_version(package)
if not package then
return nil
end
local info = OPKG.info(package)
local data = {}
local version = ""
local i = 0
for k, v in pairs(info) do
if v.Package == package and v.Status.installed then
version = v.Version
i = i + 1
end
end
if i > 1 then -- more then one valid record
return data
end
local sver = UTIL.split(version, "[%.%-]", nil, true)
data = {
version = version,
major = tonumber(sver[1]) or 0,
minor = tonumber(sver[2]) or 0,
patch = tonumber(sver[3]) or 0,
build = tonumber(sver[4]) or 0
}
return data
end
-- replacement of build-in read of UCI option -- replacement of build-in read of UCI option
-- modified AbstractValue.cfgvalue(self, section) from cbi.lua -- modified AbstractValue.cfgvalue(self, section) from cbi.lua
-- needed to read from other option then current value definition -- needed to read from other option then current value definition
@ -103,6 +164,28 @@ function read_value(self, section, option)
end end
end end
-- replacement of build-in Flag.parse of cbi.lua
-- modified to mark section as changed if value changes
-- current parse did not do this, but it is done AbstaractValue.parse()
function flag_parse(self, section)
local fexists = self.map:formvalue(
luci.cbi.FEXIST_PREFIX .. self.config .. "." .. section .. "." .. self.option)
if fexists then
local fvalue = self:formvalue(section) and self.enabled or self.disabled
local cvalue = self:cfgvalue(section)
if fvalue ~= self.default or (not self.optional and not self.rmempty) then
self:write(section, fvalue)
else
self:remove(section)
end
if (fvalue ~= cvalue) then self.section.changed = true end
else
self:remove(section)
self.section.changed = true
end
end
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
-- copied from https://svn.nmap.org/nmap/nselib/url.lua -- copied from https://svn.nmap.org/nmap/nselib/url.lua
-- @author Diego Nehab -- @author Diego Nehab

View file

@ -2,6 +2,12 @@
<!-- ++ BEGIN ++ Dynamic DNS ++ overview_status.htm ++ --> <!-- ++ BEGIN ++ Dynamic DNS ++ overview_status.htm ++ -->
<script type="text/javascript">//<![CDATA[ <script type="text/javascript">//<![CDATA[
// variables to store version information
var luci_version
var luci_build
var ddns_version
var ddns_required
// helper to extract section from objects id // helper to extract section from objects id
// cbi.ddns.SECTION._xyz // cbi.ddns.SECTION._xyz
function _id2section(id) { function _id2section(id) {
@ -14,7 +20,11 @@
// called by XHR.poll and onclick_startstop // called by XHR.poll and onclick_startstop
function _data2elements(data) { function _data2elements(data) {
// DDNS Service // DDNS Service
// data[0] ignored here // fill Version informations
luci_version = data[0].luci_ver
luci_build = data[0].luci_build
ddns_version = data[0].script_ver
ddns_required = data[0].script_min
// Service sections // Service sections
for( i = 1; i < data.length; i++ ) for( i = 1; i < data.length; i++ )
@ -38,7 +48,7 @@
btn.className = "cbi-button cbi-input-apply"; btn.className = "cbi-button cbi-input-apply";
} }
btn.disabled = false; // button enabled btn.disabled = false; // button enabled
// last update // last update
switch (data[i].datelast) { switch (data[i].datelast) {
case "_empty_": case "_empty_":
@ -71,7 +81,7 @@
nup.innerHTML = '<em><%:Disabled%></em>'; nup.innerHTML = '<em><%:Disabled%></em>';
btn.value = '----------'; btn.value = '----------';
btn.className = "cbi-button cbi-input-button"; // no image btn.className = "cbi-button cbi-input-button"; // no image
btn.disabled = true; // disabled btn.disabled = true; // disabled
} }
break; break;
default: default:
@ -84,13 +94,13 @@
// registered IP // registered IP
// rip.innerHTML = "Registered IP"; // rip.innerHTML = "Registered IP";
if (data[i].domain == "_nodomain_") if (data[i].domain == "_nodomain_")
rip.innerHTML = ''; rip.innerHTML = '';
else if (data[i].reg_ip == "_nodata_") else if (data[i].reg_ip == "_nodata_")
rip.innerHTML = '<em><%:No data%></em>'; rip.innerHTML = '<em><%:No data%></em>';
else else
rip.innerHTML = data[i].reg_ip; rip.innerHTML = data[i].reg_ip;
// monitored interfacce // monitored interfacce
// data[i].iface ignored here // data[i].iface ignored here
} }
@ -121,13 +131,27 @@
} else { } else {
btn.value = '----------'; btn.value = '----------';
btn.className = "cbi-button cbi-input-button"; // no image btn.className = "cbi-button cbi-input-button"; // no image
btn.disabled = true; // disabled btn.disabled = true; // disabled
} }
}
// event handler for map.title link
function onclick_maptitle() {
var str = "<%:Version Information%>";
str += "\n\nluci-app-ddns:";
str += "\n\t<%:Version%>:\t" + luci_version;
str += "\n\t<%:Build%>:\t" + luci_build;
str += "\n\nddns-scripts <%:installed%>:";
str += "\n\t<%:Version%>:\t" + ddns_version;
str += "\n\nddns-scripts <%:required%>:";
str += "\n\t<%:Version%>:\t" + ddns_required + " <%:or greater%>";
str += "\n\n"
alert(str);
} }
// event handler for start/stop button // event handler for start/stop button
function onclick_startstop(id) { function onclick_startstop(id) {
// extract section // extract section
var section = _id2section(id); var section = _id2section(id);
// get elements // get elements
var cbx = document.getElementById("cbid.ddns." + section + ".enabled"); // Enabled var cbx = document.getElementById("cbid.ddns." + section + ".enabled"); // Enabled
@ -158,14 +182,20 @@
); );
} }
// force to immediate show status on page load (not waiting for XHR.poll)
XHR.get('<%=luci.dispatcher.build_url("admin", "services", "ddns", "status")%>', null,
function(x, data) {
_data2elements(data);
}
);
// define only ONE XHR.poll in a page because if one is running it blocks the other one // define only ONE XHR.poll in a page because if one is running it blocks the other one
// optimum is to define on Map or Section Level from here you can reach all elements // optimum is to define on Map or Section Level from here you can reach all elements
// we need update every 30 seconds only // we need update every 15 seconds only
XHR.poll(30, '<%=luci.dispatcher.build_url("admin", "services", "ddns", "status")%>', null, XHR.poll(15, '<%=luci.dispatcher.build_url("admin", "services", "ddns", "status")%>', null,
function(x, data) function(x, data) {
{
_data2elements(data); _data2elements(data);
} }
); );
//]]></script> //]]></script>

View file

@ -1,127 +1,140 @@
<!-- ++ BEGIN ++ Dynamic DNS ++ system_status.htm ++ --> <!-- ++ BEGIN ++ Dynamic DNS ++ system_status.htm ++ -->
<script type="text/javascript">//<![CDATA[ <script type="text/javascript">//<![CDATA[
XHR.poll(10, '<%=luci.dispatcher.build_url("admin", "services", "ddns", "status")%>', null, // helper to move status data to the relevant
function(x, data) // screen objects
// called by XHR.poll and XHR.get
function _data2elements(x, data) {
var tbl = document.getElementById('ddns_status_table');
// security check
if ( !(tbl) ) { return; }
// clear all rows
while (tbl.rows.length > 1)
tbl.deleteRow(1);
// variable for Modulo-Division use to set cbi-rowstyle-? (0 or 1)
var x = -1;
var i = 1;
// no data => no ddns-scripts Version 2 installed
if ( !data ) {
var txt = '<br /><strong><font color="red"><%:Old version of ddns-scripts installed%></font>' ;
var url = '<a href="' ;
url += '<%=luci.dispatcher.build_url("admin", "system", "packages")%>' ;
url += '"><%:install update here%></a></strong>' ;
var tr = tbl.insertRow(-1);
tr.className = 'cbi-section-table-row cbi-rowstyle-' + (((i + x) % 2) + 1);
var td = tr.insertCell(-1);
td.colSpan = 2 ;
td.innerHTML = txt + " - " + url
tr.insertCell(-1).colSpan = 3 ;
return;
}
// DDNS Service disabled
if (data[0].enabled == 0) {
var txt = '<strong><font color="red"><%:DDNS Autostart disabled%></font>' ;
var url = '<a href="' + data[0].url_up + '"><%:enable here%></a></strong>' ;
var tr = tbl.insertRow(-1);
tr.className = 'cbi-section-table-row cbi-rowstyle-' + (((i + x) % 2) + 1);
var td = tr.insertCell(-1);
td.colSpan = 2 ;
td.innerHTML = txt + " - " + url
tr.insertCell(-1).colSpan = 3 ;
x++ ;
}
for( i = 1; i < data.length; i++ )
{ {
var tbl = document.getElementById('ddns_status_table'); var tr = tbl.insertRow(-1);
// security check tr.className = 'cbi-section-table-row cbi-rowstyle-' + (((i + x) % 2) + 1) ;
if ( !(tbl) ) { return; }
// clear all rows // configuration
while (tbl.rows.length > 1) tr.insertCell(-1).innerHTML = '<strong>' + data[i].section + '</strong>' ;
tbl.deleteRow(1);
// variable for Modulo-Division use to set cbi-rowstyle-? (0 or 1) // pid
var x = -1; // data[i].pid ignored here
var i = 1;
// no data => no ddns-scripts Version 2 installed // last update
if ( !data ) { // data[i].datelast ignored here
var txt = '<br /><strong><font color="red"><%:Old version of ddns-scripts installed%></font>' ;
var url = '<a href="' ; // next update
url += '<%=luci.dispatcher.build_url("admin", "system", "packages")%>' ; switch (data[i].datenext) {
url += '"><%:install update here%></a></strong>' ; case "_empty_":
var tr = tbl.insertRow(-1); tr.insertCell(-1).innerHTML = '<em><%:Unknown error%></em>' ;
tr.className = 'cbi-section-table-row cbi-rowstyle-' + (((i + x) % 2) + 1); break;
var td = tr.insertCell(-1); case "_stopped_":
td.colSpan = 2 ; tr.insertCell(-1).innerHTML = '<em><%:Stopped%></em>' ;
td.innerHTML = txt + " - " + url break;
tr.insertCell(-1).colSpan = 3 ; case "_disabled_":
return; tr.insertCell(-1).innerHTML = '<em><%:Disabled%></em>' ;
break;
case "_noupdate_":
tr.insertCell(-1).innerHTML = '<em><%:Update error%></em>' ;
break;
case "_runonce_":
tr.insertCell(-1).innerHTML = '<em><%:Run once%></em>' ;
break;
case "_verify_":
tr.insertCell(-1).innerHTML = '<em><%:Verify%></em>';
break;
default:
tr.insertCell(-1).innerHTML = data[i].datenext ;
break;
} }
// DDNS Service disabled // domain
if (data[0].enabled == 0) { if (data[i].domain == "_nodomain_")
var txt = '<strong><font color="red"><%:DDNS Autostart disabled%></font>' ; tr.insertCell(-1).innerHTML = '<em><%:config error%></em>';
var url = '<a href="' + data[0].url_up + '"><%:enable here%></a></strong>' ; else
var tr = tbl.insertRow(-1); tr.insertCell(-1).innerHTML = data[i].domain;
tr.className = 'cbi-section-table-row cbi-rowstyle-' + (((i + x) % 2) + 1);
var td = tr.insertCell(-1);
td.colSpan = 2 ;
td.innerHTML = txt + " - " + url
tr.insertCell(-1).colSpan = 3 ;
x++ ;
}
for( i = 1; i < data.length; i++ ) // registered IP
{ switch (data[i].reg_ip) {
var tr = tbl.insertRow(-1); case "_nodomain_":
tr.className = 'cbi-section-table-row cbi-rowstyle-' + (((i + x) % 2) + 1) ;
// configuration
tr.insertCell(-1).innerHTML = '<strong>' + data[i].section + '</strong>' ;
// pid
// data[i].pid ignored here
// last update
// data[i].datelast ignored here
// next update
switch (data[i].datenext) {
case "_empty_":
tr.insertCell(-1).innerHTML = '<em><%:Unknown error%></em>' ;
break;
case "_stopped_":
tr.insertCell(-1).innerHTML = '<em><%:Stopped%></em>' ;
break;
case "_disabled_":
tr.insertCell(-1).innerHTML = '<em><%:Disabled%></em>' ;
break;
case "_noupdate_":
tr.insertCell(-1).innerHTML = '<em><%:Update error%></em>' ;
break;
case "_runonce_":
tr.insertCell(-1).innerHTML = '<em><%:Run once%></em>' ;
break;
case "_verify_":
tr.insertCell(-1).innerHTML = '<em><%:Verify%></em>';
break;
default:
tr.insertCell(-1).innerHTML = data[i].datenext ;
break;
}
// domain
if (data[i].domain == "_nodomain_")
tr.insertCell(-1).innerHTML = '<em><%:config error%></em>';
else
tr.insertCell(-1).innerHTML = data[i].domain;
// registered IP
switch (data[i].reg_ip) {
case "_nodomain_":
tr.insertCell(-1).innerHTML = '<em><%:Config error%></em>';
break;
case "_nodata_":
tr.insertCell(-1).innerHTML = '<em><%:No data%></em>';
break;
case "_noipv6_":
tr.insertCell(-1).innerHTML = '<em><%:IPv6 not supported%></em>';
break;
default:
tr.insertCell(-1).innerHTML = data[i].reg_ip;
break;
}
// monitored interfacce
if (data[i].iface == "_nonet_")
tr.insertCell(-1).innerHTML = '<em><%:Config error%></em>'; tr.insertCell(-1).innerHTML = '<em><%:Config error%></em>';
else break;
tr.insertCell(-1).innerHTML = data[i].iface; case "_nodata_":
tr.insertCell(-1).innerHTML = '<em><%:No data%></em>';
break;
case "_noipv6_":
tr.insertCell(-1).innerHTML = '<em><%:IPv6 not supported%></em>';
break;
default:
tr.insertCell(-1).innerHTML = data[i].reg_ip;
break;
} }
if (tbl.rows.length == 1 || (data[0].enabled == 0 && tbl.rows.length == 2) ) { // monitored interfacce
var br = '<br />'; if (data[i].iface == "_nonet_")
if (tbl.rows.length > 1) tr.insertCell(-1).innerHTML = '<em><%:Config error%></em>';
br = ''; else
var tr = tbl.insertRow(-1); tr.insertCell(-1).innerHTML = data[i].iface;
tr.className = "cbi-section-table-row"; }
var td = tr.insertCell(-1);
td.colSpan = 5; if (tbl.rows.length == 1 || (data[0].enabled == 0 && tbl.rows.length == 2) ) {
td.innerHTML = '<em>' + br + '<%:There is no service configured.%></em>' ; var br = '<br />';
} if (tbl.rows.length > 1)
br = '';
var tr = tbl.insertRow(-1);
tr.className = "cbi-section-table-row";
var td = tr.insertCell(-1);
td.colSpan = 5;
td.innerHTML = '<em>' + br + '<%:There is no service configured.%></em>' ;
}
}
// force to immediate show status (not waiting for XHR.poll)
XHR.get('<%=luci.dispatcher.build_url("admin", "services", "ddns", "status")%>', null,
function(x, data) {
_data2elements(x, data);
}
);
XHR.poll(10, '<%=luci.dispatcher.build_url("admin", "services", "ddns", "status")%>', null,
function(x, data) {
_data2elements(x, data);
} }
); );
//]]></script> //]]></script>

View file

@ -1,10 +1,8 @@
#!/bin/sh #!/bin/sh
# needed for "Save and Apply" to restart ddns # no longer needed for "Save and Apply" to restart ddns
uci -q batch <<-EOF >/dev/null uci -q batch <<-EOF >/dev/null
delete ucitrack.@ddns[-1] delete ucitrack.@ddns[-1]
add ucitrack ddns
set ucitrack.@ddns[-1].init="ddns"
commit ucitrack commit ucitrack
EOF EOF

View file

@ -1,13 +1,14 @@
#!/bin/sh #!/bin/sh
# /usr/lib/ddns/luci_dns_helper.sh # /usr/lib/ddns/luci_dns_helper.sh
# #
# Written by Christian Schoenebeck in August 2014 to support: # Written in August 2014
# this script is used by luci-app-ddns # by Christian Schoenebeck <christian dot schoenebeck at gmail dot com>
# This script is used by luci-app-ddns
# - getting registered IP # - getting registered IP
# - check if possible to get local IP # - check if possible to get local IP
# - verifing given DNS- or Proxy-Server # - verifing given DNS- or Proxy-Server
# #
# variables in small chars are read from /etc/config/ddns # variables in small chars are read from /etc/config/ddns as parameter given here
# variables in big chars are defined inside these scripts as gloval vars # variables in big chars are defined inside these scripts as gloval vars
# variables in big chars beginning with "__" are local defined inside functions only # variables in big chars beginning with "__" are local defined inside functions only
# set -vx #script debugger # set -vx #script debugger
@ -18,13 +19,13 @@
# set -vx #script debugger # set -vx #script debugger
# preset some variables wrong or not set in dynamic_dns_functions.sh # preset some variables, wrong or not set in dynamic_dns_functions.sh
SECTION_ID="dynamic_dns_lucihelper" SECTION_ID="lucihelper"
LOGFILE="$LOGDIR/$SECTION_ID.log" LOGFILE="$LOGDIR/$SECTION_ID.log"
LUCI_HELPER="ACTIV" # supress verbose and critical logging VERBOSE_MODE=0 # no console logging
# global variables normally set by reading DDNS UCI configuration # global variables normally set by reading DDNS UCI configuration
use_logfile=0 use_syslog=0 # no syslog
use_syslog=0 use_logfile=0 # by default no logfile, can be changed here
case "$1" in case "$1" in
get_registered_ip) get_registered_ip)
@ -34,21 +35,24 @@ case "$1" in
force_ipversion=${4:-"0"} # Force IP Version - default 0 - No force_ipversion=${4:-"0"} # Force IP Version - default 0 - No
force_dnstcp=${5:-"0"} # Force TCP on DNS - default 0 - No force_dnstcp=${5:-"0"} # Force TCP on DNS - default 0 - No
dns_server=${6:-""} # DNS server - default No DNS dns_server=${6:-""} # DNS server - default No DNS
write_log 7 "-----> get_registered_ip IP"
get_registered_ip IP get_registered_ip IP
[ $? -ne 0 ] && IP="" [ $? -ne 0 ] && IP=""
echo -n "$IP" # suppress LF echo -n "$IP" # suppress LF
;; ;;
verify_dns) verify_dns)
# $2 == dns-server to verify # no need for force_dnstcp because # $2 : dns-server to verify # no need for force_dnstcp because
# verify with nc (netcat) uses tcp anyway # verify with nc (netcat) uses tcp anyway
use_ipv6=${3:-"0"} # Use IPv6 - default IPv4 use_ipv6=${3:-"0"} # Use IPv6 - default IPv4
force_ipversion=${4:-"0"} # Force IP Version - default 0 - No force_ipversion=${4:-"0"} # Force IP Version - default 0 - No
write_log 7 "-----> verify_dns '$2'"
verify_dns "$2" verify_dns "$2"
;; ;;
verify_proxy) verify_proxy)
# $2 == proxy string to verify # $2 : proxy string to verify
use_ipv6=${3:-"0"} # Use IPv6 - default IPv4 use_ipv6=${3:-"0"} # Use IPv6 - default IPv4
force_ipversion=${4:-"0"} # Force IP Version - default 0 - No force_ipversion=${4:-"0"} # Force IP Version - default 0 - No
write_log 7 "-----> verify_proxy '$2'"
verify_proxy "$2" verify_proxy "$2"
;; ;;
get_local_ip) get_local_ip)
@ -62,7 +66,7 @@ case "$1" in
proxy="$8" # proxy if set proxy="$8" # proxy if set
force_ipversion="0" # not needed but must be set force_ipversion="0" # not needed but must be set
use_https="0" # not needed but must be set use_https="0" # not needed but must be set
[ -n "$proxy" -a "$ip_source" == "web" ] && { [ -n "$proxy" -a "$ip_source" = "web" ] && {
# proxy defined, used for ip_source=web # proxy defined, used for ip_source=web
export HTTP_PROXY="http://$proxy" export HTTP_PROXY="http://$proxy"
export HTTPS_PROXY="http://$proxy" export HTTPS_PROXY="http://$proxy"
@ -70,13 +74,17 @@ case "$1" in
export https_proxy="http://$proxy" export https_proxy="http://$proxy"
} }
# don't need IP only the return code # don't need IP only the return code
[ "$ip_source" == "web" -o "$ip_source" == "script"] && { [ "$ip_source" = "web" -o "$ip_source" = "script" ] && {
# we wait only 3 seconds for an # we wait only 3 seconds for an
# answer from "web" or "script" # answer from "web" or "script"
__timeout 3 -- get_local_ip IP write_log 7 "-----> timeout 3 -- get_local_ip IP"
} || get_local_ip IP timeout 3 -- get_local_ip IP
} || {
write_log 7 "-----> get_local_ip IP"
get_local_ip IP
}
;; ;;
*) *)
return 1 return 255
;; ;;
esac esac

View file

@ -1,8 +1,8 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: luci-app-ddns\n" "Project-Id-Version: luci-app-ddns\n"
"POT-Creation-Date: 2014-10-04 16:26+1000\n" "POT-Creation-Date: 2014-11-09 13:41+0100\n"
"PO-Revision-Date: 2014-10-04 16:27+0100\n" "PO-Revision-Date: 2014-11-09 14:29+0100\n"
"Last-Translator: Christian Schoenebeck <christian.schoenebeck@gmail.com>\n" "Last-Translator: Christian Schoenebeck <christian.schoenebeck@gmail.com>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
"Language: de\n" "Language: de\n"
@ -36,6 +36,9 @@ msgstr ""
">Wenn Sie Aktualisierungen für IPv4 und IPv6 senden möchten benötigen Sie " ">Wenn Sie Aktualisierungen für IPv4 und IPv6 senden möchten benötigen Sie "
"zwei Konfigurationen z.B. 'myddns_ipv4' und 'myddns_ipv6'" "zwei Konfigurationen z.B. 'myddns_ipv4' und 'myddns_ipv6'"
msgid "Build"
msgstr "Build"
msgid "" msgid ""
"BusyBox's nslookup and Wget do not support to specify the IP version to use " "BusyBox's nslookup and Wget do not support to specify the IP version to use "
"for communication with DDNS Provider." "for communication with DDNS Provider."
@ -347,6 +350,9 @@ msgstr "Bitte [Speichern & Anwenden] Sie Änderungen zunächst"
msgid "Please press [Read] button" msgid "Please press [Read] button"
msgstr "Bitte Protokolldatei einlesen" msgstr "Bitte Protokolldatei einlesen"
msgid "Please update to the current version!"
msgstr "Aktualisieren Sie bitte auf die aktuelle Version!"
msgid "Process ID" msgid "Process ID"
msgstr "Prozess ID" msgstr "Prozess ID"
@ -377,6 +383,9 @@ msgstr "Dienst"
msgid "Show more" msgid "Show more"
msgstr "Zeige mehr" msgstr "Zeige mehr"
msgid "Software update required"
msgstr "Softwareaktualisierung nötig"
msgid "Source of IP address" msgid "Source of IP address"
msgstr "Quelle der IP-Adresse" msgstr "Quelle der IP-Adresse"
@ -386,6 +395,13 @@ msgstr "Start / Stopp"
msgid "Stopped" msgid "Stopped"
msgstr "Angehalten" msgstr "Angehalten"
msgid ""
"The currently installed 'ddns-scripts' package did not support all available "
"settings."
msgstr ""
"Die installierte Software 'ddns-scripts' unterstützt nicht alle verfügbaren "
"Optionen."
msgid "There is no service configured." msgid "There is no service configured."
msgstr "Kein Dienst konfiguriert" msgstr "Kein Dienst konfiguriert"
@ -419,6 +435,9 @@ msgstr ""
"Definiert das Skript mit dem die aktuelle IP-Adresse des System gelesen " "Definiert das Skript mit dem die aktuelle IP-Adresse des System gelesen "
"wird." "wird."
msgid "Version Information"
msgstr "Versionsinformationen"
msgid "" msgid ""
"Writes detailed messages to log file. File will be truncated automatically." "Writes detailed messages to log file. File will be truncated automatically."
msgstr "" msgstr ""
@ -490,6 +509,9 @@ msgstr "Stunden"
msgid "install update here" msgid "install update here"
msgstr "Aktualisierung hier installieren" msgstr "Aktualisierung hier installieren"
msgid "installed"
msgstr "installiert"
msgid "interface" msgid "interface"
msgstr "Schnittstelle" msgstr "Schnittstelle"
@ -542,6 +564,9 @@ msgstr "nslookup kann den Namen nicht auflösen"
msgid "or" msgid "or"
msgstr "oder" msgstr "oder"
msgid "or greater"
msgstr "oder größer"
msgid "please disable" msgid "please disable"
msgstr "Bitte deaktivieren" msgstr "Bitte deaktivieren"
@ -557,6 +582,9 @@ msgstr "Bitte 'IPv4' Adressversion auswählen in den"
msgid "proxy port missing" msgid "proxy port missing"
msgstr "Proxy-Port fehlt" msgstr "Proxy-Port fehlt"
msgid "required"
msgstr "erforderlich"
msgid "seconds" msgid "seconds"
msgstr "Sekunden" msgstr "Sekunden"

View file

@ -18,6 +18,9 @@ msgid ""
"separate Configurations i.e. 'myddns_ipv4' and 'myddns_ipv6'" "separate Configurations i.e. 'myddns_ipv4' and 'myddns_ipv6'"
msgstr "" msgstr ""
msgid "Build"
msgstr ""
msgid "" msgid ""
"BusyBox's nslookup and Wget do not support to specify the IP version to use " "BusyBox's nslookup and Wget do not support to specify the IP version to use "
"for communication with DDNS Provider." "for communication with DDNS Provider."
@ -279,6 +282,9 @@ msgstr ""
msgid "Please press [Read] button" msgid "Please press [Read] button"
msgstr "" msgstr ""
msgid "Please update to the current version!"
msgstr ""
msgid "Process ID" msgid "Process ID"
msgstr "" msgstr ""
@ -309,6 +315,9 @@ msgstr ""
msgid "Show more" msgid "Show more"
msgstr "" msgstr ""
msgid "Software update required"
msgstr ""
msgid "Source of IP address" msgid "Source of IP address"
msgstr "" msgstr ""
@ -318,6 +327,11 @@ msgstr ""
msgid "Stopped" msgid "Stopped"
msgstr "" msgstr ""
msgid ""
"The currently installed 'ddns-scripts' package did not support all available "
"settings."
msgstr ""
msgid "There is no service configured." msgid "There is no service configured."
msgstr "" msgstr ""
@ -347,6 +361,9 @@ msgstr ""
msgid "User defined script to read systems IP-Address" msgid "User defined script to read systems IP-Address"
msgstr "" msgstr ""
msgid "Version Information"
msgstr ""
msgid "" msgid ""
"Writes detailed messages to log file. File will be truncated automatically." "Writes detailed messages to log file. File will be truncated automatically."
msgstr "" msgstr ""
@ -407,6 +424,9 @@ msgstr ""
msgid "install update here" msgid "install update here"
msgstr "" msgstr ""
msgid "installed"
msgstr ""
msgid "interface" msgid "interface"
msgstr "" msgstr ""
@ -458,6 +478,9 @@ msgstr ""
msgid "or" msgid "or"
msgstr "" msgstr ""
msgid "or greater"
msgstr ""
msgid "please disable" msgid "please disable"
msgstr "" msgstr ""
@ -473,6 +496,9 @@ msgstr ""
msgid "proxy port missing" msgid "proxy port missing"
msgstr "" msgstr ""
msgid "required"
msgstr ""
msgid "seconds" msgid "seconds"
msgstr "" msgstr ""