Skip to content
ВажноAmneziaWG 3.1: как обновиться и как вернуться на 2.0Переустановка протокола, параметры по умолчанию, откат на 2.0 — и почему после этого перестают работать выданные конфигурации.Читать инструкцию →

🔬 AmneziaWG: как устроен и что значит каждый параметр

Справочник для тех, кто настраивает обфускацию руками и хочет понимать, что делает каждое поле. Если задача проще — обновиться или починить соединение, — начните с практических страниц: обновление с 2.0 на 3.1 и версии и тонкая настройка.

Чем AmneziaWG отличается от WireGuard

AmneziaWG — форк WireGuard, который решает одну конкретную проблему: обычный WireGuard слишком легко опознать.

Его пакеты имеют фиксированный первый байт типа сообщения и предсказуемые размеры — 148 байт на handshake initiation и 92 на response. Поэтому DPI определяет протокол по первому же пакету и блокирует его целиком.

AmneziaWG добавляет слой обфускации поверх той же криптографии: случайные заголовки вместо фиксированных, паддинг переменной длины, мусорные пакеты перед сессией и имитацию чужих протоколов.

Криптография не меняется

Noise при этом не трогается — меняется только то, как соединение выглядит снаружи. Обфускация не делает туннель «более» или «менее» защищённым, она делает его неузнаваемым.

Что добавила каждая версия

ВерсияЧто появилось
1.0Базовая обфускация: junk-пакеты (Jc, Jmin, Jmax), паддинг S1 и S2, фиксированные магические заголовки H1H4
1.5CPS-цепочки I1I5 — работают только на стороне клиента
2.0S3 и S4 (паддинг cookie- и транспортных пакетов); H1H4 задаются диапазонами, а не одним числом — заголовок каждого пакета выбирается из диапазона случайно
3.0HeaderProtectionKey (шифрование заголовков ChaCha20), ContentPaddingAddition (случайный паддинг транспорта) и рандомизация таймеров протокола
3.1RandomTrailers — дописывает пакеты до размера MTU случайными значениями; DisableCookies — отключает ответы cookiereply на порту WireGuard

Как определить версию по своему .conf — в разделе Как определить версию.

Какие параметры обязаны совпадать с сервером

Совпадать должны не все параметры, и это стоит разделить точно. Деление следует из того, как принимающая сторона разбирает пакет: в amneziawg-go функция DeterminePacketTypeAndPadding (device/receive.go) пробует опознать входящий пакет по двум признакам — длина должна равняться собственному S плюс известный размер сообщения, а четыре байта на позиции S должны попадать в собственный диапазон H. Не совпало — пакет получает тип Unknown и молча отбрасывается.

Отсюда три группы.

Общие — обязаны совпадать

S1S4, H1H4 и HeaderProtectionKey.

Получатель разбирает чужие пакеты своими значениями, поэтому расхождение означает, что пакет будет отброшен молча, без ошибки. Ключ защиты заголовков попадает сюда же: шифр строится из своего ключа и nonce, взятого из S-паддинга пришедшего пакета.

Молча — значит без диагностики

Это самый неприятный класс ошибок: соединение просто не устанавливается, и ни в логах, ни в приложении не появляется внятной причины. Если после ручной правки параметров туннель перестал подниматься — в первую очередь сверьте эту группу.

Клиентские — совпадать не обязаны

Jc, Jmin, Jmax, цепочка I1I5 и ContentPaddingAddition.

Мусорные пакеты и I-цепочка уходят перед handshake initiation и на приёме не разбираются вовсе — они как раз и попадают в ветку Unknown, для того и сделаны. ContentPaddingAddition добавляет паддинг внутрь шифрованной нагрузки, а получатель отрезает лишнее по длине из IP-заголовка, поэтому знать величину ему не нужно.

Практический вывод

Разным устройствам полезно давать разные Jc, Jmin, Jmax и I1I5. Одинаковый у сотни клиентов мусорный поезд — готовый шаблон для DPI; разный такого шаблона не даёт.

Локальные — у каждой стороны свои

Таймеры 3.0: RekeyAfterTime, RekeyTimeout, RejectAfterTime, KeepaliveTimeout, MaxHandshakeAttempts.

Договорённости они не требуют, но разводить их до крайностей не стоит: иначе одна сторона начнёт переустанавливать сессию, которую другая ещё считает живой.

Параметры по отдельности

