From 018441b27de93cbdcd4b8c40c57f3ed1e999ba4a Mon Sep 17 00:00:00 2001 From: Y Date: Sat, 16 Dec 2017 20:26:59 +0100 Subject: [PATCH] systemd units --- TODO.md | 2 -- extra/bin/pyruse-boot | 3 +++ extra/systemd/action_nftBan.conf | 3 +++ extra/systemd/pyruse-boot@.service | 16 ++++++++++++ extra/systemd/pyruse.service | 16 ++++++++++++ pyruse/actions/action_nftBan.py | 39 ++++++++++++++++++++++++------ pyruse/main.py | 10 +++++++- 7 files changed, 78 insertions(+), 11 deletions(-) create mode 100755 extra/bin/pyruse-boot create mode 100644 extra/systemd/action_nftBan.conf create mode 100644 extra/systemd/pyruse-boot@.service create mode 100644 extra/systemd/pyruse.service diff --git a/TODO.md b/TODO.md index 7333443..4a10857 100644 --- a/TODO.md +++ b/TODO.md @@ -1,7 +1,5 @@ # TODO * Maybe switch from storing the daily journal in a file, to storing it in a database. -* Write the systemd service that starts pyruse on boot. -* Write the systemd service+timer that restores bans after a reboot. * Maybe switch from Step.run() recursion to Step.run()-in-a-loop to avoid too-deep call stacks. * Eventually make the code more elegant, as I learn more about Python… diff --git a/extra/bin/pyruse-boot b/extra/bin/pyruse-boot new file mode 100755 index 0000000..4dc5e5f --- /dev/null +++ b/extra/bin/pyruse-boot @@ -0,0 +1,3 @@ +#!/usr/bin/python +from pyruse import main +main.boot(sys.argv[1]) diff --git a/extra/systemd/action_nftBan.conf b/extra/systemd/action_nftBan.conf new file mode 100644 index 0000000..b029abd --- /dev/null +++ b/extra/systemd/action_nftBan.conf @@ -0,0 +1,3 @@ +[Unit] +Requires=nftables.service +After=nftables.service diff --git a/extra/systemd/pyruse-boot@.service b/extra/systemd/pyruse-boot@.service new file mode 100644 index 0000000..178429d --- /dev/null +++ b/extra/systemd/pyruse-boot@.service @@ -0,0 +1,16 @@ +[Unit] +Description=Initialization of pyruse module %I + +[Service] +Type=oneshot +ExecStart=/usr/bin/pyruse-boot "%I" +CapabilityBoundingSet=CAP_SYS_CHROOT +NoNewPrivileges=true +PrivateDevices=yes +PrivateTmp=yes +ProtectHome=yes +ProtectSystem=full +ReadWriteDirectories=/var/lib/pyruse + +[Install] +WantedBy=multi-user.target diff --git a/extra/systemd/pyruse.service b/extra/systemd/pyruse.service new file mode 100644 index 0000000..d15e3cd --- /dev/null +++ b/extra/systemd/pyruse.service @@ -0,0 +1,16 @@ +[Unit] +Description=Route systemd-journal logs to filters and actions (ban, report…) + +[Service] +ExecStart=/usr/bin/pyruse +CapabilityBoundingSet=CAP_SYS_CHROOT +NoNewPrivileges=true +PrivateDevices=yes +PrivateTmp=yes +ProtectHome=yes +ProtectSystem=full +ReadWriteDirectories=/var/lib/pyruse +Restart=on-failure + +[Install] +WantedBy=multi-user.target diff --git a/pyruse/actions/action_nftBan.py b/pyruse/actions/action_nftBan.py index cc07da1..7adb840 100644 --- a/pyruse/actions/action_nftBan.py +++ b/pyruse/actions/action_nftBan.py @@ -40,6 +40,36 @@ class Action(base.Action): except IOError: pass # new file + if previousTS: + cmd = list(Action._nft) + cmd.append("delete element %s {%s}" % (nftSet, ip)) + subprocess.run(cmd) + + until = self._doBan(now, ip, nftSet) + + newBan["timestamp"] = until.timestamp() + bans.append(newBan) + with open(Action._storage, "w") as dataFile: + json.dump(bans, dataFile) + + def boot(self): + now = datetime.datetime.utcnow() + bans = [] + try: + with open(Action._storage) as dataFile: + for ban in json.load(dataFile): + if ban["timestamp"] <= now.timestamp(): + continue + else: + bans.append(ban) + self._doBan(now, ip, nftSet) + except IOError: + pass # no file + + with open(Action._storage, "w") as dataFile: + json.dump(bans, dataFile) + + def _doBan(self, now, ip, nftSet): if self.banSeconds: until = now + datetime.timedelta(seconds = self.banSeconds) timeout = " timeout %ss" % str(self.banSeconds) @@ -47,15 +77,8 @@ class Action(base.Action): until = now + datetime.timedelta(days = 365) timeout = "" - if previousTS: - cmd = list(Action._nft) - cmd.append("delete element %s {%s}" % (nftSet, ip)) - subprocess.run(cmd) cmd = list(Action._nft) cmd.append("add element %s {%s%s}" % (nftSet, ip, timeout)) subprocess.run(cmd) - newBan["timestamp"] = until.timestamp() - bans.append(newBan) - with open(Action._storage, "w") as dataFile: - json.dump(bans, dataFile) + return until diff --git a/pyruse/main.py b/pyruse/main.py index 5f43123..517a506 100644 --- a/pyruse/main.py +++ b/pyruse/main.py @@ -26,7 +26,15 @@ def _doForEachJournalEntry(fct): if event == journal.APPEND: for entry in j: fct(j) - + +def boot(modName): + if "action_" in modName: + module.get({"action": modName}).module.boot() + elif "filter_" in modName: + module.get({"filter": modName}).module.boot() + else: + raise ValueError("Neither “action_” nor “filter_” found in the module name; the `boot` feature cannot work for %s\n" % modName) + def main(): _setPyrusePaths() conf = config.Config(PYRUSE_PATHS)