mirror of https://github.com/fail2ban/fail2ban
fixup! Allow unbanip of tuple IDs
parent
ee0a5273fb
commit
e03e9bde0b
|
@ -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>"],
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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:
|
||||||
|
|
Loading…
Reference in New Issue