"""
security.py: defines security services (vpnclient, vpnserver, ipsec and
firewall)
"""

import logging

from core import constants
from core.services.coreservices import CoreService


class VPNClient(CoreService):
    name = "VPNClient"
    group = "Security"
    configs = ("vpnclient.sh",)
    startup = ("sh vpnclient.sh",)
    shutdown = ("killall openvpn",)
    validate = ("pidof openvpn",)
    custom_needed = True

    @classmethod
    def generate_config(cls, node, filename):
        """
        Return the client.conf and vpnclient.sh file contents to
        """
        cfg = "#!/bin/sh\n"
        cfg += "# custom VPN Client configuration for service (security.py)\n"
        fname = "%s/examples/services/sampleVPNClient" % constants.CORE_DATA_DIR

        try:
            cfg += open(fname, "rb").read()
        except IOError:
            logging.exception(
                "Error opening VPN client configuration template (%s)", fname
            )

        return cfg


class VPNServer(CoreService):
    name = "VPNServer"
    group = "Security"
    configs = ("vpnserver.sh",)
    startup = ("sh vpnserver.sh",)
    shutdown = ("killall openvpn",)
    validate = ("pidof openvpn",)
    custom_needed = True

    @classmethod
    def generate_config(cls, node, filename):
        """
        Return the sample server.conf and vpnserver.sh file contents to
        GUI for user customization.
        """
        cfg = "#!/bin/sh\n"
        cfg += "# custom VPN Server Configuration for service (security.py)\n"
        fname = "%s/examples/services/sampleVPNServer" % constants.CORE_DATA_DIR

        try:
            cfg += open(fname, "rb").read()
        except IOError:
            logging.exception(
                "Error opening VPN server configuration template (%s)", fname
            )

        return cfg


class IPsec(CoreService):
    name = "IPsec"
    group = "Security"
    configs = ("ipsec.sh",)
    startup = ("sh ipsec.sh",)
    shutdown = ("killall racoon",)
    custom_needed = True

    @classmethod
    def generate_config(cls, node, filename):
        """
        Return the ipsec.conf and racoon.conf file contents to
        GUI for user customization.
        """
        cfg = "#!/bin/sh\n"
        cfg += "# set up static tunnel mode security assocation for service "
        cfg += "(security.py)\n"
        fname = "%s/examples/services/sampleIPsec" % constants.CORE_DATA_DIR
        try:
            with open(fname, "r") as f:
                cfg += f.read()
        except IOError:
            logging.exception("Error opening IPsec configuration template (%s)", fname)
        return cfg


class Firewall(CoreService):
    name = "Firewall"
    group = "Security"
    configs = ("firewall.sh",)
    startup = ("sh firewall.sh",)
    custom_needed = True

    @classmethod
    def generate_config(cls, node, filename):
        """
        Return the firewall rule examples to GUI for user customization.
        """
        cfg = "#!/bin/sh\n"
        cfg += "# custom node firewall rules for service (security.py)\n"
        fname = "%s/examples/services/sampleFirewall" % constants.CORE_DATA_DIR

        try:
            cfg += open(fname, "rb").read()
        except IOError:
            logging.exception(
                "Error opening Firewall configuration template (%s)", fname
            )

        return cfg


class Nat(CoreService):
    """
    IPv4 source NAT service.
    """

    name = "NAT"
    executables = ("iptables",)
    group = "Security"
    configs = ("nat.sh",)
    startup = ("sh nat.sh",)
    custom_needed = False

    @classmethod
    def generateifcnatrule(cls, ifc, line_prefix=""):
        """
        Generate a NAT line for one interface.
        """
        cfg = line_prefix + "iptables -t nat -A POSTROUTING -o "
        cfg += ifc.name + " -j MASQUERADE\n"

        cfg += line_prefix + "iptables -A FORWARD -i " + ifc.name
        cfg += " -m state --state RELATED,ESTABLISHED -j ACCEPT\n"

        cfg += line_prefix + "iptables -A FORWARD -i "
        cfg += ifc.name + " -j DROP\n"
        return cfg

    @classmethod
    def generate_config(cls, node, filename):
        """
        NAT out the first interface
        """
        cfg = "#!/bin/sh\n"
        cfg += "# generated by security.py\n"
        cfg += "# NAT out the first interface by default\n"
        have_nat = False
        for ifc in node.netifs():
            if hasattr(ifc, "control") and ifc.control is True:
                continue
            if have_nat:
                cfg += cls.generateifcnatrule(ifc, line_prefix="#")
            else:
                have_nat = True
                cfg += "# NAT out the " + ifc.name + " interface\n"
                cfg += cls.generateifcnatrule(ifc)
                cfg += "\n"
        return cfg
