fixup! Allow unbanip of tuple IDs

pull/3533/head
Laurent Desausoi 2023-06-22 16:14:41 +02:00
parent ee0a5273fb
commit e03e9bde0b
4 changed files with 53 additions and 33 deletions

View File

@ -105,7 +105,7 @@ protocol = [
["set <JAIL> usedns <VALUE>", "sets the usedns mode for <JAIL>"], ["set <JAIL> usedns <VALUE>", "sets the usedns mode for <JAIL>"],
["set <JAIL> attempt <IP> [<failure1> ... <failureN>]", "manually notify about <IP> failure"], ["set <JAIL> attempt <IP> [<failure1> ... <failureN>]", "manually notify about <IP> failure"],
["set <JAIL> banip <IP> ... <IP>", "manually Ban <IP> for <JAIL>"], ["set <JAIL> banip <IP> ... <IP>", "manually Ban <IP> for <JAIL>"],
["set <JAIL> unbanip [--report-absent] <IP> ... <IP>", "manually Unban <IP> in <JAIL>"], ["set <JAIL> unbanip [--report-absent] [--expr] <IP> ... <IP>", "manually Unban <IP> in <JAIL>"],
["set <JAIL> maxretry <RETRY>", "sets the number of failures <RETRY> before banning the host for <JAIL>"], ["set <JAIL> maxretry <RETRY>", "sets the number of failures <RETRY> before banning the host for <JAIL>"],
["set <JAIL> maxmatches <INT>", "sets the max number of matches stored in memory per ticket in <JAIL>"], ["set <JAIL> maxmatches <INT>", "sets the max number of matches stored in memory per ticket in <JAIL>"],
["set <JAIL> maxlines <LINES>", "sets the number of <LINES> to buffer for regex search for <JAIL>"], ["set <JAIL> maxlines <LINES>", "sets the number of <LINES> to buffer for regex search for <JAIL>"],

View File

@ -242,6 +242,33 @@ class Actions(JailThread, Mapping):
return self.__checkBan(tickets) return self.__checkBan(tickets)
def removeMultiBannedIP(self, ips=None, db=True, ifexists=False):
"""Removes multiple banned IPs calling actions' unban method
Parameters
----------
ip : list, tuple or None
The IPs as list to unban or all IPs if None
Raises
------
ValueError
If at least one `ip` is not banned
"""
if ips is None:
return self.__flushBan(db)
missed = []
cnt = 0
for ip in ips:
try:
cnt += self.removeBannedIP(ip, db, ifexists)
except ValueError:
if not ifexists:
missed.append(ip)
if missed:
raise ValueError("not banned: %r" % missed)
return cnt
def removeBannedIP(self, ip=None, db=True, ifexists=False): def removeBannedIP(self, ip=None, db=True, ifexists=False):
"""Removes banned IP calling actions' unban method """Removes banned IP calling actions' unban method
@ -250,8 +277,8 @@ class Actions(JailThread, Mapping):
Parameters Parameters
---------- ----------
ip : list, str, IPAddr or None ip : str, IPAddr, TUPLE_ID representation (tuple/list) or None
The IP address (or multiple IPs as list) to unban or all IPs if None The ID to unban or all IPs if None
Raises Raises
------ ------
@ -261,26 +288,6 @@ class Actions(JailThread, Mapping):
# Unban all? # Unban all?
if ip is None: if ip is None:
return self.__flushBan(db) return self.__flushBan(db)
# Multiple IPs:
if isinstance(ip, (list, tuple)):
missed = []
cnt = 0
for i in ip:
try:
cnt += self.removeBannedIP(i, db, ifexists)
except ValueError:
if not ifexists:
missed.append(i)
if missed:
raise ValueError("not banned: %r" % missed)
return cnt
# IPs can be represented in string format (e.g.: tuples)
is_ip_parsed = True
if isinstance(ip, str):
try:
ip = eval(ip)
except Exception:
is_ip_parsed = False
# Single IP: # Single IP:
# Always delete ip from database (also if currently not banned) # Always delete ip from database (also if currently not banned)
if db and self._jail.database is not None: if db and self._jail.database is not None:
@ -292,12 +299,12 @@ class Actions(JailThread, Mapping):
self.__unBan(ticket) self.__unBan(ticket)
else: else:
# Multiple IPs by subnet or dns: # Multiple IPs by subnet or dns:
if not is_ip_parsed and not isinstance(ip, IPAddr): if not isinstance(ip, (IPAddr, tuple, list)):
ipa = IPAddr(ip) ipa = IPAddr(ip)
if not ipa.isSingle: # subnet (mask/cidr) or raw (may be dns/hostname): if not ipa.isSingle: # subnet (mask/cidr) or raw (may be dns/hostname):
ips = list(filter(ipa.contains, self.banManager.getBanList())) ips = list(filter(ipa.contains, self.banManager.getBanList()))
if ips: if ips:
return self.removeBannedIP(ips, db, ifexists) return self.removeMultiBannedIP(ips, db, ifexists)
# not found: # not found:
msg = "%s is not banned" % str(ip) msg = "%s is not banned" % str(ip)
logSys.log(logging.MSG, msg) logSys.log(logging.MSG, msg)

View File

@ -31,6 +31,7 @@ import os
import signal import signal
import stat import stat
import sys import sys
from ast import literal_eval
from .observer import Observers, ObserverThread from .observer import Observers, ObserverThread
from .jails import Jails from .jails import Jails
@ -528,18 +529,26 @@ class Server:
def setBanIP(self, name, value): def setBanIP(self, name, value):
return self.__jails[name].actions.addBannedIP(value) return self.__jails[name].actions.addBannedIP(value)
def setUnbanIP(self, name=None, value=None, ifexists=True): def setUnbanIP(self, name=None, values=None, ifexists=True, ifexpr=False):
def parseExpr(v):
try:
return literal_eval(v)
except SyntaxError:
return v
if name is not None: if name is not None:
# single jail: # single jail:
jails = [self.__jails[name]] jails = [self.__jails[name]]
else: else:
# in all jails: # in all jails:
jails = list(self.__jails.values()) jails = list(self.__jails.values())
# unban given or all (if value is None): # parse values if it contains an expression
if values and ifexpr:
values = map(parseExpr, values)
# unban given or all (if values is None):
cnt = 0 cnt = 0
ifexists |= (name is None) ifexists |= (name is None)
for jail in jails: for jail in jails:
cnt += jail.actions.removeBannedIP(value, ifexists=ifexists) cnt += jail.actions.removeMultiBannedIP(values, ifexists=ifexists)
return cnt return cnt
def banned(self, name=None, ids=None): def banned(self, name=None, ids=None):

View File

@ -363,13 +363,17 @@ class Transmitter:
value = command[2:] value = command[2:]
return self.__server.setBanIP(name,value) return self.__server.setBanIP(name,value)
elif command[1] == "unbanip": elif command[1] == "unbanip":
ifexpr = False
ifexists = True ifexists = True
if command[2] != "--report-absent": offset = 2
value = command[2:] if "--report-absent" in command:
else:
ifexists = False ifexists = False
value = command[3:] offset += 1
return self.__server.setUnbanIP(name, value, ifexists=ifexists) if "--expr" in command:
ifexpr = True
offset += 1
value = command[offset:]
return self.__server.setUnbanIP(name, value, ifexists=ifexists, ifexpr=ifexpr)
elif command[1] == "addaction": elif command[1] == "addaction":
args = [command[2]] args = [command[2]]
if len(command) > 3: if len(command) > 3: