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