systemd units

master
Y 2017-12-16 20:26:59 +01:00
parent 86f27e8aa3
commit 018441b27d
7 changed files with 78 additions and 11 deletions

View File

@ -1,7 +1,5 @@
# TODO # TODO
* Maybe switch from storing the daily journal in a file, to storing it in a database. * 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. * 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… * Eventually make the code more elegant, as I learn more about Python…

3
extra/bin/pyruse-boot Executable file
View File

@ -0,0 +1,3 @@
#!/usr/bin/python
from pyruse import main
main.boot(sys.argv[1])

View File

@ -0,0 +1,3 @@
[Unit]
Requires=nftables.service
After=nftables.service

View File

@ -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

View File

@ -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

View File

@ -40,6 +40,36 @@ class Action(base.Action):
except IOError: except IOError:
pass # new file 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: if self.banSeconds:
until = now + datetime.timedelta(seconds = self.banSeconds) until = now + datetime.timedelta(seconds = self.banSeconds)
timeout = " timeout %ss" % str(self.banSeconds) timeout = " timeout %ss" % str(self.banSeconds)
@ -47,15 +77,8 @@ class Action(base.Action):
until = now + datetime.timedelta(days = 365) until = now + datetime.timedelta(days = 365)
timeout = "" timeout = ""
if previousTS:
cmd = list(Action._nft)
cmd.append("delete element %s {%s}" % (nftSet, ip))
subprocess.run(cmd)
cmd = list(Action._nft) cmd = list(Action._nft)
cmd.append("add element %s {%s%s}" % (nftSet, ip, timeout)) cmd.append("add element %s {%s%s}" % (nftSet, ip, timeout))
subprocess.run(cmd) subprocess.run(cmd)
newBan["timestamp"] = until.timestamp() return until
bans.append(newBan)
with open(Action._storage, "w") as dataFile:
json.dump(bans, dataFile)

View File

@ -26,7 +26,15 @@ def _doForEachJournalEntry(fct):
if event == journal.APPEND: if event == journal.APPEND:
for entry in j: for entry in j:
fct(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(): def main():
_setPyrusePaths() _setPyrusePaths()
conf = config.Config(PYRUSE_PATHS) conf = config.Config(PYRUSE_PATHS)