Преход от OpenVPN към WireGuard за обединяване на мрежи в една L2 мрежа

Преход от OpenVPN към WireGuard за обединяване на мрежи в една L2 мрежа

Бих искал да споделя опит в обединяването на мрежи в три географски отдалечени апартамента, във всеки от които руутерите с 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.

Преди няколко дни източниците, свързани с ИТ, разпространиха новина, че 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 ms

Обаче, скоростта значително се увеличи. Така, в апартамент с рутер-сървър имам скорост на интернет свързване от 30 Mbps, а в останалите апартаменти по 5 Mbps. При това, по време на използването на OpenVPN, не успях да постигна скорост на предаване на данни между мрежите над 3.8 Mbps, според показанията на iperf, докато WireGuard "достигна" същите 5 Mbps.

Конфигурация на WireGuard на VPS[Interface]
Адрес = 192.168.30.1/24
ListenPort = 51820
PrivateKey =

[Peer]
PublicKey =
AllowedIPs = 192.168.30.2/32

[Peer]
PublicKey =
AllowedIPs = 192.168.30.3/32

[Peer]
PublicKey =
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.

Надявам се, че статията ще бъде полезна за някого.

P.S. Също така искам да споделя своя скрипт, който ми изпраща PUSH известие на телефона в приложението WirePusher, когато в мрежата ми се появи ново устройство. Ето линк към скрипта: github.com/r0ck3r/device_discover.

UPDATE: Конфигурация на 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 # Променете на външния 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

Източник: habr.com

Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри 🔥 Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри | ProHoster