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")
31 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>)."))
39 local net = nw:get_network(arg[1])
41 -- redirect to overview page if network does not exist anymore (e.g. after a revert)
43 luci.http.redirect(luci.dispatcher.build_url("admin/network/network"))
47 local ifc = net:get_interfaces()[1]
49 s = m:section(NamedSection, arg[1], "interface", translate("Common Configuration"))
52 s:tab("general", translate("General Setup"))
53 if has_ipv6 then s:tab("ipv6", translate("IPv6 Setup")) end
54 if has_pppd then s:tab("ppp", translate("PPP Settings")) end
55 if has_pppoa then s:tab("atm", translate("ATM Settings")) end
56 if has_6in4 then s:tab("tunnel", translate("Tunnel Settings")) end
57 s:tab("physical", translate("Physical Settings"))
58 s:tab("firewall", translate("Firewall Settings"))
60 st = s:taboption("general", DummyValue, "__status", translate("Status"))
61 st.template = "admin_network/iface_status"
65 back = s:taboption("general", DummyValue, "_overview", translate("Overview"))
67 back.titleref = luci.dispatcher.build_url("admin", "network", "network")
70 p = s:taboption("general", ListValue, "proto", translate("Protocol"))
71 p.override_scheme = true
73 p:value("static", translate("static"))
74 p:value("dhcp", "DHCP")
75 if has_pppd then p:value("ppp", "PPP") end
76 if has_pppoe then p:value("pppoe", "PPPoE") end
77 if has_pppoa then p:value("pppoa", "PPPoA") end
78 if has_3g then p:value("3g", "UMTS/3G") end
79 if has_pptp then p:value("pptp", "PPTP") end
80 if has_6in4 then p:value("6in4", "6in4") end
81 p:value("none", translate("none"))
83 if not ( has_pppd and has_pppoe and has_pppoa and has_3g and has_pptp ) then
84 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 br = s:taboption("physical", Flag, "type", translate("Bridge interfaces"), translate("creates a bridge over specified interface(s)"))
90 br:depends("proto", "static")
91 br:depends("proto", "dhcp")
92 br:depends("proto", "none")
94 stp = s:taboption("physical", Flag, "stp", translate("Enable <abbr title=\"Spanning Tree Protocol\">STP</abbr>"),
95 translate("Enables the Spanning Tree Protocol on this bridge"))
96 stp:depends("type", "bridge")
99 ifname_single = s:taboption("physical", Value, "ifname_single", translate("Interface"))
100 ifname_single.template = "cbi/network_ifacelist"
101 ifname_single.widget = "radio"
102 ifname_single.nobridges = true
103 ifname_single.network = arg[1]
104 ifname_single.rmempty = true
105 ifname_single:depends({ type = "", proto = "static" })
106 ifname_single:depends({ type = "", proto = "dhcp" })
107 ifname_single:depends({ type = "", proto = "pppoe" })
108 ifname_single:depends({ type = "", proto = "pppoa" })
109 ifname_single:depends({ type = "", proto = "none" })
111 function ifname_single.cfgvalue(self, s)
112 return self.map.uci:get("network", s, "ifname")
115 function ifname_single.write(self, s, val)
116 local n = nw:get_network(s)
119 for _, i in ipairs(n:get_interfaces()) do
123 for i in ut.imatch(val) do
126 -- if this is not a bridge, only assign first interface
127 if self.option == "ifname_single" then
134 ifname_multi = s:taboption("physical", Value, "ifname_multi", translate("Interface"))
135 ifname_multi.template = "cbi/network_ifacelist"
136 ifname_multi.nobridges = true
137 ifname_multi.network = arg[1]
138 ifname_multi.widget = "checkbox"
139 ifname_multi:depends("type", "bridge")
140 ifname_multi.cfgvalue = ifname_single.cfgvalue
141 ifname_multi.write = ifname_single.write
144 local fwd_to, fwd_from
146 fwzone = s:taboption("firewall", Value, "_fwzone",
147 translate("Create / Assign firewall-zone"),
148 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."))
150 fwzone.template = "cbi/firewall_zonelist"
151 fwzone.network = arg[1]
152 fwzone.rmempty = false
154 function fwzone.cfgvalue(self, section)
156 local z = fw:get_zone_by_network(section)
157 return z and z:name()
160 function fwzone.write(self, section, value)
161 local zone = fw:get_zone(value)
163 if not zone and value == '-' then
164 value = m:formvalue(self:cbid(section) .. ".newzone")
165 if value and #value > 0 then
166 zone = fw:add_zone(value)
168 fw:del_network(section)
173 fw:del_network(section)
174 zone:add_network(section)
178 ipaddr = s:taboption("general", Value, "ipaddr", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Address"))
179 ipaddr.optional = true
180 ipaddr.datatype = "ip4addr"
181 ipaddr:depends("proto", "static")
183 nm = s:taboption("general", Value, "netmask", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Netmask"))
185 nm.datatype = "ip4addr"
186 nm:depends("proto", "static")
187 nm:value("255.255.255.0")
188 nm:value("255.255.0.0")
189 nm:value("255.0.0.0")
191 gw = s:taboption("general", Value, "gateway", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Gateway"))
193 gw.datatype = "ip4addr"
194 gw:depends("proto", "static")
196 bcast = s:taboption("general", Value, "bcast", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Broadcast"))
197 bcast.optional = true
198 bcast.datatype = "ip4addr"
199 bcast:depends("proto", "static")
202 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"))
203 ip6addr.optional = true
204 ip6addr.datatype = "ip6addr"
205 ip6addr:depends("proto", "static")
206 ip6addr:depends("proto", "6in4")
208 ip6gw = s:taboption("ipv6", Value, "ip6gw", translate("<abbr title=\"Internet Protocol Version 6\">IPv6</abbr>-Gateway"))
209 ip6gw.optional = true
210 ip6gw.datatype = "ip6addr"
211 ip6gw:depends("proto", "static")
214 dns = s:taboption("general", DynamicList, "dns", translate("<abbr title=\"Domain Name System\">DNS</abbr>-Server"),
215 translate("You can specify multiple DNS servers here, press enter to add a new entry. Servers entered here will override " ..
216 "automatically assigned ones."))
220 dns.datatype = "ipaddr"
221 dns:depends("peerdns", "")
223 mtu = s:taboption("physical", Value, "mtu", "MTU")
225 mtu.datatype = "uinteger"
226 mtu.placeholder = 1500
228 srv = s:taboption("general", Value, "server", translate("<abbr title=\"Point-to-Point Tunneling Protocol\">PPTP</abbr>-Server"))
229 srv:depends("proto", "pptp")
231 srv.datatype = "ip4addr"
234 peer = s:taboption("general", Value, "peeraddr", translate("Server IPv4-Address"))
235 peer.optional = false
236 peer.datatype = "ip4addr"
237 peer:depends("proto", "6in4")
239 ttl = s:taboption("physical", Value, "ttl", translate("TTL"))
242 ttl.datatype = "uinteger"
243 ttl:depends("proto", "6in4")
246 mac = s:taboption("physical", Value, "macaddr", translate("<abbr title=\"Media Access Control\">MAC</abbr>-Address"))
247 mac:depends("proto", "none")
248 mac:depends("proto", "static")
249 mac:depends("proto", "dhcp")
250 mac.placeholder = ifc and ifc:mac():upper()
253 service = s:taboption("general", ListValue, "service", translate("Service type"))
254 service:value("", translate("-- Please choose --"))
255 service:value("umts", "UMTS/GPRS")
256 service:value("cdma", "CDMA")
257 service:value("evdo", "EV-DO")
258 service:depends("proto", "3g")
259 service.rmempty = true
261 apn = s:taboption("general", Value, "apn", translate("Access point (APN)"))
262 apn:depends("proto", "3g")
264 pincode = s:taboption("general", Value, "pincode",
265 translate("PIN code"),
266 translate("Make sure that you provide the correct pin code here or you might lock your sim card!")
268 pincode:depends("proto", "3g")
272 tunid = s:taboption("general", Value, "tunnelid", translate("HE.net Tunnel ID"))
273 tunid.optional = true
274 tunid.datatype = "uinteger"
275 tunid:depends("proto", "6in4")
278 if has_pppd or has_pppoe or has_pppoa or has_3g or has_pptp or has_6in4 then
279 user = s:taboption("general", Value, "username", translate("Username"))
281 user:depends("proto", "pptp")
282 user:depends("proto", "pppoe")
283 user:depends("proto", "pppoa")
284 user:depends("proto", "ppp")
285 user:depends("proto", "3g")
286 user:depends("proto", "6in4")
288 pass = s:taboption("general", Value, "password", translate("Password"))
291 pass:depends("proto", "pptp")
292 pass:depends("proto", "pppoe")
293 pass:depends("proto", "pppoa")
294 pass:depends("proto", "ppp")
295 pass:depends("proto", "3g")
296 pass:depends("proto", "6in4")
299 if has_pppd or has_pppoe or has_pppoa or has_3g or has_pptp then
300 ka = s:taboption("ppp", Value, "keepalive",
301 translate("Keep-Alive"),
302 translate("Number of failed connection tests to initiate automatic reconnect")
304 ka:depends("proto", "pptp")
305 ka:depends("proto", "pppoe")
306 ka:depends("proto", "pppoa")
307 ka:depends("proto", "ppp")
308 ka:depends("proto", "3g")
310 demand = s:taboption("ppp", Value, "demand",
311 translate("Automatic Disconnect"),
312 translate("Time (in seconds) after which an unused connection will be closed")
314 demand.optional = true
315 demand.datatype = "uinteger"
316 demand:depends("proto", "pptp")
317 demand:depends("proto", "pppoe")
318 demand:depends("proto", "pppoa")
319 demand:depends("proto", "ppp")
320 demand:depends("proto", "3g")
324 encaps = s:taboption("atm", ListValue, "encaps", translate("PPPoA Encapsulation"))
325 encaps:depends("proto", "pppoa")
326 encaps:value("vc", "VC-Mux")
327 encaps:value("llc", "LLC")
329 atmdev = s:taboption("atm", Value, "atmdev", translate("ATM device number"))
330 atmdev:depends("proto", "pppoa")
332 atmdev.datatype = "uinteger"
334 vci = s:taboption("atm", Value, "vci", translate("ATM Virtual Channel Identifier (VCI)"))
335 vci:depends("proto", "pppoa")
337 vci.datatype = "uinteger"
339 vpi = s:taboption("atm", Value, "vpi", translate("ATM Virtual Path Identifier (VPI)"))
340 vpi:depends("proto", "pppoa")
342 vpi.datatype = "uinteger"
345 if has_pptp or has_pppd or has_pppoe or has_pppoa or has_3g then
346 device = s:taboption("general", Value, "device",
347 translate("Modem device"),
348 translate("The device node of your modem, e.g. /dev/ttyUSB0")
350 device:depends("proto", "ppp")
351 device:depends("proto", "3g")
353 defaultroute = s:taboption("ppp", Flag, "defaultroute",
354 translate("Replace default route"),
355 translate("Let pppd replace the current default route to use the PPP interface after successful connect")
357 defaultroute:depends("proto", "ppp")
358 defaultroute:depends("proto", "pppoa")
359 defaultroute:depends("proto", "pppoe")
360 defaultroute:depends("proto", "pptp")
361 defaultroute:depends("proto", "3g")
362 defaultroute.rmempty = false
363 function defaultroute.cfgvalue(...)
364 return ( AbstractValue.cfgvalue(...) or '1' )
367 peerdns = s:taboption("ppp", Flag, "peerdns",
368 translate("Use peer DNS"),
369 translate("Configure the local DNS server to use the name servers adverticed by the PPP peer")
371 peerdns:depends("proto", "ppp")
372 peerdns:depends("proto", "pppoa")
373 peerdns:depends("proto", "pppoe")
374 peerdns:depends("proto", "pptp")
375 peerdns:depends("proto", "3g")
376 peerdns.rmempty = false
377 function peerdns.cfgvalue(...)
378 return ( AbstractValue.cfgvalue(...) or '1' )
382 ipv6 = s:taboption("ppp", Flag, "ipv6", translate("Enable IPv6 on PPP link") )
383 ipv6:depends("proto", "ppp")
384 ipv6:depends("proto", "pppoa")
385 ipv6:depends("proto", "pppoe")
386 ipv6:depends("proto", "pptp")
387 ipv6:depends("proto", "3g")
390 connect = s:taboption("ppp", Value, "connect",
391 translate("Connect script"),
392 translate("Let pppd run this script after establishing the PPP link")
394 connect:depends("proto", "ppp")
395 connect:depends("proto", "pppoe")
396 connect:depends("proto", "pppoa")
397 connect:depends("proto", "pptp")
398 connect:depends("proto", "3g")
400 disconnect = s:taboption("ppp", Value, "disconnect",
401 translate("Disconnect script"),
402 translate("Let pppd run this script before tearing down the PPP link")
404 disconnect:depends("proto", "ppp")
405 disconnect:depends("proto", "pppoe")
406 disconnect:depends("proto", "pppoa")
407 disconnect:depends("proto", "pptp")
408 disconnect:depends("proto", "3g")
410 pppd_options = s:taboption("ppp", Value, "pppd_options",
411 translate("Additional pppd options"),
412 translate("Specify additional command line arguments for pppd here")
414 pppd_options:depends("proto", "ppp")
415 pppd_options:depends("proto", "pppoa")
416 pppd_options:depends("proto", "pppoe")
417 pppd_options:depends("proto", "pptp")
418 pppd_options:depends("proto", "3g")
420 maxwait = s:taboption("ppp", Value, "maxwait",
421 translate("Setup wait time"),
422 translate("Seconds to wait for the modem to become ready before attempting to connect")
424 maxwait:depends("proto", "3g")
425 maxwait.default = "0"
426 maxwait.optional = true
427 maxwait.datatype = "uinteger"
430 s2 = m:section(TypedSection, "alias", translate("IP-Aliases"))
433 s2:depends("interface", arg[1])
434 s2.defaults.interface = arg[1]
436 s2:tab("general", translate("General Setup"))
437 s2.defaults.proto = "static"
439 ip = s2:taboption("general", Value, "ipaddr", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Address"))
441 ip.datatype = "ip4addr"
443 nm = s2:taboption("general", Value, "netmask", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Netmask"))
445 nm.datatype = "ip4addr"
446 nm:value("255.255.255.0")
447 nm:value("255.255.0.0")
448 nm:value("255.0.0.0")
450 gw = s2:taboption("general", Value, "gateway", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Gateway"))
452 gw.datatype = "ip4addr"
455 s2:tab("ipv6", translate("IPv6 Setup"))
457 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"))
459 ip6.datatype = "ip6addr"
461 gw6 = s2:taboption("ipv6", Value, "ip6gw", translate("<abbr title=\"Internet Protocol Version 6\">IPv6</abbr>-Gateway"))
463 gw6.datatype = "ip6addr"
466 s2:tab("advanced", translate("Advanced Settings"))
468 bcast = s2:taboption("advanced", Value, "bcast", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Broadcast"))
469 bcast.optional = true
470 bcast.datatype = "ip4addr"
472 dns = s2:taboption("advanced", Value, "dns", translate("<abbr title=\"Domain Name System\">DNS</abbr>-Server"))
474 dns.datatype = "ip4addr"
477 m2 = Map("dhcp", "", "")
478 function m2.on_parse()
479 local has_section = false
481 m2.uci:foreach("dhcp", "dhcp", function(s)
482 if s.interface == arg[1] then
488 if not has_section then
489 m2.uci:section("dhcp", "dhcp", nil, { interface = arg[1], ignore = "1" })
494 s = m2:section(TypedSection, "dhcp", translate("DHCP Server"))
497 s:tab("general", translate("General Setup"))
498 s:tab("advanced", translate("Advanced Settings"))
500 function s.filter(self, section)
501 return m2.uci:get("dhcp", section, "interface") == arg[1]
504 local ignore = s:taboption("general", Flag, "ignore",
505 translate("Ignore interface"),
506 translate("Disable <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</abbr> for " ..
509 ignore.rmempty = false
511 local start = s:taboption("general", Value, "start", translate("Start"),
512 translate("Lowest leased address as offset from the network address."))
513 start.optional = true
514 start.datatype = "uinteger"
515 start.default = "100"
517 local limit = s:taboption("general", Value, "limit", translate("Limit"),
518 translate("Maximum number of leased addresses."))
519 limit.optional = true
520 limit.datatype = "uinteger"
521 limit.default = "150"
523 local ltime = s:taboption("general", Value, "leasetime", translate("Leasetime"),
524 translate("Expiry time of leased addresses, minimum is 2 Minutes (<code>2m</code>)."))
526 ltime.default = "12h"
528 local dd = s:taboption("advanced", Flag, "dynamicdhcp",
529 translate("Dynamic <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</abbr>"),
530 translate("Dynamically allocate DHCP addresses for clients. If disabled, only " ..
531 "clients having static leases will be served."))
534 function dd.cfgvalue(self, section)
535 return Flag.cfgvalue(self, section) or "1"
538 s:taboption("advanced", Flag, "force", translate("Force"),
539 translate("Force DHCP on this network even if another server is detected."))
541 -- XXX: is this actually useful?
542 --s:taboption("advanced", Value, "name", translate("Name"),
543 -- translate("Define a name for this network."))
545 mask = s:taboption("advanced", Value, "netmask",
546 translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Netmask"),
547 translate("Override the netmask sent to clients. Normally it is calculated " ..
548 "from the subnet that is served."))
551 mask.datatype = "ip4addr"
553 s:taboption("advanced", DynamicList, "dhcp_option", translate("DHCP-Options"),
554 translate("Define additional DHCP options, for example \"<code>6,192.168.2.1," ..
555 "192.168.2.2</code>\" which advertises different DNS servers to clients."))
557 for i, n in ipairs(s.children) do
559 n:depends("ignore", "")