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_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")
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>)."))
40 local net = nw:get_network(arg[1])
42 -- redirect to overview page if network does not exist anymore (e.g. after a revert)
44 luci.http.redirect(luci.dispatcher.build_url("admin/network/network"))
48 local ifc = net:get_interfaces()[1]
50 s = m:section(NamedSection, arg[1], "interface", translate("Common Configuration"))
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"))
61 st = s:taboption("general", DummyValue, "__status", translate("Status"))
62 st.template = "admin_network/iface_status"
66 back = s:taboption("general", DummyValue, "_overview", translate("Overview"))
68 back.titleref = luci.dispatcher.build_url("admin", "network", "network")
71 p = s:taboption("general", ListValue, "proto", translate("Protocol"))
72 p.override_scheme = true
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"))
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")
89 br = s:taboption("physical", Flag, "type", translate("Bridge interfaces"), translate("creates a bridge over specified interface(s)"))
92 br:depends("proto", "static")
93 br:depends("proto", "dhcp")
94 br:depends("proto", "none")
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")
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" })
113 function ifname_single.cfgvalue(self, s)
114 return self.map.uci:get("network", s, "ifname")
117 function ifname_single.write(self, s, val)
118 local n = nw:get_network(s)
121 for _, i in ipairs(n:get_interfaces()) do
125 for i in ut.imatch(val) do
128 -- if this is not a bridge, only assign first interface
129 if self.option == "ifname_single" then
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
146 local fwd_to, fwd_from
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."))
152 fwzone.template = "cbi/firewall_zonelist"
153 fwzone.network = arg[1]
154 fwzone.rmempty = false
156 function fwzone.cfgvalue(self, section)
158 local z = fw:get_zone_by_network(section)
159 return z and z:name()
162 function fwzone.write(self, section, value)
163 local zone = fw:get_zone(value)
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)
170 fw:del_network(section)
175 fw:del_network(section)
176 zone:add_network(section)
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")
185 nm = s:taboption("general", Value, "netmask", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Netmask"))
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")
193 gw = s:taboption("general", Value, "gateway", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Gateway"))
195 gw.datatype = "ip4addr"
196 gw:depends("proto", "static")
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")
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")
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")
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."))
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" })
229 mtu = s:taboption("physical", Value, "mtu", "MTU")
231 mtu.datatype = "uinteger"
232 mtu.placeholder = 1500
234 srv = s:taboption("general", Value, "server", translate("<abbr title=\"Point-to-Point Tunneling Protocol\">PPTP</abbr>-Server"))
235 srv:depends("proto", "pptp")
237 srv.datatype = "ip4addr"
240 peer = s:taboption("general", Value, "peeraddr", translate("Server IPv4-Address"))
241 peer.optional = false
242 peer.datatype = "ip4addr"
243 peer:depends("proto", "6in4")
246 if has_6in4 or has_6to4 then
247 ttl = s:taboption("physical", Value, "ttl", translate("TTL"))
250 ttl.datatype = "uinteger"
251 ttl:depends("proto", "6in4")
252 ttl:depends("proto", "6to4")
256 advi = s:taboption("general", Value, "adv_interface", translate("Advertise IPv6 on network"))
257 advi.widget = "radio"
258 advi.exclude = arg[1]
260 advi.template = "cbi/network_netlist"
262 advi.nobridges = true
263 advi:depends("proto", "6to4")
265 advn = s:taboption("general", Value, "adv_subnet", translate("Advertised network ID"), translate("Allowed range is 1 to FFFF"))
267 advn:depends("proto", "6to4")
269 function advn.write(self, section, value)
270 value = tonumber(value, 16) or 1
272 if value > 65535 then value = 65535
273 elseif value < 1 then value = 1 end
275 Value.write(self, section, "%X" % value)
279 mac = s:taboption("physical", Value, "macaddr", translate("<abbr title=\"Media Access Control\">MAC</abbr>-Address"))
280 mac:depends("proto", "none")
281 mac:depends("proto", "static")
282 mac:depends("proto", "dhcp")
283 mac.placeholder = ifc and ifc:mac():upper()
286 service = s:taboption("general", ListValue, "service", translate("Service type"))
287 service:value("", translate("-- Please choose --"))
288 service:value("umts", "UMTS/GPRS")
289 service:value("cdma", "CDMA")
290 service:value("evdo", "EV-DO")
291 service:depends("proto", "3g")
292 service.rmempty = true
294 apn = s:taboption("general", Value, "apn", translate("Access point (APN)"))
295 apn:depends("proto", "3g")
297 pincode = s:taboption("general", Value, "pincode",
298 translate("PIN code"),
299 translate("Make sure that you provide the correct pin code here or you might lock your sim card!")
301 pincode:depends("proto", "3g")
305 tunid = s:taboption("general", Value, "tunnelid", translate("HE.net Tunnel ID"))
306 tunid.optional = true
307 tunid.datatype = "uinteger"
308 tunid:depends("proto", "6in4")
311 if has_pppd or has_pppoe or has_pppoa or has_3g or has_pptp or has_6in4 then
312 user = s:taboption("general", Value, "username", translate("Username"))
314 user:depends("proto", "pptp")
315 user:depends("proto", "pppoe")
316 user:depends("proto", "pppoa")
317 user:depends("proto", "ppp")
318 user:depends("proto", "3g")
319 user:depends("proto", "6in4")
321 pass = s:taboption("general", Value, "password", translate("Password"))
324 pass:depends("proto", "pptp")
325 pass:depends("proto", "pppoe")
326 pass:depends("proto", "pppoa")
327 pass:depends("proto", "ppp")
328 pass:depends("proto", "3g")
329 pass:depends("proto", "6in4")
332 if has_pppd or has_pppoe or has_pppoa or has_3g or has_pptp then
333 ka = s:taboption("ppp", Value, "keepalive",
334 translate("Keep-Alive"),
335 translate("Number of failed connection tests to initiate automatic reconnect")
337 ka:depends("proto", "pptp")
338 ka:depends("proto", "pppoe")
339 ka:depends("proto", "pppoa")
340 ka:depends("proto", "ppp")
341 ka:depends("proto", "3g")
343 demand = s:taboption("ppp", Value, "demand",
344 translate("Automatic Disconnect"),
345 translate("Time (in seconds) after which an unused connection will be closed")
347 demand.optional = true
348 demand.datatype = "uinteger"
349 demand:depends("proto", "pptp")
350 demand:depends("proto", "pppoe")
351 demand:depends("proto", "pppoa")
352 demand:depends("proto", "ppp")
353 demand:depends("proto", "3g")
357 encaps = s:taboption("atm", ListValue, "encaps", translate("PPPoA Encapsulation"))
358 encaps:depends("proto", "pppoa")
359 encaps:value("vc", "VC-Mux")
360 encaps:value("llc", "LLC")
362 atmdev = s:taboption("atm", Value, "atmdev", translate("ATM device number"))
363 atmdev:depends("proto", "pppoa")
365 atmdev.datatype = "uinteger"
367 vci = s:taboption("atm", Value, "vci", translate("ATM Virtual Channel Identifier (VCI)"))
368 vci:depends("proto", "pppoa")
370 vci.datatype = "uinteger"
372 vpi = s:taboption("atm", Value, "vpi", translate("ATM Virtual Path Identifier (VPI)"))
373 vpi:depends("proto", "pppoa")
375 vpi.datatype = "uinteger"
378 if has_pptp or has_pppd or has_pppoe or has_pppoa or has_3g then
379 device = s:taboption("general", Value, "device",
380 translate("Modem device"),
381 translate("The device node of your modem, e.g. /dev/ttyUSB0")
383 device:depends("proto", "ppp")
384 device:depends("proto", "3g")
386 defaultroute = s:taboption("ppp", Flag, "defaultroute",
387 translate("Replace default route"),
388 translate("Let pppd replace the current default route to use the PPP interface after successful connect")
390 defaultroute:depends("proto", "ppp")
391 defaultroute:depends("proto", "pppoa")
392 defaultroute:depends("proto", "pppoe")
393 defaultroute:depends("proto", "pptp")
394 defaultroute:depends("proto", "3g")
395 defaultroute.rmempty = false
396 function defaultroute.cfgvalue(...)
397 return ( AbstractValue.cfgvalue(...) or '1' )
400 peerdns = s:taboption("ppp", Flag, "peerdns",
401 translate("Use peer DNS"),
402 translate("Configure the local DNS server to use the name servers adverticed by the PPP peer")
404 peerdns:depends("proto", "ppp")
405 peerdns:depends("proto", "pppoa")
406 peerdns:depends("proto", "pppoe")
407 peerdns:depends("proto", "pptp")
408 peerdns:depends("proto", "3g")
409 peerdns.rmempty = false
410 function peerdns.cfgvalue(...)
411 return ( AbstractValue.cfgvalue(...) or '1' )
415 ipv6 = s:taboption("ppp", Flag, "ipv6", translate("Enable IPv6 on PPP link") )
416 ipv6:depends("proto", "ppp")
417 ipv6:depends("proto", "pppoa")
418 ipv6:depends("proto", "pppoe")
419 ipv6:depends("proto", "pptp")
420 ipv6:depends("proto", "3g")
423 connect = s:taboption("ppp", Value, "connect",
424 translate("Connect script"),
425 translate("Let pppd run this script after establishing the PPP link")
427 connect:depends("proto", "ppp")
428 connect:depends("proto", "pppoe")
429 connect:depends("proto", "pppoa")
430 connect:depends("proto", "pptp")
431 connect:depends("proto", "3g")
433 disconnect = s:taboption("ppp", Value, "disconnect",
434 translate("Disconnect script"),
435 translate("Let pppd run this script before tearing down the PPP link")
437 disconnect:depends("proto", "ppp")
438 disconnect:depends("proto", "pppoe")
439 disconnect:depends("proto", "pppoa")
440 disconnect:depends("proto", "pptp")
441 disconnect:depends("proto", "3g")
443 pppd_options = s:taboption("ppp", Value, "pppd_options",
444 translate("Additional pppd options"),
445 translate("Specify additional command line arguments for pppd here")
447 pppd_options:depends("proto", "ppp")
448 pppd_options:depends("proto", "pppoa")
449 pppd_options:depends("proto", "pppoe")
450 pppd_options:depends("proto", "pptp")
451 pppd_options:depends("proto", "3g")
453 maxwait = s:taboption("ppp", Value, "maxwait",
454 translate("Setup wait time"),
455 translate("Seconds to wait for the modem to become ready before attempting to connect")
457 maxwait:depends("proto", "3g")
458 maxwait.default = "0"
459 maxwait.optional = true
460 maxwait.datatype = "uinteger"
463 s2 = m:section(TypedSection, "alias", translate("IP-Aliases"))
466 s2:depends("interface", arg[1])
467 s2.defaults.interface = arg[1]
469 s2:tab("general", translate("General Setup"))
470 s2.defaults.proto = "static"
472 ip = s2:taboption("general", Value, "ipaddr", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Address"))
474 ip.datatype = "ip4addr"
476 nm = s2:taboption("general", Value, "netmask", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Netmask"))
478 nm.datatype = "ip4addr"
479 nm:value("255.255.255.0")
480 nm:value("255.255.0.0")
481 nm:value("255.0.0.0")
483 gw = s2:taboption("general", Value, "gateway", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Gateway"))
485 gw.datatype = "ip4addr"
488 s2:tab("ipv6", translate("IPv6 Setup"))
490 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"))
492 ip6.datatype = "ip6addr"
494 gw6 = s2:taboption("ipv6", Value, "ip6gw", translate("<abbr title=\"Internet Protocol Version 6\">IPv6</abbr>-Gateway"))
496 gw6.datatype = "ip6addr"
499 s2:tab("advanced", translate("Advanced Settings"))
501 bcast = s2:taboption("advanced", Value, "bcast", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Broadcast"))
502 bcast.optional = true
503 bcast.datatype = "ip4addr"
505 dns = s2:taboption("advanced", Value, "dns", translate("<abbr title=\"Domain Name System\">DNS</abbr>-Server"))
507 dns.datatype = "ip4addr"
510 m2 = Map("dhcp", "", "")
511 function m2.on_parse()
512 local has_section = false
514 m2.uci:foreach("dhcp", "dhcp", function(s)
515 if s.interface == arg[1] then
521 if not has_section then
522 m2.uci:section("dhcp", "dhcp", nil, { interface = arg[1], ignore = "1" })
527 s = m2:section(TypedSection, "dhcp", translate("DHCP Server"))
530 s:tab("general", translate("General Setup"))
531 s:tab("advanced", translate("Advanced Settings"))
533 function s.filter(self, section)
534 return m2.uci:get("dhcp", section, "interface") == arg[1]
537 local ignore = s:taboption("general", Flag, "ignore",
538 translate("Ignore interface"),
539 translate("Disable <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</abbr> for " ..
542 ignore.rmempty = false
544 local start = s:taboption("general", Value, "start", translate("Start"),
545 translate("Lowest leased address as offset from the network address."))
546 start.optional = true
547 start.datatype = "uinteger"
548 start.default = "100"
550 local limit = s:taboption("general", Value, "limit", translate("Limit"),
551 translate("Maximum number of leased addresses."))
552 limit.optional = true
553 limit.datatype = "uinteger"
554 limit.default = "150"
556 local ltime = s:taboption("general", Value, "leasetime", translate("Leasetime"),
557 translate("Expiry time of leased addresses, minimum is 2 Minutes (<code>2m</code>)."))
559 ltime.default = "12h"
561 local dd = s:taboption("advanced", Flag, "dynamicdhcp",
562 translate("Dynamic <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</abbr>"),
563 translate("Dynamically allocate DHCP addresses for clients. If disabled, only " ..
564 "clients having static leases will be served."))
567 function dd.cfgvalue(self, section)
568 return Flag.cfgvalue(self, section) or "1"
571 s:taboption("advanced", Flag, "force", translate("Force"),
572 translate("Force DHCP on this network even if another server is detected."))
574 -- XXX: is this actually useful?
575 --s:taboption("advanced", Value, "name", translate("Name"),
576 -- translate("Define a name for this network."))
578 mask = s:taboption("advanced", Value, "netmask",
579 translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Netmask"),
580 translate("Override the netmask sent to clients. Normally it is calculated " ..
581 "from the subnet that is served."))
584 mask.datatype = "ip4addr"
586 s:taboption("advanced", DynamicList, "dhcp_option", translate("DHCP-Options"),
587 translate("Define additional DHCP options, for example \"<code>6,192.168.2.1," ..
588 "192.168.2.2</code>\" which advertises different DNS servers to clients."))
590 for i, n in ipairs(s.children) do
592 n:depends("ignore", "")