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.
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")
18 s1 = m1:section(TypedSection, "unbound")
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"))
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/"))
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/ "))
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/"))
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/"))
62 --Basic Tab, unconditional pieces
63 ena = s1:taboption("basic", Flag, "enabled", translate("Enable Unbound:"),
64 translate("Enable the initialization scripts for Unbound"))
67 mcf = s1:taboption("basic", Flag, "manual_conf", translate("Manual Conf:"),
68 translate("Skip UCI and use /etc/unbound/unbound.conf"))
71 lci = s1:taboption("basic", Flag, "extended_luci", translate("Extended Tabs:"),
72 translate("See detailed tabs for statistics, debug, and manual configuration"))
77 -- Not in manual configuration mode; show UCI
79 lsv = s1:taboption("basic", Flag, "localservice", translate("Local Service:"),
80 translate("Accept queries only from local subnets"))
83 vld = s1:taboption("basic", Flag, "validator", translate("Enable DNSSEC:"),
84 translate("Enable the DNSSEC validator module"))
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"))
90 nvd:depends({ validator = true })
92 d64 = s1:taboption("basic", Flag, "dns64", translate("Enable DNS64:"),
93 translate("Enable the DNS64 module"))
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"
101 pfx:depends({ dns64 = true })
103 prt = s1:taboption("basic", Value, "listen_port", translate("Listening Port:"),
104 translate("Choose Unbounds listening port"))
105 prt.datatype = "port"
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 })
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"))
118 rlh = s1:taboption("advanced", Flag, "rebind_localhost", translate("Filter Localhost Rebind:"),
119 translate("Protect against upstream response of 127.0.0.0/8"))
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"))
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"
136 rpn:depends({ rebind_protection = 2 })
137 rpn:depends({ rebind_protection = 3 })
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")
147 dp6 = s1:taboption("DHCP", Flag, "dhcp4_slaac6", translate("DHCPv4 to SLAAC:"),
148 translate("Use DHCPv4 MAC to discover IP6 hosts SLAAC (EUI64)"))
150 dp6:depends({ dhcp_link = "odhcpd" })
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" })
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" })
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" })
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" })
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" })
196 --TODO: dnsmasq needs to not reference resolve-file and get off port 53.
198 --Resource Tuning Tab
199 ctl = s1:taboption("resource", ListValue, "unbound_control", translate("Unbound Control App:"),
200 translate("Enable access for unbound-control"))
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"))
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"))
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"))
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"))
233 qry = s1:taboption("resource", Flag, "query_minimize", translate("Query Minimize:"),
234 translate("Break down query components for limited added privacy"))
236 qry:depends({ recursion = "passive" })
237 qry:depends({ recursion = "aggressive" })
239 qrs = s1:taboption("resource", Flag, "query_min_strict", translate("Strict Minimize:"),
240 translate("Strict version of 'query minimize' but it can break DNS"))
242 qrs:depends({ query_minimize = true })
244 ath = s1:taboption("resource", Flag, "prefetch_root", translate("Prefetch Root:"),
245 translate("Obtain complete root zone files and install in auth-zone: clause"))
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))"
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))"
258 stt = s1:taboption("resource", Flag, "extended_stats", translate("Extended Statistics:"),
259 translate("Extended statistics are printed from unbound-control"))
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))"
269 ag2:value("9", "9 ("..translate("default")..")")
270 ag2:value("12", "12")
271 ag2:value("24", "24")
272 ag2:value("99", "99 ("..translate("never")..")")
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"
283 function ena.cfgvalue(self, section)
284 return luci.sys.init.enabled("unbound") and self.enabled or self.disabled
288 function ena.write(self, section, value)
290 luci.sys.init.enable("unbound")
291 luci.sys.call("/etc/init.d/unbound start >/dev/null")
293 luci.sys.call("/etc/init.d/unbound stop >/dev/null")
294 luci.sys.init.disable("unbound")
297 return Flag.write(self, section, value)
301 function m1.on_apply(self)
302 function ena.validate(self, value)
304 luci.sys.call("/etc/init.d/unbound restart >/dev/null 2>&1")
306 luci.sys.call("/etc/init.d/unbound stop >/dev/null 2>&1")
311 -- Restart Unbound with configuration and reload the page (some options hide)
312 luci.http.redirect(luci.dispatcher.build_url("admin", "services", "unbound"))