#!/usr/bin/lua local util = require("luci.util") local fs = require("luci.fs") local ltn12 = require 'luci.ltn12' local sys = require("luci.sys") local json = require("luci.json") local nixio = require 'nixio' local platform_info = require("platform_info") local hostname = sys.hostname() local model = platform_info.get_model() local release = util.trim(fs.readfile("/lib/gluon/release") or "") function escape_html(s) return (s:gsub('&', '&'):gsub('<', '<'):gsub('>', '>'):gsub('"', '"')) end function neighbours(ifname) local info = util.exec("gluon-neighbour-info -d ff02::2:1001 -p 1001 -r nodeinfo -t 3 -i " .. ifname) local macs = {} for _, line in ipairs(util.split(info)) do local data = json.decode(line) if data then if data["network"] and data["network"]["mesh_interfaces"] then for _, mac in ipairs(data["network"]["mesh_interfaces"]) do macs[mac] = data end end end end return macs end io.write("Content-type: text/html\n\n") io.write("\n") io.write("") io.write("") io.write("") io.write("" .. escape_html(hostname) .. "") io.write("") io.write("") io.write("

" .. escape_html(hostname) .. "

") io.write("
")

io.write("Model: " .. escape_html(model) .. "\n")
io.write("Firmware release: " .. escape_html(release) .. "\n\n")

io.write(escape_html(util.trim(sys.exec("uptime | sed 's/^ \+//'"))) .. "\n\n")
io.write(escape_html(sys.exec("ip address show dev br-client")) .. "\n")
io.write(escape_html(sys.exec("free -m")) .. "\n")
io.write(escape_html(sys.exec("df /rom /overlay")))
io.write("
") io.write("

Neighbours

") local interfaces = util.split(util.trim(util.exec("iw dev | grep IBSS -B 5 | grep Interface | cut -d' ' -f2"))) for _, ifname in ipairs(interfaces) do io.write("

" .. escape_html(ifname) .. "

") io.write("
")

  io.write(escape_html(sys.exec("iw dev " .. ifname .. " link")) .. "\n")

  for _, line in ipairs(util.split(util.exec("iw dev " .. ifname .. " station dump"))) do
    local mac = line:match("^Station (.*) %(on ")
    if mac then
      io.write("Station " .. mac .. " (on " .. escape_html(ifname) .. ")\n")
    else
      io.write(escape_html(line) .. "\n")
    end
  end

  io.write("
") end local err, fastd_status = pcall( function() local fastd_sock = nixio.socket('unix', 'stream') assert(fastd_sock:connect('/var/run/fastd.mesh_vpn.socket')) -- Stop as soon as we see an empty chunk local function guard_source(src) return function() local chunk, err = src() if not chunk then return nil, err end if chunk:len() == 0 then return nil end return chunk end end source = guard_source(ltn12.source.file(fastd_sock)) decoder = json.Decoder() ltn12.pump.all(source, decoder:sink()) fastd_sock:close() return decoder:get() end ) io.write("

VPN status

") io.write("
")

if fastd_status then
  io.write(string.format("fastd running for %.3f seconds\n", fastd_status.uptime/1000))

  local peers = 0
  local connections = 0

  for key, peer in pairs(fastd_status.peers) do
    peers = peers+1

    if peer.connection then
      connections = connections+1
    end
  end

  io.write(string.format("There are %i peers configured, of which %i are connected:\n\n", peers, connections))

  for key, peer in pairs(fastd_status.peers) do
    io.write(string.format("%s: ", escape_html(peer.name)))

    if peer.connection then
      io.write(string.format("connected for %.3f seconds\n", peer.connection.established/1000))
    else
      io.write("not connected\n")
    end
  end

else
  io.write("fastd not running")
end

io.write("
") io.write("") io.write("") io.write("")