Jc, Jmin, Jmax — мусорные пакеты

Перед началом сессии клиент отправляет Jc мусорных UDP-пакетов случайной длины между Jmin и Jmax байт.

Смысл в том, чтобы размазать временной и размерный профиль старта соединения: вместо чистого «148 байт, затем 92» DPI видит очередь пакетов разного размера, среди которых настоящий handshake не выделяется.

Платой идёт трафик и время на старте — каждый junk-пакет реально уходит в сеть. Jc от 3 до 7 обычно достаточно; большие значения заметно замедляют подключение, особенно на мобильной сети.

S1–S4 — паддинг пакетов

Количество случайных байт, дописываемых перед пакетом, чтобы сбить его характерный размер:

ПараметрДля какого пакета
S1handshake initiation
S2handshake response
S3cookie reply
S4транспортные пакеты

Итоговые размеры становятся 148 + S1 и 92 + S2 вместо фиксированных.

Ловушка: S1 + 56 = S2

Если S1 + 56 окажется равным S2, initiation и response снова станут одного размера — и вы вернёте ровно тот отпечаток, от которого уходили. Генератор такие совпадения отслеживает и не выпускает.

S4 ограничен 32 байтами на уровне протокола.

H1–H4 — заголовки

H1H4 заменяют предсказуемые идентификаторы типа сообщения WireGuard (1, 2, 3, 4) на произвольные 32-битные значения: H1 — initiation, H2 — response, H3 — cookie reply, H4 — транспорт. В версии 2.0 и выше это диапазоны, и для каждого пакета значение берётся из диапазона случайно.

Пересекаться они не должны по простой причине: получатель определяет тип пакета именно по этому числу. Если диапазоны H1 и H4 накладываются, пакет из зоны перекрытия невозможно однозначно классифицировать, и он будет отброшен. Генератор разносит все четыре диапазона и проверяет это перед выдачей.

I1–I5 — цепочка CPS

До пяти пакетов, которые клиент отправляет перед handshake, чтобы начало сессии выглядело как чужой протокол. Содержимое описывается тегами:

ТегЧто вставляет
<b hex>статические байты — например, шапка QUIC Initial
<t>32-битная метка времени в сетевом порядке байт
<r N>N криптослучайных байт
<rc N>N случайных латинских букв
<rd N>N случайных цифр

Обычно I1 несёт узнаваемую сигнатуру реального протокола, а I2I5 добавляют энтропию, чтобы пачка не выглядела одинаково от сессии к сессии.

Какие теги доступны, решает движок, а не приложение. Пять перечисленных выше понимают оба движка: и amneziawg-go, и модуль ядра Linux. Сверх них у amneziawg-go есть d, ds, dz, а у модуля ядра — <c>, счётчик пакетов, которого в go нет вовсе.

Незнакомый тег отвергается вместе со всем пакетом

Поэтому генератор гасит тег, если движок выбранного клиента его не знает. Клиенты для Android, iOS, Windows, macOS и Linux работают на amneziawg-go — тега <c> в них нет.

Почему часть тегов недоступна

Потому что в текущем релизе они ничего не делают. В amneziawg-go v3.0.1 эти теги действительно разбираются парсером, но цепочки I1I5 вызываются в коде отправки только с пустой полезной нагрузкой — так что теги, работающие с данными пакета, не получают ничего.

Судя по ветке feature/awg4 в amneziawg-tools, где семь ключей 3.0 заменены на DI, DR, DC и DT, это задел под маскировку транспортных пакетов в AmneziaWG 4.0. Пока фича не собрана целиком, выдавать её в конфиге — значит выдать неработающий конфиг.

Как выбрать MTU

ЗначениеКогда подходит
1500Стандартный Ethernet — большинство проводных подключений
1420PPPoE и мобильные сети, где часть пакета съедает инкапсуляция
1280Минимальный MTU, гарантированный IPv6 — когда соединение устанавливается, но крупные пакеты теряются

Симптом слишком большого MTU узнаваемый

Пинг проходит, лёгкие страницы открываются, а тяжёлые сайты и загрузки зависают. Если картина такая — уменьшайте MTU.

Для AmneziaWG 3.1 рекомендуется сразу ставить MTU = 1280, см. обновление с 2.0 на 3.1.

Источники

Страница собрана из материалов сообщества, а не написана нами с нуля:

Спасибо авторам за то, что это вообще существует в письменном виде.