Настройка динамической маршрутизации (в частности BGP) поверх туннеля OpenVPN на Linux (и вероятно *BSD)

Зачем и о чём эта статья?


Если погуглить на тему «openvpn bgp», то можно найти несколько интересных и полезных с практической точки зрения статей (например раз или два). Но начиная решать задачку вынесенную в заголовок, я по многим причинам даже не удосужился погуглить. Идея пришла как-то сама собой в процессе долгой работы с OpenVPN вообще (в рамках вполне типовых задач, с фиксированным набором сетей с обеих сторон), работы с реализацией OpenVPN на системе RouterOS от MikroTik и стыковки между собой систем на Linux и RouterOS. Собственно в процессе осознания причин написания собственной реализации OpenVPN в RouterOS и пришло «озарение» как можно такую задачу решить в рамках вполне себе штатной редакции OpenVPN. Далее была короткая экспериментальная проверка, показавшая полную работоспособность идеи и запуск этого решения в «промышленную» эксплуатацию.


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



Суть проблемы («кто виноват?»)


Чем же так существенно различаются штатная версия OpenVPN и та, что реализована в RouterOS? Отличий вероятно несколько, но в данной статье мы рассмотрим только одно: штатный OpenVPN в системах кроме RouterOS (и возможно некоторых других) является комбайном, который содержит в себе и транспортную часть (то есть собственно передачу пакетов, она же forwarding, он же data plane) и маршрутизирующую (то есть обмен информацией о маршрутах, он же routing, он же control plane), а в RouterOS сервис OpenVPN отвечает только за транспортную часть, а маршрутизацией занимается другой процесс системы, что позволяет с одной стороны не дублировать функциональность маршрутизирующей подсистемы (и тем более не держать несколько одинаковых таблиц маршрутов в разных сервисах и постоянно синхронизировать их между собой), а с другой стороны, позволяет поверх такого транспорта прозрачно осуществлять передачу таблиц маршрутов и изменять таблицы маршрутов с обеих сторон на лету.


Кроме того, штатная реализация OpenVPN имеет ещё один недостаток: передача маршрутов происходит только в одну сторону (от сервера к клиенту) и только в момент установления сессии (то есть поднятия туннеля). Никакого штатного способа добавить маршрут во внутреннюю таблицу маршрутов OpenVPN на ходу в процессе работы туннеля нет, так же как и передать маршруты с одной стороны на другую. Более того, невозможно даже получить саму таблицу маршрутов.


Решение проблемы («Что делать»)


Анализируя свои скрипты, автоматизирующие назначение маршрутов разным клиентам, я обратил внимание, что у OpenVPN есть две различных опции, задающих маршруты:


  • iroute — задаёт маршруты внутри таблицы маршрутизации процесса OpenVPN.
  • route — задаёт маршруты, которые процесс OpenVPN передаёт в системную таблицу маршрутов (то есть добавляет в таблицу маршруты через свой туннельный интерфейс при подключении и удаляет их же при отключении).

Возник очевидный вопрос: а что будет, если с помощью iroute добавить маршрут 0.0.0.0/0 с обеих сторон, а после этого нужные маршруты (в том числе динамически возникающие или пропадающие) добавлять или удалять на самом туннельном интерфейсе средствами например сервиса маршрутизации (routed, zebra/quagga, bird и т. п.)?


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


Схема работает в режим TLS-over-TCP, то есть для настройки предварительно необходимо сгенерировать ключи и сертификаты SSL.


Ниже привожу примерную конфигурацию OpenVPN для серверной и клиентской стороны.


Конфигурация серверной стороны (по одной для каждого клиента).


Файл server_dyn_rt.conf (сторона сервера)


