23 Commits

Author SHA1 Message Date
adator85
884c5bf0cd . 2024-03-23 02:43:24 +01:00
adator85
7e24d7cf4c . 2024-03-23 01:50:55 +01:00
adator85
d16b73656f . 2024-03-21 21:31:24 +01:00
adator85
8acbb7187c . 2024-03-20 23:57:23 +01:00
adator85
51bea90e6f . 2024-03-20 23:53:46 +01:00
adator85
4cb54b5b2e . 2024-03-20 23:49:14 +01:00
adator85
310f732a5b . 2024-03-20 23:46:23 +01:00
adator85
018fd8d959 . 2024-03-20 23:45:44 +01:00
adator85
07fa518fcc . 2024-03-20 23:19:28 +01:00
adator85
37dcd23353 . 2024-03-20 21:39:42 +01:00
adator85
748e7bffc9 Correction du status 2024-03-20 21:16:10 +01:00
adator85
681e0da041 Mise en forme du code 2024-03-20 20:33:50 +01:00
adator85
667281ffb4 Ajout de quelques param de config 2024-03-20 20:12:51 +01:00
adator85
4b18675e8b . 2024-03-20 01:26:30 +01:00
adator85
f63aabfb7a . 2024-03-20 00:54:37 +01:00
adator85
b4c1df7f4a . 2024-03-19 23:37:58 +01:00
adator85
4c1a929867 Adding freeipapi scan 2024-03-19 23:34:21 +01:00
adator
0f1aa6f946 Merge pull request #7 from adator85/dev
Fix KeyError when a user change nickname
2024-02-20 01:12:32 +01:00
adator85
20684339d3 Fix KeyError when a user change nickname 2024-02-20 01:10:54 +01:00
adator
d53a3c58c9 Merge pull request #6 from adator85/dev
Corriger les commandes qui ce dupliquent lors du rechargement du mod
2024-02-02 23:24:13 +01:00
adator85
5c7f0e3ad0 Corriger les commandes qui ce dupliquent lors du rechargement du mod 2024-02-02 23:22:49 +01:00
adator
168f8db5ab Merge pull request #5 from adator85/dev
Bug - Correction de la commande .code
2024-02-02 22:54:28 +01:00
adator85
91a6218692 Bug - Correction de la commande .code 2024-02-02 22:52:06 +01:00
6 changed files with 583 additions and 153 deletions

View File

@@ -32,7 +32,7 @@ class Base:
self.db_create_first_admin() # Créer un nouvel admin si la base de données est vide self.db_create_first_admin() # Créer un nouvel admin si la base de données est vide
def get_unixtime(self)->int: def get_unixtime(self) -> int:
""" """
Cette fonction retourne un UNIXTIME de type 12365456 Cette fonction retourne un UNIXTIME de type 12365456
Return: Current time in seconds since the Epoch (int) Return: Current time in seconds since the Epoch (int)
@@ -40,7 +40,7 @@ class Base:
unixtime = int( time.time() ) unixtime = int( time.time() )
return unixtime return unixtime
def get_datetime(self)->str: def get_datetime(self) -> str:
""" """
Retourne une date au format string (24-12-2023 20:50:59) Retourne une date au format string (24-12-2023 20:50:59)
""" """
@@ -137,7 +137,7 @@ class Base:
(:createdOn, :user, :password, :hostname, :vhost, :level)""" (:createdOn, :user, :password, :hostname, :vhost, :level)"""
, mes_donnees) , mes_donnees)
pass return None
def create_timer(self, time_to_wait: float, func: object, func_args: tuple = ()) -> None: def create_timer(self, time_to_wait: float, func: object, func_args: tuple = ()) -> None:
@@ -153,9 +153,15 @@ class Base:
except AssertionError as ae: except AssertionError as ae:
self.__debug(f'Assertion Error -> {ae}') self.__debug(f'Assertion Error -> {ae}')
def create_thread(self, func:object, func_args: tuple = ()) -> None: def create_thread(self, func:object, func_args: tuple = (), run_once:bool = False) -> None:
try: try:
func_name = func.__name__ func_name = func.__name__
if run_once:
for thread in self.running_threads:
if thread.getName() == func_name:
return None
# if func_name in self.running_threads: # if func_name in self.running_threads:
# print(f"HeartBeat is running") # print(f"HeartBeat is running")
# return None # return None
@@ -243,7 +249,7 @@ class Base:
self.running_sockets.remove(soc) self.running_sockets.remove(soc)
print(f"> Socket ==> closed {str(soc.fileno())}") print(f"> Socket ==> closed {str(soc.fileno())}")
pass return None
def db_init(self) -> tuple[Engine, Connection]: def db_init(self) -> tuple[Engine, Connection]:
@@ -367,7 +373,7 @@ class Base:
# Run Garbage Collector Timer # Run Garbage Collector Timer
self.garbage_collector_timer() self.garbage_collector_timer()
self.garbage_collector_thread() self.garbage_collector_thread()
self.garbage_collector_sockets() # self.garbage_collector_sockets()
return None return None
for key, value in self.periodic_func.items(): for key, value in self.periodic_func.items():

View File

@@ -1,4 +1,5 @@
import os import os
from typing import Literal, Dict, List
########################################## ##########################################
# CONFIGURATION FILE : # # CONFIGURATION FILE : #
# Rename file to : configuration.py # # Rename file to : configuration.py #
@@ -6,7 +7,7 @@ import os
class Config: class Config:
DEFENDER_VERSION = '1.1.0' # MAJOR.MINOR.BATCH DEFENDER_VERSION = '3.3.2' # MAJOR.MINOR.BATCH
DEFENDER_DB_PATH = 'db' + os.sep # Séparateur en fonction de l'OS DEFENDER_DB_PATH = 'db' + os.sep # Séparateur en fonction de l'OS
DEFENDER_DB_NAME = 'defender' # Le nom de la base de données principale DEFENDER_DB_NAME = 'defender' # Le nom de la base de données principale
SERVICE_NAME = 'defender' # Le nom du service SERVICE_NAME = 'defender' # Le nom du service
@@ -37,7 +38,11 @@ class Config:
SALON_JAIL_MODES = 'sS' # Mode du salon pot de miel SALON_JAIL_MODES = 'sS' # Mode du salon pot de miel
SALON_LIBERER = '#welcome' # Le salon ou sera envoyé l'utilisateur clean SALON_LIBERER = '#welcome' # Le salon ou sera envoyé l'utilisateur clean
API_TIMEOUT = 2 # Timeout des api's
PORTS_TO_SCAN = [3028, 8080, 1080, 1085, 4145, 9050] # Liste des ports a scanné pour une detection de proxy PORTS_TO_SCAN = [3028, 8080, 1080, 1085, 4145, 9050] # Liste des ports a scanné pour une detection de proxy
WHITELISTED_IP = ['127.0.0.1'] # IP a ne pas scanner
GLINE_DURATION = '1d' # La durée du gline
DEBUG = 0 # Afficher l'ensemble des messages du serveurs dans la console DEBUG = 0 # Afficher l'ensemble des messages du serveurs dans la console

View File

