Példa egy szolgáltatás létrehozására

Első szolgáltatas amit nyújtani szeretnénk az a cég weblapjának elérhetősége az internetről. Ehhez egy olyan proxy modult indítunk, amely a csomag eredeti céljától függetlenűl mindenképpen a DMZ-ben lévő webszerverhez csatlakozik, melynek IP címe: 192.168.0.2.

Ehhez négy dolgot kell tennünk. Első, hogy megmondjuk a Zorp-nak, figyeljen a tűzfal külső lábán a 80-as porton jövő kérésekre. Ezt a kovetkező sorrral tudjuk megtenni:

Example 4-2. Listener létrehozása

	    Listener(SockAddrInet("10.9.8.7", 80), plug_direct_service)
	  

Így a Zorp figyelni fog a 10.9.8.7 -es IP cim 80-as portján, és ha érkezik egy kapcsolat, akkor elinditja a plug_direct_service nevu Service-t.

Ezután létre kell hoznunk azt a szolgáltatást, amit kapcsolódáskor a Listener elindít. Esetünkben ez most egy direkt kapcsolódású szolgáltatás, ami azt jelenti, hogy mi határozzuk meg - az eredeti céltol teljesen függetlenül - hogy mi legyen a szerver címe. Ez most azert fontos, mivel kintről csak a 10.9.8.7-es cím elérhető, a DMZ-ben levő IP cimek nem route-olhatoak.

Itt például a cél a 192.168.0.2-es gép 8080-as portja. (ahol remélhetőleg egy web szerver várja a kéréseket.)

Example 4-3. Direkt kapcsolódású szolgáltatás létrehozása

	    
	    plug_direct_service = \
	        Service("directplug", 
	        DirectedChainer(SockAddrInet("192.168.0.2", 8080)), 
	        MyPlug)
	  
A fenti szolgaltatasdefinicio a kovetkezoket kozli a Zorppal: a szolgaltatas neve ("directplug"), az alkalmazott Chainer (ami megmondja, hogy a DMZ-ben levo hoszthoz kell kapcsolodni), valamint az inditando Proxy modul azonositoja (MyPlug), melyet később kifejtünk.

Végül engedélyezzük a zónadefinicióban is az internet felől érkező, a DMZ-be tartó directplug szolgaltatast.

Example 4-4. Zóna definíció szolgáltatás engedélyezéssel

	    
	    Zorp.zones = [
	        InetZone("intranet","192.168.1.0","255.255.255.0", None),
	        InetZone("DMZ", "192.168.0.0", "255.255.255.0", None,
		    inbound_services = ["directplug"]),
	        InetZone("internet", "0.0.0.0", "0.0.0.0", None,
	            outbound_services = ["directplug"])]
	    
A szolgáltatás neve helyett '*'-t megadva minden, adott iranyba halado kerest engedélyezhetunk. (inbound_services = ["*"])

Már csak a MyPlug osztályt kell definiálni. A példánkban egy egyszerű, Plug tipusú proxy modult használunk.

Example 4-5. Származtatott proxy modul definíciója

	    class MyPlug(Plug.PlugProxy):
	        def config(self):
	            pass
	  
Amennyiben a kiszolgáló proxy megfelel nekünk alapbeállítással is, nem kötelező új osztályt definiálni, ebben az esetben a szolgáltatás definíciója a következő:

Example 4-6. Szolgáltatás definíció beépített proxy osztállyal

	    plug_direct_service = \
	        Service("directplug",
		    DirectedChainer(SockAddrInet("192.168.0.2", 8080)), 
	            PlugProxy)
	  
Nézzük egyben az egész policy-t:

	  from Zorp.Zorp import *
	  from Zorp import Zorp
	  from Zorp.Zone import InetZone
	  from Zorp.Service import Service
	  from Zorp.SockAddr import SockAddrInet
	  from Zorp.Chainer import TransparentChainer, DirectedChainer, InbandChainer, FailoverChainer
	  from Zorp.Plug import PlugProxy
	  from Zorp import Http
	  from Zorp.Http import HttpProxy
	  from Zorp.Ftp import FtpProxyAllow
	  from Zorp.Listener import Listener

	  Zorp.firewall_name = 'bzorp@fiktiv'

	  Zorp.zones= [
	      InetZone("intranet","192.168.1.0","255.255.255.0", None),
	      InetZone("DMZ", "192.168.0.0", "255.255.255.0", None,
		  outbound_services=[],
		  inbound_services = ["directplug"]),
              InetZone("internet", "0.0.0.0", "0.0.0.0", None,
		  outbound_services = ["directplug"],
		  inbound_services = [])]

	  class MyPlug(Plug.PlugProxy):
	      def config(self):
		  pass

	  def init(name):
	      plug_direct_service = \
		  Service("directplug",
	                  DirectedChainer(None,
			  SockAddrInet("192.168.0.2", 8080)), 
	                  MyPlug)
	      Listener(SockAddr.SockAddrInet("10.9.8.7", 80),
		       plug_direct_service)

	
Nézzük tovább a lehetőségeket. A fiktív vállalatunknál a DMZ-be rakott szerveren vannak a cég, és alkalmazottainak weboldalai, így azokat jó lenne, ha el lehetne érni pl. módosítás céljából belülről. Ehhez most (még) nyugodtan felhasználhatjuk a már leírt MyPlug osztályt. Így csak a service-t és a Listenert kell megírni, illetve engedélyezni a kapcsolatot a zóna definícióban.

