Subversion Repositories configs

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :

# This file is part of Fail2Ban.
#
# Fail2Ban is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# Fail2Ban is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Fail2Ban; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

import socket
import smtplib
from email.mime.text import MIMEText
from email.utils import formatdate, formataddr

from fail2ban.server.actions import ActionBase, CallingMap

messages = {}
messages['start'] = \
"""Hi,

The jail %(jailname)s has been started successfully.

Regards,
Fail2Ban"""

messages['stop'] = \
"""Hi,

The jail %(jailname)s has been stopped.

Regards,
Fail2Ban"""

messages['ban'] = {}
messages['ban']['head'] = \
"""Hi,

The IP %(ip)s has just been banned for %(bantime)i seconds
by Fail2Ban after %(failures)i attempts against %(jailname)s.
"""
messages['ban']['tail'] = \
"""
Regards,
Fail2Ban"""
messages['ban']['matches'] = \
"""
Matches for this ban:
%(matches)s
"""
messages['ban']['ipmatches'] = \
"""
Matches for %(ip)s:
%(ipmatches)s
"""
messages['ban']['ipjailmatches'] = \
"""
Matches for %(ip)s for jail %(jailname)s:
%(ipjailmatches)s
"""

class SMTPAction(ActionBase):
        """Fail2Ban action which sends emails to inform on jail starting,
        stopping and bans.
        """

        def __init__(
                self, jail, name, host="localhost", user=None, password=None,
                sendername="Fail2Ban", sender="fail2ban", dest="root", matches=None):
                """Initialise action.

                Parameters
                ----------
                jail : Jail
                        The jail which the action belongs to.
                name : str
                        Named assigned to the action.
                host : str, optional
                        SMTP host, of host:port format. Default host "localhost" and
                        port "25"
                user : str, optional
                        Username used for authentication with SMTP server.
                password : str, optional
                        Password used for authentication with SMTP server.
                sendername : str, optional
                        Name to use for from address in email. Default "Fail2Ban".
                sender : str, optional
                        Email address to use for from address in email.
                        Default "fail2ban".
                dest : str, optional
                        Email addresses of intended recipient(s) in comma space ", "
                        delimited format. Default "root".
                matches : str, optional
                        Type of matches to be included from ban in email. Can be one
                        of "matches", "ipmatches" or "ipjailmatches". Default None
                        (see man jail.conf.5).
                """

                super(SMTPAction, self).__init__(jail, name)

                self.host = host
                #TODO: self.ssl = ssl

                self.user = user
                self.password =password

                self.fromname = sendername
                self.fromaddr = sender
                self.toaddr = dest

                self.matches = matches

                self.message_values = CallingMap(
                        jailname = self._jail.name,
                        hostname = socket.gethostname,
                        bantime = self._jail.actions.getBanTime,
                        )

        def _sendMessage(self, subject, text):
                """Sends message based on arguments and instance's properties.

                Parameters
                ----------
                subject : str
                        Subject of the email.
                text : str
                        Body of the email.

                Raises
                ------
                SMTPConnectionError
                        Error on connecting to host.
                SMTPAuthenticationError
                        Error authenticating with SMTP server.
                SMTPException
                        See Python `smtplib` for full list of other possible
                        exceptions.
                """
                msg = MIMEText(text)
                msg['Subject'] = subject
                msg['From'] = formataddr((self.fromname, self.fromaddr))
                msg['To'] = self.toaddr
                msg['Date'] = formatdate()

                smtp = smtplib.SMTP()
                try:
                        self._logSys.debug("Connected to SMTP '%s', response: %i: %s",
                                self.host, *smtp.connect(self.host))
                        if self.user and self.password:
                                smtp.login(self.user, self.password)
                        failed_recipients = smtp.sendmail(
                                self.fromaddr, self.toaddr.split(", "), msg.as_string())
                except smtplib.SMTPConnectError:
                        self._logSys.error("Error connecting to host '%s'", self.host)
                        raise
                except smtplib.SMTPAuthenticationError:
                        self._logSys.error(
                                "Failed to authenticate with host '%s' user '%s'",
                                self.host, self.user)
                        raise
                except smtplib.SMTPException:
                        self._logSys.error(
                                "Error sending mail to host '%s' from '%s' to '%s'",
                                self.host, self.fromaddr, self.toaddr)
                        raise
                else:
                        if failed_recipients:
                                self._logSys.warning(
                                        "Email to '%s' failed to following recipients: %r",
                                        self.toaddr, failed_recipients)
                        self._logSys.debug("Email '%s' successfully sent", subject)
                finally:
                        try:
                                self._logSys.debug("Disconnected from '%s', response %i: %s",
                                        self.host, *smtp.quit())
                        except smtplib.SMTPServerDisconnected:
                                pass # Not connected

        def start(self):
                """Sends email to recipients informing that the jail has started.
                """
                self._sendMessage(
                        "[Fail2Ban] %(jailname)s: started on %(hostname)s" %
                                self.message_values,
                        messages['start'] % self.message_values)

        def stop(self):
                """Sends email to recipients informing that the jail has stopped.
                """
                self._sendMessage(
                        "[Fail2Ban] %(jailname)s: stopped on %(hostname)s" %
                                self.message_values,
                        messages['stop'] % self.message_values)

        def ban(self, aInfo):
                """Sends email to recipients informing that ban has occurred.

                Parameters
                ----------
                aInfo : dict
                        Dictionary which includes information in relation to
                        the ban.
                """
                aInfo.update(self.message_values)
                message = "".join([
                        messages['ban']['head'],
                        messages['ban'].get(self.matches, ""),
                        messages['ban']['tail']
                        ])
                self._sendMessage(
                        "[Fail2Ban] %(jailname)s: banned %(ip)s from %(hostname)s" %
                                aInfo,
                        message % aInfo)

Action = SMTPAction