
Celui de komaz et le pare-feu générique (mac-ip et blacklist) sont fonctionnel, il ne manque que la limitation de débit et la QoS pour komaz
757 lines
No EOL
28 KiB
Python
Executable file
757 lines
No EOL
28 KiB
Python
Executable file
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
|
|
import sys
|
|
import os
|
|
sys.path.append('/usr/scripts/gestion')
|
|
sys.path.append('/usr/scripts/lc_ldap')
|
|
|
|
from config import NETs, blacklist_sanctions, blacklist_sanctions_soft, mac_komaz, mac_titanic
|
|
|
|
import config.firewall
|
|
import lc_ldap
|
|
import socket
|
|
from ipset import IpsetError, Ipset
|
|
from iptools import AddrInNet, NetSubnets, IpSubnet, NetInNets
|
|
import subprocess
|
|
from affich_tools import *
|
|
|
|
squeeze = os.uname()[2] < '3'
|
|
|
|
conn = lc_ldap.lc_ldap_admin()
|
|
hostname = socket.gethostname()
|
|
|
|
default_chains = ['INPUT', 'OUTPUT', 'FORWARD', 'PREROUTING', 'POSTROUTING']
|
|
tables = ['raw', 'mangle', 'filter', 'nat']
|
|
|
|
dev = hostname in config.firewall.dev.keys() and config.firewall.dev[hostname] or {}
|
|
|
|
def pretty_print(table, chain):
|
|
anim('\t%s dans %s' % (chain, table))
|
|
|
|
class firewall_base(object) :
|
|
|
|
def machines(self):
|
|
if self._machines:
|
|
return self._machines
|
|
self._machines, self._adherents = conn.allMachinesAdherents()
|
|
return self._machines
|
|
|
|
def adherents(self):
|
|
if self._adherents:
|
|
return self._adherents
|
|
self._machines, self._adherents = conn.allMachinesAdherents()
|
|
self._adherents = [ adh for adh in self._adherents if adh.paiement_ok ]
|
|
return self._adherents
|
|
|
|
def blacklisted_machines(self):
|
|
if self._blacklisted_machines:
|
|
return self._blacklisted_machines
|
|
if self._machines:
|
|
self._blacklisted_machines = [ machine for machine in self._machines if machine.blacklist_actif() ]
|
|
return self._blacklisted_machines
|
|
blacklisted = [ machine for machine in conn.search("blacklist=*",sizelimit=4096) if machine.blacklist_actif() ]
|
|
self._blacklisted_machines = set()
|
|
for item in blacklisted:
|
|
if isinstance(item, lc_ldap.proprio):
|
|
self._blacklisted_machines = self._blacklisted_machines.union(item.machines())
|
|
elif isinstance(item, lc_ldap.machine):
|
|
self._blacklisted_machines.add(item)
|
|
else:
|
|
print >> sys.stderr, 'Objet %s inconnu blacklisté' % a.__class__.__name__
|
|
return self._blacklisted_machines
|
|
|
|
def add(self, table, chain, rule):
|
|
if not chain in self.chain_list[table]:
|
|
self.chain_list[table].append(chain)
|
|
self.rules_list[table][chain]=[]
|
|
self.rules_list[table][chain].append(rule)
|
|
|
|
def delete(self, table=None, chain=None):
|
|
if not table:
|
|
for table in tables:
|
|
self.delete(table, chain)
|
|
if not chain:
|
|
for chain in self.chain_list[table]:
|
|
self.delete(table, chain)
|
|
self.clear(table, chain)
|
|
|
|
def flush(self, table=None, chain=None):
|
|
if not table:
|
|
for table in tables:
|
|
self.flush(table, chain)
|
|
if not chain:
|
|
for chain in self.chain_list[table]:
|
|
self.flush(table, chain)
|
|
self.clear(table, chain)
|
|
self.chain_list[table].append(chain)
|
|
self.rules_list[table][chain]=[]
|
|
|
|
def clear(self, table, chain):
|
|
if not chain in self.chain_list[table]:
|
|
return
|
|
if not chain in default_chains:
|
|
self.chain_list[table].remove(chain)
|
|
del(self.rules_list[table][chain])
|
|
else:
|
|
self.rules_list[table][chain]=[]
|
|
|
|
def restore(self, noflush=False, table=None, chains=[]):
|
|
str=self.format(chains)
|
|
f=open('/tmp/ipt_rules', 'w')
|
|
f.write(str)
|
|
f.close()
|
|
params = ['/sbin/iptables-restore']
|
|
if noflush:
|
|
params.append('--noflush')
|
|
if table and table in ['raw', 'mangle', 'filter', 'nat']:
|
|
params.append('--table')
|
|
params.append(table)
|
|
p = subprocess.Popen(params , stdin=subprocess.PIPE)
|
|
p.communicate(input=str)
|
|
|
|
def apply(self, table, chain):
|
|
if not chain in self.chain_list[table]:
|
|
return
|
|
|
|
str = self.format([chain])
|
|
# TODO
|
|
|
|
self.clear(table, chain)
|
|
|
|
def format(self, chains=[]):
|
|
str = ''
|
|
for table in self.chain_list.keys():
|
|
str += '*%s\n' % table
|
|
for chain in self.chain_list[table]:
|
|
if not chains or chain in chains or chain in default_chains:
|
|
str += ':%s %s [0:0]\n' % (chain, chain in default_chains and 'ACCEPT' or '-')
|
|
for chain in self.chain_list[table]:
|
|
if not chains or chain in chains :
|
|
for rule in self.rules_list[table][chain]:
|
|
str += '-A %s %s\n' % (chain, rule)
|
|
self.clear(table, chain)
|
|
str += 'COMMIT\n'
|
|
return str
|
|
|
|
def __init__(self):
|
|
#initialisation des structures communes : récupération des ipset
|
|
|
|
self.reloadable = {
|
|
'blacklist_hard' : self.blacklist_hard,
|
|
'test_mac_ip' : self.test_mac_ip,
|
|
}
|
|
|
|
self.use_ipset = [self.blacklist_hard, self.test_mac_ip]
|
|
|
|
self._machines = None
|
|
self._adherents = None
|
|
self._blacklisted_machines = None
|
|
|
|
self.chain_list={
|
|
'raw':['OUTPUT', 'PREROUTING'],
|
|
'mangle':['INPUT', 'OUTPUT', 'FORWARD', 'PREROUTING', 'POSTROUTING'],
|
|
'filter':['INPUT', 'OUTPUT', 'FORWARD'],
|
|
'nat':['OUTPUT', 'PREROUTING', 'POSTROUTING']
|
|
}
|
|
self.rules_list = {
|
|
'raw': { 'OUTPUT':[], 'PREROUTING':[] },
|
|
'mangle':{'INPUT':[], 'OUTPUT':[], 'FORWARD':[], 'PREROUTING':[], 'POSTROUTING':[]},
|
|
'filter':{'INPUT':[], 'OUTPUT':[], 'FORWARD':[]},
|
|
'nat':{'OUTPUT':[], 'PREROUTING':[], 'POSTROUTING':[]}
|
|
}
|
|
|
|
self.ipset={}
|
|
|
|
self.ipset['mac_ip']={
|
|
'adh' : Ipset("MAC-IP-ADH","macipmap","--from 138.231.136.0 --to 138.231.151.255"),
|
|
'adm' : Ipset("MAC-IP-ADM","macipmap","--from 10.231.136.0 --to 10.231.136.255"),
|
|
'app' : Ipset("MAC-IP-APP","macipmap","--from 10.2.9.0 --to 10.2.9.255"),
|
|
}
|
|
|
|
self.ipset['blacklist']={
|
|
'soft' : Ipset("BLACKLIST-SOFT","ipmap","--from 138.231.136.0 --to 138.231.151.255"),
|
|
'hard' : Ipset("BLACKLIST-HARD","ipmap","--from 138.231.136.0 --to 138.231.151.255"),
|
|
}
|
|
|
|
|
|
|
|
def start(self):
|
|
# On precache avant tout la liste des machines et des adhérents, on en aura besoin
|
|
anim('\tChargement des machines')
|
|
self.machines()
|
|
print OK
|
|
|
|
if squeeze:
|
|
anim('\tVidage du pare-feu')
|
|
fw.restore()
|
|
print OK
|
|
|
|
self.raw_table()
|
|
self.mangle_table()
|
|
self.filter_table()
|
|
self.nat_table()
|
|
|
|
anim('\tRestoration d\'iptables')
|
|
fw.restore()
|
|
print OK
|
|
return
|
|
|
|
def stop(self):
|
|
|
|
fw.delete()
|
|
fw.restore()
|
|
return
|
|
|
|
def restart(self):
|
|
self.start()
|
|
return
|
|
|
|
|
|
def raw_table(self):
|
|
table = 'raw'
|
|
return
|
|
|
|
def mangle_table(self):
|
|
table = 'mangle'
|
|
return
|
|
|
|
def filter_table(self):
|
|
table = 'filter'
|
|
|
|
mac_ip_chain = self.test_mac_ip(table, fill_ipset=True)
|
|
blacklist_hard_chain = self.blacklist_hard(table, fill_ipset=True)
|
|
|
|
chain = 'INPUT'
|
|
self.add(table, chain, '-i lo -j ACCEPT')
|
|
self.add(table, chain, '-p icmp -j ACCEPT')
|
|
self.add(table, chain, '-m state --state RELATED,ESTABLISHED -j ACCEPT')
|
|
for net in NETs['all'] + NETs['adm'] + NETs['personnel-ens']:
|
|
self.add(table, chain, '-s %s -j %s' % (net, mac_ip_chain))
|
|
self.add(table, chain, '-j %s' % blacklist_hard_chain)
|
|
|
|
chain = 'FORWARD'
|
|
self.add(table, chain, '-j REJECT')
|
|
|
|
return
|
|
|
|
def nat_table(self):
|
|
table = 'nat'
|
|
return
|
|
|
|
|
|
|
|
|
|
def blacklist_hard_maj(self, ip_list):
|
|
for ip in ip_list:
|
|
machine = db.search("ipHostNumber=%s" % ip)
|
|
# Est-ce qu'il y a des blacklists hard parmis les blacklists de la machine
|
|
if set([bl.value['type'] for bl in machine.blacklist_actif() ]).intersection(blacklist_sanctions):
|
|
try: self.ipset['blacklist']['hard'].add(ip)
|
|
except IpsetError: pass
|
|
else:
|
|
try: self.ipset['blacklist']['hard'].delete(ip)
|
|
except IpsetError: pass
|
|
|
|
def blacklist_hard(self, table=None, fill_ipset=False, apply=False):
|
|
chain = 'BLACKLIST_HARD'
|
|
|
|
if fill_ipset:
|
|
anim('\tRestoration de l\'ipset %s' % self.ipset['blacklist']['hard'])
|
|
# On récupère la liste de toutes les ips blacklistés hard
|
|
bl_hard_ips = set(
|
|
str(ip) for ips in
|
|
[
|
|
machine['ipHostNumber'] for machine in self.blacklisted_machines()
|
|
if set([bl.value['type'] for bl in machine.blacklist_actif() ]).intersection(blacklist_sanctions)
|
|
]
|
|
for ip in ips
|
|
)
|
|
|
|
self.ipset['blacklist']['hard'].restore(bl_hard_ips)
|
|
print OK
|
|
|
|
if table == 'filter':
|
|
pretty_print(table, chain)
|
|
self.add(table, chain, '-m set --match-set %s src -j REJECT' % self.ipset['blacklist']['hard'] )
|
|
self.add(table, chain, '-m set --match-set %s dst -j REJECT' % self.ipset['blacklist']['hard'] )
|
|
print OK
|
|
|
|
if apply:
|
|
self.apply(table, chain)
|
|
return chain
|
|
|
|
def test_mac_ip_dispatch(self, func, machine):
|
|
"""Détermine à quel set de mac-ip appliquer la fonction func (add, delete, append, ...)"""
|
|
ips = machine['ipHostNumber']
|
|
for ip in ips:
|
|
# Si la machines est sur le réseau des adhérents
|
|
if AddrInNet(str(ip), NETs['wifi']):
|
|
# Komaz voit directement les machines wifi
|
|
if hostname == 'komaz':
|
|
func('adh', "%s,%s" % (ip, machine['macAddress'][0]))
|
|
# Les autres serveurs les voient à travers komaz
|
|
else:
|
|
func('adh', "%s,%s" % (ip, mac_komaz))
|
|
elif AddrInNet(str(ip), NETs['fil']):
|
|
func('adh', "%s,%s" % (ip, machine['macAddress'][0]))
|
|
# Si la machine est sur le réseau admin
|
|
elif AddrInNet(str(ip), NETs['adm']):
|
|
func('adm', "%s,%s" % (ip, machine['macAddress'][0]))
|
|
# Si la machine est sur le réseaux des appartements de l'ENS
|
|
elif AddrInNet(str(ip), NETs['personnel-ens']):
|
|
# Les machines sont natter derrire komaz
|
|
if hostname == 'komaz':
|
|
func('app', "%s,%s" % (ip, machine['macAddress'][0]))
|
|
|
|
def test_mac_ip(self, table=None, fill_ipset=False, apply=False):
|
|
chain = 'TEST_MAC-IP'
|
|
|
|
if fill_ipset:
|
|
anim('\tRestoration des ipsets %s' % ', '.join(self.ipset['mac_ip'].keys()))
|
|
rules={
|
|
'adh':[],
|
|
'adm':[],
|
|
'app':[],
|
|
}
|
|
for machine in self.machines():
|
|
self.test_mac_ip_dispatch(lambda set, data: rules[set].append(data), machine)
|
|
|
|
for set,rules in rules.items():
|
|
self.ipset['mac_ip'][set].restore(rules)
|
|
print OK
|
|
|
|
if table == 'filter':
|
|
pretty_print(table, chain)
|
|
if hostname == 'komaz':
|
|
for key in ['out', 'tun-ovh' ]:
|
|
self.add(table, chain, '-i %s -j RETURN' % dev[key])
|
|
|
|
for key in ['accueil', 'isolement', ]:
|
|
for net in NETs[key]:
|
|
self.add(table, chain, '-s %s -j RETURN' % net)
|
|
for key in self.ipset['mac_ip'].keys():
|
|
self.add(table, chain, '-m set --match-set %s src,src -j RETURN' % self.ipset['mac_ip'][key])
|
|
|
|
# Proxy ARP de Komaz et Titanic pour OVH
|
|
ip_ovh = conn.search("host=ovh.adm.crans.org")[0]['ipHostNumber'][0]
|
|
self.add(table, chain, '-m mac -s %s --mac-source %s -j RETURN' % (ip_ovh, mac_komaz))
|
|
self.add(table, chain, '-m mac -s %s --mac-source %s -j RETURN' % (ip_ovh, mac_titanic))
|
|
|
|
self.add(table, chain, '-j REJECT')
|
|
print OK
|
|
|
|
if apply:
|
|
self.apply(table, chain)
|
|
return chain
|
|
|
|
def mac_ip_maj(self, ip_list):
|
|
for ip in ip_list:
|
|
machine = db.search("ipHostNumber=%s" % ip)
|
|
if machine:
|
|
try: test_mac_ip_dispatch(lambda set, data: self.ipset['mac_ip'][set].add(data), machine)
|
|
except IpsetError: pass
|
|
else:
|
|
try: test_mac_ip_dispatch(lambda set, data: self.ipset['mac_ip'][set].delete(data), machine)
|
|
except IpsetError: pass
|
|
|
|
|
|
class firewall_komaz(firewall_base):
|
|
|
|
def __init__(self):
|
|
super(self.__class__, self).__init__()
|
|
|
|
self.reloadable.update({
|
|
'log_all' : self.log_all,
|
|
'admin_vlan' : self.admin_vlan,
|
|
'clamp_mss' : self.clamp_mss,
|
|
'ingress_filtering' : self.ingress_filtering,
|
|
'ssh_on_https' : self.ssh_on_https,
|
|
'connexion_secours' : self.connexion_secours,
|
|
'connexion_appartement' : self.connexion_appartement,
|
|
'blacklist_soft' : self.blacklist_soft,
|
|
'reseaux_non_routable' : self.reseaux_non_routable,
|
|
'filtrage_ports' : self.filtrage_ports,
|
|
})
|
|
|
|
self.use_ipset.extend([self.blacklist_soft, self.reseaux_non_routable])
|
|
|
|
self.ipset['reseaux_non_routable'] = {
|
|
'deny' : Ipset("RESEAUX-NON-ROUTABLE-DENY","nethash"),
|
|
'allow' : Ipset("RESEAUX-NON-ROUTABLE-ALLOW","nethash"),
|
|
}
|
|
|
|
def raw_table(self):
|
|
return
|
|
|
|
def mangle_table(self):
|
|
table = 'mangle'
|
|
super(self.__class__, self).mangle_table()
|
|
|
|
chain = 'PREROUTING'
|
|
self.add(table, chain, '-j %s' % self.log_all(table))
|
|
self.add(table, chain, '-j %s' % self.blacklist_soft(table, fill_ipset=True))
|
|
self.add(table, chain, '-j %s' % self.connexion_secours(table))
|
|
self.add(table, chain, '-p tcp -j CONNMARK --restore-mark')
|
|
|
|
chain = 'POSTROUNTING'
|
|
self.add(table, chain, '-j %s' % self.clamp_mss(table))
|
|
#TODO QoS
|
|
return
|
|
|
|
def filter_table(self):
|
|
table = 'filter'
|
|
super(self.__class__, self).filter_table()
|
|
|
|
mac_ip_chain = self.test_mac_ip()
|
|
blacklist_hard_chain = self.blacklist_hard()
|
|
|
|
chain = 'FORWARD'
|
|
self.clear(table, chain)
|
|
self.add(table, chain, '-i lo -j ACCEPT')
|
|
self.add(table, chain, '-p icmp -j ACCEPT')
|
|
self.add(table, chain, '-j %s' % self.admin_vlan(table))
|
|
self.add(table, chain, '-m state --state RELATED,ESTABLISHED -j ACCEPT')
|
|
self.add(table, chain, '-j %s' % self.reseaux_non_routable(table, fill_ipset=True))
|
|
self.add(table, chain, '-j %s' % self.blacklist_soft(table))
|
|
for net in NETs['all'] + NETs['adm'] + NETs['personnel-ens']:
|
|
self.add(table, chain, '-s %s -j %s' % (net, mac_ip_chain))
|
|
self.add(table, chain, '-i %s -j %s' % (dev['out'], blacklist_hard_chain))
|
|
self.add(table, chain, '-o %s -j %s' % (dev['out'], blacklist_hard_chain))
|
|
self.add(table, chain, '-j %s' % self.connexion_secours(table))
|
|
self.add(table, chain, '-j %s' % self.connexion_appartement(table))
|
|
self.add(table, chain, '-j %s' % self.ingress_filtering(table))
|
|
self.add(table, chain, '-j %s' % self.filtrage_ports(table))
|
|
return
|
|
|
|
def nat_table(self):
|
|
table = 'nat'
|
|
super(self.__class__, self).nat_table()
|
|
|
|
chain = 'PREROUTING'
|
|
self.add(table, chain, '-j %s' % self.ssh_on_https(table))
|
|
self.add(table, chain, '-j %s' % self.connexion_secours(table))
|
|
self.add(table, chain, '-j %s' % self.blacklist_soft(table))
|
|
|
|
chain = 'POSTROUTING'
|
|
self.add(table, chain, '-j %s' % self.connexion_appartement(table))
|
|
return
|
|
|
|
|
|
def log_all(self, table=None, apply=False):
|
|
chain = 'LOG_ALL'
|
|
|
|
if table == 'mangle':
|
|
pretty_print(table, chain)
|
|
for device in dev.values():
|
|
self.add(table, chain, '-i %s -m state --state NEW -j LOG --log-prefix "LOG_ALL "' % device)
|
|
print OK
|
|
|
|
if apply:
|
|
self.apply(table, chain)
|
|
return chain
|
|
|
|
def admin_vlan(self, table=None, apply=False):
|
|
chain = 'VLAN-ADM'
|
|
|
|
if table == 'filter':
|
|
pretty_print(table, chain)
|
|
for net in NETs['adm']:
|
|
self.add(table, chain, '-d %s -j REJECT' % net)
|
|
print OK
|
|
|
|
if apply:
|
|
self.apply(table, chain)
|
|
return chain
|
|
|
|
def qos(self, table=None, apply=False):
|
|
return
|
|
|
|
def clamp_mss(self, table=None, apply=False):
|
|
chain = 'CLAMP-MSS'
|
|
if table == 'mangle':
|
|
pretty_print(table, chain)
|
|
|
|
self.add(table, chain, '-p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu')
|
|
print OK
|
|
|
|
if apply:
|
|
self.apply(table, chain)
|
|
return chain
|
|
|
|
def ingress_filtering(self, table=None, apply=False):
|
|
"""
|
|
Pour ne pas router les paquêtes n'appartenant pas à notre plage ip voulant sortir de notre réseau
|
|
et empêcher certain type de spoof (cf http://travaux.ovh.net/?do=details&id=5183)
|
|
"""
|
|
chain = 'INGRESS_FILTERING'
|
|
if table == 'filter':
|
|
pretty_print(table, chain)
|
|
|
|
for net in NETs['all']:
|
|
self.add(table, chain, '-o %s -s %s -j RETURN' % (dev['out'], net))
|
|
self.add(table, chain, '-o %s -j LOG --log-prefix BAD_ROUTE' % dev['out'])
|
|
self.add(table, chain, '-o %s -j DROP' % dev['out'])
|
|
for net_d in NETs['all']:
|
|
for net_s in NETs['all']:
|
|
self.add(table, chain,'-i %s ! -s %s -d %s -j RETURN' % (dev['out'], net_s, net_d))
|
|
self.add(table, chain,'-i %s -j LOG --log-prefix BAD_SRC' % dev['out'])
|
|
self.add(table, chain,'-i %s -j DROP' % dev['out'])
|
|
print OK
|
|
|
|
if apply:
|
|
self.apply(table, chain)
|
|
return chain
|
|
|
|
def ssh_on_https(self, table=None, apply=False):
|
|
chain = 'SSH2'
|
|
|
|
if table == 'nat':
|
|
pretty_print(table, chain)
|
|
self.add(table, chain, '-p tcp -d 138.231.136.2 --dport 22 -j DNAT --to-destination 138.231.136.1:22') # redirection du ssh vers zamok
|
|
self.add(table, chain, '-p tcp -d 138.231.136.2 --dport 443 -j DNAT --to-destination 138.231.136.1:22') # redirection du ssh vers zamok (pour passer dans un proxy, avec corkscrew)
|
|
print OK
|
|
|
|
if apply:
|
|
self.apply(table, chain)
|
|
return chain
|
|
|
|
def connexion_secours(self, table=None, apply=False):
|
|
chain = 'CONNEXION-SECOURS'
|
|
|
|
if table == 'mangle':
|
|
pretty_print(table, chain)
|
|
self.add(table, chain, '-p tcp -s 138.231.136.0/16 ! -d 138.231.136.0/16 --destination-port 80 -m condition --condition secours -j MARK --set-mark %s' % (config.firewall.mark['secours']))
|
|
self.add(table, chain, '-m mark --mark %s -j ACCEPT' % config.firewall.mark['secours'])
|
|
print OK
|
|
|
|
if table == 'nat':
|
|
pretty_print(table, chain)
|
|
self.add(table, chain, '-p tcp -m mark --mark %s -j DNAT --to-destination 10.231.136.4:3129' % config.firewall.mark['secours'] )
|
|
print OK
|
|
|
|
if table == 'filter':
|
|
pretty_print(table, chain)
|
|
self.add(table, chain, '-p tcp -s 138.231.136.0/16 ! -d 138.231.136.0/16 --destination-port 443 -m condition --condition secours -j REJECT')
|
|
self.add(table, chain, '-m mark --mark %s -j ACCEPT' % config.firewall.mark['secours'])
|
|
print OK
|
|
|
|
if apply:
|
|
self.apply(table, chain)
|
|
return chain
|
|
|
|
def connexion_appartement(self, table=None, apply=False):
|
|
chain = 'CONNEXION-APPARTEMENT'
|
|
|
|
if table == 'nat':
|
|
pretty_print(table, chain)
|
|
for dev_key in ['out', 'fil', 'wifi']:
|
|
for net in NETs['personnel-ens']:
|
|
self.add(table, chain, '-o %s -s %s -j SNAT --to 138.231.136.44' % (dev[dev_key], net))
|
|
print OK
|
|
|
|
if table == 'filter':
|
|
pretty_print(table, chain)
|
|
for net in NETs['personnel-ens']:
|
|
self.add(table, chain, '-s %s -j ACCEPT' % net)
|
|
self.add(table, chain, '-d %s -j ACCEPT' % net)
|
|
print OK
|
|
|
|
if apply:
|
|
self.apply(table, chain)
|
|
return chain
|
|
|
|
def blacklist_soft_maj(self, ip_list):
|
|
for ip in ip_list:
|
|
machine = db.search("ipHostNumber=%s" % ip)
|
|
if not machine:
|
|
try: self.ipset['blacklist']['soft'].delete(ip)
|
|
except IpsetError: pass
|
|
else:
|
|
# Est-ce qu'il y a des blacklists soft parmis les blacklists de la machine
|
|
if set([bl.value['type'] for bl in machine.blacklist_actif() ]).intersection(blacklist_sanctions_soft):
|
|
try: self.ipset['blacklist']['soft'].add(ip)
|
|
except IpsetError: pass
|
|
else:
|
|
try: self.ipset['blacklist']['soft'].delete(ip)
|
|
except IpsetError: pass
|
|
|
|
def blacklist_soft(self, table=None, fill_ipset=False, apply=False):
|
|
chain = 'BLACKLIST_SOFT'
|
|
|
|
if fill_ipset:
|
|
anim('\tRestoration de l\'ipset %s' % self.ipset['blacklist']['soft'])
|
|
# On récupère la liste de toutes les ips blacklistés soft
|
|
bl_soft_ips = set(
|
|
str(ip) for ips in
|
|
[
|
|
machine['ipHostNumber'] for machine in self.blacklisted_machines()
|
|
if set([bl.value['type'] for bl in machine.blacklist_actif() ]).intersection(blacklist_sanctions_soft)
|
|
]
|
|
for ip in ips
|
|
)
|
|
|
|
self.ipset['blacklist']['soft'].restore(bl_soft_ips)
|
|
print OK
|
|
|
|
if table == 'mangle':
|
|
pretty_print(table, chain)
|
|
self.add(table, chain, '-p tcp ! --dport 80 -j RETURN')
|
|
self.add(table, chain, '! -p tcp -j RETURN')
|
|
for net in NETs['all']:
|
|
self.add(table, chain, '-d %s -j RETURN' % net)
|
|
self.add(table, chain, '-m set --match-set %s src -j MARK --set-mark %s'
|
|
% (self.ipset['blacklist']['soft'], config.firewall.mark['proxy']))
|
|
print OK
|
|
|
|
if table == 'filter':
|
|
pretty_print(table, chain)
|
|
self.add(table, chain, '-m mark --mark %s -j ACCEPT' % config.firewall.mark['proxy'])
|
|
print OK
|
|
|
|
if table == 'nat':
|
|
pretty_print(table, chain)
|
|
self.add(table, chain, '-p tcp -m mark --mark %s -j DNAT --to-destination 10.231.136.4:3128' % config.firewall.mark['proxy'] )
|
|
print OK
|
|
|
|
if apply:
|
|
self.apply(table, chain)
|
|
return chain
|
|
|
|
def reseaux_non_routable(self, table=None, fill_ipset=False, apply=False):
|
|
chain = 'RESEAUX_NON_ROUTABLES'
|
|
|
|
if fill_ipset:
|
|
anim('\tRestoration de l\'ipset reseaux_non_routable')
|
|
allowed = [ net for nets in NETs.values() for net in nets if NetInNets(net, config.firewall.reseaux_non_routables) ]
|
|
self.ipset['reseaux_non_routable']['allow'].restore(allowed)
|
|
self.ipset['reseaux_non_routable']['deny'].restore(config.firewall.reseaux_non_routables)
|
|
print OK
|
|
|
|
if table == 'filter':
|
|
pretty_print(table, chain)
|
|
self.add(table, chain, '-m set --match-set %s src -j RETURN' % self.ipset['reseaux_non_routable']['allow'])
|
|
self.add(table, chain, '-m set --match-set %s dst -j RETURN' % self.ipset['reseaux_non_routable']['allow'])
|
|
self.add(table, chain, '-m set --match-set %s src -j DROP' % self.ipset['reseaux_non_routable']['deny'])
|
|
self.add(table, chain, '-m set --match-set %s dst -j DROP' % self.ipset['reseaux_non_routable']['deny'])
|
|
print OK
|
|
|
|
if apply:
|
|
self.apply(table, chain)
|
|
return chain
|
|
|
|
def filtrage_ports_maj(self, ip_lists):
|
|
self.filtrage_ports('filter', apply=True)
|
|
|
|
def filtrage_ports(self, table=None, apply=False):
|
|
chain = 'FILTRAGE-PORTS'
|
|
|
|
def format_port(port):
|
|
port = str(port)
|
|
if port.endswith(':'):
|
|
port = '%s65535' % port
|
|
if port.startswith(':'):
|
|
port = '0%s' % port
|
|
return port
|
|
|
|
def add_ports(ip, proto, sens):
|
|
self.add(
|
|
table,
|
|
chain,
|
|
'-p %s -%s %s -m multiport --dports %s -j RETURN' % (
|
|
proto,
|
|
(sens=='out' and 's') or (sens == 'in' and 'd'),
|
|
ip,
|
|
','.join( format_port(port) for port in machine['portTCP%s' % sens])
|
|
)
|
|
)
|
|
|
|
if table == 'filter':
|
|
pretty_print(table, chain)
|
|
for machine in self.machines():
|
|
for ip in machine['ipHostNumber']:
|
|
if 'portTCPout' in machine.attrs.keys():
|
|
add_ports(ip,'tcp','out')
|
|
if 'portUDPout' in machine.attrs.keys():
|
|
add_ports(ip,'udp','out')
|
|
if 'portTCPin' in machine.attrs.keys():
|
|
add_ports(ip,'tcp','in')
|
|
if 'portUDPin' in machine.attrs.keys():
|
|
add_ports(ip,'udp','in')
|
|
|
|
for net in NETs['adherents'] + NETs['wifi-adh'] + NETs['personnel-ens']:
|
|
for proto in config.firewall.ports_default.keys():
|
|
if config.firewall.ports_default[proto]['output']:
|
|
self.add(table, chain, '-p %s -s %s -m multiport --dports %s -j RETURN' % (proto, net, ','.join( format_port(port) for port in config.firewall.ports_default[proto]['output'])))
|
|
if config.firewall.ports_default[proto]['input']:
|
|
self.add(table, chain, '-p %s -d %s -m multiport --dports %s -j RETURN' % (proto, net, ','.join( format_port(port) for port in config.firewall.ports_default[proto]['input'])))
|
|
|
|
self.add(table, chain, '-j REJECT')
|
|
print OK
|
|
|
|
if apply:
|
|
self.apply(table, chain)
|
|
return chain
|
|
|
|
|
|
if __name__ == '__main__' :
|
|
firewall = {
|
|
'komaz' : firewall_komaz,
|
|
}
|
|
# Chaînes pouvant être recontruites
|
|
if hostname in firewall.keys():
|
|
fw = firewall[hostname]()
|
|
else:
|
|
fw = firewall_base()
|
|
chaines = fw.reloadable.keys()
|
|
|
|
def __usage(txt=None) :
|
|
if txt!=None : cprint(txt,'gras')
|
|
|
|
print """Usage:
|
|
%(p)s start : Construction du firewall.
|
|
%(p)s restart : Reconstruction du firewall.
|
|
%(p)s stop : Arrêt du firewall.
|
|
%(p)s <noms de chaînes> : reconstruit les chaînes
|
|
Les chaînes pouvant être reconstruites sont :
|
|
%(chaines)s
|
|
Pour reconfiguration d'IPs particulières, utiliser generate. """ % \
|
|
{ 'p' : sys.argv[0].split('/')[-1] , 'chaines' : '\n '.join(chaines) }
|
|
sys.exit(-1)
|
|
|
|
# Bons arguments ?
|
|
if len(sys.argv) == 1 :
|
|
__usage()
|
|
for arg in sys.argv[1:] :
|
|
if arg in [ 'stop', 'restart', 'start' ] and len(sys.argv) != 2 :
|
|
__usage("L'argument %s ne peut être employé que seul." % arg)
|
|
|
|
if arg not in [ 'stop', 'restart', 'start' ] + chaines :
|
|
__usage("L'argument %s est inconnu." % arg)
|
|
|
|
for arg in sys.argv[1:] :
|
|
if arg == 'stop':
|
|
fw.stop()
|
|
elif arg == 'start':
|
|
fw.start()
|
|
elif arg == 'restart':
|
|
fw.restart()
|
|
else:
|
|
|
|
if squeeze:
|
|
anim('\tVidage de %s' % fw.reloadable[arg]())
|
|
for table in ['raw', 'mangle', 'filter', 'nat']:
|
|
fw.flush(table, fw.reloadable[arg]())
|
|
fw.restore(noflush=True)
|
|
print OK
|
|
|
|
for table in ['raw', 'mangle', 'filter', 'nat']:
|
|
fw.reloadable[arg](table)
|
|
if fw.reloadable[arg] in fw.use_ipset:
|
|
fw.reloadable[arg](fill_ipset=True)
|
|
|
|
anim('\tRestoration d\'iptables')
|
|
fw.restore(noflush=True)
|
|
print OK |