Zverejnenie domáceho servera cez VPS, keď CGNAT blokuje porty
Cesta od prehliadača k domácemu stroju: dokáž, že linka je za CGNAT, nasmeruj DNS na VPS, urob DNAT jedného portu, oprav spätnú trasu a over zvonka.
Začal som zvonka, ako by to urobil používateľ: napísal som názov do prehliadača telefónu na mobilných dátach a sledoval, ako spojenie visí, kým nevypršal čas. Názov sa prekladal, takže DNS bolo v poriadku. Aj stránka presmerovania portov domáceho routera bola slepou uličkou, lebo jej adresa WAN ukazovala 100.64.31.42, a to nie je adresa, na ktorú ma poskytovateľ z internetu smeruje. To číslo vysvetľuje celú poruchu: linka je za carrier-grade NAT, takže verejná adresa na mojej strane tunela patrí poskytovateľovi. Čo nasleduje, je cesta, ktorú som prešiel od toho zaseknutého panelu k službe, ktorá odpovedá.
Začni u klienta a choď dovnútra
Predtým než zmeníš akékoľvek pravidlo, dokáž, kde sa reťaz zastaví. Na notebooku som spustil dig +short files.example.net a dostal späť adresu VPS, čo vylúčilo zastarané DNS na mojom stroji. Potom curl -v --connect-timeout 5 files.example.net:5022 vypršal namiesto toho, aby bol odmietnutý. Ten rozdiel je dôležitý: vypršanie zvyčajne znamená, že sa pakety po ceste zahadzujú, zatiaľ čo odmietnutie znamená, že niečo odpovedalo a povedalo nie.
Ďalším skokom dovnútra bolo samotné VPS. ss -ltnp neukázalo nič, čo by počúvalo na 5022, čo sa očakávalo pred vznikom pravidla DNAT. Na tom istom stroji wg show (alebo ip -br a show tun0 pre OpenVPN) potvrdilo, že domáci peer beží a má čerstvý handshake. Ak peer nebeží, žiadne pravidlo NAT nepomôže, a zelené svetlo na stránke VPN domáceho routera neznamená nič.
Potvrď, že domáca linka je naozaj za CGNAT
Porovnaj adresu, ktorú router hlási na rozhraní WAN, s tým, čo vidí externá služba. Všetko v 100.64.0.0/10, teda od 100.64.x.x do 100.127.x.x, je rozsah zdieľaných adries z RFC 6598 a z internetu nie je dosiahnuteľné. K rovnakému záveru dôjdeš, keď router tvrdí, že má bežnú privátnu adresu, a verejné vyhľadanie vráti niečo nesúvisiace. Linka CGNAT môže mať aj verejnú adresu platnú len do ďalšieho lease, takže presmerovanie portu vyzerá hodinu funkčne a potom ticho zomrie.
Niektorí poskytovatelia skutočne dávajú pravú verejnú adresu, ale blokujú prichádzajúce porty 80 a 443 na rezidenčných účtoch. Ak je tvoja služba len webová a adresa WAN je skutočne verejná, opýtaj sa podpory, kým postavíš relay. Ak nie je, nižšie uvedený návrh platí pre každý port rovnako a stojí za to experiment na strane routera zastaviť: translator v sieti poskytovateľa ukončí spojenie skôr, než vôbec dorazí na tvoje rozhranie WAN.
Nasmeruj názov na adresu VPS
DNS nepreposiela prevádzku, takže záznam A služby musí obsahovať verejnú adresu VPS. Záznam A na 192.168.1.20 sa užitočne prekladá len pre klientov, ktorí už sú vo VPN; z internetu sa prekladá na adresu, ktorú nikto nedokáže smerovať. Pre administratívny prístup k samotnému VPS držím samostatný názov, aby som nikdy neplietol, na ktorého hostiteľa záznam ukazuje.
Ak HTTP servíruje aj VPS, aj domáci stroj, daj každému vlastný názov a nechaj VPS rozhodnúť, kto odpovedá. Zložiť ich do jedného názvu a dúfať, že proxy vyberie správny backend, je presne to, ako stráviš celé popoludnie ladením nesprávneho hostiteľa.
Jeden port cez DNAT, SSH zostane na 22
Priamou možnosťou je cieľový NAT na VPS. Zapni forwarding pre bežiace jadro a drž v pravidle tunelovú adresu domáceho servera, nie jeho adresu LAN:
sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A PREROUTING -p tcp -d 198.51.100.10 --dport 5022 -j DNAT --to-destination 10.8.0.2
Nechaj SSH k samotnému VPS na 22 a preposielaj iný port, napríklad 5022, na domáci stroj. Keď preposielaš 22 na vypnutý stroj, stratíš jedinú cestu, ktorá ho mohla opraviť. Rovnaká logika platí pre proxy: drž správcovský port VPS mimo pravidiel relaye.
Urob pravidlá trvalými, keď fungujú. Na Debiane alebo Ubuntu ich apt install iptables-persistent a potom netfilter-persistent save zapíšu do /etc/iptables/rules.v4. Na hostiteľovi s firewalld je ekvivalentom trvalé preposlanie portu v zóne, ktoré pred uplatnením potrebuje firewall-cmd --reload. Pravidlá, ktoré žijú len v pamäti, zmiznú pri prvom údržbovom reštarte poskytovateľa, zvyčajne v nevhodnú hodinu.
Oprav spätnú trasu, alebo sa vyhni tomu ju potrebovať
DNAT prepisuje len cieľ. Domáci server vidí spojenie z pôvodnej adresy klienta, a ak jeho predvolená trasa mieri na domáci router, odpoveď vychádza cez domáci WAN, kde ju translator poskytovateľa zahodí. Tá asymetria bola druhá porucha, na ktorú som narazil, po tom čo pravidlo DNAT vyzeralo úplne správne.
Fungujú dve opravy. Daj domácemu stroju politickú trasu, aby prevádzka z tunela išla späť tunelom:
ip rule add from 10.8.0.2 table 100
ip route add default dev wg0 table 100
Alebo nechaj VPS prepísať zdroj, aby odpoveď mala adresu, ktorú dokáže dosiahnuť, a nechaj conntrack ju na ceste von otočiť:
iptables -t nat -A POSTROUTING -d 10.8.0.2 -p tcp --dport 5022 -j SNAT --to-source 10.8.0.1
Verzia SNAT skrýva skutočnú adresu klienta pred domácim serverom, takže aplikačné logy ukazujú 10.8.0.1 ako peer. Prevezmi pôvodnú adresu na aplikačnej vrstve, alebo prijmi stratu logovania po klientoch, ale rozhodni sa vedome, namiesto toho aby si to zistil počas incidentu.
Skontroluj celú cestu zvonka
Over zo siete, ktorá nie je ani VPS, ani domov: telefón na mobilných dátach, alebo lacný shell inde. nc -vz files.example.net 5022 by malo hlásiť úspešné spojenie a openssl s_client -connect files.example.net:443 -servername files.example.net by malo ukázať certifikát pre verejný názov. Potom skontroluj security group alebo cloudový firewall poskytovateľa. Pravidlo DNAT, ktoré nikdy nevidí paket, býva blokované o jednu vrstvu vyššie než hostiteľ.
Nakoniec rozhodni, čo sa stane, keď tunel spadne. Pravidlo DNAT ďalej prijíma spojenia a ticho ich posiela do mŕtveho tunela, čo vyzerá presne ako pokazená služba. Kontrola stavu na VPS, ktorá port odmieta, kým peer nebeží, stojí pár riadkov a ušetrí hodinu hádania. Potom prestaň upravovať pravidlá a sleduj to deň, kým tomu uveríš.