نیٹ ورکس کو ایک L2 نیٹ ورک میں جوڑنے کے لیے OpenVPN سے WireGuard پر سوئچ کرنا

نیٹ ورکس کو ایک L2 نیٹ ورک میں جوڑنے کے لیے OpenVPN سے WireGuard پر سوئچ کرنا

Хотел бы поделиться опытом объединения сетей в трех географически удаленных квартирах, в каждой из которых в качестве шлюза используются роутеры с OpenWRT, в одну общую сеть. При выборе способа объединения сетей между L3 с маршрутизацией подсетей и L2 с бриджингом, когда все узлы сети будут находиться в одной подсети, было отдано предпочтение второму способу, более сложному в настройке, но дающим бОльшие возможности, так как в создаваемой сети планировалось прозрачное использование технологий Wake-on-Lan и DLNA.

Часть 1: Предыстория

В качестве протокола для реализации этой задачи изначально был выбран OpenVPN, так как, во-первых, он может создавать устройство tap, которое без проблем добавляется в мост, а во-вторых, OpenVPN поддерживает работу по протоколу TCP, что было также немаловажно, ведь ни в одной из квартир не имелось выделенного IP-адреса, а использовать STUN мне не удалось, так как мой провайдер почему-то блокирует входящие подключения по протоколу UDP из своих сетей, в то время как протокол TCP позволял мне пробросить порт VPN-сервера на арендуемый VPS при помощи SSH. Да, такой подход дает большую нагрузку, так как данные шифруются дважды, но вводить VPS в свою частную сеть я не захотел, так как оставался риск получения третьими лицами контроля над ним, следовательно, иметь в домашней сети такое устройство являлось крайне нежелательным и было решено заплатить за безопасность большим оверхедом.

Для проброса порта на роутере, на котором планировалось развернуть сервер, была использована программа sshtunnel. Описывать тонкости ее конфигурации не буду — это делается достаточно легко, просто отмечу, что ее задачей был проброс TCP-порта 1194 с роутера на VPS. Далее был настроен сервер OpenVPN на устройстве tap0, которое заводилось в мост br-lan. Проверив подключение к только что созданному серверу с ноутбука — стало понятно, что идея с пробросом порта себя оправдала и мой ноутбук стал членом сети роутера, хотя физически в ней не находился.

Дело оставалось за малым: нужно было распределить IP-адреса в разных квартирах так, чтобы они не конфликтовали и настроить маршрутизаторы в качестве OpenVPN-клиентов.
Были выбраны такие IP-адреса маршрутизаторов и диапазоны DHCP-серверов:

  • 192.168.10.1 с диапазоном 192.168.10.2 - 192.168.10.80 для сервера
  • 192.168.10.100 с диапазоном 192.168.10.101 - 192.168.10.149 для маршрутизатора в квартире №2
  • 192.168.10.150 с диапазоном 192.168.10.151 - 192.168.10.199 для маршрутизатора в квартире №3

Также было необходимо назначить именно эти адреса для маршрутизаторов-клиентов OpenVPN-сервера, путем добавления в его конфигурацию строчки:

ifconfig-pool-persist /etc/openvpn/ipp.txt 0

и добавлением следующих строк в файл /etc/openvpn/ipp.txt:

flat1_id 192.168.10.100
flat2_id 192.168.10.150

где flat1_id и flat2_id — это имена устройств, указываемые при создании сертификатов для подключения к OpenVPN

Далее на роутерах были настроены OpenVPN-клиенты, устройства tap0 на обоих были занесены в мост br-lan. На этом этапе казалось, что все в порядке, так как все три сети видят друг друга и работают как единое целое. Однако, выяснилась не очень приятная деталь: иногда устройства могли получить IP-адрес не от своего маршрутизатора, со всеми вытекающими последствиями. По какой-то причине, маршрутизатор в какой-то из квартир не успевал ответить вовремя на DHCPDISCOVER и устройство получало не свой адрес. Я понял, что мне нужно отфильтровать такие запросы в tap0 на каждом из маршрутизаторов, но, как выяснилось, iptables не может работать с устройством, если оно является частью моста и мне на помощь должен прийти ebtables. К моему сожалению, в моих прошивках его не оказалось и пришлось пересобирать образы для каждого устройства. Сделав это и добавив такие строки в /etc/rc.local каждого маршрутизатора проблема была решена:

