luci-app-dnscrypt-proxy: Updates for new repository/maintainer
[project/luci.git] / applications / luci-app-dnscrypt-proxy / luasrc / model / cbi / dnscrypt-proxy / overview_tab.lua
1 -- Copyright 2017-2018 Dirk Brenken (dev@brenken.org)
2 -- This is free software, licensed under the Apache License, Version 2.0
3
4 local fs        = require("nixio.fs")
5 local uci       = require("luci.model.uci").cursor()
6 local util      = require("luci.util")
7 local date      = require("luci.http.protocol.date")
8 local res_input = "/usr/share/dnscrypt-proxy/dnscrypt-resolvers.csv"
9 local res_dir   = fs.dirname(res_input)
10 local dump      = util.ubus("network.interface", "dump", {})
11 local plug_cnt  = tonumber(luci.sys.exec("env -i /usr/sbin/dnscrypt-proxy --version | grep 'Support for plugins: present' | wc -l"))
12 local res_list  = {}
13 local url       = "https://raw.githubusercontent.com/dyne/dnscrypt-proxy/master/dnscrypt-resolvers.csv"
14
15 if not fs.access(res_input) then
16         if not fs.access("/lib/libustream-ssl.so") then
17                 m = SimpleForm("error", nil, translate("No default resolver list and no SSL support available.<br />")
18                         .. translate("Please install a resolver list to '/usr/share/dnscrypt-proxy/dnscrypt-resolvers.csv' to use this package."))
19                 m.submit = false
20                 m.reset = false
21                 return m
22         else
23                 luci.sys.call("env -i /bin/uclient-fetch --no-check-certificate -O " .. res_input .. " " .. url .. " >/dev/null 2>&1")
24         end
25 end
26
27 if not uci:get_first("dnscrypt-proxy", "global") then
28         uci:add("dnscrypt-proxy", "global")
29         uci:save("dnscrypt-proxy")
30         uci:commit("dnscrypt-proxy")
31 end
32
33 if fs.access(res_input) then
34         for line in io.lines(res_input) or {} do
35                 local name,
36                 location,
37                 dnssec,
38                 nolog = line:match("^([^,]+),.-,\".-\",\"*(.-)\"*,.-,[0-9],\"*([yesno]+)\"*,\"*([yesno]+)\"*,.*")
39                 if name ~= "" and name ~= "Name" then
40                         if location == "" then
41                                 location = "-"
42                         end
43                         if dnssec == "" then
44                                 dnssec = "-"
45                         end
46                         if nolog == "" then
47                                 nolog = "-"
48                         end
49                         res_list[#res_list + 1] = { name = name, location = location, dnssec = dnssec, nolog = nolog }
50                 end
51         end
52 end
53
54 m = Map("dnscrypt-proxy", translate("DNSCrypt-Proxy"),
55         translate("Configuration of the DNSCrypt-Proxy package. ")
56         .. translatef("For further information "
57         .. "<a href=\"%s\" target=\"_blank\">"
58         .. "see the wiki online</a>", "https://wiki.openwrt.org/inbox/dnscrypt"))
59 m:chain("dhcp")
60
61 function m.on_after_commit(self)
62         function d1.validate(self, value, s1)
63                 if value == "1" then
64                         uci:commit("dnscrypt-proxy")
65                         uci:set("dhcp", s1, "noresolv", 1)
66                         if not fs.access("/etc/resolv-crypt.conf") or fs.stat("/etc/resolv-crypt.conf").size == 0 then
67                                 uci:set("dhcp", s1, "resolvfile", "/tmp/resolv.conf.auto")
68                         else
69                                 uci:set("dhcp", s1, "resolvfile", "/etc/resolv-crypt.conf")
70                         end
71                         local server_list = {}
72                         local cnt = 1
73                         uci:foreach("dnscrypt-proxy", "dnscrypt-proxy", function(s)
74                                 server_list[cnt] = s['address'] .. "#" .. s['port']
75                                 cnt = cnt + 1
76                         end)
77                         server_list[cnt] = "/pool.ntp.org/8.8.8.8"
78                         uci:set_list("dhcp", s1, "server", server_list)
79                         if cnt > 2 then
80                                 uci:set("dhcp", s1, "allservers", 1)
81                         else
82                                 uci:set("dhcp", s1, "allservers", 0)
83                         end
84                         uci:save("dhcp")
85                         uci:commit("dhcp")
86                 end
87                 return value
88         end
89         luci.sys.call("env -i /etc/init.d/dnscrypt-proxy restart >/dev/null 2>&1")
90         luci.sys.call("env -i /etc/init.d/dnsmasq restart >/dev/null 2>&1")
91 end
92
93 s = m:section(TypedSection, "global", translate("General Options"))
94 s.anonymous = true
95
96 -- Main dnscrypt-proxy resource list
97
98 o1 = s:option(DummyValue, "", translate("Default Resolver List"))
99 o1.template = "dnscrypt-proxy/res_options"
100 o1.value = res_input
101
102 o2 = s:option(DummyValue, "", translate("File Date"))
103 o2.template = "dnscrypt-proxy/res_options"
104 if fs.access(res_input) then
105         o2.value = date.to_http(fs.stat(res_input).mtime)
106 else
107         o2.value = "-"
108 end
109
110 o3 = s:option(DummyValue, "", translate("File Checksum"))
111 o3.template = "dnscrypt-proxy/res_options"
112 if fs.access(res_input) then
113         o3.value = luci.sys.exec("sha256sum " .. res_input .. " | awk '{print $1}'")
114 else
115         o3.value = "-"
116 end
117
118 if fs.access("/lib/libustream-ssl.so") then
119         btn1 = s:option(Button, "", translate("Refresh Resolver List"),
120                 translate("Download the current resolver list from 'github.com/dyne/dnscrypt-proxy'."))
121         btn1.inputtitle = translate("Refresh List")
122         btn1.inputstyle = "apply"
123         btn1.disabled = false
124         function btn1.write()
125                 if not fs.access(res_dir) then
126                         fs.mkdir(res_dir)
127                 end
128                 luci.sys.call("env -i /bin/uclient-fetch --no-check-certificate -O " .. res_input .. " " .. url .. " >/dev/null 2>&1")
129                 luci.http.redirect(luci.dispatcher.build_url("admin", "services", "dnscrypt-proxy"))
130         end
131 else
132         btn1 = s:option(Button, "", translate("Refresh Resolver List"),
133                 translate("No SSL support available.<br />")
134                 .. translate("Please install a 'libustream-ssl' library to download the current resolver list from 'github.com/dyne/dnscrypt-proxy'."))
135         btn1.inputtitle = translate("-------")
136         btn1.inputstyle = "button"
137         btn1.disabled = true
138 end
139
140 if not fs.access("/etc/resolv-crypt.conf") or fs.stat("/etc/resolv-crypt.conf").size == 0 then
141         btn2 = s:option(Button, "", translate("Create Custom Config File"),
142                 translate("Create '/etc/resolv-crypt.conf' with 'options timeout:1' to reduce DNS upstream timeouts with multiple DNSCrypt instances.<br />")
143                 .. translatef("For further information "
144                 .. "<a href=\"%s\" target=\"_blank\">"
145                 .. "see the wiki online</a>", "https://wiki.openwrt.org/inbox/dnscrypt"))
146         btn2.inputtitle = translate("Create Config File")
147         btn2.inputstyle = "apply"
148         btn2.disabled = false
149         function btn2.write()
150                 luci.sys.call("env -i echo 'options timeout:1' > '/etc/resolv-crypt.conf'")
151                 luci.http.redirect(luci.dispatcher.build_url("admin", "services", "dnscrypt-proxy"))
152         end
153 else
154         btn2 = s:option(Button, "", translate("Create Custom Config File"),
155                 translate("The config file '/etc/resolv-crypt.conf' already exist.<br />")
156                 .. translate("Please edit the file manually in the 'Advanced' section."))
157         btn2.inputtitle = translate("-------")
158         btn2.inputstyle = "button"
159         btn2.disabled = true
160 end
161
162 -- Trigger settings
163
164 t = s:option(ListValue, "procd_trigger", translate("Startup Trigger"),
165         translate("By default the DNSCrypt-Proxy startup will be triggered by ifup events of 'All' available network interfaces.<br />")
166         .. translate("To restrict the trigger, select only the relevant network interface. Usually the 'wan' interface should work for most users."))
167 t:value("", "All")
168 if dump then
169         local i, v
170         for i, v in ipairs(dump.interface) do
171                 if v.interface ~= "loopback" then
172                         t:value(v.interface)
173                 end
174         end
175 end
176 t.default = procd_trigger or "All"
177 t.rmempty = true
178
179 -- Mandatory options per instance
180
181 s = m:section(TypedSection, "dnscrypt-proxy", translate("Instance Options"))
182 s.anonymous = true
183 s.addremove = true
184
185 i1 = s:option(Value, "address", translate("IP Address"),
186         translate("The local IPv4 or IPv6 address. The latter one should be specified within brackets, e.g. '[::1]'."))
187 i1.default = address or "127.0.0.1"
188 i1.rmempty = false
189
190 i2 = s:option(Value, "port", translate("Port"),
191         translate("The listening port for DNS queries."))
192 i2.datatype = "port"
193 i2.default = port
194 i2.rmempty = false
195
196 i3 = s:option(ListValue, "resolver", translate("Resolver (LOC/SEC/NOLOG)"),
197         translate("Name of the remote DNS service for resolving queries incl. Location, DNSSEC- and NOLOG-Flag."))
198 i3.datatype = "hostname"
199 i3.widget = "select"
200 local i, v
201 for i, v in ipairs(res_list) do
202         if v.name then
203                 i3:value(v.name, v.name .. " (" .. v.location .. "/" .. v.dnssec .. "/" .. v.nolog .. ")")
204         end
205 end
206 i3.default = resolver
207 i3.rmempty = false
208
209 -- Extra options per instance
210
211 e1 = s:option(Value, "resolvers_list", translate("Alternate Resolver List"),
212         translate("Specify a non-default Resolver List."))
213 e1.datatype = "file"
214 e1.optional = true
215
216 e2 = s:option(Value, "ephemeral_keys", translate("Ephemeral Keys"),
217         translate("Improve privacy by using an ephemeral public key for each query. ")
218         .. translate("This option requires extra CPU cycles and is useless with most DNSCrypt server."))
219 e2.datatype = "bool"
220 e2.value = 1
221 e2.optional = true
222
223 if plug_cnt > 0 then
224         e3 = s:option(DynamicList, "blacklist", translate("Blacklist"),
225                 translate("Local blacklists allow you to block abuse sites by domains or ip addresses. ")
226                 .. 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'."))
227         e3.optional = true
228
229         e4 = s:option(Value, "block_ipv6", translate("Block IPv6"),
230                 translate("Disable IPv6 to speed up DNSCrypt-Proxy."))
231         e4.datatype = "bool"
232         e4.value = 1
233         e4.optional = true
234
235         e5 = s:option(Value, "local_cache", translate("Local Cache"),
236                 translate("Enable Caching to speed up DNSCcrypt-Proxy."))
237         e5.datatype = "bool"
238         e5.value = 1
239         e5.optional = true
240         
241         e6 = s:option(Value, "query_log_file", translate("DNS Query Logfile"),
242         translate("Log the received DNS queries to a file, so you can watch in real-time what is happening on the network."))
243         e6.optional = true
244 end
245
246 -- Dnsmasq options
247
248 m1 = Map("dhcp")
249
250 s1 = m1:section(TypedSection, "dnsmasq", translate("Dnsmasq Options"))
251 s1.anonymous = true
252
253 d1 = s1:option(Flag, "", translate("Transfer Options To Dnsmasq"),
254         translate("Apply DNSCrypt-Proxy specific settings to the Dnsmasq configuration.<br />")
255         .. translate("Please note: This may change the values for 'noresolv', 'resolvfile', 'allservers' and the list 'server' settings."))
256 d1.default = d1.enabled
257 d1.rmempty = false
258
259 return m, m1