luci-base: add luci.sys.net.host_hints() and regenerate documentation
[project/luci.git] / modules / luci-base / luasrc / sys.lua
index 77f4d44..5d203aa 100644 (file)
@@ -292,48 +292,74 @@ function net.ipv6_hints(callback)
        end
 end
 
+function net.host_hints(callback)
+       if callback then
+               _nethints(1, function(mac, v4, v6, name)
+                       if mac and mac ~= "00:00:00:00:00:00" and (v4 or v6 or name) then
+                               callback(mac, v4, v6, name)
+                       end
+               end)
+       else
+               local rv = { }
+               _nethints(1, function(mac, v4, v6, name)
+                       if mac and mac ~= "00:00:00:00:00:00" and (v4 or v6 or name) then
+                               local e = { }
+                               if v4   then e.ipv4 = v4   end
+                               if v6   then e.ipv6 = v6   end
+                               if name then e.name = name end
+                               rv[mac] = e
+                       end
+               end)
+               return rv
+       end
+end
+
 function net.conntrack(callback)
-       local connt = {}
-       if fs.access("/proc/net/nf_conntrack", "r") then
-               for line in io.lines("/proc/net/nf_conntrack") do
-                       line = line:match "^(.-( [^ =]+=).-)%2"
-                       local entry, flags = _parse_mixed_record(line, " +")
-                       if flags[6] ~= "TIME_WAIT" then
-                               entry.layer3 = flags[1]
-                               entry.layer4 = flags[3]
-                               for i=1, #entry do
-                                       entry[i] = nil
-                               end
+       local ok, nfct = pcall(io.lines, "/proc/net/nf_conntrack")
+       if not ok or not nfct then
+               return nil
+       end
 
-                               if callback then
-                                       callback(entry)
-                               else
-                                       connt[#connt+1] = entry
+       local line, connt = nil, (not callback) and { }
+       for line in nfct do
+               local fam, l3, l4, timeout, state, tuples =
+                       line:match("^(ipv[46]) +(%d+) +%S+ +(%d+) +(%d+) +([A-Z_]+) +(.+)$")
+
+               if fam and l3 and l4 and timeout and state and tuples and
+                  state ~= "TIME_WAIT"
+               then
+                       l4 = nixio.getprotobynumber(l4)
+
+                       local entry = {
+                               bytes = 0,
+                               packets = 0,
+                               layer3 = fam,
+                               layer4 = l4 and l4.name or "unknown",
+                               timeout = tonumber(timeout, 10)
+                       }
+
+                       local key, val
+                       for key, val in tuples:gmatch("(%w+)=(%S+)") do
+                               if key == "bytes" or key == "packets" then
+                                       entry[key] = entry[key] + tonumber(val, 10)
+                               elseif key == "src" or key == "dst" or key == "sport" or key == "dport" then
+                                       if entry[key] == nil then
+                                               entry[key] = val
+                                       end
+                               elseif val then
+                                       entry[key] = val
                                end
                        end
-               end
-       elseif fs.access("/proc/net/ip_conntrack", "r") then
-               for line in io.lines("/proc/net/ip_conntrack") do
-                       line = line:match "^(.-( [^ =]+=).-)%2"
-                       local entry, flags = _parse_mixed_record(line, " +")
-                       if flags[4] ~= "TIME_WAIT" then
-                               entry.layer3 = "ipv4"
-                               entry.layer4 = flags[1]
-                               for i=1, #entry do
-                                       entry[i] = nil
-                               end
 
-                               if callback then
-                                       callback(entry)
-                               else
-                                       connt[#connt+1] = entry
-                               end
+                       if callback then
+                               callback(entry)
+                       else
+                               connt[#connt+1] = entry
                        end
                end
-       else
-               return nil
        end
-       return connt
+
+       return callback and true or connt
 end
 
 function net.devices()
@@ -655,28 +681,3 @@ end
 function init.stop(name)
        return (init_action("stop", name) == 0)
 end
-
-
--- Internal functions
-
-function _parse_mixed_record(cnt, delimiter)
-       delimiter = delimiter or "  "
-       local data = {}
-       local flags = {}
-
-       for i, l in pairs(luci.util.split(luci.util.trim(cnt), "\n")) do
-               for j, f in pairs(luci.util.split(luci.util.trim(l), delimiter, nil, true)) do
-                       local k, x, v = f:match('([^%s][^:=]*) *([:=]*) *"*([^\n"]*)"*')
-
-                       if k then
-                               if x == "" then
-                                       table.insert(flags, k)
-                               else
-                                       data[k] = v
-                               end
-                       end
-               end
-       end
-
-       return data, flags
-end