Преминаване от 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.2192.168.10.80 за сървера
  • 192.168.10.100 с диапазон от 192.168.10.101192.168.10.149 за маршрутизатора в апартамент №2
  • 192.168.10.150 с диапазон от 192.168.10.151192.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
* Конфигурациите на устройствата са публикувани в спойлер в края на статията.

И така, ping-овете между възлите на мрежата 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 мбит/сек, а в другите апартаменти - по 5 мбит/сек. При това, по време на използването на OpenVPN не успях да постигна скорост на предаване на данни между мрежите над 3.8 мбит/сек според показанията на iperf, докато WireGuard я увеличи до същите 5 мбит/сек.

Конфигурация на WireGuard на VPS[Interface]
Адрес = 192.168.30.1/24
Слушащ порт = 51820
Личен ключ =

[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