Skip to content

Commit

Permalink
Added new ellis_actions module : mail.
Browse files Browse the repository at this point in the history
Also updated a few things.
  • Loading branch information
Frzk committed Jun 20, 2018
1 parent 03ae3ba commit d7f2900
Show file tree
Hide file tree
Showing 7 changed files with 157 additions and 11 deletions.
2 changes: 1 addition & 1 deletion ellis/action.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ async def run(self, kwargs=None):
await task
except Exception as e:
# FIXME: write a better Exception handler.
print("EXC:\n {0}".format(e))
raise e

@classmethod
def from_string(cls, action_str):
Expand Down
6 changes: 4 additions & 2 deletions ellis/ellis.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,11 +232,13 @@ def exit(self):
def exceptions_handler(self, loop, context):
"""
"""
exception = context['exception']

print("CAUGHT EXCEPTION:\n")
print(" Message: {0}\n".format(context['message']))

try:
print(" Exception: {0}\n".format(context['exception']))
print(" Future: {0}".format(context['future']))
print(" Future: {0}\n".format(context['future']))
print(" Exception: {0}".format(exception))
except:
pass
10 changes: 5 additions & 5 deletions ellis_actions/ipset.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ async def add(self, setname, ip, timeout=0):
The resulting command looks like this:
``ipset add -exist rig_blacklist4 192.0.2.10 timeout 14400``
``ipset add -exist ellis_blacklist4 192.0.2.10 timeout 14400``
"""
args = ['add', '-exist', setname, ip, 'timeout', timeout]
Expand All @@ -57,7 +57,7 @@ async def list(self, setname=None):
The resulting command looks like one of the following:
* ``ipset list``
* ``ipset list rig_blacklist4``
* ``ipset list ellis_blacklist4``
"""
args = ['list']
Expand All @@ -71,13 +71,13 @@ def chose_blacklist(self, ip):
"""
Given an IP address, figure out the ipset we have to use.
If the address is an IPv4, we have to use *rig_blacklist4*.
If the address is an IPv6, we have to use *rig_blacklist6*.
If the address is an IPv4, we have to use *ellis_blacklist4*.
If the address is an IPv6, we have to use *ellis_blacklist6*.
Raises ipaddress.AddressValueError if the address is neither
an IPv4 nor an IPv6.
"""
blacklist = 'rig_blacklist{0}'
blacklist = 'ellis_blacklist{0}'

try:
address = ipaddress.ip_address(ip)
Expand Down
39 changes: 39 additions & 0 deletions ellis_actions/mail.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#!/usr/bin/env python
# coding: utf-8


import asyncio

from smtplibaio import SMTP


async def send(from_addr, to_addrs, subject="Ellis", msg="", **kwargs):
"""
Sends an e-mail to the provided address.
:param from_addr: E-mail address of the sender.
:type from_addr: str
:param to_addrs: E-mail address(es) of the receiver(s).
:type to_addrs: list or str
:param msg: Message to be sent.
:type msg: str
"""
async with SMTP() as client:
msg = "Subject: {0}\n\n{1}".format(subject, msg)

if kwargs:
# To append kwargs to the given message, we first
# transform it into a more human friendly string:
values = "\n".join(["{0}: {1}".format(k, v)
for k, v
in kwargs.items()])

# Actually append caught values to the message:
msg = ("{0}\n\nThe following variables have been caught:"
"\n{1}".format(msg, values))

try:
await client.sendmail(from_addr, to_addrs, msg)
except:
# FIXME: print a friendly message to stdout.
raise
105 changes: 105 additions & 0 deletions ellis_actions/nftables.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#!/usr/bin/env python
# coding: utf-8

import ipaddress

from .shell_commander import ShellCommander


class NFTablesSetNotFound(Exception):
pass


class NFTables(ShellCommander):
"""
"""
CMD = 'nft'

def __init__(self, tablename):
"""
"""
super().__init__()

self.tablename = tablename

async def add(self, setname, ip, timeout):
"""
Adds the given IP address to the specified set.
If timeout is specified, the IP will stay in the set for the given
duration. Else it will stay in the set during the set default timeout.
timeout must be given in seconds.
The resulting command looks like this:
``nft add element inet firewall ellis_blacklist4 { 192.0.2.10 timeout 30s }``
"""
# We have to double-quote the '{' '}' at both ends for `format` to work.
to_ban = "{{ {0} timeout {1}s }}".format(ip, timeout)

args = ['add', 'element', 'inet', self.tablename, setname, to_ban]

return await self.start(__class__.CMD, *args)

def chose_blacklist(self, ip):
"""
Given an IP address, figure out the set we have to use.
If the address is an IPv4, we have to use *ellis_blacklist4*.
If the address is an IPv6, we have to use *ellis_blacklist6*.
Raises ipaddress.AddressValueError if the address is neither
an IPv4 nor an IPv6.
"""
blacklist = 'ellis_blacklist{0}'

try:
address = ipaddress.ip_address(ip)
except ipaddress.AddressValueError:
raise
else:
if address.version is 6:
# We don't ban private IPv6:
if address.is_private:
msg = "We don't ban private addresses ({0} given)." \
.format(address)
raise ipaddress.AddressValueError(msg)
else:
# Do we have an embedded IPv4 ?
if address.ipv4_mapped is not None:
address = address.ipv4_mapped
elif address.sixtofour is not None:
address = address.sixtofour

blacklist = blacklist.format(address.version)

return (address, blacklist)

def handle_error(self, err):
"""
"""
msg = err.decode()

print("FIXME (raise a custom Exception) - {}".format(msg))
"""
if "Kernel error received: Operation not permitted" in msg:
raise IpsetNoRights(msg)
elif "The set with the given name does not exist" in msg:
raise IpsetSetNotFound(msg)
elif "Element cannot be added to the set: it's already added" in msg:
raise IpsetAlreadyInSet(msg)
else:
raise IpsetError(msg)
"""


async def ban(ip, table='filter', timeout=600):
"""
"""
nft = NFTables(table)
address, set_name = nft.chose_blacklist(ip)
print("Adding {0} to {1}:{2}".format(address, table, set_name))

return await nft.add(set_name, address, timeout)
4 changes: 2 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
python-systemd==231
smtplibaio==1.0.4
systemd-python>=231
smtplibaio>=2.0.1
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,6 @@
],

install_requires=[
'smtplibaio >= 1.0.4',
'smtplibaio >= 2.0.1',
'systemd-python >= 231',
])

0 comments on commit d7f2900

Please sign in to comment.