AmneziaWG (AWG) — справочник для zapret-gui

SkillProductivity

Complete reference for AmneziaWG (AWG) in the zapret-gui project (Keenetic routers on Entware / OpenWrt / Linux). Use for any tasks concerning: AWG configs (.conf — [Interface]/[Peer], wg-quick extensions), obfuscation parameters (Jc/Jmin/Jmax, S1-S4, H1-H4, I1-I5, J1-J3, Itime), and protocol versio

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the AmneziaWG (AWG) — справочник для zapret-gui skill

What this skill tells your AI

The instructions your AI receives, as published by avatardd/zapret-gui in .claude/skills/awg/SKILL.md and read by ahel’s review.

Единый источник истины о том, как AmneziaWG реально работает и как с ним обращаться в zapret-gui. Читать перед тем, как трогать разбор/генерацию .conf, менеджер туннелей, параметры обфускации, WARP, интеграцию с Keenetic или объяснять пользователю «почему handshake есть, а трафика нет».

Источники истины (в порядке убывания авторитета):

  1. amnezia-vpn/amneziawg-go — userspace-реализация протокола на Go (README.md = спецификация параметров обфускации; сверено с v3.1.20260814); amnezia-vpn/amneziawg-tools — форк wireguard-tools (awg/awg-quick), сверено с v3.1.20260812. README на ветке 3.1 не изменился: два новых параметра (§2.1.2) описаны только кодом — device/uapi.go и src/config.c. Окончательный список ключей, которые вообще можно писать в .conf, — это key_match в его src/config.c, а НЕ документация: docs.amnezia.org описывает параметры протокола, часть которых парсер не принимает (см. §2.1 про J1..J3/Itime). docs.amnezia.org — описание протокола и версий (1.0 / 1.5 / 2.0); поколение AWG 3+ документировано только в README amneziawg-go (§2.1.1).
  2. awg show <iface> / awg showconf <iface> — что демон реально принял. Если в showconf нет ваших I1/S3/H* — значит до awg setconf они не дошли (см. §3, §12). Это первичная диагностика.
  3. Наш кодcore/awg_config.py (парсер/генератор .conf, ключи), core/awg_manager.py (up/down/status/diagnostics), core/awg_platform.py (пути), core/awg_installer.py + core/awg_detector.py (бинари/арх), core/warp_generator.py + core/warp_importer.py + core/awg_warp_in_warp.py (WARP), core/ndms/wg_discovery.py (нативный WG Keenetic), core/awg_watchdog.py, core/awg_autostart_manager.py + core/awg_init_script.py, api/awg.py, web/js/pages/awg_*.js.

⚠️ Версия протокола — главный источник «handshake есть, трафика нет». AmneziaWG несовместим между мажорными версиями обфускации (§2.3). Если клиент шлёт data-пакеты в формате одной версии, а пир ждёт другую — handshake проходит (он на общих параметрах), а transport-пакеты дропаются. Классическая картина в awg show: transfer: 92 B received, 20 KB sent — мы отправляем, сервер молчит. См. §12.


1. Как AWG используется в zapret-gui

Модель: один туннель = один сетевой интерфейс (как у WireGuard; в отличие от sing-box, где инстанс = файл). Имя инстанса = имя .conf без расширения и = имя интерфейса (конфиг awg0.conf → интерфейс awg0).

Мы НЕ используем awg-quick. Логику wg-quick (Address/MTU/Table/DNS/ PreUp…PostDown, маршруты из AllowedIPs) мы реализуем сами в awg_manager._do_up, а ядро поднимаем напрямую:

amneziawg-go <iface>                 # форкает userspace-демон + TUN-устройство
awg setconf <iface> <filtered.conf>  # заливает крипто + обфускацию в демон
ip link set dev <iface> mtu <MTU>
ip addr add <Address> dev <iface>
ip link set dev <iface> up
ip route add <AllowedIPs> dev <iface> table <id>   # если Table != off

Почему так, а не awg-quick up: на Keenetic/Entware нет полноценного bash и ряда утилит, которые тянет awg-quick; нам нужен контроль над таблицами маршрутизации (Selective routing GUI) и устойчивый teardown. Поэтому amneziawg-go (userspace) + awg setconf + ручной ip — наш базовый путь.

