Portál AbcLinuxu, 12. května 2025 11:42
Dobrý den,
začal jsem využívat program fail2ban nakonfigurovaný pro využívání iptables. Program je geniální, ovšem chybí mi podpora pro IPv6. Autoři se o tom nikde nezmiňují, ani jsem nasazení podpory pro ipv6 nenašel v žádném TODO listu ani roadmap, ...
Rozhodl jsem se, že by nebylo špatné, kdybych si podporu pro IPv6 přidal. Ovšem Python neovládám a proto bych poprosil o radu i místní, věřím, že práce nebude zbytečná pro nikoho a že bych to nevyužil jen já.
Prozkoumal jsem zdrojové kódy fail2ban 0.8.4 a zjednodušeně bych přidal podporu takto:
V action.d jsou akce pro iptables (jinou podporu zatím neuvažujme) a vymyslel jsem to takto:
actionban = iptables -I fail2ban-<name> 1 -s <ip> -j DROP
změnit na
actionban = ip<ipv6>tables -I fail2ban-<name> 1 -s <ip> -j DROP
A za <ipv6> bych dosazoval buď "6" (pokud bude <ip> typu IPv6) nebo "None" (pokud jsem to pochopil správně a je to ekvivalent pro PHP "null"). A takto by to bylo obdobně dál. Samozřejmě, že IPv6 by fungovalo jen při iptables.
A nyní to důležité, prosím o pomoc s touto úpravou zde na abclinuxu, aby to mohl kdokoliv použít (výsledkem by mohl být nějaký patch nebo něco takového).
Zatím jsem udělal jen toto:
upravil jsem tyto "fce" v server/action.py:
##
# Executes the action "ban" command.
#
# @return True if the command succeeded
def execActionBan(self, aInfo):
if re.match("\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b", aInfo["ip"]):
aInfo["ipv6"] = None
else:
aInfo["ipv6"] = 6
return self.__processCmd(self.__actionBan, aInfo)
##
# Executes the action "unban" command.
#
# @return True if the command succeeded
def execActionUnban(self, aInfo):
if re.match("\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b", aInfo["ip"]):
aInfo["ipv6"] = None
else:
aInfo["ipv6"] = 6
return self.__processCmd(self.__actionUnban, aInfo)
Předpokládám, že by to mělo fungovat, tak, jak jsem si myslel.
TODO list:
Dosazování <ipv6> za actioncheck
Start ActionStart a stop ActionStop s ip6tables
Z nějakéhodůvodu nebere fail2ban IPv6 adresy za <HOST> - opravit
Přidáte se?
Takže se mé řešení asi ukazuje jako mírně složité. Dále nedoporučuji uvažovat nad nahrazováním <ipv6>, ale asi to provádět takto:
##
# Executes the action "ban" command.
#
# @return True if the command succeeded
def execActionBan(self, aInfo):
actionBanCMD = self.__actionBan
if not re.match("\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b", aInfo["ip"]):
return self.__processCmd(actionBanCMD, aInfo)
##
# Executes the action "unban" command.
#
# @return True if the command succeeded
def execActionUnban(self, aInfo):
actionUnbanCMD = self.__actionUnban
if not re.match("\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b", aInfo["ip"]):
actionUnbanCMD = actionUnbanCMD.replace('iptables ', 'ip6tables')
return self.__processCmd(actionUnbanCMD, aInfo)
ActionCheck, ActionStart a ActionStop se asi bude řešit přímo v __processCmd ve stejném souboru
Zkusil jsem upravit fci __processCMD takto:
##
# Executes a command with preliminary checks and substitutions.
#
# Before executing any commands, executes the "check" command first
# in order to check if prerequirements are met. If this check fails,
# it tries to restore a sane environnement before executing the real
# command.
# Replaces "aInfo" and "cInfo" in the query too.
#
# @param cmd The command to execute
# @param aInfo Dynamic properties
# @return True if the command succeeded
def __processCmd(self, cmd, aInfo = None):
""" Executes an OS command.
"""
if cmd == "":
logSys.debug("Nothing to do")
return True
# IPv4
checkCmd = Action.replaceTag(self.__actionCheck, self.__cInfo)
if not Action.executeCmd(checkCmd):
logSys.error("Invariant check failed. Trying to restore a sane" +
" environment")
stopCmd = Action.replaceTag(self.__actionStop, self.__cInfo)
Action.executeCmd(stopCmd)
startCmd = Action.replaceTag(self.__actionStart, self.__cInfo)
Action.executeCmd(startCmd)
if not Action.executeCmd(checkCmd):
logSys.fatal("Unable to restore environment")
return False
# IPv6
checkCmd = Action.replaceTag(self.__actionCheck, self.__cInfo)
checkCmd = checkCmd.replace('iptables ', 'ip6tables')
if not Action.executeCmd(checkCmd):
logSys.error("Invariant check failed. Trying to restore a sane" +
" environment")
stopCmd = Action.replaceTag(self.__actionStop, self.__cInfo)
stopCmd = stopCmd.replace('iptables ', 'ip6tables')
Action.executeCmd(stopCmd)
startCmd = Action.replaceTag(self.__actionStart, self.__cInfo)
startCmd = startCmd.replace('iptables ', 'ip6tables')
Action.executeCmd(startCmd)
if not Action.executeCmd(checkCmd):
logSys.fatal("Unable to restore environment")
return False
# Replace tags
if not aInfo == None:
realCmd = Action.replaceTag(cmd, aInfo)
else:
realCmd = cmd
# Replace static fields
realCmd = Action.replaceTag(realCmd, self.__cInfo)
return Action.executeCmd(realCmd)
Mrkněte se prosím na to, zda to tak může být, nebo zda byste to udělali jinak/lépe. Nic jiného mě nenapadlo.
Momentálně zbývá hlavní část a to, jak naučit fail2ban rozpoznávat IPv6 adresy v regulárních výrazech, zatím to rozeznává pouze IPv4.
Prosím, podívejte se na to také, neříkejte mi, že jsem sám, komu by se to hodilo.
Zatím jsem musel upravit soubor server/action.py takto:
##
# Executes the action "start" command.
#
# Replaces the tags in the action command with value of "cInfo"
# and executes the resulting command.
#
# @return True if the command succeeded
def execActionStart(self):
startCmd = Action.replaceTag(self.__actionStart, self.__cInfo)
Action.executeCmd(startCmd)
startCmd = startCmd.replace('iptables ', 'ip6tables ')
return Action.executeCmd(startCmd)
##
# Executes the action "ban" command.
#
# @return True if the command succeeded
def execActionBan(self, aInfo):
if not re.match("\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b", str(aInfo["ip"])):self.__actionBan = self.__actionBan.replace('iptables ', 'ip6tables ');return self.__processCmd(self.__actionBan, aInfo)
else:return self.__processCmd(self.__actionBan, aInfo)
##
# Executes the action "unban" command.
#
# @return True if the command succeeded
def execActionUnban(self, aInfo):
if not re.match("\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b", aInfo["ip"]):self.__actionUnban = self.__actionUnban.replace('iptables ', 'ip6tables ');return self.__processCmd(self.__actionUnban, aInfo)
else:return self.__processCmd(self.__actionUnban, aInfo)
##
# Executes the action "stop" command.
#
# Replaces the tags in the action command with value of "cInfo"
# and executes the resulting command.
#
# @return True if the command succeeded
def execActionStop(self):
stopCmd = Action.replaceTag(self.__actionStop, self.__cInfo)
Action.executeCmd(stopCmd)
stopCmd = stopCmd.replace('iptables ', 'ip6tables ')
return Action.executeCmd(stopCmd)
V současné době to dělá následující:
Při startu to přidá pravidlo do iptables a ip6tables. Při zastavení vše smaže. Při restartu oboje naráz.
Momentálně to při zjištění změny a získání IP adresy k zabanování nepřidá pravidlo s IP adresou do žádného iptables.
Dále je potřeba ověřit funkčnost autochecku
Je nutné zprovoznit to, aby fail2ban bral z logu IPv6 adresy
Tiskni
Sdílej:
ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.