#! /usr/bin/env python
# -*- coding: utf-8 -*-
###########################################################################
# Eole NG
# Copyright Pole de Competence Eole  (Ministere Education - Academie Dijon)
# Licence CeCill  cf /root/LicenceEole.txt
# eole@ac-dijon.fr
#
# gestion des taches d'interdiction du matin et du soir
# horaires.firewall
#
###########################################################################

"""horaires du pare-feu

%prog <modele Era>"""

from optparse import OptionParser
from os.path import isfile
import socket
authorized_ports = [4200, 8090, 7080, 22, 53]

def parse_cmd_line():
    """parsing de la ligne de commande"""
    parser = OptionParser(__doc__, version = '%prog v1.0')
    parser.add_option("-i", "--input",
                      dest = "input_filename", default = "horaires.txt",
                      help = "Fichier horaires a renseigner",
                      metavar = "INPUT_FILE")
    options, args = parser.parse_args()
    return options

RULES = """
/sbin/iptables -nL |grep "nuit-" 2>&1 >/dev/null

if [ $? == "0" ]
then
/sbin/iptables -F nuit-input
/sbin/iptables -F nuit-forward
/sbin/iptables -D FORWARD -j nuit-forward
/sbin/iptables -D INPUT -j  nuit-input
/sbin/iptables -X nuit-forward
/sbin/iptables -X nuit-input
fi

/sbin/iptables -N nuit-input
/sbin/iptables -N nuit-forward
/sbin/iptables -t filter -A nuit-input -m state --state ESTABLISHED,RELATED -j ACCEPT
/sbin/iptables -t filter -A nuit-forward -m state --state ESTABLISHED,RELATED -j ACCEPT
%s
%s
"""

def run():
    """script en mode ligne de commande"""
    options  = parse_cmd_line()
    input_file = options.input_filename
    if is_well_formed(input_file):
        print RULES % ("\n".join(list(get_rules())), "\n".join(list(gen_scheduled_rules(input_file))))

## GENERATION DE REGLE
"""dictionnaire mapping code de jour et jour en syntaxe iptables -m time"""
DAYS = {'0':'Sun', '1':'Mon', '2':'Tue', '3':'Wed', '4':'Thu', '5':'Fri', '6':'Sat', '7':'Sun'}

def gen_scheduled_rules(input_file):
    """
        règles d'application des chaine nuit-input et de la chaine nuit-forward
        s'applique que entre begin et end
    """
    for day, begin, end in split_lines(input_file):
        begin = "%s:00"%begin
        end = "%s:00"%end
        # gestion des cas ipttime bizard (from 0:00 to 0:00 coupe toute la journée)
        if begin == "0:00":
            begin = "0:01"
        if end == "24:00":
            end = "23:58"
        if '-' not in begin:
            yield "/sbin/iptables -I INPUT -m time --timestart %s --timestop %s --weekdays %s -j nuit-input" % ('0:0', begin, DAYS[day])
            yield "/sbin/iptables -I FORWARD -m time --timestart %s --timestop %s --weekdays %s -j nuit-forward" % ('0:0', begin, DAYS[day])
        if '-' not in end:
            yield "/sbin/iptables -I INPUT -m time --timestart %s --timestop %s --weekdays %s -j nuit-input" % (end, '23:59', DAYS[day])
            yield "/sbin/iptables -I FORWARD -m time --timestart %s --timestop %s --weekdays %s -j nuit-forward" % (end, '23:59', DAYS[day])

def get_rules():
    """
        génère les règles de nuit:
        - autorise les sites de mises à jour
        - autorise le proxy pour des ips configurées
        - autorise les ips autorisées à se connecter en ssh et sur l'ead2
        - interdit le reste
    """
    # autorisation des ports configurés
    for ip, netmask, interface in soir_firewall():
        for ip_netmask in make_ip_netmask_str(ip, netmask):
            for port in get_ports():
                yield "/sbin/iptables -A nuit-input -p tcp -i %s -s %s --dport %s -j ACCEPT" % (interface, ip_netmask, port)
        yield "/sbin/iptables -A nuit-input -i %s -j DROP" %interface
        yield "/sbin/iptables -A nuit-forward -i %s -j DROP" %interface


## UTILITAIRES

def get_proxied():
    """
        renvoie la liste des ips ayant droit à un accès au proxy
    """
    return []

def get_ports():
    """
        renvoie la liste de ports pour laquelle on a des exceptions de fermeture de firewall
    """
    f_name = "/usr/share/ead2/backend/tmp/firewall_schedule_ports.txt"
    result = authorized_ports
    if isfile(f_name):
        ports = file(f_name).read().splitlines()
        for port in ports:
            try:
                port = int(port)
                if port < 65635 and port not in result:
                    result.append(port)
            except:
                pass
    return result

def is_well_formed(input_file):
    """teste l'intégrité du fichier horaires"""
    if isfile(input_file):
        for jour, debut, fin in split_lines(input_file):
            rg = [str(i) for i in range(0, 24)]
            rg.append('-')
            if jour not in rg or debut not in rg or fin not in rg:
                return False
        return True
    else:
        return False

def split_lines(input_file):
    for ligne in file(input_file, 'r').read().splitlines():
        jour, debut, fin = ligne.split()
        jour, debut, fin = jour, debut, fin
        yield jour, debut, fin

def get_interfaces(dico):
    """recupere depuis le dico creole toutes les interfaces"""
    return ["eth%s" % interface for interface in range(int(dico['nombre_interfaces']))]

def get_ip_netmask(interface, dico):
    if dico["ssh_%s"% interface] == "oui":
        ips= dico['ip_ssh_%s'%interface]
        netmask = dico['netmask_ssh_%s'%interface]
        return ips, netmask
    return "", ""

def make_ip_netmask_str(ips, netmasks):
    """
        construit les string ip/netmask et gère les cas ips = list et netmask =string ...
    """
    if netmasks:
        if hasattr(ips, '__iter__') and not hasattr(netmasks, '__iter__'): # cas rencontré (erreur parse dico maitre/esclave)
            netmasks = (netmasks,)
        if hasattr(netmasks, '__iter__') and not hasattr(ips, '__iter__'):
            ips = (ips,)
        if hasattr(netmasks, '__iter__'):
            for index, ip in enumerate(ips):
                str = "%s/%s" % (ip, netmasks[index])
                yield str
        else:
            str = "%s/%s" % (ips, netmasks)
            yield str

def soir_firewall():
    """
        renvoie les ips, netmasks par interface
    """
    try:
        from creole.parsedico import parse_dico
    except:
        raise ImportError, "Pas de creole sur la machine"

    creole_dict = parse_dico()
    for interface in get_interfaces(creole_dict):
        ips, netmask = get_ip_netmask(interface, creole_dict)
        yield ips, netmask, interface

if __name__ == '__main__':
    class bcolors:
        HEADER = '\033[95m'
        OKBLUE = '\033[94m'
        OKGREEN = '\033[92m'
        WARNING = '\033[93m'
        FAIL = '\033[91m'
        ENDC = '\033[0m'
    
    print bcolors.WARNING + \
"ATTENTION, Les horaires de pare-feu ne sont plus pris en compte" \
+ bcolors.ENDC
    
    #run()
