#!/usr/bin/env python '''Funzioni usate dai vari programmi eslock''' __version__ = "$Revision: 0.6 $" import pika import logging import logging.handlers import re import shlex import subprocess import os import yaml import json from socket import gethostname from pika import exceptions from subprocess import CalledProcessError, PIPE from netaddr import IPNetwork, IPAddress, AddrFormatError logger = logging.getLogger(__name__) def manage_config(config_file, default_config): '''Leggi il file di configurazione.''' try: fp = open(config_file) except IOError: write_config(default_config, config_file) return default_config try: config_from_file = yaml.load(fp) except ValueError: print('Errori nel file di configurazione: '+config_file) raise SystemExit return dict(default_config.items()+config_from_file.items()) def write_config(default_config, config_file): """scrivi file di configurazione con i defaults""" try: fp = open(config_file, 'w') except (OSError, IOError) as e: print('problemi con il file di configurazione: '+str(e)) raise SystemExit yaml.dump(default_config, fp, default_flow_style=False) def set_logger(log_file, log_level_main, log_level_file, log_level_console, log_backupcounter): """setta il logger, sia come file che console""" levels = {'CRITICAL': 50, 'ERROR': 40, 'WARNING': 30, 'INFO': 20, 'DEBUG': 10, 'NOTSET': 0} logger = logging.getLogger(__name__) logger.setLevel(levels[log_level_main]) fh = logging.handlers.TimedRotatingFileHandler( log_file, when='midnight', backupCount=(log_backupcounter)) formatter = logging.Formatter(fmt='%(asctime)s %(levelname)s: %(message)s', datefmt='%Y-%m-%dT%H:%M:%S') fh.setFormatter(formatter) fh.setLevel(levels[log_level_file]) logger.addHandler(fh) ch = logging.StreamHandler() ch.setLevel(levels[log_level_console]) logger.addHandler(ch) logger.propagate = False # load whitelist here and not in manage_config to have logger configured load_whitelist() return logger def open_connection(rmq_user, rmq_pwd, rmq_host, rmq_port, rmq_vhost, rmq_heartbeat): """apre la connessione con rabbitmq""" credentials = pika.PlainCredentials(rmq_user, rmq_pwd) parameters = pika.ConnectionParameters(host=rmq_host, port=rmq_port, virtual_host=rmq_vhost, heartbeat_interval=rmq_heartbeat, credentials=credentials) try: conn = pika.BlockingConnection(parameters) return conn except exceptions.AMQPConnectionError as e: logger.error('Non riesco a connettermi a '+rmq_host+': '+str(e)) return False def validate_blacklist(ip_list, is_net=False): """valida la lista di indirizzi per evitare di bloccare roba pericolosa ritorna una lista contenente solo indirizzi che vanno bene. Elimina anche gli indirizzi delle reti dada""" purged = [] for item in ip_list: if validate_ip(item, is_net): purged.append(item) return purged def load_whitelist(): global whitelist whitelist = {} logger.info('Loading whitelist from /etc/eslock/whitelist.json') try: with open('/etc/eslock/whitelist.json') as handle: whitelist = json.loads(handle.read()) logger.info('Whitelist loaded') except EnvironmentError as e: logger.warn('Whitelist load error: %s' % str(e)) pass logger.info(whitelist) def check_whitelist_ip(ip_address): for address in whitelist.keys(): # logger.debug(address) # logger.debug(whitelist[address][1]) # logger.debug(whitelist[address][0]) if whitelist[address][1] == "net": c_ip = IPNetwork(whitelist[address][0]) else: c_ip = IPAddress(whitelist[address][0]) if ip_address in IPNetwork(whitelist[address][0]): # print "Is ours " + str(ip_address) return False if c_ip in IPNetwork(ip_address): # print "Is ours2 " + str(ip_address) return False return True def validate_ip(ip_address, is_net=False): pattern = r"\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b" if re.match(pattern, ip_address): try: if is_net: ip = IPNetwork(ip_address) # if ip.size > 256: # logger.warn('Too much ip address to blacklist (>256) :' # +ip_address) # return False else: ip = IPAddress(ip_address) if ip.is_private(): logger.warn('Is private :'+ip_address) return False elif (not check_whitelist_ip(ip)): logger.warn('Is ours '+ip_address) return False elif (ip in IPNetwork('92.103.17.202')): # RT 670644 logger.warn('Whitelisted '+ip_address) return False elif (ip in IPNetwork('199.83.128.0/21') or ip in IPNetwork('198.143.32.0/19') or ip in IPNetwork('149.126.72.0/21') or ip in IPNetwork('103.28.248.0/22') or ip in IPNetwork('185.11.124.0/22') or ip in IPNetwork('192.230.64.0/18') or ip in IPNetwork('45.64.64.0/22') or ip in IPNetwork('107.154.126.0/24')): logger.warn('Whitelisted (SiteLocK)'+ip_address) return False elif ip.is_loopback(): logger.warn('Is loopback '+ip_address) return False if not is_net: if ip.is_netmask(): logger.warn('Is netmask '+ip_address) return False elif ip.is_hostmask(): logger.warn('Is hostmask '+ip_address) return False return True except AddrFormatError: logger.warn('Format Error: '+ip_address) return False else: logger.warn('Is invalid: '+ip_address) return False def create_ipset(name, set_type='hash:ip', hashsize=4096, timeout=3600, maxelem=65536): """crea ipset se non esistente""" FNULL = open(os.devnull, 'w') name = 'bl_'+name commandline = str('ipset list --terse -name -q '+name) logger.debug('command line to check for set existence: '+commandline) if subprocess.call(shlex.split(commandline), stdout=FNULL) == 0: logger.debug('ipset already present: '+name) return True else: try: if timeout: commandline = str('ipset create ' + name + ' '+set_type + ' hashsize '+str(hashsize) + ' timeout '+str(timeout) + ' maxelem '+str(maxelem)) else: commandline = str('ipset create ' + name + ' '+set_type + ' hashsize '+str(hashsize) + ' maxelem '+str(maxelem)) logger.debug('command line to create set: '+commandline) subprocess.check_call(shlex.split(commandline), stdout=FNULL) except CalledProcessError: logger.critical('set creation error '+name) return False logger.info('set created: '+name) return True def add_ipset_line(ip, ipset, timeout=0, comment=''): """aggiunge in indirizzo al set desiderato""" ipset = 'bl_'+ipset FNULL = open(os.devnull, 'w') commandline = str('ipset -exist add %(name)s %(ip)s' % {'name': ipset, 'ip': ip}) if timeout: commandline += str(' timeout %(t)d' % {'t': timeout}) if comment: commandline += str(' comment %(c)d' % {'c': comment}) try: subprocess.check_call(shlex.split(commandline), stdout=FNULL) except CalledProcessError: logger.debug('Commandline: '+commandline) logger.error('Failed to add member '+ip+' to set '+ipset) return False return True def del_ipset_line(ip, ipset): """rimuove un indirizzo dal set desiderato""" ipset = 'bl_'+ipset FNULL = open(os.devnull, 'w') try: commandline = str('ipset -exist del %(name)s %(ip)s' % {'name': ipset, 'ip': ip}) subprocess.check_call(shlex.split(commandline), stdout=FNULL) except CalledProcessError: logger.error('Failed to remove member '+ip+' from set '+ipset) return False return True def add_ipset_bulk(ip_list, ipset): """aggiungo una lista di indirizzi al set indicato""" ipset = 'bl_'+ipset logger.debug('Procedo al caricamento bulk sul set '+ipset) listona = [] for item in ip_list: listona.append('add %(ipset)s %(ip)s\n' %{'ipset': ipset, 'ip':item}) stringona = ''.join(listona) commandline = str('ipset -exist restore') try: p = subprocess.Popen(shlex.split(commandline), stdin=PIPE, stdout=PIPE, stderr=PIPE) except CalledProcessError: logger.debug('Failed to Popen for add address to set '+ipset) return False try: (stdoutdata, stderrdata) = p.communicate(input=stringona) except (IOError, OSError): logger.debug('Error while bulk adding address to set '+ipset) logger.debug('stdout:'+stdoutdata) logger.debug('stderr:'+stderrdata) return False if p.returncode != 0: logger.debug('Failed to bulk add address to set '+ipset) return False return True def get_cluster(): """Restituisco il nome del cluster secondo la convenzione register""" cluster = re.match(r"^(.+?)\d+", gethostname()) if cluster: return cluster.group(1) else: return False