ebtables -A INPUT --in-interface tap0 --protocol ipv4 --ip-protocol udp --ip-destination-port 67:68 -j DROP
ebtables -A INPUT --in-interface tap0 --protocol ipv4 --ip-protocol udp --ip-source-port 67:68 -j DROP
ebtables -A FORWARD --out-interface tap0 --protocol ipv4 --ip-protocol udp --ip-destination-port 67:68 -j DROP
ebtables -A FORWARD --out-interface tap0 --protocol ipv4 --ip-protocol udp --ip-source-port 67:68 -j DROP

Такая конфигурация просуществовала на протяжении трех лет.

Часть 2: Знакомство с WireGuard

В последнее время в Интернете все чаще стали говорить о WireGuard, восхищаясь простотой его конфигурации, высокой скоростью передачи, низким пингом при сопоставимой безопасности. Поиск дополнительной информации о нем давал понять, что ни работа в качестве члена моста, ни работа по протоколу TCP им не поддерживается, что наводило меня на мысли о том, что альтернатив OpenVPN для меня по-прежнему нет. Так я откладывал знакомство с WireGuard.

Несколько дней назад по ресурсам, так или иначе связанным с IT, пролетела новость о том, что WireGuard наконец будет включен в ядро Linux, начиная с версии 5.6. Новостные статьи, как всегда, хвалили WireGuard. Я вновь погрузился в поиски путей замены старого доброго OpenVPN. На этот раз я напоролся на اس مضمون. В ней говорилось о создании Ethernet-туннеля поверх L3 при помощи GRE. Эта статья вселила в меня надежду. Оставалось неясно что делать с протоколом UDP. Поиск приводил меня к статьям об использовании socat в связке с SSH-туннелем, для проброса UDP-порта, однако, в них отмечалось, что такой подход работает только в режиме одного соединения, то есть работа нескольких VPN-клиентов оказалась бы невозможной. Мне пришла идея поднять VPN-сервер на VPS, а для клиентов настроить GRE, но, как оказалось, GRE не поддерживает шифрование, что приведет к тому, что в случае получения доступа к серверу третьими лицами, в их руках оказывается весь трафик между моими сетями, что меня не устраивало в принципе.

Вновь было принято решение в пользу избыточного шифрования, путем использования VPN поверх VPN по следующей схеме:

VPN первого уровня:
VPS ہے سرور с внутренним адресом 192.168.30.1
ایم سی ہے клиентом VPS с внутренним адресом 192.168.30.2
ایم کے 2۔ ہے клиентом VPS с внутренним адресом 192.168.30.3
ایم کے 3۔ ہے клиентом VPS с внутренним адресом 192.168.30.4

VPN второго уровня:
ایم سی ہے سرور с внешним адресом 192.168.30.2 и внутренним 192.168.31.1
ایم کے 2۔ ہے клиентом ایم سی с адресом 192.168.30.2 и имеет внутренний IP 192.168.31.2
ایم کے 3۔ ہے клиентом ایم سی с адресом 192.168.30.2 и имеет внутренний IP 192.168.31.3

* ایم سی — маршрутизатор-сервер в квартире 1, ایم کے 2۔ — маршрутизатор в квартире 2, ایم کے 3۔ — маршрутизатор в квартире 3
* Конфигурации устройств опубликованы в спойлере в конце статьи.

И так, пинги между узлами сети 192.168.31.0/24 ходят, пора перейти к настройке GRE-туннеля. Перед этим, дабы не терять доступ к маршрутизаторам, стоит настроить SSH-туннели для проброса 22 порта на VPS, таким образом, что, например, на 10022-ом порту VPS будет доступен маршрутизатор из квартиры 2, а на 11122-порту VPS будет доступен маршрутизатор из квартиры 3. Настройку проброса лучше всего выполнить все тем-же sshtunnel, так как он восстановит туннель в случае его падения.