Поток:

  • Конфиги лежат в platform.config_dir (Keenetic: /opt/etc/amneziawg/). CRUD — через api/awg.py поверх core/awg_config.py.
  • awg setconf получает НЕ весь .conf, а отфильтрованный (только WG_INTERFACE_FIELDS + WG_PEER_FIELDS, §3) — wg-quick-поля демон не понимает.
  • Маршрутизация GUI поверх: target_iface = <iface>, правила навешивает core/routing/applier при подъёме интерфейса.

2. Параметры обфускации AmneziaWG (официальная истина)

AmneziaWG — форк WireGuard-Go, который убирает узнаваемые DPI-сигнатуры WireGuard, сохраняя его крипто и производительность. Все «магия» — дополнительные поля в секции [Interface] (в README апстрима эта секция называется [Device]). Какие из них обязаны совпадать с пиром, а какие задаются только на клиенте — см. таблицу «сторон» ниже: путать их дорого. Если все параметры = 0 → ведёт себя как обычный WireGuard (для плавной миграции), и «значение не задано» апстрим трактует именно как 0.

2.1 Таблица параметров (источник: amneziawg-go README + docs.amnezia.org)

ПараметрЧто делаетДиапазон/рекомендацияВерсия
JcКол-во junk-пакетов перед handshake (после I1–I5)рекоменд. 4–12 (docs: 0–10)1.0
JminМин. размер junk-пакетабайты; Jmin ≤ Jmax1.0
JmaxМакс. размер junk-пакетабайты; Jmax < MTU (иначе фрагментация); docs: 64–10241.0
S1Префикс-padding handshake init0–64 байт1.0
S2Префикс-padding handshake response0–64 байт1.0
S3Префикс-padding handshake cookie0–64 байт2.0
S4Префикс-padding transport (data)0–32 байта2.0
H1Магический заголовок (тип) пакета init0…42949672951.0
H2Магический заголовок пакета response0…42949672951.0
H3Магический заголовок пакета cookie0…42949672951.0
H4Магический заголовок transport (data)0…42949672951.0
I1…I5Signature-пакеты перед handshake (мимикрия под реальный протокол); отправляются по порядку I1→I5, пропускаются, если значение не заданопоследовательность тегов, §2.1.21.5
J1…J3Доп. junk-параметры1.5, удалены в 2.0
ItimeТайминг signature-пакетов1.5, удалён в 2.0

Где параметр обязан совпадать с пиром. README amneziawg-go вводит явное деление: server-side — значение ОБЯЗАНО быть одинаковым на обоих концах, client-side — можно задавать только у клиента.

ПараметрСторонаПрактический вывод
Jc/Jmin/Jmaxclient-side«Junk-пакеты не несут данных, задавать на обеих сторонах не требуется; общая рекомендация — только на клиенте» (README). Поэтому junk и работает против ванильного WireGuard-пира (§8.1)
I1…I5client-sideто же самое: signature-пакеты пир просто игнорирует
S1–S4, H1–H4должны совпадатьэто формат САМИХ пакетов, пир обязан уметь их разобрать
HeaderProtectionKeyserver-sideключ защиты заголовка (§2.1.1)
ContentPaddingAddition, тайминги, PersistentKeepaliveclient-side«важно задать паддинг с обеих сторон, но строго не обязательно»

Тип range,x (AWG 3): значение может быть "a-b", "a" или "(off)" — например PersistentKeepalive = 22-30. Значение не задано = 0 для любого параметра.

2.1.2 Синтаксис I1…I5 — это НЕ просто hex

Значение I1..I5 — последовательность тегов (README amneziawg-go, раздел «Custom signature packets»):

ТегЧто кладёт в пакет
<b 0x[seq]>статические байты: [seq] — hex-строка чётной длины (2 знака на байт)
<r [size]>[size] случайных байт
<rd [size]>[size] случайных цифр [0-9]
<rc [size]>[size] случайных букв [a-zA-Z]
<t>4 байта текущего времени в формате UNIX

Теги можно комбинировать в одной строке. Наш парсер (§3.2) заточен под самый частый случай — многострочный <b …> — и остальные теги переносит как есть (мы их не интерпретируем, это делает демон). Если правишь parse_conf, не считай, что содержимое I* обязано быть hex: <r 32><t> — валидное значение.

Jmax и MTU. README: «если Jmax ≥ системного MTU (не того, что задан в AWG), система нарежет пакет на фрагменты, что со стороны цензора выглядит подозрительно». То же про итоговый размер signature-пакета.

