The docs folder had drifted into a mixed-language contract: IMPLEMENTATION_SPEC.md was entirely in English while the rest was Russian with English headings. Prose is now Russian throughout; English is kept only where it is technically load-bearing (commands, tool output, config keys, file/module/table names, tc handles) and for terms with no settled Russian equivalent in this context (drift, reconcile, peer, namespace, handshake). docs/README.md now states that contract explicitly. Rewriting the spec surfaced several places where it described intent rather than the code. Corrected against traffic_core/src: - module layout: the spec showed traffic/ and firewall/ as directories with model/inspect/apply submodules. They are single files, and sysctl_tuning.rs was missing from the tree entirely. - data model: Peer was documented as carrying public key, handshake and counters. It carries only ipv4; runtime state lives in a separate PeerRuntime, and there is no desired-state struct at all - it is derived inline from config plus sorted peers. RuntimeTarget.netns_path is a String, not a PathBuf. - interface detection: the spec listed a third step taking the first non-loopback interface with an IPv4 address. No such fallback exists; detection bails with an explicit error, which is safer and is now documented as deliberate. - reconcile: the pseudo-flow folded firewall into reconcile_traffic. They are two independent reconciles with separate locks. - locking: only traffic.lock was documented. There are three locks, and sysctl_tuning.lock has a 30s timeout rather than 10s. Stale-lock recovery via /proc/<pid> was undocumented. - sysctl_tuning: the module also manages /etc/modules-load.d/90-awg2-harness-bbr.conf when BBR is active, and refuses to touch either managed file without its marker. Both docs and the acceptance checklist claimed only the sysctl.d file was written. - status contract: the documented output was outdated. All 15 printed sections are now listed in the order status.rs emits them, including the degraded path when no container is found, and the fact that the Network tuning block is printed between the System service line and the container lines. - swap: size was documented as a constant 2048 MB instead of swap.size_mb, and the /etc/fstab.awg2-harness.bak backup was undocumented. - apply/verify: the tolerated-error lists are now the actual closed sets from the code. Acceptance checklist gained checks for the daemon startup failure policy (sysctl/swap fatal, traffic/firewall not), lock contention and stale-lock recovery, degraded status, the modules-load file, and the marker guard. The stale host wg requirement was dropped from its host-tools item. Every path, table, counter and log string quoted in the docs was verified to exist in the source. cargo test --workspace: 110 + 4 passed.
6.3 KiB
Anti-torrent: ограничение числа соединений
Этот модуль — часть текущего production-контракта AWG2 Harness. Он вписывается в multi-orchestrator модель, потому что сервер выделенный, а бинарь уже владеет AWG2-owned network state вокруг Amnezia: tc, ifb0, lifecycle recovery и диагностика.
1. Цель
Не детектить BitTorrent как протокол. Цель проще: ограничить количество одновременных conntrack flows на один VPN peer IP. Торрент-клиенты обычно пытаются держать сотни TCP/UDP peer-сессий, DHT/uTP/trackers. Лимит в диапазоне 100–250 одновременных flows заметно ухудшает P2P-поведение, но почти не затрагивает обычные сценарии при корректной настройке.
Это мягкий технический барьер, а не abuse-система со страйками.
2. Важное исправление к простой команде
Не использовать такую форму как production rule (это антипример; 200 здесь не default и не production-рекомендация):
nft add rule inet filter forward ip saddr 10.8.1.0/24 ct count over 200 drop
Проблемы:
- Это может стать общим лимитом для всей подсети, а не лимитом на каждого клиента.
- Нет ownership: правило кладётся в generic
inet filter forward, который может принадлежать не нашему пакету. - Неочевидно, в каком network namespace оно применяется.
- Нет named counter и нормальной диагностики.
Нужен per-source key через meter/set и отдельная таблица, которой владеет только AWG2 Harness.
3. Рекомендуемая форма правила nftables
Правило должно применяться в том же network namespace, где живёт Amnezia AWG/WG interface и где уже применяются tc/ifb0 rules. На практике это namespace контейнера Amnezia, полученный через /proc/<container_pid>/ns/net.
table inet awg2_harness {
counter antitorrent_dropped_v4 {}
chain forward_antitorrent {
type filter hook forward priority filter; policy accept;
ip saddr <peer_ipv4_cidr> ct state new \
meter awg2_peer_connlimit_v4 { ip saddr ct count over <max_connections_per_peer> } \
counter name antitorrent_dropped_v4 \
drop
}
}
Пример для текущей production-подсети:
table inet awg2_harness {
counter antitorrent_dropped_v4 {}
chain forward_antitorrent {
type filter hook forward priority filter; policy accept;
ip saddr 10.8.1.0/24 ct state new \
meter awg2_peer_connlimit_v4 { ip saddr ct count over 100 } \
counter name antitorrent_dropped_v4 \
drop
}
}
ct state new важен: ограничиваются новые flow attempts сверх порога, а уже установленные flows не начинают внезапно дропаться только потому, что счётчик стал высоким.
4. Порог
Рекомендуемый стартовый production baseline:
[anti_torrent]
enabled = true
max_connections_per_peer = 150
Практические варианты:
100— более строгий режим.150— текущий рекомендуемый стартовый baseline, мягче к обычному browsing/mobile traffic.200/250— ещё более permissive варианты.70— агрессивный режим только после наблюдения реального трафика.
5. Почему это должно быть в orchestrator
Модуль должен жить в Rust-бинаре, а не отдельным ручным правилом, потому что orchestrator должен:
- применять правило после container restart/update, когда network namespace изменился;
- проверять actual state и чинить drift;
- показывать status/counters;
- не ломать unrelated nftables/Docker/Amnezia rules;
- удалять или отключать только owned state при
enabled = false.
6. Conntrack и производительность
ct count использует conntrack. На текущем масштабе это нормально: даже 23 peers × 100 flows = около 2300 активных flows до ограничения. Это не выглядит опасно для production-хоста само по себе.
Что надо мониторить:
sysctl net.netfilter.nf_conntrack_count
sysctl net.netfilter.nf_conntrack_max
nft list table inet awg2_harness
Если nf_conntrack_count приближается к nf_conntrack_max, проблема уже системная: надо разбираться с timeout, abuse или capacity. Не надо автоматически увеличивать nf_conntrack_max из orchestrator без отдельного решения.
7. Критерии приёмки
- В правильном Amnezia netns существует
table inet awg2_harness. - В таблице есть
chain forward_antitorrentс hookforward. - Правило ограничивает
ip saddr <peer_ipv4_cidr>. - Лимит применяется per source VPN IP, а не глобально на всю подсеть.
- Drop counter растёт при превышении threshold.
- Нормальные сценарии с числом flows ниже threshold не затрагиваются.
- При restart контейнера правило пересоздаётся в новом netns.
- При
anti_torrent.enabled = falseудаляется или отключается только AWG2-owned nftables state.