Gyakran hasznos lehet anélkül felosztani egy fizikai hálózatot (például egy Ethernet szegmenst) két külön hálózati szegmensre, hogy külön IP-alhálózatot kellene létrehozunk és összekötnünk ezeket egy útválasztóval. A két ilyen módon kialakított hálózatot összekötő eszközt nevezzük “hálózati hídnak” (bridge). A legalább két hálózati felülettel rendelkező FreeBSD rendszerek képesek hálózati híd szerepét betölteni.
A hálózati híd az eszközök adatkapcsolati rétegben a hozzátartozó felületein megjelenő (vagyis Ethernet) címének megtanulásával működik. A két hálózat között csak akkor közvetít forgalmat, amikor a forrás és cél nem ugyanabban a hálózatban található.
A hálózati hidak bizonyos szempontból lényegében nagyon kevés porttal rendelkező Ethernet switch-ek.
Napjainkban akad néhány igen jellemző szituáció, ahol szükség van a hálózati hidak alkalmazására.
A hálózati hidak alapvető feladata két vagy több hálózati szegmens összekötése. Az egyszerű hálózati környezet felállítása helyett több okból is felmerülhet a hidak létrehozása: kábelezési megszorítások, tűzfalazás vagy pszeudo hálózatok, például virtuális gépek felületének csatlakoztatása miatt. Egy híd használatával ráadásul össze tudunk kötni egy vezeték nélküli hozzáférési pontként üzemelő felületet egy vezetékes hálózattal.
Sokszor előfordulhat, hogy útválasztás vagy hálózati címfordítás (NAT) nélkül szeretnénk tűzfalat használni.
Példaként képzeljünk el egy olyan kis méretű céget, amely egy DSL vagy ISDN vonalon kapcsolódik az internet-szolgáltatójához. A szolgáltatótól 13, mindenki által használható IP-címet kaptak és a hálózatukban 10 gép van. Ebben a helyzetben egy útválasztást végző tűzfal működtetése nehézkessé válna az alhálózatok problémái miatt.
Egy hídként viselkedő tűzfallal azonban minden IP számozási probléma nélkül egyszerűen be tudjuk dobni a gépeket a DSL/ISDN útválasztó mögé.
Egy hálózati híddal úgy kapcsolunk össze két hálózati szegmenst, hogy közben meg tudjuk vizsgálni a kettejük között mozgó Ethernet kereteket. Ezt a híd felületen a bpf(4) valamint a tcpdump(1) segítségével tudjuk megoldani, vagy úgy, ha egy másik felületen elküldjük az összes keret másolatát (span, vagyis feszítő port).
A két Ethernet hálózatot egy IP alapú összeköttetésen keresztül is össze tudunk kötni, ha a hálózatokat egy EtherIP járaton keresztül kötjük össze híddal, vagy egy OpenVPN-hez hasonló tap(4) alapú megoldással.
A hálózatokat több linken keresztül kötjük össze és a redundáns útvonalakat a feszítőfa protokollal (Spanning Tree Protocol, STP). Az Ethernetes hálózatok esetében a megfelelő működéshez a két eszköz között csak egyetlen aktív útvonal létezhet, így a feszítőfa protokoll észleli a hurkokat és a redundáns összeköttetéseket blokkolt állapotba teszi. Amikor azonban az aktív linkek egyike meghibásodik, akkor a protokoll újraszámolja a fát és a hálózati pontjai közti konnektivitást megpróbálja helyreállítani az addig blokkolt linkek ismételt engedélyezésével.
Ebben a szakaszban az if_bridge(4) hálózati híd implementációval foglalkozunk, de a Netgraph segítségével is tudunk hidakat építeni. Ez utóbbiról az ng_bridge(4) man oldalon olvashatunk.
Amikor létrehozunk egy hálózati hidat, az ifconfig(8) automatikusan betölti a hozzátartozó meghajtót. Ha viszont a rendszermag beállításait tartalmazó állományba felvesszük a device if_bridge sort, akkor akár be is építhetjük a rendszermagba.
A csomagszűrés minden olyan tűzfallal használható, amely a pfil(9) rendszerre kapcsolódik. Maga a tűzfal is betölthető modulként, vagy belefordítható a rendszermagba.
A hálózati híddal forgalmat is tudunk szabályozni az altq(4) vagy a dummynet(4) segítségével.
Hálózati hidak felületek klónozásával hozhatóak létre. A híd létrehozásához használjuk az ifconfig(8) programot, és a megfelelő meghajtó automatikusan betöltődik, ha nem lenne még elérhető a rendszermagban.
# ifconfig bridge create bridge0 # ifconfig bridge0 bridge0: flags=8802<BROADCAST,SIMPLEX,MULTICAST> metric 0 mtu 1500 ether 96:3d:4b:f1:79:7a id 00:00:00:00:00:00 priority 32768 hellotime 2 fwddelay 15 maxage 20 holdcnt 6 proto rstp maxaddr 100 timeout 1200 root id 00:00:00:00:00:00 priority 0 ifcost 0 port 0
Ekkor létrejön a hálózati hídhoz tartozó felület és véletlenszerűen generálódik hozzá egy Ethernetes cím. A maxaddr és a timeout paraméterek vezérlik, hogy a híd mennyi MAC-címet tartson meg a keretek továbbításáért felelős táblázatban és mennyi másodperc után töröljön automatikusan egy bejegyzést a legutolsó használat után. A többi paraméter a feszítőfa működését irányítja.
Vegyük fel a hídhoz tartozó hálózati tagfelületeket. A híd csak akkor fog a tagfelületek között csomagokat továbbküldeni, amikor a híd és a tagok is up állapotban vannak:
# ifconfig bridge0 addm fxp0 addm fxp1 up # ifconfig fxp0 up # ifconfig fxp1 up
A híd most már átküldi az Ethernet kereteket a fxp0 és fxp1 felületek között. Az iméntiekkel megegyező konfigurációt az /etc/rc.conf állományban így alakíthatjuk ki:
cloned_interfaces="bridge0" ifconfig_bridge0="addm fxp0 addm fxp1 up" ifconfig_fxp0="up" ifconfig_fxp1="up"
Ha a hídhoz IP-címet is rendelni akarunk, akkor inkább magánál a hídnál adjuk meg, ne a tagoknál. Ezt statikusan vagy DHCP használatával is megtehetjük:
# ifconfig bridge0 inet 192.168.0.1/24
A hídhoz IPv6 címet is hozzá tudunk rendelni.
Ha engedélyezzük a csomagszűrést, a hídon áthaladó csomagok először a küldő felület érkezési oldalára kerülnek, majd a hídra, végül a megfelelő irányban levő felület küldési oldalára. Bármelyik fázis letiltható. Amikor a csomagok áramlásának iránya fontos számunkra, akkor jobban járunk, ha nem magára a hídra, hanem csak a tagfelületekre állítjuk be a tűzfalat.
A híd számos módosítható beállítással rendelkezik a nem-IP és ARP csomagok átküldésére, valamint arra, hogy az IPFW tűzfal adatkapcsolati réteg szintjén működhessen. Az if_bridge(4) man oldal ennek részleteit tárja fel.
A híd meghajtója a gyors feszítőfa protokollt (Rapid Spanning Tree Protocol, RSTP avagy 802.1w) valósítja meg, ami visszafelé kompatibilis a korábban említett feszítőfa protokollal. A feszítőfákat a hálózati topológiában felbukkanó hurkok észlelésére és eltávolítására alkalmazzák. Az RSTP azonban a hagyományos STP-nél valamivel gyorsabb konvergenciát ígér, mivel itt a szomszédos switch-ek kicserélik egymás között az adataikat, és így újabb hurkok létrehozása nélkül képesek viszonylag gyorsan egyik állapotból átváltani a másikba.
Az alábbi táblázat a támogatott működési módokat láthatjuk:
Operációs rendszer | STP módok | Alapértelmezés |
---|---|---|
FreeBSD 5.4--FreeBSD 6.2 | STP | STP |
FreeBSD 6.3+ | RSTP vagy STP | STP |
FreeBSD 7.0+ | RSTP vagy STP | RSTP |
A tagfelületeken az stp paranccsal tudjuk engedélyezni a feszítőfák használatát. Az fxp0 és fxp1 felületeket összekötő hídfelület esetében tehát így:
# ifconfig bridge0 stp fxp0 stp fxp1 bridge0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500 ether d6:cf:d5:a0:94:6d id 00:01:02:4b:d4:50 priority 32768 hellotime 2 fwddelay 15 maxage 20 holdcnt 6 proto rstp maxaddr 100 timeout 1200 root id 00:01:02:4b:d4:50 priority 32768 ifcost 0 port 0 member: fxp0 flags=1c7<LEARNING,DISCOVER,STP,AUTOEDGE,PTP,AUTOPTP> port 3 priority 128 path cost 200000 proto rstp role designated state forwarding member: fxp1 flags=1c7<LEARNING,DISCOVER,STP,AUTOEDGE,PTP,AUTOPTP> port 4 priority 128 path cost 200000 proto rstp role designated state forwarding
Láthatjuk, hogy a híd a feszítőfában megkapta a 00:01:02:4b:d4:50-es azonosítót és a 32768-as prioritást. Mivel root id értéke is ugyanez, elmondhatjuk, hogy ez a fa gyökereként funkcionáló híd.
Ha a hálózaton már valahol létezik egy másik híd:
bridge0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500 ether 96:3d:4b:f1:79:7a id 00:13:d4:9a:06:7a priority 32768 hellotime 2 fwddelay 15 maxage 20 holdcnt 6 proto rstp maxaddr 100 timeout 1200 root id 00:01:02:4b:d4:50 priority 32768 ifcost 400000 port 4 member: fxp0 flags=1c7<LEARNING,DISCOVER,STP,AUTOEDGE,PTP,AUTOPTP> port 4 priority 128 path cost 200000 proto rstp role root state forwarding member: fxp1 flags=1c7<LEARNING,DISCOVER,STP,AUTOEDGE,PTP,AUTOPTP> port 5 priority 128 path cost 200000 proto rstp role designated state forwarding
A root id 00:01:02:4b:d4:50 priority 32768 ifcost 400000 port 4 sor mutatja, hogy a fa gyökerét képező híd most a 00:01:02:4b:d4:50 azonosítóval rendelkezik, és ezt a hidat 400000-res költséggel éri el a port 4 (a 4. porton) keresztül, amely jelen esetben az fxp0 felület.
A hidak támogatják az ún. megfigyelési módot, ahol a csomagokat a bpf(4) feldolgozásuk után eldobja, így nem folytatódik a feldolgozásuk vagy nem haladnak tovább. Ennek kihasználásával a két vagy több felületen érkező adatokat egyetlen bpf(4) folyammá tudjuk alakítani. Ez olyan hálózati csapok forgalmának átszerkesztésében hasznos, ahol a két különböző felületen keresztül küldjük ki az RX/TX (fogadás/küldés) jeleket.
Az alábbi paranccsal tudjuk megoldani, hogy négy felületről érkező adatot legyünk képesek egyetlen folyamként olvasni:
# ifconfig bridge0 addm fxp0 addm fxp1 addm fxp2 addm fxp3 monitor up # tcpdump -i bridge0
A hídhoz befutó Ethernet keretek mindegyikéről készül egy másolat, ami egy megadott feszítő porton keresztül megy tovább. Hidanként végtelen számú ilyen feszítő port létezhet, és ha egy felületet feszítő portnak adtunk meg, akkor hagyományos portként már nem használhatjuk. Ez leginkább akkor hasznos, amikor passzívan akarjuk megfigyelni a híddal rendelkező hálózatot a híd valamelyik feszítő portjára csatlakozó gépről.
Küldessük az összes keretről egy másolatot az fxp4 felületre:
# ifconfig bridge0 span fxp4
A privát felületek (private interface) csak más privát felületek felé küldenek tovább adatot. Így feltétel nélkül tudjuk korlátozni a forgalmat, és sem Ethernet keretek, sem pedig ARP nem megy keresztül rajtuk. Ha viszont szelektíven akarjuk korlátozni a forgalmat, akkor helyette használjunk tűzfalat.
Ha a híd egyik tagfelületét tapadósnak (sticky) adjuk meg, akkor a dinamikusan megtanult címek bejegyzései a gyorsítótárba kerülésük után állandósulnak. A tapadós bejegyzések soha nem évülnek el vagy cserélődnek le, még abban az esetben sem, ha utána az adott címet egy másik felületről látjuk. Így a továbbításra vonatkozó táblázatot nem kell előre feltöltenünk, és a híd egyik oldalán meglátott kliensek nem képesek átvándorolni egy másik hálózati szegmensbe.
Másik ilyen példa a tapadós címek használatára az lehetne, amikor a hidat VLAN-nal kombináljuk, és így egy olyan útválasztót hozunk létre, ahol az ügyfeleink az IP-címtartomány pocséklása nélkül zárhatóak el egymástól. Tegyük fel, hogy az A-ugyfel a vlan100, és a B-ugyfel a vlan101 felületen csatlakozik. A híd IP-címe 192.168.0.1, amely maga is egy internet felé mutató útválasztó.
# ifconfig bridge0 addm vlan100 sticky vlan100 addm vlan101 sticky vlan101 # ifconfig bridge0 inet 192.168.0.1/24
Mind a két kliens a 192.168.0.1 címet látja alapértelmezett átjáróként, és mivel a híd gyorsítótára tapadós bejegyzéseket tartalmaz, a MAC-címeik meghamisításával nem tudják elcsípni a másikuk forgalmát.
A VLAN-ok közti bárminemű kommunikációt privát felületek létrehozásával akadályozzuk meg (vagy egy tűzfallal):
# ifconfig bridge0 private vlan100 private vlan101
Ezzel a megoldással az ügyfeleinket teljesen elszigeteljük egymástól úgy, hogy közben az egész /24 címtartomány külön alhálózatok kialakítása nélkül kiosztható.
Korlátozhatóak az egy felület mögül küldeni képes egyedi MAC-címek. Amikor ezen a határon felül érkeznek ismeretlen feladótól csomagok, egészen addig eldobjuk ezeket, amíg egy korábban már regisztrált bejegyzést a rendszer ki nem töröl vagy ki nem veszünk a gyorsítótárból.
A következő példában az vlan100 felületen csatlakozó A-ugyfel számára korlátozzuk le 10-re az Ethernet eszközök számát:
# ifconfig bridge0 ifmaxaddr vlan100 10
A hidak és az STP paraméterei az alap FreeBSD rendszerben megtalálható SNMP démonnal felügyelhetőek. A hídhoz exportált felügyeleti információk (Management Information Base, MIB) megfelelnek az IETF által előírt szabványoknak, így akár tetszőleges SNMP kliens vagy bármilyen más felügyeleti szoftver alkalmas az olvasásukra.
A hidat működtető gépen az /etc/snmp.config állományban engedélyezzük a begemotSnmpdModulePath."bridge" = "/usr/lib/snmp_bridge.so" sort és indítsuk el a bsnmpd démont. Itt még szükség lehet más beállítások, például a közösségek nevének (community name) vagy a hozzáférési listák (access list) módosítására is. Ezzel kapcsolatban a bsnmpd(1) és az snmp_bridge(3) man oldalakat lapozzuk fel.
A következő példában a Net-SNMP nevű szoftver (net-mgmt/net-snmp) fogjuk használni a híd elérésére, de ugyanerre a net-mgmt/bsnmptools port is alkalmas. Az SNMP klienst használó gépen egészítsük ki az $HOME/.snmp/snmp.conf állományt a híd felügyeleti információinak importálásával az Net-SNMP rendszerébe:
mibdirs +/usr/share/snmp/mibs mibs +BRIDGE-MIB:RSTP-MIB:BEGEMOT-MIB:BEGEMOT-BRIDGE-MIB
Az IETF BRIDGE-MIB (RFC 4188) használatán keresztül így tudjuk elindítani egy híd felügyeletét:
% snmpwalk -v 2c -c public bridge1.example.com mib-2.dot1dBridge BRIDGE-MIB::dot1dBaseBridgeAddress.0 = STRING: 66:fb:9b:6e:5c:44 BRIDGE-MIB::dot1dBaseNumPorts.0 = INTEGER: 1 ports BRIDGE-MIB::dot1dStpTimeSinceTopologyChange.0 = Timeticks: (189959) 0:31:39.59 centi-seconds BRIDGE-MIB::dot1dStpTopChanges.0 = Counter32: 2 BRIDGE-MIB::dot1dStpDesignatedRoot.0 = Hex-STRING: 80 00 00 01 02 4B D4 50 ... BRIDGE-MIB::dot1dStpPortState.3 = INTEGER: forwarding(5) BRIDGE-MIB::dot1dStpPortEnable.3 = INTEGER: enabled(1) BRIDGE-MIB::dot1dStpPortPathCost.3 = INTEGER: 200000 BRIDGE-MIB::dot1dStpPortDesignatedRoot.3 = Hex-STRING: 80 00 00 01 02 4B D4 50 BRIDGE-MIB::dot1dStpPortDesignatedCost.3 = INTEGER: 0 BRIDGE-MIB::dot1dStpPortDesignatedBridge.3 = Hex-STRING: 80 00 00 01 02 4B D4 50 BRIDGE-MIB::dot1dStpPortDesignatedPort.3 = Hex-STRING: 03 80 BRIDGE-MIB::dot1dStpPortForwardTransitions.3 = Counter32: 1 RSTP-MIB::dot1dStpVersion.0 = INTEGER: rstp(2)
A példában látszik, hogy a dot1dStpTopChanges.0 értéke kettő, ami arra utal, hogy az STP híd topológiája kétszer változott. A topológia változása pedig azt jelenti, hogy a hálózaton belül egy vagy több link állapota megváltozott vagy egyszerűen meghibásodott és ezért egy új fát kellett számolni. A dot1dStpTimeSinceTopologyChange.0 érték adja meg, hogy ez pontosan mikor is történt.
Több híd felületének felügyeletéhez a belső BEGEMOT-BRIDGE-MIB parancsot is használhatjuk:
% snmpwalk -v 2c -c public bridge1.example.com enterprises.fokus.begemot.begemotBridge BEGEMOT-BRIDGE-MIB::begemotBridgeBaseName."bridge0" = STRING: bridge0 BEGEMOT-BRIDGE-MIB::begemotBridgeBaseName."bridge2" = STRING: bridge2 BEGEMOT-BRIDGE-MIB::begemotBridgeBaseAddress."bridge0" = STRING: e:ce:3b:5a:9e:13 BEGEMOT-BRIDGE-MIB::begemotBridgeBaseAddress."bridge2" = STRING: 12:5e:4d:74:d:fc BEGEMOT-BRIDGE-MIB::begemotBridgeBaseNumPorts."bridge0" = INTEGER: 1 BEGEMOT-BRIDGE-MIB::begemotBridgeBaseNumPorts."bridge2" = INTEGER: 1 ... BEGEMOT-BRIDGE-MIB::begemotBridgeStpTimeSinceTopologyChange."bridge0" = Timeticks: (116927) 0:19:29.27 centi-seconds BEGEMOT-BRIDGE-MIB::begemotBridgeStpTimeSinceTopologyChange."bridge2" = Timeticks: (82773) 0:13:47.73 centi-seconds BEGEMOT-BRIDGE-MIB::begemotBridgeStpTopChanges."bridge0" = Counter32: 1 BEGEMOT-BRIDGE-MIB::begemotBridgeStpTopChanges."bridge2" = Counter32: 1 BEGEMOT-BRIDGE-MIB::begemotBridgeStpDesignatedRoot."bridge0" = Hex-STRING: 80 00 00 40 95 30 5E 31 BEGEMOT-BRIDGE-MIB::begemotBridgeStpDesignatedRoot."bridge2" = Hex-STRING: 80 00 00 50 8B B8 C6 A9
Így tudjuk megadni, hogy a hidat mib-2.dot1dBridge részfán keresztül akarjuk megfigyelni:
% snmpset -v 2c -c private bridge1.example.com BEGEMOT-BRIDGE-MIB::begemotBridgeDefaultBridgeIf.0 s bridge2
Ha kérdése van a FreeBSD-vel kapcsolatban, a következő
címre írhat (angolul): <freebsd-questions@FreeBSD.org>.
Ha ezzel a dokumentummal kapcsolatban van kérdése,
kérjük erre a címre írjon: <gabor@FreeBSD.org>.