Hidden interfaces, last-seen pings, activity by subnet

- interfaces.exclude in steward.yaml (names or shell patterns) leaves
  interfaces out of GET /interfaces, the web UI's picker and
  'steward interface list'. Subnets on them are still served.
- With the ping check on, active leases are pinged every minute; a
  client that answers gets a last-seen time (leases.last_seen,
  migration 4). Not answering never takes a client offline.
- The activity log filters by subnet (--subnet, the Activity page,
  GET /events?subnet=).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
abrown38andClaude Opus 5.5 committed 2026-10-18 17:50:21 +01:00
1 parent 6ad1bb9a0d
commit 5e6c61cc8e
31 files changed
+358 -39

No files matched your search

+3 -1
View File
@@ -290,7 +290,9 @@ func (s *Server) ack(ctx context.Context, cfg *config, iface string, p *dhcp4.Pa
return s.nak(cfg, iface, p, sub, why)
}
start, host := now, p.HostName()
var seen *time.Time
if l := s.leases[ip]; l != nil && l.Owns(cl.mac, cl.id) {
seen = l.LastSeen
if l.ActiveAt(now) {
start = l.Start
}
@@ -300,7 +302,7 @@ func (s *Server) ack(ctx context.Context, cfg *config, iface string, p *dhcp4.Pa
}
}
l := &model.Lease{IP: ip, SubnetID: sub.ID, MAC: cl.mac, ClientID: cl.id, Hostname: host, State: model.LeaseActive,
Start: start, End: now.Add(sub.leaseTime), Interface: iface}
Start: start, End: now.Add(sub.leaseTime), Interface: iface, LastSeen: seen}
err := s.putLease(ctx, l)
delete(s.offers, ip)
s.mu.Unlock()