Commit Graph
3 Commits
Author SHA1 Message Date
bobbanandClaude Sonnet 5.5 22cfdbede0 Fix how the audit log displays entries; record admin-link and domain checks
Entries were stored in UTC without a zone marker and the Audit and
Diagnostic Log pages read them as local time, so every entry showed
shifted by the viewer's UTC offset (two hours early in Sweden). A shared
parseDbTimestamp() now reads them as UTC, and replaces the inline
workaround the Consistency page had.

The Audit Log never displayed an entry's details at all, so adding an
admin link showed only "server #1". Link entries now carry the server
name and the label/URL, and a new Details column shows them, along with
things like a port scan's address and range. Entries made within the
same second are now ordered by id instead of arbitrarily.

A domain's "Check now" was the one user-triggered action that wasn't
audited; it is now.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 22:40:35 +02:00
bobbanandClaude Sonnet 5 3f2b5da7be Let the consistency report exclude address ranges
Docker reuses the same subnet on many hosts, and those networks aren't
part of the LAN, so they show up as conflicts and unlisted addresses. The
report only knew about 172.16.0.0/12 through a hardcoded rule; Docker can
just as well pick 192.168.x or 10.x.

The Consistency page now has an Excluded ranges card: CIDR ranges (IPv4
or IPv6) and single addresses, added with a form and removed with one
click, shown to everyone and editable by operators. There's also an
"Exclude range" button on each finding that pre-fills a /24 (or /64) around
its address to edit. Exclusions are applied to servers, IPAM and DNS
before anything is compared, so an excluded address never appears in any
kind of finding, whichever source it came from, and the card says how many
addresses are currently being hidden so it's clear the filter is doing
something.

The old hardcoded rule becomes a visible default (172.16.0.0/12) that can
be removed -- it was silently wrong for anyone using 172.16/12 as a real
LAN. That default is also slightly stronger than before: an address in the
range is now left out even if it is in IPAM or DNS, where the old rule only
skipped it when nothing else mentioned it. Remove or narrow it if that
isn't wanted.

Ranges are validated and normalised on the server (both families, prefix
bounds, no /0, at most 50), a bad one is rejected with a message naming it
and nothing is saved, and changes are audit-logged with before/after.
Matching uses Node's BlockList. Stored as a settings value; managed from
the report rather than admin-only Settings, like ignoring a finding.

Verified with 44 checks (range parsing and rejection, boundary addresses
just inside and outside a range, IPv6, single addresses, exclusion across
all sources and finding kinds, the hidden-address count, route
validation/roles/audit) and in a browser against the real router: add,
invalid, remove the default, exclude from a finding. Real dev database
mtime untouched.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-26 18:57:28 +02:00
bobbanandClaude Sonnet 5 2352689fd3 Add a consistency report across IPAM, DNS and servers
New Consistency page listing where the three places this app records
what lives at an address disagree:
- Address conflicts: the same address reported by more than one server.
- DNS out of date: a record named after a server (its hostname, or its
  short name) that points at an address the server doesn't report.
- IPAM out of date: an entry labelled with a server's name at an
  address the server doesn't report.
- Not in IPAM: addresses a server reports or DNS points at that IPAM
  doesn't list, merged into one finding per address, with a one-click
  "Add to IPAM" that pre-fills a label.
- No DNS record: server LAN addresses no cached A/AAAA record resolves to.

It compares data the app already holds and fetches nothing when opened,
so the page states how many servers had reported addresses and how many
DNS zones are synced (and how old the oldest sync is) -- DNS records are
only cached for zones that have been synced, and a report that silently
treated missing data as "no records" would mislead.

Rules chosen to keep it from crying wolf:
- Only private addresses are compared; public DNS records aren't expected
  to be in IPAM.
- Servers with no reported addresses are never judged.
- Agents report IPv4 only, so records are only compared within an address
  family (an AAAA record isn't "stale" for lacking an IPv6 address).
- Docker bridge networks (172.16/12) are ignored: shared ones aren't
  conflicts, and they aren't listed unless someone put them in DNS.
- Tailscale addresses don't need DNS records (MagicDNS), and IPAM entries
  kept current by the Tailscale/Proxmox syncs aren't second-guessed.

Findings anyone has decided are fine can be ignored (operators) with a
reason. An ignore is keyed on the finding's stable identity so it stays
ignored across runs, its stored text comes from the finding rather than
the request, and it is marked "no longer occurring" once the condition
goes away. Ignore/restore are audit-logged.

New table consistency_ignores (migration 0012). portScan's private-address
helper is now exported and shared.

Verified with 36 checks (each rule and its exclusions, address-family and
case/trailing-dot handling, IPv6 case, ordering, stable keys, the report
route including a garbled agent report, source counts, ignore/unignore
rules and audit entries) and by driving the page against the real routers
in a browser: Add to IPAM actually created the entry, ignore and restore,
severity filter, "show all", the viewer view, and narrow-width layout
(which found and fixed a squeezed badge and clipped buttons). Real dev
database mtime untouched.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-26 04:08:51 +02:00