Przejście z OpenVPN na WireGuard w celu połączenia sieci w jedną sieć L2

Przejście z OpenVPN na WireGuard w celu połączenia sieci w jedną sieć L2

Chciałbym podzielić się doświadczeniem łączenia sieci w trzech geograficznie oddalonych mieszkaniach, w każdym z których routery z OpenWRT pełniły rolę bramy, w jedną wspólną sieć. Wybierając sposób łączenia sieci między L3 z trasowaniem podsieci a L2 z bridgingiem, gdy wszystkie węzły sieci znajdują się w jednej podsieci, zdecydowano się na drugi sposób, bardziej skomplikowany w konfiguracji, ale oferujący większe możliwości, ponieważ w tworzonej sieci planowano przejrzyste wykorzystanie technologii Wake-on-LAN i DLNA.

Część 1: Tło

Jako protokół do realizacji tego zadania początkowo wybrano OpenVPN, ponieważ, po pierwsze, może tworzyć urządzenie tap, które bez problemu można dodać do mostu, a po drugie, OpenVPN obsługuje pracę w protokole TCP, co również miało duże znaczenie, gdyż w żadnym z mieszkań nie było do dyspozycji dedykowanego adresu IP, a korzystanie ze STUN się nie powiodło, ponieważ mój dostawca z jakiegoś powodu blokuje przychodzące połączenia w protokole UDP z własnych sieci, podczas gdy protokół TCP pozwolił mi przekierować port serwera VPN na wynajmowany VPS za pomocą SSH. Tak, takie podejście generuje dużą obciążalność, ponieważ dane są szyfrowane podwójnie, ale nie chciałem wprowadzać VPS do swojej prywatnej sieci, ponieważ istniałby ryzyko, że osoby trzecie zyskają nad nim kontrolę, co oznacza, że posiadanie takiego urządzenia w sieci domowej było skrajnie niepożądane i zdecydowano, że warto zapłacić za bezpieczeństwo wyższymi kosztami.

Do przekierowania portu na routerze, na którym planowano uruchomić serwer, użyto programu sshtunnel. Nie będę opisywał szczegółów jego konfiguracji — jest to dość proste, tylko zauważę, że jego zadaniem było przekierowanie portu TCP 1194 z routera na VPS. Następnie skonfigurowano serwer OpenVPN na urządzeniu tap0, które było włączone do mostu br-lan. Sprawdzając połączenie z nowo utworzonym serwerem z laptopa, stało się jasne, że pomysł z przekierowaniem portu się sprawdził i mój laptop stał się członkiem sieci routera, mimo że fizycznie w niej nie był.

Pozostało tylko jedno: należy przypisać adresy IP w różnych mieszkaniach tak, aby nie kolidowały i skonfigurować routery jako klientów OpenVPN.
Wybrano takie adresy IP routerów i zakresy serwerów DHCP:

  • 192.168.10.1 z zakresem 192.168.10.2192.168.10.80 dla serwera
  • 192.168.10.100 z zakresem 192.168.10.101192.168.10.149 dla routera w mieszkaniu nr 2
  • 192.168.10.150 z zakresem 192.168.10.151192.168.10.199 dla routera w mieszkaniu nr 3

Należy również przypisać te adresy do klientów routerów serwera OpenVPN, dodając do jego konfiguracji linię:

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

i dodając następujące linie do pliku /etc/openvpn/ipp.txt:

flat1_id 192.168.10.100
flat2_id 192.168.10.150

gdzie flat1_id i flat2_id to nazwy urządzeń podawane przy tworzeniu certyfikatów do łączenia z OpenVPN

Następnie na routerach skonfigurowano klientów OpenVPN, urządzenia tap0 na obu zostały dodane do mostu br-lan. Na tym etapie wydawało się, że wszystko jest w porządku, ponieważ wszystkie trzy sieci widziały się nawzajem i działały jak jedna całość. Jednak okazał się nieprzyjemny szczegół: czasami urządzenia mogły otrzymać adres IP nie z własnego routera, co miało swoje konsekwencje. Z jakiegoś powodu, router w którymś z mieszkań nie zdążał odpowiedzieć na DHCPDISCOVER i urządzenie otrzymywało nie swój adres. Zrozumiałem, że muszę przefiltrować takie zapytania w tap0 na każdym z routerów, ale, jak się okazało, iptables nie może działać z urządzeniem, które jest częścią mostu, więc musiałem sięgnąć po ebtables. Niestety, w moich oprogramowaniach nie było go, więc musiałem przebudować obrazy dla każdego urządzenia. Po zrobieniu tego i dodaniu takich linii do /etc/rc.local każdego routera problem został rozwiązany:

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

Taka konfiguracja przetrwała przez trzy lata.

Część 2: Wprowadzenie do WireGuard

Ostatnio w Internecie coraz częściej mówi się o WireGuard, zachwycając się prostotą jego konfiguracji, dużą szybkością transferu, niskim pingiem przy porównywalnym poziomie bezpieczeństwa. Poszukiwanie dodatkowych informacji na jego temat wskazywało, że ani praca jako członek mostu, ani działanie w protokole TCP nie jest przez niego wspierane, co skłaniało mnie do myślenia, że nie ma dla mnie alternatyw dla OpenVPN. W ten sposób odkładałem spotkanie z WireGuard.

Kilka dni temu w zasobach związanych z IT pojawiła się informacja, że WireGuard w końcu zostanie włączony do jądra Linux, począwszy od wersji 5.6. Artykuły prasowe, jak zawsze, chwaliły WireGuard. Ponownie zanurzyłem się w poszukiwaniach sposobów na zastąpienie starego, dobrego OpenVPN. Tym razem natknąłem się na ten artykuł. Mówiło się w niej o utworzeniu tunelu Ethernet na L3 przy pomocy GRE. Artykuł wzmocnił moją nadzieję. Nie było jasne, co robić z protokołem UDP. Poszukiwania kierowały mnie do artykułów o używaniu socat w połączeniu z tunelowaniem SSH, aby przekazać port UDP, jednak zauważono, że takie podejście działa tylko w trybie jednego połączenia, co oznacza, że działanie wielu klientów VPN byłoby niemożliwe. Wpadłem na pomysł uruchomienia serwera VPN na VPS, a dla klientów skonfigurowania GRE, ale, jak się okazało, GRE nie obsługuje szyfrowania, co spowodowałoby, że w przypadku uzyskania dostępu do serwera przez osoby trzecie, wszystkie dane między moimi sieciami znajdowałyby się w ich rękach, co z zasady mi nie odpowiadało.

Ponownie podjęto decyzję na rzecz nadmiarowego szyfrowania, stosując VPN nad VPN według następującego schematu:

VPN pierwszego poziomu:
VPS jest serwerem z wewnętrznym adresem 192.168.30.1
MC jest klient VPS z wewnętrznym adresem 192.168.30.2
MK2 jest klient VPS z wewnętrznym adresem 192.168.30.3
MK3 jest klient VPS z wewnętrznym adresem 192.168.30.4

VPN drugiego poziomu:
MC jest serwerem z zewnętrznym adresem 192.168.30.2 i wewnętrznym 192.168.31.1
MK2 jest klient MC z adresem 192.168.30.2 i wewnętrznym IP 192.168.31.2
MK3 jest klient MC z adresem 192.168.30.2 i wewnętrznym IP 192.168.31.3

* MC — router-serwer w mieszkaniu 1, MK2 — router w mieszkaniu 2, MK3 — router w mieszkaniu 3
* Konfiguracje urządzeń opublikowane są w spoilerze na końcu artykułu.

I tak, pingi między węzłami sieci 192.168.31.0/24 działają, czas przejść do konfiguracji tunelu GRE. Przed tym, aby nie utracić dostępu do routerów, warto skonfigurować tunel SSH do przekazania portu 22 na VPS, w ten sposób, że na porcie 10022 router z mieszkania 2 będzie dostępny z VPS, a na porcie 11122 router z mieszkania 3. Najlepiej skonfigurować przekazywanie przy użyciu sshtunnel, ponieważ przywróci on tunel w przypadku jego awarii.

Tunel skonfigurowany, można łączyć się z SSH przez przekazany port:

ssh root@MÓJ_VPS -p 10022

Następnie należy wyłączyć OpenVPN:

/etc/init.d/openvpn stop

Teraz skonfigurujmy tunel GRE na routerze z mieszkania 2:

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

I dodamy ut 인터페이스 do mostu:

brctl addif br-lan grelan0

Podobną procedurę wykonamy na routerze-serwerze:

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

I również dodamy ut 인터페이스 do mostu:

brctl addif br-lan grelan0

Od tego momentu ping zaczyna poprawnie działać w nowej sieci i z satysfakcją udaję się napić kawy. Następnie, aby ocenić działanie sieci po drugiej stronie kabla, próbuję połączyć się przez SSH z jednym z komputerów w mieszkaniu 2, ale klient ssh 'zawiesza się', nie proponując wprowadzenia hasła. Próbuję połączyć się z tym komputerem przez telnet na porcie 22 i widzę linijkę, z której można wywnioskować, że połączenie się nawiązuje, serwer SSH odpowiada, lecz z jakiegoś powodu nie oferuje mi zalogowania.

$ telnet 192.168.10.110 22
SSH-2.0-OpenSSH_8.1

Próbuję połączyć się z nim przez VNC i widzę czarny ekran. Uspokajam się, myśląc, że to wina zdalnego komputera, ponieważ z routerem z tej mieszkania mogę się spokojnie połączyć przez wewnętrzny adres. Jednak postanawiam połączyć się z SSH tego komputera przez router i z zaskoczeniem odkrywam, że połączenie się udało, a zdalny komputer działa zupełnie normalnie, ale nie może również połączyć się z moim komputerem.

Wyprowadzam urządzenie grelan0 z mostu i uruchamiam OpenVPN na routerze w mieszkaniu 2, upewniając się, że sieć znów działa prawidłowo i połączenia się nie zrywają. Szukając, natrafiam na fora, gdzie ludzie skarżą się na podobne problemy, w których radzą zwiększyć MTU. Powiedziane — zrobione. Jednak, zanim MTU zostało ustawione na wystarczająco dużą wartość — 7000 dla urządzeń gretap, występowały przerwy w połączeniach TCP lub niska prędkość przesyłu. Z powodu wysokiego MTU dla gretap — MTU dla połączeń WireGuard pierwszego i drugiego poziomu zostały ustawione na 8000 i 7500 odpowiednio.

Przeprowadziłem podobne ustawienia na routerze w mieszkaniu 3, z tą różnicą, że na routerze serwerze dodano drugi interfejs gretap o nazwie grelan1, który także został dodany do mostu br-lan.

Wszystko działa. Teraz można umieścić składnię gretap w autostart. Aby to zrobić:

Umieściłem te linie w /etc/rc.local na routerze w mieszkaniu 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

Dodałem to do /etc/rc.local na routerze w mieszkaniu 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

I na routerze-serwerze:

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

Po ponownym uruchomieniu routerów klienckich zauważyłem, że z jakiegoś powodu nie łączą się z serwerem. Podłączając się do ich SSH (na szczęście wcześniej skonfigurowałem sshtunnel do tego) odkryłem, że WireGuard z jakiegoś powodu tworzy trasę dla endpointu, i to błędną. Dla 192.168.30.2 w tabeli tras podano trasę przez interfejs pppoe-wan, czyli przez internet, podczas gdy trasa do niego powinna być skierowana przez interfejs wg0. Po usunięciu tej trasy połączenie zostało przywrócone. Nie udało mi się znaleźć gdziekolwiek instrukcji, jak wymusić WireGuard, aby nie tworzył tych tras. Co więcej, nie zrozumiałem, czy to cecha OpenWRT, czy samego WireGuard. Nie chcąc trwonić czasu na rozwiązywanie tego problemu, po prostu dodałem na obu routerach do skryptu, który działa co jakiś czas, linię usuwającą tę trasę:

route del 192.168.30.2

Podsumowując

Na razie nie udało mi się całkowicie porzucić OpenVPN, ponieważ czasami muszę podłączyć się do nowej sieci z laptopa lub telefonu, a konfiguracja urządzenia gretap na nich w ogólnym przypadku jest niewykonalna, ale mimo to zyskałem przewagę w szybkości transmisji danych między mieszkaniami, a przykładowo korzystanie z VNC nie sprawia już kłopotów. Ping zmniejszył się nieznacznie, ale stał się bardziej stabilny:

Podczas korzystania z OpenVPN:

[r0ck3r@desktop ~]$ ping -c 20 192.168.10.110
PING 192.168.10.110 (192.168.10.110) 56(84) bajtów danych.
64 bajty z 192.168.10.110: icmp_seq=1 ttl=64 czas=133 ms
...
64 bajty z 192.168.10.110: icmp_seq=20 ttl=64 czas=125 ms

--- statystyki ping 192.168.10.110 ---
20 pakietów wysłanych, 20 odebranych, 0% utraty pakietów, czas 19006ms
rtt min/avg/max/mdev = 124.722/126.152/136.907/3.065 ms

Podczas korzystania z WireGuard:

[r0ck3r@desktop ~]$ ping -c 20 192.168.10.110
PING 192.168.10.110 (192.168.10.110) 56(84) bajtów danych.
64 bajty z 192.168.10.110: icmp_seq=1 ttl=64 czas=124 ms
...
64 bajty z 192.168.10.110: icmp_seq=20 ttl=64 czas=124 ms
--- statystyki ping 192.168.10.110 ---
20 pakietów wysłanych, 20 odebranych, 0% utraty pakietów, czas 19003ms
rtt min/avg/max/mdev = 123.954/124.423/126.708/0.675 ms

Na to w większym stopniu wpływa wysoki ping do VPS, który wynosi około 61.5 ms

Jednak prędkość znacznie wzrosła. W mieszkaniu z routerem-serwerem mam prędkość połączenia z Internetem 30 Mbit/s, a w pozostałych mieszkaniach 5 Mbit/s. Ponadto, podczas korzystania z OpenVPN nie udało mi się osiągnąć prędkości przesyłu danych między sieciami większej niż 3,8 Mbit/s według pomiarów iperf, podczas gdy WireGuard "wyciągnął" ją do tych samych 5 Mbit/s.

Konfiguracja WireGuard na VPS[Interface]
Adres = 192.168.30.1/24
PortSłuchania = 51820
KluczPrywatny =

[Peer]
PublicKey =
AllowedIPs = 192.168.30.2/32

[Peer]
PublicKey =
AllowedIPs = 192.168.30.3/32

[Peer]
PublicKey =
AllowedIPs = 192.168.30.4/32

Konfiguracja WireGuard na MS (dodawane do /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'

Konfiguracja WireGuard na MK2 (dodawane do /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'

Konfiguracja WireGuard na MK3 (dodawane do /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'

W opisanych konfiguracjach dla VPN drugiego poziomu podaję klientom WireGuard port 51821. Teoretycznie to nie jest konieczne, ponieważ klient nawiąże połączenie z dowolnego wolnego portu, ale zrobiłem to, aby można było zablokować wszystkie przychodzące połączenia na interfejsach wg0 wszystkich routerów, z wyjątkiem przychodzących połączeń UDP na port 51821.

Mam nadzieję, że artykuł będzie dla kogoś przydatny.

P.S. Chcę także podzielić się moim skryptem, który wysyła mi powiadomienie PUSH na telefon do aplikacji WirePusher, gdy w mojej sieci pojawia się nowe urządzenie. Oto link do skryptu: github.com/r0ck3r/device_discover.

AKTUALIZACJA: Konfiguracja serwera i klientów OpenVPN

Serwer 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

Klient OpenVPN

client
tls-client
dev tap
proto tcp
remote VPS_IP 1194 # Zmień na zewnętrzny adres IP swojego routera
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

Do generacji certyfikatów użyłem easy-rsa

Źródło: habr.com

Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS 🔥 Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS | ProHoster