daemon
compress
ping-timer-rem
persist-tun
persist-key
tls-server
proto tcp-server
topology net30
mode server
script-security 3
keepalive 15 45
tun-mtu 1500
remote-cert-tls client
verify-x509-name <CLIENT_DISTINGUISHED_NAME>	name
auth <TLS_AUTH_ALGORITHM>
cipher <CIPHER_ALGORITHM>
local <SERVER_PUBLIC_IP>
lport <SERVER_PUBLIC_PORT>
dev-type tun
dev <TUNNEL_INTERFACE_NAME>
ifconfig <TUNNEL_SERVER_SIDE_IP> <TUNNEL_CLIENT_SIDE_IP>
client-connect client_connect.sh
push "route-gateway <TUNNEL_SERVER_SIDE_IP>"
push "topology net30"
push&nbsp"persist-tun"
push&nbsp"persist-key"
<dh>
... Diffie-Hellman data
<</dh>
<ca>
... Certificate Authority certificate data
</ca>
<cert>
... Server certificate data
</cert>
<key>
... Server Private Key data
</key>

Файл client_connect.sh (сторона сервера)


#!/bin/sh
echo 'ifconfig-push TUNNEL_CLIENT_SIDE_IP TUNNEL_SERVER_SIDE_IP' >> ${1}
echo 'push "iroute 0.0.0.0 0.0.0.0"' >> ${1}
echo 'iroute 0.0.0.0 0.0.0.0' >> ${1}
exit 0

Файл client_dyn_rt.conf (сторона клиента)


daemon
compress
tls-client
auth <TLS_AUTH_ALGORITHM>
cipher <CIPHER_ALGORITHM>
client
dev-type tun
dev <TUNNEL_INTERFACE_NAME>
script-security 3
remote-cert-tls server
verify-x509-name <SERVER_DISTINGUISHED_NAME> name
remote <SERVER_PUBLIC_IP> <SERVER_PUBLIC_PORT> tcp
<ca>
... Certificate Authority certificate data
</ca>
<cert>
... Client certificate data
</cert>
<key>
... Client Private Key data
</key>

Настройки пакетов и протоколов маршрутизации не привожу как из-за многообразия пакетов, так и из-за многообразия самих настроек (собственно в качестве источника примеров настройки можно использовать вторую из статей, ссылки на которые приведены в начале статьи). Хочу лишь заметить, что вышеприведённая настройка позволяет использовать в частности BGP (который лично мне нравится как своей «управляемостью», так и способностью передавать маршруты различных протоколов в рамках одной сессии). В случае BGP в качестве адреса соседа (neighbor) на стороне «сервера» следует использовать адрес <TUNNEL_CLIENT_SIDE_IP>, а на стороне «клиента» соответственно адрес <TUNNEL_SERVER_SIDE_IP> или же «внутренние» адреса соответствующих сторон, но тогда надо добавлять соответствующие маршруты в конфигурацию сервера и/или клиента.



Плюсы и минусы вышеприведённого решения


