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