Skip to content

v2.0.0

Choose a tag to compare

@Ashteeer Ashteeer released this 09 Aug 18:48
· 1 commit to main since this release

Breaking change. v1.0.0 implemented the spec wrong: it wrote a text file of ip:sha256hash pairs. The list "formatted as ip:hash" is an ipset set of type hash:ip — the kernel facility. v2.0.0 is that.

The app now writes no files at all. The kernel set is the storage.

How it works

ipset -exist restore   <<<   create dns_clients hash:ip family inet hashsize 1024 maxelem 65536 timeout 10800
                             add dns_clients 192.168.1.5 timeout 10800
  • Every incoming DNS request on every transport protocol is intercepted through the official IDnsRequestController interface — UDP, TCP, DoT (Tls), DoH and DoH3 (Https), DoQ (Quic) and the PROXY protocol variants.
  • Each new query re-adds the client. Thanks to the global -exist flag, ipset does not error on a duplicate — it resets the timeout of the existing element. That is the refresh behaviour.
  • Idle clients are expired by the kernel itself. Entries live in the kernel, so restarting the DNS server does not lose them.
  • Default timeout is 3 hours. Nothing is filtered out by default — every request from every client is tracked.

Highlights

  • Batched writes. A process per DNS query is not viable, so pushes of the same client are coalesced (60 s window, far below the 3 h timeout) and a whole batch is fed to a single ipset restore process per tick.
  • IPv4 and IPv6 through separate sets (dns_clients / dns_clients6), since an ipset set has a fixed address family. ::ffff:a.b.c.d is unwrapped into plain IPv4; link local scope ids are stripped.
  • Resilient. If ipset is missing or the process lacks CAP_NET_ADMIN, the error is logged once, entries stay queued, the setup is retried, and a failed batch is requeued rather than dropped.
  • hash:net mode to aggregate clients into /24, /64, … instead of single addresses.
  • dryRun logs the exact ipset commands without executing them, so the config can be validated anywhere.
  • Never interferes. The app always returns Allow; any internal failure is caught and cannot affect DNS resolution.
  • Set names, type, timeout, create parameters, batching, network and protocol filters and log verbosity are all in dnsApp.config, and saving it hot reloads the app.

Requirements

  • Technitium DNS Server v15.3 or later (app API DnsServerCore.ApplicationCommon 10.1, .NET 10). Verified against v15.4.
  • Linux with the ipset binary installed (apt install ipset).
  • The DNS server process must be root or hold CAP_NET_ADMIN. In Docker: --cap-add NET_ADMIN; note the official image does not ship the ipset binary.

Surviving a reboot is out of scope for the app and is handled by ipset save / ipset restore (ipset-persistent, a systemd unit, etc.).

Install

  1. Download IPCollectorApp-v2.0.0.zip below.
  2. DNS server web console -> Apps -> Install, upload the zip.
  3. Open Config to adjust the settings, then Save.
  4. Verify on the host: ipset list dns_clients.

Upgrading from v1.0.0

The config format changed completely; the old storage, hashing and output sections are gone. Delete the old dnsApp.config (or let the app rewrite it) and re-apply your settings. The old ip-list.txt and ip-state.json files in the app folder can be removed.