999c81dee782c1ebf066585998d063c07b8b8257
[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