8f0e3224b49be626d4a438154533e167cc3ce12c
[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