The torrent flag was read inside loops over users rows (users/stats,
peers, metrics) and each read queried the config table. SQLite has a
single connection here, so the nested query waited for it forever: the
first stats request or Prometheus scrape locked awg-ctrl for good, and
the panel showed no users and timed out.
- the block setting is kept in memory (loaded at start, updated on
save), so the flag never touches the database
- the set of flagged IPs is taken once before the query, not per row
- regression test: collectMetrics must finish with users in the table
Panel: a 401 from the panel itself (its JWT not accepted) now returns to
the login screen; a 401 relayed from a node's awg-ctrl does not.
- awg-ctrl: optional nft table awg_torrent (GET/PUT /api/torrent, off by
default). A connection is judged by its first packets, like Xray's
sniffing: DHT, UDP trackers, uTP SYN, and with @ih support the plain
TCP handshake and HTTP announce. A match marks the connection in
conntrack and drops it whole; without @ih only the UDP part is used
- devices that tried are kept in a 10-minute set and flagged as
"torrent" in user and device stats; with shaping on they sit in the
background class while the flag lasts
- metrics: awg_torrent_block_enabled/active, awg_torrent_blocked_total,
awg_torrent_devices and per-peer awg_peer_torrent
- panel: "Торренты" section in server settings, "торренты" chip on users
and devices; Save sends only what changed