Files
Fail2banMqttActionBanishment/generic/fail2ban/action.d/f2b_mqtt_action_banisher.py
T
2026-07-20 11:05:07 +02:00

80 lines
2.1 KiB
Python

#!/usr/bin/python3
"""Fail2ban action: publish each ban/unban event to the local MQTT broker."""
import configparser
import datetime
import json
import socket
import sys
import uuid
from pathlib import Path
from typing import Any
import paho.mqtt.publish as publish
CONFIG_FILE = Path('/etc/fail2ban/mqtt.conf')
LOG_FILE = '/var/log/fail2ban.log'
# Timeout global sur toutes les connexions socket (évite de bloquer fail2ban)
socket.setdefaulttimeout(5)
def load_mqtt_config() -> dict[str, Any]:
parser = configparser.ConfigParser()
if not parser.read(CONFIG_FILE):
raise FileNotFoundError(f'{CONFIG_FILE} introuvable — voir mqtt.conf.example')
section = parser['mqtt']
return {
'host': section.get('host', '127.0.0.1'),
'port': section.getint('port', 1883),
'username': section['username'],
'password': section['password'],
}
def log(message: str) -> None:
try:
with open(LOG_FILE, 'a') as f:
f.write('{} [MQTT PUBLISHER] {}\n'.format(datetime.datetime.now(), message))
except OSError as e:
print(f'fail2ban mqtt log error: {e}')
def publish_message(base_topic: str, mqtt_params: dict[str, Any], topic: str, **payload: Any) -> None:
try:
message = json.dumps(payload)
publish.single(base_topic + topic, message, **mqtt_params)
except Exception as e:
log(f'publish_message error: {e}')
def main() -> None:
try:
config = load_mqtt_config()
except Exception as e:
log(f'config error: {e}')
return
node_id = uuid.getnode()
node_type = 'fail2ban'
base_topic = f'{node_type}/{node_id}'
mqtt_params: dict[str, Any] = dict(
qos=0,
retain=False,
hostname=config['host'],
port=config['port'],
keepalive=60,
auth=dict(username=config['username'], password=config['password']),
client_id=f'{node_type}_{node_id}',
)
try:
payload = json.loads(sys.argv[1])
publish_message(base_topic, mqtt_params, '/jail', node=node_id, **payload)
except Exception as e:
log(f'main error: {e}')
if __name__ == '__main__':
main()