Начните там, где появляется сообщение. Клиент подключается, туннель поднимается, и затем журнал сообщает, что команда добавления маршрута в Linux завершилась ошибкой File exists. Ничто в этой фразе не относится к сертификату, ключу или файлу конфигурации, хотя слова это подсказывают. Ядро описывает свою таблицу маршрутов, и у префикса, который вы просили установить, уже есть запись.

Следуйте собственному порядку клиента: что он запросил, что уже содержала таблица, кто поместил эту запись туда, и только потом что менять. Каждый шаг убирает одного возможного владельца.

Что клиент на самом деле запрашивал

Перед сбоем клиент записывает маршрут, который собирается добавить, обычно как пункт назначения, маску сети, шлюз и иногда как метрику или таблицу. Эта строка — запрос. Следующая за ней ошибка — ответ ядра, и оба нужно читать рядом.

journalctl -u openvpn-client@office -b --no-pager | grep -nE 'route|File exists'
openvpn --config /etc/openvpn/client/office.ovpn --verb 4 --log /tmp/ovpn.log

Ненулевой код выхода помощника маршрутов менее информативен, чем текст под ним, потому что разные ответы ядра дают ненулевой статус. Сохраните точное сообщение; различие между существующей записью и недоступным шлюзом решает, какой из следующих разделов применим.

Читайте существующий маршрут, а не только адрес

Поиска в таблице того же точечного четверика недостаточно. Объект маршрута определяется семейством адресов, таблицей, префиксом назначения, метрикой, протоколом и выходным устройством, и записи, разделяющие префикс, могут законно сосуществовать, когда эти атрибуты различаются. Сталкивается весь объект, а не текст.

ip -4 route show table all | grep -F '10.40.'
ip -4 route show match 10.40.0.0/16
ip -4 route get 10.40.0.5

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

Запишите префикс, таблицу, метрику и устройство рядом с неудачным запросом. Если существующая запись имеет те же атрибуты и тот же следующий переход, у вас дублированная инструкция, а не проблема маршрутизации.

Четыре владельца, которые могут быть у префикса

Подключённые маршруты происходят из назначенного адреса и пересоздаются системой всякий раз, когда этот адрес существует. Клиент DHCP или менеджер соединений устанавливает маршруты как часть своего жизненного цикла. Другой клиент VPN может уже нести тот же префикс. А локальный хук или скрипт может добавить такой, о котором больше ничего не знает.

Каждому владельцу нужна своя коррекция. Подключённый маршрут не ваш для удаления; его удаление может нарушить локальный доступ до того, как туннель станет пригодным, и ядро вернёт его. Маршрут, принадлежащий менеджеру, следует менять через этого менеджера, а не вручную с помощью ip route del, которое отменит следующее переподключение.

Сохранённый интерфейс облегчает ту же путаницу. Когда устройство туннеля переживает переподключение, маршруты, установленные собственным кодом настройки, могут оставаться и при втором запуске, поэтому скрипт, предполагающий чистое состояние, падает во второй раз и работает в первый. Либо намеренно очистите устаревшую запись, либо сделайте код настройки идемпотентным.

block-local отвечает на другой вопрос

Когда профиль отправляет весь трафик через туннель, клиент должен решить, что происходит с локальной сетью. Флаг block-local меняет это решение, направляя локальную LAN через туннель и сохраняя документированное исключение для шлюза LAN; это выбор политики трафика с видимыми последствиями для доступности.

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

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

Замкните цикл: удалите дубликат в его источнике

Когда вы знаете, какой владелец держит запись, удалите дублирующую инструкцию там, где она определена. Это может быть строка route в профиле, push с сервера или хук, которому больше не нужно выполняться.

ip -4 route show match 10.40.0.0/16
ip -4 route get 10.40.0.5
journalctl -u openvpn-client@office -b --no-pager | tail -n 15

Затем переподключитесь и подтвердите три вещи: туннель поднимается, нужное назначение разрешается в желаемый путь, и сбой исчезает, не оставляя на своём месте нового. Чистый журнал с неверно выбранным путём — не исправление.

Если префикс означает локальную LAN с одной стороны и удалённую сеть с другой, проблема в перекрытии адресов, а не в дубликате, и никакое удаление не сделает оба значения истинными одновременно. Этот случай требует другого плана для одной из двух сетей. Решите, какая сторона будет перенумерована, прежде чем трогать любую из них.

Похожие статьи