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