⚠️ J1..J3 и Itime нельзя отдавать в awg setconf — вообще никогда. Их нет в key_match парсера amneziawg-tools (src/config.c) ни в одном релизе, включая свежий v3.1.20260812. На неизвестном ключе парсер делает goto error: печатает Line unrecognized: '<строка>' и отбрасывает конфиг целиком. То есть один лишний ключ из чужого .conf = интерфейс не поднимается вовсе, а наружу видно лишь невнятное «Unable to modify interface». Разбирать и сохранять их при round-trip мы обязаны (профиль из клиента Amnezia не должен терять поля), а в setconf — не отдаём: AWG_FIELDS_UNSUPPORTED_BY_TOOLS + _setconf_skip_fields в core/awg_config.py, сторож — tests/test_awg_config.py.

2.1.1 AWG 3+: защита заголовка, паддинг содержимого, тайминги

Ветка amneziawg-go v3.x (текущая; сверено с README v3.1.20260814 — на 3.1 он не менялся) добавила поколение параметров, которое апстрим маркирует как [AWG 3+]. В .conf они живут в секции устройства ([Device] в терминах README = [Interface] в терминах wg-quick):

КлючТип / сторонаНазначение
HeaderProtectionKeykey,string, server-sideКлюч шифрования низкоэнтропийных полей заголовка — тех, что WireGuard использует для аутентификации и собственного шифрования. Нонсом служит crypto-паддинг S1–S4. Генерируется awg genkey
ContentPaddingAdditionuint32,range, client-sideДополнительный паддинг содержимого
RekeyAfterTimeuint32,range, секЧерез сколько клиент пробует сделать handshake
RekeyTimeoutuint32,range, секТаймаут, после которого handshake повторяется
RejectAfterTimeuint32,range, секКогда клиент форсирует handshake и отвергает входящие данные
KeepaliveTimeoutuint32,range, секЧерез сколько после последней отправки данных шлётся keepalive
MaxHandshakeAttemptsuint32,rangeПредел попыток handshake

⚠️ Защита заголовка требует S1–S4 не меньше 12 (README, «Header protection»): паддинг служит нонсом шифра. HeaderProtectionKey при S* < 12 — нерабочая связка.

Все семь ключей принимаются парсером tools — они есть в key_match (src/config.c, v3.0.20260730 и новее), в отличие от J1..J3/Itime. То есть в awg setconf их отдавать можно и нужно.

Наш статус: поддержаны — константа AWG3_INTERFACE_FIELDS в core/awg_config.py входит в WG_INTERFACE_FIELDS, поэтому поля переживают round-trip и доходят до демона. validate() проверяет их как тип range ("a-b" / "a" / "(off)" — числом их валидировать нельзя), HeaderProtectionKey — как base64-ключ на 32 байта, и отдельно ругается, если при заданном ключе минимальный из S1..S4 меньше AWG3_HEADER_PROTECTION_MIN_S (12).

⚠️ Раньше этих полей в списке не было, и AWG3-профиль молча терял их при render_setconf: демон поднимался без защиты заголовка, а пир, который её ждёт, дропал data-пакеты — тот самый «92 B in / 20 KB out» (§12). Тесты-сторожа: TestAwg3Fields в tests/test_awg_config.py.

2.1.2 AWG 3.1: случайные хвосты и отказ от cookie-ответов

Пара amneziawg-go v3.1.20260814 + amneziawg-tools v3.1.20260812 добавила ровно два ключа в секцию устройства. В README их нет — источник истины здесь только код: device/uapi.go (UAPI-ключи) и src/config.c (key_match).

КлючUAPI-ключТипНазначение
RandomTrailersrandom_trailersboolДописывать служебным пакетам (init / response / cookie) хвост случайной длины — до размера UDP-окна пира. Размер пакета перестаёт быть константой, по которой его опознаёт DPI
DisableCookiesdisable_cookiesboolНе отвечать cookie-reply на отброшенный handshake. Cookie-ответ — заметная сигнатура WireGuard, но это же и штатная анти-DoS-защита

⚠️ RandomTrailers симметричен — включать надо на ОБОИХ концах. Приёмник опознаёт служебный пакет по точному размеру и допускает больший только при включённом флаге (DeterminePacketTypeAndPadding в device/receive.go). Включён у клиента и выключен у сервера — handshake не проходит вовсе: пакет просто не распознаётся как init.

