summaryrefslogtreecommitdiffhomepage
path: root/applications/luci-app-dnscrypt-proxy/luasrc
diff options
context:
space:
mode:
Diffstat (limited to 'applications/luci-app-dnscrypt-proxy/luasrc')
-rw-r--r--applications/luci-app-dnscrypt-proxy/luasrc/controller/dnscrypt-proxy.lua38
-rw-r--r--applications/luci-app-dnscrypt-proxy/luasrc/model/cbi/dnscrypt-proxy/cfg_dnsmasq_tab.lua39
-rw-r--r--applications/luci-app-dnscrypt-proxy/luasrc/model/cbi/dnscrypt-proxy/cfg_resolvcrypt_tab.lua39
-rw-r--r--applications/luci-app-dnscrypt-proxy/luasrc/model/cbi/dnscrypt-proxy/configuration_tab.lua39
-rw-r--r--applications/luci-app-dnscrypt-proxy/luasrc/model/cbi/dnscrypt-proxy/overview_tab.lua263
-rw-r--r--applications/luci-app-dnscrypt-proxy/luasrc/view/dnscrypt-proxy/config_css.htm13
-rw-r--r--applications/luci-app-dnscrypt-proxy/luasrc/view/dnscrypt-proxy/logread.htm15
-rw-r--r--applications/luci-app-dnscrypt-proxy/luasrc/view/dnscrypt-proxy/res_options.htm10
-rw-r--r--applications/luci-app-dnscrypt-proxy/luasrc/view/dnscrypt-proxy/view_reslist.htm15
9 files changed, 471 insertions, 0 deletions
diff --git a/applications/luci-app-dnscrypt-proxy/luasrc/controller/dnscrypt-proxy.lua b/applications/luci-app-dnscrypt-proxy/luasrc/controller/dnscrypt-proxy.lua
new file mode 100644
index 0000000000..ca078f0cd3
--- /dev/null
+++ b/applications/luci-app-dnscrypt-proxy/luasrc/controller/dnscrypt-proxy.lua
@@ -0,0 +1,38 @@
+-- Copyright 2017 Dirk Brenken (dev@brenken.org)
+-- This is free software, licensed under the Apache License, Version 2.0
+
+module("luci.controller.dnscrypt-proxy", package.seeall)
+
+local util = require("luci.util")
+local i18n = require("luci.i18n")
+local templ = require("luci.template")
+
+function index()
+ if not nixio.fs.access("/etc/config/dnscrypt-proxy") then
+ nixio.fs.writefile("/etc/config/dnscrypt-proxy", "")
+ end
+ entry({"admin", "services", "dnscrypt-proxy"}, firstchild(), _("DNSCrypt-Proxy"), 60).dependent = false
+ entry({"admin", "services", "dnscrypt-proxy", "tab_from_cbi"}, cbi("dnscrypt-proxy/overview_tab", {hideresetbtn=true, hidesavebtn=true}), _("Overview"), 10).leaf = true
+ entry({"admin", "services", "dnscrypt-proxy", "logfile"}, call("logread"), _("View Logfile"), 20).leaf = true
+ entry({"admin", "services", "dnscrypt-proxy", "advanced"}, firstchild(), _("Advanced"), 100)
+ entry({"admin", "services", "dnscrypt-proxy", "advanced", "configuration"}, form("dnscrypt-proxy/configuration_tab"), _("Edit DNSCrypt-Proxy Configuration"), 110).leaf = true
+ entry({"admin", "services", "dnscrypt-proxy", "advanced", "cfg_dnsmasq"}, form("dnscrypt-proxy/cfg_dnsmasq_tab"), _("Edit Dnsmasq Configuration"), 120).leaf = true
+ entry({"admin", "services", "dnscrypt-proxy", "advanced", "cfg_resolvcrypt"}, form("dnscrypt-proxy/cfg_resolvcrypt_tab"), _("Edit Resolvcrypt Configuration"), 130).leaf = true
+ entry({"admin", "services", "dnscrypt-proxy", "advanced", "view_reslist"}, call("view_reslist"), _("View Resolver List"), 140).leaf = true
+end
+
+function view_reslist()
+ local reslist = util.trim(util.exec("cat /usr/share/dnscrypt-proxy/dnscrypt-resolvers.csv"))
+ templ.render("dnscrypt-proxy/view_reslist", {title = i18n.translate("DNSCrypt-Proxy Resolver List"), content = reslist})
+end
+
+function logread()
+ local logfile
+
+ if nixio.fs.access("/var/log/messages") then
+ logfile = util.trim(util.exec("cat /var/log/messages | grep 'dnscrypt-proxy'"))
+ else
+ logfile = util.trim(util.exec("logread -e 'dnscrypt-proxy'"))
+ end
+ templ.render("dnscrypt-proxy/logread", {title = i18n.translate("DNSCrypt-Proxy Logfile"), content = logfile})
+end
diff --git a/applications/luci-app-dnscrypt-proxy/luasrc/model/cbi/dnscrypt-proxy/cfg_dnsmasq_tab.lua b/applications/luci-app-dnscrypt-proxy/luasrc/model/cbi/dnscrypt-proxy/cfg_dnsmasq_tab.lua
new file mode 100644
index 0000000000..6e75ac9f97
--- /dev/null
+++ b/applications/luci-app-dnscrypt-proxy/luasrc/model/cbi/dnscrypt-proxy/cfg_dnsmasq_tab.lua
@@ -0,0 +1,39 @@
+-- Copyright 2017 Dirk Brenken (dev@brenken.org)
+-- This is free software, licensed under the Apache License, Version 2.0
+
+local nxfs = require("nixio.fs")
+local util = require("luci.util")
+local uci_input = "/etc/config/dhcp"
+
+if not nxfs.access(uci_input) then
+ m = SimpleForm("error", nil, translate("Input file not found, please check your configuration."))
+ m.reset = false
+ m.submit = false
+ return m
+end
+
+m = SimpleForm("input", nil)
+m:append(Template("dnscrypt-proxy/config_css"))
+m.submit = translate("Save")
+m.reset = false
+
+s = m:section(SimpleSection, nil,
+ translate("This form allows you to modify the content of the main Dnsmasq configuration file (/etc/config/dhcp)."))
+
+f = s:option(TextValue, "data")
+f.rows = 20
+f.rmempty = true
+
+function f.cfgvalue()
+ return nxfs.readfile(uci_input) or ""
+end
+
+function f.write(self, section, data)
+ return nxfs.writefile(uci_input, "\n" .. util.trim(data:gsub("\r\n", "\n")) .. "\n")
+end
+
+function s.handle(self, state, data)
+ return true
+end
+
+return m
diff --git a/applications/luci-app-dnscrypt-proxy/luasrc/model/cbi/dnscrypt-proxy/cfg_resolvcrypt_tab.lua b/applications/luci-app-dnscrypt-proxy/luasrc/model/cbi/dnscrypt-proxy/cfg_resolvcrypt_tab.lua
new file mode 100644
index 0000000000..f172b15f81
--- /dev/null
+++ b/applications/luci-app-dnscrypt-proxy/luasrc/model/cbi/dnscrypt-proxy/cfg_resolvcrypt_tab.lua
@@ -0,0 +1,39 @@
+-- Copyright 2017 Dirk Brenken (dev@brenken.org)
+-- This is free software, licensed under the Apache License, Version 2.0
+
+local nxfs = require("nixio.fs")
+local util = require("luci.util")
+local res_input = "/etc/resolv-crypt.conf"
+
+if not nxfs.access(res_input) then
+ m = SimpleForm("error", nil, translate("Input file not found, please check your configuration."))
+ m.reset = false
+ m.submit = false
+ return m
+end
+
+m = SimpleForm("input", nil)
+m:append(Template("dnscrypt-proxy/config_css"))
+m.submit = translate("Save")
+m.reset = false
+
+s = m:section(SimpleSection, nil,
+ translate("This form allows you to modify the content of the resolv-crypt configuration file (/etc/resolv-crypt.conf)."))
+
+f = s:option(TextValue, "data")
+f.rows = 20
+f.rmempty = true
+
+function f.cfgvalue()
+ return nxfs.readfile(res_input) or ""
+end
+
+function f.write(self, section, data)
+ return nxfs.writefile(res_input, "\n" .. util.trim(data:gsub("\r\n", "\n")) .. "\n")
+end
+
+function s.handle(self, state, data)
+ return true
+end
+
+return m
diff --git a/applications/luci-app-dnscrypt-proxy/luasrc/model/cbi/dnscrypt-proxy/configuration_tab.lua b/applications/luci-app-dnscrypt-proxy/luasrc/model/cbi/dnscrypt-proxy/configuration_tab.lua
new file mode 100644
index 0000000000..f1842731d5
--- /dev/null
+++ b/applications/luci-app-dnscrypt-proxy/luasrc/model/cbi/dnscrypt-proxy/configuration_tab.lua
@@ -0,0 +1,39 @@
+-- Copyright 2017 Dirk Brenken (dev@brenken.org)
+-- This is free software, licensed under the Apache License, Version 2.0
+
+local nxfs = require("nixio.fs")
+local util = require("luci.util")
+local uci_input = "/etc/config/dnscrypt-proxy"
+
+if not nxfs.access(uci_input) then
+ m = SimpleForm("error", nil, translate("Input file not found, please check your configuration."))
+ m.reset = false
+ m.submit = false
+ return m
+end
+
+m = SimpleForm("input", nil)
+m:append(Template("dnscrypt-proxy/config_css"))
+m.submit = translate("Save")
+m.reset = false
+
+s = m:section(SimpleSection, nil,
+ translate("This form allows you to modify the content of the main DNSCrypt-Proxy configuration file (/etc/config/dnscrypt-proxy)."))
+
+f = s:option(TextValue, "data")
+f.rows = 20
+f.rmempty = true
+
+function f.cfgvalue()
+ return nxfs.readfile(uci_input) or ""
+end
+
+function f.write(self, section, data)
+ return nxfs.writefile(uci_input, "\n" .. util.trim(data:gsub("\r\n", "\n")) .. "\n")
+end
+
+function s.handle(self, state, data)
+ return true
+end
+
+return m
diff --git a/applications/luci-app-dnscrypt-proxy/luasrc/model/cbi/dnscrypt-proxy/overview_tab.lua b/applications/luci-app-dnscrypt-proxy/luasrc/model/cbi/dnscrypt-proxy/overview_tab.lua
new file mode 100644
index 0000000000..8f0e3224b4
--- /dev/null
+++ b/applications/luci-app-dnscrypt-proxy/luasrc/model/cbi/dnscrypt-proxy/overview_tab.lua
@@ -0,0 +1,263 @@
+-- Copyright 2017-2018 Dirk Brenken (dev@brenken.org)
+-- This is free software, licensed under the Apache License, Version 2.0
+
+local fs = require("nixio.fs")
+local uci = require("luci.model.uci").cursor()
+local util = require("luci.util")
+local res_input = "/usr/share/dnscrypt-proxy/dnscrypt-resolvers.csv"
+local res_dir = fs.dirname(res_input)
+local dump = util.ubus("network.interface", "dump", {})
+local plug_cnt = tonumber(luci.sys.exec("env -i /usr/sbin/dnscrypt-proxy --version | grep 'Support for plugins: present' | wc -l"))
+local res_list = {}
+local url = "https://raw.githubusercontent.com/dyne/dnscrypt-proxy/master/dnscrypt-resolvers.csv"
+
+local _, date = pcall(require, "luci.http.date")
+if not date then
+ _, date = pcall(require, "luci.http.protocol.date")
+end
+
+if not fs.access(res_input) then
+ if not fs.access("/lib/libustream-ssl.so") then
+ m = SimpleForm("error", nil, translate("No default resolver list and no SSL support available.<br />")
+ .. translate("Please install a resolver list to '/usr/share/dnscrypt-proxy/dnscrypt-resolvers.csv' to use this package."))
+ m.submit = false
+ m.reset = false
+ return m
+ else
+ luci.sys.call("env -i /bin/uclient-fetch --no-check-certificate -O " .. res_input .. " " .. url .. " >/dev/null 2>&1")
+ end
+end
+
+if not uci:get_first("dnscrypt-proxy", "global") then
+ uci:add("dnscrypt-proxy", "global")
+ uci:save("dnscrypt-proxy")
+ uci:commit("dnscrypt-proxy")
+end
+
+if fs.access(res_input) then
+ for line in io.lines(res_input) or {} do
+ local name,
+ location,
+ dnssec,
+ nolog = line:match("^([^,]+),.-,\".-\",\"*(.-)\"*,.-,[0-9],\"*([yesno]+)\"*,\"*([yesno]+)\"*,.*")
+ if name ~= "" and name ~= "Name" then
+ if location == "" then
+ location = "-"
+ end
+ if dnssec == "" then
+ dnssec = "-"
+ end
+ if nolog == "" then
+ nolog = "-"
+ end
+ res_list[#res_list + 1] = { name = name, location = location, dnssec = dnssec, nolog = nolog }
+ end
+ end
+end
+
+m = Map("dnscrypt-proxy", translate("DNSCrypt-Proxy"),
+ translate("Configuration of the DNSCrypt-Proxy package. ")
+ .. translatef("For further information "
+ .. "<a href=\"%s\" target=\"_blank\">"
+ .. "see the wiki online</a>", "https://wiki.openwrt.org/inbox/dnscrypt"))
+m:chain("dhcp")
+
+function m.on_after_commit(self)
+ function d1.validate(self, value, s1)
+ if value == "1" then
+ uci:commit("dnscrypt-proxy")
+ uci:set("dhcp", s1, "noresolv", 1)
+ if not fs.access("/etc/resolv-crypt.conf") or fs.stat("/etc/resolv-crypt.conf").size == 0 then
+ uci:set("dhcp", s1, "resolvfile", "/tmp/resolv.conf.auto")
+ else
+ uci:set("dhcp", s1, "resolvfile", "/etc/resolv-crypt.conf")
+ end
+ local server_list = {}
+ local cnt = 1
+ uci:foreach("dnscrypt-proxy", "dnscrypt-proxy", function(s)
+ server_list[cnt] = s['address'] .. "#" .. s['port']
+ cnt = cnt + 1
+ end)
+ server_list[cnt] = "/pool.ntp.org/8.8.8.8"
+ uci:set_list("dhcp", s1, "server", server_list)
+ if cnt > 2 then
+ uci:set("dhcp", s1, "allservers", 1)
+ else
+ uci:set("dhcp", s1, "allservers", 0)
+ end
+ uci:save("dhcp")
+ uci:commit("dhcp")
+ end
+ return value
+ end
+ luci.sys.call("env -i /etc/init.d/dnscrypt-proxy restart >/dev/null 2>&1")
+ luci.sys.call("env -i /etc/init.d/dnsmasq restart >/dev/null 2>&1")
+end
+
+s = m:section(TypedSection, "global", translate("General Options"))
+s.anonymous = true
+
+-- Main dnscrypt-proxy resource list
+
+o1 = s:option(DummyValue, "", translate("Default Resolver List"))
+o1.template = "dnscrypt-proxy/res_options"
+o1.value = res_input
+
+o2 = s:option(DummyValue, "", translate("File Date"))
+o2.template = "dnscrypt-proxy/res_options"
+if fs.access(res_input) then
+ o2.value = date.to_http(fs.stat(res_input).mtime)
+else
+ o2.value = "-"
+end
+
+o3 = s:option(DummyValue, "", translate("File Checksum"))
+o3.template = "dnscrypt-proxy/res_options"
+if fs.access(res_input) then
+ o3.value = luci.sys.exec("sha256sum " .. res_input .. " | awk '{print $1}'")
+else
+ o3.value = "-"
+end
+
+if fs.access("/lib/libustream-ssl.so") then
+ btn1 = s:option(Button, "", translate("Refresh Resolver List"),
+ translate("Download the current resolver list from 'github.com/dyne/dnscrypt-proxy'."))
+ btn1.inputtitle = translate("Refresh List")
+ btn1.inputstyle = "apply"
+ btn1.disabled = false
+ function btn1.write()
+ if not fs.access(res_dir) then
+ fs.mkdir(res_dir)
+ end
+ luci.sys.call("env -i /bin/uclient-fetch --no-check-certificate -O " .. res_input .. " " .. url .. " >/dev/null 2>&1")
+ luci.http.redirect(luci.dispatcher.build_url("admin", "services", "dnscrypt-proxy"))
+ end
+else
+ btn1 = s:option(Button, "", translate("Refresh Resolver List"),
+ translate("No SSL support available.<br />")
+ .. translate("Please install a 'libustream-ssl' library to download the current resolver list from 'github.com/dyne/dnscrypt-proxy'."))
+ btn1.inputtitle = translate("-------")
+ btn1.inputstyle = "button"
+ btn1.disabled = true
+end
+
+if not fs.access("/etc/resolv-crypt.conf") or fs.stat("/etc/resolv-crypt.conf").size == 0 then
+ btn2 = s:option(Button, "", translate("Create Custom Config File"),
+ translate("Create '/etc/resolv-crypt.conf' with 'options timeout:1' to reduce DNS upstream timeouts with multiple DNSCrypt instances.<br />")
+ .. translatef("For further information "
+ .. "<a href=\"%s\" target=\"_blank\">"
+ .. "see the wiki online</a>", "https://wiki.openwrt.org/inbox/dnscrypt"))
+ btn2.inputtitle = translate("Create Config File")
+ btn2.inputstyle = "apply"
+ btn2.disabled = false
+ function btn2.write()
+ luci.sys.call("env -i echo 'options timeout:1' > '/etc/resolv-crypt.conf'")
+ luci.http.redirect(luci.dispatcher.build_url("admin", "services", "dnscrypt-proxy"))
+ end
+else
+ btn2 = s:option(Button, "", translate("Create Custom Config File"),
+ translate("The config file '/etc/resolv-crypt.conf' already exist.<br />")
+ .. translate("Please edit the file manually in the 'Advanced' section."))
+ btn2.inputtitle = translate("-------")
+ btn2.inputstyle = "button"
+ btn2.disabled = true
+end
+
+-- Trigger settings
+
+t = s:option(ListValue, "procd_trigger", translate("Startup Trigger"),
+ translate("By default the DNSCrypt-Proxy startup will be triggered by ifup events of 'All' available network interfaces.<br />")
+ .. translate("To restrict the trigger, select only the relevant network interface. Usually the 'wan' interface should work for most users."))
+t:value("", "All")
+if dump then
+ local i, v
+ for i, v in ipairs(dump.interface) do
+ if v.interface ~= "loopback" then
+ t:value(v.interface)
+ end
+ end
+end
+t.default = procd_trigger or "All"
+t.rmempty = true
+
+-- Mandatory options per instance
+
+s = m:section(TypedSection, "dnscrypt-proxy", translate("Instance Options"))
+s.anonymous = true
+s.addremove = true
+
+i1 = s:option(Value, "address", translate("IP Address"),
+ translate("The local IPv4 or IPv6 address. The latter one should be specified within brackets, e.g. '[::1]'."))
+i1.default = address or "127.0.0.1"
+i1.rmempty = false
+
+i2 = s:option(Value, "port", translate("Port"),
+ translate("The listening port for DNS queries."))
+i2.datatype = "port"
+i2.default = port
+i2.rmempty = false
+
+i3 = s:option(ListValue, "resolver", translate("Resolver (LOC/SEC/NOLOG)"),
+ translate("Name of the remote DNS service for resolving queries incl. Location, DNSSEC- and NOLOG-Flag."))
+i3.datatype = "hostname"
+i3.widget = "select"
+local i, v
+for i, v in ipairs(res_list) do
+ if v.name then
+ i3:value(v.name, v.name .. " (" .. v.location .. "/" .. v.dnssec .. "/" .. v.nolog .. ")")
+ end
+end
+i3.default = resolver
+i3.rmempty = false
+
+-- Extra options per instance
+
+e1 = s:option(Value, "resolvers_list", translate("Alternate Resolver List"),
+ translate("Specify a non-default Resolver List."))
+e1.datatype = "file"
+e1.optional = true
+
+e2 = s:option(Value, "ephemeral_keys", translate("Ephemeral Keys"),
+ translate("Improve privacy by using an ephemeral public key for each query. ")
+ .. translate("This option requires extra CPU cycles and is useless with most DNSCrypt server."))
+e2.datatype = "bool"
+e2.value = 1
+e2.optional = true
+
+if plug_cnt > 0 then
+ e3 = s:option(DynamicList, "blacklist", translate("Blacklist"),
+ translate("Local blacklists allow you to block abuse sites by domains or ip addresses. ")
+ .. translate("The value for this property is the blocklist type and path to the file, e.g.'domains:/path/to/dbl.txt' or 'ips:/path/to/ipbl.txt'."))
+ e3.optional = true
+
+ e4 = s:option(Value, "block_ipv6", translate("Block IPv6"),
+ translate("Disable IPv6 to speed up DNSCrypt-Proxy."))
+ e4.datatype = "bool"
+ e4.value = 1
+ e4.optional = true
+
+ e5 = s:option(Value, "local_cache", translate("Local Cache"),
+ translate("Enable Caching to speed up DNSCcrypt-Proxy."))
+ e5.datatype = "bool"
+ e5.value = 1
+ e5.optional = true
+
+ e6 = s:option(Value, "query_log_file", translate("DNS Query Logfile"),
+ translate("Log the received DNS queries to a file, so you can watch in real-time what is happening on the network."))
+ e6.optional = true
+end
+
+-- Dnsmasq options
+
+m1 = Map("dhcp")
+
+s1 = m1:section(TypedSection, "dnsmasq", translate("Dnsmasq Options"))
+s1.anonymous = true
+
+d1 = s1:option(Flag, "", translate("Transfer Options To Dnsmasq"),
+ translate("Apply DNSCrypt-Proxy specific settings to the Dnsmasq configuration.<br />")
+ .. translate("Please note: This may change the values for 'noresolv', 'resolvfile', 'allservers' and the list 'server' settings."))
+d1.default = d1.enabled
+d1.rmempty = false
+
+return m, m1
diff --git a/applications/luci-app-dnscrypt-proxy/luasrc/view/dnscrypt-proxy/config_css.htm b/applications/luci-app-dnscrypt-proxy/luasrc/view/dnscrypt-proxy/config_css.htm
new file mode 100644
index 0000000000..2233a15e31
--- /dev/null
+++ b/applications/luci-app-dnscrypt-proxy/luasrc/view/dnscrypt-proxy/config_css.htm
@@ -0,0 +1,13 @@
+<style type="text/css">
+ textarea
+ {
+ border: 1px solid #cccccc;
+ padding: 5px;
+ font-size: 12px;
+ font-family: monospace;
+ resize: none;
+ white-space: pre;
+ overflow-wrap: normal;
+ overflow-x: scroll;
+ }
+</style>
diff --git a/applications/luci-app-dnscrypt-proxy/luasrc/view/dnscrypt-proxy/logread.htm b/applications/luci-app-dnscrypt-proxy/luasrc/view/dnscrypt-proxy/logread.htm
new file mode 100644
index 0000000000..5c5ac6f81f
--- /dev/null
+++ b/applications/luci-app-dnscrypt-proxy/luasrc/view/dnscrypt-proxy/logread.htm
@@ -0,0 +1,15 @@
+<%#
+Copyright 2017 Dirk Brenken (dev@brenken.org)
+This is free software, licensed under the Apache License, Version 2.0
+-%>
+
+<%+header%>
+
+<div class="cbi-map">
+ <fieldset class="cbi-section">
+ <div class="cbi-section-descr"><%:This form shows the syslog output, pre-filtered for DNSCrypt-Proxy related messages only.%></div>
+ <textarea id="logread_id" style="width: 100%; height: 450px; border: 1px solid #cccccc; padding: 5px; font-size: 12px; font-family: monospace; resize: none;" readonly="readonly" wrap="off" rows="<%=content:cmatch("\n")+2%>"><%=content:pcdata()%></textarea>
+ </fieldset>
+</div>
+
+<%+footer%>
diff --git a/applications/luci-app-dnscrypt-proxy/luasrc/view/dnscrypt-proxy/res_options.htm b/applications/luci-app-dnscrypt-proxy/luasrc/view/dnscrypt-proxy/res_options.htm
new file mode 100644
index 0000000000..04dc37bc9d
--- /dev/null
+++ b/applications/luci-app-dnscrypt-proxy/luasrc/view/dnscrypt-proxy/res_options.htm
@@ -0,0 +1,10 @@
+<%#
+Copyright 2017 Dirk Brenken (dev@brenken.org)
+This is free software, licensed under the Apache License, Version 2.0
+-%>
+
+<%+cbi/valueheader%>
+
+<input name="reslist" id="reslist" type="text" class="cbi-input-text" style="background:transparent;border:none;box-shadow:none;color:#0069d6;width:500px" value="<%=self:cfgvalue(section)%>" disabled="disabled" />
+
+<%+cbi/valuefooter%>
diff --git a/applications/luci-app-dnscrypt-proxy/luasrc/view/dnscrypt-proxy/view_reslist.htm b/applications/luci-app-dnscrypt-proxy/luasrc/view/dnscrypt-proxy/view_reslist.htm
new file mode 100644
index 0000000000..76a2300932
--- /dev/null
+++ b/applications/luci-app-dnscrypt-proxy/luasrc/view/dnscrypt-proxy/view_reslist.htm
@@ -0,0 +1,15 @@
+<%#
+Copyright 2017 Dirk Brenken (dev@brenken.org)
+This is free software, licensed under the Apache License, Version 2.0
+-%>
+
+<%+header%>
+
+<div class="cbi-map">
+ <fieldset class="cbi-section">
+ <div class="cbi-section-descr"><%:This form shows the content of the current DNSCrypt Resolver List.%></div>
+ <textarea id="logread_id" style="width: 100%; height: 450px; border: 1px solid #cccccc; padding: 5px; font-size: 12px; font-family: monospace; resize: none;" readonly="readonly" wrap="off" rows="<%=content:cmatch("\n")+2%>"><%=content:pcdata()%></textarea>
+ </fieldset>
+</div>
+
+<%+footer%>