Două mașini virtuale pe același host ajung în LAN printr-o punte, iar o regulă plasată în lanțul ip forward arată un contor care nu se mișcă niciodată. Cadrele sunt reale, traficul trece, iar regula pur și simplu nu este pe calea lui. Compararea celor două moduri în care Linux expune traficul prin punte explică această tăcere și explică și de ce încărcarea unui modul vechi este un răspuns mai slab decât pare.

Două căi printr-un singur host

Un pachet poate părăsi acest host în două moduri foarte diferite, iar diferența decide ce hook-uri îl văd. Dacă destinația este dincolo de un port fizic și cadrul este comutat între două porturi ale punții, hostul transmite mai departe un cadru Ethernet; codul de rutare nu este consultat și nu are loc niciun salt rutat. Dacă destinația este hostul însuși sau o rețea atinsă printr-o interfață de tunel, pachetul este rutat și hook-urile stratului IP se aplică într-adevăr. Ține minte această bifurcație, pentru că fiecare întrebare ulterioară despre lanțuri și familii decurge din care dintre cele două căi o ia un cadru.

Acea distincție este toată povestea din spatele unei reguli care nu numără nimic. Un cadru prin punte de la veth9a1 la enp3s0 traversează puntea, nu stiva IP, așa că un lanț ip forward nu vede nimic cu care să se potrivească. Numele interfețelor dintr-un exemplu mai vechi nu stabilesc ce cale ai, și de aceea primul pas este să te uiți la topologie, nu la setul de reguli.

Un tunel adaugă un al treilea caz care merită un nume. Un dispozitiv TUN livrează pachete IP hostului, deci acestea sunt rutate și trec într-adevăr prin lanțuri IP, în timp ce un dispozitiv TAP conectat la o punte livrează cadre și se comportă ca cazul punții. Tipul dispozitivului, nu numele produsului, decide.

Compară cele două familii care pot vedea un cadru prin punte

Linux acceptă filtrarea nativă a punții prin familia bridge a nftables și nu are nevoie de niciun modul vechi pentru a inspecta și elimina cadre în zbor. Documentația punții a kernelului însuși face această recomandare direct, ceea ce merită știut înainte ca un rezultat de căutare să îți spună să încarci un modul.

Observation pointWhat it seesWhat it costs
nftables bridge family chainsEthernet frames forwarded between bridge ports, in both directionsRules must be written in bridge syntax with link-layer matches
Legacy br_netfilter plus an ip chainBridged IPv4 and IPv6 packets, re-exposed through IP-layer hooksExisting host rules may begin matching traffic they never saw before
inet chain for routed trafficPackets the host routes, including traffic arriving from a TUN deviceNo visibility into purely switched frames

Folosirea comenzii nft în locul iptables nu plasează, prin ea însăși, o regulă în familia corectă. Un lanț declarat în familia bridge vede cadre; un lanț declarat în ip, ip6 sau inet nu le vede, indiferent ce binar l-a creat. Familia este o proprietate a lanțului, nu a instrumentului care l-a scris.

Calea veche funcționează altfel și de aceea merită comparat în loc să alegi o parte din obișnuință. Încărcarea br_netfilter și activarea setărilor bridge-nf-call expune din nou traficul IPv4 și IPv6 prin punte prin hook-urile stratului IP, astfel încât o regulă obișnuită iptables poate în sfârșit să se potrivească cu el. Cadrele nu se schimbă; se schimbă mulțimea de hook-uri prin care trec, ceea ce înseamnă că fiecare regulă de host existentă are acum un public nou.

Citește calea efectivă înainte de a adăuga o regulă

Trei comenzi stabilesc unde ești: la ce este conectată puntea, dacă modulul vechi este activ și ce lanțuri există deja în familia bridge. Rulează-le înainte de a scrie ceva, pentru că răspunsul decide care dintre cele două proiecte îl extinzi. Sărirea peste acest pas este felul în care o regulă corectă ajunge într-un lanț prin care nu trece nimic.

bridge link show
lsmod | grep br_netfilter
nft list ruleset | grep -A4 "chain forward"

Ieșirea separă cazurile curat. Porturile listate sub punte îți spun ce interfețe sunt comutate; un rezultat gol lsmod înseamnă nicio vizibilitate la nivelul IP al cadrelor prin punte; un lanț forward existent al familiei bridge înseamnă că există deja un proprietar al politicii și că regula ta îi aparține acolo, nu unui lanț nou al ei.

Apoi adaugă o regulă ușor de recitit, cu un contor și fără a schimba verdictul, și trimite un singur flux reprezentativ prin punte. Un contor care se mișcă dovedește că s-a ajuns la regulă cu cadrul. Asta este tot ce dovedește, așa că urmează și cu calea refuzată, deoarece o politică ce acceptă tot produce și ea un contor în mișcare.

nft add rule bridge filter forward iifname "veth9a1" oifname "enp3s0" counter accept

Unde modulul vechi schimbă comportamentul

Activarea căii vechi pe o punte în funcțiune nu este un act neutru de adăugare de vizibilitate. Regulile care erau înainte inaccesibile pentru traficul prin punte devin accesibile, inclusiv reguli de host scrise pentru altă interfață, iar o politică drop implicită în lanțul ip forward poate brusc să se aplice cadrelor care treceau netulburate. Pe un host administrat prin acea punte, rezultatul este o blocare fără consolă. Acesta nu este un mod de eșec ipotetic; este consecința obișnuită a extinderii unui set de hook-uri pe o mașină la care ajungi prin calea pe care tocmai ai extins-o.

Secvența mai sigură este să decizi ce familie deține politica, să scrii regulile acolo și să păstrezi o cale de recuperare independentă înainte de a schimba orice sysctl. Dacă două familii au reguli, documentează care este autoritatea; două politici suprapuse sunt felul în care un pachet este acceptat într-un loc și eliminat în altul fără niciun fișier de citit.

Izolarea în sine are nevoie încă de un proiect complet. Permiterea unei surse către o destinație dovedește doar că un flux funcționează, în timp ce cerința este de obicei ca o VM să nu poată ajunge la vecinii ei sau la host. Contoarele de pe regulile de refuz contează mai mult decât contorul de pe regula de acceptare, pentru că acela este cel despre care te așteptai deja să se miște.

În sfârșit, ține separat cazul intrării hostului. Traficul adresat IP-ului punții ajunge la input, nu la forward, iar o regulă în forward nu îl va vedea niciodată, orice familie ai alege. Trei cazuri, două familii, o lecție: calea decide hook-ul, iar hook-ul decide dacă regula ta există deloc.

Articole similare