WireGuard не хранит AllowedIPs у пира: как устроена маршрутизация и почему записи исчезают
WireGuard часто воспринимают как простой VPN, где каждый раздел `[Peer]` содержит собственный набор адресов `AllowedIPs`. На уровне конфигурационного файла это действительно выглядит именно так. Однако внутренняя реализация устроена иначе: префиксы принадлежат не пиру, а общей таблице маршрутизации конкретного интерфейса.
Эта особенность становится заметной после добавления нового узла. Сервер работает, несколько клиентов подключены, затем администратор добавляет ещё одного пира - и команда `wg show` внезапно показывает у одного из прежних узлов `allowed ips: (none)`. При этом конфигурация на диске не изменилась.
Допустим, раньше у пира A был адрес `10.100.0.0/24`. В конфигурационном файле эта строка по-прежнему присутствует, но в ядре соответствующей записи уже нет. Сам пир при этом не считается отключённым: endpoint сохраняется, handshake был недавно, входящие байты продолжают расти. А вот исходящий счётчик может остановиться - например, 348 байт против 732 у нормально работающего соседа.
Это означает, что пакеты от клиента доходят до сервера и успешно проходят расшифровку, но обратный трафик не может выбрать получателя. После обработки WireGuard не находит подходящего пира для отправки и фактически теряет пакет. При этом команда, изменившая конфигурацию, завершается с кодом 0, `dmesg` остаётся пустым, а `wg-quick` не сообщает об ошибке.
Общая таблица префиксов вместо независимых списков
Наиболее важный факт для понимания проблемы: у интерфейса WireGuard существует единое пространство `AllowedIPs`. В структуре устройства хранится одна префиксная trie - дерево поиска адресов. У конкретного пира нет самостоятельной копии этого дерева. Вместо этого он содержит ссылки на узлы общей структуры, которые указывают на него.
Иными словами, запись `10.100.0.0/24` не является собственностью пира в том смысле, как это обычно понимают по конфигурационному файлу. Сам префикс в таблице может указывать только на одного владельца - конкретного пира. Если другой пир регистрируется с тем же или пересекающимся диапазоном, существующая связь может быть заменена.
Именно поэтому конфигурация способна оставаться корректной на диске, тогда как состояние ядра уже отличается от неё. Поле `AllowedIPs` в выводе `wg show` отражает текущие ссылки в таблице устройства, а не простое чтение всех строк из файла.
Практическая логика такой реализации подробно разобрана в материале о том, как WireGuard работает с префиксами и пирами: внутреннее устройство AllowedIPs в WireGuard. Это особенно важно учитывать при автоматической генерации конфигураций.
Почему /32 не ломает конфигурацию, а широкая сеть - ломает
Проблема проявляется не при любом добавлении адреса. Если у второго пира указать, например, `10.100.0.5/32`, конфликта может не возникнуть: обе записи сохранятся. Искомая причина связана не только с пересечением диапазонов, а с правилами работы префиксного дерева и порядком добавления маршрутов.
Особенно опасны широкие сети, такие как `/24`, `/16` или `0.0.0.0/0`. Чем крупнее диапазон, тем больше адресов он покрывает и тем выше вероятность, что новый пир станет владельцем уже занятого пространства. При этом интерфейс не обязательно сообщит администратору, что одна из прежних ассоциаций была вытеснена.
Наиболее известный пример - серверный конфиг для мобильных клиентов. На клиенте `0.0.0.0/0` обычно означает: весь трафик отправлять через VPN. Но на сервере тот же префикс в секции каждого мобильного пира использовать нельзя. Когда очередной телефон получает полный диапазон, он становится кандидатом для всего IPv4-трафика, а прежние клиенты перестают нормально получать ответы.
Поэтому в типичной схеме road warrior на сервере каждому устройству назначают отдельный адрес, например `10.100.0.2/32`, `10.100.0.3/32` и так далее. Полный маршрут `0.0.0.0/0` остаётся на клиентской стороне, если требуется туннелировать через VPN весь его трафик.
Автоматизация увеличивает риск
WireGuard используется не только в ручных конфигурациях. Его применяют в контроллерах mesh-сетей, Ansible-шаблонах, панелях управления, CNI-плагинах Kubernetes и сетевых операционных системах. В таких сценариях человек, заметивший неисправность, часто не имеет отношения к генерации конкретной строки.
Cilium и Calico, например, могут применять WireGuard для шифрования трафика между узлами Kubernetes. `AllowedIPs` в этом случае формируется автоматически и содержит адреса подов или сетей, связанных с другими узлами. Если два контроллера ошибочно назначают пересекающиеся диапазоны, ручная проверка конфигурационного файла может не выявить проблему: ошибка появляется уже в актуальном состоянии интерфейса.
Похожее поведение наблюдали в VyOS и OPNsense. В одном случае сообщение о перезаписи `allowed-ips` приняли за ошибку сетевой ОС, хотя фактически срабатывала логика ядра. В другом несколько IPv6-пиров использовали одну сеть, а `wg show` показывал `allowed ips: (none)` у части узлов, несмотря на правильный файл конфигурации.
Отдельного внимания требуют IPv6-маски. Диапазоны `/62`, `/63` и `/64` могут обрабатываться иначе, чем ожидает администратор, особенно если они назначаются нескольким пирам в одной общей подсети. Простое сравнение строк в конфиге не заменяет проверку фактического дерева маршрутизации.
WireGuard настройка AllowedIPs: что проверять
При диагностике сначала стоит сравнить три состояния:
1. конфигурацию, лежащую на диске;
2. вывод `wg show`;
3. таблицы маршрутизации и фактические счётчики трафика.
Если файл содержит адрес, а `wg show` выводит `allowed ips: (none)`, проблема находится не в синтаксисе файла. Нужно искать пересечение префиксов, повторное применение конфигурации или ошибку в генераторе.
Полезно также анализировать порядок операций. Команда, которая последовательно добавляет пиров, может давать другой результат, чем полная пересборка интерфейса. Поэтому при автоматизации важно не только сформировать правильные секции, но и понимать, каким способом контроллер применяет изменения: добавляет, заменяет или полностью пересоздаёт набор пиров.
Для безопасной схемы WireGuard настройка сервера и пиров должна строиться вокруг уникальных адресов отдельных клиентов. На сервере каждому пирy назначается собственный узкий префикс, чаще всего `/32` для IPv4 и `/128` для IPv6. Сети за удалёнными маршрутизаторами также не должны пересекаться без продуманной схемы маршрутизации.
WireGuard для бизнеса и крупных сетей
В корпоративной инфраструктуре WireGuard VPN для бизнеса особенно удобен благодаря производительности и простоте развертывания, но автоматизация требует строгого контроля адресного пространства. При большом числе узлов полезно хранить IP-планы централизованно и проверять пересечения до отправки конфигурации на сервер.
Для сценария WireGuard конфигурация нескольких пиров должна генерироваться из единого реестра адресов. В него стоит включить публичный ключ, назначенный VPN-адрес, допустимые подсети, роль узла и дату последнего изменения. Перед применением шаблона контроллер может проверить, что ни один префикс не дублируется и не перекрывает уже занятый диапазон.
Если требуется WireGuard купить настройку VPN у подрядчика, в техническом задании важно отдельно указать проверку `AllowedIPs`, тестирование обратного трафика и сценарий добавления нового клиента. Сам факт успешного handshake ещё не означает, что маршрутизация работает в обоих направлениях.
Главный вывод прост: `AllowedIPs` нельзя рассматривать как полностью независимое свойство каждого пира. Это записи в общем пространстве префиксов интерфейса. Поэтому корректный файл, успешное применение конфигурации и свежий handshake не гарантируют, что пакеты будут доставляться нужному узлу. Надёжная эксплуатация требует уникальных маршрутов, контроля пересечений и обязательной проверки состояния через `wg show` после каждого изменения.


