commit c0543ca1256b5f87d127779395394e2fbce554be Author: root Date: Thu Dec 25 09:43:54 2025 -0800 Initial backup commit diff --git a/firehol-sync.sh b/firehol-sync.sh new file mode 100755 index 0000000..f34cda3 --- /dev/null +++ b/firehol-sync.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +MIKROTIK="10.10.10.1" +USER="fail2ban" +LIST="firehol_l1" +TIMEOUT="7d" +TMP="/tmp/firehol_l1.txt" +LOG="/var/log/firehol-sync.log" + +echo "[$(date)] FireHOL sync started" >> $LOG + +curl -s https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/firehol_level1.netset \ + | grep -E '^[0-9]' \ + | grep -v ':' \ + | grep -Ev '^(0\.|10\.|127\.|169\.254\.|172\.(1[6-9]|2[0-9]|3[0-1])\.|192\.168\.|224\.|240\.)' \ + > $TMP + +while read ip; do + ssh -o ConnectTimeout=3 $USER@$MIKROTIK \ + "/ip firewall address-list add list=$LIST address=$ip timeout=$TIMEOUT comment=FireHOL" \ + 2>/dev/null +done < $TMP + +echo "[$(date)] FireHOL sync finished" >> $LOG diff --git a/firehol_diff_sync.py b/firehol_diff_sync.py new file mode 100755 index 0000000..50efdbb --- /dev/null +++ b/firehol_diff_sync.py @@ -0,0 +1,139 @@ +#!/usr/bin/env python3 + +from routeros_api import RouterOsApiPool +import requests +import ipaddress +import datetime +import sys + +# ======================= +# CONFIGURATION +# ======================= + +MIKROTIK_IP = "10.10.10.1" +USER = "fail2ban" +PASSWORD = "password" + +ADDRESS_LIST = "firehol_l1" +TIMEOUT = "7d" + +FIREHOL_URL = "https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/firehol_level1.netset" + +# Whitelist (ALWAYS CIDR) +WHITELIST = { + "100.64.0.0/10" # Apartment CGNAT +} + +# Safety cap +MAX_NEW_ENTRIES = 5000 + +# ======================= +# FUNCTIONS +# ======================= + +def valid_net(net): + try: + n = ipaddress.ip_network(net, strict=False) + + if n.version != 4: + return False + + if n.prefixlen < 10: + return False + + if ( + n.is_private + or n.is_loopback + or n.is_multicast + or n.is_reserved + or n.is_link_local + ): + return False + + return True + except Exception: + return False + + +def is_whitelisted(net): + try: + n = ipaddress.ip_network(net, strict=False) + for w in WHITELIST: + wnet = ipaddress.ip_network(w, strict=False) + if n.subnet_of(wnet) or n == wnet: + return True + return False + except Exception: + return False + + +# ======================= +# MAIN +# ======================= + +print(f"[{datetime.datetime.now()}] FireHOL diff sync start") + +# Fetch FireHOL +try: + response = requests.get(FIREHOL_URL, timeout=30) + response.raise_for_status() + firehol_raw = response.text.splitlines() +except Exception as e: + print(f"ERROR: Failed to fetch FireHOL list: {e}") + sys.exit(1) + +# Parse & filter FireHOL +firehol = { + net.strip() + for net in firehol_raw + if valid_net(net.strip()) and not is_whitelisted(net.strip()) +} + +print(f"Parsed FireHOL entries after filtering: {len(firehol)}") + +# Connect to MikroTik API (RouterOS v7) +try: + api_pool = RouterOsApiPool( + MIKROTIK_IP, + username=USER, + password=PASSWORD, + plaintext_login=True + ) + api = api_pool.get_api() +except Exception as e: + print(f"ERROR: Failed to connect to MikroTik API: {e}") + sys.exit(1) + +address_list = api.get_resource("/ip/firewall/address-list") + +# Fetch existing MikroTik entries +current = { + entry["address"] + for entry in address_list.get(list=ADDRESS_LIST) +} + +print(f"Current MikroTik entries: {len(current)}") + +# Diff calculation +to_add = firehol - current + +print(f"New entries to add: {len(to_add)}") + +# Safety check +if len(to_add) > MAX_NEW_ENTRIES: + print("ERROR: Safety stop — too many new entries") + api_pool.disconnect() + sys.exit(1) + +# Add missing entries +for net in sorted(to_add): + address_list.add( + list=ADDRESS_LIST, + address=net, + timeout=TIMEOUT, + comment="FireHOL L1" + ) + +api_pool.disconnect() + +print("FireHOL diff sync complete") diff --git a/test.py b/test.py new file mode 100644 index 0000000..b54ddd1 --- /dev/null +++ b/test.py @@ -0,0 +1,13 @@ +from routeros_api import RouterOsApiPool + +api_pool = RouterOsApiPool( + "10.10.10.1", + username="fail2ban", + password="password", + port=8728, + plaintext_login=True +) + +api = api_pool.get_api() +print("API LOGIN OK") +api_pool.disconnect()