Минусы:

  1. На один сервер должен приходится строго один клиент, поэтому для нескольких клиентов придётся держать активными несколько процессов OpenVPN. Как следствие — некоторый перерасход памяти и всякое такое.
  2. Нельзя использовать режим общего ключа (preshared key) в OpenVPN, потому что в этом режиме запрещена динамическая передача параметров от сервера клиенту (push/pull). Из-за этого требуется более сложная конфигурация, включающая генерацию набора ключей и сертификатов, а также скрипт генерации куска конфигурации клиента на стороне сервера (который правда можно заменить каталогом статических файлов, заменив опцию client-connect /path/to/script на опцию client-connect-dir /path/to/config/dir, что повышает уровень безопасности серверной стороны.

Плюсы:

  1. В отличие от таких протоколов как GRE/IPIP туннели OpenVPN могут иметь MTU равное 1500 байт (потому что процесс OpenVPN скрывает «под капотом» всю фрагментацию/дефрагментацию, отдавая в туннельный интерфейс пакеты полной длины). Это упрощает настройку всяких вторичных туннелей поверх туннеля OpenVPN.
  2. Туннель OpenVPN одновременно поддерживает передачу как протокола IPv4, так и IPv6, что позволяет сократить количество туннелей между парами узлов, затраты на их настройку и администрирование, а также передавать маршруты IPv6 в рамках той же сессии BGP, что и маршруты IPv4.
  3. Все плюсы протокола OpenVPN, такие как простота настройки промежуточного сетевого оборудования (или вообще полное отсутствие необходимости в таковой), возможность маскировки трафика под HTTPS, наличие реализации под большинство платформ et cetera, et cetera.

Надеюсь кому-то вышеприведённое руководство окажется полезным.

Комментарии 14

    0
    В отличие от таких протоколов как GRE/IPIP туннели OpenVPN могут иметь MTU равное 1500 байт (потому что процесс OpenVPN скрывает «под капотом» всю фрагментацию/дефрагментацию, отдавая в туннельный интерфейс пакеты полной длины). Это упрощает настройку всяких вторичных туннелей поверх туннеля OpenVPN.

    А плюс ли это? Оверхэд есть у любого туннеля, соответственно если у интерфейса MTU равен MTU внутри туннеля — придется дробить пакеты.
      0

      Ээээ. В отношении OpenVPN говорить об оверхэде смысла нет. Он не для сокращения оверхэда. В статье, где сравнивали пропускную способность OpenVPN и WireGuard однозначно показали что у OpenVPN ПС раза в три-четыре ниже, чем у WG. И всё из-за оверхеда, фрагментации/дефрагментации и т. п.


      Как-то так.

        0
        Тут речь о другом.
        Максимально эффективная утилизация канала будет если внутри туннеля используется MTU с учетом что туннелю как то эти пакеты еще заворачивать на физическом уровне.
        Если внутри туннеля 1500 и у физического интерфейса 1500 — то в один пакет это сообщение упихать никак не получается (опустим сжатие — пакет вполне может быть несжимаем)
          0
          Максимально эффективная утилизация канала будет если внутри туннеля используется MTU с учетом что туннелю как то эти пакеты еще заворачивать на физическом уровне.

          Я в данном случае даже и не спорю. Ещё раз повторю, OpenVPN в данном случае не про эффективность, он про «проходимость» (она же «проницаемость»). То есть если делать решение именно «эффективное» (не только с точки зрения утилизации), то это не к OpenVPN уже как минимум из-за того, что это комбайн, который содержит в себе маршрутизатор. Который а) дублирует функциональность ОС, которая делает это явно эффективнее (ибо делает это на уровне ядра, без переключения контекстов на userspace) и б) делает это явно менее функционально, потому что ядро позволяет использовать всякие другие «плюшки» вроде policy-based routing и иже с ним, чего OpenVPN не умеет от слова «совсем».

          И да, вышеприведённая статья на самом-то деле «выросла» из удачной попытки скрестить Linux и RouterOS именно по OpenVPN и при этом обеспечить с обеих сторон динамическую маршрутизацию. Но изначальный первичный эксперимент делался таки именно между двумя чистыми Linux, а уже потом был «обратно» пристыкован RouterOS и схема подтверждена на такой связке. Кстати в случае если клиентом является RouterOS скрипт для клиента на сервере на одну команду меньше, потому что не нужна команда
          echo 'push "iroute 0.0.0.0 0.0.0.0"'
        0

        Если вы за динамику, почему тогда bgp, а не ospf, например? Не очень понятно кто ваши "клиенты" — сеть филиалов, или вообще разные компании? Ну и картинок не хватает))

          0
          С одной стороны так сложилось, что моё знакомство с динамической маршрутизацией началось «по-серьёзному» с BGP (были «поигрулечки» с RIP, но это было давно и неправда).
          С другой стороны про OSPF бытует мнение (не моё, где-то на форуме бегло проскочило), что он не очень оптимально работает в случае большого числа маршрутов /32. Что в моём случае как раз имеет место быть (обходы запретов одного «замечательного» ведомства как пример).
          С третьей стороны ИМХО (Имею Мнение, Хрен Оспоришь) BGP кажется мне более управляемым протоколом, в первую очередь потому, что базируется на unicast, допускает multihop и всё такое.
          Ну и наконец, BGP замечательно передаёт данные всяких там MPLS, VRF и иже с ними.

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

          Ну вот так как-то.
          0
          Добрый )
          У меня полтора десятка филиалов на pfsense\opnsense связаны с Центром по OpenVPN + OSPF. pfsense\opnsense живет на Proxmox VE (PVE). «Ни единого разрыва» (с). Скорость переключения с основного канала на резервный и обратно ~5-7 сек. На pfsense пользую пакет FRR (умеет и OSPF и BGP).

          Зы. Кому нужна голая БСД — BSD Router Project (BSDRP) в помощь. Возможности bsdrp.net/features, пример настройки bsdrp.net/documentation/examples/simple_bgp-rip-ospf_lab
            0
            У меня полтора десятка филиалов на pfsense\opnsense связаны с Центром по OpenVPN + OSPF.

            А из/в филиалы какого размера сети ходят? Уже не /24 ли случаем?

            На pfsense пользую пакет FRR

            Хотел попробовать, но руки пока не дошли. Ну и кроме того среди «промышленных» open source маршрутизаторов FRR как-то пока не особо засветился. В отличие от большой тройки (Quagga, BIRD, Exa-BGP). Соответственно изначально у меня как раз Quagga была, сейчас вот на BIRD мигрировал и пока FRR в планах нет. Но кто знает, может и появится.

            Что же касается использования *BSD, то увы, без виртуализации у них очень уж маленький список поддерживаемого железа, а виртуализация так и так делается НЕ на платформах *BSD. В итоге с большой вероятностью так и так придётся иметь дело с Linux (ваш Proxmox тому пример, ибо это DebIan). Не вижу смысла городить огород/зоопарк, усложняя тем самым стоимость обслуживания и технической поддержки. Сам лично с FreeBSD я имел дело начиная с версии 1.1.5.1 годах ещё в 90-х, а полностью отказался от неё во всех проектах лет 5-7 назад и именно из-за катастрофически маленькой поддержки железа, прежде всего по «религиозным» (бишь лицензионным) соображениям: ну не могли в BSD портировать просто так скажем драйверы Wi-Fi из Linux, потому что нельзя код под лицензией GPL в BSD просто так взять и утащить. В итоге, когда Linux просто из коробки работал почти с любыми беспроводными адаптерами, на той же FreeBSD их было по пальцам одной руки посчитать. Тоже самое касалось поддержки многих видеоадаптеров и так далее по списку. А обновление была отдельная очень больная тема. До сих пор помню как переход с версии на версию (даже кажется минорную) тех же KDE потребовал пересборки половины портов в системе (да, я портами пользовался и продолжаю считать именно этот способ самым кашерным). А так да, системы хорошие.
              0
              Proxmox — это Debian + мод. ядро от Убунты.

              А из/в филиалы какого размера сети ходят? Уже не /24 ли случаем?

              Есть и /24 и /28
                0
                Proxmox — это Debian + мод. ядро от Убунты

                Учитывая, что Ubuntu есть форк DebIan, разница не очень большая. Насколько я помню Proxmox всё-таки от чистого DebIan форкнулся, но могу и ошибаться.

                Есть и /24 и /28

                Вот тут один из главных моментов с OSPF и кроется. Насколько я читал он не очень хорош при большом числе сетей /32, а вот это как раз мой случай.

                По большому же счёту вопрос не в том, OSPF, BGP или RIP. Вопрос в том, что в штатный (то есть не модифицированный специально) OpenVPN «на лету» маршруты ни добавить, ни убавить нельзя без переподключения. Именно о том как это собственно обойти как раз статья и есть.
                  0
                  Стоп-стоп.
                  У меня из Филиала к Центру постоянно подняты несколько впн-линков. Причем в настройках впн-сервера в Центре маршруты автоматом не раздаются и в Филиале «руками» маршруты не настраиваются. OSPF сам «решает», кто из линков «главнее» и пускает трафик через означенный впн-линк. При этом опенвпн — оригинальный, никем не патченный. И «ронять-поднимать» впн-туннели для этого не требуется.

                  Насколько я читал он не очень хорош при большом числе сетей /32, а вот это как раз мой случай.

                  Разверните тестовый стенд (да хотя бы и на VirtBOX-е) и проверьте свою «теорию».
                    0
                    Я вот как раз в начале приводил ссылочку на ровно такое решение (ссылка с названием «раз»). Оно именно про это.

                    Что касается неудобства OSPF для множества /32, то теория не моя, я выше уже писал что прочитал про это на форуме каком-то, сам лично не проверял. Моё же личное отношение к ЛЮБЫМ протоколам маршрутизации, которые базируются на мультикасте (RIP, OSPF) отрицательное. Ну просто из опыта разнообразной возни именно с самим мультикастом. Выше я писал про то, что BGP кажется мне более управляемым. Так вот как раз из-за того, что он НЕ-мультикастовый и можно легко понять почему скажем нет взаимодействия между двумя маршрутизаторами (смотрим в таблицу маршрутов и видим что скажем нет маршрута до пира) и всякое такое. А вот с мультикастом всё это выглядит посложнее уже (особенно если в промежутке какое-нибудь импортозамещённое оборудование стоит, не ко сну будь помянуто).

                    Ну вот так как-то.
                      0
                      Моё же личное отношение к ЛЮБЫМ протоколам маршрутизации, которые базируются на мультикасте (RIP, OSPF) отрицательное.


                      RIP, EIGRP, OSPF — все же broadcast.

                      Multicast (мультикаст) – процесс отправки пакета от одного хоста к некоторой ограниченной группе хостов.

                      Broadcast (бродкаст) – процесс отправки пакета от одного хоста ко всем хостам в сети.


                      OSPF умеет Non-Broadcast (NBMA)
                      Cкрин с настройками OSPF на pfsense (используется пакет FRR):

                      image

                      прочитал про это на форуме каком-то, сам лично не проверял
                      Не верьте на слово. Развертывайте и пробуйте.
                        0
                        Развертывайте и пробуйте.

                        Да как бы незачем мне. Меня (как я уже выше писал) более чем устраивает BGP. В том числе возможностью работы с несколькими протоколами (IPv4 и IPv6) в рамках ОДНОГО соединения. И не только IPv4/IPv6 но и L2VPN. И опять-таки в рамках ОДНОГО соединения.

                        Свои причины НЕ пользоваться всеми ветками BSD в промышленных решениях я также изложил выше. Они у меня примерно такие же как и всех крупных интернет-деятелей (вроде Яндекса), которые были вынуждены (не хотели, а именно были вынуждены по многим причинам) отказаться от BSD в пользу разных Linux. Да, возможно с тех пор и причины исчезли, и BSD ещё круче стали (надеюсь), но нам не шашечки, нам ехать. А вот ехать на них выходило дороже, чем на Linux-ах (и я тоже писал почему).

                        Предлагаю с советами кому, что и как делать закончить. На вкус и цвет все фломастеры разные. Кому-то красные нравятся, а кому-то синие.
                        Не хотите использовать BGP — не используйте, я не навязываю. Я вот лично НЕ ХОЧУ использовать OSPF. Ну не нравится он МНЕ и всё тут. То же самое и к BSD в промышленной эксплуатации относится. Да, система хорошая и всё такое, но по эксплуатационным затратам дороже выходит. И не надо мне рассказывать про то что «поставил и забыл». Дырки раз в 10 лет даже в OpenBSD находили. Так что обновлять раньше или позже таки приходится. И вот тут у «сообщественных» BSD были большие проблемы ещё в те времена когда RPM (который в тот момент «вилочничать» вздумал) и DPkg, и все прочие менеджеры пакетов успешно такие проблемы порешали. А в BSD в это время самый нормальный и рабочий способ обновления был «из портов». Особенно если ещё и система кастомизированная, включая ядро. Только-только в качестве решения пыталась пробиться PC-BSD. Да, допускаю что с тех пор много воды утекло и всё могло измениться, но как говорится «ложечки-то мы конечно нашли, но осадочек-то остался».
                        Да, и к FRR это тоже относится кстати. Который форк Квагги, которая форк просто Зебры, которая синтаксический, но НЕ пофункциональный (в частности advertize map нема) «клон» Cisco IOS. Мне хватило как раз Квагги, вот недавно перебрался на BIRD. Ну да, птиц штука интересная, настройка в некоторых моментах не такая очевидная как в Z/Q/FRR, но более функциональная и с точки зрения программиста явно более удобная и гибкая. И кстати да, управление со стороны скриптов очень даже удобная штука, хотя пока мне и не нужная.

          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

          Самое читаемое