⚠️ Значение пишется как on/off или число, но НЕ true/false. parse_bool в src/config.c знает только on/off (без учёта регистра) и десятичное число (0 = выкл). На true он печатает «Boolean value is neither on/off nor 0/1» и, как на любой ошибке разбора, отбрасывает конфиг целиком. Наш validate() ловит это на импорте, пока ещё видно, какое поле виновато.

⚠️ Это отдельная планка поколения, а не «ещё два поля AWG 3+». Движок v3.0.x на этих UAPI-ключах отвечает invalid UAPI device key → EINVAL → знакомое «Unable to modify interface: Invalid argument». Поэтому required_generation() поднимает такой профиль до 3.1, а не до 3.0: подсказка «нужен AWG 3.0» пользователю, у которого как раз 3.0, увела бы совсем не туда.

Наш статус: поддержаны — AWG31_INTERFACE_FIELDS в core/awg_config.py входит в WG_INTERFACE_FIELDS, поэтому поля переживают round-trip и доходят до awg setconf.

2.1.2а Поле [Peer] AdvancedSecurity

В key_match секции [Peer] у tools, кроме стандартных PublicKey, PresharedKey, AllowedIPs, Endpoint, PersistentKeepalive, есть ещё AdvancedSecurity (флаг «продвинутой безопасности» для конкретного пира). Он есть и в нашем WG_PEER_FIELDS, так что импортированный профиль его не теряет.

PersistentKeepalive в AWG 3+ — тоже тип range: валидны 25, 22-30 и (off). validate() принимает все три формы и проверяет границы 0..65535 для числовых.

Junk vs padding vs header — не путать. Jc/Jmin/Jmax — отдельные мусорные пакеты ДО рукопожатия. S1–S4 — случайный префикс ВНУТРИ реальных пакетов каждого типа. H1–H4 — подменяют первый байт (тип сообщения), чтобы DPI не видел сигнатуру WireGuard.

2.2 H1–H4: ограничения

  • Стандартный WireGuard использует типы сообщений 1, 2, 3, 4 (init/ response/cookie/transport). H1–H4 их заменяют — но это работает, только если AmneziaWG-обфускацию понимает и пир. Cloudflare WARP — это ВАНИЛЬНЫЙ WireGuard, он H1–H4 ≠ 1,2,3,4 не понимает и дропает handshake. Поэтому для WARP warp_generator оставляет H1=1, H2=2, H3=3, H4=4S1=S2=0), а обфускацию даёт только junk-пакетами (Jc/Jmin/Jmax) — их ванильный WireGuard просто игнорирует. Нестандартные H* (5 … 0x7FFFFFFF) уместны лишь для AmneziaWG-aware сервера, не для чистого WARP (core/warp_generator.py). Проверено локально: против ванильного WG-пира handshake проходит ТОЛЬКО при S1=S2=0 и H1..H4=1,2,3,4; рандомные H* или S>0 → handshake не идёт.
  • В AmneziaWG 2.0 у H1–H4 появилась поддержка диапазонов (range): значения выбираются случайно в заданном окне и не должны перекрываться. В .conf это строка вида H1 = 123-456. parse_conf хранит H* как строки, а validate() принимает для H1–H4 либо одиночный uint, либо диапазон N-M (N<=M); прочие числовые поля обфускации остаются строгими int. amneziawg-tools (src/config.c) хранит H* как opaque-строки (parse_awg_string) — так что это лишь GUI-санити-чек формата.

2.3 Версии протокола и совместимость (КРИТИЧНО)

ВерсияЧто добавляетПараметры
1.0базовая обфускация: junk + magic-headers + padding init/responseJc, Jmin, Jmax, S1, S2, H1–H4
1.5мимикрия под обычные UDP-протоколы (QUIC, DNS…) через signature-пакеты+ I1–I5, J1–J3, Itime
2.0«полная мимикрия»: меняющиеся заголовки и размеры пакетов и в data-фазе+ S3, S4; range для H1–H4; − J1–J3, Itime
3.0 (AWG 3+)шифрование полей заголовка, кастомный паддинг содержимого, настраиваемые тайминги WireGuard+ HeaderProtectionKey, ContentPaddingAddition, RekeyAfterTime, RekeyTimeout, RejectAfterTime, KeepaliveTimeout, MaxHandshakeAttempts; тип range у таймингов и PersistentKeepalive (§2.1.1)
3.1случайная длина служебных пакетов, отказ от cookie-ответов+ RandomTrailers, DisableCookies (bool, on/off; §2.1.2)