Туннель настроен, можно подключаться к SSH через проброшенный порт:

ssh root@МОЙ_VPS -p 10022

Далее следует отключить OpenVPN:

/etc/init.d/openvpn stop

Теперь настроим GRE-туннель на маршрутизаторе из квартиры 2:

ip link add grelan0 type gretap remote 192.168.31.1 local 192.168.31.2
ip link set grelan0 up

И добавим созданный интерфейс в мост:

brctl addif br-lan grelan0

Аналогичную процедуру выполним на маршрутизаторе-сервере:

ip link add grelan0 type gretap remote 192.168.31.2 local 192.168.31.1
ip link set grelan0 up

И, также, добавим созданный интерфейс в мост:

brctl addif br-lan grelan0

начиная с этого момента пинги начинают успешно ходить в новую сеть и я, с удовлетворением отправляюсь пить кофе. Затем, чтобы оценить, как работает сеть на другом конце провода, я пытаюсь подключиться по SSH к одному из компьютеров в квартире 2, но ssh-клиент «зависает», не предлагая ввести пароль. Пробую подключиться к этому компьютеру по telnet на 22 порт и вижу строку, из которой можно понять, что соединение устанавливается, SSH-сервер отвечает, просто по какой-то причине не предлагает мне войти.

$ telnet 192.168.10.110 22
SSH-2.0-OpenSSH_8.1

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

Я вывожу устройство grelan0 из моста и запускаю OpenVPN на маршрутизаторе в квартире 2 и убеждаюсь, что сеть вновь работает как положено и соединения не обрываются. Поиском натыкаюсь на форумы, где люди жалуются на такие же проблемы, где им советуют поднять MTU. Сказано — сделано. Однако, пока MTU не был установлен достаточно большим — 7000 для устройств gretap, наблюдались либо обрывы соединений TCP, либо низкая скорость передачи. Из-за высокого MTU для gretap — MTU для соединений WireGuard первого и второго уровня были выставлены в 8000 и 7500 соответственно.

Провел аналогичную настройку и на маршрутизаторе из квартиры 3, с той лишь разницей, что на маршрутизаторе сервере добавился второй интерфейс gretap с именем grelan1, который также был добавлен в мост br-lan.

Все работает. Теперь можно поместить сборку gretap в автозагрузку. Для этого:

Поместил эти строки в /etc/rc.local на маршрутизаторе в квартире 2:

ip link add grelan0 type gretap remote 192.168.31.1 local 192.168.31.2
ip link set dev grelan0 mtu 7000
ip link set grelan0 up
brctl addif br-lan grelan0

Добавил это в /etc/rc.local на маршрутизаторе в квартире 3:

ip link add grelan0 type gretap remote 192.168.31.1 local 192.168.31.3
ip link set dev grelan0 mtu 7000
ip link set grelan0 up
brctl addif br-lan grelan0

И на маршрутизаторе-сервере:

ip link add grelan0 type gretap remote 192.168.31.2 local 192.168.31.1
ip link set dev grelan0 mtu 7000
ip link set grelan0 up
brctl addif br-lan grelan0

ip link add grelan1 type gretap remote 192.168.31.3 local 192.168.31.1
ip link set dev grelan1 mtu 7000
ip link set grelan1 up
brctl addif br-lan grelan1

После перезагрузки клиентских роутеров я обнаружил, что они по какой-то причине не подключаются к серверу. Подключившись к их SSH (благо, я предварительно настроил sshtunnel для этого) было обнаружено, что WireGuard зачем-то создает маршрут для endpoint, при этом неверный. Так, для 192.168.30.2 в таблице маршрутов был указан маршрут через интерфейс pppoe-wan, то есть через интернет, хотя маршрут до него должен был быть направлен через интерфейс wg0. После удаления этого маршрута соединение восстановилось. Найти где-то инструкций о том, как заставить WireGuard не создавать этих маршрутов мне не удалось. Более того, я даже не понял, особенность это OpenWRT, либо самого WireGuard. Не став долго разбираться с этой проблемой, я просто добавил на оба роутера в скрипт, зацикленный по таймеру, строку удалявшую этот маршрут:

