aboutsummaryrefslogtreecommitdiff
path: root/straper/db/public/fail2ban/etc-fail2ban/action.d/smtp.py
diff options
context:
space:
mode:
Diffstat (limited to 'straper/db/public/fail2ban/etc-fail2ban/action.d/smtp.py')
-rw-r--r--straper/db/public/fail2ban/etc-fail2ban/action.d/smtp.py240
1 files changed, 240 insertions, 0 deletions
diff --git a/straper/db/public/fail2ban/etc-fail2ban/action.d/smtp.py b/straper/db/public/fail2ban/etc-fail2ban/action.d/smtp.py
new file mode 100644
index 0000000..40eda1b
--- /dev/null
+++ b/straper/db/public/fail2ban/etc-fail2ban/action.d/smtp.py
@@ -0,0 +1,240 @@
+# 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", ssl=False, 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"
+ ssl : bool, optional
+ Whether to use TLS for the SMTP connection or not. Default False.
+ 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
+ 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 = lambda: self._jail.actions.getBanTime(),
+ )
+
+ # bypass ban/unban for restored tickets
+ self.norestored = 1
+
+ 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_host, smtp_port = self.host.split(':')
+ smtp = smtplib.SMTP(host=smtp_host, port=smtp_port)
+ try:
+ r = smtp.connect(host=smtp_host, port=smtp_port)
+ self._logSys.debug("Connected to SMTP '%s', response: %i: %s",
+ self.host, *r)
+
+ if self.ssl: # pragma: no cover
+ r = smtp.starttls()[0];
+ if r != 220: # pragma: no cover
+ raise Exception("Failed to starttls() on '%s': %s" % (self.host, r))
+
+ if self.user and self.password: # pragma: no cover (ATM no tests covering that)
+ smtp.login(self.user, self.password)
+ failed_recipients = smtp.sendmail(
+ self.fromaddr, self.toaddr.split(", "), msg.as_string())
+ except smtplib.SMTPConnectError: # pragma: no cover
+ self._logSys.error("Error connecting to host '%s'", self.host)
+ raise
+ except smtplib.SMTPAuthenticationError: # pragma: no cover
+ self._logSys.error(
+ "Failed to authenticate with host '%s' user '%s'",
+ self.host, self.user)
+ raise
+ except smtplib.SMTPException: # pragma: no cover
+ self._logSys.error(
+ "Error sending mail to host '%s' from '%s' to '%s'",
+ self.host, self.fromaddr, self.toaddr)
+ raise
+ else:
+ if failed_recipients: # pragma: no cover
+ 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: # pragma: no cover
+ 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.
+ """
+ if aInfo.get('restored'):
+ return
+ 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