diff --git a/cockpit/vanrouter/vanrouter.js b/cockpit/vanrouter/vanrouter.js
index 02de422..e28e94b 100644
--- a/cockpit/vanrouter/vanrouter.js
+++ b/cockpit/vanrouter/vanrouter.js
@@ -51,7 +51,28 @@ async function readAP(a) {
return { band: a.band, unit: a.unit, active, ssid, chan, width, stations };
}
-function renderAPs(aps) {
+async function readClientDir() {
+ // MAC -> { ip, host } for AP clients. Kernel neighbor table first (covers
+ // static-IP clients), then dnsmasq leases on top (authoritative + hostname).
+ const dir = {};
+ try {
+ JSON.parse(await run(["ip", "-j", "neigh", "show", "dev", "br0"])).forEach(n => {
+ if (n.lladdr && n.dst && !n.dst.includes(":")) // IPv4 only
+ dir[n.lladdr.toLowerCase()] = { ip: n.dst, host: null };
+ });
+ } catch (e) { /* ignore */ }
+ try {
+ // lease line:
+ (await run(["cat", "/var/lib/misc/dnsmasq.leases"])).trim().split("\n").forEach(l => {
+ const f = l.split(" ");
+ if (f.length >= 4)
+ dir[f[1].toLowerCase()] = { ip: f[2], host: f[3] === "*" ? null : f[3] };
+ });
+ } catch (e) { /* ignore */ }
+ return dir;
+}
+
+function renderAPs(aps, dir) {
const el = document.getElementById("ap");
el.innerHTML = "";
aps.forEach(ap => {
@@ -68,9 +89,11 @@ function renderAPs(aps) {
`
`;
if (ap.stations.length) {
- html += `| MAC | Signal | TX rate |
`;
+ html += `| MAC | IP | Hostname | Signal | TX rate |
`;
ap.stations.forEach(s => {
- html += `| ${esc(s.mac)} | ${esc(s.sig || "?")} dBm | ${esc(s.tx || "?")} |
`;
+ const c = dir[s.mac.toLowerCase()] || {};
+ html += `| ${esc(s.mac)} | ${esc(c.ip || "—")} | ${esc(c.host || "—")} | ` +
+ `${esc(s.sig || "?")} dBm | ${esc(s.tx || "?")} |
`;
});
html += `
`;
}
@@ -279,9 +302,9 @@ async function restartAP(unit) {
async function refresh() {
try {
- const [aps, th, bat, fo, wan] = await Promise.all([
- Promise.all(APS.map(readAP)), readThermal(), readBattery(), readFailover(), readWAN()]);
- renderAPs(aps);
+ const [aps, dir, th, bat, fo, wan] = await Promise.all([
+ Promise.all(APS.map(readAP)), readClientDir(), readThermal(), readBattery(), readFailover(), readWAN()]);
+ renderAPs(aps, dir);
renderThermal(th);
renderBattery(bat);
renderFailover(fo);