Нумерация версий ≠ нумерация релизов, но с 3.0 они совпали. amneziawg-go прыгнул с v0.2.19 сразу на v3.0.0, и [AWG 3+] в README — это ровно поколение параметров этой ветки. Пользователь со старым бинарём (v0.2.x) AWG3-полей не понимает: демон их не применит, а awg из старого amneziawg-tools (v1.0.2026*) на них ещё и отбросит весь конфиг (Line unrecognized). То есть «профиль AWG3 + старая пара бинарей» = туннель не поднимется вовсе, а не деградирует.

Версия должна совпадать на обоих концах. Подключиться по 2.0 к старому пиру нельзя; в старом AmneziaVPN профиль 2.0 даже не покажется, хотя сервер его поддерживает (docs.amnezia.org). Это и есть инженерная причина "92 B in / 20 KB out": handshake собирается на общих параметрах и проходит, а data-пакеты пир дропает, потому что ждёт другой набор обфускации (например, на сервере включены S3/S4/I1, а в нашем конфиге их нет — или наоборот, мы их потеряли при парсинге, см. §3).


3. Формат .conf и наш парсер (core/awg_config.py)

API модуля: parse_conf(text) -> {"interface": {...}, "peers": [{...}]}, render_conf(cfg) -> text, validate(cfg) -> [errors], generate_keypair().

3.1 Какие поля куда идут

ГруппаКонстантаКуда применяется
Крипто + ListenPort + FwMark + вся обфускацияWG_INTERFACE_FIELDSв демон через awg setconf
Address, DNS, MTU, Table, PreUp, PostUp, PreDown, PostDown, SaveConfigWGQUICK_INTERFACE_FIELDSнаша wg-quick-логика в _do_up (демон их НЕ видит)
PublicKey, PresharedKey, AllowedIPs, Endpoint, PersistentKeepaliveWG_PEER_FIELDSв демон через awg setconf

WG_INTERFACE_FIELDS содержит: PrivateKey, ListenPort, FwMark, обфускацию v1 (Jc, Jmin, Jmax, S1, S2, H1, H2, H3, H4) и расширенную (S3, S4, I1–I5, J1–J3, Itime). Числовые валидируются как int (AWG_OBFUSCATION_FIELDS), а H1–H4 — как int ИЛИ диапазон N-M (§2.2); hex-blob I1–I5, J1–J3 — отдельно (AWG_V2_BLOB_FIELDS).

Голого поля I в AmneziaWG нет — signature-пакеты это I1…I5 (подтверждено парсером amneziawg-tools src/config.c: key_match только I1..I5). Раньше I ошибочно числился в наших списках как «v1»-параметр; убрано (см. CHANGELOG), чтобы случайный I= не ушёл в awg setconf — иначе тулза отбросила бы весь конфиг. Расширенный набор у нас исторически назван «v2», хотя по docs.amnezia.org J1–J3/Itime относятся к 1.5 и удалены в 2.0 — мы их просто пропускаем как есть, решение принимает движок.

3.2 Парсинг hex-blob I1–I5 (многострочный <b …>) — частый баг

I1…I5 в .conf приходят как бинарный blob в одной из форм:

# однострочная
I1 = <b 0xf6ab...>

# многострочная (закрывается '>' или новым 'Key=' или пустой строкой)
I1 = <b
0xf6ab34c1...
9d2e...
>

parse_conf накапливает hex-куски (pending_*/flush_pending) и склеивает их. Без этой обработки парсер брал только <b, и I1 терялся при render_setconf → handshake проходил, а сервер дропал data → ровно «92 B in / 20 KB out». Если меняешь парсер — не сломай blob-склейку; тесты — tests/test_awg_config.py.

3.3 Прочее

  • Голым адресам без маски parse_conf добавляет /32//128, чтобы awg/ip их приняли.
  • _is_base64_key проверяет ключи: 44 символа, заканчивается =, декодится в 32 байта. validate() ругается на кривые ключи/Endpoint/AllowedIPs.
  • render_conf пишет полный .conf (для хранения/показа), а в awg setconf уходит отфильтрованный временный файл (только setconf-поля).

4. Инструменты AmneziaWG (CLI)

Форк wireguard-tools, CLI идентичен — просто awg вместо wg:

