@ -9,6 +9,9 @@ from jinja2 import Environment, FileSystemLoader
import requests
import base64
import json
import subprocess
import socket
import argparse
config = ConfigParser ( )
config . read ( ' config.ini ' )
@ -23,151 +26,613 @@ client_hostname = socket.gethostname().split('.', 1)[0]
all_switchs = api_client . list ( " switchs/ports-config/ " )
# Création de l'environnement Jinja
ENV = Environment ( loader = FileSystemLoader ( ' . ' ) )
class iptables :
def __init__ ( self ) :
self . nat4 = " \n *nat "
self . mangle4 = " \n *mangle "
self . filter4 = " \n *filter "
self . nat6 = " \n *nat "
self . mangle6 = " \n *mangle "
self . filter6 = " \n *filter "
self . subnet_ports = api_client . list ( " firewall/subnet-ports/ " )
self . verbose = False
self . action = None
self . export = False
# Création du template final avec les valeurs contenues dans le dictionnaire "valeurs" - Ces valeurs sont positionnées dans un objet "temp", qui sera utilisé par le moteur, et que l'on retrouve dans le template.
def commit ( self , chain ) :
self . add ( chain , " COMMIT \n " )
def commit_filter ( self ) :
self . add ( " filter4 " , " COMMIT \n " )
self . add ( " filter6 " , " COMMIT \n " )
class Switch :
def __init__ ( self ) :
self . additionnal = None
self . all_vlans = api_client . list ( " machines/vlan/ " )
self . settings = api_client . view ( " preferences/optionaltopologie/ " )
# Import du fichier template dans une variable "template"
self . hp_tpl = ENV . get_template ( " templates/hp.tpl " )
self . conf = None
self . name = None
self . switch = None
self . headers = None
self . creds_dict = None
def get_conf_file_name ( self ) :
return self . switch [ " short_name " ] + " .conf "
def preprocess_hp ( self ) :
""" Prérempli certains valeurs renvoyées directement à jinja, pour plus de simplicité """
def add_to_vlans ( vlans , vlan , port , tagged = True ) :
if not vlan [ ' vlan_id ' ] in vlans :
if not tagged :
vlans [ vlan [ ' vlan_id ' ] ] = { ' ports_untagged ' : [ str ( port [ ' port ' ] ) ] , ' ports_tagged ' : [ ] , ' name ' : vlan [ ' name ' ] }
else :
vlans [ vlan [ ' vlan_id ' ] ] = { ' ports_tagged ' : [ str ( port [ ' port ' ] ) ] , ' ports_untagged ' : [ ] , ' name ' : vlan [ ' name ' ] }
else :
if not tagged :
vlans [ vlan [ ' vlan_id ' ] ] [ ' ports_untagged ' ] . append ( str ( port [ ' port ' ] ) )
else :
vlans [ vlan [ ' vlan_id ' ] ] [ ' ports_tagged ' ] . append ( str ( port [ ' port ' ] ) )
vlans = dict ( )
for port in self . switch [ ' ports ' ] :
if port [ ' get_port_profil ' ] [ ' vlan_untagged ' ] :
add_to_vlans ( vlans , port [ ' get_port_profil ' ] [ ' vlan_untagged ' ] , port , tagged = False )
if port [ ' get_port_profil ' ] [ ' vlan_tagged ' ] :
for vlan in port [ ' get_port_profil ' ] [ ' vlan_tagged ' ] :
add_to_vlans ( vlans , vlan , port )
#Trie les ip par vlan, et les ajoute ainsi que les subnet
for ip , subnet in self . switch [ " interfaces_subnet " ] . items ( ) :
vlans [ subnet [ 0 ] [ " vlan_id " ] ] . setdefault ( " ipv4 " , { } )
vlans [ subnet [ 0 ] [ " vlan_id " ] ] [ " ipv4 " ] [ ip ] = subnet
for ipv6 , subnet in self . switch [ " interfaces6_subnet " ] . items ( ) :
vlans [ subnet [ " vlan_id " ] ] . setdefault ( " ipv6 " , { } )
vlans [ subnet [ " vlan_id " ] ] [ " ipv6 " ] [ ipv6 ] = subnet
#Regroupement des options par vlans : dhcp_soop,arp, et dhcpv6, ainsi que igmp, mld , ra-guard et loop_protect
arp_protect_vlans = [ vlan [ " vlan_id " ] for vlan in self . all_vlans if vlan [ " arp_protect " ] ]
dhcp_snooping_vlans = [ vlan [ " vlan_id " ] for vlan in self . all_vlans if vlan [ " dhcp_snooping " ] ]
dhcpv6_snooping_vlans = [ vlan [ " vlan_id " ] for vlan in self . all_vlans if vlan [ " dhcpv6_snooping " ] ]
igmp_vlans = [ vlan [ " vlan_id " ] for vlan in self . all_vlans if vlan [ " igmp " ] ]
mld_vlans = [ vlan [ " vlan_id " ] for vlan in self . all_vlans if vlan [ " mld " ] ]
ra_guarded = [ str ( port [ ' port ' ] ) for port in self . switch [ ' ports ' ] if port [ ' get_port_profil ' ] [ ' ra_guard ' ] ]
loop_protected = [ str ( port [ ' port ' ] ) for port in self . switch [ ' ports ' ] if port [ ' get_port_profil ' ] [ ' loop_protect ' ] ]
self . additionals = { ' ra_guarded ' : ra_guarded , ' loop_protected ' : loop_protected , ' vlans ' : vlans , ' arp_protect_vlans ' : arp_protect_vlans , ' dhcp_snooping_vlans ' : dhcp_snooping_vlans , ' dhcpv6_snooping_vlans ' : dhcpv6_snooping_vlans , ' igmp_vlans ' : igmp_vlans , ' mld_vlans ' : mld_vlans }
def gen_conf_hp ( self ) :
""" Génère la config pour ce switch hp """
self . preprocess_hp ( )
self . conf = self . hp_tpl . render ( switch = self . switch , settings = self . settings , additionals = self . additionals )
def check_and_get_login ( self ) :
""" Récupère les login/mdp du switch, renvoie false si ils sont indisponibles """
self . creds_dict = self . switch [ " get_management_cred_value " ]
if self . creds_dict :
return True
def commit_mangle ( self ) :
self . add ( " mangle4 " , " COMMIT \n " )
self . add ( " mangle6 " , " COMMIT \n " )
def commit_nat ( self ) :
self . add ( " nat4 " , " COMMIT \n " )
self . add ( " nat6 " , " COMMIT \n " )
def add ( self , chain , value ) :
setattr ( self , chain , getattr ( self , chain ) + " \n " + value )
def add_in_subtable ( self , chain , subtable , value ) :
if ' 4 ' in chain :
self . add ( chain , " -A " + subtable + " " + value )
elif ' 6 ' in chain :
self . add ( chain , " -A " + subtable + " " + value )
else :
self . add ( chain + ' 4 ' , " -A " + subtable + " " + value )
self . add ( chain + ' 6 ' , " -A " + subtable + " " + value )
def init_filter ( self , subchain , decision = " ACCEPT " , mode = ' all ' ) :
if mode == ' all ' or mode == ' 4 ' :
self . add ( " filter4 " , " : " + subchain + " " + decision )
if mode == ' all ' or mode == ' 6 ' :
self . add ( " filter6 " , " : " + subchain + " " + decision )
def init_nat ( self , subchain , decision = " ACCEPT " , mode = ' all ' ) :
if mode == ' all ' or mode == ' 4 ' :
self . add ( " nat4 " , " : " + subchain + " " + decision )
if mode == ' all ' or mode == ' 6 ' :
self . add ( " nat6 " , " : " + subchain + " " + decision )
def init_mangle ( self , subchain , decision = " ACCEPT " , mode = ' all ' ) :
if mode == ' all ' or mode == ' 4 ' :
self . add ( " mangle4 " , " : " + subchain + " " + decision )
if mode == ' all ' or mode == ' 6 ' :
self . add ( " mangle6 " , " : " + subchain + " " + decision )
def jump ( self , chain , subchainA , subchainB ) :
self . add ( chain , " -A " + subchainA + " -j " + subchainB )
def jump_all_trafic ( self , chain , subchainA , subchainB , mode = ' all ' ) :
if mode == ' all ' or mode == ' 4 ' :
self . add ( chain + ' 4 ' , " -A " + subchainA + " -j " + subchainB )
if mode == ' all ' or mode == ' 6 ' :
self . add ( chain + ' 6 ' , " -A " + subchainA + " -j " + subchainB )
def jump_traficfrom ( self , chain , interface , subchainA , subchainB , mode = ' all ' ) :
if mode == ' all ' or mode == ' 4 ' :
self . add ( chain + ' 4 ' , " -A " + subchainA + " -i " + interface + " -j " + subchainB )
if mode == ' all ' or mode == ' 6 ' :
self . add ( chain + ' 6 ' , " -A " + subchainA + " -i " + interface + " -j " + subchainB )
def jump_traficto ( self , chain , interface , subchainA , subchainB , mode = ' all ' ) :
if mode == ' all ' or mode == ' 4 ' :
self . add ( chain + ' 4 ' , " -A " + subchainA + " -o " + interface + " -j " + subchainB )
if mode == ' all ' or mode == ' 6 ' :
self . add ( chain + ' 6 ' , " -A " + subchainA + " -o " + interface + " -j " + subchainB )
def atomic_add ( self , chain , subtable , command , mode = ' 4 ' ) :
command_to_send = " -t %s -I %s 1 %s " % ( chain , subtable , command )
if mode == ' all ' or mode == ' 4 ' :
command_to_execute = [ " sudo " , " -n " , " /sbin/iptables " ] + command_to_send . split ( )
if mode == ' all ' or mode == ' 6 ' :
command_to_execute = [ " sudo " , " -n " , " /sbin/ip6tables " ] + command_to_send . split ( )
process = subprocess . Popen ( command_to_execute , stdin = subprocess . PIPE , stdout = subprocess . PIPE )
def atomic_del ( self , chain , subtable , command , mode = ' 4 ' ) :
command_to_send = " -t %s -D %s %s " % ( chain , subtable , command )
if mode == ' all ' or mode == ' 4 ' :
command_to_execute = [ " sudo " , " -n " , " /sbin/iptables " ] + command_to_send . split ( )
if mode == ' all ' or mode == ' 6 ' :
command_to_execute = [ " sudo " , " -n " , " /sbin/ip6tables " ] + command_to_send . split ( )
process = subprocess . Popen ( command_to_execute , stdin = subprocess . PIPE , stdout = subprocess . PIPE )
def routeur6 ( self , table ) :
""" Methode appellée spécifiquement pour le parefeu v6 """
if table == " filter " :
self . base_filter ( )
if self . verbose :
print ( " Filter : interdit les machines blacklistées en forward " )
self . blacklist_hard_forward ( )
if self . verbose :
print ( " Filter : filtage ports v6 " )
self . filtrage_ports ( ip_type = ' 6 ' )
if self . verbose :
print ( " Filter : limit connexions forward " )
self . limit_ssh_connexion_forward ( )
if self . verbose :
print ( " Filter : Limit connexion src " )
self . limit_connexion_srcip ( )
elif table == " mangle " :
if self . verbose :
print ( " Mangle : Mise en place des logs " )
self . log ( )
if self . verbose :
print ( " Mangle : Réglage correct du MSS " )
self . mss ( )
else :
pass
def routeur4 ( self , table ) :
""" Methode appellée spécifiquement pour le parefeu v4 """
if table == " filter " :
self . base_filter ( )
if self . verbose :
print ( " Filter : interdit les machines blacklistées en forward " )
self . blacklist_hard_forward ( )
if self . verbose :
print ( " Filter : filtrage ports 4 " )
self . filtrage_ports ( ip_type = ' 4 ' )
if self . verbose :
print ( " Filter : limit ssh connexion forward " )
self . limit_ssh_connexion_forward ( )
if self . verbose :
print ( " Filter : limit connexion src ip " )
self . limit_connexion_srcip ( )
elif table == " mangle " :
if self . verbose :
print ( " Mangle : Mise en place des logs " )
self . log ( )
if self . verbose :
print ( " Mangle : Réglage correct du MSS " )
self . mss ( )
elif table == " nat " :
if self . verbose :
print ( " Nat : priv fil " )
self . nat_prive_ip ( ' fil ' )
if self . verbose :
print ( " Nat : priv wifi " )
self . nat_prive_ip ( ' wifi ' )
def portail ( self , table ) :
if table == " filter " :
self . base_filter ( )
if self . verbose :
print ( " Filter : autorisation des ip en sortie " )
self . captif_autorized_ip ( )
if table == " nat " :
if self . verbose :
print ( " Nat : nat et captures les connexions du portail masquerade " )
self . nat_connexion_portail ( )
self . capture_connexion_portail ( )
def users ( self , table ) :
""" Securisation d ' un serveur avec comptes d ' utilisateurs """
if table == ' filter ' :
#self.blacklist_output()
self . base_filter ( )
if self . verbose :
print ( " Filter : Forbid admin vlan for users " )
self . forbid_adm ( )
else :
pass
def radius ( self , table ) :
if table == ' filter ' :
if self . verbose :
print ( " Filter : acceptation des connexions uniquement des serveurs federez " )
self . accept_freerad_from_server ( )
else :
pass
def base_filter ( self ) :
if self . verbose :
print ( " Filter : reseaux non routables " )
self . reseaux_non_routables ( )
if self . verbose :
print ( " Filter : bl hard " )
self . blacklist_hard ( )
if self . verbose :
print ( " Filter : connexion input " )
if self . verbose :
print ( " Limitation des connexions " )
self . limit_ssh_connexion_input ( )
self . limit_connexion_dstip ( )
def gen_filter ( self , empty = False ) :
self . init_filter ( " INPUT " )
self . init_filter ( " FORWARD " )
self . init_filter ( " OUTPUT " )
if not empty :
if self . verbose :
print ( " Filter : icmp " )
self . filter_icmp ( )
if self . verbose :
print ( " Filter : icmpv6 " )
self . filter_icmpv6 ( )
if self . verbose :
print ( " Filter : accept established " )
self . accept_established ( )
for role in self . role :
if hasattr ( self , role ) :
getattr ( self , role ) ( ' filter ' )
self . commit_filter ( )
def filtrage_ports ( self , ip_type = ' 4 ' , subtable = ' FILTRAGE-PORTS ' ) :
""" Filtrage ports en entrée/sortie du réseau """
if ip_type == ' 4 ' :
chain = " filter4 "
else :
chain = " filter6 "
self . init_filter ( subtable , decision = " - " )
for interface in self . interfaces [ ' sortie ' ] :
self . jump_traficto ( " filter " , interface , " FORWARD " , subtable , mode = ip_type )
self . jump_traficfrom ( " filter " , interface , " FORWARD " , subtable , mode = ip_type )
for subnet in self . subnet_ports :
ports = ' , ' . join ( rule [ " show_port " ] for rule in subnet [ " ouverture_ports " ] [ " tcp_ports_in " ] )
if ports :
if ip_type == ' 4 ' :
self . add_in_subtable ( chain , subtable , """ -m iprange --dst-range %s - %s -p tcp -m multiport --dports %s -j RETURN """ % ( rule [ " domaine_ip_start " ] , rule [ " domaine_ip_stop " ] , ports ) )
if ip_type == ' 6 ' :
self . add_in_subtable ( chain , subtable , """ -s %s -p tcp -m multiport --dports %s -j RETURN """ % ( ip_range , ports ) )
ports = ' , ' . join ( rule [ " show_port " ] for rule in subnet [ " ouverture_ports " ] [ " tcp_ports_out " ] )
if ports :
self . add_in_subtable ( chain , subtable , """ -m iprange --src-range %s - %s -p tcp -m multiport --dports %s -j RETURN """ % ( rule [ " domaine_ip_start " ] , rule [ " domaine_ip_stop " ] , ports ) )
ports = ' , ' . join ( rule [ " show_port " ] for rule in subnet [ " ouverture_ports " ] [ " udp_ports_in " ] )
if ports :
self . add_in_subtable ( chain , subtable , """ -m iprange --dst-range %s - %s -p udp -m multiport --dports %s -j RETURN """ % ( rule [ " domaine_ip_start " ] , rule [ " domaine_ip_stop " ] , ports ) )
ports = ' , ' . join ( rule [ " show_port " ] for rule in subnet [ " ouverture_ports " ] [ " udp_ports_out " ] )
if ports :
self . add_in_subtable ( chain , subtable , """ -m iprange --src-range %s - %s -p udp -m multiport --dports %s -j RETURN """ % ( rule [ " domaine_ip_start " ] , rule [ " domaine_ip_stop " ] , ports ) )
#Ajout des règles générales
for realm in self . config_firewall . ports_realm [ ip_type ] :
ports = ' , ' . join ( self . format_port ( port ) for port in self . config_firewall . ports_default [ ' tcp ' ] [ ' output ' ] )
if ports :
for ip_range in get_range ( ip_type , realm ) :
self . add_in_subtable ( chain , subtable , """ -s %s -p tcp -m multiport --dports %s -j RETURN """ % ( ip_range , ports ) )
ports = ' , ' . join ( self . format_port ( port ) for port in self . config_firewall . ports_default [ ' tcp ' ] [ ' input ' ] )
if ports :
for ip_range in get_range ( ip_type , realm ) :
self . add_in_subtable ( chain , subtable , """ -d %s -p tcp -m multiport --dports %s -j RETURN """ % ( ip_range , ports ) )
ports = ' , ' . join ( self . format_port ( port ) for port in self . config_firewall . ports_default [ ' udp ' ] [ ' output ' ] )
if ports :
for ip_range in get_range ( ip_type , realm ) :
self . add_in_subtable ( chain , subtable , """ -s %s -p udp -m multiport --dports %s -j RETURN """ % ( ip_range , ports ) )
ports = ' , ' . join ( self . format_port ( port ) for port in self . config_firewall . ports_default [ ' udp ' ] [ ' input ' ] )
if ports :
for ip_range in get_range ( ip_type , realm ) :
self . add_in_subtable ( chain , subtable , """ -d %s -p udp -m multiport --dports %s -j RETURN """ % ( ip_range , ports ) )
#Ajout des machines avec ouvertures particulières
for machine in self . conn . search ( u ' (&(portTCPout=*)( %s =*)) ' % ldap_object_name ) :
self . add_in_subtable ( chain , subtable , """ -s %s -p tcp -m multiport --dports %s -j RETURN """ % ( machine [ ldap_object_name ] [ 0 ] . value , ' , ' . join ( self . format_port ( port ) for port in machine [ ' portTCPout ' ] ) ) )
for machine in self . conn . search ( u ' (&(portTCPin=*)( %s =*)) ' % ldap_object_name ) :
self . add_in_subtable ( chain , subtable , """ -d %s -p tcp -m multiport --dports %s -j RETURN """ % ( machine [ ldap_object_name ] [ 0 ] . value , ' , ' . join ( self . format_port ( port ) for port in machine [ ' portTCPin ' ] ) ) )
for machine in self . conn . search ( u ' (&(portUDPout=*)( %s =*)) ' % ldap_object_name ) :
self . add_in_subtable ( chain , subtable , """ -s %s -p udp -m multiport --dports %s -j RETURN """ % ( machine [ ldap_object_name ] [ 0 ] . value , ' , ' . join ( self . format_port ( port ) for port in machine [ ' portUDPout ' ] ) ) )
for machine in self . conn . search ( u ' (&(portUDPin=*)( %s =*)) ' % ldap_object_name ) :
self . add_in_subtable ( chain , subtable , """ -d %s -p udp -m multiport --dports %s -j RETURN """ % ( machine [ ldap_object_name ] [ 0 ] . value , ' , ' . join ( self . format_port ( port ) for port in machine [ ' portUDPin ' ] ) ) )
#Rejet du reste
self . add_in_subtable ( chain , subtable , """ -j REJECT """ )
def accept_freerad_from_server ( self , subtable = ' RADIUS-SERVER ' ) :
""" Accepte uniquement le trafique venant des serveurs radius federez """
self . init_filter ( subtable , decision = " - " )
for interface in self . interfaces [ ' sortie ' ] :
self . jump_traficfrom ( " filter " , interface , " INPUT " , subtable )
for server in self . config_firewall . radius_server :
self . add_in_subtable ( " filter4 " , subtable , """ -s %s -p %s -m multiport --dports %s -j ACCEPT """ % ( server [ ' ipaddr ' ] , server [ ' protocol ' ] , ' , ' . join ( server [ ' port ' ] ) ) )
self . add_in_subtable ( " filter6 " , subtable , """ -s %s -p %s -m multiport --dports %s -j ACCEPT """ % ( server [ ' ip6addr ' ] , server [ ' protocol ' ] , ' , ' . join ( server [ ' port ' ] ) ) )
self . add_in_subtable ( " filter " , subtable , """ -j REJECT """ )
def reseaux_non_routables ( self , subtable = ' ADM-NETWORK ' ) :
""" Bloc le trafic vers les réseaux non routables """
self . init_filter ( subtable , decision = " - " )
for interface in self . interfaces [ ' non-routables ' ] :
self . jump_traficto ( " filter " , interface , " FORWARD " , subtable )
self . add_in_subtable ( " filter " , subtable , """ -j REJECT """ )
def captif_autorized_ip ( self , subtable = ' FILTRE-IP-PORTAIL ' ) :
""" Autorise les ip whitelistées sur le portail captif accueil """
self . init_filter ( subtable , decision = " - " )
self . jump_all_trafic ( " filter " , " FORWARD " , subtable , mode = ' 4 ' )
for ip in self . config . accueil_route . keys ( ) :
if ' tcp ' in self . config . accueil_route [ ip ] :
self . add_in_subtable ( " filter4 " , subtable , """ -p tcp -d %s -m multiport --dports %s -j ACCEPT """ % ( ip , ' , ' . join ( self . config . accueil_route [ ip ] [ ' tcp ' ] ) ) )
if ' udp ' in self . config . accueil_route [ ip ] :
self . add_in_subtable ( " filter4 " , subtable , """ -p udp -d %s -m multiport --dports %s -j ACCEPT """ % ( ip , ' , ' . join ( self . config . accueil_route [ ip ] [ ' udp ' ] ) ) )
self . add_in_subtable ( " filter4 " , subtable , """ -j REJECT """ )
def capture_connexion_portail ( self , subtable = " PORTAIL-CAPTIF-REDIRECT " ) :
""" Nat les connexions derrière l ' ip de la machine du portail """
self . init_nat ( subtable , decision = " - " )
for interface in self . interfaces [ ' routables ' ] :
self . jump_traficfrom ( " nat " , interface , " PREROUTING " , subtable , mode = ' 4 ' )
for ip in self . config . accueil_route . keys ( ) :
if ' tcp ' in self . config . accueil_route [ ip ] :
self . add_in_subtable ( " nat4 " , subtable , """ -p tcp -d %s -m multiport --dports %s -j RETURN """ % ( ip , ' , ' . join ( self . config . accueil_route [ ip ] [ ' tcp ' ] ) ) )
if ' udp ' in self . config . accueil_route [ ip ] :
self . add_in_subtable ( " nat4 " , subtable , """ -p udp -d %s -m multiport --dports %s -j RETURN """ % ( ip , ' , ' . join ( self . config . accueil_route [ ip ] [ ' udp ' ] ) ) )
self . add_in_subtable ( " nat4 " , subtable , """ -p udp -s %(ip)s /16 --dport 53 -j DNAT --to %(ip)s """ % { ' ip ' : self . config_firewall . portail [ ' accueil ' ] } )
self . add_in_subtable ( " nat4 " , subtable , """ -p tcp -s %(ip)s /16 --dport 53 -j DNAT --to %(ip)s """ % { ' ip ' : self . config_firewall . portail [ ' accueil ' ] } )
self . add_in_subtable ( " nat4 " , subtable , """ -p tcp -s %(ip)s /16 --dport 80 -j DNAT --to %(ip)s """ % { ' ip ' : self . config_firewall . portail [ ' accueil ' ] } )
self . add_in_subtable ( " nat4 " , subtable , """ -p tcp -s %(ip)s /16 --dport 80 -j DNAT --to %(ip)s """ % { ' ip ' : self . config_firewall . portail [ ' isolement ' ] } )
def nat_connexion_portail ( self , subtable = " PORTAIL-CAPTIF-NAT " ) :
""" Nat les connexions derrière l ' ip de la machine du portail """
self . init_nat ( subtable , decision = " - " )
for interface in self . interfaces [ ' sortie ' ] :
self . jump_traficto ( " nat " , interface , " POSTROUTING " , subtable , mode = ' 4 ' )
for ip in self . config . accueil_route . keys ( ) :
if ' tcp ' in self . config . accueil_route [ ip ] :
self . add_in_subtable ( " nat4 " , subtable , """ -p tcp -d %s -m multiport --dports %s -j MASQUERADE """ % ( ip , ' , ' . join ( self . config . accueil_route [ ip ] [ ' tcp ' ] ) ) )
if ' udp ' in self . config . accueil_route [ ip ] :
self . add_in_subtable ( " nat4 " , subtable , """ -p udp -d %s -m multiport --dports %s -j MASQUERADE """ % ( ip , ' , ' . join ( self . config . accueil_route [ ip ] [ ' udp ' ] ) ) )
def accept_established ( self , subtable = ' ESTABLISHED-CONN ' ) :
""" Accepte les connexions déjà établies """
self . init_filter ( subtable , decision = " - " )
self . jump_all_trafic ( " filter " , " FORWARD " , subtable )
self . jump_all_trafic ( " filter " , " INPUT " , subtable )
self . add_in_subtable ( " filter " , subtable , """ -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT """ )
def filter_icmpv6 ( self , subtable = ' ICMPV6 ' ) :
self . init_filter ( subtable , decision = " - " , mode = ' 6 ' )
self . jump_all_trafic ( " filter " , " INPUT " , subtable , mode = ' 6 ' )
self . jump_all_trafic ( " filter " , " FORWARD " , subtable , mode = ' 6 ' )
self . jump_all_trafic ( " filter " , " OUTPUT " , subtable , mode = ' 6 ' )
self . add_in_subtable ( " filter6 " , subtable , """ -p icmpv6 -m icmp6 --icmpv6-type echo-request -j ACCEPT """ )
self . add_in_subtable ( " filter6 " , subtable , """ -p icmpv6 -m icmp6 --icmpv6-type echo-reply -j ACCEPT """ )
self . add_in_subtable ( " filter6 " , subtable , """ -p icmpv6 -m icmp6 --icmpv6-type destination-unreachable -j ACCEPT """ )
self . add_in_subtable ( " filter6 " , subtable , """ -p icmpv6 -m icmp6 --icmpv6-type packet-too-big -j ACCEPT """ )
self . add_in_subtable ( " filter6 " , subtable , """ -p icmpv6 -m icmp6 --icmpv6-type ttl-zero-during-transit -j ACCEPT """ )
self . add_in_subtable ( " filter6 " , subtable , """ -p icmpv6 -m icmp6 --icmpv6-type parameter-problem -j ACCEPT """ )
def filter_icmp ( self , subtable = ' ICMP ' ) :
self . init_filter ( subtable , decision = " - " , mode = ' 4 ' )
self . jump_all_trafic ( " filter " , " FORWARD " , subtable , mode = ' 4 ' )
self . jump_all_trafic ( " filter " , " OUTPUT " , subtable , mode = ' 4 ' )
self . jump_all_trafic ( " filter " , " INPUT " , subtable , mode = ' 4 ' )
self . add_in_subtable ( " filter4 " , subtable , """ -p icmp -j ACCEPT """ )
def limit_ssh_connexion_input ( self , subtable = ' LIMIT-SSH-INPUT ' ) :
self . init_filter ( subtable , decision = " - " )
for interface in self . interfaces [ ' routables ' ] :
self . jump_traficfrom ( " filter " , interface , " INPUT " , subtable )
self . add_in_subtable ( " filter " , subtable , """ -p tcp --dport ssh -m state --state NEW -m recent --name SSH-INPUT --set """ )
self . add_in_subtable ( " filter " , subtable , """ -p tcp --dport ssh -m state --state NEW -m recent --name SSH-INPUT --update --seconds 120 --hitcount 10 --rttl -j DROP """ )
def limit_ssh_connexion_forward ( self , subtable = ' LIMIT-SSH-FORWARD ' ) :
self . init_filter ( subtable , decision = " - " )
for interface in self . interfaces [ ' sortie ' ] :
self . jump_traficfrom ( " filter " , interface , " FORWARD " , subtable )
self . add_in_subtable ( " filter " , subtable , """ -p tcp --dport ssh -m state --state NEW -m recent --name SSH-FORWARD --set """ )
self . add_in_subtable ( " filter " , subtable , """ -p tcp --dport ssh -m state --state NEW -m recent --name SSH-FORWARD --update --seconds 30 --hitcount 10 --rttl -j DROP """ )
def limit_connexion_srcip ( self , subtable = ' LIMIT-CONNEXION-SRCIP ' ) :
self . init_filter ( subtable , decision = " - " )
for interface in self . interfaces [ ' sortie ' ] :
self . jump_traficto ( " filter " , interface , " FORWARD " , subtable )
self . add_in_subtable ( " filter " , subtable , """ -p udp -m hashlimit --hashlimit-upto 400/sec --hashlimit-burst 800 --hashlimit-mode srcip --hashlimit-name LIMIT_UDP_SRCIP_CONNEXION -j RETURN """ )
self . add_in_subtable ( " filter " , subtable , """ -p udp -m hashlimit --hashlimit-upto 5/hour --hashlimit-burst 5 --hashlimit-mode srcip --hashlimit-name LIMIT_UDP_SRCIP_CONNEXION_LOG -j LOG --log-prefix " CONNEXION_LIMIT_UDP " """ )
self . add_in_subtable ( " filter " , subtable , """ -p udp -j REJECT """ )
self . add_in_subtable ( " filter " , subtable , """ -p tcp -m hashlimit --hashlimit-upto 2000/min --hashlimit-burst 4000 --hashlimit-mode srcip --hashlimit-name LIMIT_TCP_SRCIP_CONNEXION -m state --state NEW -j RETURN """ )
self . add_in_subtable ( " filter " , subtable , """ -p tcp -m hashlimit --hashlimit-upto 5/hour --hashlimit-burst 5 --hashlimit-mode srcip --hashlimit-name LIMIT_TCP_SRCIP_CONNEXION_LOG -m state --state NEW -j LOG --log-prefix " CONNEXION_LIMIT_TCP_SRCIP " """ )
self . add_in_subtable ( " filter " , subtable , """ -p tcp -m state --state NEW -j REJECT """ )
self . add_in_subtable ( " filter " , subtable , """ -m hashlimit --hashlimit-upto 400/sec --hashlimit-burst 800 --hashlimit-mode srcip --hashlimit-name LIMIT_OTHER_SRCIP_CONNEXION -j RETURN """ )
self . add_in_subtable ( " filter " , subtable , """ -m hashlimit --hashlimit-upto 5/hour --hashlimit-burst 5 --hashlimit-mode srcip --hashlimit-name LIMIT_OTHER_SRCIP_CONNEXION_LOG -j LOG --log-prefix " CONNEXION_LIMIT " """ )
self . add_in_subtable ( " filter " , subtable , """ -j REJECT """ )
def limit_connexion_dstip ( self , subtable = ' LIMIT-CONNEXION-DSTIP ' , cible = ' INPUT ' ) :
self . init_filter ( subtable , decision = " - " )
if " sortie " in self . interfaces :
for interface in self . interfaces [ ' sortie ' ] :
self . jump_traficfrom ( " filter " , interface , " FORWARD " , subtable )
for interface in self . interfaces [ ' routables ' ] :
self . jump_traficfrom ( " filter " , interface , " INPUT " , subtable )
self . add_in_subtable ( " filter " , subtable , """ -p udp -m hashlimit --hashlimit-upto 400/sec --hashlimit-burst 800 --hashlimit-mode srcip --hashlimit-name LIMIT_UDP_DSTIP_CONNEXION -j RETURN """ )
self . add_in_subtable ( " filter " , subtable , """ -p udp -m hashlimit --hashlimit-upto 5/hour --hashlimit-burst 5 --hashlimit-mode srcip --hashlimit-name LIMIT_UDP_DSTIP_CONNEXION_LOG -j LOG --log-prefix " CONNEXION_LIMIT_UDP " """ )
self . add_in_subtable ( " filter " , subtable , """ -p udp -j REJECT """ )
self . add_in_subtable ( " filter " , subtable , """ -p tcp -m hashlimit --hashlimit-upto 2000/min --hashlimit-burst 4000 --hashlimit-mode srcip --hashlimit-name LIMIT_TCP_DSTIP_CONNEXION -m state --state NEW -j RETURN """ )
self . add_in_subtable ( " filter " , subtable , """ -p tcp -m hashlimit --hashlimit-upto 5/hour --hashlimit-burst 5 --hashlimit-mode srcip --hashlimit-name LIMIT_TCP_DSTIP_CONNEXION_LOG -m state --state NEW -j LOG --log-prefix " CONNEXION_LIMIT_TCP_DSTIP " """ )
self . add_in_subtable ( " filter " , subtable , """ -p tcp -m state --state NEW -j REJECT """ )
self . add_in_subtable ( " filter " , subtable , """ -m hashlimit --hashlimit-upto 400/sec --hashlimit-burst 800 --hashlimit-mode srcip --hashlimit-name LIMIT_OTHER_DSTIP_CONNEXION -j RETURN """ )
self . add_in_subtable ( " filter " , subtable , """ -m hashlimit --hashlimit-upto 5/hour --hashlimit-burst 5 --hashlimit-mode srcip --hashlimit-name LIMIT_OTHER_DSTIP_CONNEXION_LOG -j LOG --log-prefix " CONNEXION_LIMIT " """ )
self . add_in_subtable ( " filter " , subtable , """ -j REJECT """ )
def blacklist_hard_forward ( self , subtable = ' BLACKLIST-HARD ' ) :
""" Blacklist les machines en forward, à appliquer sur les routeurs de sortie """
for interface in self . interfaces [ ' routables ' ] :
self . jump_traficfrom ( " filter " , interface , " FORWARD " , subtable )
def blacklist_hard ( self , subtable = ' BLACKLIST-HARD ' ) :
""" Génération de la chaine blackliste hard, blackliste des mac des machines bl """
self . init_filter ( subtable , decision = " - " )
for interface in self . interfaces [ ' routables ' ] :
self . jump_traficfrom ( " filter " , interface , " INPUT " , subtable )
for machine in self . conn . allMachines ( ) :
if machine . blacklist_actif ( ) and set ( bl [ ' type ' ] for bl in machine . blacklist_actif ( ) ) . intersection ( self . config . blacklist_sanctions ) and machine [ ' macAddress ' ] and machine [ ' macAddress ' ] [ 0 ] . value != ' <automatique> ' :
self . add_in_subtable ( " filter " , subtable , """ -m mac --mac-source %s -j REJECT """ % machine [ ' macAddress ' ] [ 0 ] . value )
def blacklist_output ( self , subtable = ' BLACKLIST-OUTPUT ' ) :
""" Génération de la chaine blackliste output, meme idée que si dessus sauf que
ici on filtre les users uid sur un serveur et non leurs ip """
self . init_filter ( subtable , decision = " - " )
for interface in self . interfaces [ ' routables ' ] :
self . jump_traficto ( " filter " , interface , " OUTPUT " , subtable )
for user in self . conn . search ( u ' (&(uidNumber=*)(!(droits=nounou))(!(droits=apprenti))(|(objectClass=adherent)(objectClass=club))) ' , sizelimit = 10000 ) :
if user . blacklist_actif ( ) :
self . add_in_subtable ( " filter " , subtable , """ -m owner --uid-owner %s -j REJECT """ % user [ ' uidNumber ' ] [ 0 ] . value )
def forbid_adm ( self , subtable = ' ADMIN-VLAN ' ) :
""" Interdit aux users non admin de parler sur les vlans admin """
self . init_filter ( subtable , decision = " - " )
for interface in self . interfaces [ ' non-routables ' ] :
self . jump_traficto ( " filter " , interface , " OUTPUT " , subtable )
for user in self . conn . search ( u ' (&(uidNumber=*)(!(droits=nounou))(!(droits=apprenti))(|(objectClass=adherent)(objectClass=club))) ' , sizelimit = 10000 ) :
self . add_in_subtable ( " filter " , subtable , """ -m owner --uid-owner %s -j REJECT """ % user [ ' uidNumber ' ] [ 0 ] . value )
def gen_nat ( self , empty = False ) :
""" Génération de la chaine nat """
self . init_nat ( " PREROUTING " )
self . init_nat ( " INPUT " )
self . init_nat ( " OUTPUT " )
self . init_nat ( " POSTROUTING " )
if not empty :
for role in self . role :
if hasattr ( self , role ) :
getattr ( self , role ) ( ' nat ' )
self . commit_nat ( )
def log ( self , subtable = ' LOGALL ' ) :
""" Logage des packet sur les interfaces choisies """
self . init_mangle ( subtable , decision = " - " )
self . jump_all_trafic ( " mangle " , " PREROUTING " , subtable )
self . add_in_subtable ( " mangle " , subtable , ' -m state --state NEW -j LOG --log-prefix " LOG_ALL " ' )
def mss ( self , subtable = ' MSS ' ) :
""" Reglage correct du MSS pour éviter les problèmes de MTU """
self . init_mangle ( subtable , decision = " - " )
self . jump_all_trafic ( " mangle " , " POSTROUTING " , subtable )
self . add_in_subtable ( " mangle " , subtable , ' -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu ' )
def nat_prive_ip ( self , nat_type ) :
""" Nat filaire en v4 """
subtable = " CONNEXION-NAT- " + nat_type . upper ( )
self . init_nat ( subtable , decision = " - " )
self . jump_all_trafic ( " nat " , " POSTROUTING " , subtable )
nat_prive_ip_plage = self . config_firewall . nat_prive_ip_plage [ nat_type ]
for nat_ip_range in range ( 1 , 26 ) :
range_name = ' nat ' + nat_prive_ip_plage . split ( ' . ' ) [ 1 ] + ' _ ' + str ( " %02d " % nat_ip_range )
self . init_nat ( range_name , decision = " - " )
self . add_in_subtable ( " nat " , subtable , ' -s ' + ' . ' . join ( nat_prive_ip_plage . split ( ' . ' ) [ : 2 ] ) + ' . ' + str ( nat_ip_range ) + ' .0/24 -j ' + range_name )
for nat_ip_range in range ( 1 , 26 ) :
range_name = ' nat ' + nat_prive_ip_plage . split ( ' . ' ) [ 1 ] + ' _ ' + str ( " %02d " % nat_ip_range )
for nat_ip_subrange in range ( 16 ) :
subrange_name = range_name + ' _ ' + str ( hex ( nat_ip_subrange ) [ 2 : ] )
self . init_nat ( subrange_name , decision = " - " )
self . add_in_subtable ( " nat " , range_name , ' -s ' + ' . ' . join ( nat_prive_ip_plage . split ( ' . ' ) [ : 2 ] ) + ' . ' + str ( nat_ip_range ) + ' . ' + str ( nat_ip_subrange * 16 ) + ' /28 -j ' + subrange_name )
for nat_private_ip in range ( 256 ) :
ip_src = ' . ' . join ( nat_prive_ip_plage . split ( ' . ' ) [ : 2 ] ) + ' . ' + str ( nat_ip_range ) + ' . ' + str ( nat_private_ip ) + ' /32 '
port_low = 10000 + 2000 * ( nat_private_ip % 26 )
port_high = port_low + 1999
subrange_name = range_name + ' _ ' + str ( hex ( nat_private_ip / 16 ) [ 2 : ] )
# On nat
for interface in self . config_firewall . nat_pub_ip_plage [ nat_type ] :
ip_nat = ' . ' . join ( self . config_firewall . nat_pub_ip_plage [ nat_type ] [ interface ] . split ( ' . ' ) [ : 3 ] ) + ' . ' + str ( 10 * ( nat_ip_range - 1 ) + nat_private_ip / 26 )
self . add_in_subtable ( " nat " , subrange_name , ' -s %s -o %s -p tcp -j SNAT --to-source %s ' % ( ip_src , self . dev [ interface ] , ip_nat + ' : ' + str ( port_low ) + ' - ' + str ( port_high ) ) )
self . add_in_subtable ( " nat " , subrange_name , ' -s %s -o %s -p udp -j SNAT --to-source %s ' % ( ip_src , self . dev [ interface ] , ip_nat + ' : ' + str ( port_low ) + ' - ' + str ( port_high ) ) )
# On nat tout ce qui match dans les règles et qui n'est pas du tcp/udp derrière la première ip publique unused (25*10) + 1
# Ne pas oublier de loguer ce qui sort de cette ip
for interface in self . config_firewall . nat_pub_ip_plage [ nat_type ] :
self . add_in_subtable ( " nat " , subtable , ' -s ' + nat_prive_ip_plage + ' -o %s -j SNAT --to-source ' % ( self . dev [ interface ] , ) + ' . ' . join ( self . config_firewall . nat_pub_ip_plage [ nat_type ] [ interface ] . split ( ' . ' ) [ : 3 ] ) + ' .250 ' )
def gen_mangle ( self , empty = False ) :
""" Génération de la chaine mangle """
self . init_mangle ( " PREROUTING " )
self . init_mangle ( " INPUT " )
self . init_mangle ( " FORWARD " )
self . init_mangle ( " OUTPUT " )
self . init_mangle ( " POSTROUTING " )
if not empty :
for role in self . role :
if hasattr ( self , role ) :
getattr ( self , role ) ( ' mangle ' )
self . commit_mangle ( )
def restore_iptables ( self , mode = ' 4 ' ) :
""" Restoration de l ' iptable générée """
if mode == ' 6 ' :
global_chain = self . nat6 + self . filter6 + self . mangle6
command_to_execute = [ " sudo " , " -n " , " /sbin/ip6tables-restore " ]
else :
return False
def login_hp ( self ) :
""" Login into rest interface of this switch """
url_login = " http:// " + self . switch [ " ipv4 " ] + " /rest/v3/login-sessions "
payload_login = {
" userName " : self . creds_dict [ " id " ] ,
" password " : self . creds_dict [ " pass " ]
}
get_cookie = requests . post ( url_login , data = json . dumps ( payload_login ) )
cookie = get_cookie . json ( ) [ ' cookie ' ]
self . headers = { " Cookie " : cookie }
def apply_conf_hp ( self ) :
""" Apply config restore via rest """
url_restore = " http:// " + self . switch [ " ipv4 " ] + " /rest/v4/system/config/cfg_restore "
provision_mode = self . settings [ " switchs_provision " ]
if provision_mode == " tftp " :
data = {
" server_type " : " ST_TFTP " ,
" file_name " : self . get_conf_file_name ( ) ,
" tftp_server_address " : {
" server_address " : {
" ip_address " : {
" version " : " IAV_IP_V4 " ,
" octets " : self . settings [ " switchs_management_interface_ip " ] } } } ,
" is_forced_reboot_enabled " : True ,
}
elif provision_mode == " sftp " :
data = {
" server_type " : " ST_SFTP " ,
" file_name " : self . get_conf_file_name ( ) ,
" tftp_server_address " : {
" server_address " : {
" ip_address " : {
" version " : " IAV_IP_V4 " ,
" octets " : self . settings [ " switchs_management_interface_ip " ] } } ,
" user_name " : self . settings [ " switchs_management_sftp_creds " ] [ " login " ] ,
" password " : self . settings [ " switchs_management_sftp_creds " ] [ " pass " ] ,
} ,
" is_forced_reboot_enabled " : True ,
}
# Nous lançons la requête de type POST.
post_restore = requests . post ( url_restore , data = json . dumps ( data ) , headers = self . headers )
def gen_conf_and_write ( self ) :
""" Génère la conf suivant le bon constructeur et l ' écrit """
if self . switch [ " model " ] :
constructor = self . switch [ " model " ] [ " constructor " ] . lower ( )
if " hp " in constructor or " aruba " in constructor :
self . gen_conf_hp ( )
self . write_conf ( )
def apply_conf ( self ) :
if self . check_and_get_login ( ) :
if self . switch [ " model " ] and self . switch [ " automatic_provision " ] == True and self . settings [ " provision_switchs_enabled " ] :
constructor = self . switch [ " model " ] [ " constructor " ] . lower ( )
if " hp " in constructor or " aruba " in constructor :
self . login_hp ( )
self . apply_conf_hp ( )
def write_conf ( self ) :
""" Ecriture de la conf du switch dans le fichier qui va bien """
with open ( " generated/ " + self . get_conf_file_name ( ) , ' w+ ' ) as f :
f . write ( self . conf )
global_chain = self . nat4 + self . filter4 + self . mangle4
command_to_execute = [ " sudo " , " -n " , " /sbin/iptables-restore " ]
process = subprocess . Popen ( command_to_execute , stdin = subprocess . PIPE , stdout = subprocess . PIPE )
process . communicate ( input = global_chain . encode ( ' utf-8 ' ) )
if self . export :
print ( global_chain )
def complete_flush_iptables ( self , mode = ' 4 ' ) :
""" Insère un parefeuv6 vide, appellé par l ' arrét du parefeu """
self . restore_iptables ( mode = mode )
def do_action ( self ) :
""" Effectue l ' action demandée """
if self . action == " start " or self . action == " restart " :
self . reload ( )
elif self . action == " stop " :
self . flush ( )
else :
raise NotImplementedError ( " Action non reconnu, actions valides : start, stop ou restart " )
def reload ( self ) :
""" Recharge le parefeu """
self . gen_mangle ( )
self . gen_nat ( )
self . gen_filter ( )
if any ( ' 6 ' in role for role in self . role ) :
self . restore_iptables ( mode = ' 6 ' )
return
if any ( ' 4 ' in role for role in self . role ) :
self . restore_iptables ( mode = ' 4 ' )
return
self . restore_iptables ( mode = ' 6 ' )
self . restore_iptables ( mode = ' 4 ' )
def flush ( self ) :
""" Vide la chaine iptables, ou ip6tables suivant le role du serveur """
self . gen_mangle ( empty = True )
self . gen_nat ( empty = True )
self . gen_filter ( empty = True )
if any ( ' 6 ' in role for role in self . role ) :
self . complete_flush_iptables ( mode = ' 6 ' )
if any ( ' 4 ' in role for role in self . role ) :
self . complete_flush_iptables ( mode = ' 4 ' )
self . restore_iptables ( mode = ' 6 ' )
self . restore_iptables ( mode = ' 4 ' )
def add_port ( self , ports , ip_cible , sens , protocole , subtable = ' FILTRAGE-PORTS ' , mode = ' 4 ' ) :
""" Ajout atomique d ' une ouverture de port
ports : liste des ports à ouvrir
sens : source ou destination
protocole : tcp ou udp
ip cible : ip où s ' applique l ' ouverture """
if sens == " source " :
self . atomic_add ( " filter " , subtable , """ - %s %s -p %s -m multiport --dports %s -j RETURN """ % ( ' s ' , ip_cible , protocole , ' , ' . join ( self . format_port ( port ) for port in ports ) ) , mode = mode )
if sens == " destination " :
self . atomic_add ( " filter " , subtable , """ - %s %s -p %s -m multiport --dports %s -j RETURN """ % ( ' d ' , ip_cible , protocole , ' , ' . join ( self . format_port ( port ) for port in ports ) ) , mode = mode )
def add_in_blacklist_hard ( self , mac , subtable = ' BLACKLIST-HARD ' , mode = ' 4 ' ) :
""" Ajoute la mac à la blacklist """
self . atomic_add ( " filter " , subtable , """ -m mac --mac-source %s -j REJECT """ % mac , mode = mode )
def del_in_blacklist_hard ( self , mac , subtable = ' BLACKLIST-HARD ' , mode = ' 4 ' ) :
""" Retire la mac de la blacklist """
self . atomic_del ( " filter " , subtable , """ -m mac --mac-source %s -j REJECT """ % mac , mode = mode )
if __name__ == ' __main__ ' :
parser = argparse . ArgumentParser ( )
parser . add_argument ( " -v " , " --verbose " , help = " increase output verbosity " , action = " store_true " )
parser . add_argument ( " -e " , " --export " , help = " export le contenu du parefeu " , action = " store_true " )
parser . add_argument ( " action " , help = " Mode reconnus : start, stop ou restart " )
args = parser . parse_args ( )
table = iptables ( )
if args . verbose :
table . verbose = True
table . action = args . action
table . export = args . export
table . do_action ( )
sw = Switch ( )