fd79d507ec4b2d1d1168e53e7984c433f2e6906a
[project/luci.git] / modules / admin-full / luasrc / model / cbi / admin_network / ifaces.lua
1 --[[
2 LuCI - Lua Configuration Interface
3
4 Copyright 2008 Steven Barth <steven@midlink.org>
5 Copyright 2008 Jo-Philipp Wich <xm@subsignal.org>
6
7 Licensed under the Apache License, Version 2.0 (the "License");
8 you may not use this file except in compliance with the License.
9 You may obtain a copy of the License at
10
11         http://www.apache.org/licenses/LICENSE-2.0
12
13 $Id$
14 ]]--
15
16 local fs = require "nixio.fs"
17 local ut = require "luci.util"
18 local nw = require "luci.model.network"
19 local fw = require "luci.model.firewall"
20
21 arg[1] = arg[1] or ""
22
23 local has_3g     = fs.access("/usr/bin/gcom")
24 local has_pptp   = fs.access("/usr/sbin/pptp")
25 local has_pppd   = fs.access("/usr/sbin/pppd")
26 local has_pppoe  = fs.glob("/usr/lib/pppd/*/rp-pppoe.so")()
27 local has_pppoa  = fs.glob("/usr/lib/pppd/*/pppoatm.so")()
28 local has_ipv6   = fs.access("/proc/net/ipv6_route")
29 local has_6in4   = fs.access("/lib/network/6in4.sh")
30 local has_6to4   = fs.access("/lib/network/6to4.sh")
31
32 m = Map("network", translate("Interfaces") .. " - " .. arg[1]:upper(), translate("On this page you can configure the network interfaces. You can bridge several interfaces by ticking the \"bridge interfaces\" field and enter the names of several network interfaces separated by spaces. You can also use <abbr title=\"Virtual Local Area Network\">VLAN</abbr> notation <samp>INTERFACE.VLANNR</samp> (<abbr title=\"for example\">e.g.</abbr>: <samp>eth0.1</samp>)."))
33 m:chain("firewall")
34 m:chain("wireless")
35
36 nw.init(m.uci)
37 fw.init(m.uci)
38
39
40 local net = nw:get_network(arg[1])
41
42 -- redirect to overview page if network does not exist anymore (e.g. after a revert)
43 if not net then
44         luci.http.redirect(luci.dispatcher.build_url("admin/network/network"))
45         return
46 end
47
48 local ifc = net:get_interfaces()[1]
49
50 s = m:section(NamedSection, arg[1], "interface", translate("Common Configuration"))
51 s.addremove = false
52
53 s:tab("general", translate("General Setup"))
54 if has_ipv6  then s:tab("ipv6", translate("IPv6 Setup")) end
55 if has_pppd  then s:tab("ppp", translate("PPP Settings")) end
56 if has_pppoa then s:tab("atm", translate("ATM Settings")) end
57 if has_6in4 or has_6to4 then s:tab("tunnel", translate("Tunnel Settings")) end
58 s:tab("physical", translate("Physical Settings"))
59 s:tab("firewall", translate("Firewall Settings"))
60
61 st = s:taboption("general", DummyValue, "__status", translate("Status"))
62 st.template = "admin_network/iface_status"
63 st.network  = arg[1]
64
65 --[[
66 back = s:taboption("general", DummyValue, "_overview", translate("Overview"))
67 back.value = ""
68 back.titleref = luci.dispatcher.build_url("admin", "network", "network")
69 ]]
70
71 p = s:taboption("general", ListValue, "proto", translate("Protocol"))
72 p.override_scheme = true
73 p.default = "static"
74 p:value("static", translate("static"))
75 p:value("dhcp", "DHCP")
76 if has_pppd  then p:value("ppp",   "PPP")     end
77 if has_pppoe then p:value("pppoe", "PPPoE")   end
78 if has_pppoa then p:value("pppoa", "PPPoA")   end
79 if has_3g    then p:value("3g",    "UMTS/3G") end
80 if has_pptp  then p:value("pptp",  "PPTP")    end
81 if has_6in4  then p:value("6in4",  "6in4")    end
82 if has_6to4  then p:value("6to4",  "6to4")    end
83 p:value("none", translate("none"))
84
85 if not ( has_pppd and has_pppoe and has_pppoa and has_3g and has_pptp ) then
86         p.description = translate("You need to install \"comgt\" for UMTS/GPRS, \"ppp-mod-pppoe\" for PPPoE, \"ppp-mod-pppoa\" for PPPoA or \"pptp\" for PPtP support")
87 end
88
89 br = s:taboption("physical", Flag, "type", translate("Bridge interfaces"), translate("creates a bridge over specified interface(s)"))
90 br.enabled = "bridge"
91 br.rmempty = true
92 br:depends("proto", "static")
93 br:depends("proto", "dhcp")
94 br:depends("proto", "none")
95
96 stp = s:taboption("physical", Flag, "stp", translate("Enable <abbr title=\"Spanning Tree Protocol\">STP</abbr>"),
97         translate("Enables the Spanning Tree Protocol on this bridge"))
98 stp:depends("type", "bridge")
99 stp.rmempty = true
100
101 ifname_single = s:taboption("physical", Value, "ifname_single", translate("Interface"))
102 ifname_single.template = "cbi/network_ifacelist"
103 ifname_single.widget = "radio"
104 ifname_single.nobridges = true
105 ifname_single.network = arg[1]
106 ifname_single.rmempty = true
107 ifname_single:depends({ type = "", proto = "static" })
108 ifname_single:depends({ type = "", proto = "dhcp"   })
109 ifname_single:depends({ type = "", proto = "pppoe"  })
110 ifname_single:depends({ type = "", proto = "pppoa"  })
111 ifname_single:depends({ type = "", proto = "none"   })
112
113 function ifname_single.cfgvalue(self, s)
114         return self.map.uci:get("network", s, "ifname")
115 end
116
117 function ifname_single.write(self, s, val)
118         local n = nw:get_network(s)
119         if n then
120                 local i
121                 for _, i in ipairs(n:get_interfaces()) do
122                         n:del_interface(i)
123                 end
124
125                 for i in ut.imatch(val) do
126                         n:add_interface(i)
127
128                         -- if this is not a bridge, only assign first interface
129                         if self.option == "ifname_single" then
130                                 break
131                         end
132                 end
133         end
134 end
135
136 ifname_multi = s:taboption("physical", Value, "ifname_multi", translate("Interface"))
137 ifname_multi.template = "cbi/network_ifacelist"
138 ifname_multi.nobridges = true
139 ifname_multi.network = arg[1]
140 ifname_multi.widget = "checkbox"
141 ifname_multi:depends("type", "bridge")
142 ifname_multi.cfgvalue = ifname_single.cfgvalue
143 ifname_multi.write = ifname_single.write
144
145
146 local fwd_to, fwd_from
147
148 fwzone = s:taboption("firewall", Value, "_fwzone",
149         translate("Create / Assign firewall-zone"),
150         translate("Choose the firewall zone you want to assign to this interface. Select <em>unspecified</em> to remove the interface from the associated zone or fill out the <em>create</em> field to define a new zone and attach the interface to it."))
151
152 fwzone.template = "cbi/firewall_zonelist"
153 fwzone.network = arg[1]
154 fwzone.rmempty = false
155
156 function fwzone.cfgvalue(self, section)
157         self.iface = section
158         local z = fw:get_zone_by_network(section)
159         return z and z:name()
160 end
161
162 function fwzone.write(self, section, value)
163         local zone = fw:get_zone(value)
164
165         if not zone and value == '-' then
166                 value = m:formvalue(self:cbid(section) .. ".newzone")
167                 if value and #value > 0 then
168                         zone = fw:add_zone(value)
169                 else
170                         fw:del_network(section)
171                 end
172         end
173
174         if zone then
175                 fw:del_network(section)
176                 zone:add_network(section)
177         end
178 end
179
180 ipaddr = s:taboption("general", Value, "ipaddr", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Address"))
181 ipaddr.optional = true
182 ipaddr.datatype = "ip4addr"
183 ipaddr:depends("proto", "static")
184
185 nm = s:taboption("general", Value, "netmask", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Netmask"))
186 nm.optional = true
187 nm.datatype = "ip4addr"
188 nm:depends("proto", "static")
189 nm:value("255.255.255.0")
190 nm:value("255.255.0.0")
191 nm:value("255.0.0.0")
192
193 gw = s:taboption("general", Value, "gateway", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Gateway"))
194 gw.optional = true
195 gw.datatype = "ip4addr"
196 gw:depends("proto", "static")
197
198 bcast = s:taboption("general", Value, "bcast", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Broadcast"))
199 bcast.optional = true
200 bcast.datatype = "ip4addr"
201 bcast:depends("proto", "static")
202
203 if has_ipv6 then
204         ip6addr = s:taboption("ipv6", Value, "ip6addr", translate("<abbr title=\"Internet Protocol Version 6\">IPv6</abbr>-Address"), translate("<abbr title=\"Classless Inter-Domain Routing\">CIDR</abbr>-Notation: address/prefix"))
205         ip6addr.optional = true
206         ip6addr.datatype = "ip6addr"
207         ip6addr:depends("proto", "static")
208         ip6addr:depends("proto", "6in4")
209
210         ip6gw = s:taboption("ipv6", Value, "ip6gw", translate("<abbr title=\"Internet Protocol Version 6\">IPv6</abbr>-Gateway"))
211         ip6gw.optional = true
212         ip6gw.datatype = "ip6addr"
213         ip6gw:depends("proto", "static")
214 end
215
216 dns = s:taboption("general", DynamicList, "dns", translate("<abbr title=\"Domain Name System\">DNS</abbr>-Server"),
217         translate("You can specify multiple DNS servers here, press enter to add a new entry. Servers entered here will override " ..
218                 "automatically assigned ones."))
219
220 dns.optional = true
221 dns.cast = "string"
222 dns.datatype = "ipaddr"
223 dns:depends({ peerdns = "", proto = "static" })
224 dns:depends({ peerdns = "", proto = "dhcp"   })
225 dns:depends({ peerdns = "", proto = "pppoe"  })
226 dns:depends({ peerdns = "", proto = "pppoa"  })
227 dns:depends({ peerdns = "", proto = "none"   })
228
229 mtu = s:taboption("physical", Value, "mtu", "MTU")
230 mtu.optional = true
231 mtu.datatype = "uinteger"
232 mtu.placeholder = 1500
233
234 srv = s:taboption("general", Value, "server", translate("<abbr title=\"Point-to-Point Tunneling Protocol\">PPTP</abbr>-Server"))
235 srv:depends("proto", "pptp")
236 srv.optional = false
237 srv.datatype = "ip4addr"
238
239 if has_6in4 then
240         peer = s:taboption("general", Value, "peeraddr", translate("Server IPv4-Address"))
241         peer.optional = false
242         peer.datatype = "ip4addr"
243         peer:depends("proto", "6in4")
244 end
245
246 if has_6in4 or has_6to4 then
247         ttl = s:taboption("physical", Value, "ttl", translate("TTL"))
248         ttl.default = "64"
249         ttl.optional = true
250         ttl.datatype = "uinteger"
251         ttl:depends("proto", "6in4")
252         ttl:depends("proto", "6to4")
253
254         advi = s:taboption("general", Value, "adv_interface", translate("Advertise IPv6 on network"))
255         advi.widget = "radio"
256         advi.exclude = arg[1]
257         advi.default = "lan"
258         advi.template = "cbi/network_netlist"
259         advi.nocreate = true
260         advi.nobridges = true
261
262         advn = s:taboption("general", Value, "adv_subnet", translate("Advertised network ID"), translate("Allowed range is 1 to FFFF"))
263         advn.default = "1"
264
265         function advn.write(self, section, value)
266                 value = tonumber(value, 16) or 1
267
268                 if value > 65535 then value = 65535
269                 elseif value < 1 then value = 1 end
270
271                 Value.write(self, section, "%X" % value)
272         end
273 end
274
275 mac = s:taboption("physical", Value, "macaddr", translate("<abbr title=\"Media Access Control\">MAC</abbr>-Address"))
276 mac:depends("proto", "none")
277 mac:depends("proto", "static")
278 mac:depends("proto", "dhcp")
279 mac.placeholder = ifc and ifc:mac():upper()
280
281 if has_3g then
282         service = s:taboption("general", ListValue, "service", translate("Service type"))
283         service:value("", translate("-- Please choose --"))
284         service:value("umts", "UMTS/GPRS")
285         service:value("cdma", "CDMA")
286         service:value("evdo", "EV-DO")
287         service:depends("proto", "3g")
288         service.rmempty = true
289
290         apn = s:taboption("general", Value, "apn", translate("Access point (APN)"))
291         apn:depends("proto", "3g")
292
293         pincode = s:taboption("general", Value, "pincode",
294          translate("PIN code"),
295          translate("Make sure that you provide the correct pin code here or you might lock your sim card!")
296         )
297         pincode:depends("proto", "3g")
298 end
299
300 if has_6in4 then
301         tunid = s:taboption("general", Value, "tunnelid", translate("HE.net Tunnel ID"))
302         tunid.optional = true
303         tunid.datatype = "uinteger"
304         tunid:depends("proto", "6in4")
305 end
306
307 if has_pppd or has_pppoe or has_pppoa or has_3g or has_pptp or has_6in4 then
308         user = s:taboption("general", Value, "username", translate("Username"))
309         user.rmempty = true
310         user:depends("proto", "pptp")
311         user:depends("proto", "pppoe")
312         user:depends("proto", "pppoa")
313         user:depends("proto", "ppp")
314         user:depends("proto", "3g")
315         user:depends("proto", "6in4")
316
317         pass = s:taboption("general", Value, "password", translate("Password"))
318         pass.rmempty = true
319         pass.password = true
320         pass:depends("proto", "pptp")
321         pass:depends("proto", "pppoe")
322         pass:depends("proto", "pppoa")
323         pass:depends("proto", "ppp")
324         pass:depends("proto", "3g")
325         pass:depends("proto", "6in4")
326 end
327
328 if has_pppd or has_pppoe or has_pppoa or has_3g or has_pptp then
329         ka = s:taboption("ppp", Value, "keepalive",
330          translate("Keep-Alive"),
331          translate("Number of failed connection tests to initiate automatic reconnect")
332         )
333         ka:depends("proto", "pptp")
334         ka:depends("proto", "pppoe")
335         ka:depends("proto", "pppoa")
336         ka:depends("proto", "ppp")
337         ka:depends("proto", "3g")
338
339         demand = s:taboption("ppp", Value, "demand",
340          translate("Automatic Disconnect"),
341          translate("Time (in seconds) after which an unused connection will be closed")
342         )
343         demand.optional = true
344         demand.datatype = "uinteger"
345         demand:depends("proto", "pptp")
346         demand:depends("proto", "pppoe")
347         demand:depends("proto", "pppoa")
348         demand:depends("proto", "ppp")
349         demand:depends("proto", "3g")
350 end
351
352 if has_pppoa then
353         encaps = s:taboption("atm", ListValue, "encaps", translate("PPPoA Encapsulation"))
354         encaps:depends("proto", "pppoa")
355         encaps:value("vc", "VC-Mux")
356         encaps:value("llc", "LLC")
357
358         atmdev = s:taboption("atm", Value, "atmdev", translate("ATM device number"))
359         atmdev:depends("proto", "pppoa")
360         atmdev.default = "0"
361         atmdev.datatype = "uinteger"
362
363         vci = s:taboption("atm", Value, "vci", translate("ATM Virtual Channel Identifier (VCI)"))
364         vci:depends("proto", "pppoa")
365         vci.default = "35"
366         vci.datatype = "uinteger"
367
368         vpi = s:taboption("atm", Value, "vpi", translate("ATM Virtual Path Identifier (VPI)"))
369         vpi:depends("proto", "pppoa")
370         vpi.default = "8"
371         vpi.datatype = "uinteger"
372 end
373
374 if has_pptp or has_pppd or has_pppoe or has_pppoa or has_3g then
375         device = s:taboption("general", Value, "device",
376          translate("Modem device"),
377          translate("The device node of your modem, e.g. /dev/ttyUSB0")
378         )
379         device:depends("proto", "ppp")
380         device:depends("proto", "3g")
381
382         defaultroute = s:taboption("ppp", Flag, "defaultroute",
383          translate("Replace default route"),
384          translate("Let pppd replace the current default route to use the PPP interface after successful connect")
385         )
386         defaultroute:depends("proto", "ppp")
387         defaultroute:depends("proto", "pppoa")
388         defaultroute:depends("proto", "pppoe")
389         defaultroute:depends("proto", "pptp")
390         defaultroute:depends("proto", "3g")
391         defaultroute.rmempty = false
392         function defaultroute.cfgvalue(...)
393                 return ( AbstractValue.cfgvalue(...) or '1' )
394         end
395
396         peerdns = s:taboption("ppp", Flag, "peerdns",
397          translate("Use peer DNS"),
398          translate("Configure the local DNS server to use the name servers adverticed by the PPP peer")
399         )
400         peerdns:depends("proto", "ppp")
401         peerdns:depends("proto", "pppoa")
402         peerdns:depends("proto", "pppoe")
403         peerdns:depends("proto", "pptp")
404         peerdns:depends("proto", "3g")
405         peerdns.rmempty = false
406         function peerdns.cfgvalue(...)
407                 return ( AbstractValue.cfgvalue(...) or '1' )
408         end
409
410         if has_ipv6 then
411                 ipv6 = s:taboption("ppp", Flag, "ipv6", translate("Enable IPv6 on PPP link") )
412                 ipv6:depends("proto", "ppp")
413                 ipv6:depends("proto", "pppoa")
414                 ipv6:depends("proto", "pppoe")
415                 ipv6:depends("proto", "pptp")
416                 ipv6:depends("proto", "3g")
417         end
418
419         connect = s:taboption("ppp", Value, "connect",
420          translate("Connect script"),
421          translate("Let pppd run this script after establishing the PPP link")
422         )
423         connect:depends("proto", "ppp")
424         connect:depends("proto", "pppoe")
425         connect:depends("proto", "pppoa")
426         connect:depends("proto", "pptp")
427         connect:depends("proto", "3g")
428
429         disconnect = s:taboption("ppp", Value, "disconnect",
430          translate("Disconnect script"),
431          translate("Let pppd run this script before tearing down the PPP link")
432         )
433         disconnect:depends("proto", "ppp")
434         disconnect:depends("proto", "pppoe")
435         disconnect:depends("proto", "pppoa")
436         disconnect:depends("proto", "pptp")
437         disconnect:depends("proto", "3g")
438
439         pppd_options = s:taboption("ppp", Value, "pppd_options",
440          translate("Additional pppd options"),
441          translate("Specify additional command line arguments for pppd here")
442         )
443         pppd_options:depends("proto", "ppp")
444         pppd_options:depends("proto", "pppoa")
445         pppd_options:depends("proto", "pppoe")
446         pppd_options:depends("proto", "pptp")
447         pppd_options:depends("proto", "3g")
448
449         maxwait = s:taboption("ppp", Value, "maxwait",
450          translate("Setup wait time"),
451          translate("Seconds to wait for the modem to become ready before attempting to connect")
452         )
453         maxwait:depends("proto", "3g")
454         maxwait.default  = "0"
455         maxwait.optional = true
456         maxwait.datatype = "uinteger"
457 end
458
459 s2 = m:section(TypedSection, "alias", translate("IP-Aliases"))
460 s2.addremove = true
461
462 s2:depends("interface", arg[1])
463 s2.defaults.interface = arg[1]
464
465 s2:tab("general", translate("General Setup"))
466 s2.defaults.proto = "static"
467
468 ip = s2:taboption("general", Value, "ipaddr", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Address"))
469 ip.optional = true
470 ip.datatype = "ip4addr"
471
472 nm = s2:taboption("general", Value, "netmask", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Netmask"))
473 nm.optional = true
474 nm.datatype = "ip4addr"
475 nm:value("255.255.255.0")
476 nm:value("255.255.0.0")
477 nm:value("255.0.0.0")
478
479 gw = s2:taboption("general", Value, "gateway", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Gateway"))
480 gw.optional = true
481 gw.datatype = "ip4addr"
482
483 if has_ipv6 then
484         s2:tab("ipv6", translate("IPv6 Setup"))
485
486         ip6 = s2:taboption("ipv6", Value, "ip6addr", translate("<abbr title=\"Internet Protocol Version 6\">IPv6</abbr>-Address"), translate("<abbr title=\"Classless Inter-Domain Routing\">CIDR</abbr>-Notation: address/prefix"))
487         ip6.optional = true
488         ip6.datatype = "ip6addr"
489
490         gw6 = s2:taboption("ipv6", Value, "ip6gw", translate("<abbr title=\"Internet Protocol Version 6\">IPv6</abbr>-Gateway"))
491         gw6.optional = true
492         gw6.datatype = "ip6addr"
493 end
494
495 s2:tab("advanced", translate("Advanced Settings"))
496
497 bcast = s2:taboption("advanced", Value, "bcast", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Broadcast"))
498 bcast.optional = true
499 bcast.datatype = "ip4addr"
500
501 dns = s2:taboption("advanced", Value, "dns", translate("<abbr title=\"Domain Name System\">DNS</abbr>-Server"))
502 dns.optional = true
503 dns.datatype = "ip4addr"
504
505
506 m2 = Map("dhcp", "", "")
507 function m2.on_parse()
508         local has_section = false
509
510         m2.uci:foreach("dhcp", "dhcp", function(s)
511                 if s.interface == arg[1] then
512                         has_section = true
513                         return false
514                 end
515         end)
516
517         if not has_section then
518                 m2.uci:section("dhcp", "dhcp", nil, { interface = arg[1], ignore = "1" })
519                 m2.uci:save("dhcp")
520         end
521 end
522
523 s = m2:section(TypedSection, "dhcp", translate("DHCP Server"))
524 s.addremove = false
525 s.anonymous = true
526 s:tab("general",  translate("General Setup"))
527 s:tab("advanced", translate("Advanced Settings"))
528
529 function s.filter(self, section)
530         return m2.uci:get("dhcp", section, "interface") == arg[1]
531 end
532
533 local ignore = s:taboption("general", Flag, "ignore",
534         translate("Ignore interface"),
535         translate("Disable <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</abbr> for " ..
536                 "this interface."))
537
538 ignore.rmempty = false
539
540 local start = s:taboption("general", Value, "start", translate("Start"),
541         translate("Lowest leased address as offset from the network address."))
542 start.optional = true
543 start.datatype = "uinteger"
544 start.default = "100"
545
546 local limit = s:taboption("general", Value, "limit", translate("Limit"),
547         translate("Maximum number of leased addresses."))
548 limit.optional = true
549 limit.datatype = "uinteger"
550 limit.default = "150"
551
552 local ltime = s:taboption("general", Value, "leasetime", translate("Leasetime"),
553         translate("Expiry time of leased addresses, minimum is 2 Minutes (<code>2m</code>)."))
554 ltime.rmempty = true
555 ltime.default = "12h"
556
557 local dd = s:taboption("advanced", Flag, "dynamicdhcp",
558         translate("Dynamic <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</abbr>"),
559         translate("Dynamically allocate DHCP addresses for clients. If disabled, only " ..
560                 "clients having static leases will be served."))
561
562 dd.rmempty = false
563 function dd.cfgvalue(self, section)
564         return Flag.cfgvalue(self, section) or "1"
565 end
566
567 s:taboption("advanced", Flag, "force", translate("Force"),
568         translate("Force DHCP on this network even if another server is detected."))
569
570 -- XXX: is this actually useful?
571 --s:taboption("advanced", Value, "name", translate("Name"),
572 --      translate("Define a name for this network."))
573
574 mask = s:taboption("advanced", Value, "netmask",
575         translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Netmask"),
576         translate("Override the netmask sent to clients. Normally it is calculated " ..
577                 "from the subnet that is served."))
578
579 mask.optional = true
580 mask.datatype = "ip4addr"
581
582 s:taboption("advanced", DynamicList, "dhcp_option", translate("DHCP-Options"),
583         translate("Define additional DHCP options, for example \"<code>6,192.168.2.1," ..
584                 "192.168.2.2</code>\" which advertises different DNS servers to clients."))
585
586 for i, n in ipairs(s.children) do
587         if n ~= ignore then
588                 n:depends("ignore", "")
589         end
590 end
591
592 return m, m2