From 039f5350311e45ab1071fd251802e519eb4dfbdc Mon Sep 17 00:00:00 2001 From: pauget Date: Sun, 7 Nov 2004 22:23:15 +0100 Subject: [PATCH] Slimfast. darcs-hash:20041107212315-41617-26f0d2cd5a5e3bda174698b8c8c8cc751438f789.gz --- gestion/classe_firewall.py | 423 +++++++++++++------------------------ 1 file changed, 146 insertions(+), 277 deletions(-) diff --git a/gestion/classe_firewall.py b/gestion/classe_firewall.py index 09a69d8c..05470127 100755 --- a/gestion/classe_firewall.py +++ b/gestion/classe_firewall.py @@ -15,11 +15,9 @@ # MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR # PURPOSE. """ classe Firewall de Komaz """ -import commands,time -import sys,os -import iptools,config,fileinput -from ldap_crans import * -from config_firewall import * +import commands,time, syslog +import iptools,config +from ldap_crans import crans_ldap from affich_tools import * class ErrorArgument(Exception): @@ -55,7 +53,15 @@ class ErrorIptables(Exception): self.output=output openlog(ident='syslog',logopt=0,facility=' LOG_USER') syslog('LOG_ALERT',cmd,err,output) - + +def iptables(self,cmd): + status,output=getstatusoutput(cmd) + if status: + raise IptablesError(cmd,status,output) + self.file_log.write(time.time+": "+cmd) + return output + + class ErrorNoSuchIp(ErrorIp): """ User defined exception @@ -109,30 +115,50 @@ class firewall: 'udp_input' : [''], 'udp_output': [':136','140:'] } mac_wifi = '00:0c:f1:fa:f1:4b' + limit = " -m limit --limit 10/s --limit-burst 10 " - - + log_template = '-m limit --limit 1/s --limit-burst 1 -j LOG --log-level notice --log-prefix ' + + reseaux_non_routables = [ '1.0.0.0/8','2.0.0.0/8','5.0.0.0/8','7.0.0.0/8',\ + '10.0.0.0/8','14.0.0.0/8','23.0.0.0/8','27.0.0.0/8','31.0.0.0/8','36.0.0.0/8',\ + '37.0.0.0/8','39.0.0.0/8','41.0.0.0/8','42.0.0.0/8','71.0.0.0/8','72.0.0.0/8',\ + '73.0.0.0/8','74.0.0.0/8','75.0.0.0/8','76.0.0.0/8','77.0.0.0/8','78.0.0.0/8',\ + '79.0.0.0/8','89.0.0.0/8','90.0.0.0/8','91.0.0.0/8','92.0.0.0/8','93.0.0.0/8',\ + '94.0.0.0/8','95.0.0.0/8','96.0.0.0/8','97.0.0.0/8','98.0.0.0/8','99.0.0.0/8',\ + '100.0.0.0/8','101.0.0.0/8','102.0.0.0/8','103.0.0.0/8','104.0.0.0/8',\ + '105.0.0.0/8','106.0.0.0/8','107.0.0.0/8','108.0.0.0/8','109.0.0.0/8',\ + '110.0.0.0/8','111.0.0.0/8','112.0.0.0/8','113.0.0.0/8','114.0.0.0/8',\ + '115.0.0.0/8','116.0.0.0/8','117.0.0.0/8','118.0.0.0/8','119.0.0.0/8',\ + '120.0.0.0/8','121.0.0.0/8','122.0.0.0/8','123.0.0.0/8','124.0.0.0/8',\ + '125.0.0.0/8','126.0.0.0/8','127.0.0.0/8','169.254.0.0/16','172.16.0.0/12',\ + '173.0.0.0/8','174.0.0.0/8','175.0.0.0/8','176.0.0.0/8','177.0.0.0/8',\ + '178.0.0.0/8','179.0.0.0/8','180.0.0.0/8','181.0.0.0/8','182.0.0.0/8',\ + '183.0.0.0/8','184.0.0.0/8','185.0.0.0/8','186.0.0.0/8','187.0.0.0/8',\ + '189.0.0.0/8','190.0.0.0/8','192.168.0.0/16','197.0.0.0/8','223.0.0.0/8',\ + '224.0.0.0/4','240.0.0.0/4'] + + ports_virus = { 'tcp' : [ 135, 445 ] , 'udp' : [] } + def __init__(self): + self.db = crans_ldap() self.file_log=open("/var/log/fw.log","a") def __del__(self): self.file_log.close() + + def start(self) : + """ Construction du firewall """ + # On commence sur de bonnes bases + self.stop() - def iptables(self,cmd): - status,output=getstatusoutput(cmd) - if status: - raise IptablesError(cmd,status,output) - self.file_log.write(time.time+": "+cmd) - return output - - def __base(self) : - """ Construction de PREROUTING et FORWARD""" - anim('\t Construction base firewall') - # table nat - for chaine in [ 'TEST_VIRUS' , 'EXT_VERS_SERVEURS', 'SERVEURS_VERS_EXT' , 'EXT_VERS_CRANS', 'TESTS_MAC-IP_FLOOD' , 'RESEAUX_NON_ROUTABLES_SRC', 'RESEAUX_NON_ROUTABLES_DST', 'TEST_FLOOD'] : + cprint('Démarrage firewall','gras') + + anim('\tConstruction structure de la table nat') + for chaine in [ 'TEST_VIRUS' , 'TESTS_MAC-IP_FLOOD' , 'RESEAUX_NON_ROUTABLES_SRC', 'RESEAUX_NON_ROUTABLES_DST', 'TEST_FLOOD'] : iptables('-t nat -N %s' % chaine) iptables("-t nat -P PREROUTING ACCEPT") + iptables("-t nat -i lo -j ACCEPT") iptables("-t nat -A PREROUTING -j TEST_VIRUS") iptables("-t nat -A PREROUTING -j RESEAUX_NON_ROUTABLES_DST") iptables("-t nat -A PREROUTING -i %s -j RESEAUX_NON_ROUTABLES_SRC" % self.eth_ext ) @@ -140,29 +166,49 @@ class firewall: iptables("-t nat -A PREROUTING -s %s -j ACCEPT" % self.zone_serveur ) iptables("-t nat -A PREROUTING -i %s -j ACCPET" % self.eth_ext ) iptables("-t nat -A PREROUTING -j TESTS_MAC-IP_FLOOD") - - # table filter - for chaine in [ 'BLACKLIST_OUTPUT', 'BLACKLIST_INPUT' ] : + print OK + + anim('\tConstruction structure de la table filter') + for chaine in [ 'EXT_VERS_SERVEURS', 'SERVEURS_VERS_EXT' , 'EXT_VERS_CRANS', 'CRANS_VERS_EXT', 'BLACKLIST_SRC', 'BLACKLIST_DST' ] : iptables('-N %s' % chaine) - for reseau in config.NETs['all'] : - iptables("-A FORWARD -s %s -j BLACKLIST_DST" % reseau ) - iptables("-A FORWARD -d %s -j BLACKLIST_SRC" % reseau ) - iptables("-A FORWARD -d %s -j EXT_VERS_SERVEURS" % self.zone_serveur ) - iptables("-A FORWARD -s %s -j SERVEURS_VERS_EXT" % self.zone_serveur ) + iptables("-A FORWARD -i %s -j BLACKLIST_DST" % self.eth_ext ) + iptables("-A FORWARD -o %s -j BLACKLIST_SRC" % self.eth_ext ) + iptables("-A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT") + iptables("-A FORWARD -i %s -d %s -j EXT_VERS_SERVEURS" % (self.eth_ext, proto, self.zone_serveur) ) + iptables("-A FORWARD -o %s -s %s -j SERVEURS_VERS_EXT" % (self.eth_ext, proto, self.zone_serveur) ) iptables("-A FORWARD -i %s -j EXT_VERS_CRANS" % self.eth_ext ) - + iptables("-A FORWARD -o %s -j CRANS_VERS_EXT" % self.eth_ext ) + print OK + + self.log_chaines() + self.test_virus() + self.reseaux_non_routables() + self.blacklist() + + for machine in self.db.search('ip=*')['machine'] : + add_machine(machine) + + # Opérations finales + anim('\tFinalisation') + for chaine in [ 'EXT_VERS_SERVEURS', 'SERVEURS_VERS_EXT' , 'EXT_VERS_CRANS' , 'CRANS_VERS_EXT'] : + iptables('-A %s -j REJECT' % chaine) + print OK + def log_chaines(self) : """ Construction des chaines de log (LOG_VIRUS et LOG_FLOOD) """ - for filtre in [ 'VIRUS', 'FLOOD' ] : + self.anim = anim('\tCréation des chaines de log',len(self.reseaux_non_routables)) + for filtre in [ 'VIRUS', 'FLOOD' ] : # Vidage de la chaîne iptables('-F LOG_%s' % filtre) iptables('-t nat -A LOG_%s %s %s:' % (filtre, self.log_template, filtre.capitalize()) ) iptables('-t nat -A LOG_%s -j DROP' % filtre ) - + self.anim.cycle() + print OK + def reseaux_non_routables(self) : """ Construction de RESEAUX_NON_ROUTABLES_{DST,SRC} """ - self.anim = anim('\t Filtrage ip non routables',len(self.reseaux_non_routables)) + self.anim = anim('\tFiltrage ip non routables',len(self.reseaux_non_routables)) for reseau in self.reseaux_non_routables : iptables("-t nat -A RESEAUX_NON_ROUTABLES_DST -d %s -j DROP" % reseau) iptables("-t nat -A RESEAUX_NON_ROUTABLES_SRC -s %s -j DROP" % reseau) @@ -173,24 +219,13 @@ class firewall: def test_virus(self) : """ Construction de la chaîne TEST_VIRUS """ iptables('-t nat -F TEST_VIRUS') - self.anim = anim('\t Filtrage virus',len(self.ports_virus)) - for port in self.ports_virus : - iptables('-t nat -A TEST_VIRUS -p tcp --dport %s -j LOG_VIRUS' % port) + self.anim = anim('\tFiltrage virus',len(self.ports_virus.keys())) + for proto, ports in self.ports_virus.items() : + iptables('-t nat -A TEST_VIRUS -p %s --dport %s -j LOG_VIRUS' % (proto, port) ) self.anim.cycle() self.anim.reinit() print OK - - def start(self): - """ - Construit le firewall - Pas d'arguments - """ - self.filtrage_mac() - self.create_forward() - self.blacklist() - self.create_adherents() - def stop(self): """ Arrête le firewall @@ -201,13 +236,13 @@ class firewall: iptables("iptables -t nat -F") iptables("iptables -X") - def add_machines(self,machine): - __test_mac_ip_flood(machine) - __test_flood(machine) - __serveurs_vers_ext__(machine) - __ext_vers_serveurs__(machine) - __crans_vers_ext__(machine) - __ext_vers_crans__(machine) + def add_machine(self,machine): + self.__test_mac_ip_flood(machine) + self.__test_flood(machine) + self.__serveurs_vers_ext(machine) + self.__ext_vers_serveurs(machine) + self.__crans_vers_ext(machine) + self.__ext_vers_crans(machine) def __serveurs_vers_ext(self,machine): ip=machine.ip() @@ -221,7 +256,7 @@ class firewall: "%s -p udp --dport %s -j ACCEPT"\ %(ip,i)) - def __ext_vers_serveurs__(self,machine): + def __ext_vers_serveurs(self,machine): ip=machine.ip() if AddrInNet(ip,self.zone_serveur): for i in machine.portTCPin().split(): @@ -233,51 +268,32 @@ class firewall: "-s %s -p udp --dport %s -j ACCEPT"\ %(ip,i)) - def __crans_vers_ext__(self,machine): + def __crans_vers_ext(self,machine): ip=machine.ip() - if not AddrInNet(ip,self.zone_serveur): - if machine.portTCPin(): - for i in machine.portTCPin().split(): - iptables("-t filter -I CRANS_VERS_EXT -d "+\ - "%s -p tcp --dport %s -j ACCEPT"\ - %(ip,i)) - else: - for i in self.ports_default["tcp_input"]: - iptables("-I CRANS_VERS_EXT -p tcp --dport "+\ - "%s -j ACCEPT"%i) - if machine.portUDPin(): - for i in machine.portUDPin().split(): - iptables("-t filter -I CRANS_VERS_EXT -d "+\ - "%s -p udp --dport %s -j ACCEPT"\ - %(ip,i)) - else: - for i in self.ports_default["udp_input"]: - iptables("-I CRANS_VERS_EXT -p udp --dport "+\ - "%s -j ACCEPT"%i) + if AddrInNet(ip,self.zone_serveur): + return + + ports = { 'tcp' : machine.portTCPin(), + 'udp' : machine.portUDPin() } + + for proto in [ 'tcp', 'udp' ] : + for port in ports[proto] + self.ports_default["%s_input" % proto ] : + iptables("-I CRANS_VERS_EXT -s %s -p %s --dport %s -j ACCEPT" \ + %(ip,proto,port)) - def __ext_vers_crans__(self,machine): + def __ext_vers_crans(self,machine): ip=machine.ip() - if not AddrInNet(ip,self.zone_serveur): - if machine.portTCPout(): - for i in machine.portTCPout().split(): - iptables("-t filter -I EXT_VERS_CRANS -d "+\ - "%s -p tcp --dport %s -j ACCEPT"\ - %(ip,i)) - else: - for i in self.ports_default["tcp_output"]: - iptables("-I EXT_VERS_CRANS -p tcp --dport "+\ - "%s -j ACCEPT"%i) - if machine.portUDPout(): - for i in machine.portUDPout().split(): - iptables("-t filter -I EXT_VERS_CRANS -d "+\ - "%s -p udp --dport %s -j ACCEPT"\ - %(ip,i)) - else: - for i in self.ports_default["udp_output"]: - iptables("-I EXT_VERS_CRANS -p udp --dport "+\ - "%s -j ACCEPT"%i) - - + if AddrInNet(ip,self.zone_serveur): + return + + ports = { 'tcp' : machine.portTCPout(), + 'udp' : machine.portUDPout() } + + for proto in [ 'tcp', 'udp' ] : + for port in ports[proto] + self.ports_default["%s_output" % proto ] : + iptables("-I EXT_VERS_CRANS -d %s -p %s --dport %s -j ACCEPT" \ + %(ip,proto,port)) + def __test_mac_ip_flood(machine): ip=machine.ip() mac=machine.mac() @@ -298,191 +314,44 @@ class firewall: else: iptables("-t nat -A PREROUTING -s "+\ "%s -m mac --mac-source %s -j LOG_FLOOD"%(ip,mac)) - - def del_entree(self,ip): - """ - Détruit une entrée dans le firewall - Note: Il faut *os.systemer lourdement* cette fonction. - Ce serait pas mal de factoriser par ici, mais de toute façon la - méthode ne me plaît pas du tout. - """ - try: - os.system("iptables -L -n > /tmp/firewall") - except: - print "Impossible de créer le fichier d'états /tmp/firewall" - exit() - chaines=[] - count=0 - for line in fileinput.input('/tmp/firewall'): - count=count+1 - if "Chain" in line: - tmp=line.split(' ') - chaine=tmp[1] - count=0 - if ip in line: - count=count-1 - iptables("iptables -D %s %i"%(chaine,count)) - os.system("rm -f /tmp/firewall") - try: - os.system("iptables -t nat -L -n > /tmp/firewall") - except: - print "Impossible de créer le fichier d'états /tmp/firewall" - exit() - chaines=[] - count=0 - for line in fileinput.input('/tmp/firewall'): - count=count+1 - if "Chain" in line: - tmp=line.split(' ') - chaine=tmp[1] - count=0 - if ip in line: - count=count-1 - iptables("iptables -t nat -D %s %i"%(chaine,count)) - os.system("rm -f /tmp/firewall") - - - def filtrage_mac(self): - """ - Crée tout le routage sur la chaîne PREROUTING - """ - db=crans_ldap() - search=db.search('host!=*.wifi.crans.org')['machine'] - barre=anim("Filtrage mac-ip des machines fixes.",len(search)) - for i in range(0,len(search)): - self.paire_macip(search[i].ip(),search[i].mac()) - barre.cycle() - barre.reinit() - print OK - search=db.search('host=*.wifi.crans.org')['machine'] - - barre=anim("Filtrage mac-ip des machines wifi.",len(search)) - for i in range(0,len(search)): - self.paire_macip(search[i].ip(),'00:0c:f1:fa:f1:4b') - barre.cycle() - barre.reinit() - print OK - - iptables("iptables -t nat -A PREROUTING -i %s -s \\!"%int_crans+\ - " 138.231.136.0/21 -j ACCEPT") - iptables("iptables -t nat -A PREROUTING -i %s -s \\!"%int_crans+\ - " 138.231.148.0/22 -j ACCEPT") - for i in reseaux_non_routables: - iptables("iptables -t nat -A PREROUTING -i %s -s %s"%(int_crans,i)+\ - " -m limit --limit %s --limit-burst %s"%(loglimit,logburst)+\ - " -j LOG --log-level %s --log-prefix %s"%\ - (loglevel,logprefix_macip)) - iptables("iptables -t nat -A PREROUTING -i %s -s %s -j DROP"%\ - (int_crans,i)) - iptables("iptables -t nat -A PREROUTING -i %s -d %s"%(int_crans,i)+\ - " -m limit --limit %s --limit-burst %s"%(loglimit,logburst)+\ - " -j LOG --log-level %s --log-prefix %s"%\ - (loglevel,logprefix_macip)) - iptables("iptables -t nat -A PREROUTING -i %s -d %s -j DROP"%\ - (int_crans,i)) - iptables("iptables -t nat -A PREROUTING -i %s -p tcp "%int_crans+\ - " -m limit --limit %s --limit-burst %s"%(loglimit,logburst)+\ - " -j LOG --log-level %s --log-prefix %s"%\ - (loglevel,logprefix_macip)) - iptables("iptables -t nat -A PREROUTING -i %s -p tcp"%int_crans+\ - " -j DROP") - iptables("iptables -t nat -A PREROUTING -i %s -p udp"%int_crans+\ - " -m limit --limit %s --limit-burst %s"%(loglimit,logburst)+\ - " -j LOG --log-level %s --log-prefix %s"%\ - (loglevel,logprefix_macip)) - iptables("iptables -t nat -A PREROUTING -i %s -p udp"%int_crans+\ - " -j DROP") - def blacklist(self): - """ - Bloque les adhérents blacklistés - """ - - db=crans_ldap() + """ Construit les chaines de blackliste (BLACKLIST_{DST,SRC}) """ + anim("\tContruction blacklist") + iptables('-F BLACKLIST_DST') + iptables('-F BLACKLIST_SRC') + blacklist=[] - search=db.search('blacklist=*&paiement=%s'%ann_scol) - for entite in search['adherent']+\ - search['club']+search['machine']: - if 'upload' in entite.blacklist_actif(): + search=self.db.search('blacklist=*&paiement=%s'%ann_scol) + for entite in search['adherent']+search['club']+search['machine']: + sanctions = entite.blacklist_actif() + if 'upload' in sanctions or 'warez' in sanctions : if search.__class__==machine: blacklist+=[entite] else: blacklist+=entite.machines() - for instance_machine in blacklist: - iptables("iptables -A BLACKLIST_INPUT -d %s"%\ - instance_machine.ip().encode("iso-8859-15")+\ - "-m limit --limit %s --limit-burst %s"%(loglimit,logburst)+\ - " -j LOG --log-level %s --log-prefix_macip %s"%\ - (loglevel,logprefix_blacklist)) - iptables("iptables -A BLACKLIST_INPUT -d %s -j REJECT"%\ - instance_machine.ip()) - iptables("iptables -A BLACKLIST_OUTPUT -s %s"%\ - instance_machine.ip().encode("iso-8859-15")+\ - "-m limit --limit %s --limit-burst %s"%(loglimit,logburst)+\ - " -j LOG --log-level %s --log-prefix_macip %s"%\ - (loglevel,logprefix_blacklist)) - iptables("iptables -A BLACKLIST_OUTPUT -s %s -j REJECT"%\ - instance_machine.ip()) - iptables("iptables -A BLACKLIST_INPUT -j EXT_VERS_CRANS") - iptables("iptables -A BLACKLIST_OUTPUT -j CRANS_VERS_EXT") - - - def create_adherents(self): - """ - Crée toutes les règles relatives aux adhérents ayant des règles - spéciales - """ - iptables("iptables -N ADHERENTS_OUTPUT") - iptables("iptables -N ADHERENTS_INPUT") - - iptables("iptables -A ADHERENTS_INPUT -m state --state "+\ - "RELATED -j ACCEPT") - iptables("iptables -A ADHERENTS_OUTPUT -m state --state "+\ - "RELATED -j ACCEPT") - iptables("iptables -A ADHERENTS_INPUT -m state --state "+\ - "ESTABLISHED -m limit --limit-burst "+\ - "%s -j ACCEPT"%limite_connexion) - iptables("iptables -A ADHERENTS_OUTPUT -m state --state "+\ - "ESTABLISHED -m limit --limit-burst "+\ - "%s -j ACCEPT"%limite_connexion) - iptables("iptables -A DEFAULT_INPUT -j ADHERENTS_INPUT") - iptables("iptables -A DEFAULT_OUTPUT -j ADHERENTS_OUTPUT") - - db=crans_ldap() - search=db.search('host=*.crans.org & portTCPin=*')['machine'] - for champ in search: - ports=champ.portTCPin() - for j in ports.split(' '): - iptables("iptables -A ADHERENTS_INPUT -d %s"%champ.ip()+\ - " -p tcp --dport %s -j ACCEPT"%j) - search=db.search('host=*.crans.org & portTCPout=*')['machine'] - for champ in search: - ports=champ.portTCPout() - for j in ports.split(' '): - iptables("iptables -A ADHERENTS_OUTPUT -d %s"%champ.ip()+\ - " -p tcp --dport %s -j ACCEPT"%j) - search=db.search('host=*.crans.org & portUDPin=*')['machine'] - for champ in search: - ports=champ.portUDPin() - for j in ports.split(' '): - iptables("iptables -A ADHERENTS_INPUT -d %s"%champ.ip()+\ - " -p udp --dport %s -j ACCEPT"%j) - search=db.search('host=*.crans.org & portUDPin=*')['machine'] - for champ in search: - ports=champ.portUDPout() - for j in ports.split(' '): - iptables("iptables -A ADHERENTS_OUTPUT -d %s"%champ.ip()+\ - " -p udp --dport %s -j ACCEPT"%j) - iptables("iptables -A ADHERENTS_INPUT"+\ - " -m limit --limit %s --limit-burst %s"%(loglimit,logburst)+\ - " -j LOG --log-level %s --log-prefix %s"%\ - (loglevel,logprefix_adherents)) - iptables("iptables -A ADHERENTS_INPUT -j REJECT") - iptables("iptables -A ADHERENTS_OUTPUT"+\ - " -m limit --limit %s --limit-burst %s"%(loglimit,logburst)+\ - " -j LOG --log-level %s --log-prefix %s"%\ - (loglevel,logprefix_adherents)) - iptables("iptables -A ADHERENTS_OUTPUT -j REJECT") - - + + for machine in blacklist: + iptables("-A BLACKLIST_DST -d %s -j REJECT" % machine.ip()) + iptables("-A BLACKLIST_SRC -s %s -j REJECT" % machine.ip()) + + print OK + + def del_entree(self,ip): + """ Détruit toutes les occurences à l'IP dans le firewall """ + for table in [ 'filter' , 'nat' ] : + for chaine in iptables("-t %s -L -n --line-numbers" % table).split('Chain ') : + nom_chaine = chaine.split(' ',1)[0] + to_del=[] + for regle in chaine.split('\n')[1:] : + # On regarde les règles une à une + regle = regle.split() + if ip in regle : + # Règle à dértuire + to_del.append(int(regle[0])) + # Destruction des règles de cette chaîne + to_del.sort() + to_del.reverse() + for i in to_del : + iptables('-t %s -D %s %s' % (table, nom_chaine, i) ) +