systemd units
parent
86f27e8aa3
commit
018441b27d
2
TODO.md
2
TODO.md
|
@ -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…
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
from pyruse import main
|
||||||
|
main.boot(sys.argv[1])
|
|
@ -0,0 +1,3 @@
|
||||||
|
[Unit]
|
||||||
|
Requires=nftables.service
|
||||||
|
After=nftables.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
|
|
@ -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
|
|
@ -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)
|
|
||||||
|
|
|
@ -27,6 +27,14 @@ def _doForEachJournalEntry(fct):
|
||||||
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)
|
||||||
|
|
Loading…
Reference in New Issue