luci-theme-material: fix theme for applyreboot page changes
[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, ath
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 prt = s1:taboption("basic", Value, "listen_port", translate("Listening Port:"),
104 translate("Choose Unbounds listening port"))
105 prt.datatype = "port"
106 prt.rmempty = false
107
108 --Avanced Tab
109 din = s1:taboption("advanced", DynamicList, "domain_insecure",
110 translate("Domain Insecure:"),
111 translate("List domains to bypass checks of DNSSEC"))
112 din:depends({ validator = true })
113
114 dfw = s1:taboption("advanced", DynamicList, "domain_forward",
115 translate("Domain Forward:"),
116 translate("List domains to simply forward to stub resolvers in /tmp/resolve.auto"))
117
118 rlh = s1:taboption("advanced", Flag, "rebind_localhost", translate("Filter Localhost Rebind:"),
119 translate("Protect against upstream response of 127.0.0.0/8"))
120 rlh.rmempty = false
121
122 rpv = s1:taboption("advanced", ListValue, "rebind_protection", translate("Filter Private Rebind:"),
123 translate("Protect against upstream responses within local subnets"))
124 rpv:value("0", translate("No Filter"))
125 rpv:value("1", translate("Filter RFC1918/4193"))
126 rpv:value("2", translate("Filter Entire Subnet"))
127 rpv.rmempty = false
128
129 rpn = s1:taboption("advanced", Value, "rebind_interface", translate("Rebind Network Filter:"),
130 translate("Network subnets to filter from upstream responses"))
131 rpn.template = "cbi/network_netlist"
132 rpn.widget = "checkbox"
133 rpn.rmempty = true
134 rpn.cast = "string"
135 rpn.nocreate = true
136 rpn:depends({ rebind_protection = 2 })
137 rpn:depends({ rebind_protection = 3 })
138
139 --DHCP Tab
140 dlk = s1:taboption("DHCP", ListValue, "dhcp_link", translate("DHCP Link:"),
141 translate("Link to supported programs to load DHCP into DNS"))
142 dlk:value("none", translate("No Link"))
143 dlk:value("dnsmasq", "dnsmasq")
144 dlk:value("odhcpd", "odhcpd")
145 dlk.rmempty = false
146
147 dp6 = s1:taboption("DHCP", Flag, "dhcp4_slaac6", translate("DHCPv4 to SLAAC:"),
148 translate("Use DHCPv4 MAC to discover IP6 hosts SLAAC (EUI64)"))
149 dp6.rmempty = false
150 dp6:depends({ dhcp_link = "odhcpd" })
151
152 dom = s1:taboption("DHCP", Value, "domain", translate("Local Domain:"),
153 translate("Domain suffix for this router and DHCP clients"))
154 dom.placeholder = "lan"
155 dom:depends({ dhcp_link = "none" })
156 dom:depends({ dhcp_link = "odhcpd" })
157
158 dty = s1:taboption("DHCP", ListValue, "domain_type", translate("Local Domain Type:"),
159 translate("How to treat queries of this local domain"))
160 dty:value("deny", translate("Ignored"))
161 dty:value("refuse", translate("Refused"))
162 dty:value("static", translate("Only Local"))
163 dty:value("transparent", translate("Also Forwarded"))
164 dty:depends({ dhcp_link = "none" })
165 dty:depends({ dhcp_link = "odhcpd" })
166
167 lfq = s1:taboption("DHCP", ListValue, "add_local_fqdn", translate("LAN DNS:"),
168 translate("How to enter the LAN or local network router in DNS"))
169 lfq:value("0", translate("No Entry"))
170 lfq:value("1", translate("Hostname, Primary Address"))
171 lfq:value("2", translate("Hostname, All Addresses"))
172 lfq:value("3", translate("Host FQDN, All Addresses"))
173 lfq:value("4", translate("Interface FQDN, All Addresses"))
174 lfq:depends({ dhcp_link = "none" })
175 lfq:depends({ dhcp_link = "odhcpd" })
176
177 wfq = s1:taboption("DHCP", ListValue, "add_wan_fqdn", translate("WAN DNS:"),
178 translate("Override the WAN side router entry in DNS"))
179 wfq:value("0", translate("Use Upstream"))
180 wfq:value("1", translate("Hostname, Primary Address"))
181 wfq:value("2", translate("Hostname, All Addresses"))
182 wfq:value("3", translate("Host FQDN, All Addresses"))
183 wfq:value("4", translate("Interface FQDN, All Addresses"))
184 wfq:depends({ dhcp_link = "none" })
185 wfq:depends({ dhcp_link = "odhcpd" })
186
187 exa = s1:taboption("DHCP", ListValue, "add_extra_dns", translate("Extra DNS:"),
188 translate("Use extra DNS entries found in /etc/config/dhcp"))
189 exa:value("0", translate("Ignore"))
190 exa:value("1", translate("Include Network/Hostnames"))
191 exa:value("2", translate("Advanced MX/SRV RR"))
192 exa:value("3", translate("Advanced CNAME RR"))
193 exa:depends({ dhcp_link = "none" })
194 exa:depends({ dhcp_link = "odhcpd" })
195
196 --TODO: dnsmasq needs to not reference resolve-file and get off port 53.
197
198 --Resource Tuning Tab
199 ctl = s1:taboption("resource", ListValue, "unbound_control", translate("Unbound Control App:"),
200 translate("Enable access for unbound-control"))
201 ctl.rmempty = false
202 ctl:value("0", translate("No Remote Control"))
203 ctl:value("1", translate("Local Host, No Encryption"))
204 ctl:value("2", translate("Local Host, Encrypted"))
205 ctl:value("3", translate("Local Subnet, Encrypted"))
206 ctl:value("4", translate("Local Subnet, Static Encryption"))
207
208 pro = s1:taboption("resource", ListValue, "protocol", translate("Recursion Protocol:"),
209 translate("Chose the protocol recursion queries leave on"))
210 pro:value("default", translate("Default"))
211 pro:value("ip4_only", translate("IP4 Only"))
212 pro:value("ip6_only", translate("IP6 Only"))
213 pro:value("ip6_prefer", translate("IP6 Preferred"))
214 pro:value("mixed", translate("IP4 and IP6"))
215 pro.rmempty = false
216
217 rsc = s1:taboption("resource", ListValue, "resource", translate("Memory Resource:"),
218 translate("Use menu System/Processes to observe any memory growth"))
219 rsc:value("default", translate("Default"))
220 rsc:value("tiny", translate("Tiny"))
221 rsc:value("small", translate("Small"))
222 rsc:value("medium", translate("Medium"))
223 rsc:value("large", translate("Large"))
224 rsc.rmempty = false
225
226 rsn = s1:taboption("resource", ListValue, "recursion", translate("Recursion Strength:"),
227 translate("Recursion activity affects memory growth and CPU load"))
228 rsn:value("default", translate("Default"))
229 rsn:value("passive", translate("Passive"))
230 rsn:value("aggressive", translate("Aggressive"))
231 rsn.rmempty = false
232
233 qry = s1:taboption("resource", Flag, "query_minimize", 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", translate("Strict Minimize:"),
240 translate("Strict version of 'query minimize' but it can break DNS"))
241 qrs.rmempty = false
242 qrs:depends({ query_minimize = true })
243
244 ath = s1:taboption("resource", Flag, "prefetch_root", translate("Prefetch Root:"),
245 translate("Obtain complete root zone files and install in auth-zone: clause"))
246 ath.rmempty = false
247
248 eds = s1:taboption("resource", Value, "edns_size", translate("EDNS Size:"),
249 translate("Limit extended DNS packet size"))
250 eds.datatype = "and(uinteger,min(512),max(4096))"
251 eds.rmempty = false
252
253 tlm = s1:taboption("resource", Value, "ttl_min", translate("TTL Minimum:"),
254 translate("Prevent excessively short cache periods"))
255 tlm.datatype = "and(uinteger,min(0),max(600))"
256 tlm.rmempty = false
257
258 stt = s1:taboption("resource", Flag, "extended_stats", translate("Extended Statistics:"),
259 translate("Extended statistics are printed from unbound-control"))
260 stt.rmempty = false
261 end
262
263
264 --Trigger Tab, always unconditional
265 ag2 = s1:taboption("trigger", Value, "root_age", translate("Root DSKEY Age:"),
266 translate("Limit days between RFC5011 copies to reduce flash writes"))
267 ag2.datatype = "and(uinteger,min(1),max(99))"
268 ag2:value("3", "3")
269 ag2:value("9", "9 ("..translate("default")..")")
270 ag2:value("12", "12")
271 ag2:value("24", "24")
272 ag2:value("99", "99 ("..translate("never")..")")
273
274 tgr = s1:taboption("trigger", Value, "trigger_interface", 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
282
283 function ena.cfgvalue(self, section)
284 return luci.sys.init.enabled("unbound") and self.enabled or self.disabled
285 end
286
287
288 function ena.write(self, section, value)
289 if value == "1" then
290 luci.sys.init.enable("unbound")
291 luci.sys.call("/etc/init.d/unbound start >/dev/null")
292 else
293 luci.sys.call("/etc/init.d/unbound stop >/dev/null")
294 luci.sys.init.disable("unbound")
295 end
296
297 return Flag.write(self, section, value)
298 end
299
300
301 function m1.on_apply(self)
302 function ena.validate(self, value)
303 if value ~= "0" then
304 luci.sys.call("/etc/init.d/unbound restart >/dev/null 2>&1")
305 else
306 luci.sys.call("/etc/init.d/unbound stop >/dev/null 2>&1")
307 end
308 end
309
310
311 -- Restart Unbound with configuration and reload the page (some options hide)
312 luci.http.redirect(luci.dispatcher.build_url("admin", "services", "unbound"))
313 end
314
315
316 return m1
317