2 -- $Id: network.lua,v 1.10 2005/03/27 01:19:41 cpressey Exp $
3 -- Lua abstraction for the Network Interfaces of a system.
5 -- BEGIN lib/network.lua --
10 --[[------------------]]--
11 --[[ NetworkInterface ]]--
12 --[[------------------]]--
15 -- This class returns an object which represents one of the system's
16 -- network interfaces.
18 -- This class is not typically instantiated directly by client code.
19 -- Instead, the user should call NetworkInterface.all() to get a table
20 -- of all network interfaces present in the system, and choose one.
23 NetworkInterface.new = function(name)
24 local ni = {} -- instance variable
25 local desc = name -- description of device
26 local up -- internal state...
28 local inet6, prefixlen, scopeid
29 local inet, netmask, broadcast
32 local toboolean = function(x)
41 -- Probe this network interface for its current state.
43 -- dc0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
44 -- inet6 fe80::250:bfff:fe96:cf68%dc0 prefixlen 64 scopeid 0x1
45 -- inet 10.0.0.19 netmask 0xffffff00 broadcast 10.0.0.255
46 -- ether 00:50:bf:96:cf:68
47 -- media: Ethernet autoselect (10baseT/UTP)
49 ni.probe = function(ni)
50 local found, len, cap, flagstring
55 inet6, prefixlen, scopeid = nil, nil, nil
56 inet, netmask, broadcast = nil, nil, nil
58 pty = Pty.open(App.expand("${root}${IFCONFIG} ${name}", { name = name }))
60 return nil, "could not open pty"
64 found, len, cap, flagstring =
65 string.find(line, "flags%s*=%s*(%d+)%s*%<([^%>]*)%>")
67 flagstring = "," .. flagstring .. ","
68 up = toboolean(string.find(flagstring, ",UP,"))
71 found, len, cap = string.find(line, "mtu%s*(%d+)")
75 found, len, cap = string.find(line, "inet6%s*([^%s]+)")
79 found, len, cap = string.find(line, "prefixlen%s*(%d+)")
81 prefixlen = tonumber(cap)
83 found, len, cap = string.find(line, "scopeid%s*0x(%x+)")
87 found, len, cap = string.find(line, "inet%s*(%d+%.%d+%.%d+%.%d+)")
91 found, len, cap = string.find(line, "netmask%s*0x(%x+)")
95 found, len, cap = string.find(line, "broadcast%s*(%d+%.%d+%.%d+%.%d+)")
99 found, len, cap = string.find(line, "ether%s*(%x%x%:%x%x%:%x%x%:%x%x%:%x%x%:%x%x%)")
103 line = pty:readline()
112 ni.is_up = function(ni)
116 ni.get_name = function(ni)
120 ni.get_inet_addr = function(ni)
124 ni.get_netmask = function(ni)
128 ni.get_broadcast_addr = function(ni)
132 ni.get_ether_addr = function(ni)
136 ni.get_desc = function(ni)
140 ni.set_desc = function(ni, new_desc)
142 -- Calculate a score for how well this string describes
143 -- a network interface. Reject obviously bogus descriptions
144 -- (usually harvested from error messages in dmesg.)
146 local calculate_score = function(s)
149 -- In the absence of any good discriminator,
150 -- the longest description wins.
151 score = string.len(s)
154 if string.find(s, "%<.*%>") then
158 -- Look for irrelevancies
159 if string.find(s, "MII bus") then
166 if calculate_score(new_desc) > calculate_score(desc) then
172 -- Set the description of a device, as best we can, based on
173 -- the available system information.
175 ni.auto_describe = function(ni)
177 -- First give some common pseudo-devices some
178 -- reasonable 'canned' descriptions.
181 ["ppp%d+"] = "Point-to-Point Protocol device",
182 ["sl%d+"] = "Serial Line IP device",
183 ["faith%d+"] = "IPv6-to-IPv4 Tunnel device",
184 ["lp%d+"] = "Network Line Printer device",
185 ["lo%d+"] = "Loopback device"
187 for pat, desc in descs do
188 if string.find(name, "^" .. pat .. "$") then
189 ni:set_desc(name .. ": " .. desc)
194 -- Now look through dmesg.boot for the names of
195 -- physical network interface hardware.
197 for line in io.lines("/var/run/dmesg.boot") do
198 local found, len, cap =
199 string.find(line, "^" .. name .. ":.*(%<.*%>).*$")
201 ni:set_desc(name .. ": " .. cap)
207 -- CmdChain-creating methods.
210 ni.cmds_assign_inet_addr = function(ni, cmds, addr)
212 cmdline = "${root}${IFCONFIG} ${name} ${addr}",
220 ni.cmds_assign_netmask = function(ni, cmds, netmask)
222 cmdline = "${root}${IFCONFIG} ${name} netmask ${netmask}",
230 ni.cmds_dhcp_configure = function(ni, cmds)
233 cmdline = "${root}${KILLALL} dhclient",
234 failure_mode = CmdChain.FAILURE_IGNORE
237 cmdline = "${root}${DHCLIENT} -1 ${name}",
248 --[[-------------------]]--
249 --[[ NetworkInterfaces ]]--
250 --[[-------------------]]--
253 -- A container/aggregate class. Contains a bunch of NetworkInterface
254 -- objects, typically the set of those available on a given system.
257 NetworkInterfaces = {}
259 NetworkInterfaces.new = function()
263 method.add = function(nis)
267 method.get = function(nis, name)
271 -- Iterator, typically used in for loops.
272 method.each = function(nis)
277 for name, ni in ni_tab do
278 table.insert(list, ni)
282 table.sort(list, function(a, b)
283 return a:get_name() < b:get_name()
295 -- Populate the NetworkInterface collection with all the
296 -- network interfaces detected as present in the system.
298 method.probe = function(nis)
299 local pty, line, name, ni, line, pat, desc
301 pty = Pty.open(App.expand("${root}${IFCONFIG} -l"))
303 return nil, "could not open pty"
305 line = pty:readline()
310 for name in string.gfind(line, "%s*([^%s]+)%s*") do
311 ni = NetworkInterface.new(name)
321 -- Returns the number of configured IP addresses of all the
322 -- NetworkInterface objects in this NetworkInterfaces object.
324 -- Practically, used for asking "Uh, is the network on?" :)
326 method.ip_addr_count = function(nis)
330 for name, ni in ni_tab do
331 ip_addr = ni:get_inet_addr()
332 if ip_addr and not string.find(ip_addr, "^127%..*$") then
341 -- User-interface methods.
345 -- Display a dialog box, allow the user to select which
346 -- network interface they want to use.
348 method.ui_select_interface = function(nis, tab)
349 local actions, ni, ifname
350 if not tab then tab = {} end
351 local ui = tab.ui or App.ui
352 local id = tab.id or "select_interface"
353 local name = tab.name or _("Select Network Interface")
354 local short_desc = tab.short_desc or _(
355 "Please select the network interface you wish to configure."
359 -- Get interface list.
362 for ni in nis:each() do
363 table.insert(actions, {
368 table.insert(actions, {
373 ifname = App.ui:present({
376 short_desc = short_desc,
381 if ifname == "cancel" then
384 return nis:get(ifname)
391 -- END of lib/network.lua --