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