Merge pull request #2001 from Rixerx/master
[oweals/luci.git] / applications / luci-app-unbound / luasrc / model / cbi / unbound / configure.lua
1 -- Copyright 2008 Steven Barth <steven@midlink.org>
2 -- Copyright 2016 Eric Luehrsen <ericluehrsen@gmail.com>
3 -- Copyright 2016 Dan Luedtke <mail@danrl.com>
4 -- Licensed to the public under the Apache License 2.0.
5
6 local m1, s1
7 local ena, mcf, lci, lsv
8 local rlh, rpv, vld, nvd, eds, prt, tlm
9 local ctl, dlk, dom, dty, lfq, wfq, exa
10 local dp6, d64, pfx, qry, qrs
11 local pro, tgr, rsc, rsn, ag2, stt
12 local rpn, din, ath
13
14 local ut = require "luci.util"
15 local sy = require "luci.sys"
16 local ht = require "luci.http"
17 local ds = require "luci.dispatcher"
18 local ucl = luci.model.uci.cursor()
19 local valman = ucl:get_first("unbound", "unbound", "manual_conf")
20
21 m1 = Map("unbound")
22 s1 = m1:section(TypedSection, "unbound", translate("DNS Resolver"),
23     translatef("Unbound <a href=\"%s\" target=\"_blank\">(NLnet Labs)</a>"
24     .. " is a validating, recursive, and caching DNS resolver.",
25     "https://www.unbound.net/"))
26
27 s1.addremove = false
28 s1.anonymous = true
29
30 --LuCI, Unbound, or Not
31 s1:tab("basic", translate("Basic"))
32
33
34 if (valman == "0") then
35     -- Not in manual configuration mode; show UCI
36     s1:tab("advanced", translate("Advanced"))
37     s1:tab("DHCP", translate("DHCP"))
38     s1:tab("resource", translate("Resource"))
39 end
40
41
42 --Basic Tab, unconditional pieces
43 ena = s1:taboption("basic", Flag, "enabled", translate("Enable Unbound:"),
44     translate("Enable the initialization scripts for Unbound"))
45 ena.rmempty = false
46
47 mcf = s1:taboption("basic", Flag, "manual_conf", translate("Manual Conf:"),
48     translate("Skip UCI and use /etc/unbound/unbound.conf"))
49 mcf.rmempty = false
50
51
52 if (valman == "0") then
53     -- Not in manual configuration mode; show UCI
54     --Basic Tab
55     lsv = s1:taboption("basic", Flag, "localservice",
56         translate("Local Service:"),
57         translate("Accept queries only from local subnets"))
58     lsv.rmempty = false
59
60     vld = s1:taboption("basic", Flag, "validator",
61         translate("Enable DNSSEC:"),
62         translate("Enable the DNSSEC validator module"))
63     vld.rmempty = false
64
65     nvd = s1:taboption("basic", Flag, "validator_ntp",
66         translate("DNSSEC NTP Fix:"),
67         translate("Break the loop where DNSSEC needs NTP and NTP needs DNS"))
68     nvd.rmempty = false
69     nvd:depends({ validator = true })
70
71     prt = s1:taboption("basic", Value, "listen_port",
72         translate("Listening Port:"),
73         translate("Choose Unbounds listening port"))
74     prt.datatype = "port"
75     prt.rmempty = false
76
77     --Avanced Tab
78     rlh = s1:taboption("advanced", Flag, "rebind_localhost",
79         translate("Filter Localhost Rebind:"),
80         translate("Protect against upstream response of 127.0.0.0/8"))
81     rlh.rmempty = false
82
83     rpv = s1:taboption("advanced", ListValue, "rebind_protection",
84         translate("Filter Private Rebind:"),
85         translate("Protect against upstream responses within local subnets"))
86     rpv:value("0", translate("No Filter"))
87     rpv:value("1", translate("Filter RFC1918/4193"))
88     rpv:value("2", translate("Filter Entire Subnet"))
89     rpv.rmempty = false
90
91     d64 = s1:taboption("advanced", Flag, "dns64", translate("Enable DNS64:"),
92         translate("Enable the DNS64 module"))
93     d64.rmempty = false
94
95     pfx = s1:taboption("advanced", Value, "dns64_prefix",
96         translate("DNS64 Prefix:"),
97         translate("Prefix for generated DNS64 addresses"))
98     pfx.datatype = "ip6addr"
99     pfx.placeholder = "64:ff9b::/96"
100     pfx.optional = true
101     pfx:depends({ dns64 = true })
102
103     din = s1:taboption("advanced", DynamicList, "domain_insecure",
104         translate("Domain Insecure:"),
105         translate("List domains to bypass checks of DNSSEC"))
106     din:depends({ validator = true })
107
108     ag2 = s1:taboption("advanced", Value, "root_age",
109         translate("Root DSKEY Age:"),
110         translate("Limit days between RFC5011 copies to reduce flash writes"))
111     ag2.datatype = "and(uinteger,min(1),max(99))"
112     ag2:value("3", "3")
113     ag2:value("9", "9 ("..translate("default")..")")
114     ag2:value("12", "12")
115     ag2:value("24", "24")
116     ag2:value("99", "99 ("..translate("never")..")")
117
118     tgr = s1:taboption("advanced", Value, "trigger_interface",
119         translate("Trigger Networks:"),
120         translate("Networks that may trigger Unbound to reload (avoid wan6)"))
121     tgr.template = "cbi/network_netlist"
122     tgr.widget = "checkbox"
123     tgr.rmempty = true
124     tgr.cast = "string"
125     tgr.nocreate = true
126
127     --DHCP Tab
128     dlk = s1:taboption("DHCP", ListValue, "dhcp_link",
129         translate("DHCP Link:"),
130         translate("Link to supported programs to load DHCP into DNS"))
131     dlk:value("none", translate("No Link"))
132     dlk:value("dnsmasq", "dnsmasq")
133     dlk:value("odhcpd", "odhcpd")
134     dlk.rmempty = false
135
136     dp6 = s1:taboption("DHCP", Flag, "dhcp4_slaac6",
137         translate("DHCPv4 to SLAAC:"),
138         translate("Use DHCPv4 MAC to discover IP6 hosts SLAAC (EUI64)"))
139     dp6.rmempty = false
140     dp6:depends({ dhcp_link = "odhcpd" })
141
142     dom = s1:taboption("DHCP", Value, "domain",
143         translate("Local Domain:"),
144         translate("Domain suffix for this router and DHCP clients"))
145     dom.placeholder = "lan"
146     dom:depends({ dhcp_link = "none" })
147     dom:depends({ dhcp_link = "odhcpd" })
148
149     dty = s1:taboption("DHCP", ListValue, "domain_type",
150         translate("Local Domain Type:"),
151         translate("How to treat queries of this local domain"))
152     dty:value("deny", translate("Denied (nxdomain)"))
153     dty:value("refuse", translate("Refused"))
154     dty:value("static", translate("Static (local only)"))
155     dty:value("transparent", translate("Transparent (local/global)"))
156     dty:depends({ dhcp_link = "none" })
157     dty:depends({ dhcp_link = "odhcpd" })
158
159     lfq = s1:taboption("DHCP", ListValue, "add_local_fqdn",
160         translate("LAN DNS:"),
161         translate("How to enter the LAN or local network router in DNS"))
162     lfq:value("0", translate("No Entry"))
163     lfq:value("1", translate("Hostname, Primary Address"))
164     lfq:value("2", translate("Hostname, All Addresses"))
165     lfq:value("3", translate("Host FQDN, All Addresses"))
166     lfq:value("4", translate("Interface FQDN, All Addresses"))
167     lfq:depends({ dhcp_link = "none" })
168     lfq:depends({ dhcp_link = "odhcpd" })
169
170     wfq = s1:taboption("DHCP", ListValue, "add_wan_fqdn",
171         translate("WAN DNS:"),
172         translate("Override the WAN side router entry in DNS"))
173     wfq:value("0", translate("Use Upstream"))
174     wfq:value("1", translate("Hostname, Primary Address"))
175     wfq:value("2", translate("Hostname, All Addresses"))
176     wfq:value("3", translate("Host FQDN, All Addresses"))
177     wfq:value("4", translate("Interface FQDN, All Addresses"))
178     wfq:depends({ dhcp_link = "none" })
179     wfq:depends({ dhcp_link = "odhcpd" })
180
181     exa = s1:taboption("DHCP", ListValue, "add_extra_dns",
182         translate("Extra DNS:"),
183         translate("Use extra DNS entries found in /etc/config/dhcp"))
184     exa:value("0", translate("Ignore"))
185     exa:value("1", translate("Host Records"))
186     exa:value("2", translate("Host/MX/SRV RR"))
187     exa:value("3", translate("Host/MX/SRV/CNAME RR"))
188     exa:depends({ dhcp_link = "none" })
189     exa:depends({ dhcp_link = "odhcpd" })
190
191     --TODO: dnsmasq needs to not reference resolve-file and get off port 53.
192
193     --Resource Tuning Tab
194     ctl = s1:taboption("resource", ListValue, "unbound_control",
195         translate("Unbound Control App:"),
196         translate("Enable access for unbound-control"))
197     ctl.rmempty = false
198     ctl:value("0", translate("No Remote Control"))
199     ctl:value("1", translate("Local Host, No Encryption"))
200     ctl:value("2", translate("Local Host, Encrypted"))
201     ctl:value("3", translate("Local Subnet, Encrypted"))
202     ctl:value("4", translate("Local Subnet, Static Encryption"))
203
204     pro = s1:taboption("resource", ListValue, "protocol",
205         translate("Recursion Protocol:"),
206         translate("Chose the protocol recursion queries leave on"))
207     pro:value("default", translate("Default"))
208     pro:value("ip4_only", translate("IP4 Only"))
209     pro:value("ip6_only", translate("IP6 Only"))
210     pro:value("ip6_prefer", translate("IP6 Preferred"))
211     pro:value("mixed", translate("IP4 and IP6"))
212     pro.rmempty = false
213
214     rsc = s1:taboption("resource", ListValue, "resource",
215         translate("Memory Resource:"),
216         translate("Use menu System/Processes to observe any memory growth"))
217     rsc:value("default", translate("Default"))
218     rsc:value("tiny", translate("Tiny"))
219     rsc:value("small", translate("Small"))
220     rsc:value("medium", translate("Medium"))
221     rsc:value("large", translate("Large"))
222     rsc.rmempty = false
223
224     rsn = s1:taboption("resource", ListValue, "recursion",
225         translate("Recursion Strength:"),
226         translate("Recursion activity affects memory growth and CPU load"))
227     rsn:value("default", translate("Default"))
228     rsn:value("passive", translate("Passive"))
229     rsn:value("aggressive", translate("Aggressive"))
230     rsn.rmempty = false
231
232     qry = s1:taboption("resource", Flag, "query_minimize",
233         translate("Query Minimize:"),
234         translate("Break down query components for limited added privacy"))
235     qry.rmempty = false
236     qry:depends({ recursion = "passive" })
237     qry:depends({ recursion = "aggressive" })
238
239     qrs = s1:taboption("resource", Flag, "query_min_strict",
240         translate("Strict Minimize:"),
241         translate("Strict version of 'query minimize' but it can break DNS"))
242     qrs.rmempty = false
243     qrs:depends({ query_minimize = true })
244
245     eds = s1:taboption("resource", Value, "edns_size",
246         translate("EDNS Size:"),
247         translate("Limit extended DNS packet size"))
248     eds.datatype = "and(uinteger,min(512),max(4096))"
249     eds.rmempty = false
250
251     tlm = s1:taboption("resource", Value, "ttl_min",
252         translate("TTL Minimum:"),
253         translate("Prevent excessively short cache periods"))
254     tlm.datatype = "and(uinteger,min(0),max(600))"
255     tlm.rmempty = false
256
257     stt = s1:taboption("resource", Flag, "extended_stats",
258         translate("Extended Statistics:"),
259         translate("Extended statistics are printed from unbound-control"))
260     stt.rmempty = false
261
262 else
263     ag2 = s1:taboption("basic", Value, "root_age",
264         translate("Root DSKEY Age:"),
265         translate("Limit days between RFC5011 copies to reduce flash writes"))
266     ag2.datatype = "and(uinteger,min(1),max(99))"
267     ag2:value("3", "3")
268     ag2:value("9", "9 ("..translate("default")..")")
269     ag2:value("12", "12")
270     ag2:value("24", "24")
271     ag2:value("99", "99 ("..translate("never")..")")
272
273     tgr = s1:taboption("basic", Value, "trigger_interface",
274         translate("Trigger Networks:"),
275         translate("Networks that may trigger Unbound to reload (avoid wan6)"))
276     tgr.template = "cbi/network_netlist"
277     tgr.widget = "checkbox"
278     tgr.rmempty = true
279     tgr.cast = "string"
280     tgr.nocreate = true
281 end
282
283
284 function ena.cfgvalue(self, section)
285     return sy.init.enabled("unbound") and self.enabled or self.disabled
286 end
287
288
289 function ena.write(self, section, value)
290     if (value == "1") then
291         sy.init.enable("unbound")
292         sy.call("/etc/init.d/unbound start >/dev/null 2>&1")
293
294     else
295         sy.call("/etc/init.d/unbound stop >/dev/null 2>&1")
296         sy.init.disable("unbound")
297     end
298
299
300     return Flag.write(self, section, value)
301 end
302
303
304 function m1.on_commit(self)
305     if sy.init.enabled("unbound") then
306         -- Restart Unbound with configuration
307         sy.call("/etc/init.d/unbound restart >/dev/null 2>&1")
308
309     else
310         sy.call("/etc/init.d/unbound stop >/dev/null 2>&1")
311     end
312 end
313
314
315 function m1.on_apply(self)
316     -- reload the page because some options hide
317     ht.redirect(ds.build_url("admin", "services", "unbound", "configure"))
318 end
319
320
321 return m1
322