From 0e2c69579a5f737b139cb87231948242a082163c Mon Sep 17 00:00:00 2001 From: zwitschi Date: Tue, 4 Aug 2026 18:38:08 +0200 Subject: [PATCH] Remove MikroTik block list script and enhance scan.py for firewall synchronization - Deleted the existing MikroTik block list script (mikrotik-block.rsc) which contained whitelisted and blocked IP addresses. - Updated scan.py to include options for synchronizing the MikroTik blocked list after scanning. - Added functionality to preview firewall changes without applying them. - Integrated the MikrotikFirewall class to manage the synchronization of blocked IPs with the MikroTik device. --- .gitignore | 1 + data/whois_cache.json | 48 ++- firewall.py | 319 ++++++++++++++++++++ reports/mikrotik-block.rsc | 603 ------------------------------------- scan.py | 39 +-- 5 files changed, 389 insertions(+), 621 deletions(-) create mode 100644 firewall.py delete mode 100644 reports/mikrotik-block.rsc diff --git a/.gitignore b/.gitignore index 4615356..9563132 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,5 @@ __pycache__/ # reports data reports/copyparty/ +reports/mikrotik/ reports/npm/ \ No newline at end of file diff --git a/data/whois_cache.json b/data/whois_cache.json index 7b0186c..6925c0e 100644 --- a/data/whois_cache.json +++ b/data/whois_cache.json @@ -864,5 +864,51 @@ "209.99.190.99": "209.99.184.0/21", "20.104.18.253": "20.64.0.0/10", "178.128.176.132": "178.128.176.0/20", - "81.171.74.60": "81.171.74.0/24" + "81.171.74.60": "81.171.74.0/24", + "72.146.33.199": "72.144.0.0/14", + "147.93.169.104": "147.93.168.0/22", + "34.39.210.94": "34.39.128.0/17", + "20.215.185.25": "20.192.0.0/10", + "23.180.120.146": "23.180.120.0/24", + "167.99.204.6": "167.99.192.0/20", + "172.213.153.79": "172.208.0.0/13", + "20.203.243.122": "20.192.0.0/10", + "194.26.192.156": "194.26.192.0/24", + "74.248.16.78": "74.248.0.0/15", + "34.141.160.140": "34.141.160.0/20", + "34.83.69.198": "34.83.64.0/20", + "2600:3000:1305:4212::82": "2600:3000::/32", + "64.226.123.37": "64.226.112.0/20", + "172.213.218.74": "172.208.0.0/13", + "159.65.10.116": "159.65.0.0/20", + "162.141.167.71": "162.141.167.0/24", + "20.91.203.45": "20.64.0.0/10", + "80.94.92.167": "80.94.92.0/24", + "194.102.104.29": "194.102.104.0/24", + "143.244.162.58": "143.244.160.0/20", + "4.223.73.90": "4.208.0.0/12", + "136.107.217.8": "136.107.128.0/17", + "20.203.179.12": "20.192.0.0/10", + "4.184.238.149": "4.176.0.0/12", + "20.52.217.208": "20.48.0.0/12", + "20.218.243.163": "20.192.0.0/10", + "34.125.219.56": "34.125.208.0/20", + "163.7.13.115": "163.7.13.0/24", + "34.26.219.248": "34.26.0.0/16", + "2.57.122.13": "2.57.122.0/24", + "34.95.238.121": "34.95.224.0/20", + "20.208.41.112": "20.192.0.0/10", + "182.88.226.154": "182.88.0.0/14", + "2602:fa59:10:712::1": "2602:fa59::/40", + "34.84.59.119": "34.84.48.0/20", + "2a04:c300:400::6f": "2a04:c300::/29", + "45.146.55.165": "45.146.55.0/24", + "85.204.70.94": "85.204.70.0/24", + "157.245.63.62": "157.245.48.0/20", + "23.178.112.210": "23.178.112.0/24", + "221.13.93.71": "221.13.64.0/19", + "163.7.13.111": "163.7.13.0/24", + "222.176.200.251": "222.176.0.0/13", + "123.163.114.150": "123.160.0.0/14", + "136.64.132.60": "136.64.0.0/15" } \ No newline at end of file diff --git a/firewall.py b/firewall.py new file mode 100644 index 0000000..2e44669 --- /dev/null +++ b/firewall.py @@ -0,0 +1,319 @@ +""" +firewall.py - +Module for interacting with the Mikrotik routeros shell to manage firewall rules and IP address lists. +Provides functions to read the current firewall configuration, add and remove IPs from the blocklist. +Reads the latest report from the IDS scan, reads the current firewall configuration, and updates the router's blocklist accordingly. +""" + +from __future__ import annotations + +import os +import json +import paramiko +from datetime import datetime +import shlex +from typing import Iterable +from utils import is_whitelisted, parse_ip, split_versions + +DATA_DIR = os.path.join(os.path.dirname(__file__), "data", "mikrotik") +REPORT_DIR = os.path.join(os.path.dirname(__file__), "reports") +MIKROTIK_DATA_DIR = os.path.join(REPORT_DIR, "mikrotik", "data") + +SSH_TIMEOUT = 10 # seconds +SSH_PORT = 22 +ROUTER_IP = os.environ.get("ROUTER_IP", "192.168.88.1") +ROUTER_USER = os.environ.get("ROUTER_USER", "admin") +ROUTER_PASSWORD = os.environ.get("ROUTER_PASSWORD", "M11ffpgm") +BLOCKLIST_NAME = os.environ.get("BLOCKLIST_NAME", "Blocked") +WHITELIST_NAMES = os.environ.get( + "WHITELIST_NAMES", "Cloudflare,Openfactory").split(",") + + +class MikrotikFirewall: + """ + Class to manage Mikrotik firewall rules and IP address lists. + Provides methods to read the current blocklist, add/remove IPs, and update the blocklist based on IDS scan reports. + """ + + def __init__(self, router_ip: str = ROUTER_IP, username: str = ROUTER_USER, + password: str = ROUTER_PASSWORD): + self.router_ip = router_ip + self.username = username + self.password = password + self.client: paramiko.SSHClient | None = None + + def connect(self) -> None: + """Establish an SSH connection to the Mikrotik router.""" + client = paramiko.SSHClient() + client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + try: + # RouterOS 7.20.x exposes an RSA host key and classic SSH ciphers. + client.connect( + self.router_ip, + port=SSH_PORT, + username=self.username, + password=self.password, + timeout=SSH_TIMEOUT, + banner_timeout=SSH_TIMEOUT, + auth_timeout=SSH_TIMEOUT, + allow_agent=False, + look_for_keys=False, + compress=False, + disabled_algorithms={"pubkeys": ["rsa-sha2-512"]}, + ) + except Exception: + client.close() + raise + self.client = client + + def disconnect(self) -> None: + """Close the SSH connection.""" + if self.client: + self.client.close() + self.client = None + + def execute_command(self, command: str) -> str: + """Execute a command on the Mikrotik router via SSH and return the output.""" + if not self.client: + raise RuntimeError("SSH client is not connected.") + stdin, stdout, stderr = self.client.exec_command(command) + output = stdout.read().decode("utf-8") + error = stderr.read().decode("utf-8") + if error: + raise RuntimeError(f"Error executing command '{command}': {error}") + return output + + def get_address_list_ipv4(self, name: str) -> set[str]: + """Retrieve the current IPv4 address list from the Mikrotik router.""" + output = self.execute_command("/ip firewall address-list print") + ips = set() + for line in output.splitlines(): + parts = line.split() + if len(parts) >= 3 and parts[1] == "list" and parts[2] == name: + ip = parts[0] + ips.add(ip) + return ips + + def get_address_list_ipv6(self, name: str) -> set[str]: + """Retrieve the current IPv6 address list from the Mikrotik router.""" + output = self.execute_command("/ipv6 firewall address-list print") + ips = set() + for line in output.splitlines(): + parts = line.split() + if len(parts) >= 3 and parts[1] == "list" and parts[2] == name: + ip = parts[0] + ips.add(ip) + return ips + + @staticmethod + def _parse_terse_output(output: str) -> list[dict[str, str]]: + """Parse RouterOS `print terse` records into key/value dictionaries.""" + records = [] + for line in output.splitlines(): + fields = {} + for field in shlex.split(line): + key, separator, value = field.partition("=") + if separator: + fields[key] = value + if fields: + records.append(fields) + return records + + def get_address_lists(self, ipv6: bool = False) -> list[dict[str, str]]: + """Retrieve all address-list entries in structured form.""" + path = "/ipv6" if ipv6 else "/ip" + output = self.execute_command( + f"{path} firewall address-list print terse") + return self._parse_terse_output(output) + + def get_firewall_rules(self, ipv6: bool = False) -> list[dict[str, str]]: + """Retrieve all firewall filter rules in structured form.""" + path = "/ipv6" if ipv6 else "/ip" + output = self.execute_command( + f"{path} firewall filter print terse") + return self._parse_terse_output(output) + + def save_state_report(self, report_dir: str = REPORT_DIR, + changes: dict | None = None) -> str: + """Save current address lists and firewall rules for auditing.""" + state = { + "router": self.router_ip, + "collected_at": datetime.now().astimezone().isoformat(), + "address_lists": { + "ipv4": self.get_address_lists(), + "ipv6": self.get_address_lists(ipv6=True), + }, + "firewall_rules": { + "ipv4": self.get_firewall_rules(), + "ipv6": self.get_firewall_rules(ipv6=True), + }, + } + if changes is not None: + state["changes"] = changes + data_dir = os.path.join(report_dir, "mikrotik", "data") + os.makedirs(data_dir, exist_ok=True) + for version in ("ipv4", "ipv6"): + with open(os.path.join(data_dir, f"address_list_{version}.json"), "w", encoding="utf-8") as file: + json.dump(state["address_lists"][version], + file, indent=2, sort_keys=True) + with open(os.path.join(data_dir, f"firewall_{version}.json"), "w", encoding="utf-8") as file: + json.dump(state["firewall_rules"][version], + file, indent=2, sort_keys=True) + timestamp = datetime.now().strftime("%Y-%m-%d-%H-%M-%S") + report_path = os.path.join(report_dir, "mikrotik", f"{timestamp}.json") + with open(report_path, "w", encoding="utf-8") as file: + json.dump(state, file, indent=2, sort_keys=True) + return report_path + + def sync_blocklist(self, blocked_ipv4: Iterable[str], + blocked_ipv6: Iterable[str], + dry_run: bool = False, + report_dir: str = REPORT_DIR) -> dict[str, list[str]]: + """Synchronize the Blocked list with scan targets and audit the result.""" + desired_ipv4 = set(blocked_ipv4) + desired_ipv6 = set(blocked_ipv6) + current_ipv4 = self.get_address_list_ipv4(BLOCKLIST_NAME) + current_ipv6 = self.get_address_list_ipv6(BLOCKLIST_NAME) + whitelisted_ipv4 = set() + whitelisted_ipv6 = set() + for name in WHITELIST_NAMES: + whitelisted_ipv4.update(self.get_address_list_ipv4(name)) + whitelisted_ipv6.update(self.get_address_list_ipv6(name)) + + changes = { + "added_ipv4": sorted(desired_ipv4 - current_ipv4 - whitelisted_ipv4), + "added_ipv6": sorted(desired_ipv6 - current_ipv6 - whitelisted_ipv6), + "removed_ipv4": sorted(current_ipv4 - desired_ipv4), + "removed_ipv6": sorted(current_ipv6 - desired_ipv6), + "dry_run": dry_run, + } + if not dry_run: + for ip in changes["removed_ipv4"]: + self.execute_command( + f"/ip firewall address-list remove [find list={BLOCKLIST_NAME} address={ip}]") + for ip in changes["removed_ipv6"]: + self.execute_command( + f"/ipv6 firewall address-list remove [find list={BLOCKLIST_NAME} address={ip}]") + self.write_address_list_ipv4(BLOCKLIST_NAME, changes["added_ipv4"]) + self.write_address_list_ipv6(BLOCKLIST_NAME, changes["added_ipv6"]) + self.save_state_report(report_dir, changes) + return changes + + def write_address_list_ipv4(self, name: str, ips: Iterable[str]) -> None: + """Write a list of IPv4 addresses to the Mikrotik router's address list.""" + for ip in ips: + if is_whitelisted(ip): + continue # Skip whitelisted IPs + self.execute_command( + f"/ip firewall address-list add list={name} address={ip}") + + def write_address_list_ipv6(self, name: str, ips: Iterable[str]) -> None: + """Write a list of IPv6 addresses to the Mikrotik router's address list.""" + for ip in ips: + if is_whitelisted(ip): + continue # Skip whitelisted IPs + self.execute_command( + f"/ipv6 firewall address-list add list={name} address={ip}") + + +def get_scan_report(report_dir: str = REPORT_DIR) -> dict[str, list[str]]: + """Read the latest scan report `mikrotik-block.rsc` from the report directory and return the list of blocked IPs.""" + report_path = os.path.join(report_dir, "mikrotik-block.rsc") + if not os.path.exists(report_path): + raise FileNotFoundError(f"Scan report not found: {report_path}") + + # add sections, they start with `/ip firewall address-list` or `/ipv6 firewall address-list` and end with a blank line or EOF + sections = { + "/ip firewall address-list": [], + "/ipv6 firewall address-list": [], + } + # add list=Cloudflare or list=Openfactory to whitelist sections, list=Blocked to blocked section + with open(report_path, "r", encoding="utf-8") as f: + current_section = None + for line in f: + line = line.strip() + if not line: + current_section = None + continue + if line.startswith("/ip firewall address-list"): + current_section = "/ip firewall address-list" + continue + if line.startswith("/ipv6 firewall address-list"): + current_section = "/ipv6 firewall address-list" + continue + if current_section: + sections[current_section].append(line) + + return sections + + +def main(): + """Legacy entry point for applying the latest generated RouterOS report.""" + # Read the latest scan report + scan_report = get_scan_report(REPORT_DIR) + + # Connect to the Mikrotik router + firewall = MikrotikFirewall() + firewall.connect() + + # read current blocked IPs from the router + current_blocked_ipv4 = firewall.get_address_list_ipv4(BLOCKLIST_NAME) + current_blocked_ipv6 = firewall.get_address_list_ipv6(BLOCKLIST_NAME) + + # read whitelisted IPs from the router + whitelisted_ipv4 = set() + whitelisted_ipv6 = set() + for wl_name in WHITELIST_NAMES: + whitelisted_ipv4.update(firewall.get_address_list_ipv4(wl_name)) + whitelisted_ipv6.update(firewall.get_address_list_ipv6(wl_name)) + + # read blocked IPs from the scan report + blocked_ipv4 = set() + blocked_ipv6 = set() + for line in scan_report["/ip firewall address-list"]: + if "list=Blocked" in line: + parts = line.split() + for part in parts: + if part.startswith("address="): + ip = part.split("=")[1] + blocked_ipv4.add(ip) + for line in scan_report["/ipv6 firewall address-list"]: + if "list=Blocked" in line: + parts = line.split() + for part in parts: + if part.startswith("address="): + ip = part.split("=")[1] + blocked_ipv6.add(ip) + + # Determine which IPs to add and remove + to_add_ipv4 = blocked_ipv4 - current_blocked_ipv4 - whitelisted_ipv4 + to_add_ipv6 = blocked_ipv6 - current_blocked_ipv6 - whitelisted_ipv6 + to_remove_ipv4 = current_blocked_ipv4 - blocked_ipv4 + to_remove_ipv6 = current_blocked_ipv6 - blocked_ipv6 + + # Remove old blocked IPs + for ip in to_remove_ipv4: + firewall.execute_command( + f"/ip firewall address-list remove [find list={BLOCKLIST_NAME} address={ip}]") + for ip in to_remove_ipv6: + firewall.execute_command( + f"/ipv6 firewall address-list remove [find list={BLOCKLIST_NAME} address={ip}]") + + # Add new blocked IPs + firewall.write_address_list_ipv4(BLOCKLIST_NAME, to_add_ipv4) + firewall.write_address_list_ipv6(BLOCKLIST_NAME, to_add_ipv6) + + firewall.save_state_report(REPORT_DIR) + + # Disconnect from the router + firewall.disconnect() + + # Print summary + print( + f"Removed {len(to_remove_ipv4)} IPv4 and {len(to_remove_ipv6)} IPv6 addresses from the blocklist.") + print( + f"Added {len(to_add_ipv4)} IPv4 and {len(to_add_ipv6)} IPv6 addresses to the blocklist.") + + +if __name__ == "__main__": + main() diff --git a/reports/mikrotik-block.rsc b/reports/mikrotik-block.rsc deleted file mode 100644 index 790d011..0000000 --- a/reports/mikrotik-block.rsc +++ /dev/null @@ -1,603 +0,0 @@ -# ids firewall export - generated 2026-08-03T17:02:13 - -# Openfactory IPv4 ranges (whitelisted) -/ip firewall address-list -add list=Openfactory address=5.226.144.0/21 - -# Cloudflare IPv4 ranges (whitelisted) -/ip firewall address-list -add list=Cloudflare address=173.245.48.0/20 -add list=Cloudflare address=103.21.244.0/22 -add list=Cloudflare address=103.22.200.0/22 -add list=Cloudflare address=103.31.4.0/22 -add list=Cloudflare address=141.101.64.0/18 -add list=Cloudflare address=108.162.192.0/18 -add list=Cloudflare address=190.93.240.0/20 -add list=Cloudflare address=188.114.96.0/20 -add list=Cloudflare address=197.234.240.0/22 -add list=Cloudflare address=198.41.128.0/17 -add list=Cloudflare address=162.158.0.0/15 -add list=Cloudflare address=104.16.0.0/13 -add list=Cloudflare address=104.24.0.0/14 -add list=Cloudflare address=172.64.0.0/13 -add list=Cloudflare address=131.0.72.0/22 - -# Cloudflare IPv6 ranges (whitelisted) -/ipv6 firewall address-list -add list=Cloudflare address=2400:cb00::/32 -add list=Cloudflare address=2606:4700::/32 -add list=Cloudflare address=2803:f800::/32 -add list=Cloudflare address=2405:b500::/32 -add list=Cloudflare address=2405:8100::/32 -add list=Cloudflare address=2a06:98c0::/29 -add list=Cloudflare address=2c0f:f248::/32 - -# PaloAlto IPv4 ranges (whitelisted) -/ip firewall address-list -add list=PaloAlto address=35.203.210.0/23 -add list=PaloAlto address=144.86.173.0/24 -add list=PaloAlto address=147.185.132.0/23 -add list=PaloAlto address=162.216.149.0/24 -add list=PaloAlto address=162.216.150.0/24 -add list=PaloAlto address=172.105.147.0/24 -add list=PaloAlto address=198.235.24.0/24 -add list=PaloAlto address=205.210.31.0/24 -add list=PaloAlto address=216.25.88.0/21 - -# PaloAlto IPv6 ranges (whitelisted) -/ipv6 firewall address-list -add list=PaloAlto address=2604:a940:300:5b6::/64 -add list=PaloAlto address=2604:a940:301:225::/64 -add list=PaloAlto address=2604:a940:302:118::/64 - -# Blocked IPv4 (509, non-whitelisted) -/ip firewall address-list -add list=Blocked address=2.57.122.173/32 -add list=Blocked address=2.58.56.101/32 -add list=Blocked address=3.27.206.50/32 -add list=Blocked address=3.77.92.222/32 -add list=Blocked address=3.79.41.12/32 -add list=Blocked address=3.101.54.4/32 -add list=Blocked address=3.107.107.18/32 -add list=Blocked address=3.237.185.144/32 -add list=Blocked address=3.250.52.216/32 -add list=Blocked address=4.176.0.0/12 -add list=Blocked address=4.192.0.0/12 -add list=Blocked address=4.208.0.0/12 -add list=Blocked address=4.224.0.0/12 -add list=Blocked address=4.246.70.112/32 -add list=Blocked address=5.34.213.142/32 -add list=Blocked address=5.161.62.209/32 -add list=Blocked address=5.161.225.116/32 -add list=Blocked address=5.253.247.16/32 -add list=Blocked address=5.255.119.161/32 -add list=Blocked address=8.229.1.130/32 -add list=Blocked address=8.229.130.50/32 -add list=Blocked address=8.231.78.19/32 -add list=Blocked address=8.234.157.73/32 -add list=Blocked address=8.234.207.247/32 -add list=Blocked address=8.235.114.162/32 -add list=Blocked address=9.205.16.190/32 -add list=Blocked address=13.57.15.41/32 -add list=Blocked address=13.83.161.80/32 -add list=Blocked address=13.126.86.18/32 -add list=Blocked address=13.221.106.198/32 -add list=Blocked address=15.206.146.240/32 -add list=Blocked address=16.146.99.254/32 -add list=Blocked address=18.142.90.109/32 -add list=Blocked address=18.191.56.164/32 -add list=Blocked address=18.227.73.7/32 -add list=Blocked address=18.236.136.230/32 -add list=Blocked address=20.0.0.0/11 -add list=Blocked address=20.46.121.148/32 -add list=Blocked address=20.46.252.52/32 -add list=Blocked address=20.48.0.0/12 -add list=Blocked address=20.64.0.0/10 -add list=Blocked address=20.150.0.0/15 -add list=Blocked address=20.160.0.0/12 -add list=Blocked address=20.184.150.240/32 -add list=Blocked address=20.192.0.0/10 -add list=Blocked address=20.215.189.213/32 -add list=Blocked address=23.94.155.57/32 -add list=Blocked address=23.95.226.104/32 -add list=Blocked address=23.102.123.231/32 -add list=Blocked address=23.161.169.62/32 -add list=Blocked address=23.161.169.127/32 -add list=Blocked address=23.178.112.0/24 -add list=Blocked address=23.180.120.134/32 -add list=Blocked address=23.180.120.147/32 -add list=Blocked address=23.234.98.171/32 -add list=Blocked address=24.144.85.55/32 -add list=Blocked address=31.56.58.0/24 -add list=Blocked address=31.58.51.130/32 -add list=Blocked address=31.58.51.184/32 -add list=Blocked address=31.59.129.193/32 -add list=Blocked address=31.184.236.8/32 -add list=Blocked address=34.7.160.235/32 -add list=Blocked address=34.7.193.250/32 -add list=Blocked address=34.11.108.163/32 -add list=Blocked address=34.11.127.22/32 -add list=Blocked address=34.17.159.73/32 -add list=Blocked address=34.18.38.137/32 -add list=Blocked address=34.21.144.169/32 -add list=Blocked address=34.24.155.203/32 -add list=Blocked address=34.26.191.118/32 -add list=Blocked address=34.31.88.250/32 -add list=Blocked address=34.40.240.124/32 -add list=Blocked address=34.42.48.100/32 -add list=Blocked address=34.47.183.174/32 -add list=Blocked address=34.47.194.183/32 -add list=Blocked address=34.55.200.45/32 -add list=Blocked address=34.59.187.134/32 -add list=Blocked address=34.64.173.205/32 -add list=Blocked address=34.65.14.246/32 -add list=Blocked address=34.65.18.71/32 -add list=Blocked address=34.65.138.195/32 -add list=Blocked address=34.69.107.154/32 -add list=Blocked address=34.73.128.17/32 -add list=Blocked address=34.75.4.161/32 -add list=Blocked address=34.82.10.34/32 -add list=Blocked address=34.86.126.198/32 -add list=Blocked address=34.86.217.208/32 -add list=Blocked address=34.90.87.32/32 -add list=Blocked address=34.90.88.37/32 -add list=Blocked address=34.91.243.226/32 -add list=Blocked address=34.94.172.72/32 -add list=Blocked address=34.95.239.96/32 -add list=Blocked address=34.105.30.251/32 -add list=Blocked address=34.116.255.65/32 -add list=Blocked address=34.118.184.2/32 -add list=Blocked address=34.131.251.163/32 -add list=Blocked address=34.139.141.56/32 -add list=Blocked address=34.145.62.28/32 -add list=Blocked address=34.146.12.12/32 -add list=Blocked address=34.148.8.63/32 -add list=Blocked address=34.154.122.183/32 -add list=Blocked address=34.158.83.192/32 -add list=Blocked address=34.171.75.208/32 -add list=Blocked address=34.175.82.8/32 -add list=Blocked address=34.181.134.189/32 -add list=Blocked address=34.186.83.134/32 -add list=Blocked address=34.187.20.70/32 -add list=Blocked address=34.187.82.183/32 -add list=Blocked address=34.187.200.119/32 -add list=Blocked address=34.242.226.103/32 -add list=Blocked address=34.244.177.56/32 -add list=Blocked address=35.95.56.230/32 -add list=Blocked address=35.157.251.190/32 -add list=Blocked address=35.182.17.8/32 -add list=Blocked address=35.184.157.121/32 -add list=Blocked address=35.187.9.30/32 -add list=Blocked address=35.192.232.168/32 -add list=Blocked address=35.196.22.146/32 -add list=Blocked address=35.198.180.224/32 -add list=Blocked address=35.199.111.12/32 -add list=Blocked address=35.199.115.51/32 -add list=Blocked address=35.199.183.190/32 -add list=Blocked address=35.201.159.247/32 -add list=Blocked address=35.204.88.252/32 -add list=Blocked address=35.204.141.252/32 -add list=Blocked address=35.230.52.27/32 -add list=Blocked address=35.231.41.225/32 -add list=Blocked address=35.231.100.82/32 -add list=Blocked address=35.237.138.104/32 -add list=Blocked address=35.237.178.50/32 -add list=Blocked address=35.243.173.211/32 -add list=Blocked address=35.243.223.147/32 -add list=Blocked address=35.255.40.65/32 -add list=Blocked address=36.106.166.92/32 -add list=Blocked address=36.106.166.223/32 -add list=Blocked address=37.140.223.6/32 -add list=Blocked address=37.140.223.58/32 -add list=Blocked address=38.248.95.248/32 -add list=Blocked address=41.143.154.1/32 -add list=Blocked address=43.98.201.177/32 -add list=Blocked address=43.228.157.102/32 -add list=Blocked address=43.228.157.191/32 -add list=Blocked address=44.224.0.0/11 -add list=Blocked address=45.8.196.200/32 -add list=Blocked address=45.45.237.69/32 -add list=Blocked address=45.45.237.214/32 -add list=Blocked address=45.61.150.67/32 -add list=Blocked address=45.61.187.30/32 -add list=Blocked address=45.67.85.190/32 -add list=Blocked address=45.88.138.44/32 -add list=Blocked address=45.130.203.154/32 -add list=Blocked address=45.130.203.177/32 -add list=Blocked address=45.131.193.139/32 -add list=Blocked address=45.131.195.0/24 -add list=Blocked address=45.134.20.116/32 -add list=Blocked address=45.134.20.128/32 -add list=Blocked address=45.138.16.114/32 -add list=Blocked address=45.139.104.172/32 -add list=Blocked address=45.146.54.80/32 -add list=Blocked address=45.146.54.137/32 -add list=Blocked address=45.146.55.11/32 -add list=Blocked address=45.146.55.48/32 -add list=Blocked address=45.148.10.0/24 -add list=Blocked address=45.153.34.16/32 -add list=Blocked address=45.153.34.43/32 -add list=Blocked address=45.153.34.182/32 -add list=Blocked address=45.154.98.0/24 -add list=Blocked address=45.154.138.181/32 -add list=Blocked address=45.154.138.232/32 -add list=Blocked address=46.23.108.234/32 -add list=Blocked address=46.232.235.0/24 -add list=Blocked address=47.85.160.47/32 -add list=Blocked address=51.79.208.246/32 -add list=Blocked address=51.103.133.211/32 -add list=Blocked address=51.103.152.96/32 -add list=Blocked address=51.116.233.22/32 -add list=Blocked address=51.120.0.0/16 -add list=Blocked address=52.139.36.144/32 -add list=Blocked address=52.159.244.176/32 -add list=Blocked address=52.160.0.0/11 -add list=Blocked address=52.224.0.0/11 -add list=Blocked address=54.82.69.43/32 -add list=Blocked address=54.163.186.39/32 -add list=Blocked address=54.169.103.174/32 -add list=Blocked address=54.179.129.22/32 -add list=Blocked address=54.206.147.115/32 -add list=Blocked address=54.210.219.163/32 -add list=Blocked address=54.216.227.171/32 -add list=Blocked address=58.212.237.231/32 -add list=Blocked address=62.60.130.128/32 -add list=Blocked address=62.60.130.227/32 -add list=Blocked address=62.93.179.146/32 -add list=Blocked address=64.23.218.208/32 -add list=Blocked address=64.89.161.82/32 -add list=Blocked address=64.89.161.85/32 -add list=Blocked address=64.225.63.129/32 -add list=Blocked address=64.225.75.246/32 -add list=Blocked address=64.227.32.66/32 -add list=Blocked address=65.0.122.218/32 -add list=Blocked address=66.187.5.228/32 -add list=Blocked address=66.187.6.102/32 -add list=Blocked address=66.228.38.221/32 -add list=Blocked address=66.249.74.165/32 -add list=Blocked address=68.183.9.16/32 -add list=Blocked address=68.183.180.73/32 -add list=Blocked address=68.220.0.0/15 -add list=Blocked address=69.30.85.194/32 -add list=Blocked address=69.164.220.85/32 -add list=Blocked address=69.164.220.232/32 -add list=Blocked address=72.146.20.230/32 -add list=Blocked address=73.116.194.16/32 -add list=Blocked address=74.7.0.0/16 -add list=Blocked address=74.208.40.151/32 -add list=Blocked address=74.248.0.0/15 -add list=Blocked address=74.248.33.172/32 -add list=Blocked address=77.90.185.230/32 -add list=Blocked address=80.91.86.169/32 -add list=Blocked address=81.171.72.93/32 -add list=Blocked address=81.171.72.135/32 -add list=Blocked address=81.171.74.60/32 -add list=Blocked address=82.39.206.154/32 -add list=Blocked address=82.102.18.0/24 -add list=Blocked address=82.102.18.190/32 -add list=Blocked address=82.165.82.154/32 -add list=Blocked address=84.17.60.251/32 -add list=Blocked address=85.11.167.225/32 -add list=Blocked address=85.204.70.0/24 -add list=Blocked address=87.121.79.42/32 -add list=Blocked address=88.184.210.4/32 -add list=Blocked address=91.92.41.115/32 -add list=Blocked address=91.92.42.86/32 -add list=Blocked address=91.92.47.101/32 -add list=Blocked address=91.92.47.153/32 -add list=Blocked address=91.92.241.196/32 -add list=Blocked address=91.92.243.245/32 -add list=Blocked address=91.124.88.29/32 -add list=Blocked address=91.124.88.36/32 -add list=Blocked address=91.134.35.95/32 -add list=Blocked address=91.148.244.131/32 -add list=Blocked address=91.148.245.81/32 -add list=Blocked address=91.192.10.86/32 -add list=Blocked address=91.193.232.0/24 -add list=Blocked address=91.224.92.159/32 -add list=Blocked address=91.224.92.190/32 -add list=Blocked address=91.230.225.0/24 -add list=Blocked address=91.239.79.146/32 -add list=Blocked address=92.118.39.29/32 -add list=Blocked address=92.118.39.126/32 -add list=Blocked address=92.119.121.196/32 -add list=Blocked address=93.123.109.0/24 -add list=Blocked address=93.152.221.13/32 -add list=Blocked address=94.154.43.0/24 -add list=Blocked address=95.85.238.18/32 -add list=Blocked address=98.159.36.147/32 -add list=Blocked address=98.159.37.147/32 -add list=Blocked address=102.37.110.74/32 -add list=Blocked address=103.76.88.36/32 -add list=Blocked address=103.76.88.37/32 -add list=Blocked address=103.153.183.126/32 -add list=Blocked address=103.168.66.237/32 -add list=Blocked address=103.177.150.66/32 -add list=Blocked address=103.215.75.19/32 -add list=Blocked address=103.215.75.66/32 -add list=Blocked address=103.221.220.62/32 -add list=Blocked address=104.28.215.219/32 -add list=Blocked address=104.28.215.220/32 -add list=Blocked address=104.28.222.131/32 -add list=Blocked address=104.28.240.0/24 -add list=Blocked address=104.28.247.219/32 -add list=Blocked address=104.28.247.220/32 -add list=Blocked address=104.28.254.131/32 -add list=Blocked address=104.28.254.134/32 -add list=Blocked address=104.168.93.75/32 -add list=Blocked address=104.196.62.35/32 -add list=Blocked address=104.199.182.104/32 -add list=Blocked address=104.208.94.19/32 -add list=Blocked address=104.234.19.67/32 -add list=Blocked address=104.238.222.26/32 -add list=Blocked address=104.248.5.228/32 -add list=Blocked address=104.248.151.168/32 -add list=Blocked address=104.251.181.106/32 -add list=Blocked address=106.63.0.0/17 -add list=Blocked address=107.170.9.103/32 -add list=Blocked address=108.130.204.104/32 -add list=Blocked address=110.176.0.0/13 -add list=Blocked address=111.113.88.210/32 -add list=Blocked address=111.113.89.107/32 -add list=Blocked address=112.94.252.15/32 -add list=Blocked address=113.57.186.101/32 -add list=Blocked address=117.14.153.168/32 -add list=Blocked address=118.81.196.142/32 -add list=Blocked address=118.81.207.202/32 -add list=Blocked address=118.194.253.208/32 -add list=Blocked address=118.212.120.78/32 -add list=Blocked address=123.158.61.179/32 -add list=Blocked address=123.160.175.254/32 -add list=Blocked address=123.178.210.228/32 -add list=Blocked address=124.88.113.10/32 -add list=Blocked address=124.117.194.69/32 -add list=Blocked address=128.90.128.13/32 -add list=Blocked address=128.90.141.10/32 -add list=Blocked address=128.199.182.55/32 -add list=Blocked address=128.199.182.152/32 -add list=Blocked address=129.212.237.196/32 -add list=Blocked address=130.12.180.39/32 -add list=Blocked address=130.12.180.126/32 -add list=Blocked address=130.12.182.12/32 -add list=Blocked address=130.12.182.254/32 -add list=Blocked address=130.131.231.171/32 -add list=Blocked address=132.196.11.13/32 -add list=Blocked address=132.196.83.33/32 -add list=Blocked address=134.122.94.138/32 -add list=Blocked address=134.199.148.147/32 -add list=Blocked address=134.209.25.199/32 -add list=Blocked address=134.209.162.128/32 -add list=Blocked address=134.209.185.72/32 -add list=Blocked address=135.119.63.61/32 -add list=Blocked address=135.119.74.228/32 -add list=Blocked address=135.225.93.215/32 -add list=Blocked address=135.232.177.160/32 -add list=Blocked address=136.64.51.224/32 -add list=Blocked address=136.66.128.85/32 -add list=Blocked address=136.66.153.34/32 -add list=Blocked address=136.70.149.147/32 -add list=Blocked address=136.107.208.33/32 -add list=Blocked address=136.108.11.195/32 -add list=Blocked address=136.109.87.37/32 -add list=Blocked address=136.110.80.8/32 -add list=Blocked address=136.115.17.125/32 -add list=Blocked address=136.116.215.248/32 -add list=Blocked address=136.144.19.51/32 -add list=Blocked address=136.144.33.102/32 -add list=Blocked address=136.144.35.201/32 -add list=Blocked address=136.144.43.127/32 -add list=Blocked address=138.124.103.234/32 -add list=Blocked address=138.197.34.12/32 -add list=Blocked address=138.197.104.211/32 -add list=Blocked address=138.197.191.87/32 -add list=Blocked address=139.28.219.70/32 -add list=Blocked address=139.59.118.17/32 -add list=Blocked address=139.59.231.238/32 -add list=Blocked address=140.248.75.106/32 -add list=Blocked address=141.98.11.171/32 -add list=Blocked address=142.93.62.168/32 -add list=Blocked address=142.93.155.36/32 -add list=Blocked address=142.111.152.16/32 -add list=Blocked address=142.111.152.57/32 -add list=Blocked address=143.20.64.236/32 -add list=Blocked address=143.110.178.165/32 -add list=Blocked address=143.110.217.244/32 -add list=Blocked address=143.198.6.225/32 -add list=Blocked address=143.198.25.99/32 -add list=Blocked address=143.244.56.0/23 -add list=Blocked address=143.244.57.123/32 -add list=Blocked address=143.244.168.161/32 -add list=Blocked address=144.76.19.27/32 -add list=Blocked address=144.126.207.57/32 -add list=Blocked address=144.172.93.117/32 -add list=Blocked address=144.172.97.164/32 -add list=Blocked address=144.172.100.174/32 -add list=Blocked address=144.172.101.168/32 -add list=Blocked address=145.132.103.19/32 -add list=Blocked address=146.70.40.68/32 -add list=Blocked address=146.70.194.0/24 -add list=Blocked address=146.190.63.48/32 -add list=Blocked address=146.190.63.248/32 -add list=Blocked address=146.190.83.166/32 -add list=Blocked address=147.93.168.91/32 -add list=Blocked address=147.93.169.103/32 -add list=Blocked address=147.93.171.188/32 -add list=Blocked address=147.182.149.75/32 -add list=Blocked address=148.251.182.79/32 -add list=Blocked address=149.56.150.98/32 -add list=Blocked address=150.255.94.250/32 -add list=Blocked address=152.39.198.115/32 -add list=Blocked address=152.42.137.175/32 -add list=Blocked address=152.53.242.93/32 -add list=Blocked address=153.75.89.249/32 -add list=Blocked address=155.2.215.98/32 -add list=Blocked address=157.143.3.35/32 -add list=Blocked address=157.245.105.107/32 -add list=Blocked address=157.245.113.227/32 -add list=Blocked address=157.245.197.36/32 -add list=Blocked address=157.245.204.205/32 -add list=Blocked address=158.101.144.198/32 -add list=Blocked address=158.158.0.0/16 -add list=Blocked address=159.65.144.72/32 -add list=Blocked address=159.89.12.166/32 -add list=Blocked address=159.89.46.165/32 -add list=Blocked address=159.89.97.19/32 -add list=Blocked address=159.89.117.109/32 -add list=Blocked address=159.89.123.252/32 -add list=Blocked address=159.89.174.87/32 -add list=Blocked address=159.203.13.62/32 -add list=Blocked address=159.223.132.86/32 -add list=Blocked address=160.179.166.124/32 -add list=Blocked address=160.179.166.222/32 -add list=Blocked address=161.118.251.181/32 -add list=Blocked address=162.141.167.14/32 -add list=Blocked address=162.243.79.174/32 -add list=Blocked address=163.7.11.71/32 -add list=Blocked address=163.7.13.205/32 -add list=Blocked address=164.90.169.163/32 -add list=Blocked address=165.22.24.78/32 -add list=Blocked address=165.22.147.152/32 -add list=Blocked address=165.22.235.3/32 -add list=Blocked address=165.245.185.158/32 -add list=Blocked address=165.245.190.205/32 -add list=Blocked address=167.71.0.47/32 -add list=Blocked address=167.71.39.61/32 -add list=Blocked address=167.86.82.167/32 -add list=Blocked address=167.99.181.249/32 -add list=Blocked address=167.99.182.39/32 -add list=Blocked address=167.99.210.137/32 -add list=Blocked address=167.172.31.131/32 -add list=Blocked address=167.172.53.28/32 -add list=Blocked address=167.172.192.26/32 -add list=Blocked address=168.62.180.116/32 -add list=Blocked address=168.144.83.150/32 -add list=Blocked address=168.144.100.227/32 -add list=Blocked address=168.144.106.212/32 -add list=Blocked address=168.144.167.238/32 -add list=Blocked address=168.144.174.42/32 -add list=Blocked address=170.64.144.116/32 -add list=Blocked address=171.104.81.195/32 -add list=Blocked address=172.86.122.106/32 -add list=Blocked address=172.98.33.251/32 -add list=Blocked address=172.170.254.20/32 -add list=Blocked address=172.171.198.214/32 -add list=Blocked address=172.196.32.64/32 -add list=Blocked address=172.200.0.0/13 -add list=Blocked address=172.208.0.0/13 -add list=Blocked address=172.213.216.126/32 -add list=Blocked address=172.232.175.132/32 -add list=Blocked address=172.245.102.64/32 -add list=Blocked address=173.239.240.222/32 -add list=Blocked address=173.249.34.197/32 -add list=Blocked address=176.227.240.17/32 -add list=Blocked address=176.227.240.61/32 -add list=Blocked address=178.16.54.137/32 -add list=Blocked address=178.62.196.238/32 -add list=Blocked address=178.128.176.132/32 -add list=Blocked address=179.43.134.114/32 -add list=Blocked address=180.95.231.78/32 -add list=Blocked address=182.119.230.145/32 -add list=Blocked address=185.93.89.147/32 -add list=Blocked address=185.93.89.167/32 -add list=Blocked address=185.151.21.124/32 -add list=Blocked address=185.177.72.0/24 -add list=Blocked address=185.177.72.29/32 -add list=Blocked address=185.192.71.0/24 -add list=Blocked address=185.213.175.168/32 -add list=Blocked address=185.223.152.0/24 -add list=Blocked address=185.238.231.167/32 -add list=Blocked address=185.251.19.30/32 -add list=Blocked address=188.166.245.173/32 -add list=Blocked address=188.213.202.0/24 -add list=Blocked address=191.232.0.0/13 -add list=Blocked address=192.34.61.236/32 -add list=Blocked address=192.133.76.0/23 -add list=Blocked address=192.133.77.15/32 -add list=Blocked address=192.253.248.7/32 -add list=Blocked address=192.253.248.142/32 -add list=Blocked address=193.19.109.0/24 -add list=Blocked address=193.36.224.57/32 -add list=Blocked address=193.36.225.0/24 -add list=Blocked address=193.37.32.0/24 -add list=Blocked address=193.37.33.0/24 -add list=Blocked address=193.47.62.168/32 -add list=Blocked address=193.143.1.112/32 -add list=Blocked address=193.148.56.148/32 -add list=Blocked address=193.148.57.33/32 -add list=Blocked address=193.149.176.55/32 -add list=Blocked address=194.5.82.0/24 -add list=Blocked address=194.32.120.151/32 -add list=Blocked address=194.156.79.68/32 -add list=Blocked address=194.233.91.21/32 -add list=Blocked address=195.178.110.0/24 -add list=Blocked address=195.178.110.211/32 -add list=Blocked address=195.178.110.223/32 -add list=Blocked address=198.98.52.229/32 -add list=Blocked address=199.16.157.0/24 -add list=Blocked address=200.162.144.0/20 -add list=Blocked address=201.78.128.89/32 -add list=Blocked address=203.159.90.217/32 -add list=Blocked address=206.81.12.187/32 -add list=Blocked address=206.81.24.227/32 -add list=Blocked address=206.189.19.19/32 -add list=Blocked address=206.189.95.232/32 -add list=Blocked address=206.189.233.36/32 -add list=Blocked address=207.154.197.113/32 -add list=Blocked address=207.241.173.229/32 -add list=Blocked address=208.84.102.195/32 -add list=Blocked address=209.87.169.142/32 -add list=Blocked address=209.99.184.0/21 -add list=Blocked address=209.126.2.173/32 -add list=Blocked address=211.175.22.56/32 -add list=Blocked address=213.35.113.47/32 -add list=Blocked address=213.111.158.220/32 -add list=Blocked address=216.24.210.46/32 -add list=Blocked address=216.24.212.0/24 -add list=Blocked address=216.26.233.39/32 -add list=Blocked address=216.73.163.0/24 -add list=Blocked address=216.73.216.0/22 -add list=Blocked address=216.73.217.176/32 -add list=Blocked address=216.81.248.20/32 -add list=Blocked address=217.217.252.197/32 -add list=Blocked address=220.202.112.100/32 -add list=Blocked address=223.199.187.171/32 - -# Blocked IPv6 (23, non-whitelisted) -/ipv6 firewall address-list -add list=Blocked address=2001:ba0:24c:a500::1/128 -add list=Blocked address=2001:4ca0:108:42::24/128 -add list=Blocked address=2400:8901::2000:62ff:fe9a:e1c2/128 -add list=Blocked address=2406:da18:525:0:a23e:e8f6:3ea1:4c2c/128 -add list=Blocked address=2600:3000::/32 -add list=Blocked address=2600:3c09::2000:5cff:fe99:c802/128 -add list=Blocked address=2600:3c15::2000:53ff:fe31:8c0b/128 -add list=Blocked address=2600:3c15::2000:9cff:fef0:8ad6/128 -add list=Blocked address=2602:fa59::/40 -add list=Blocked address=2a00:6340:2008:ec80:64cc:9116:beb2:1931/128 -add list=Blocked address=2a00:6340:2008:ec80:be24:11ff:fe3b:4058/128 -add list=Blocked address=2a00:6340:2008:ec80:be24:11ff:fe82:2775/128 -add list=Blocked address=2a01:2a8:a0dd:1::1012/128 -add list=Blocked address=2a01:4f8:c014:7f9e::1/128 -add list=Blocked address=2a04:4e40:4400:0:537:cdd2:7250:95db/128 -add list=Blocked address=2a04:4e40:e000::/48 -add list=Blocked address=2a04:c300::/29 -add list=Blocked address=2a05:4140:3::37cd/128 -add list=Blocked address=2a06:a880:5:7fb3::1/128 -add list=Blocked address=2a09:bac1:76c0:460::5e:6a/128 -add list=Blocked address=2a09:bac5::/32 -add list=Blocked address=2a0a:4cc0:2000:8528:c4e8:3ff:febb:3ee9/128 -add list=Blocked address=2a13:adc0::2ed:89ff:fe58:19c5/128 - -/ip firewall filter -add chain=input action=accept src-address-list=Openfactory comment="ids openfactory whitelist (v4)" -add chain=input action=accept src-address-list=Cloudflare comment="ids cloudflare whitelist (v4)" -add chain=input action=accept src-address-list=PaloAlto comment="ids paloalto whitelist (v4)" -add chain=input action=drop src-address-list=Blocked comment="ids blocked (v4)" -add chain=forward action=drop src-address-list=Blocked comment="ids blocked (v4)" - -/ipv6 firewall filter -add chain=input action=accept src-address-list=Openfactory comment="ids openfactory whitelist (v6)" -add chain=input action=accept src-address-list=Cloudflare comment="ids cloudflare whitelist (v6)" -add chain=input action=accept src-address-list=PaloAlto comment="ids paloalto whitelist (v6)" -add chain=input action=drop src-address-list=Blocked comment="ids blocked (v6)" -add chain=forward action=drop src-address-list=Blocked comment="ids blocked (v6)" diff --git a/scan.py b/scan.py index 6d663a4..b0a77d4 100644 --- a/scan.py +++ b/scan.py @@ -12,6 +12,7 @@ import os from datetime import datetime import utils +from firewall import MikrotikFirewall from copyparty import CopypartyAnalyzer, DEFAULT_LOG_PATH as CP_DEFAULT_LOG, DEFAULT_REPORT_DIR as CP_DEFAULT_REPORT from npm import NpmAnalyzer, DEFAULT_LOG_PATH as NPM_DEFAULT_LOG, DEFAULT_REPORT_DIR as NPM_DEFAULT_REPORT @@ -49,8 +50,10 @@ def main() -> None: help="rows in the top-IP tables (default: 30)") parser.add_argument("--quiet", action="store_true", help="write files, suppress console reports") - parser.add_argument("--no-rsc", action="store_true", - help="skip MikroTik consolidated .rsc generation") + parser.add_argument("--update-firewall", action="store_true", + help="synchronize the MikroTik Blocked list after scanning") + parser.add_argument("--dry-run", action="store_true", + help="preview firewall changes without applying them") args = parser.parse_args() @@ -63,7 +66,7 @@ def main() -> None: report_dir=args.copyparty_report_dir, top=args.top, quiet=args.quiet, - write_rsc=not args.no_rsc, + write_rsc=False, min_denied=args.min_denied, ) @@ -72,7 +75,7 @@ def main() -> None: report_dir=args.npm_report_dir, top=args.top, quiet=args.quiet, - write_rsc=not args.no_rsc, + write_rsc=False, min_errors=args.min_errors, error_ratio=args.error_ratio, ) @@ -114,6 +117,7 @@ def main() -> None: print("\nGrouping blocked IPs into subnets using WHOIS...") final_blocked_targets = utils.consolidate_by_subnet( final_blocked_ips, threshold=3) + blocked_ipv4, blocked_ipv6 = utils.split_versions(final_blocked_targets) print("\n=== Consolidated Summary ===") print( @@ -123,19 +127,20 @@ def main() -> None: print(f"Total unified blocked IPs: {len(final_blocked_ips)}") print(f"Total target blocks/subnets: {len(final_blocked_targets)}") - # 5. Write Consolidated MikroTik RouterOS Script - if not args.no_rsc: - rsc_path = os.path.join(args.report_dir, "mikrotik-block.rsc") - utils.ensure_dirs(args.report_dir) - path, n_blocked, n_whitelisted = utils.write_mikrotik( - rsc_path, - "ids", - final_blocked_targets - ) - print(f"\nConsolidated MikroTik script: {path}") - print( - f" {n_blocked} targets blocked, {n_whitelisted} CIDR ranges whitelisted") - + if args.update_firewall: + firewall = MikrotikFirewall() + firewall.connect() + try: + changes = firewall.sync_blocklist( + blocked_ipv4, blocked_ipv6, dry_run=args.dry_run, + report_dir=args.report_dir) + finally: + firewall.disconnect() + action = "Would" if args.dry_run else "" + print(f"{action} add {len(changes['added_ipv4'])} IPv4 and " + f"{len(changes['added_ipv6'])} IPv6 addresses; " + f"remove {len(changes['removed_ipv4'])} IPv4 and " + f"{len(changes['removed_ipv6'])} IPv6 addresses.") if __name__ == "__main__": main()