Így a szükséges új elemek:

Example 4-7.

	    plug_transparent_service = \
	        Service("intransplug",
		   TransparentChainer(forge_addr=TRUE),
	           MyPlug)

	    Listener(SockAddrInet("192.168.1.1", 8080), plug_transparent_service)
	  
A következő kívánság, hogy a cég alkalmazottai el tudják érni az internetet, vagyis webezni tudjanak. Ehhez újból felhasználjuk a MyPlug osztályt. Mivel az intranet-en belső IP-ket használunk, ezért a kéréseknél "álcázni" kell ezeket az IP-ket.

A szerverhez való kapcsolódáskor a kapcsolat forráscímét a TransparentChainer osztály két paraméter alapján határozza meg:

  1. local, ha nem None, akkor erre a címre bindol kapcsolódás előtt

  2. forge_addr, ha értéke TRUE, akkor a tűzfal felveszi a kliens eredeti címét kapcsolódás előtt. Ilyenkor a local paraméter értéke érdektelen.

Example 4-8.

	    
	    plug_transparent2_service = \
	        Service("transplug",
		        TransparentChainer(local=None, forge_addr=FALSE),
		        MyPlug)
	    Listener(SockAddrInet("192.168.1.1", 80), 
	        plug_transparent2_service)
	  
Ezzel létrehoztunk egy olyan szolgáltatást, amely a kliens által kért célhoz csatlakozik (transzparensen), viszont átirja a csomag source IP-jét a saját IP-jére, azaz masquarade-olja a csatlakozást. (A későbbiekben NAT-ra is lehetőség lesz.) A kapcsolat kiszolgálója (kezelője) pedig a már ismert MyPlug nevü osztály lesz.

Nézzük meg, hogy hol is tartunk:

Example 4-9.

	    ...

	    Zorp.firewall_name = 'bzorp@fiktiv'

	    Zorp.zones= [
	        InetZone("intranet","192.168.1.0", "255.255.255.0", None,
	            outbound_services = ["intransplug", "transplug"],
		    inbound_services = []),
	        InetZone("DMZ", "192.168.0.0", "255.255.255.0", None,
		    outbound_services = [],
		    inbound_services = ["directplug", "intransplug"]),
	        InetZone("internet", "0.0.0.0", "0.0.0.0", None,
		    inbound_services = ["transplug"],
		    outbound_services = ["directplug"])]

	    class MyPlug(Plug.PlugProxy):
	        def config(self):
		    pass

	    def init(name):
	        plug_direct_service = \
		    Service("directplug",
			    DirectedChainer(SockAddrInet("192.168.0.2", 8080)),
			    MyPlug)

	        plug_transparent_service = \
		    Service("intransplug",
			    TransparentChainer(forge_addr=TRUE),
			    MyPlug)

	        plug_transparent2_service = \
		    Service("transplug",
			    TransparentChainer(),
			    MyPlug)

	    Listener(SockAddrInet("10.9.8.7", 80),
	             plug_direct_service)
	    Listener(SockAddrInet("192.168.1.1", 8080),
	             plug_transparent_service)
	    Listener(SockAddrInet("192.168.1.1", 80),
		     plug_transparent2_service)
	  
Ez a konfiguráció így egy kicsit furcsa, hiszen nem használja ki, hogy nekünk applikáció szintű tűzfalunk van. Ezért most első körben cseréljük le a "transparens" Plug proxy-t az internet felé menő forgalomról, és állítsunk be helyette egy valódi http proxy modult. Ehhez viszont már nem lesz jó a MyPlug osztály, hiszen azt a Plug osztályból származtattuk. Helyette hozzunk létre egy MyHttp osztályt.

Example 4-10. Http proxy osztály definiálása

	    class MyHttp(Http.HttpProxy):
	        def config(self):
		    self.transparent_mode = 1
	  
A transzparencia fogalma sajnos nem teljesen egyértelmű. Jelentheti a kapcsolatra utaló célcím szerinti transzparenciát, illetve utalhat a protokollfüggő proxyk azon sajátosságára, hogy transzparens és nem transparens protokoll szimulációjára is képesek. A célcím szerinti transzparenciát a esetünkben a TransparentChainer osztály használata jelenti, míg az InbandChainer a protokoll belső logikája alapján fogja eldönteni, hogy hova is csatlakozzon. A kényelmi szempontok azt diktálják, hogy a transzparens üzemmódot perferáljuk. Ebben az esetben a chainerünk maradhat transzparens chainer és a proxyosztálynak meg kell adnunk, hogy transzparensen végezze a protokoll műveleteket.

Example 4-11.

	    http_service = Service.Service("http", TransparentChainer(), MyHttp)
	  
A kívülről befelé jövő http kéréseket is sokkal logikusabb a http proxyn keresztűl küldeni, mint a Plug proxyn, ezzel is védve a szervert a támadásokkal szemben (persze meg mindig direkt a szerver címére irányítva), a belső hálóról a DMZ-be menő forgalmat viszont érdemes a Plug proxyn hagyni, ha nem követel túl nagy ellenőrzést ez a forgalom.