route del 192.168.30.2

خلاصہ

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

При использовании OpenVPN:

[r0ck3r@desktop ~]$ ping -c 20 192.168.10.110
PING 192.168.10.110 (192.168.10.110) 56(84) bytes of data.
64 bytes from 192.168.10.110: icmp_seq=1 ttl=64 time=133 ms
...
64 bytes from 192.168.10.110: icmp_seq=20 ttl=64 time=125 ms

--- 192.168.10.110 ping statistics ---
20 packets transmitted, 20 received, 0% packet loss, time 19006ms
rtt min/avg/max/mdev = 124.722/126.152/136.907/3.065 ms

При использовании WireGuard:

[r0ck3r@desktop ~]$ ping -c 20 192.168.10.110
PING 192.168.10.110 (192.168.10.110) 56(84) bytes of data.
64 bytes from 192.168.10.110: icmp_seq=1 ttl=64 time=124 ms
...
64 bytes from 192.168.10.110: icmp_seq=20 ttl=64 time=124 ms
--- 192.168.10.110 ping statistics ---
20 packets transmitted, 20 received, 0% packet loss, time 19003ms
rtt min/avg/max/mdev = 123.954/124.423/126.708/0.675 ms

На него в большей степени влияет высокий пинг до VPS, который составляет примерно 61.5 мс

Однако, скорость увеличилась значительно. Так, в квартире с маршрутизатором-сервером я имею скорость подключения к Интернету 30 мбит/сек, а в остальных квартирах по 5 мбит/сек. При этом, во время использования OpenVPN мне не удавалось достичь скорости передачи данных между сетями больше 3,8 мбит/сек по показаниями iperf, в то время как WireGuard «прокачал» ее до тех же 5 мбит/сек.

Конфигурация WireGuard на VPS[Interface] Address = 192.168.30.1/24
ListenPort = 51820
PrivateKey = <ЗАКРЫТЫЙ_КЛЮЧ_ДЛЯ_VPS>

[Peer] PublicKey = <ОТКРЫТЫЙ_КЛЮЧ_VPN_1_МС>
AllowedIPs = 192.168.30.2/32

[Peer] PublicKey = <ОТКРЫТЫЙ_КЛЮЧ_VPN_2_МК2>
AllowedIPs = 192.168.30.3/32

[Peer] PublicKey = <ОТКРЫТЫЙ_КЛЮЧ_VPN_2_МК3>
AllowedIPs = 192.168.30.4/32

Конфигурация WireGuard на МС (добавляется в /etc/config/network)

#VPN первого уровня - клиент
config interface 'wg0'
        option proto 'wireguard'
        list addresses '192.168.30.2/24'
        option private_key 'ЗАКРЫТЫЙ_КЛЮЧ_VPN_1_МС'
        option auto '1'
        option mtu '8000'

config wireguard_wg0
        option public_key 'ОТКРЫТЫЙ_КЛЮЧ_VPN_1_VPS'
        option endpoint_port '51820'
        option route_allowed_ips '1'
        option persistent_keepalive '25'
        list allowed_ips '192.168.30.0/24'
        option endpoint_host 'IP_АДРЕС_VPS'

#VPN второго уровня - сервер
config interface 'wg1'
        option proto 'wireguard'
        option private_key 'ЗАКРЫТЫЙ_КЛЮЧ_VPN_2_МС'
        option listen_port '51821'
        list addresses '192.168.31.1/24'
        option auto '1'
        option mtu '7500'

config wireguard_wg1
        option public_key 'ОТКРЫТЫЙ_КЛЮЧ_VPN_2_МК2'
        list allowed_ips '192.168.31.2'

config wireguard_wg1ip link add grelan0 type gretap remote 192.168.31.1 local 192.168.31.3

        option public_key 'ОТКРЫТЫЙ_КЛЮЧ_VPN_2_МК3'
        list allowed_ips '192.168.31.3'

Конфигурация WireGuard на МК2 (добавляется в /etc/config/network)

