Cererea este mereu o variantă a aceleiași propoziții: păstrează VPN-ul pentru navigare, dar lasă SSH sau un job de backup să folosească conexiunea normală. Sfatul care circulă pentru asta, să redirecționezi portul cu reguli NAT din iptables, nu face asta. O regulă NAT rescrie adrese și porturi în interiorul unui flux; nu alege niciodată prin ce interfață iese pachetul. Decizia aparține căutării de rută, iar căutarea de rută are nevoie de ajutor ca să vadă un port.

De ce o rută simplă nu poate potrivi un port

Linux alege o rută căutând adresa destinației într-o tabelă, după ce tabelele candidate sunt filtrate prin reguli de politică. Acele reguli pot potrivi un marcaj de firewall, o adresă sursă, o interfață de intrare sau un UID. O intrare de rută nu are ea însăși câmp de port, fiindcă ruta e aleasă înainte ca antetul de transport să conteze.

iproute2 și kernelurile actuale lărgesc selectorul de reguli: ipproto, sport și dport sunt acceptate, deci ip rule add ipproto tcp dport 22 table 100 exprimă intenția într-o singură linie. Rulează ip rule add help pe gazda reală ca să vezi dacă buildul tău listează dport. Dacă o face, ai terminat cu o comandă; dacă nu, calea cu marcaj de mai jos este echivalentul.

În orice caz, regula este doar un indicator. Tabela 100 tot are nevoie de o rută, și asta este partea pe care oamenii o uită.

Trei piese, sau una

Forma modernă este regula unică de mai sus plus o rută în tabela alternativă. Forma clasică adaugă netfilter la mijloc: marchează pachetul, apoi potrivește marcajul într-o regulă. Ambele se termină la aceeași căutare; diferă prin locul unde este citit portul.

Abordarea cu marcaj există pentru că netfilter vede antetul de transport, iar codul de rutare istoric nu îl vedea. Acesta este tot mecanismul și explică de ce soluția de rezervă sunt trei piese care cooperează, nu o comandă isteață.

Cele trei piese în ordine

Mai întâi, marchează fluxurile pe care vrei să le deturnezi, într-un lanț care rulează destul de devreme ca marcajul să existe înainte de decizia de rută:

nft add table inet vpnexempt
nft 'add chain inet vpnexempt out { type route hook output priority mangle; }'
nft add rule inet vpnexempt out tcp dport 22 meta mark set 0x1

Al doilea, trimite pachetele marcate într-o tabelă separată:

ip rule add fwmark 0x1/0x1 table 100

Al treilea, dă acelei tabele o rută implicită prin legătura fizică. Adresele sunt ilustrative; înlocuiește-le cu ale tale:

ip route add default via 192.168.1.1 dev wlan0 table 100

Sari peste al treilea pas și pachetul marcat nu găsește nicio rută în tabela 100, așa că eșuează. Simptomul arată ca și cum regula a stricat rețeaua, când de fapt a eliminat singura cale rămasă pachetului.

Ce îl ține funcțional după primul pachet

Marcajele se aplică pachetelor de ieșire. Răspunsul sosește pe interfața fizică cu adresa pe care legătura a atribuit-o, iar tabela principală poate prefera în continuare tunelul pentru acea destinație. Două mecanisme țin calea de întoarcere consecventă: o regulă bazată pe sursă pentru adresa legăturii și connection tracking, care păstrează decizia pe toată durata fluxului. Salvarea marcajului în conntrack și restaurarea lui la răspuns este modul obișnuit de a face stabilă o excepție cu stare.

Filtrarea căii inverse este celălalt ucigaș tăcut. Dacă kernelul validează strict calea de întoarcere și răspunsul sosește pe o interfață pe care tabela principală nu ar alege-o, pachetul este eliminat fără mesaj. rp_filter valorile implicite diferă de la o distribuție la alta și depind de dacă interfața este redirecționată, așa că citește valoarea efectivă în loc să presupui că este oprită.

Nu marca transportul propriu al tunelului. Un tunel WireGuard sau UDP OpenVPN nu este TCP 22, deci rețeta de mai sus este sigură, dar o excepție scrisă ca tot ce nu este destinația tunelului poate captura pachetele criptate și poate rupe tunelul într-un mod care arată ca o buclă de rutare.

Verifică în loc să presupui

Întreabă kernelul ce cale ar alege, pentru destinație și pentru port, apoi rulează transferul real:

ip route get 203.0.113.10
ip rule show
nft list ruleset

Dacă marcajul există dar contoarele nu se mișcă niciodată, regula nu potrivește. Contoarele sunt diferența dintre o configurație pe care ai scris-o și o politică pe care kernelul o aplică.

Când acesta este instrumentul greșit

Excepțiile bazate pe port sunt fragile prin natură. Serviciile își mută porturile, HTTP/3 sosește ca UDP 443, iar o aplicație poate deschide mai multe fluxuri de tipuri diferite. Dacă cerința reală este ca acest program să folosească legătura normală, stratul de rutare este locul greșit; un spațiu de nume de rețea sau un proxy per aplicație se potrivește mai bine.

Dacă cerința este ca această subrețea să folosească legătura normală, sari complet peste marcaje și adaugă o rută mai specifică. Este mai simplu, este vizibil într-o singură tabelă, iar următoarea persoană o poate audita fără să citească un set de reguli.

Notează care dintre cele trei cerințe o ai de fapt înainte de a atinge firewallul. Mecanismul de mai sus este precis, iar precizia aplicată la stratul greșit este doar o pană mai lungă.

Articole similare