@@ -1,6 +1,6 @@
import ssl, re, importlib, sys, time, threading, socket import ssl, re, importlib, sys, time, threading, socket
from datetime import datetime, timedelta from datetime import datetime, timedelta
from typing import Union
from core.configuration import Config from core.configuration import Config
from core.base import Base from core.base import Base
@@ -27,7 +27,7 @@ class Irc:
self.commands_level = { self.commands_level = {
0: ['help', 'auth', 'copyright'], 0: ['help', 'auth', 'copyright'],
1: ['load','reload','unload', 'deauth', 'uptime'], 1: ['load','reload','unload', 'deauth', 'uptime'],
2: ['show_sessions','show_modules', 'show_timers', 'show_threads'], 2: ['show_modules', 'show_timers', 'show_threads', 'sentinel'],
3: ['quit', 'restart','addaccess','editaccess', 'delaccess'] 3: ['quit', 'restart','addaccess','editaccess', 'delaccess']
} }
@@ -38,7 +38,7 @@ class Irc:
self.commands.append(command) self.commands.append(command)
self.Base = Base(self.Config) self.Base = Base(self.Config)
self.Base.create_thread(self.heartbeat, (self.beat, )) self.Base.create_thread(func=self.heartbeat, func_args=(self.beat, ))
############################################## ##############################################
# CONNEXION IRC # # CONNEXION IRC #
@@ -57,9 +57,9 @@ class Irc:
self.IrcSocket.connect(connexion_information) self.IrcSocket.connect(connexion_information)
# Créer un object ssl # Créer un object ssl
ssl_context = self.__ssl_context() # ssl_context = self.__ssl_context()
ssl_connexion = ssl_context.wrap_socket(self.IrcSocket, server_hostname=self.Config.SERVEUR_HOSTNAME) # ssl_connexion = ssl_context.wrap_socket(self.IrcSocket, server_hostname=self.Config.SERVEUR_HOSTNAME)
self.IrcSocket = ssl_connexion # self.IrcSocket = ssl_connexion
return None return None
@@ -78,50 +78,66 @@ class Irc:
self.load_existing_modules() # Charger les modules existant dans la base de données self.load_existing_modules() # Charger les modules existant dans la base de données
while self.signal: while self.signal:
if self.RESTART == 1: try:
self.IrcSocket.shutdown(socket.SHUT_RDWR) if self.RESTART == 1:
self.IrcSocket.close() self.IrcSocket.shutdown(socket.SHUT_RDWR)
self.IrcSocket.close()
while self.IrcSocket.fileno() != -1: while self.IrcSocket.fileno() != -1:
time.sleep(0.5) time.sleep(0.5)
self.debug("--> En attente de la fermeture du socket ...") self.debug("--> En attente de la fermeture du socket ...")
self.__create_socket() self.__create_socket()
self.__link(self.IrcSocket) self.__link(self.IrcSocket)
self.load_existing_modules() self.load_existing_modules()
self.RESTART = 0 self.RESTART = 0
# 4072 max what the socket can grab # 4072 max what the socket can grab
buffer_size = self.IrcSocket.getsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF) buffer_size = self.IrcSocket.getsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF)
# data = self.IrcSocket.recv(buffer_size).splitlines(True) # data = self.IrcSocket.recv(buffer_size).splitlines(True)
data_in_bytes = self.IrcSocket.recv(buffer_size) data_in_bytes = self.IrcSocket.recv(buffer_size)
count_bytes = len(data_in_bytes)
while count_bytes > 4070: count_bytes = len(data_in_bytes)
# If the received message is > 4070 then loop and add the value to the variable
new_data = self.IrcSocket.recv(buffer_size)
data_in_bytes += new_data
count_bytes = len(new_data)
# print("========================================================")
data = data_in_bytes.splitlines() while count_bytes > 4070:
# If the received message is > 4070 then loop and add the value to the variable
new_data = self.IrcSocket.recv(buffer_size)
data_in_bytes += new_data
count_bytes = len(new_data)
# print("========================================================")
# print(f"{str(buffer_size)} - {str(len(data_in_bytes))}") data = data_in_bytes.splitlines()
# print(f"{str(buffer_size)} - {str(len(data_in_bytes))}")
if not data: if not data:
break break
self.send_response(data) self.send_response(data)
if self.IrcSocket.fileno() == -1:
print('restarting the socket')
self.RESTART = 1
except ssl.SSLEOFError as soe:
self.debug(f"SSLEOFError __connect_to_irc: {soe} - {data}")
except ssl.SSLError as se:
self.debug(f"SSLError __connect_to_irc: {se} - {data}")
except OSError as oe:
self.debug(f"SSLError __connect_to_irc: {oe} - {data}")
except Exception as e:
self.debug(f"Exception __connect_to_irc: {e} - {data}")
self.IrcSocket.shutdown(socket.SHUT_RDWR) self.IrcSocket.shutdown(socket.SHUT_RDWR)
self.IrcSocket.close() self.IrcSocket.close()
self.debug("--> Fermeture de Defender ...")
except AssertionError as ae: except AssertionError as ae:
self.debug(f'Assertion error : {ae}') self.debug(f'Assertion error : {ae}')
except ValueError as ve: except ValueError as ve:
self.debug(f'Value Error : {ve}') self.debug(f'Value Error : {ve}')
except OSError as oe: except ssl.SSLEOFError as soe:
self.debug(f"OS Error : {oe}") self.debug(f"OS Error __connect_to_irc: {soe}")
except Exception as e:
self.debug(f"Exception: {e}")
def __link(self, writer:socket.socket) -> None: def __link(self, writer:socket.socket) -> None:
"""Créer le link et envoyer les informations nécessaires pour la """Créer le link et envoyer les informations nécessaires pour la
@@ -130,7 +146,6 @@ class Irc:
Args: Args:
writer (StreamWriter): permet l'envoi des informations au serveur. writer (StreamWriter): permet l'envoi des informations au serveur.
""" """
nickname = self.Config.SERVICE_NICKNAME nickname = self.Config.SERVICE_NICKNAME
username = self.Config.SERVICE_USERNAME username = self.Config.SERVICE_USERNAME
realname = self.Config.SERVICE_REALNAME realname = self.Config.SERVICE_REALNAME
@@ -151,8 +166,6 @@ class Irc:
unixtime = self.Base.get_unixtime() unixtime = self.Base.get_unixtime()
# Envoyer un message d'identification # Envoyer un message d'identification
# strtobytes = bytes(":" + sid + " PASS :" + password + "\r\n", 'utf-8')
# self.IrcSocket.send(strtobytes)
writer.send(f":{sid} PASS :{password}\r\n".encode('utf-8')) writer.send(f":{sid} PASS :{password}\r\n".encode('utf-8'))
writer.send(f":{sid} PROTOCTL NICKv2 VHP UMODE2 NICKIP SJOIN SJOIN2 SJ3 NOQUIT TKLEXT MLOCK SID MTAGS\r\n".encode('utf-8')) writer.send(f":{sid} PROTOCTL NICKv2 VHP UMODE2 NICKIP SJOIN SJOIN2 SJ3 NOQUIT TKLEXT MLOCK SID MTAGS\r\n".encode('utf-8'))
writer.send(f":{sid} PROTOCTL EAUTH={link},,,{service_name}-v{version}\r\n".encode('utf-8')) writer.send(f":{sid} PROTOCTL EAUTH={link},,,{service_name}-v{version}\r\n".encode('utf-8'))
@@ -164,11 +177,9 @@ class Irc:
writer.send(f":{sid} MODE {chan} +{cmodes}\r\n".encode('utf-8')) writer.send(f":{sid} MODE {chan} +{cmodes}\r\n".encode('utf-8'))
writer.send(f":{service_id} SAMODE {chan} +{umodes} {nickname}\r\n".encode('utf-8')) writer.send(f":{service_id} SAMODE {chan} +{umodes} {nickname}\r\n".encode('utf-8'))
# writer.write(f"USER {nickname} {username} {username} {nickname} {username} :{username}\r\n".encode('utf-8')) return None
# writer.write(f"USER {username} {username} {username} :{username}\r\n".encode('utf-8'))
# writer.write(f"NICK {nickname}\r\n".encode('utf-8'))
def send2socket(self, send_message:str)->None: def send2socket(self, send_message:str) -> None:
"""Envoit les commandes à envoyer au serveur. """Envoit les commandes à envoyer au serveur.
Args: Args:
@@ -185,8 +196,12 @@ class Irc:
self.IrcSocket.send(f"{send_message}\r\n".encode(self.CHARSET[0],'replace')) self.IrcSocket.send(f"{send_message}\r\n".encode(self.CHARSET[0],'replace'))
except AssertionError as ae: except AssertionError as ae:
self.debug(f"Assertion error : {ae}") self.debug(f"Assertion error : {ae}")
except ssl.SSLEOFError as soe:
self.debug(f"SSLEOFError send2socket: {soe} - {send_message}")
except ssl.SSLError as se:
self.debug(f"SSLError send2socket: {se} - {send_message}")
except OSError as oe: except OSError as oe:
self.debug(f"OS Error : {oe}") self.debug(f"OSError send2socket: {oe} - {send_message}")
def send_response(self, responses:list[bytes]) -> None: def send_response(self, responses:list[bytes]) -> None:
try: try:
@@ -207,6 +222,7 @@ class Irc:
############################################## ##############################################
# FIN CONNEXION IRC # # FIN CONNEXION IRC #
############################################## ##############################################
def load_existing_modules(self) -> None: def load_existing_modules(self) -> None:
"""Charge les modules qui existe déja dans la base de données """Charge les modules qui existe déja dans la base de données
@@ -219,7 +235,7 @@ class Irc:
return None return None
def get_defender_uptime(self)->str: def get_defender_uptime(self) -> str:
"""Savoir depuis quand Defender est connecté """Savoir depuis quand Defender est connecté
Returns: Returns:
@@ -348,6 +364,8 @@ class Irc:
except ModuleNotFoundError as moduleNotFound: except ModuleNotFoundError as moduleNotFound:
self.debug(f"MODULE_NOT_FOUND: {moduleNotFound}") self.debug(f"MODULE_NOT_FOUND: {moduleNotFound}")
self.send2socket(f":{self.Config.SERVICE_NICKNAME} PRIVMSG {self.Config.SERVICE_CHANLOG} :[ {self.Config.CONFIG_COLOR['rouge']}MODULE_NOT_FOUND{self.Config.CONFIG_COLOR['noire']} ]: {moduleNotFound}") self.send2socket(f":{self.Config.SERVICE_NICKNAME} PRIVMSG {self.Config.SERVICE_CHANLOG} :[ {self.Config.CONFIG_COLOR['rouge']}MODULE_NOT_FOUND{self.Config.CONFIG_COLOR['noire']} ]: {moduleNotFound}")
except Exception as e:
self.debug(f"Something went wrong with a module you want to load : {e}")
def insert_db_uid(self, uid:str, nickname:str, username:str, hostname:str, umodes:str, vhost:str, isWebirc: bool) -> None: def insert_db_uid(self, uid:str, nickname:str, username:str, hostname:str, umodes:str, vhost:str, isWebirc: bool) -> None:
@@ -429,8 +447,6 @@ class Irc:
vhost = self.db_uid[uid]['vhost'] vhost = self.db_uid[uid]['vhost']
level = int(level) level = int(level)
self.db_admin[uid] = { self.db_admin[uid] = {
'nickname': nickname, 'nickname': nickname,
'username': username, 'username': username,
@@ -533,7 +549,7 @@ class Irc:
self.debug(response) self.debug(response)
return response return response
def get_uid(self, uidornickname:str) -> str | None: def get_uid(self, uidornickname:str) -> Union[str, None]:
uid_recherche = uidornickname uid_recherche = uidornickname
response = None response = None
@@ -546,7 +562,7 @@ class Irc:
return response return response
def get_nickname(self, uidornickname:str) -> str | None: def get_nickname(self, uidornickname:str) -> Union[str, None]:
nickname_recherche = uidornickname nickname_recherche = uidornickname
@@ -607,10 +623,13 @@ class Irc:
cmd_to_send:list[str] = data.copy() cmd_to_send:list[str] = data.copy()
cmd = data.copy() cmd = data.copy()
cmd_to_debug = data.copy()
cmd_to_debug.pop(0)
if len(cmd) == 0 or len(cmd) == 1: if len(cmd) == 0 or len(cmd) == 1:
return False return False
self.debug(cmd) self.debug(cmd_to_debug)
match cmd[0]: match cmd[0]:
@@ -739,6 +758,9 @@ class Irc:
self.insert_db_uid(uid, nickname, username, hostname, umodes, vhost, isWebirc) self.insert_db_uid(uid, nickname, username, hostname, umodes, vhost, isWebirc)
for classe_name, classe_object in self.loaded_classes.items():
classe_object.cmd(cmd_to_send)
case 'PRIVMSG': case 'PRIVMSG':
try: try:
# Supprimer la premiere valeur # Supprimer la premiere valeur
@@ -810,9 +832,10 @@ class Irc:
case _: case _:
pass pass
# Envoyer la commande aux classes dynamiquement chargées if cmd[2] != 'UID':
for classe_name, classe_object in self.loaded_classes.items(): # Envoyer la commande aux classes dynamiquement chargées
classe_object.cmd(cmd_to_send) for classe_name, classe_object in self.loaded_classes.items():
classe_object.cmd(cmd_to_send)
except IndexError as ie: except IndexError as ie:
self.debug(f"IRC CMD -> IndexError : {ie} - {cmd} - length {str(len(cmd))}") self.debug(f"IRC CMD -> IndexError : {ie} - {cmd} - length {str(len(cmd))}")
@@ -1023,37 +1046,12 @@ class Irc:
case 'unload': case 'unload':
# unload mod_dktmb # unload mod_dktmb
module_name = str(cmd[1]).lower() # Le nom du module. exemple: mod_defender try:
class_name = module_name.split('_')[1].capitalize() # Nom de la class. exemple: Defender module_name = str(cmd[1]).lower() # Le nom du module. exemple: mod_defender
class_name = module_name.split('_')[1].capitalize() # Nom de la class. exemple: Defender
if class_name in self.loaded_classes:
for level, command in self.loaded_classes[class_name].commands_level.items():
# Supprimer la commande de la variable commands
for c in self.loaded_classes[class_name].commands_level[level]:
self.commands.remove(c)
self.commands_level[level].remove(c)
del self.loaded_classes[class_name]
# Supprimer le module de la base de données
self.Base.db_delete_module(module_name)
self.send2socket(f":{self.Config.SERVICE_NICKNAME} PRIVMSG {self.Config.SERVICE_CHANLOG} :Module {module_name} supprimé")
case 'reload':
# reload mod_dktmb
module_name = str(cmd[1]).lower() # ==> mod_defender
class_name = module_name.split('_')[1].capitalize() # ==> Defender
if 'mods.' + module_name in sys.modules:
self.debug('Module Already Loaded ... reload the module ...')
the_module = sys.modules['mods.' + module_name]
importlib.reload(the_module)
# Supprimer la class déja instancier
if class_name in self.loaded_classes: if class_name in self.loaded_classes:
# Supprimer les commandes déclarer dans la classe self.loaded_classes[class_name].unload()
for level, command in self.loaded_classes[class_name].commands_level.items(): for level, command in self.loaded_classes[class_name].commands_level.items():
# Supprimer la commande de la variable commands # Supprimer la commande de la variable commands
for c in self.loaded_classes[class_name].commands_level[level]: for c in self.loaded_classes[class_name].commands_level[level]:
@@ -1062,14 +1060,46 @@ class Irc:
del self.loaded_classes[class_name] del self.loaded_classes[class_name]
my_class = getattr(the_module, class_name, None) # Supprimer le module de la base de données
new_instance = my_class(self.ircObject) self.Base.db_delete_module(module_name)
self.loaded_classes[class_name] = new_instance
self.send2socket(f":{self.Config.SERVICE_NICKNAME} PRIVMSG {self.Config.SERVICE_CHANLOG} :Module {module_name} rechargé") self.send2socket(f":{self.Config.SERVICE_NICKNAME} PRIVMSG {self.Config.SERVICE_CHANLOG} :Module {module_name} supprimé")
return False except:
else: self.debug(f"Something went wrong with a module you want to load")
self.send2socket(f":{self.Config.SERVICE_NICKNAME} PRIVMSG {self.Config.SERVICE_CHANLOG} :Module {module_name} n'est pas chargé !")
case 'reload':
# reload mod_dktmb
try:
module_name = str(cmd[1]).lower() # ==> mod_defender
class_name = module_name.split('_')[1].capitalize() # ==> Defender
if 'mods.' + module_name in sys.modules:
self.loaded_classes[class_name].unload()
self.debug('Module Already Loaded ... reload the module ...')
the_module = sys.modules['mods.' + module_name]
importlib.reload(the_module)
# Supprimer la class déja instancier
if class_name in self.loaded_classes:
# Supprimer les commandes déclarer dans la classe
for level, command in self.loaded_classes[class_name].commands_level.items():
# Supprimer la commande de la variable commands
for c in self.loaded_classes[class_name].commands_level[level]:
self.commands.remove(c)
self.commands_level[level].remove(c)
del self.loaded_classes[class_name]
my_class = getattr(the_module, class_name, None)
new_instance = my_class(self.ircObject)
self.loaded_classes[class_name] = new_instance
self.send2socket(f":{self.Config.SERVICE_NICKNAME} PRIVMSG {self.Config.SERVICE_CHANLOG} :Module {module_name} rechargé")
return False
else:
self.send2socket(f":{self.Config.SERVICE_NICKNAME} PRIVMSG {self.Config.SERVICE_CHANLOG} :Module {module_name} n'est pas chargé !")
except:
self.debug(f"Something went wrong with a module you want to reload")
case 'quit': case 'quit':
try: try:
@@ -1102,6 +1132,9 @@ class Irc:
self.db_uid.clear() #Vider UID_DB self.db_uid.clear() #Vider UID_DB
self.db_chan = [] #Vider les salons self.db_chan = [] #Vider les salons
for class_name in self.loaded_classes:
self.loaded_classes[class_name].unload()
self.send2socket(f':{dnickname} NOTICE {fromuser} : Redémarrage du service {dnickname}') self.send2socket(f':{dnickname} NOTICE {fromuser} : Redémarrage du service {dnickname}')
self.send2socket(f':{self.Config.SERVEUR_LINK} SQUIT {self.Config.SERVEUR_LINK} :{final_reason}') self.send2socket(f':{self.Config.SERVEUR_LINK} SQUIT {self.Config.SERVEUR_LINK} :{final_reason}')
self.debug(f'Redémarrage du server {dnickname}') self.debug(f'Redémarrage du server {dnickname}')
@@ -1133,7 +1166,12 @@ class Irc:
self.send2socket(f":{dnickname} PRIVMSG {dchanlog} :Aucun timers en cours d'execution") self.send2socket(f":{dnickname} PRIVMSG {dchanlog} :Aucun timers en cours d'execution")
case 'show_threads': case 'show_threads':
self.send2socket(f":{dnickname} PRIVMSG {dchanlog} :{self.Base.running_threads}")
running_thread_name:list = []
for thread in self.Base.running_threads:
running_thread_name.append(f"{thread.getName()} ({thread.is_alive()})")
self.send2socket(f":{dnickname} PRIVMSG {dchanlog} :{str(running_thread_name)}")
case 'uptime': case 'uptime':
uptime = self.get_defender_uptime() uptime = self.get_defender_uptime()
@@ -1142,5 +1180,21 @@ class Irc:
case 'copyright': case 'copyright':
self.send2socket(f':{dnickname} NOTICE {fromuser} : # Defender V.{self.Config.DEFENDER_VERSION} Developped by adator® and dktmb® #') self.send2socket(f':{dnickname} NOTICE {fromuser} : # Defender V.{self.Config.DEFENDER_VERSION} Developped by adator® and dktmb® #')
case 'sentinel':
# .sentinel on
activation = str(cmd[1]).lower()
service_id = self.Config.SERVICE_ID
channel_to_dont_quit = [self.Config.SALON_JAIL, dchanlog]
if activation == 'on':
for chan in self.db_chan:
if not chan in channel_to_dont_quit:
self.send2socket(f":{service_id} JOIN {chan}")
if activation == 'off':
for chan in self.db_chan:
if not chan in channel_to_dont_quit:
self.send2socket(f":{service_id} PART {chan}")
case _: case _:
pass pass

View File

@@ -1,5 +1,6 @@
from datetime import datetime from datetime import datetime
import re, socket, psutil, requests, json from typing import Union
import re, socket, psutil, requests, json, time
from core.irc import Irc from core.irc import Irc
# Le module crée devra réspecter quelques conditions # Le module crée devra réspecter quelques conditions
@@ -9,7 +10,10 @@ from core.irc import Irc
# 2 . Récuperer la configuration dans une variable # 2 . Récuperer la configuration dans une variable
# 3 . Définir et enregistrer les nouvelles commandes # 3 . Définir et enregistrer les nouvelles commandes
# 4 . Créer vos tables, en utilisant toujours le nom des votre classe en minuscule ==> defender_votre-table # 4 . Créer vos tables, en utilisant toujours le nom des votre classe en minuscule ==> defender_votre-table
# 3. une methode _hcmds(self, user:str, cmd: list) devra toujours etre crée. # 3. Methode suivantes:
# cmd(self, data:list)
# _hcmds(self, user:str, cmd: list)
# unload(self)
class Defender(): class Defender():
@@ -18,6 +22,20 @@ class Defender():
self.Irc = ircInstance # Ajouter l'object mod_irc a la classe ( Obligatoire ) self.Irc = ircInstance # Ajouter l'object mod_irc a la classe ( Obligatoire )
self.Config = ircInstance.Config # Ajouter la configuration a la classe ( Obligatoire ) self.Config = ircInstance.Config # Ajouter la configuration a la classe ( Obligatoire )
self.Base = ircInstance.Base # Ajouter l'objet Base au module ( Obligatoire ) self.Base = ircInstance.Base # Ajouter l'objet Base au module ( Obligatoire )
self.timeout = self.Config.API_TIMEOUT # API Timeout
self.freeipapi_remote_ip:list = [] # Liste qui va contenir les adresses ip a scanner avec freeipapi
self.cloudfilt_remote_ip:list = [] # Liste qui va contenir les adresses ip a scanner avec cloudfilt
self.abuseipdb_remote_ip:list = [] # Liste qui va contenir les adresses ip a scanner avec abuseipdb
self.psutil_remote_ip:list = [] # Liste qui va contenir les adresses ip a scanner avec psutil_scan
self.localscan_remote_ip:list = [] # Liste qui va contenir les adresses ip a scanner avec local_scan
self.abuseipdb_isRunning:bool = True
self.freeipapi_isRunning:bool = True
self.cloudfilt_isRunning:bool = True
self.psutil_isRunning:bool = True
self.localscan_isRunning:bool = True
self.reputationTimer_isRunning:bool = True
self.Irc.debug(f'Module {self.__class__.__name__} loaded ...') self.Irc.debug(f'Module {self.__class__.__name__} loaded ...')
@@ -45,11 +63,28 @@ class Defender():
""" """
for level, com in commands.items(): for level, com in commands.items():
for c in commands[level]: for c in commands[level]:
self.Irc.commands_level[level].append(c) if not c in self.Irc.commands:
self.Irc.commands.append(c) self.Irc.commands_level[level].append(c)
self.Irc.commands.append(c)
return None return None
def unload(self) -> None:
self.freeipapi_remote_ip:list = [] # Liste qui va contenir les adresses ip a scanner avec freeipapi
self.cloudfilt_remote_ip:list = [] # Liste qui va contenir les adresses ip a scanner avec cloudfilt
self.abuseipdb_remote_ip:list = [] # Liste qui va contenir les adresses ip a scanner avec abuseipdb
self.psutil_remote_ip:list = [] # Liste qui va contenir les adresses ip a scanner avec psutil_scan
self.localscan_remote_ip:list = [] # Liste qui va contenir les adresses ip a scanner avec local_scan
self.abuseipdb_isRunning:bool = False
self.freeipapi_isRunning:bool = False
self.cloudfilt_isRunning:bool = False
self.psutil_isRunning:bool = False
self.localscan_isRunning:bool = False
self.reputationTimer_isRunning:bool = False
return None
def __create_tables(self) -> None: def __create_tables(self) -> None:
"""Methode qui va créer la base de donnée si elle n'existe pas. """Methode qui va créer la base de donnée si elle n'existe pas.
Une Session unique pour cette classe sera crée, qui sera utilisé dans cette classe / module Une Session unique pour cette classe sera crée, qui sera utilisé dans cette classe / module
@@ -95,6 +130,7 @@ class Defender():
self.flood_system = {} # Variable qui va contenir les users self.flood_system = {} # Variable qui va contenir les users
self.reputation_first_connexion = {'ip': '', 'score': -1} # Contient les premieres informations de connexion self.reputation_first_connexion = {'ip': '', 'score': -1} # Contient les premieres informations de connexion
self.abuseipdb_key = '13c34603fee4d2941a2c443cc5c77fd750757ca2a2c1b304bd0f418aff80c24be12651d1a3cfe674' # Laisser vide si aucune clé self.abuseipdb_key = '13c34603fee4d2941a2c443cc5c77fd750757ca2a2c1b304bd0f418aff80c24be12651d1a3cfe674' # Laisser vide si aucune clé
self.cloudfilt_key = 'r1gEtjtfgRQjtNBDMxsg' # Laisser vide si aucune clé
# Rejoindre les salons # Rejoindre les salons
self.join_saved_channels() self.join_saved_channels()
@@ -108,6 +144,8 @@ class Defender():
'local_scan': 0, 'local_scan': 0,
'psutil_scan': 0, 'psutil_scan': 0,
'abuseipdb_scan': 0, 'abuseipdb_scan': 0,
'freeipapi_scan': 0,
'cloudfilt_scan': 0,
'flood': 0, 'flood': 0,
'flood_message': 5, 'flood_message': 5,
'flood_time': 1, 'flood_time': 1,
@@ -117,6 +155,14 @@ class Defender():
# Syncrhoniser la variable defConfig avec la configuration de la base de données. # Syncrhoniser la variable defConfig avec la configuration de la base de données.
self.sync_db_configuration() self.sync_db_configuration()
# Démarrer les threads pour démarrer les api
self.Base.create_thread(func=self.thread_freeipapi_scan)
self.Base.create_thread(func=self.thread_cloudfilt_scan)
self.Base.create_thread(func=self.thread_abuseipdb_scan)
self.Base.create_thread(func=self.thread_local_scan)
self.Base.create_thread(func=self.thread_psutil_scan)
self.Base.create_thread(func=self.thread_reputation_timer)
return True return True
def sync_db_configuration(self) -> None: def sync_db_configuration(self) -> None:
@@ -348,11 +394,11 @@ class Defender():
uptime = current_datetime - connected_time uptime = current_datetime - connected_time
convert_to_minutes = uptime.seconds / 60 convert_to_minutes = uptime.seconds / 60
uptime_minutes = round(number=convert_to_minutes, ndigits=2) uptime_minutes = round(number=convert_to_minutes, ndigits=0)
return uptime_minutes return uptime_minutes
def system_reputation(self, uid:str)->None: def system_reputation(self, uid:str)-> None:
# Reputation security # Reputation security
# - Activation ou désactivation du système --> OK # - Activation ou désactivation du système --> OK
# - Le user sera en mesure de changer la limite de la réputation --> OK # - Le user sera en mesure de changer la limite de la réputation --> OK
@@ -394,7 +440,7 @@ class Defender():
self.Irc.debug(f"system_reputation : {jailed_nickname} à été capturé par le système de réputation") self.Irc.debug(f"system_reputation : {jailed_nickname} à été capturé par le système de réputation")
# self.Irc.create_ping_timer(int(self.defConfig['reputation_timer']) * 60, 'Defender', 'system_reputation_timer') # self.Irc.create_ping_timer(int(self.defConfig['reputation_timer']) * 60, 'Defender', 'system_reputation_timer')
self.Base.create_timer(int(self.defConfig['reputation_timer']) * 60, self.system_reputation_timer) # self.Base.create_timer(int(self.defConfig['reputation_timer']) * 60, self.system_reputation_timer)
else: else:
self.Irc.debug(f"system_reputation : {jailed_nickname} à été supprimé du système de réputation car connecté via WebIrc ou il est dans la 'Trusted list'") self.Irc.debug(f"system_reputation : {jailed_nickname} à été supprimé du système de réputation car connecté via WebIrc ou il est dans la 'Trusted list'")
self.delete_db_reputation(uid) self.delete_db_reputation(uid)
@@ -425,6 +471,7 @@ class Defender():
if not self.db_reputation[uid]['isWebirc']: # Si il ne vient pas de WebIRC if not self.db_reputation[uid]['isWebirc']: # Si il ne vient pas de WebIRC
self.Irc.debug(f"Nickname: {self.db_reputation[uid]['nickname']} | uptime: {self.get_user_uptime_in_minutes(uid)} | reputation time: {reputation_timer}") self.Irc.debug(f"Nickname: {self.db_reputation[uid]['nickname']} | uptime: {self.get_user_uptime_in_minutes(uid)} | reputation time: {reputation_timer}")
if self.get_user_uptime_in_minutes(uid) >= reputation_timer and int(self.db_reputation[uid]['score']) <= int(reputation_seuil): if self.get_user_uptime_in_minutes(uid) >= reputation_timer and int(self.db_reputation[uid]['score']) <= int(reputation_seuil):
self.Irc.debug('-----'*20)
self.Irc.send2socket(f":{service_id} PRIVMSG {dchanlog} :[{color_red} REPUTATION {color_black}] : Action sur {self.db_reputation[uid]['nickname']} aprés {str(reputation_timer)} minutes d'inactivité") self.Irc.send2socket(f":{service_id} PRIVMSG {dchanlog} :[{color_red} REPUTATION {color_black}] : Action sur {self.db_reputation[uid]['nickname']} aprés {str(reputation_timer)} minutes d'inactivité")
# if not system_reputation_timer_action(cglobal['reputation_timer_action'], uid, self.db_reputation[uid]['nickname']): # if not system_reputation_timer_action(cglobal['reputation_timer_action'], uid, self.db_reputation[uid]['nickname']):
# return False # return False
@@ -446,6 +493,16 @@ class Defender():
except AssertionError as ae: except AssertionError as ae:
self.Irc.debug(f'Assertion Error -> {ae}') self.Irc.debug(f'Assertion Error -> {ae}')
def thread_reputation_timer(self) -> None:
try:
while self.reputationTimer_isRunning:
self.system_reputation_timer()
time.sleep(5)
return None
except ValueError as ve:
self.Irc.debug(f"thread_reputation_timer Error : {ve}")
def _execute_flood_action(self, action:str, channel:str) -> None: def _execute_flood_action(self, action:str, channel:str) -> None:
"""DO NOT EXECUTE THIS FUNCTION WITHOUT THREADING """DO NOT EXECUTE THIS FUNCTION WITHOUT THREADING
@@ -532,6 +589,13 @@ class Defender():
return None return None
def scan_ports(self, remote_ip: str) -> None: def scan_ports(self, remote_ip: str) -> None:
"""local_scan
Args:
remote_ip (str): _description_
"""
if remote_ip in self.Config.WHITELISTED_IP:
return None
for port in self.Config.PORTS_TO_SCAN: for port in self.Config.PORTS_TO_SCAN:
newSocket = '' newSocket = ''
@@ -550,6 +614,8 @@ class Defender():
self.Irc.debug(f"Le port {str(port)} est fermé") self.Irc.debug(f"Le port {str(port)} est fermé")
except AttributeError as ae: except AttributeError as ae:
self.Irc.debug(f"AttributeError : {ae}") self.Irc.debug(f"AttributeError : {ae}")
except socket.gaierror as err:
self.Irc.debug(f"Address Info Error: {err}")
finally: finally:
# newSocket.shutdown(socket.SHUT_RDWR) # newSocket.shutdown(socket.SHUT_RDWR)
newSocket.close() newSocket.close()
@@ -557,7 +623,37 @@ class Defender():
pass pass
def thread_local_scan(self) -> None:
try:
while self.localscan_isRunning:
list_to_remove:list = []
for ip in self.localscan_remote_ip:
self.scan_ports(ip)
list_to_remove.append(ip)
time.sleep(1)
for ip_to_remove in list_to_remove:
self.localscan_remote_ip.remove(ip_to_remove)
time.sleep(1)
return None
except ValueError as ve:
self.Irc.debug(f"thread_local_scan Error : {ve}")
def get_ports_connexion(self, remote_ip: str) -> list[int]: def get_ports_connexion(self, remote_ip: str) -> list[int]:
"""psutil_scan
Args:
remote_ip (str): _description_
Returns:
list[int]: _description_
"""
if remote_ip in self.Config.WHITELISTED_IP:
return None
connections = psutil.net_connections(kind='inet') connections = psutil.net_connections(kind='inet')
matching_ports = [conn.raddr.port for conn in connections if conn.raddr and conn.raddr.ip == remote_ip] matching_ports = [conn.raddr.port for conn in connections if conn.raddr and conn.raddr.ip == remote_ip]
@@ -565,7 +661,26 @@ class Defender():
return matching_ports return matching_ports
def abuseipdb_scan(self, remote_ip:str) -> dict[str, any] | None: def thread_psutil_scan(self) -> None:
try:
while self.psutil_isRunning:
list_to_remove:list = []
for ip in self.psutil_remote_ip:
self.get_ports_connexion(ip)
list_to_remove.append(ip)
time.sleep(1)
for ip_to_remove in list_to_remove:
self.psutil_remote_ip.remove(ip_to_remove)
time.sleep(1)
return None
except ValueError as ve:
self.Irc.debug(f"thread_psutil_scan Error : {ve}")
def abuseipdb_scan(self, remote_ip:str) -> Union[dict[str, any], None]:
"""Analyse l'ip avec AbuseIpDB """Analyse l'ip avec AbuseIpDB
Cette methode devra etre lancer toujours via un thread ou un timer. Cette methode devra etre lancer toujours via un thread ou un timer.
Args: Args:
@@ -575,6 +690,8 @@ class Defender():
dict[str, any] | None: les informations du provider dict[str, any] | None: les informations du provider
keys : 'score', 'country', 'isTor', 'totalReports' keys : 'score', 'country', 'isTor', 'totalReports'
""" """
if remote_ip in self.Config.WHITELISTED_IP:
return None
if self.defConfig['abuseipdb_scan'] == 0: if self.defConfig['abuseipdb_scan'] == 0:
return None return None
@@ -592,11 +709,14 @@ class Defender():
'Key': self.abuseipdb_key 'Key': self.abuseipdb_key
} }
response = requests.request(method='GET', url=url, headers=headers, params=querystring) response = requests.request(method='GET', url=url, headers=headers, params=querystring, timeout=self.timeout)
# Formatted output # Formatted output
decodedResponse = json.loads(response.text) decodedResponse = json.loads(response.text)
try: try:
if not 'data' in decodedResponse:
return None
result = { result = {
'score': decodedResponse['data']['abuseConfidenceScore'], 'score': decodedResponse['data']['abuseConfidenceScore'],
'country': decodedResponse['data']['countryCode'], 'country': decodedResponse['data']['countryCode'],
@@ -609,13 +729,191 @@ class Defender():
color_red = self.Config.CONFIG_COLOR['rouge'] color_red = self.Config.CONFIG_COLOR['rouge']
color_black = self.Config.CONFIG_COLOR['noire'] color_black = self.Config.CONFIG_COLOR['noire']
self.Irc.send2socket(f":{service_id} PRIVMSG {service_chanlog} :[ {color_red}ABUSEIPDB_SCAN{color_black} ] : Connexion de {remote_ip} Score: {str(result['score'])} | Country : {result['country']} | Tor : {str(result['isTor'])} | Total Reports : {str(result['totalReports'])}") self.Irc.send2socket(f":{service_id} PRIVMSG {service_chanlog} :[ {color_red}ABUSEIPDB_SCAN{color_black} ] : Connexion de {remote_ip} ==> Score: {str(result['score'])} | Country : {result['country']} | Tor : {str(result['isTor'])} | Total Reports : {str(result['totalReports'])}")
if result['isTor']:
self.Irc.send2socket(f":{service_id} GLINE +*@{remote_ip} {self.Config.GLINE_DURATION} This server do not allow Tor connexions {str(result['isTor'])} - Detected by Abuseipdb")
elif result['score'] >= 95:
self.Irc.send2socket(f":{service_id} GLINE +*@{remote_ip} {self.Config.GLINE_DURATION} You were banned from this server because your abuse score is = {str(result['score'])} - Detected by Abuseipdb")
response.close() response.close()
return result return result
except KeyError as ke: except KeyError as ke:
self.Irc.debug(f"AbuseIpDb KeyError : {ke}") self.Irc.debug(f"AbuseIpDb KeyError : {ke}")
except requests.ReadTimeout as rt:
self.Irc.debug(f"AbuseIpDb Timeout : {rt}")
except requests.ConnectionError as ce:
self.Irc.debug(f"AbuseIpDb Connection Error : {ce}")
def thread_abuseipdb_scan(self) -> None:
try:
while self.abuseipdb_isRunning:
list_to_remove:list = []
for ip in self.abuseipdb_remote_ip:
self.abuseipdb_scan(ip)
list_to_remove.append(ip)
time.sleep(1)
for ip_to_remove in list_to_remove:
self.abuseipdb_remote_ip.remove(ip_to_remove)
time.sleep(1)
return None
except ValueError as ve:
self.Irc.debug(f"thread_abuseipdb_scan Error : {ve}")
def freeipapi_scan(self, remote_ip:str) -> Union[dict[str, any], None]:
"""Analyse l'ip avec Freeipapi
Cette methode devra etre lancer toujours via un thread ou un timer.
Args:
remote_ip (_type_): l'ip a analyser
Returns:
dict[str, any] | None: les informations du provider
keys : 'countryCode', 'isProxy'
"""
if remote_ip in self.Config.WHITELISTED_IP:
return None
if self.defConfig['freeipapi_scan'] == 0:
return None
service_id = self.Config.SERVICE_ID
service_chanlog = self.Config.SERVICE_CHANLOG
color_red = self.Config.CONFIG_COLOR['rouge']
color_black = self.Config.CONFIG_COLOR['noire']
url = f'https://freeipapi.com/api/json/{remote_ip}'
headers = {
'Accept': 'application/json',
}
response = requests.request(method='GET', url=url, headers=headers, timeout=self.timeout)
# Formatted output
decodedResponse = json.loads(response.text)
try:
status_code = response.status_code
if status_code == 429:
self.Irc.debug(f'Too Many Requests - The rate limit for the API has been exceeded.')
return None
elif status_code != 200:
print("salut salut")
return None
result = {
'countryCode': decodedResponse['countryCode'] if 'countryCode' in decodedResponse else None,
'isProxy': decodedResponse['isProxy'] if 'isProxy' in decodedResponse else None
}
self.Irc.send2socket(f":{service_id} PRIVMSG {service_chanlog} :[ {color_red}FREEIPAPI_SCAN{color_black} ] : Connexion de {remote_ip} ==> Proxy: {str(result['isProxy'])} | Country : {str(result['countryCode'])}")
if result['isProxy']:
self.Irc.send2socket(f":{service_id} GLINE +*@{remote_ip} {self.Config.GLINE_DURATION} This server do not allow proxy connexions {str(result['isProxy'])} - detected by freeipapi")
response.close()
return result
except KeyError as ke:
self.Irc.debug(f"FREEIPAPI_SCAN KeyError : {ke}")
def thread_freeipapi_scan(self) -> None:
try:
while self.freeipapi_isRunning:
list_to_remove:list = []
for ip in self.freeipapi_remote_ip:
self.freeipapi_scan(ip)
list_to_remove.append(ip)
time.sleep(1)
for ip_to_remove in list_to_remove:
self.freeipapi_remote_ip.remove(ip_to_remove)
time.sleep(1)
return None
except ValueError as ve:
self.Irc.debug(f"thread_freeipapi_scan Error : {ve}")
def cloudfilt_scan(self, remote_ip:str) -> Union[dict[str, any], None]:
"""Analyse l'ip avec cloudfilt
Cette methode devra etre lancer toujours via un thread ou un timer.
Args:
remote_ip (_type_): l'ip a analyser
Returns:
dict[str, any] | None: les informations du provider
keys : 'countryCode', 'isProxy'
"""
if remote_ip in self.Config.WHITELISTED_IP:
return None
if self.defConfig['cloudfilt_scan'] == 0:
return None
if self.cloudfilt_key == '':
return None
service_id = self.Config.SERVICE_ID
service_chanlog = self.Config.SERVICE_CHANLOG
color_red = self.Config.CONFIG_COLOR['rouge']
color_black = self.Config.CONFIG_COLOR['noire']
url = f"https://developers18334.cloudfilt.com/"
data = {
'ip': remote_ip,
'key': self.cloudfilt_key
}
response = requests.post(url=url, data=data)
# Formatted output
decodedResponse = json.loads(response.text)
try:
status_code = response.status_code
if status_code != 200:
self.Irc.debug(f'Error connecting to cloudfilt API | Code: {str(status_code)}')
return None
result = {
'countryiso': decodedResponse['countryiso'] if 'countryiso' in decodedResponse else None,
'listed': decodedResponse['listed'] if 'listed' in decodedResponse else None,
'listed_by': decodedResponse['listed_by'] if 'listed_by' in decodedResponse else None,
'host': decodedResponse['host'] if 'host' in decodedResponse else None
}
self.Irc.send2socket(f":{service_id} PRIVMSG {service_chanlog} :[ {color_red}CLOUDFILT_SCAN{color_black} ] : Connexion de {str(remote_ip)} ==> Host: {str(result['host'])} | country: {str(result['countryiso'])} | listed: {str(result['listed'])} | listed by : {str(result['listed_by'])}")
if result['listed']:
self.Irc.send2socket(f":{service_id} GLINE +*@{remote_ip} {self.Config.GLINE_DURATION} You connexion is listed as dangerous {str(result['listed'])} {str(result['listed_by'])} - detected by cloudfilt")
response.close()
return result
except KeyError as ke:
self.Irc.debug(f"CLOUDFILT_SCAN KeyError : {ke}")
return None
def thread_cloudfilt_scan(self) -> None:
try:
while self.cloudfilt_isRunning:
list_to_remove:list = []
for ip in self.cloudfilt_remote_ip:
self.cloudfilt_scan(ip)
list_to_remove.append(ip)
time.sleep(1)
for ip_to_remove in list_to_remove:
self.cloudfilt_remote_ip.remove(ip_to_remove)
time.sleep(1)
return None
except ValueError as ve:
self.Irc.debug(f"Thread_cloudfilt_scan Error : {ve}")
def cmd(self, data:list) -> None: def cmd(self, data:list) -> None:
@@ -634,14 +932,21 @@ class Defender():
self.reputation_first_connexion['score'] = cmd[3] self.reputation_first_connexion['score'] = cmd[3]
# self.Base.scan_ports(cmd[2]) # self.Base.scan_ports(cmd[2])
if self.defConfig['local_scan'] == 1: if self.defConfig['local_scan'] == 1 and not cmd[2] in self.Config.WHITELISTED_IP:
self.Base.create_thread(self.scan_ports, (cmd[2], )) self.localscan_remote_ip.append(cmd[2])
if self.defConfig['psutil_scan'] == 1: if self.defConfig['psutil_scan'] == 1 and not cmd[2] in self.Config.WHITELISTED_IP:
self.Base.create_thread(self.get_ports_connexion, (cmd[2], )) self.psutil_remote_ip.append(cmd[2])
if self.defConfig['abuseipdb_scan'] == 1 and not cmd[2] in self.Config.WHITELISTED_IP:
self.abuseipdb_remote_ip.append(cmd[2])
if self.defConfig['freeipapi_scan'] == 1 and not cmd[2] in self.Config.WHITELISTED_IP:
self.freeipapi_remote_ip.append(cmd[2])
if self.defConfig['cloudfilt_scan'] == 1 and not cmd[2] in self.Config.WHITELISTED_IP:
self.cloudfilt_remote_ip.append(cmd[2])
if self.defConfig['abuseipdb_scan'] == 1:
self.Base.create_thread(self.abuseipdb_scan, (cmd[2], ))
# Possibilité de déclancher les bans a ce niveau. # Possibilité de déclancher les bans a ce niveau.
except IndexError: except IndexError:
self.Irc.debug(f'cmd reputation: index error') self.Irc.debug(f'cmd reputation: index error')
@@ -725,33 +1030,42 @@ class Defender():
case 'SLOG': case 'SLOG':
# self.Base.scan_ports(cmd[7]) # self.Base.scan_ports(cmd[7])
cmd.pop(0) cmd.pop(0)
if self.defConfig['local_scan'] == 1: if self.defConfig['local_scan'] == 1 and not cmd[7] in self.Config.WHITELISTED_IP:
self.Base.create_thread(self.scan_ports, (cmd[7], )) self.localscan_remote_ip.append(cmd[7])
if self.defConfig['psutil_scan'] == 1: if self.defConfig['psutil_scan'] == 1 and not cmd[7] in self.Config.WHITELISTED_IP:
self.Base.create_thread(self.get_ports_connexion, (cmd[7], )) self.psutil_remote_ip.append(cmd[7])
if self.defConfig['abuseipdb_scan'] == 1: if self.defConfig['abuseipdb_scan'] == 1 and not cmd[7] in self.Config.WHITELISTED_IP:
self.Base.create_thread(self.abuseipdb_scan, (cmd[7], )) self.abuseipdb_remote_ip.append(cmd[7])
if self.defConfig['freeipapi_scan'] == 1 and not cmd[7] in self.Config.WHITELISTED_IP:
self.freeipapi_remote_ip.append[cmd[7]]
if self.defConfig['cloudfilt_scan'] == 1 and not cmd[7] in self.Config.WHITELISTED_IP:
self.cloudfilt_remote_ip.append(cmd[7])
case 'NICK': case 'NICK':
# :0010BS24L NICK [NEWNICK] 1697917711 # :0010BS24L NICK [NEWNICK] 1697917711
# Changement de nickname # Changement de nickname
cmd.pop(0) try:
uid = str(cmd[0]).replace(':','') cmd.pop(0)
oldnick = self.db_reputation[uid]['nickname'] uid = str(cmd[0]).replace(':','')
newnickname = cmd[2] oldnick = self.db_reputation[uid]['nickname']
newnickname = cmd[2]
jail_salon = self.Config.SALON_JAIL jail_salon = self.Config.SALON_JAIL
service_id = self.Config.SERVICE_ID service_id = self.Config.SERVICE_ID
self.update_db_reputation(uid, newnickname) self.update_db_reputation(uid, newnickname)
if uid in self.db_reputation: if uid in self.db_reputation:
for chan in self.Irc.db_chan: for chan in self.Irc.db_chan:
if chan != jail_salon: if chan != jail_salon:
self.Irc.send2socket(f":{service_id} MODE {chan} -b {oldnick}!*@*") self.Irc.send2socket(f":{service_id} MODE {chan} -b {oldnick}!*@*")
self.Irc.send2socket(f":{service_id} MODE {chan} +b {newnickname}!*@*") self.Irc.send2socket(f":{service_id} MODE {chan} +b {newnickname}!*@*")
except KeyError as ke:
self.Irc.debug(f'cmd - NICK - KeyError: {ke}')
case 'QUIT': case 'QUIT':
# :001N1WD7L QUIT :Quit: free_znc_1 # :001N1WD7L QUIT :Quit: free_znc_1
@@ -773,7 +1087,6 @@ class Defender():
command = str(cmd[0]).lower() command = str(cmd[0]).lower()
fromuser = user fromuser = user
# print(command)
dnickname = self.Config.SERVICE_NICKNAME # Defender nickname dnickname = self.Config.SERVICE_NICKNAME # Defender nickname
dchanlog = self.Config.SERVICE_CHANLOG # Defender chan log dchanlog = self.Config.SERVICE_CHANLOG # Defender chan log
@@ -810,6 +1123,10 @@ class Defender():
release_code = cmd[1] release_code = cmd[1]
jailed_nickname = self.Irc.get_nickname(fromuser) jailed_nickname = self.Irc.get_nickname(fromuser)
jailed_UID = self.Irc.get_uid(fromuser) jailed_UID = self.Irc.get_uid(fromuser)
if not jailed_UID in self.db_reputation:
self.Irc.send2socket(f":{dnickname} NOTICE {fromuser} : No code is requested ...")
return False
jailed_IP = self.db_reputation[jailed_UID]['ip'] jailed_IP = self.db_reputation[jailed_UID]['ip']
jailed_salon = self.Config.SALON_JAIL jailed_salon = self.Config.SALON_JAIL
reputation_seuil = self.defConfig['reputation_seuil'] reputation_seuil = self.defConfig['reputation_seuil']
@@ -846,7 +1163,9 @@ class Defender():
except IndexError: except IndexError:
self.Irc.debug('_hcmd code: out of index') self.Irc.debug('_hcmd code: out of index')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} code [code]') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} code [code]')
pass except KeyError as ke:
self.Irc.debug(f'_hcmd code: KeyError {ke}')
# self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} code [code]')
pass pass
case 'reputation': case 'reputation':
@@ -962,6 +1281,8 @@ class Defender():
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set local_scan [ON/OFF]') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set local_scan [ON/OFF]')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set psutil_scan [ON/OFF]') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set psutil_scan [ON/OFF]')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set abuseipdb_scan [ON/OFF]') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set abuseipdb_scan [ON/OFF]')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set freeipapi_scan [ON/OFF]')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set cloudfilt_scan [ON/OFF]')
option = str(cmd[2]).lower() # => local_scan, psutil_scan, abuseipdb_scan option = str(cmd[2]).lower() # => local_scan, psutil_scan, abuseipdb_scan
action = str(cmd[3]).lower() # => on / off action = str(cmd[3]).lower() # => on / off
@@ -1009,14 +1330,49 @@ class Defender():
self.update_db_configuration(option, 0) self.update_db_configuration(option, 0)
self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Deactivated by {fromuser}") self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Deactivated by {fromuser}")
case 'freeipapi_scan':
if action == 'on':
if self.defConfig[option] == 1:
self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Already activated")
return None
self.update_db_configuration(option, 1)
self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Activated by {fromuser}")
elif action == 'off':
if self.defConfig[option] == 0:
self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Already Deactivated")
return None
self.update_db_configuration(option, 0)
self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Deactivated by {fromuser}")
case 'cloudfilt_scan':
if action == 'on':
if self.defConfig[option] == 1:
self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Already activated")
return None
self.update_db_configuration(option, 1)
self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Activated by {fromuser}")
elif action == 'off':
if self.defConfig[option] == 0:
self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Already Deactivated")
return None
self.update_db_configuration(option, 0)
self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Deactivated by {fromuser}")
case _: case _:
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set local_scan [ON/OFF]') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set local_scan [ON/OFF]')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set psutil_scan [ON/OFF]') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set psutil_scan [ON/OFF]')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set abuseipdb_scan [ON/OFF]') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set abuseipdb_scan [ON/OFF]')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set freeipapi_scan [ON/OFF]')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set cloudfilt_scan [ON/OFF]')
else: else:
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set local_scan [ON/OFF]') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set local_scan [ON/OFF]')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set psutil_scan [ON/OFF]') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set psutil_scan [ON/OFF]')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set abuseipdb_scan [ON/OFF]') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set abuseipdb_scan [ON/OFF]')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set freeipapi_scan [ON/OFF]')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set cloudfilt_scan [ON/OFF]')
case 'flood': case 'flood':
# .flood on/off # .flood on/off
@@ -1076,16 +1432,21 @@ class Defender():
self.Irc.debug(f"{self.__class__.__name__} Value Error : {ve}") self.Irc.debug(f"{self.__class__.__name__} Value Error : {ve}")
case 'status': case 'status':
color_green = self.Config.CONFIG_COLOR['verte']
color_red = self.Config.CONFIG_COLOR['rouge']
color_black = self.Config.CONFIG_COLOR['noire']
try: try:
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Reputation ==> {self.defConfig["reputation"]}') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : [{color_green if self.defConfig["reputation"] == 1 else color_red}Reputation{color_black}] ==> {self.defConfig["reputation"]}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : reputation_seuil ==> {self.defConfig["reputation_seuil"]}') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : reputation_seuil ==> {self.defConfig["reputation_seuil"]}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : reputation_ban_all_chan ==> {self.defConfig["reputation_ban_all_chan"]}') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : reputation_ban_all_chan ==> {self.defConfig["reputation_ban_all_chan"]}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : reputation_timer ==> {self.defConfig["reputation_timer"]}') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : reputation_timer ==> {self.defConfig["reputation_timer"]}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : [Proxy_scan]') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : [Proxy_scan]')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : local_scan ==> {self.defConfig["local_scan"]}') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : {color_green if self.defConfig["local_scan"] == 1 else color_red}local_scan{color_black} ==> {self.defConfig["local_scan"]}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : psutil_scan ==> {self.defConfig["psutil_scan"]}') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : {color_green if self.defConfig["psutil_scan"] == 1 else color_red}psutil_scan{color_black} ==> {self.defConfig["psutil_scan"]}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : abuseipdb_scan ==> {self.defConfig["abuseipdb_scan"]}') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : {color_green if self.defConfig["abuseipdb_scan"] == 1 else color_red}abuseipdb_scan{color_black} ==> {self.defConfig["abuseipdb_scan"]}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Flood ==> {self.defConfig["flood"]}') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : {color_green if self.defConfig["freeipapi_scan"] == 1 else color_red}freeipapi_scan{color_black} ==> {self.defConfig["freeipapi_scan"]}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : {color_green if self.defConfig["cloudfilt_scan"] == 1 else color_red}cloudfilt_scan{color_black} ==> {self.defConfig["cloudfilt_scan"]}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : [{color_green if self.defConfig["flood"] == 1 else color_red}Flood{color_black}] ==> {self.defConfig["flood"]}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : flood_action ==> Coming soon') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : flood_action ==> Coming soon')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : flood_message ==> {self.defConfig["flood_message"]}') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : flood_message ==> {self.defConfig["flood_message"]}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : flood_time ==> {self.defConfig["flood_time"]}') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : flood_time ==> {self.defConfig["flood_time"]}')

View File

@@ -66,6 +66,10 @@ class Test():
self.core.db_execute_query(self.session, table_logs) self.core.db_execute_query(self.session, table_logs)
return None return None
def unload(self) -> None:
return None
def _hcmds(self, user:str, cmd: list) -> None: def _hcmds(self, user:str, cmd: list) -> None:
command = cmd[0].lower() command = cmd[0].lower()