
Скрипт для парсинга списков IP и ручного импорта в simplewall
Для обеспечения информационной безопасности необходимо блокировать взаимодействие с потенциально опасными IP-адресами, но антивирусы и межсетевые экраны обладают скудными списками, так как они включают туда только то, что сами проанализировали, а между тем, существует множество общедоступных списков потенциально опасных IP-адресов (подробнее про такие списки тут).
В данной статье расскажу как можно частично автоматизировать, а именно парсить списки, экспортировать текущие настройки свободного сетевого экрана simplewall и с сохранением текущих настроек импортировать новый набор правил, при этом предыдущие добавленные скриптом будут удалены, чтобы держать списки актуальными.
simplewall работает только под операционной системой Windows и подробнее про него можно прочитать по адресу континентсвободы.рф/simplewall-setevoj-ekran-dlya-windows/, а так же скачать.
Предварительно нужно открыть simplewall и в нем файл\экспорт.
Экспортированный файл profile.xml необходимо поместить вместе с нашим скриптом, назовем его IP-XML.py.
Вот код нашего скрипта:
# -*- coding: utf-8 -*-
"""
Created on Sat Mar 8 18:31:48 2025
@author: Алексей Черемных https://alekseycheremnykh.ru/
"""
import requests
import ipaddress
from xml.etree import ElementTree
from xml.etree.ElementTree import Element, SubElement, tostring
from xml.dom import minidom
import time
import os
urls = [
"https://feodotracker.abuse.ch/downloads/ipblocklist_recommended.txt",
"https://sslbl.abuse.ch/blacklist/sslipblacklist.txt",
"https://cinsarmy.com/list/ci-badguys.txt",
"https://raw.githubusercontent.com/firehol/blocklist-ipsets/refs/heads/master/et_compromised.ipset"
]
def fetch_ips_from_url(url):
"""Загружает список IP-адресов и диапазонов из URL."""
try:
response = requests.get(url)
response.raise_for_status() # Raises HTTPError for bad responses (4XX, 5XX)
return response.text.splitlines()
except requests.exceptions.RequestException as e:
print(f"Ошибка при загрузке {url}: {e}")
return []
def clean_and_extract_ips(lines):
"""Очищает строки и извлекает IP-адреса и диапазоны."""
ips = []
for line in lines:
line = line.strip()
if not line or line.startswith("#") or "Spamhaus" in line or "Last-Modified" in line or "Expires" in line:
continue
# Разделяем строку по символу ';' и берем первую часть
parts = line.split(";")
ip_or_range = parts[0].strip()
try:
# Пробуем распарсить как IP-адрес или диапазон
if "/" in ip_or_range:
# Это CIDR диапазон
network = ipaddress.ip_network(ip_or_range, strict=False)
# Добавляем все IP-адреса из диапазона (кроме адреса сети и широковещательного адреса)
ips.append(str(network))
#for ip in network.hosts():
# ips.append(str(ip))
else:
# Это одиночный IP-адрес
ipaddress.ip_address(ip_or_range)
ips.append(ip_or_range)
except ValueError:
# Если не удалось распарсить, игнорируем строку
print(f"Неверный формат IP: {line}")
continue
return ips
def create_simplewall_xml(url_ip_dict, existing_xml_root=None):
"""Создает XML-файл для Simplewall."""
if existing_xml_root is None:
root = Element("root")
root.set("version", "5")
root.set("type", "3")
root.set("timestamp", str(int(time.time())))
apps = SubElement(root, "apps")
rules_custom = SubElement(root, "rules_custom")
root.append(rules_custom) # Добавляем rules_custom в root
rules_config = SubElement(root, "rules_config")
else:
root = existing_xml_root
rules_custom = root.find("rules_custom")
if rules_custom is None:
rules_custom = SubElement(root, "rules_custom")
root.append(rules_custom)
# Если есть существующий XML, удаляем правила с comment="IP from external list"
if existing_xml_root is not None:
for item in list(rules_custom): # Итерируемся по копии списка, чтобы можно было удалять элементы
if item.get("comment") == "IP from external list":
rules_custom.remove(item) # Удаляем правило, если comment="IP from external list"
# Добавляем правила для каждого URL, разбивая на части по 10 IP-адресов
for url, ips in url_ip_dict.items():
for i in range(0, len(ips), 10):
ip_subset = ips[i:i + 10]
ip_string = ";".join(ip_subset) + ";" # Объединяем IP-адреса в строку, разделенную точкой с запятой
item = SubElement(rules_custom, "item")
item.set("name", f"Block IPs from {url} (part {i//10 + 1})") # Имя правила
item.set("rule", ip_string) # IP-адреса из URL
item.set("comment", "IP from external list") # Комментарий
item.set("dir", "2")
item.set("is_block", "true") # Блокировать
item.set("is_enabled", "true")
# Преобразуем ElementTree в строку с форматированием
xml_string = tostring(root, encoding='utf8', method='xml')
dom = minidom.parseString(xml_string)
pretty_xml = dom.toprettyxml(indent=" ")
return pretty_xml
def main():
"""Основная функция."""
# urls = [
# "https://rules.emergingthreats.net/blockrules/compromised-ips.txt",
# "https://www.spamhaus.org/drop/drop.txt",
# ]
url_ip_dict = {} # Словарь для хранения IP-адресов для каждого URL
for url in urls:
lines = fetch_ips_from_url(url)
if lines:
url_ip_dict[url] = clean_and_extract_ips(lines)
# Читаем существующий XML-файл (если он есть)
existing_xml_root = None
if os.path.exists("profile.xml"):
try:
tree = ElementTree.parse("profile.xml")
existing_xml_root = tree.getroot()
except Exception as e:
print(f"Ошибка при чтении profile.xml: {e}")
# Создаем XML
xml_content = create_simplewall_xml(url_ip_dict, existing_xml_root)
# Сохраняем в файл
with open("simplewall_ips.xml", "w", encoding="utf-8") as f:
f.write(xml_content)
print("XML-файл simplewall_ips.xml успешно создан.")
if __name__ == "__main__":
main()
Скрипт генерирует файл simplewall_ips.xml, который можно импортировать в simplewall при помощи файл\импорт.
Ве правила, которые были ранее добавлены при помощи данного скрипта будут удалены, а благодаря строке item.set("dir", "2") направление будет любое.
В начале скрипта есть переменная urls, в которой содержаться списки. Просто добавьте туда их в формате urls = ["первый список", "второй список"].
Также списки можно поискать на iplists[.]firehol[.]org.
Сразу хочу предупредить, что данное решение я толком не тестировал и не могу гарантировать, что оно не будет сжирать ваши ресурсы.