Настройка динамической маршрутизации (в частности 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 name auth cipher local lport dev-type tun dev ifconfig client-connect client_connect.sh push "route-gateway " push "topology net30" push "persist-tun" push "persist-key" . Diffie-Hellman data . Certificate Authority certificate data . Server certificate data . Server Private Key data
Файл client_connect.sh (сторона сервера)
#!/bin/sh echo 'ifconfig-push TUNNEL_CLIENT_SIDE_IP TUNNEL_SERVER_SIDE_IP' >> $ echo 'push "iroute 0.0.0.0 0.0.0.0"' >> $ echo 'iroute 0.0.0.0 0.0.0.0' >> $ exit 0
Файл client_dyn_rt.conf (сторона клиента)
daemon compress tls-client auth cipher client dev-type tun dev script-security 3 remote-cert-tls server verify-x509-name name remote tcp . Certificate Authority certificate data . Client certificate data . Client Private Key data
Настройки пакетов и протоколов маршрутизации не привожу как из-за многообразия пакетов, так и из-за многообразия самих настроек (собственно в качестве источника примеров настройки можно использовать вторую из статей, ссылки на которые приведены в начале статьи). Хочу лишь заметить, что вышеприведённая настройка позволяет использовать в частности BGP (который лично мне нравится как своей «управляемостью», так и способностью передавать маршруты различных протоколов в рамках одной сессии). В случае BGP в качестве адреса соседа (neighbor) на стороне «сервера» следует использовать адрес , а на стороне «клиента» соответственно адрес или же «внутренние» адреса соответствующих сторон, но тогда надо добавлять соответствующие маршруты в конфигурацию сервера и/или клиента.
Плюсы и минусы вышеприведённого решения
- На один сервер должен приходится строго один клиент, поэтому для нескольких клиентов придётся держать активными несколько процессов OpenVPN. Как следствие — некоторый перерасход памяти и всякое такое.
- Нельзя использовать режим общего ключа (preshared key) в OpenVPN, потому что в этом режиме запрещена динамическая передача параметров от сервера клиенту (push/pull). Из-за этого требуется более сложная конфигурация, включающая генерацию набора ключей и сертификатов, а также скрипт генерации куска конфигурации клиента на стороне сервера (который правда можно заменить каталогом статических файлов, заменив опцию client-connect /path/to/script на опцию client-connect-dir /path/to/config/dir , что повышает уровень безопасности серверной стороны.
- В отличие от таких протоколов как GRE/IPIP туннели OpenVPN могут иметь MTU равное 1500 байт (потому что процесс OpenVPN скрывает «под капотом» всю фрагментацию/дефрагментацию, отдавая в туннельный интерфейс пакеты полной длины). Это упрощает настройку всяких вторичных туннелей поверх туннеля OpenVPN.
- Туннель OpenVPN одновременно поддерживает передачу как протокола IPv4, так и IPv6, что позволяет сократить количество туннелей между парами узлов, затраты на их настройку и администрирование, а также передавать маршруты IPv6 в рамках той же сессии BGP, что и маршруты IPv4.
- Все плюсы протокола OpenVPN, такие как простота настройки промежуточного сетевого оборудования (или вообще полное отсутствие необходимости в таковой), возможность маскировки трафика под HTTPS, наличие реализации под большинство платформ et cetera, et cetera.
Надеюсь кому-то вышеприведённое руководство окажется полезным.
How to set routes for my vpn connection
In my previous question I was asking about setting up vpnc connection. I’ve installed network-manager-vpnc so now I can configure all this stuff right from network manager gui. I have got this pretty picture from related topic: So the question is how to figure out what Address, Netmask and Gateway should I use to pass ONLY this trafic through vpn. As a basis I have got an ip and a port of the external service which I want to use through vpnc. So inernet and other traffic should go as always through ethernet or wifi.
- External ip: 10.20.30.40
- Port: 1433 (this is sql server actually)
5 Answers 5
- Now click on the “IPv4 Settings” tab and click “Routes…”
- Click “Add” and in the “Address” box, enter the IP address of the machine you which to access. For our XYZ server, this is “203.0.113.3”. In the “Netmask” box enter “255.255.255.255” (to indicate we only want this single IP address). Leave the Gateway and Metric boxes empty.
- Select “Use this connection only for resources on its network”
- Click “Ok” on the “Editing IPv4 routes” box
- Click “Save…”
I’m using the VPN to connect to my internal network, at the office. I want to keep my internet access using my provider, but I also want to access several machines within the office.
- Use this connection only for resources on its network
- Add a new route with:
- IP address : 192.168.100.0 (the address of my office network; not just one specific machine)
- Netmask : 255.255.255.0
- Gateway : 192.168.100.143 (I get the IP from the route table after connection the VPN for the first time).
- Metric : 1
This command line do the same as the above configuration:
sudo route add -net 192.168.100.0/24 gw 192.168.100.143 metric 1
Afterwards, I can connect to any office host on that network, using ssh, remmina, etc.