В начале года я разработал AmneziaWG контейнер для Mikrotik. С тех пор произошло довольно много изменений, и судя по тому, как на хабре часто выходят разного рода статьи, где то один, то другой придумывает и вайбкодит свой новый впн-клиент, то складывается впечатление, что об Amnezia уже все забыли, хотя она очень даже помогает решать рабочие задачи.
TLDR
В данный момент это самый быстрый контейнер (весом 94.7 КБ) для Mikrotik, который реализует протокол AmneziaWG: максимально эффективно утилизируя ресурсы роутера. Протокол AmneziaWG на 80% состоит из обычного Wireguard, и на 20% состоит из своих дополнений, поэтому берем родной микротиковский Wireguard (который очень эффективно работает с криптографией на отдельном чипе), а остальное реализовываем программно. Так получился очень маленький и быстрый контейнер, обеспечивающий почти 300мбит на устройствах типа Mikrotik Hap Ax3, и 200мбит на Mikrotik Hap Ax2. Как вишенка на торте — он сам умеет быть сервером, помогая соединять микротики друг с другом.
Что это?
Маленький контейнер, который позволяет роутерам mikrotik подключаться к amneziawg серверам, с полной поддержкой протокола AmneziaWG 1.0, 1.5, 2.0, 3.0, 3.1. Работает прямо на роутере, а значит вы можете сами настроить/донастроить нужную вам маршрутизацию.
Как работает?
Протокол AmneziaWG на 80% состоит из Wireguard. Это проверенный и надежный протокол, который ещё в 2020 году сам Линус включил в ядро Linux — он простой(значит быстрый), понятный, безопасный. Да, про безопасность в последнее время все забили подзабыли — ставят всякие непонятные клиенты из appstor’а, все вокруг кодят свои реализации vpn по принципу «лишь бы работало», хотя раньше вопрос надежности и доверия было одним из главных требований…
Так вот, остальные 20% — это накрутка AmneziaWG, которая добавляет рандомных мусорных пакетов, для усложнения обнаружения трафика. И так как в роутерах Mikrotik уже есть полноценная и хорошая реализация Wireguard, но нет AmneziaWG — значит можно взять wireguard, а остальное докодить самому. Так и появился awg-proxy — контейнер, реализовывающий amneziawg.
Бан от github’а
Когда я написал статью и опубликовал её — буквально в тот же день проект набрал 150 звезд(!). Я обрадовался, чуть дотюнил проект, покрыл её тестами, лёг спать, а на утро увидел, что github его забанил! В личку уже полетели вопросики, а я, толком не спав, вскочил и начал разбираться. Сначала подумал, что так github душит всё что ему кажется подозрительным, отправил аппеляцию, но она рассматривается очень долго. Сильно не тупил — создал второй аккаунт, переопубликовал проект в нём (не делая изменений), но и его github очень быстро удалил. В это время уже наступило утро, просмотры статьи росли, а ссылки вели на нерабочие контейнеры.
Поняв, что я делаю что-то не так пошел думать, где же я резко ошибся. Спустя пару часов я понял, что причина в моих новых свежих тестах: по ошибке, я добавил и по глупости закоммитил в проект тесты, которые запускаются при сборке и коннектятся к сетевым адресам. А сборку я сделал сразу на github actions. А это сразу красный флаг: кто-то просит «github actions» подключаться к каким-то внешним серверам, что очень похоже на вредоносную активность, за которую гит быстро банит. В общем, я вырезал такие тесты, и уже текущий репозиторий (на момент публикации статьи имеет 371 звезду) больше не банился (тьфу-тьфу!). С самого начала я ориентировался на простоту, поэтому создал конфигуратор, с которым довольно легко можно получить список команд для микротика, когда лень разбираться (мне самому было бы лень всё это изучать).
Amnezia 2.0?
Буквально первый же комментарий от @sirota сообщил, что amneziawg буквально недавно выпустила версию awg 2.0. Пока я был занят разработкой — я проспал это нововведение, и оперативно добавлял поддержку этой версии. Из ключевого, в awg 2.0 значительно усилили протокол, добавив рандомный размер паддинга пакетов, что по сути смещает весь траффик от wireguard на рандомное количество байт, а значит, станосится сложнее определить что это за трафик.
А можно быстрее?
Контейнер был написан на Go, но всё равно мне казалось что можно быстрее. В итоге, с помощью claude code контейнер был переписан на Си, что дало выигрыш как по скорости и памяти, так и по размеру: контейнер уменьшился с 5МБ до 80-90КБ, а пропускаемые через себя трафик — сразу на 50%. Причина очень проста: Go тянет довольно тяжелый «лишний» обвес в виде дополнительных инструкций безопасности, в то время как Си реализует всё нативно. Меньше инструкций = меньше тактов ЦПУ на пакет = выше пропускная способность трафика.
Чтобы их не смешивать и всё-же оставить дань наследия решению на Go, создал отдельный репозиторий, он и стал основным.
Отдельно хочу поблагодарить Виктора @wiktorbgu, за оказанную поддержку и независимые тесты. У него есть свой неплохой канал по сетевым технологиям — советую подписаться (ссылок не будет, найдете если надо. А у меня своего нет и наверное не будет, сорян, даже не ищите хе-хе).
Есть потребность связывать микротики друг с другом
Представим ситуацию: вам нужно связать два офиса друг с другом, но обычные протоколы не работают по той или иной причине. А у нас вроде есть рабочий awg, но он не умеет связывать микротики друг с другом. Не беда — доработка напильником, реализация реверс-алгоритма, и мы получаем серверный режим awg. Под капотом — всё тот же родной микротиковский Wireguard, обеспечивающий безопасность и быстрое шифрование на отдельном чипе, снаружи — протокол awg в контейнере.
Чтобы было легче добавлять будущих клиентов — в разделе mikrotik: container -> envs сохраняется ссылка на конфигуратор с параметрами вашего конфига амнезии. Просто открываете его, и ваш конфигуратор просто спрашивает какого по счету №№ клиента генерируем.
Конфигуратор, кстати, полностью оффлайновый. Ни один запрос, ни одна кнопка или метрика не отправляет запрос наружу. Всё в стиле шифропанка, как мы любим.
Что было потом
Потом добавил поддержку dns-имён (даже в самой amneziavpn она появилась много позже) в виде адреса сервера. Полезно, когда адрес динамический. Было несколько ошибок, когда ip от dns резолвился лишь один раз при старте контейнера, а при его смене, контейнер не утруждался узнать новый. Добавил поддержку RU-диапазона адресов, для динамической(выборочной) маршрутизации трафика.
Начали поступать issues в проект, один из них пожаловался, что контейнер плохо работает на PPPOE. Оказалось, проблем несколько: неоптимальный и несогласованный MTU, из-за которого пакет выходил из Wireguard размером с 1420 байт, а выходной интерфейс его мог порезать до 1400 байт. Изучив TCP, выяснил что стоит обнулять специальный флаг DF (don’t fragment), указывающий на запрет фрагментации пакета, и так у нас пакеты дробились, что повышало качество протокола.
С MTU вообще отдельная история: по-умолчанию в wireguard размер пакета (mtu) составляет 1420 байт (20 байт IPv4 + 8 байт UDP + 32 байт WireGuard + 20 байт внутренняя инкапсуляция IPv4 = 80 байт от обычных 1500 в ethernet). Далее, идет обвязка awg которая с версии AWG 2.0+ съедает от 0 до 128 байт от полезного трафика. Всё зависит от значения S4: чем его диапазон больше, тем больше отъедается полезной нагрузки, а значит и пропускной способности.
Далее добавил поддержку ipv6 — в оригинальном amneziawg она есть из коробки (как и в wireguard), а вот AmneziaVPN всё ещё не поддерживает его, хотя казалось бы — в наше время легко реализуется с помощью кодинговых агентов. Собственно, хоть и ipv6 внедряется очень медленно, но не реализовать его поддержку там, где он есть — было бы большой ошибкой, так-что теперь ipv6 тоже полностью поддерживается в контейнере, в том числе с работой через dns, в том числе в dual-режиме: если по dns-имени получаем сразу 2 адреса: ipv6+ipv4, то сначала пытаемся подключиться по ipv6, а в случае неудачи переключается на ipv4.
Отсюда получаем таблицу полезной нагрузки (MTU) — если значение S4 больше 16, то полезная нагрузка значительно снижается. Поэтому, его рекомендуется держать в пределах 12-16.
|
Размер S4 (в байтах) |
MTU IPv4 |
MTU IPv6 |
|---|---|---|
|
0 |
1420 |
1420 |
|
12 |
1420 |
1408 |
|
16 |
1420 |
1404 |
|
24 |
1416 |
1396 |
|
65 |
1375 |
1355 |
|
148 |
1292 |
1272 |
Конечно, это всё добавил в конфигуратор, чтобы он видя ваш S4 сам подбирал MTU в изначальном wireguard-интерфейсе.
Awg 3.0
В августе вышел AmneziaWG 3.0: он довольно интересно реализовывает имитацию поведения и маскировку под довольно популярные протоколы, такие как Quic, и вообще позволяет задавать свои паттерны пакетов (подробнее здесь, неплохой разбор от @meshroom). К тому времени я взял уже полюбившийся Claude Code и адаптировал контейнер под него. Не то, чтобы я этим горжусь, но и время своё я ценю. Обложил контейнер тестами, погонял вдоль и поперёк у себя, выложил.
Недооценённая фича: Рандомизация портов
После очередной волны банов (в т.ч. моего сервера. за что? я ведь только до нужных мне сервисов дотягивался…), я задумался как же сделать так, чтобы сервер вызывал меньше подозрений. В общем я пришел к выводам:
-
Протокол AWG 3.0 в целом неплох
-
Однако всё-равно серверы попадают в бан
-
Чтобы снизить подозрительность сервера, надо всем клиентам менять порт. Лучше почаще, так как это делает тот же torrent или webrtc. Рандомные порты в обе стороны = сервер проживет дольше.
Очень много внимания в интернете уделяется маскировке трафика, и так мало внимания уделяется простой периодической смене портов. Это как гигиена смены ipv4 адреса, только для портов. Чем больше трафика идет с разных адресов на один и тот же порт целевого сервере — тем больше накапливается «статистики» и подозрений. Так-что чтобы его избежать был придуман (я не заявляю первенство, но и не подсматривал ни у кого такое) довольно простой механизм: на сервере настраивается проброс диапазона портов через iptables в amneziawg server, и на клиенте в контейнере прописывается порт в виде диапазона: 10000;20000;55000-57000 — контейнер при подключении берет рандомный из них и пробует подключиться.
В версии 1.4.5 (актуальная) научил контейнер самостоятельно прыгать-периодически менять порт (главное прописать в ENV контейнера диапазон портов). Как мне кажется, это очень недооцененная фича, и я был бы рад, если бы её завезли в оригинальный awg/amneziavpn клиенты.
Генерация ключей по ssh?
Многие из вас пользовались AmneziaVPN — она позволяет сгенерировать конфиг подключения. Однако у неё есть очень важный изъян: она подключается к серверу по ssh и генерирует ключик, выполняя команды на сервере. Парочку моих серверов забанили буквально через несколько часов после того, как я с домашнего/мобильного интернета подключился к серверу. Кроме того, Appstore перестал принимать обновления клиентов amneziavpn в котором они реализовали протокол awg 3.0, так-что, например, моя знакомая не могла им пользоваться. Единственный обновляемый был AmneziaWG , который является форком от Wireguard: всё тот же неприятный туповатый интерфейс, который при создании туннеля просит назвать его на латинице. Так вот, чтобы решить сразу обе эти проблемы я завайбкодил телеграмм-бота, который помогает генерировать конфиги для амнезии. Он поддерживает как докерезированный amneziavpn, так и базовый нативный amneziawg server, и выдаёт строку подключения сразу как в виде QR-кода для AmneziaWG, так и ключик текстом для amneziavpn.
Ipv6
Про ipv6 стоит сказать отдельно: он не просто поддерживается, а очень даже работает. Поддерживается как клиентский режим, так и серверный режим(когда ваш микротик принимает подключения). И если вы ещё не используете ipv6 — советую всё-же перейти на него.
Оффлайн версия
Несколько issues в проекте висели довольно долго — там просили добавить режим оффлайн-установки. Это когда роутер не имеет доступа в интернет(до github), но их по какой-то причине им надо установить контейнер. Такой вариант оффлайн-установки тоже был добавлен в конфигуратор.
Увеличение скорости
До сих пор контейнер упирался примерно в ~180мбит на download и ~80мбит на upload на протоколе awg 3.0 (на awg 1.0 выжимаются все 250мбит в обе стороны). При этом, во время спидтеста скорость скачет от 250мбит до 100мбит. Столь значительный разбег просто не давал мне спать. Я не мог понять из-за чего он случается! Я перепробовал 100500 разных техник и механик — но все они были безрезультатные — всё упирается в фиксированный размер буфера интерфейса в 416 КБ , и ничем его нельзя было увеличить (вендор лок от микротика). Во время спидтеста (или прочей высокой нагрузки на сеть) происходит вот что:
-
Компьютер в сети отправляет запрос на скачивание
-
Удаленный сервер начинает отдавать вам кучу контента
-
Этот контент поступает на интерфейс микротика, который ограничен 416 КБ
-
CPU, выделенное на контейнер не успевает обрабатывать пакеты (я всё пробовал чтобы успевал — никак)
-
В итоге микротик отбрасывает пакеты, которые не успели обработаться
-
Растет количество потерь
-
Протокол TCP видя потери снижает размер окна вдвое (скорость режется вдвое)
-
В итоге скорость резко проседает и довольно медленно растёт, пока снова не вызовутся потери
И вот, выходит версия RouterOS 7.24 в котором они втихушку выпускают параметр privileged=yes, который позволяет разблокировать в контейнере буквально всё, и самое главное — позволяет управлять размером буфера! После кучки проб я остановился на размере буфера в 32МБ — это достаточно много, чтобы успеть всё обработать, и по идее не должно сильно отъедать микротики. Даже на самых простых микротиках вроде hap ac2 оперативная память составляет 128МБ, большая часть из которых свободно.
Такое увеличение буфера позволило наконец-то убрать ограничения буфера интерфейса, и наконец упереться в ЦПУ. Наконец-то мы достигли максимально возможной производительности!
AWG 3.0 Hap ax2: 200-250mbit
AWG 3.0 Hap ax3, RB5009B: 250-350mbit
На данный момент этот контейнер является самым быстрым решением, реализующим amneziawg протокол. Если у вас этот протокол получится ещё лучше — пишите, я с радостью поставлю на вас ссылки!
Поддержка WARP-клиентов
Среди всех issues несколько раз всплывало то, что часть людей использовали этот контейнер в виде warp-клиента. Я такого поведения не ожидал, я затачивал и тестировал только на amneziawg-клиентах. Во всех этих issues просили добавить парочку функций по автовосстановлению соединения, что собственно и было добавлено.
Итого
С момента публикации контейнер значительно преобразился — повышена производительность и устойчивость к ошибкам, реализовано довольно много фич. Самое главное — такие контейнеры работают стабильно, проект набрал 370+ звезд и продолжает развиваться.
Собственно всё, надеюсь вы узнали из данного материала что-то новенькое!
Disclaimer. Материал носит образовательный и ознакомительный характер и посвящён вопросам работы протокола AmneziaWG. Примеры приводятся для сценариев защищённого удалённого доступа к собственным системам и инфраструктуре (администрирование, корпоративные сети, тестовые стенды). Не используйте информацию из статьи для нарушения законодательства РФ и иных применимых норм, а также правил площадок и провайдеров. Автор не несёт ответственности за последствия использования описанных подходов.
ссылка на оригинал статьи https://habr.com/ru/articles/1102150/