fix: harden production topology and runtime state
This commit is contained in:
@@ -25,9 +25,11 @@
|
||||
- [ ] `awg2-harness status` показывает PID/netns контейнера.
|
||||
- [ ] `awg2-harness status` показывает найденный интерфейс.
|
||||
- [ ] Количество peers совпадает с `docker exec "$C" awg show all allowed-ips`.
|
||||
- [ ] Peer с несколькими allowed IP даёт отдельный класс на каждый адрес (в этой команде адреса разделены пробелом).
|
||||
- [ ] Каждый peer имеет ровно один server-side IPv4 `/32` внутри `amnezia.peer_ipv4_cidr`; `(none)` допустим и не создаёт класс.
|
||||
- [ ] IPv4+IPv6, IPv6-only, несколько allowed IP, маска не `/32` и адрес вне configured CIDR дают явную `unsupported topology` до изменения traffic/anti-torrent state.
|
||||
- [ ] Одинаковый отказ проверен для `show all allowed-ips`, fallback `show` и `show all dump`; AWG 3.1 interface-row не ошибочно принимается за peer.
|
||||
- [ ] Offline peers с allowed IP тоже попадают в список shaping.
|
||||
- [ ] IP вне `amnezia.peer_ipv4_cidr` не попадают в traffic shaping.
|
||||
- [ ] IP вне `amnezia.peer_ipv4_cidr` не игнорируется молча: весь topology reconcile завершается ошибкой.
|
||||
- [ ] В секции `WireGuard clients` вывода `status` нет строки, соответствующей самому интерфейсу (столбец `Public key` не содержит приватный ключ устройства).
|
||||
- [ ] `docker exec "$C" readlink -f /usr/bin/wg` возвращает `/usr/bin/awg`.
|
||||
|
||||
@@ -150,7 +152,7 @@
|
||||
- [ ] `awg2-harness apply-network-tuning` успешно завершается.
|
||||
- [ ] `awg2-harness inspect-network-tuning` показывает `enabled: true` и `drift: no`.
|
||||
- [ ] Создаётся `/etc/sysctl.d/90-awg2-harness-vpn.conf`.
|
||||
- [ ] `/etc/modules-load.d/90-awg2-harness-bbr.conf` создан, если BBR активен, и отсутствует, если BBR неактивен.
|
||||
- [ ] `/etc/modules-load.d/90-awg2-harness-bbr.conf` создан, если BBR желателен по configured policy и доступен, и отсутствует при `tcp_bbr = off`/недоступном `auto`.
|
||||
- [ ] `/etc/sysctl.conf` не изменён.
|
||||
- [ ] В обоих managed-файлах первая строка содержит marker `Managed by awg2-harness sysctl_tuning`.
|
||||
- [ ] Файл без marker по managed-пути не перезаписывается и не удаляется: команда завершается ошибкой.
|
||||
@@ -158,7 +160,10 @@
|
||||
- [ ] В shipped/default config `netdev_backlog_enabled = false`, `netdev_max_backlog = 10000`, а `net.core.netdev_max_backlog` отсутствует в managed-файле.
|
||||
- [ ] При смене `netdev_backlog_enabled = true` на `false` key удаляется из persistence; оператор учитывает, что текущее runtime-значение до reboot автоматически не сбрасывается.
|
||||
- [ ] До/после ручного включения backlog сняты `/proc/net/softnet_stat`, CPU и latency под реальной нагрузкой.
|
||||
- [ ] `net.ipv4.tcp_congestion_control` и `net.core.default_qdisc` присутствуют в managed-файле только при активном BBR.
|
||||
- [ ] В shipped/default config `tcp_bbr = off`, `default_qdisc = fq`, `udp_rmem_min_enabled = false`; `default_qdisc = fq_codel` отвергается валидацией.
|
||||
- [ ] `net.ipv4.tcp_congestion_control` и `net.core.default_qdisc` присутствуют в managed-файле только когда BBR желателен по policy.
|
||||
- [ ] Status отдельно показывает `bbr_available`, `bbr_desired` и фактический `bbr_runtime_active`; при available BBR и runtime `cubic` последнее поле равно `no`.
|
||||
- [ ] При `tcp_bbr = off` уже активный runtime BBR не выдаётся за desired и не маскируется как неактивный.
|
||||
- [ ] `swap` пишет `vm.swappiness` в `/etc/sysctl.d/90-awg2-harness-swap.conf`, а не в `99-awg2-harness.conf`.
|
||||
- [ ] При обновлении с прежней версии `/etc/sysctl.d/99-awg2-harness.conf` удаляется, если несёт маркер `# Managed by awg2-harness`.
|
||||
- [ ] Файл по пути `99-awg2-harness.conf` без этого маркера остаётся нетронутым и не ломает `ensure-swap`.
|
||||
@@ -181,6 +186,7 @@
|
||||
- [ ] Runtime apply меняет только drifted keys (`sysctl -w`), без `sysctl --system`.
|
||||
- [ ] При `tcp_bbr = auto` и недоступном BBR сервис не падает, в статусе есть warning.
|
||||
- [ ] При `tcp_bbr = require` и недоступном BBR команда/старт завершается с ошибкой.
|
||||
- [ ] Sustained per-peer cap проверен в двух конфигурациях, BBR-off и BBR-on; HTB `rate == ceil` даёт одинаковый лимит.
|
||||
- [ ] При `enabled=false` managed-файл удаляется только если содержит managed marker.
|
||||
|
||||
## I. Anti-torrent guard на nftables
|
||||
@@ -260,10 +266,14 @@
|
||||
- [ ] Повторный `apply-firewall` идемпотентен и не вносит лишних изменений в healthy state.
|
||||
- [ ] Legacy fields `host_firewall.amnezia_port`/`amnezia_protocols` отвергаются как `unknown field`.
|
||||
- [ ] Новая конфигурация строится в inactive A/B chain до switch; искусственный сбой `ip6tables` после IPv4 switch возвращает IPv4 на прежнюю цепочку.
|
||||
- [ ] Managed jumps переключаются только через insert-new + exact-spec delete; numeric `-R INPUT <n>`/`-D INPUT <n>` не используются.
|
||||
- [ ] Чужое правило, конкурентно вставленное первым в `INPUT`, не заменяется и не удаляется; rollback удаляет только новый managed jump.
|
||||
- [ ] После `docker restart` anti-torrent правила продолжают восстанавливаться корректно и не ломаются host firewall логикой.
|
||||
- [ ] Проверено, где реально проходит VPN-трафик в вашей Docker-схеме (`INPUT` vs `FORWARD`) и это отражено в эксплуатационной заметке.
|
||||
- [ ] Для release-кандидата зафиксирован итог проверки `INPUT` vs `FORWARD` на реальном сервере (команды/логи/вывод) и подтверждено, что текущие правила firewall покрывают реальный путь трафика.
|
||||
- [ ] `status` показывает блок `Docker/Amnezia port path` с полями `expected_host_udp_port`, `docker_userland_proxy`, `published_udp_port`, `awg_listen_udp_port`, `port_contract` и note про Docker-managed `FORWARD`.
|
||||
- [ ] В том же блоке перечислены все UDP `host_bindings`, включая одновременно `0.0.0.0:<port>` и `[::]:<port>`; IPv6 выводится в квадратных скобках.
|
||||
- [ ] Docker routed binding с пустым `HostPort` сохраняется в диагностике и не превращается в выдуманный numeric port.
|
||||
- [ ] `status` показывает поля `host_forward_policy_drop` и `docker_forward_rules_present` в блоке `Docker/Amnezia port path`.
|
||||
- [ ] Если `docker_userland_proxy=false` и `FORWARD policy DROP`, при отсутствии явных Docker accept-признаков `status` выводит warning, но `awg2-harness` не изменяет `FORWARD` автоматически.
|
||||
- [ ] Сверено соответствие: `amnezia.expected_host_udp_port` ↔ опубликованный Docker UDP host port ↔ `docker exec <container> awg show <interface> listen-port`; `port_contract: ok`.
|
||||
|
||||
+11
-5
@@ -55,13 +55,13 @@ ifb_name = "ifb0"
|
||||
enabled = true
|
||||
apply_on_daemon_start = true
|
||||
ip_forward = true
|
||||
tcp_bbr = "auto" # off | auto | require
|
||||
default_qdisc = "fq" # none | fq | fq_codel
|
||||
tcp_bbr = "off" # off | auto | require
|
||||
default_qdisc = "fq" # none | fq
|
||||
rmem_max = 67108864
|
||||
wmem_max = 67108864
|
||||
netdev_backlog_enabled = false
|
||||
netdev_max_backlog = 10000
|
||||
udp_rmem_min_enabled = true
|
||||
udp_rmem_min_enabled = false
|
||||
udp_rmem_min = 8192
|
||||
|
||||
[host_firewall]
|
||||
@@ -103,6 +103,8 @@ swappiness = 1
|
||||
|
||||
`amnezia.peer_ipv4_cidr` — подсеть VPN peers. Production default — `10.8.1.0/24`; значение конфигурируемое.
|
||||
|
||||
Поддерживаемая server-side topology строго соответствует официальной self-hosted схеме Amnezia/AWG 3.1: у каждого peer либо нет маршрута (`(none)`), либо есть ровно один IPv4 host route `/32` внутри `amnezia.peer_ipv4_cidr`. IPv6, смешанные IPv4+IPv6, несколько маршрутов, более широкая маска и адрес вне подсети дают явную ошибку `unsupported topology` до изменения `tc` и anti-torrent state. Клиентские `0.0.0.0/0, ::/0` и внешний IPv6 Docker publish относятся к другим плоскостям и этим ограничением не запрещаются.
|
||||
|
||||
`amnezia.expected_host_udp_port` — ожидаемый published UDP host port Docker для AmneziaWG. Поле обязательное и используется диагностикой `status` для контракта `expected host port ↔ Docker binding ↔ awg/wg listen-port`. Оно не создаёт host INPUT allow-rule: трафик к published bridge container проходит через Docker `FORWARD`/NAT path, а не через host `INPUT`.
|
||||
|
||||
`traffic.peer_limit` — per-peer лимит в обе стороны. Текущий production default — `50mbit`.
|
||||
@@ -121,15 +123,19 @@ swappiness = 1
|
||||
|
||||
- persistent-файл: `/etc/sysctl.d/90-awg2-harness-vpn.conf`;
|
||||
- модуль `swap` отдельно управляет `/etc/sysctl.d/90-awg2-harness-swap.conf` (только `vm.swappiness`); прежний путь `/etc/sysctl.d/99-awg2-harness.conf` удаляется при первом запуске новой версии, если несёт старый маркер;
|
||||
- дополнительный managed-файл `/etc/modules-load.d/90-awg2-harness-bbr.conf` создаётся только при фактически активном BBR и удаляется, когда BBR неактивен;
|
||||
- дополнительный managed-файл `/etc/modules-load.d/90-awg2-harness-bbr.conf` создаётся только когда BBR выбран desired policy (`auto`/`require` и BBR доступен), и удаляется при `tcp_bbr = "off"` или недоступном `auto`;
|
||||
- оба managed-файла несут в первой строке маркер `# Managed by awg2-harness sysctl_tuning`; файл без маркера не перезаписывается и не удаляется, вместо этого возвращается ошибка;
|
||||
- `net.ipv4.tcp_congestion_control` и `net.core.default_qdisc` управляются только при активном BBR;
|
||||
- `net.ipv4.tcp_congestion_control` и `net.core.default_qdisc` управляются только когда BBR желателен по policy; `default_qdisc` принимает только `none | fq` и не управляет per-peer `fq_codel`;
|
||||
- runtime apply: только `sysctl -w` и только для drifted keys;
|
||||
- на установке `.deb` модуль не применяется;
|
||||
- на старте daemon модуль применяется, если `enabled=true` и `apply_on_daemon_start=true`;
|
||||
- `tcp_bbr = auto` не валит запуск при недоступном BBR (warning), `require` — валит;
|
||||
- для `sysctl_tuning`: `modprobe` обязателен только для `tcp_bbr = "require"`.
|
||||
|
||||
Production default — `tcp_bbr = "off"`: BBR влияет на локальные TCP sockets хоста, но не ускоряет UDP transport AWG и не является частью HTB peer limiter. `auto`/`require` остаются осознанным opt-in. Status разделяет три разных факта: `bbr_available`, `bbr_desired` и фактический `bbr_runtime_active`, вычисленный по текущему `net.ipv4.tcp_congestion_control`.
|
||||
|
||||
`udp_rmem_min_enabled = false` — production default, потому что `net.ipv4.udp_rmem_min` является per-network-namespace sysctl: запись на хосте не меняет UDP stack AWG-контейнера. Значение `udp_rmem_min = 8192` сохранено как opt-in для локальных UDP sockets хоста; отдельный container-side reconcile ради него не добавляется.
|
||||
|
||||
`netdev_backlog_enabled = false` — безопасный production default: harness не управляет `net.core.netdev_max_backlog`, пока оператор не включит это явно после измерений. Значение `netdev_max_backlog = 10000` используется только при `netdev_backlog_enabled = true`.
|
||||
|
||||
При обновлении с конфига, где backlog раньше был включён, переключение флага в `false` удаляет key из managed-файла, но не перезаписывает уже изменённое runtime-значение. До следующей перезагрузки его можно вернуть вручную к baseline дистрибутива. Перед осознанным включением backlog снимите pre/post-метрики `/proc/net/softnet_stat` (в том числе dropped/time_squeeze) и CPU/latency под реальной нагрузкой.
|
||||
|
||||
+28
-11
@@ -127,7 +127,7 @@ awg2-harness validate-runtime
|
||||
|
||||
При `swap.enabled = false` управляемый файл удаляется. **Остаются на месте**: сам swapfile, его активность в ядре и запись в `/etc/fstab` — то есть после перезагрузки swap снова включится. Удаляется только persistence `vm.swappiness`. Runtime-значение `vm.swappiness` при этом намеренно не меняется: назначать произвольное значение означало бы выдумать политику, о которой оператор не просил. После перезагрузки действует kernel default. Активный swap при отключении модуля тоже не выключается — деструктивное действие не должно запускаться самим фактом отключения функции.
|
||||
|
||||
`net.ipv4.tcp_congestion_control` и `net.core.default_qdisc` попадают в целевое состояние только при активном BBR.
|
||||
`net.ipv4.tcp_congestion_control` и `net.core.default_qdisc` попадают в целевое состояние только когда BBR желателен по policy. Фактическая активность диагностируется отдельно по runtime `net.ipv4.tcp_congestion_control`.
|
||||
|
||||
## 3. Структура модулей
|
||||
|
||||
@@ -152,7 +152,15 @@ traffic_core/src/
|
||||
│ ├── host.rs owned iptables/ip6tables INPUT chains (host namespace)
|
||||
│ └── antitorrent.rs таблица inet awg2_harness (namespace по конфигу)
|
||||
├── sysctl_tuning.rs управляемый sysctl baseline
|
||||
├── swap.rs управляемый swap
|
||||
├── swap/
|
||||
│ ├── mod.rs facade и orchestration ensure_swap
|
||||
│ ├── model.rs модели desired/runtime/status и replacement state
|
||||
│ ├── path.rs syntax/path-chain safety и state directory
|
||||
│ ├── ownership.rs ownership record и legacy sidecar
|
||||
│ ├── runtime.rs swapon/swapoff/mkswap и parser runtime state
|
||||
│ ├── replacement.rs создание, resize и rollback транзакции
|
||||
│ ├── persistence.rs /etc/fstab, swappiness и legacy migration
|
||||
│ └── status.rs inspect_swap и drift aggregation
|
||||
├── status.rs сборка и печать статуса
|
||||
├── lock.rs файловые блокировки
|
||||
└── error.rs типы ошибок
|
||||
@@ -273,11 +281,13 @@ struct PeerTrafficStatus {
|
||||
awg show all allowed-ips
|
||||
```
|
||||
|
||||
Правила разбора:
|
||||
Правила разбора и общий `PeerTopology` contract:
|
||||
|
||||
- строки разбираются структурно на public key peer и его allowed IPs;
|
||||
- в этой команде allowed ips одного peer разделены **пробелом**, в `show all dump` — запятой, в обычном `show` — `", "`; нужно потреблять все токены начиная с третьей колонки, иначе peers с несколькими allowed IP получат shaping только по первому адресу;
|
||||
- оставляются только IPv4 `/32` внутри `amnezia.peer_ipv4_cidr`;
|
||||
- в этой команде allowed ips разделены **пробелом**, в `show all dump` — запятой, в обычном `show` — `", "`; parser обязан проверить весь список, а не молча взять первый адрес;
|
||||
- поддерживается ровно один IPv4 `/32` внутри `amnezia.peer_ipv4_cidr` на peer; `(none)` допустим и не создаёт peer class;
|
||||
- IPv6-only, IPv4+IPv6, несколько allowed IPs, маска не `/32`, невалидный CIDR или IPv4 вне configured peer CIDR возвращают typed `UnsupportedTopology`;
|
||||
- topology проверяется один раз на startup/periodic/event cycle и передаётся traffic и anti-torrent. При ошибке ни одна из этих подсистем не начинает mutation и не сообщает успешный reconcile;
|
||||
- offline peers включаются: online-состояние не является требованием для shaping;
|
||||
- перед присвоением class id строки peer IP сортируются лексикографически, чтобы сохранить действующий контракт class-id.
|
||||
|
||||
@@ -287,7 +297,7 @@ awg show all allowed-ips
|
||||
awg show
|
||||
```
|
||||
|
||||
Fallback-парсер разбирает текстовый вывод, извлекая строки `allowed ips:`. Он используется, если основная команда завершилась ошибкой или вернула пустой результат.
|
||||
Fallback-парсер разбирает текстовый вывод, извлекая строки `allowed ips:`. Он используется, если основная команда завершилась ошибкой или вернула пустой результат, и применяет тот же строгий topology contract.
|
||||
|
||||
Классификация строк `show all dump`:
|
||||
|
||||
@@ -365,7 +375,7 @@ apply_firewall():
|
||||
apply_antitorrent_firewall(config) # namespace по anti_torrent.apply_in_amnezia_netns
|
||||
```
|
||||
|
||||
Каждый из firewall-путей сначала инспектирует фактическое состояние и выходит без изменений, если drift отсутствует. Anti-torrent таблица заменяется одной атомарной nft-транзакцией. Host firewall сначала строит и проверяет inactive chain отдельно для IPv4/IPv6, затем переключает помеченный jump; сбой IPv6 после IPv4 switch откатывает IPv4. После apply выполняется обязательная повторная инспекция.
|
||||
Каждый из firewall-путей сначала инспектирует фактическое состояние и выходит без изменений, если drift отсутствует. Anti-torrent таблица заменяется одной атомарной nft-транзакцией и при включённом guard требует успешно проверенный `PeerTopology`; host firewall от server-side peer topology не зависит. Host firewall сначала строит и проверяет inactive chain отдельно для IPv4/IPv6. Новый jump всегда вставляется через `-I INPUT 1`; старый остаётся вторым до успешного переключения обеих IP-family и затем удаляется по полной rule specification. Numeric `-R/-D` для managed jumps не используется. Сбой IPv6 удаляет новый IPv4 jump по точной specification, поэтому старый IPv4 jump всё время остаётся рабочим. После apply выполняется обязательная повторная инспекция.
|
||||
|
||||
Для production контролируемая полная пересборка при drift — единственный поддерживаемый путь.
|
||||
|
||||
@@ -407,6 +417,8 @@ apply_firewall():
|
||||
|
||||
Host firewall не открывает published Amnezia UDP port в `INPUT`: Docker bridge publish проходит через `FORWARD`/NAT. Собственная chain разрешает loopback, established/related, configured SSH и optional ICMP/ICMPv6, затем завершает обработку configured `DROP`/`ACCEPT` verdict. Поле `amnezia.expected_host_udp_port` относится только к диагностике port path.
|
||||
|
||||
Жизненный цикл managed jump использует только exact rule spec с comment `awg2-harness:host-firewall` и target `AWG2H_A`/`AWG2H_B`. Чужое правило, вставленное другим firewall manager между inspect и switch, не может быть заменено или удалено по изменившемуся номеру строки.
|
||||
|
||||
## 11. Anti-torrent firewall guard
|
||||
|
||||
Это часть production-контракта AWG2. Модуль вписывается в мульти-оркестраторную модель, потому что сервер выделенный и бинарю разрешено владеть host/network правилами, нужными VPN-продукту. Правило всё равно обязано быть узко ограниченным и наблюдаемым.
|
||||
@@ -542,7 +554,8 @@ System:
|
||||
interface: <iface>
|
||||
Network tuning:
|
||||
enabled, apply_on_daemon_start, tcp_bbr_mode, conf_path, modules_load_path,
|
||||
значения управляемых ключей, bbr_available, bbr_active, drift[, reason][, warning]
|
||||
значения управляемых ключей, bbr_available, bbr_desired,
|
||||
bbr_runtime_active, drift[, reason][, warning]
|
||||
Peers:
|
||||
total: N
|
||||
- <peer ip>
|
||||
@@ -560,6 +573,7 @@ Host firewall:
|
||||
enabled, ssh_port, input_policy, drift[, reason]
|
||||
Docker/Amnezia port path:
|
||||
expected_host_udp_port, docker_userland_proxy, published_udp_port,
|
||||
host_bindings (все HostIp:HostPort, включая routed binding без HostPort),
|
||||
awg_listen_udp_port, port_contract, host_forward_policy_drop,
|
||||
docker_forward_rules_present, note[, warning]
|
||||
Anti-torrent:
|
||||
@@ -693,7 +707,7 @@ inode = 123456
|
||||
|
||||
### Перезапись `/etc/fstab`
|
||||
|
||||
Это самая разрушительная операция пакета, поэтому она транзакционная и вынесена в отдельный модуль `fstab.rs`. Контракт:
|
||||
Это самая разрушительная операция пакета, поэтому она транзакционная и изолирована в `swap/persistence.rs`. Контракт:
|
||||
|
||||
- ошибка чтения `/etc/fstab` **никогда** не интерпретируется как пустой файл. `PermissionDenied`, ошибка ввода-вывода и отсутствие файла различаются, и все три прекращают операцию. Отсутствие `/etc/fstab` на Debian-хосте считается аномалией, а не основанием создать его с нуля;
|
||||
- пустой или состоящий из пробелов кандидат отклоняется;
|
||||
@@ -714,8 +728,8 @@ inode = 123456
|
||||
|
||||
- валидация конфига, включая форму `amnezia.wg_binaries`;
|
||||
- разбор `config.example.toml` в актуальную схему с точным default-порядком контейнеров, `awg`/`wg` и anti-torrent baseline `500`;
|
||||
- парсер `awg|wg show all allowed-ips`, включая несколько allowed ips через пробел;
|
||||
- fallback-парсер `awg|wg show`;
|
||||
- парсер `awg|wg show all allowed-ips`: один IPv4 `/32` проходит, IPv4+IPv6, IPv6-only, несколько маршрутов, маска не `/32` и адрес вне configured CIDR дают explicit `UnsupportedTopology`;
|
||||
- fallback-парсер `awg|wg show` и dump-парсер применяют тот же topology contract; `(none)` остаётся допустимым;
|
||||
- классификация peer/interface строк `awg|wg show all dump` против двух 30-полевых AWG 3.1 fixtures, AWG 3.0 с включённой и выключенной защитой заголовка, AWG 2.x, чистого WireGuard, а также конфигурации AWG 2.0, прочитанной tools AWG 3.0;
|
||||
- разбор dump с несколькими интерфейсами, с интерфейсом без peers и с повреждёнными строками;
|
||||
- порядок выбора бинаря wg и ошибка при отсутствии всех кандидатов;
|
||||
@@ -727,6 +741,9 @@ inode = 123456
|
||||
- packet statistics из Debian-подобного `tc -s class`;
|
||||
- отказ удалять foreign IFB/root qdisc;
|
||||
- typed Docker readiness retry/timeout/lower-priority event;
|
||||
- Docker UDP bindings: dual-stack HostIp, routed binding с пустым HostPort и неоднозначные/divergent host ports;
|
||||
- BBR decision: доступный BBR при runtime `cubic` означает `desired=yes`, `runtime_active=no`; mode `off` не маскирует уже активный runtime BBR;
|
||||
- host firewall rollback удаляет новый jump по exact specification и не затрагивает чужое правило в начале `INPUT`;
|
||||
- conntrack count из Amnezia namespace и global max с host;
|
||||
- diff drift;
|
||||
- расчёт окна перезагрузки;
|
||||
|
||||
@@ -51,6 +51,8 @@ docker exec "$C" awg show awg0 listen-port
|
||||
docker inspect -f 'ports={{json .NetworkSettings.Ports}}' amnezia-dns
|
||||
```
|
||||
|
||||
В `status` для AWG publish ожидается полный список фактических bindings, например `0.0.0.0:443` и `[::]:443`. Это внешний Docker publish; он не меняет IPv4-only server peer topology. Каждый server peer обязан иметь ровно один IPv4 `/32` внутри configured CIDR. Смешанный/IPv6/multiple `AllowedIPs` должен останавливать traffic и anti-torrent reconcile с `unsupported topology`.
|
||||
|
||||
Проверка host firewall выполняется через Docker-совместимый frontend. В `INPUT` ожидается первый jump с comment `awg2-harness:host-firewall`, но не allow-rule для `443/udp`:
|
||||
|
||||
```bash
|
||||
|
||||
@@ -55,6 +55,8 @@ Reference image содержит `/usr/bin/awg`, `/usr/bin/awg-quick` и symlink
|
||||
|
||||
Harness не выбирает реализацию и не требует конкретную из них. Peer state читается через `docker exec` официальным `awg` внутри контейнера. Это единая container-side точка доступа для kernel и userspace вариантов и не создаёт зависимости от версии host-side tools.
|
||||
|
||||
Поддерживаемый harness-контракт соответствует официальной self-hosted server topology Amnezia/AWG 3.1: один IPv4 host route `/32` на peer. Generic client config может содержать `0.0.0.0/0` и `::/0`, а Docker — публиковать AWG UDP port на внешних IPv4 и IPv6 адресах; это не server-side peer addressing. IPv6/mixed/multiple server `AllowedIPs` harness отвергает до traffic и anti-torrent mutation.
|
||||
|
||||
## Контракт `show all dump`
|
||||
|
||||
Исторические widths являются диагностикой:
|
||||
|
||||
Reference in New Issue
Block a user