Advertisement
TheGerman

Cleaning your iptables blocked IPs - fail2ban

Feb 9th, 2025
107
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.53 KB | Source Code | 0 0
  1. # After a few weeks "unsupervised," one of my servers had 130k+ IPs blocked by fail2ban
  2. # To process this "humongous" number of entries, the machine was often slow and non-responsive
  3. # I was locked outside of the machine because my IP was not being "authorized" - but it was
  4. # not blocked, too. Even adding the IP to the pool of authorized sources, the number of entries
  5. # was too large for the firewall to process.
  6.  
  7. # I thought about a Python script to check all entries from my iptables, and if any CIDR had
  8. # more than 15 unique IPs blocked, the entire /24 would be blocked.
  9. # To further reduce the number of iptables entries, if possible, will join separate /24 into a larger
  10. # netblock.
  11.  
  12. # Last, the script will create a bash shell script to add the blacklisted CIDRs into the iptables using UFW
  13.  
  14. # Quick explanation:
  15. # Dump the iptables into a plain text file
  16. # If curious, check the number of lines for the iptables file ("wc -l iptables.banned_ips.txt")
  17. # Flush fail2ban ("fail2ban-client unban --all")
  18. # Double check the new number of iptables lines after flushing fail2ban ("iptables -L -n | wc -l")
  19. # Run the script to analyze the iptables dump and generate the CIDR file
  20. # Run the script to add the CIDR into iptables
  21.  
  22. # STEPS:
  23. # Save your iptables output using "iptables -L -n > /tmp/iptables.banned_ips.txt"
  24. # After saving your iptables output, remember to flush your fail2ban --> "fail2ban-client unban --all"
  25. # You should have a CLEAN firewall
  26.  
  27.  
  28. import sys
  29. import re
  30. from ipaddress import ip_network, ip_address, collapse_addresses
  31. from collections import defaultdict
  32.  
  33. THRESHOLD = 15  # Minimum number of bad IPs in a /24 to block
  34.  
  35. def extract_and_convert(input_file, output_file, ufw_script):
  36.     blocked_ips = defaultdict(set)  # Stores individual bad IPs per /24 CIDR
  37.     whitelisted_networks = set()  # Stores unique /24 subnets to be whitelisted
  38.     whitelisted_ips = set()  # Stores individual whitelisted IPs (as IPv4Address objects)
  39.  
  40.     # Step 1: Identify whitelisted IPs and CIDRs
  41.     with open(input_file, 'r') as f:
  42.         for line in f:
  43.             if line.startswith("ACCEPT"):  # Process "ACCEPT" lines
  44.                 match = re.search(r'(\d+\.\d+\.\d+\.\d+)', line)
  45.                 if match:
  46.                     ip = ip_address(match.group(1))
  47.                     cidr = ip_network(f"{ip}/24", strict=False)
  48.                     whitelisted_networks.add(cidr)
  49.                     whitelisted_ips.add(ip)
  50.                     print(f"Whitelisted CIDR: {cidr} (from IP {ip})")
  51.  
  52.     # Step 2: Process "REJECT" lines while avoiding whitelisted networks
  53.     with open(input_file, 'r') as f:
  54.         for line in f:
  55.             if line.startswith("REJECT"):
  56.                 match = re.search(r'(\d+\.\d+\.\d+\.\d+)', line)
  57.                 if match:
  58.                     ip = ip_address(match.group(1))
  59.                     cidr = ip_network(f"{ip}/24", strict=False)
  60.  
  61.                     if cidr not in whitelisted_networks and ip not in whitelisted_ips:
  62.                         blocked_ips[cidr].add(ip)
  63.  
  64.     # Step 3: Filter CIDRs based on threshold
  65.     filtered_cidrs = {cidr for cidr, ips in blocked_ips.items() if len(ips) >= THRESHOLD}
  66.  
  67.     # Step 4: Aggregate CIDRs while respecting whitelist constraints
  68.     aggregated_networks = []
  69.     for cidr in sorted(collapse_addresses(filtered_cidrs)):
  70.         if not any(ip in cidr for ip in whitelisted_ips):
  71.             aggregated_networks.append(cidr)
  72.             # print(f"Optimized CIDR: {cidr}")
  73.  
  74.     # Step 5: Write optimized CIDR blocks to output file
  75.     with open(output_file, 'w') as out_f:
  76.         for cidr in aggregated_networks:
  77.             out_f.write(str(cidr) + "\n")
  78.  
  79.     # Step 6: Generate a UFW script
  80.     with open(ufw_script, 'w') as ufw_f:
  81.         ufw_f.write("#!/bin/bash\n")
  82.         ufw_f.write("# Auto-generated script to block bad actors using UFW\n\n")
  83.         ufw_f.write("UFW=/usr/sbin/ufw\n\n")
  84.  
  85.         for cidr in aggregated_networks:
  86.             ufw_f.write(f"$UFW deny from {cidr} to any\n")
  87.  
  88.         ufw_f.write("\n# Reload UFW rules\n")
  89.         ufw_f.write("$UFW reload\n")
  90.  
  91.     print(f"UFW blocking script saved as: {ufw_script}")
  92.     print("Make sure to run: chmod +x", ufw_script)
  93.  
  94. # Check for correct usage
  95. if len(sys.argv) != 4:
  96.     print("Usage: python script.py <input_file> <output_cidr_file> <ufw_script>")
  97.     sys.exit(1)
  98.  
  99. # Get file paths from command-line arguments
  100. input_file = sys.argv[1]
  101. output_cidr_file = sys.argv[2]
  102. ufw_script = sys.argv[3]
  103.  
  104. extract_and_convert(input_file, output_cidr_file, ufw_script)
  105.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement