OpenVPN - Site-to-site bridge dvou sítí na linkové (L2) vrstvě

Tak jsem to nakonec dal dohromady. Pro případ, že se sem někdo dopátrá při řešení podobného scénáře (nebo pro sebe v budoucnu), popíšu, jak jsem to zprovoznil.

Napřed příprava. Původní síť používala IP rozsah 192.168.1.0/24, ten jsem chtěl zachovat. Nové síti na druhé lokaci jsem chtěl dát 192.168.2.0/24. Tyto rozsahy ale bohužel nepatří do jedné podsítě /23, takže jsem musel použít až /22. Což mi nechává rozsahy 192.168.0.0/24 a 192.168.3.0/24 vyhrazené pro budoucí použití.

Na obou sítích jsem tedy nastavil podsíť 192.168.0.0/22 (maska 255.255.252.0). První Turris má adresu 192.168.1.1 a jeho DHCP přiděluje rozsah 192.168.1.100-250, druhý Turris má adresu 192.168.2.1 a jeho DHCP přiděluje rozsah 192.168.2.100-250. Toto zajišťuje, že obě sítě dokáží fungovat jak samostatně, tak propojeně.

Na prvním Turrisu jsem již měl přes reForis zprovozněný OpenVPN server (pro starý tun tunel), jehož certifikáty bude využívat i druhá instance OpenVPN (pro nový tap tunel). Taky to znamená, že si pro druhý Turris můžu nechat přes reForis vygenerovat .ovpn konfigurák, což jsem využil.

První Turris bude sloužit jako server. Do /etc/config/openvpn jsem přidal novou sekci inspirovanou existující sekcí server_turris:

config openvpn 'server_turris_tap'
    option enabled '1'
    option port '1195'
    option proto 'udp'
    option dev 'tap_turris'
    option ca '/etc/ssl/ca/openvpn/ca.crt'
    option crl_verify '/etc/ssl/ca/openvpn/ca.crl'
    option cert '/etc/ssl/ca/openvpn/01.crt'
    option key '/etc/ssl/ca/openvpn/01.key'
    option dh '/etc/ssl/ca/openvpn/dhparam.pem'
    option duplicate_cn '0'
    option keepalive '10 120'
    option persist_key '1'
    option persist_tun '1'
    option status '/tmp/openvpn-status-tap.log'
    option verb '3'
    option mute '20'
    option client_to_client '1'
    option server_bridge 'nogw'

Důležité změny jsou: rozhraní tap_turris, jiný port, jiný název pro status soubor a volba server_bridge 'nogw'. Ta zajišťuje, že OpenVPN nebude nijak zajišťovat přiřazování IP adres a vše přenechá síti samotné. Individuální klienti tak získají IP adresu pomocí DHCP na straně serveru. Port 1195 bylo třeba povolit v LuCI úpravou existujícího firewallového pravidla pro původní OpenVPN instanci.

Druhý Turris bude mít roli klienta. Do /etc/config/openvpn jsem přidal:

config openvpn 'client_turris_tap'
    option config '/etc/openvpn/site-to-site.ovpn'
    option enabled '1'

Do /etc/openvpn/site-to-site.ovpn jsem nahrál konfigurák, který vznikl úpravou konfiguráku stáhnutého z reForisu na prvním Turrisu:

client
dev tap_turris
proto udp
remote x.x.x.x 1195
remote-cert-tls server
nobind
persist-key
persist-tun
verb 3
mute 20
mute-replay-warnings

<ca>...</ca>
<cert>...</cert>
<key>...</key>

Po startu OpenVPN na obou Turrisech vznikne nové fyzické síťové rozhraní tap_turris, které je nutné přidat do existujícího bridge pro LAN (br-lan) - to jsem naklikal v LuCI.

Takto už začne propojení fungovat. Po nějaké době jsem si ale všiml, že některá zařízení dostala IP adresu a bránu ze špatné strany sítě, což znamená, že se jejich provoz ven zbytečně směruje skrz VPN. Čili je opravdu nutné nějak zablokovat DHCP provoz skrz VPN, ať si každou stranu sítě striktně obsluhuje její vlastní DHCP server.

Blokace DHCP skrz VPN se ale ukázala jako nejtěžší problém k vyřešení. První pokusy se specifikací rozhraní přes firewall v LuCI nikam nevedly, ani iptables s instalací podpory pro fyzická rozhraní physdev. Zřejmě iptables nevidí na interní komunikaci v rámci bridge, což asi dává smysl. Pomohlo až použití ebtables a instalace balíčku kmod-ebtables-ipv4:

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

Tyto příkazy jsem přidal do /etc/rc.local pouze na druhém (klientském) Turrisu, protože k prvnímu se mohou připojovat na tap instanci i individuální klienti a u nich je DHCP skrz VPN nutné. Blokování by ale mělo fungovat oběma směry.

Ještě dodám, že jsem původně do ebtables dával kromě FORWARD i zahazování INPUT a OUTPUT směrů, ale to z nějakého důvodu pokazilo i lokální fungování DHCP. Nejsem si jistý, proč (neboť bylo vždy specifikováno rozhraní tap_turris). Stejně tak si nejsem jistý, že takto nastavené ebtables skutečně fungují, ale zatím jsem na zařízení se špatně přiřazenou IP adresou a bránou nenarazil. Budu to ale sledovat.

Dále jsem zjistil, že když jsem připojený z venku přes starý tun tunel, dostanu se na první část sítě (kde je server), ale už ne skrz nový tap tunel na druhou část sítě. Nakonec mi došlo, že je to tím, že druhý Turris vůbec neví o existenci původní VPN podsítě 192.168.4.0/24 na prvním Turrisu, a proto neví, co s pakety odpovědí. Pomohlo toto přidat do nastavení serveru:

config openvpn 'server_turris_tap'
    ...
    list push 'route 192.168.4.0 255.255.255.0 192.168.1.1'

Druhý Turris tak odpovědi pošle na bránu prvního Turrise, který už si s nimi poradí.

Poslední dodatek je k testování - nemám totiž na jednom místě dvě různá připojení k internetu (pokud nepočítám nouzově přes telefon). Proto jsem WAN druhého Turrise připojil přes wifi do guest sítě prvního, povolil z ní ve firewallu provoz do VPN a jako remote klienta nastavil bránu guest sítě. Finální otestování pak proběhlo přes wifi hotspot telefonu.

Uff. No nebylo to úplně jednoduché, ale vesměs to šlo hladčeji, než jsem čekal, a jednotlivé kroky dávaly smysl. A zatím se zdá, že to funguje dobře. Tak snad někdy nevystrčí růžky nějaký neočekávaný zádrhel.

5 Likes