2 LuCI - Lua Configuration Interface
4 Copyright 2008 Steven Barth <steven@midlink.org>
5 Copyright 2008 Jo-Philipp Wich <xm@subsignal.org>
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
11 http://www.apache.org/licenses/LICENSE-2.0
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"
23 local has_dnsmasq = fs.access("/etc/config/dhcp")
24 local has_firewall = fs.access("/etc/config/firewall")
26 local has_3g = fs.access("/usr/bin/gcom")
27 local has_pptp = fs.access("/usr/sbin/pptp")
28 local has_pppd = fs.access("/usr/sbin/pppd")
29 local has_pppoe = fs.glob("/usr/lib/pppd/*/rp-pppoe.so")()
30 local has_pppoa = fs.glob("/usr/lib/pppd/*/pppoatm.so")()
31 local has_ipv6 = fs.access("/proc/net/ipv6_route")
32 local has_6in4 = fs.access("/lib/network/6in4.sh")
33 local has_6to4 = fs.access("/lib/network/6to4.sh")
35 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>)."))
46 local net = nw:get_network(arg[1])
48 -- redirect to overview page if network does not exist anymore (e.g. after a revert)
50 luci.http.redirect(luci.dispatcher.build_url("admin/network/network"))
54 local ifc = net:get_interfaces()[1]
56 s = m:section(NamedSection, arg[1], "interface", translate("Common Configuration"))
59 s:tab("general", translate("General Setup"))
60 if has_ipv6 then s:tab("ipv6", translate("IPv6 Setup")) end
61 if has_pppd then s:tab("ppp", translate("PPP Settings")) end
62 if has_pppoa then s:tab("atm", translate("ATM Settings")) end
63 if has_6in4 or has_6to4 then s:tab("tunnel", translate("Tunnel Settings")) end
64 s:tab("physical", translate("Physical Settings"))
65 if has_firewall then s:tab("firewall", translate("Firewall Settings")) end
67 st = s:taboption("general", DummyValue, "__status", translate("Status"))
68 st.template = "admin_network/iface_status"
72 back = s:taboption("general", DummyValue, "_overview", translate("Overview"))
74 back.titleref = luci.dispatcher.build_url("admin", "network", "network")
77 p = s:taboption("general", ListValue, "proto", translate("Protocol"))
78 p.override_scheme = true
80 p:value("static", translate("static"))
81 p:value("dhcp", "DHCP")
82 if has_pppd then p:value("ppp", "PPP") end
83 if has_pppoe then p:value("pppoe", "PPPoE") end
84 if has_pppoa then p:value("pppoa", "PPPoA") end
85 if has_3g then p:value("3g", "UMTS/3G") end
86 if has_pptp then p:value("pptp", "PPTP") end
87 if has_6in4 then p:value("6in4", "6in4") end
88 if has_6to4 then p:value("6to4", "6to4") end
89 p:value("none", translate("none"))
91 if not ( has_pppd and has_pppoe and has_pppoa and has_3g and has_pptp ) then
92 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")
95 br = s:taboption("physical", Flag, "type", translate("Bridge interfaces"), translate("creates a bridge over specified interface(s)"))
98 br:depends("proto", "static")
99 br:depends("proto", "dhcp")
100 br:depends("proto", "none")
102 stp = s:taboption("physical", Flag, "stp", translate("Enable <abbr title=\"Spanning Tree Protocol\">STP</abbr>"),
103 translate("Enables the Spanning Tree Protocol on this bridge"))
104 stp:depends("type", "bridge")
107 ifname_single = s:taboption("physical", Value, "ifname_single", translate("Interface"))
108 ifname_single.template = "cbi/network_ifacelist"
109 ifname_single.widget = "radio"
110 ifname_single.nobridges = true
111 ifname_single.network = arg[1]
112 ifname_single.rmempty = true
113 ifname_single:depends({ type = "", proto = "static" })
114 ifname_single:depends({ type = "", proto = "dhcp" })
115 ifname_single:depends({ type = "", proto = "pppoe" })
116 ifname_single:depends({ type = "", proto = "pppoa" })
117 ifname_single:depends({ type = "", proto = "none" })
119 function ifname_single.cfgvalue(self, s)
120 return self.map.uci:get("network", s, "ifname")
123 function ifname_single.write(self, s, val)
124 local n = nw:get_network(s)
127 for _, i in ipairs(n:get_interfaces()) do
131 for i in ut.imatch(val) do
134 -- if this is not a bridge, only assign first interface
135 if self.option == "ifname_single" then
142 ifname_multi = s:taboption("physical", Value, "ifname_multi", translate("Interface"))
143 ifname_multi.template = "cbi/network_ifacelist"
144 ifname_multi.nobridges = true
145 ifname_multi.network = arg[1]
146 ifname_multi.widget = "checkbox"
147 ifname_multi:depends("type", "bridge")
148 ifname_multi.cfgvalue = ifname_single.cfgvalue
149 ifname_multi.write = ifname_single.write
153 fwzone = s:taboption("firewall", Value, "_fwzone",
154 translate("Create / Assign firewall-zone"),
155 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."))
157 fwzone.template = "cbi/firewall_zonelist"
158 fwzone.network = arg[1]
159 fwzone.rmempty = false
161 function fwzone.cfgvalue(self, section)
163 local z = fw:get_zone_by_network(section)
164 return z and z:name()
167 function fwzone.write(self, section, value)
168 local zone = fw:get_zone(value)
170 if not zone and value == '-' then
171 value = m:formvalue(self:cbid(section) .. ".newzone")
172 if value and #value > 0 then
173 zone = fw:add_zone(value)
175 fw:del_network(section)
180 fw:del_network(section)
181 zone:add_network(section)
186 ipaddr = s:taboption("general", Value, "ipaddr", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Address"))
187 ipaddr.optional = true
188 ipaddr.datatype = "ip4addr"
189 ipaddr:depends("proto", "static")
191 nm = s:taboption("general", Value, "netmask", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Netmask"))
193 nm.datatype = "ip4addr"
194 nm:depends("proto", "static")
195 nm:value("255.255.255.0")
196 nm:value("255.255.0.0")
197 nm:value("255.0.0.0")
199 gw = s:taboption("general", Value, "gateway", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Gateway"))
201 gw.datatype = "ip4addr"
202 gw:depends("proto", "static")
204 bcast = s:taboption("general", Value, "bcast", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Broadcast"))
205 bcast.optional = true
206 bcast.datatype = "ip4addr"
207 bcast:depends("proto", "static")
210 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"))
211 ip6addr.optional = true
212 ip6addr.datatype = "ip6addr"
213 ip6addr:depends("proto", "static")
214 ip6addr:depends("proto", "6in4")
216 ip6gw = s:taboption("ipv6", Value, "ip6gw", translate("<abbr title=\"Internet Protocol Version 6\">IPv6</abbr>-Gateway"))
217 ip6gw.optional = true
218 ip6gw.datatype = "ip6addr"
219 ip6gw:depends("proto", "static")
222 dns = s:taboption("general", DynamicList, "dns", translate("<abbr title=\"Domain Name System\">DNS</abbr>-Server"),
223 translate("You can specify multiple DNS servers here, press enter to add a new entry. Servers entered here will override " ..
224 "automatically assigned ones."))
228 dns.datatype = "ipaddr"
229 dns:depends({ peerdns = "", proto = "static" })
230 dns:depends({ peerdns = "", proto = "dhcp" })
231 dns:depends({ peerdns = "", proto = "pppoe" })
232 dns:depends({ peerdns = "", proto = "pppoa" })
233 dns:depends({ peerdns = "", proto = "none" })
235 mtu = s:taboption("physical", Value, "mtu", "MTU")
237 mtu.datatype = "uinteger"
238 mtu.placeholder = 1500
240 srv = s:taboption("general", Value, "server", translate("<abbr title=\"Point-to-Point Tunneling Protocol\">PPTP</abbr>-Server"))
241 srv:depends("proto", "pptp")
243 srv.datatype = "ip4addr"
246 peer = s:taboption("general", Value, "peeraddr", translate("Server IPv4-Address"))
247 peer.optional = false
248 peer.datatype = "ip4addr"
249 peer:depends("proto", "6in4")
252 if has_6in4 or has_6to4 then
253 ttl = s:taboption("physical", Value, "ttl", translate("TTL"))
256 ttl.datatype = "uinteger"
257 ttl:depends("proto", "6in4")
258 ttl:depends("proto", "6to4")
262 advi = s:taboption("general", Value, "adv_interface", translate("Advertise IPv6 on network"))
263 advi.widget = "checkbox"
264 advi.exclude = arg[1]
266 advi.template = "cbi/network_netlist"
268 advi.nobridges = true
269 advi:depends("proto", "6to4")
271 advn = s:taboption("general", Value, "adv_subnet", translate("Advertised network ID"), translate("Allowed range is 1 to FFFF"))
273 advn:depends("proto", "6to4")
275 function advn.write(self, section, value)
276 value = tonumber(value, 16) or 1
278 if value > 65535 then value = 65535
279 elseif value < 1 then value = 1 end
281 Value.write(self, section, "%X" % value)
285 mac = s:taboption("physical", Value, "macaddr", translate("<abbr title=\"Media Access Control\">MAC</abbr>-Address"))
286 mac:depends("proto", "none")
287 mac:depends("proto", "static")
288 mac:depends("proto", "dhcp")
289 mac.placeholder = ifc and ifc:mac():upper()
292 service = s:taboption("general", ListValue, "service", translate("Service type"))
293 service:value("", translate("-- Please choose --"))
294 service:value("umts", "UMTS/GPRS")
295 service:value("cdma", "CDMA")
296 service:value("evdo", "EV-DO")
297 service:depends("proto", "3g")
298 service.rmempty = true
300 apn = s:taboption("general", Value, "apn", translate("Access point (APN)"))
301 apn:depends("proto", "3g")
303 pincode = s:taboption("general", Value, "pincode",
304 translate("PIN code"),
305 translate("Make sure that you provide the correct pin code here or you might lock your sim card!")
307 pincode:depends("proto", "3g")
311 tunid = s:taboption("general", Value, "tunnelid", translate("HE.net Tunnel ID"))
312 tunid.optional = true
313 tunid.datatype = "uinteger"
314 tunid:depends("proto", "6in4")
317 if has_pppd or has_pppoe or has_pppoa or has_3g or has_pptp or has_6in4 then
318 user = s:taboption("general", Value, "username", translate("Username"))
320 user:depends("proto", "pptp")
321 user:depends("proto", "pppoe")
322 user:depends("proto", "pppoa")
323 user:depends("proto", "ppp")
324 user:depends("proto", "3g")
325 user:depends("proto", "6in4")
327 pass = s:taboption("general", Value, "password", translate("Password"))
330 pass:depends("proto", "pptp")
331 pass:depends("proto", "pppoe")
332 pass:depends("proto", "pppoa")
333 pass:depends("proto", "ppp")
334 pass:depends("proto", "3g")
335 pass:depends("proto", "6in4")
338 if has_pppd or has_pppoe or has_pppoa or has_3g or has_pptp then
339 ka = s:taboption("ppp", Value, "keepalive",
340 translate("Keep-Alive"),
341 translate("Number of failed connection tests to initiate automatic reconnect")
343 ka:depends("proto", "pptp")
344 ka:depends("proto", "pppoe")
345 ka:depends("proto", "pppoa")
346 ka:depends("proto", "ppp")
347 ka:depends("proto", "3g")
349 demand = s:taboption("ppp", Value, "demand",
350 translate("Automatic Disconnect"),
351 translate("Time (in seconds) after which an unused connection will be closed")
353 demand.optional = true
354 demand.datatype = "uinteger"
355 demand:depends("proto", "pptp")
356 demand:depends("proto", "pppoe")
357 demand:depends("proto", "pppoa")
358 demand:depends("proto", "ppp")
359 demand:depends("proto", "3g")
363 encaps = s:taboption("atm", ListValue, "encaps", translate("PPPoA Encapsulation"))
364 encaps:depends("proto", "pppoa")
365 encaps:value("vc", "VC-Mux")
366 encaps:value("llc", "LLC")
368 atmdev = s:taboption("atm", Value, "atmdev", translate("ATM device number"))
369 atmdev:depends("proto", "pppoa")
371 atmdev.datatype = "uinteger"
373 vci = s:taboption("atm", Value, "vci", translate("ATM Virtual Channel Identifier (VCI)"))
374 vci:depends("proto", "pppoa")
376 vci.datatype = "uinteger"
378 vpi = s:taboption("atm", Value, "vpi", translate("ATM Virtual Path Identifier (VPI)"))
379 vpi:depends("proto", "pppoa")
381 vpi.datatype = "uinteger"
384 if has_pptp or has_pppd or has_pppoe or has_pppoa or has_3g then
385 device = s:taboption("general", Value, "device",
386 translate("Modem device"),
387 translate("The device node of your modem, e.g. /dev/ttyUSB0")
389 device:depends("proto", "ppp")
390 device:depends("proto", "3g")
392 defaultroute = s:taboption("ppp", Flag, "defaultroute",
393 translate("Replace default route"),
394 translate("Let pppd replace the current default route to use the PPP interface after successful connect")
396 defaultroute:depends("proto", "ppp")
397 defaultroute:depends("proto", "pppoa")
398 defaultroute:depends("proto", "pppoe")
399 defaultroute:depends("proto", "pptp")
400 defaultroute:depends("proto", "3g")
401 defaultroute.rmempty = false
402 function defaultroute.cfgvalue(...)
403 return ( AbstractValue.cfgvalue(...) or '1' )
406 peerdns = s:taboption("ppp", Flag, "peerdns",
407 translate("Use peer DNS"),
408 translate("Configure the local DNS server to use the name servers adverticed by the PPP peer")
410 peerdns:depends("proto", "ppp")
411 peerdns:depends("proto", "pppoa")
412 peerdns:depends("proto", "pppoe")
413 peerdns:depends("proto", "pptp")
414 peerdns:depends("proto", "3g")
415 peerdns.rmempty = false
416 function peerdns.cfgvalue(...)
417 return ( AbstractValue.cfgvalue(...) or '1' )
421 ipv6 = s:taboption("ppp", Flag, "ipv6", translate("Enable IPv6 on PPP link") )
422 ipv6:depends("proto", "ppp")
423 ipv6:depends("proto", "pppoa")
424 ipv6:depends("proto", "pppoe")
425 ipv6:depends("proto", "pptp")
426 ipv6:depends("proto", "3g")
429 connect = s:taboption("ppp", Value, "connect",
430 translate("Connect script"),
431 translate("Let pppd run this script after establishing the PPP link")
433 connect:depends("proto", "ppp")
434 connect:depends("proto", "pppoe")
435 connect:depends("proto", "pppoa")
436 connect:depends("proto", "pptp")
437 connect:depends("proto", "3g")
439 disconnect = s:taboption("ppp", Value, "disconnect",
440 translate("Disconnect script"),
441 translate("Let pppd run this script before tearing down the PPP link")
443 disconnect:depends("proto", "ppp")
444 disconnect:depends("proto", "pppoe")
445 disconnect:depends("proto", "pppoa")
446 disconnect:depends("proto", "pptp")
447 disconnect:depends("proto", "3g")
449 pppd_options = s:taboption("ppp", Value, "pppd_options",
450 translate("Additional pppd options"),
451 translate("Specify additional command line arguments for pppd here")
453 pppd_options:depends("proto", "ppp")
454 pppd_options:depends("proto", "pppoa")
455 pppd_options:depends("proto", "pppoe")
456 pppd_options:depends("proto", "pptp")
457 pppd_options:depends("proto", "3g")
459 maxwait = s:taboption("ppp", Value, "maxwait",
460 translate("Setup wait time"),
461 translate("Seconds to wait for the modem to become ready before attempting to connect")
463 maxwait:depends("proto", "3g")
464 maxwait.default = "0"
465 maxwait.optional = true
466 maxwait.datatype = "uinteger"
469 s2 = m:section(TypedSection, "alias", translate("IP-Aliases"))
472 s2:depends("interface", arg[1])
473 s2.defaults.interface = arg[1]
475 s2:tab("general", translate("General Setup"))
476 s2.defaults.proto = "static"
478 ip = s2:taboption("general", Value, "ipaddr", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Address"))
480 ip.datatype = "ip4addr"
482 nm = s2:taboption("general", Value, "netmask", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Netmask"))
484 nm.datatype = "ip4addr"
485 nm:value("255.255.255.0")
486 nm:value("255.255.0.0")
487 nm:value("255.0.0.0")
489 gw = s2:taboption("general", Value, "gateway", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Gateway"))
491 gw.datatype = "ip4addr"
494 s2:tab("ipv6", translate("IPv6 Setup"))
496 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"))
498 ip6.datatype = "ip6addr"
500 gw6 = s2:taboption("ipv6", Value, "ip6gw", translate("<abbr title=\"Internet Protocol Version 6\">IPv6</abbr>-Gateway"))
502 gw6.datatype = "ip6addr"
505 s2:tab("advanced", translate("Advanced Settings"))
507 bcast = s2:taboption("advanced", Value, "bcast", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Broadcast"))
508 bcast.optional = true
509 bcast.datatype = "ip4addr"
511 dns = s2:taboption("advanced", Value, "dns", translate("<abbr title=\"Domain Name System\">DNS</abbr>-Server"))
513 dns.datatype = "ip4addr"
517 -- Display DNS settings if dnsmasq is available
521 m2 = Map("dhcp", "", "")
522 function m2.on_parse()
523 local has_section = false
525 m2.uci:foreach("dhcp", "dhcp", function(s)
526 if s.interface == arg[1] then
532 if not has_section then
533 m2.uci:section("dhcp", "dhcp", nil, { interface = arg[1], ignore = "1" })
538 s = m2:section(TypedSection, "dhcp", translate("DHCP Server"))
541 s:tab("general", translate("General Setup"))
542 s:tab("advanced", translate("Advanced Settings"))
544 function s.filter(self, section)
545 return m2.uci:get("dhcp", section, "interface") == arg[1]
548 local ignore = s:taboption("general", Flag, "ignore",
549 translate("Ignore interface"),
550 translate("Disable <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</abbr> for " ..
553 ignore.rmempty = false
555 local start = s:taboption("general", Value, "start", translate("Start"),
556 translate("Lowest leased address as offset from the network address."))
557 start.optional = true
558 start.datatype = "uinteger"
559 start.default = "100"
561 local limit = s:taboption("general", Value, "limit", translate("Limit"),
562 translate("Maximum number of leased addresses."))
563 limit.optional = true
564 limit.datatype = "uinteger"
565 limit.default = "150"
567 local ltime = s:taboption("general", Value, "leasetime", translate("Leasetime"),
568 translate("Expiry time of leased addresses, minimum is 2 Minutes (<code>2m</code>)."))
570 ltime.default = "12h"
572 local dd = s:taboption("advanced", Flag, "dynamicdhcp",
573 translate("Dynamic <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</abbr>"),
574 translate("Dynamically allocate DHCP addresses for clients. If disabled, only " ..
575 "clients having static leases will be served."))
578 function dd.cfgvalue(self, section)
579 return Flag.cfgvalue(self, section) or "1"
582 s:taboption("advanced", Flag, "force", translate("Force"),
583 translate("Force DHCP on this network even if another server is detected."))
585 -- XXX: is this actually useful?
586 --s:taboption("advanced", Value, "name", translate("Name"),
587 -- translate("Define a name for this network."))
589 mask = s:taboption("advanced", Value, "netmask",
590 translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Netmask"),
591 translate("Override the netmask sent to clients. Normally it is calculated " ..
592 "from the subnet that is served."))
595 mask.datatype = "ip4addr"
597 s:taboption("advanced", DynamicList, "dhcp_option", translate("DHCP-Options"),
598 translate("Define additional DHCP options, for example \"<code>6,192.168.2.1," ..
599 "192.168.2.2</code>\" which advertises different DNS servers to clients."))
601 for i, n in ipairs(s.children) do
603 n:depends("ignore", "")