#VPN первого уровня - клиент
config interface 'wg0'
        option proto 'wireguard'
        list addresses '192.168.30.3/24'
        option private_key 'ЗАКРЫТЫЙ_КЛЮЧ_VPN_1_МК2'
        option auto '1'
        option mtu '8000'

config wireguard_wg0
        option public_key 'ОТКРЫТЫЙ_КЛЮЧ_VPN_1_VPS'
        option endpoint_port '51820'
        option persistent_keepalive '25'
        list allowed_ips '192.168.30.0/24'
        option endpoint_host 'IP_АДРЕС_VPS'

#VPN второго уровня - клиент
config interface 'wg1'
        option proto 'wireguard'
        option private_key 'ЗАКРЫТЫЙ_КЛЮЧ_VPN_2_МК2'
        list addresses '192.168.31.2/24'
        option auto '1'
        option listen_port '51821'
        option mtu '7500'

config wireguard_wg1
        option public_key 'ОТКРЫТЫЙ_КЛЮЧ_VPN_2_МС'
        option endpoint_host '192.168.30.2'
        option endpoint_port '51821'
        option persistent_keepalive '25'
        list allowed_ips '192.168.31.0/24'

Конфигурация WireGuard на МК3 (добавляется в /etc/config/network)

#VPN первого уровня - клиент
config interface 'wg0'
        option proto 'wireguard'
        list addresses '192.168.30.4/24'
        option private_key 'ЗАКРЫТЫЙ_КЛЮЧ_VPN_1_МК3'
        option auto '1'
        option mtu '8000'

config wireguard_wg0
        option public_key 'ОТКРЫТЫЙ_КЛЮЧ_VPN_1_VPS'
        option endpoint_port '51820'
        option persistent_keepalive '25'
        list allowed_ips '192.168.30.0/24'
        option endpoint_host 'IP_АДРЕС_VPS'

#VPN второго уровня - клиент
config interface 'wg1'
        option proto 'wireguard'
        option private_key 'ЗАКРЫТЫЙ_КЛЮЧ_VPN_2_МК3'
        list addresses '192.168.31.3/24'
        option auto '1'
        option listen_port '51821'
        option mtu '7500'

config wireguard_wg1
        option public_key 'ОТКРЫТЫЙ_КЛЮЧ_VPN_2_МС'
        option endpoint_host '192.168.30.2'
        option endpoint_port '51821'
        option persistent_keepalive '25'
        list allowed_ips '192.168.31.0/24'

В описанных конфигурациях для VPN второго уровня я указываю клиентам WireGuard порт 51821. По идее это не нужно, так как клиент установит соединение с любого свободного непривилегированного порта, но я сделал так, чтобы можно было запретить все входящие соединения на интерфейсах wg0 всех маршрутизаторов, кроме входящих UDP-соединений на порт 51821.

Надеюсь, что статья будет кому-то полезна.

PS Также, хочу поделиться своим скриптом, который шлет мне PUSH-уведомление на телефон в приложение WirePusher, когда в моей сети появляется новое устройство. Вот ссылка на скрипт: github.com/r0ck3r/device_discover.

: اپ ڈیٹ Конфигурация OpenVPN-сервера и клиентов

OpenVPN-сервер

client-to-client

ca /etc/openvpn/server/ca.crt
cert /etc/openvpn/server/vpn-server.crt
dh /etc/openvpn/server/dh.pem
key /etc/openvpn/server/vpn-server.key

dev tap
ifconfig-pool-persist /etc/openvpn/ipp.txt 0
keepalive 10 60
proto tcp4
server-bridge 192.168.10.1 255.255.255.0 192.168.10.80 192.168.10.254
status /var/log/openvpn-status.log
verb 3
comp-lzo

OpenVPN-клиент

client
tls-client
dev tap
proto tcp
remote VPS_IP 1194 # Change to your router's External IP
resolv-retry infinite
nobind

ca client/ca.crt
cert client/client.crt
key client/client.key
dh client/dh.pem

comp-lzo
persist-tun
persist-key
verb 3

Для генерации сертификатов использовал easy-rsa

ماخذ: www.habr.com

نیا تبصرہ شامل کریں