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.
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, rsc, rsn, ag2, stt
15 local ut = require "luci.util"
16 local sy = require "luci.sys"
17 local ht = require "luci.http"
18 local ds = require "luci.dispatcher"
19 local ucl = luci.model.uci.cursor()
20 local valman = ucl:get_first("unbound", "unbound", "manual_conf")
21 local dhcplk = ucl:get_first("unbound", "unbound", "dhcp_link")
22 local lstrig = ucl:get_first("dhcp", "odhcpd", "leasetrigger") or "undefined"
25 s1 = m1:section(TypedSection, "unbound", translate("Recursive DNS"),
26 translatef("Unbound <a href=\"%s\" target=\"_blank\">(NLnet Labs)</a>"
27 .. " is a validating, recursive, and caching DNS resolver"
28 .. " <a href=\"%s\" target=\"_blank\">(help)</a>.",
29 "https://www.unbound.net/",
30 "https://github.com/openwrt/packages/blob/master/net/unbound/files/README.md"))
35 if (valman == "0") and (dhcplk == "odhcpd") and (lstrig ~= "/usr/lib/unbound/odhcpd.sh") then
36 m1.message = translatef( "Note: local DNS is configured to look at odhpcd, "
37 .. "but odhpcd UCI lease trigger is incorrectly set: ")
38 .. "dhcp.odhcpd.leasetrigger='" .. lstrig .. "'"
41 --LuCI, Unbound, or Not
42 s1:tab("basic", translate("Basic"))
45 if (valman == "0") then
46 -- Not in manual configuration mode; show UCI
47 s1:tab("advanced", translate("Advanced"))
48 s1:tab("DHCP", translate("DHCP"))
49 s1:tab("resource", translate("Resource"))
53 --Basic Tab, unconditional pieces
54 ena = s1:taboption("basic", Flag, "enabled", translate("Enable Unbound"),
55 translate("Enable the initialization scripts for Unbound"))
58 mcf = s1:taboption("basic", Flag, "manual_conf", translate("Manual Conf"),
59 translate("Skip UCI and use /etc/unbound/unbound.conf"))
63 if (valman == "0") then
64 -- Not in manual configuration mode; show UCI
66 lsv = s1:taboption("basic", Flag, "localservice",
67 translate("Local Service"),
68 translate("Accept queries only from local subnets"))
71 vld = s1:taboption("basic", Flag, "validator",
72 translate("Enable DNSSEC"),
73 translate("Enable the DNSSEC validator module"))
76 nvd = s1:taboption("basic", Flag, "validator_ntp",
77 translate("DNSSEC NTP Fix"),
78 translate("Break the loop where DNSSEC needs NTP and NTP needs DNS"))
81 nvd:depends("validator", true)
83 prt = s1:taboption("basic", Value, "listen_port",
84 translate("Listening Port"),
85 translate("Choose Unbounds listening port"))
87 prt.placeholder = "53"
90 rlh = s1:taboption("advanced", Flag, "rebind_localhost",
91 translate("Filter Localhost Rebind"),
92 translate("Protect against upstream response of 127.0.0.0/8"))
95 rpv = s1:taboption("advanced", ListValue, "rebind_protection",
96 translate("Filter Private Rebind"),
97 translate("Protect against upstream responses within local subnets"))
98 rpv:value("0", translate("No Filter"))
99 rpv:value("1", translate("Filter Private Address"))
100 rpv:value("2", translate("Filter Entire Subnet"))
103 d64 = s1:taboption("advanced", Flag, "dns64", translate("Enable DNS64"),
104 translate("Enable the DNS64 module"))
107 pfx = s1:taboption("advanced", Value, "dns64_prefix",
108 translate("DNS64 Prefix"),
109 translate("Prefix for generated DNS64 addresses"))
110 pfx.datatype = "ip6addr"
111 pfx.placeholder = "64:ff9b::/96"
113 pfx:depends("dns64", true)
115 din = s1:taboption("advanced", DynamicList, "domain_insecure",
116 translate("Domain Insecure"),
117 translate("List domains to bypass checks of DNSSEC"))
118 din:depends("validator", true)
120 ag2 = s1:taboption("advanced", Value, "root_age",
121 translate("Root DSKEY Age"),
122 translate("Limit days between RFC5011 copies to reduce flash writes"))
123 ag2.datatype = "and(uinteger,min(1),max(99))"
125 ag2:value("9", "9 ("..translate("default")..")")
126 ag2:value("12", "12")
127 ag2:value("24", "24")
128 ag2:value("99", "99 ("..translate("never")..")")
130 ifc = s1:taboption("advanced", Value, "iface_lan",
131 translate("LAN Networks"),
132 translate("Networks to consider LAN (served) beyond those served by DHCP"))
133 ifc.template = "cbi/network_netlist"
134 ifc.widget = "checkbox"
139 wfc = s1:taboption("advanced", Value, "iface_wan",
140 translate("WAN Networks"),
141 translate("Networks to consider WAN (unserved)"))
142 wfc.template = "cbi/network_netlist"
143 wfc.widget = "checkbox"
148 tgr = s1:taboption("advanced", Value, "iface_trig",
149 translate("Trigger Networks"),
150 translate("Networks that may trigger Unbound to reload (avoid wan6)"))
151 tgr.template = "cbi/network_netlist"
152 tgr.widget = "checkbox"
158 dlk = s1:taboption("DHCP", ListValue, "dhcp_link",
159 translate("DHCP Link"),
160 translate("Link to supported programs to load DHCP into DNS"))
161 dlk:value("none", translate("(none)"))
162 dlk:value("dnsmasq", "dnsmasq")
163 dlk:value("odhcpd", "odhcpd")
166 dp6 = s1:taboption("DHCP", Flag, "dhcp4_slaac6",
167 translate("DHCPv4 to SLAAC"),
168 translate("Use DHCPv4 MAC to discover IP6 hosts SLAAC (EUI64)"))
170 dp6:depends("dhcp_link", "odhcpd")
172 dom = s1:taboption("DHCP", Value, "domain",
173 translate("Local Domain"),
174 translate("Domain suffix for this router and DHCP clients"))
175 dom.placeholder = "lan"
178 dty = s1:taboption("DHCP", ListValue, "domain_type",
179 translate("Local Domain Type"),
180 translate("How to treat queries of this local domain"))
182 dty:value("deny", translate("Denied (nxdomain)"))
183 dty:value("refuse", translate("Refused"))
184 dty:value("static", translate("Static (local only)"))
185 dty:value("transparent", translate("Transparent (local/global)"))
186 dty:depends("dhcp_link", "none")
187 dty:depends("dhcp_link", "odhcpd")
189 lfq = s1:taboption("DHCP", ListValue, "add_local_fqdn",
190 translate("LAN DNS"),
191 translate("How to enter the LAN or local network router in DNS"))
193 lfq:value("0", translate("No Entry"))
194 lfq:value("1", translate("Hostname, Primary Address"))
195 lfq:value("2", translate("Hostname, All Addresses"))
196 lfq:value("3", translate("Host FQDN, All Addresses"))
197 lfq:value("4", translate("Interface FQDN, All Addresses"))
198 lfq:depends("dhcp_link", "none")
199 lfq:depends("dhcp_link", "odhcpd")
201 wfq = s1:taboption("DHCP", ListValue, "add_wan_fqdn",
202 translate("WAN DNS"),
203 translate("Override the WAN side router entry in DNS"))
205 wfq:value("0", translate("Use Upstream"))
206 wfq:value("1", translate("Hostname, Primary Address"))
207 wfq:value("2", translate("Hostname, All Addresses"))
208 wfq:value("3", translate("Host FQDN, All Addresses"))
209 wfq:value("4", translate("Interface FQDN, All Addresses"))
210 wfq:depends("dhcp_link", "none")
211 wfq:depends("dhcp_link", "odhcpd")
213 exa = s1:taboption("DHCP", ListValue, "add_extra_dns",
214 translate("Extra DNS"),
215 translate("Use extra DNS entries found in /etc/config/dhcp"))
217 exa:value("0", translate("Ignore"))
218 exa:value("1", translate("Host Records"))
219 exa:value("2", translate("Host/MX/SRV RR"))
220 exa:value("3", translate("Host/MX/SRV/CNAME RR"))
221 exa:depends("dhcp_link", "none")
222 exa:depends("dhcp_link", "odhcpd")
224 --TODO: dnsmasq needs to not reference resolve-file and get off port 53.
226 --Resource Tuning Tab
227 ctl = s1:taboption("resource", ListValue, "unbound_control",
228 translate("Unbound Control App"),
229 translate("Enable access for unbound-control"))
231 ctl:value("0", translate("No Remote Control"))
232 ctl:value("1", translate("Local Host, No Encryption"))
233 ctl:value("2", translate("Local Host, Encrypted"))
234 ctl:value("3", translate("Local Subnet, Encrypted"))
235 ctl:value("4", translate("Local Subnet, Static Encryption"))
237 pro = s1:taboption("resource", ListValue, "protocol",
238 translate("Recursion Protocol"),
239 translate("Choose the IP versions used upstream and downstream"))
240 pro:value("default", translate("Default"))
241 pro:value("ip4_only", translate("IP4 Only"))
242 pro:value("ip6_local", translate("IP4 All and IP6 Local"))
243 pro:value("ip6_only", translate("IP6 Only*"))
244 pro:value("ip6_prefer", translate("IP6 Preferred"))
245 pro:value("mixed", translate("IP4 and IP6"))
248 rsc = s1:taboption("resource", ListValue, "resource",
249 translate("Memory Resource"),
250 translate("Use menu System/Processes to observe any memory growth"))
251 rsc:value("default", translate("Default"))
252 rsc:value("tiny", translate("Tiny"))
253 rsc:value("small", translate("Small"))
254 rsc:value("medium", translate("Medium"))
255 rsc:value("large", translate("Large"))
258 rsn = s1:taboption("resource", ListValue, "recursion",
259 translate("Recursion Strength"),
260 translate("Recursion activity affects memory growth and CPU load"))
261 rsn:value("default", translate("Default"))
262 rsn:value("passive", translate("Passive"))
263 rsn:value("aggressive", translate("Aggressive"))
266 qry = s1:taboption("resource", Flag, "query_minimize",
267 translate("Query Minimize"),
268 translate("Break down query components for limited added privacy"))
270 qry:depends("recursion", "passive")
271 qry:depends("recursion", "aggressive")
273 qrs = s1:taboption("resource", Flag, "query_min_strict",
274 translate("Strict Minimize"),
275 translate("Strict version of 'query minimize' but it can break DNS"))
277 qrs:depends("query_minimize", true)
279 eds = s1:taboption("resource", Value, "edns_size",
280 translate("EDNS Size"),
281 translate("Limit extended DNS packet size"))
282 eds.datatype = "and(uinteger,min(512),max(4096))"
283 eds.placeholder = "1280"
285 tlm = s1:taboption("resource", Value, "ttl_min",
286 translate("TTL Minimum"),
287 translate("Prevent excessively short cache periods"))
288 tlm.datatype = "and(uinteger,min(0),max(1200))"
289 tlm.placeholder = "120"
291 rtt = s1:taboption("resource", Value, "rate_limit",
292 translate("Query Rate Limit"),
293 translate("Prevent client query overload; zero is off"))
294 rtt.datatype = "and(uinteger,min(0),max(5000))"
295 rtt.placeholder = "0"
297 stt = s1:taboption("resource", Flag, "extended_stats",
298 translate("Extended Statistics"),
299 translate("Extended statistics are printed from unbound-control"))
303 ag2 = s1:taboption("basic", Value, "root_age",
304 translate("Root DSKEY Age"),
305 translate("Limit days between RFC5011 copies to reduce flash writes"))
306 ag2.datatype = "and(uinteger,min(1),max(99))"
308 ag2:value("9", "9 ("..translate("default")..")")
309 ag2:value("12", "12")
310 ag2:value("24", "24")
311 ag2:value("99", "99 ("..translate("never")..")")
313 tgr = s1:taboption("basic", Value, "trigger_interface",
314 translate("Trigger Networks"),
315 translate("Networks that may trigger Unbound to reload (avoid wan6)"))
316 tgr.template = "cbi/network_netlist"
317 tgr.widget = "checkbox"
324 function ena.cfgvalue(self, section)
325 return sy.init.enabled("unbound") and self.enabled or self.disabled
329 function ena.write(self, section, value)
330 if (value == "1") then
331 sy.init.enable("unbound")
332 sy.call("/etc/init.d/unbound start >/dev/null 2>&1")
335 sy.call("/etc/init.d/unbound stop >/dev/null 2>&1")
336 sy.init.disable("unbound")
340 return Flag.write(self, section, value)
344 function m1.on_commit(self)
345 if sy.init.enabled("unbound") then
346 -- Restart Unbound with configuration
347 sy.call("/etc/init.d/unbound restart >/dev/null 2>&1")
350 sy.call("/etc/init.d/unbound stop >/dev/null 2>&1")
355 function m1.on_apply(self)
356 -- reload the page because some options hide
357 ht.redirect(ds.build_url("admin", "services", "unbound", "configure"))