КомандаНазначениеИспользуем мы?
awg show [<iface>] [dump]статус: handshake, transfer, endpoint, allowed-ipsда (status/diagnostics; dump — таб-разделённый машинный вид)
awg showconf <iface>дамп активного конфига демонада (диагностика — что реально принято)
awg setconf <iface> <file>залить конфиг в демон (replace)да (основной путь конфигурации)
awg syncconf <iface> <file>применить дельту без сброса peersнет (мы делаем setconf при up)
awg genkey / pubkey / genpskгенерация ключейчерез наш generate_keypair (Python)
awg set <iface> …точечная правканет
awg-quick up/down <conf>bash-обёртка (Address/MTU/Table/routes/DNS)НЕТ — реализуем сами (§1)
amneziawg-go <iface>запустить userspace-демон + TUNда (это и есть «движок»)

Альтернативы userspace-демону: модуль ядра amneziawg (DKMS / amneziawg-linux-kernel-module). Мы ставим/детектим userspace amneziawg-go (§7) — он не требует сборки под ядро роутера.


5. Жизненный цикл туннеля (awg_manager)

5.1 Подъём — _do_up

  1. validate() конфига; если ошибки — не стартуем.
  2. PreUp-хуки.
  3. amneziawg-go <iface> (subprocess) — форкает демон + TUN. PID находим через pgrep, пишем в <run_dir>/awg-<iface>.pid.
  4. короткая пауза (UAPI-сокет /var/run/wireguard/<iface>.sock должен подняться).
  5. awg setconf <iface> <filtered.conf> — крипто + обфускация.
  6. ip link set dev <iface> mtu <MTU> (если задан).
  7. ip addr add <Address> (каждый адрес).
  8. ip link set dev <iface> up.
  9. маршруты из AllowedIPstable <id> (если Table != off). id — стабильный хэш имени интерфейса в диапазоне 100…999.
  10. снимок состояния <run_dir>/awg-<iface>.last_up.json + список добавленных маршрутов <run_dir>/awg-<iface>.routes.json (чтобы корректно снять при down).
  11. PostUp-хуки → core.routing.applier.apply_all_on_interface_up().

5.2 Снятие — _do_down

Обратный порядок: PreDown → снять правила роутинга → удалить добавленные маршруты → ip link downip link delete dev <iface> → SIGTERM (затем SIGKILL) демону по PID → удалить pid-файл и UAPI-сокет → PostDown → откат auto-dnsmasq (если это был последний AWG-интерфейс).

restart = down → up. status(name) парсит awg show <iface> dump (per-peer: latest_handshake unix-ts, rx_bytes, tx_bytes).


6. Платформенные пути (awg_platform)

Keenetic/EntwareOpenWrtGeneric Linux
bin/opt/usr/sbin/usr/sbin/usr/local/bin
config/opt/etc/amneziawg/etc/amneziawg/etc/amneziawg
run/opt/var/run/awg/var/run/awg/var/run/awg
init/opt/etc/init.d/etc/init.d/etc/systemd/system

Файлы в run_dir: awg-<iface>.pid, awg-<iface>.routes.json, awg-<iface>.last_up.json.

UAPI-сокет демона лежит НЕ в нашем run_dir — путь задаёт сам движок:

БинарьКаталог сокета
amneziawg-go v3.x/var/run/amneziawg/<iface>.sock (ipc/uapi_unix.go: var socketDirectory = "/var/run/amneziawg")
awg (tools v3.1.20260812)тот же: SOCK_PATH RUNSTATEDIR "/amneziawg/" (src/ipc-uapi-unix.h)
унаследованный от wireguard-go (старые сборки v0.2.x)/var/run/wireguard/<iface>.sock

Единый список каталогов — awg_platform.UAPI_SOCKET_DIRS (v3-путь первым); platform.uapi_paths(iface) отдаёт все кандидаты, uapi_path(iface) — существующий, иначе путь текущей ветки. Подчистка в awg_manager._cleanup_iface() и поиск интерфейсов в awg_detector обходят оба каталога: на роутере вполне может стоять и старый amneziawg-go.

Раньше оба места были захардкожены на /var/run/wireguard/, и с бинарями v3 сокет после SIGKILL оставался лежать, а обнаружение интерфейсов по сокетам не находило ничего. На путь ЗАПУСКА это не влияло и не влияет — _do_up сокет намеренно НЕ ждёт (был регресс, ронявший AWG на Keenetic, см. комментарий в _do_up). Сторож — TestUapiSocketDirs в tests/test_awg_manager_lifecycle.py.

Shortened here. Read the whole file on GitHub.

Signals

GitHub stars
133
Forks
10
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
awg
Source
github.com/avatardd/zapret-gui