mirror of
https://github.com/Ground-Zerro/DomainMapper.git
synced 2025-12-10 01:47:18 +07:00
fix
Исправление досадных ошибок. Фильтрация CloudFlare может не работать.
This commit is contained in:
@@ -27,7 +27,7 @@
|
|||||||
- Возможен выбор DNS сервера из установленного в системе, а также Google Public DNS, Quad9, Cloudflare DNS, OpenDNS, Cisco Umbrella, DNS.Watch, Dyn, CleanBrowsing, Alternate DNS, AdGuard DNS, Control D или все сразу.
|
- Возможен выбор DNS сервера из установленного в системе, а также Google Public DNS, Quad9, Cloudflare DNS, OpenDNS, Cisco Umbrella, DNS.Watch, Dyn, CleanBrowsing, Alternate DNS, AdGuard DNS, Control D или все сразу.
|
||||||
- Разрешение DNS имени происходит используя каждый из указанных пользователем DNS серверов и не останавливается при первом же успешном получении его IP-адреса.
|
- Разрешение DNS имени происходит используя каждый из указанных пользователем DNS серверов и не останавливается при первом же успешном получении его IP-адреса.
|
||||||
- Пользователь может создать свой список с DNS именами, необходимыми лично ему.
|
- Пользователь может создать свой список с DNS именами, необходимыми лично ему.
|
||||||
- Агрегация маршрутов до /24 (255.255.255.0).
|
- Агрегация маршрутов до /16 (255.255.0.0), /24 (255.255.255.0).
|
||||||
|
|
||||||
|
|
||||||
**Автоматизация:**
|
**Автоматизация:**
|
||||||
@@ -50,8 +50,8 @@ pip3 install -r requirements.txt
|
|||||||
**Работа с личным списком DNS:**
|
**Работа с личным списком DNS:**
|
||||||
- Создать файл "custom-dns-list.txt", записать в него DNS имена (одна строчка - одно имя) и положить рядом со скриптом. Список будет подхвачен при запуске и отображен в меню как "Custom DNS list".
|
- Создать файл "custom-dns-list.txt", записать в него DNS имена (одна строчка - одно имя) и положить рядом со скриптом. Список будет подхвачен при запуске и отображен в меню как "Custom DNS list".
|
||||||
|
|
||||||
**Для тех кто не знает "как", но кому оучень нужно:**
|
**Кто не знает "как", но кому "очень нужно":**
|
||||||
- Загляните в директорию Windows репозитория.
|
- Загляните в директорию "Windows" репозитория.
|
||||||
|
|
||||||
**New**
|
**New**
|
||||||
- Агрегация маршрутов. Запрос от @sergeeximius
|
- Агрегация маршрутов. Запрос от @sergeeximius
|
||||||
|
|||||||
@@ -48,7 +48,8 @@ cloudflare =
|
|||||||
# Сгруппировать подсети
|
# Сгруппировать подсети
|
||||||
# опции:
|
# опции:
|
||||||
# пустое значение - пользователю будет выведено меню выбора
|
# пустое значение - пользователю будет выведено меню выбора
|
||||||
# yes - группировка подсетей до /24 (255.255.255.0)
|
# 16 - группировка подсетей до /16 (255.255.0.0)
|
||||||
|
# 24 - группировка подсетей до /24 (255.255.255.0)
|
||||||
# no - оставить как есть
|
# no - оставить как есть
|
||||||
subnet =
|
subnet =
|
||||||
|
|
||||||
|
|||||||
134
main.py
134
main.py
@@ -2,14 +2,12 @@ import asyncio
|
|||||||
import configparser
|
import configparser
|
||||||
import ipaddress
|
import ipaddress
|
||||||
import os
|
import os
|
||||||
import re
|
|
||||||
from asyncio import Semaphore
|
from asyncio import Semaphore
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
|
||||||
import dns.asyncresolver
|
import dns.asyncresolver
|
||||||
import httpx
|
import httpx
|
||||||
from colorama import Fore, Style
|
from colorama import Fore, Style, init
|
||||||
from colorama import init
|
|
||||||
|
|
||||||
# Цвета
|
# Цвета
|
||||||
init(autoreset=True)
|
init(autoreset=True)
|
||||||
@@ -56,11 +54,11 @@ def read_config(filename):
|
|||||||
print(f"{Style.BRIGHT}Использовать DNS сервер:{Style.RESET_ALL} {dns_server_indices if dns_server_indices else 'спросить у пользователя'}")
|
print(f"{Style.BRIGHT}Использовать DNS сервер:{Style.RESET_ALL} {dns_server_indices if dns_server_indices else 'спросить у пользователя'}")
|
||||||
print(f"{Style.BRIGHT}Количество одновременных запросов к одному DNS серверу:{Style.RESET_ALL} {request_limit}")
|
print(f"{Style.BRIGHT}Количество одновременных запросов к одному DNS серверу:{Style.RESET_ALL} {request_limit}")
|
||||||
print(f"{Style.BRIGHT}Фильтр IP-адресов Cloudflare:{Style.RESET_ALL} {'включен' if cloudflare == 'yes' else 'выключен' if cloudflare == 'no' else 'спросить у пользователя'}")
|
print(f"{Style.BRIGHT}Фильтр IP-адресов Cloudflare:{Style.RESET_ALL} {'включен' if cloudflare == 'yes' else 'выключен' if cloudflare == 'no' else 'спросить у пользователя'}")
|
||||||
|
print(f"{Style.BRIGHT}Агрегация IP-адресов:{Style.RESET_ALL} {'до /16 подсети' if subnet == '16' else 'до /24 подсети' if subnet == '24' else 'вЫключена' if subnet == 'no' else 'спросить у пользователя'}")
|
||||||
print(f"{Style.BRIGHT}Сохранить результаты в файл:{Style.RESET_ALL} {filename}")
|
print(f"{Style.BRIGHT}Сохранить результаты в файл:{Style.RESET_ALL} {filename}")
|
||||||
print(f"{Style.BRIGHT}Формат сохранения:{Style.RESET_ALL} {'только IP' if filetype == 'ip' else 'Linux route' if filetype == 'unix' else 'CIDR-нотация' if filetype == 'cidr' else 'Windows route' if filetype == 'win' else 'CLI Mikrotik firewall' if filetype == 'mikrotik' else 'open vpn' if filetype == 'ovpn' else 'спросить у пользователя'}")
|
print(f"{Style.BRIGHT}Формат сохранения:{Style.RESET_ALL} {'только IP' if filetype == 'ip' else 'Linux route' if filetype == 'unix' else 'CIDR-нотация' if filetype == 'cidr' else 'Windows route' if filetype == 'win' else 'CLI Mikrotik firewall' if filetype == 'mikrotik' else 'open vpn' if filetype == 'ovpn' else 'спросить у пользователя'}")
|
||||||
print(f"{Style.BRIGHT}Шлюз/Имя интерфейса для маршрутов:{Style.RESET_ALL} {gateway if gateway else 'спросить у пользователя'}")
|
print(f"{Style.BRIGHT}Шлюз/Имя интерфейса для маршрутов:{Style.RESET_ALL} {gateway if gateway else 'спросить у пользователя'}")
|
||||||
print(f"{Style.BRIGHT}Имя списка для Mikrotik firewall:{Style.RESET_ALL} {mk_list_name if mk_list_name else 'спросить у пользователя'}")
|
print(f"{Style.BRIGHT}Имя списка для Mikrotik firewall:{Style.RESET_ALL} {mk_list_name if mk_list_name else 'спросить у пользователя'}")
|
||||||
print(f"{Style.BRIGHT}Группировка IP-адресов в подсети:{Style.RESET_ALL} {'включена' if subnet == 'yes' else 'выключена' if subnet == 'no' else 'спросить у пользователя'}")
|
|
||||||
print(f"{Style.BRIGHT}Выполнить по завершению:{Style.RESET_ALL} {run_command if run_command else 'не указано'}")
|
print(f"{Style.BRIGHT}Выполнить по завершению:{Style.RESET_ALL} {run_command if run_command else 'не указано'}")
|
||||||
return service, request_limit, filename, cloudflare, filetype, gateway, run_command, dns_server_indices, mk_list_name, subnet
|
return service, request_limit, filename, cloudflare, filetype, gateway, run_command, dns_server_indices, mk_list_name, subnet
|
||||||
|
|
||||||
@@ -132,11 +130,15 @@ async def get_cloudflare_ips():
|
|||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
text = response.text
|
text = response.text
|
||||||
cloudflare_ips = set()
|
cloudflare_ips = set()
|
||||||
cidr_blocks = re.findall(r'(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/\d{1,2})', text)
|
for line in text.splitlines():
|
||||||
for cidr in cidr_blocks:
|
line = line.strip()
|
||||||
ip_network = ipaddress.ip_network(cidr)
|
if '/' in line:
|
||||||
for ip in ip_network:
|
try:
|
||||||
cloudflare_ips.add(str(ip))
|
ip_network = ipaddress.ip_network(line)
|
||||||
|
for ip in ip_network:
|
||||||
|
cloudflare_ips.add(str(ip))
|
||||||
|
except ValueError:
|
||||||
|
continue
|
||||||
return cloudflare_ips
|
return cloudflare_ips
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print("Ошибка при получении IP адресов Cloudflare:", e)
|
print("Ошибка при получении IP адресов Cloudflare:", e)
|
||||||
@@ -149,15 +151,17 @@ async def resolve_domain(domain, resolver, semaphore, dns_server_name, null_ips_
|
|||||||
total_domains_processed[0] += 1
|
total_domains_processed[0] += 1
|
||||||
response = await resolver.resolve(domain)
|
response = await resolver.resolve(domain)
|
||||||
ips = [ip.address for ip in response]
|
ips = [ip.address for ip in response]
|
||||||
|
filtered_ips = []
|
||||||
for ip_address in ips:
|
for ip_address in ips:
|
||||||
if ip_address in ('127.0.0.1', '0.0.0.0') or ip_address in resolver.nameservers:
|
if ip_address in ('127.0.0.1', '0.0.0.0') or ip_address in resolver.nameservers:
|
||||||
null_ips_count[0] += 1
|
null_ips_count[0] += 1
|
||||||
elif ip_address in cloudflare_ips:
|
elif ip_address in cloudflare_ips:
|
||||||
cloudflare_ips_count[0] += 1
|
cloudflare_ips_count[0] += 1
|
||||||
else:
|
else:
|
||||||
|
filtered_ips.append(ip_address)
|
||||||
print(f"{Fore.BLUE}{domain} IP-адрес: {ip_address} - {dns_server_name}{Style.RESET_ALL}")
|
print(f"{Fore.BLUE}{domain} IP-адрес: {ip_address} - {dns_server_name}{Style.RESET_ALL}")
|
||||||
return ips
|
return filtered_ips
|
||||||
except Exception as e:
|
except Exception as e: # Ловим все ошибки чтобы код не прервался
|
||||||
print(f"{Fore.RED}Не удалось получить IP-адрес: {domain} - {dns_server_name}{Style.RESET_ALL}")
|
print(f"{Fore.RED}Не удалось получить IP-адрес: {domain} - {dns_server_name}{Style.RESET_ALL}")
|
||||||
return []
|
return []
|
||||||
|
|
||||||
@@ -191,7 +195,6 @@ async def resolve_dns(service, dns_names, dns_servers, cloudflare_ips, unique_ip
|
|||||||
|
|
||||||
|
|
||||||
def check_service_config(service, urls, local_dns_names):
|
def check_service_config(service, urls, local_dns_names):
|
||||||
services = []
|
|
||||||
if service:
|
if service:
|
||||||
services = [s.strip() for s in service.split(',')]
|
services = [s.strip() for s in service.split(',')]
|
||||||
if "custom" in services:
|
if "custom" in services:
|
||||||
@@ -239,7 +242,7 @@ def check_include_cloudflare(cloudflare):
|
|||||||
elif cloudflare.lower() == 'no':
|
elif cloudflare.lower() == 'no':
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
return input(f"\nИсключить IP адреса Cloudflare из итогового списка? ({green('yes')} "
|
return input(f"\n{yellow('Исключить IP адреса Cloudflare из итогового списка?')} ({green('yes')} "
|
||||||
f"- исключить, {green('Enter')} - оставить): ").strip().lower() == "yes"
|
f"- исключить, {green('Enter')} - оставить): ").strip().lower() == "yes"
|
||||||
|
|
||||||
|
|
||||||
@@ -302,39 +305,71 @@ def mk_comment(selected_service):
|
|||||||
|
|
||||||
# Выбор формата сохранения списка разрешенных DNS имен
|
# Выбор формата сохранения списка разрешенных DNS имен
|
||||||
def subnetting(subnet):
|
def subnetting(subnet):
|
||||||
if subnet.lower() == 'yes':
|
# Если значение пустое, запрашиваем ввод от пользователя
|
||||||
|
if subnet.lower() == '':
|
||||||
|
subnet = input(f"\n{yellow('Объединить IP-адреса в подсети?')} "
|
||||||
|
f"\n{green('16')} - сократить до /16 (255.255.0.0)"
|
||||||
|
f"\n{green('24')} - сократить до /24 (255.255.255.0)"
|
||||||
|
f"\n{green('Enter')} - пропустить: ").strip().lower()
|
||||||
|
|
||||||
|
# Обрабатываем ввод или параметр
|
||||||
|
if subnet == '16':
|
||||||
|
return "16", "255.255.0.0"
|
||||||
|
elif subnet == '24':
|
||||||
return "24", "255.255.255.0"
|
return "24", "255.255.255.0"
|
||||||
elif subnet.lower() == 'no':
|
|
||||||
return "32", "255.255.255.255"
|
|
||||||
else:
|
else:
|
||||||
choice = input(f"\n{yellow('Сгруппировать IP-адреса в подсети?')} ({green('yes')} - да, {green('Enter')} - нет): ").strip().lower()
|
return "32", "255.255.255.255"
|
||||||
if choice == "yes":
|
|
||||||
return "24", "255.255.255.0"
|
|
||||||
else:
|
|
||||||
return "32", "255.255.255.255"
|
|
||||||
|
|
||||||
|
|
||||||
def group_ips_in_subnets(filename):
|
def group_ips_in_subnets(filename, submask):
|
||||||
try:
|
try:
|
||||||
|
# Чтение всех IP-адресов из файла
|
||||||
with open(filename, 'r', encoding='utf-8-sig') as file:
|
with open(filename, 'r', encoding='utf-8-sig') as file:
|
||||||
ips = {line.strip() for line in file if line.strip()} # Собираем уникальные IP адреса
|
ips = {line.strip() for line in file if line.strip()} # Собираем уникальные IP адреса
|
||||||
|
|
||||||
# Преобразование всех IP в их подсети /24
|
# Обработка подсетей в зависимости от маски
|
||||||
subnet_ips = set()
|
if submask == "24":
|
||||||
for ip in ips:
|
# Множество для хранения всех подсетей /24
|
||||||
try:
|
subnets = set()
|
||||||
# Преобразуем IP в сеть /24 (маска 255.255.255.0)
|
|
||||||
network = ipaddress.ip_network(f"{ip}/24", strict=False)
|
|
||||||
subnet_ips.add(str(network.network_address))
|
|
||||||
except ValueError as e:
|
|
||||||
print(f"{red('Ошибка в IP адресе:')} {ip} - {e}")
|
|
||||||
|
|
||||||
# Перезаписываем файл с уникальными подсетями
|
# Преобразование всех IP в их подсети /24
|
||||||
with open(filename, 'w', encoding='utf-8-sig') as file:
|
for ip in ips:
|
||||||
for subnet in subnet_ips:
|
try:
|
||||||
file.write(subnet + '\n')
|
# Преобразуем IP в сеть /24 (маска 255.255.255.0)
|
||||||
|
network_24 = ipaddress.ip_network(f"{ip}/24", strict=False)
|
||||||
|
subnets.add(str(network_24.network_address))
|
||||||
|
except ValueError as e:
|
||||||
|
print(f"{red('Ошибка в IP адресе:')} {ip} - {e}")
|
||||||
|
|
||||||
print("IP-адреса сгруппированы...")
|
# Перезаписываем файл с уникальными подсетями /24
|
||||||
|
with open(filename, 'w', encoding='utf-8-sig') as file:
|
||||||
|
for subnet in sorted(subnets):
|
||||||
|
file.write(subnet + '\n')
|
||||||
|
|
||||||
|
print(f"{Style.BRIGHT}IP-адреса агрегированы до /{submask} подсети{Style.RESET_ALL}")
|
||||||
|
|
||||||
|
elif submask == "16":
|
||||||
|
# Множество для хранения всех объединенных подсетей /16
|
||||||
|
subnets = set()
|
||||||
|
|
||||||
|
# Преобразование всех IP в их подсети /16
|
||||||
|
for ip in ips:
|
||||||
|
try:
|
||||||
|
# Преобразуем IP в сеть /16 (маска 255.255.0.0)
|
||||||
|
network_16 = ipaddress.ip_network(f"{ip}/16", strict=False)
|
||||||
|
subnets.add(str(network_16.network_address))
|
||||||
|
except ValueError as e:
|
||||||
|
print(f"{red('Ошибка в IP адресе:')} {ip} - {e}")
|
||||||
|
|
||||||
|
# Перезаписываем файл с уникальными подсетями /16
|
||||||
|
with open(filename, 'w', encoding='utf-8-sig') as file:
|
||||||
|
for subnet in sorted(subnets):
|
||||||
|
file.write(subnet + '\n')
|
||||||
|
|
||||||
|
print(f"{Style.BRIGHT}IP-адреса агрегированы до /{submask} подсети{Style.RESET_ALL}")
|
||||||
|
|
||||||
|
else:
|
||||||
|
print(f"{red('Неправильная маска подсети:')} {submask}")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"{red('Ошибка при обработке файла:')} {e}")
|
print(f"{red('Ошибка при обработке файла:')} {e}")
|
||||||
@@ -355,17 +390,17 @@ def process_file_format(filename, filetype, gateway, selected_service, mk_list_n
|
|||||||
for ip in ips:
|
for ip in ips:
|
||||||
file.write(formatter(ip.strip()) + '\n')
|
file.write(formatter(ip.strip()) + '\n')
|
||||||
|
|
||||||
# Определение маски подсети для отображения пользователю
|
# Определение маски подсети для отображения пользователю и ее корректной записи в файл
|
||||||
display_submask = "255.255.255.0" if submask == "24" else "255.255.255.255"
|
display_submask = "255.255.0.0" if submask == "16" else "255.255.255.0" if submask == "24" else "255.255.255.255"
|
||||||
|
|
||||||
if not filetype:
|
if not filetype:
|
||||||
filetype = input(f"""
|
filetype = input(f"""
|
||||||
{yellow('В каком формате сохранить файл?')}
|
{yellow('В каком формате сохранить файл?')}
|
||||||
{green('win')} - route add {cyan('IP')} mask {cyan(display_submask)} {cyan('GATEWAY')}
|
{green('win')} - route add {cyan('IP')} mask {display_submask} {cyan('GATEWAY')}
|
||||||
{green('unix')} - ip route {cyan('IP')}/{cyan(submask)} {cyan('GATEWAY')}
|
{green('unix')} - ip route {cyan('IP')}/{submask} {cyan('GATEWAY')}
|
||||||
{green('cidr')} - {cyan('IP')}/{cyan(submask)}
|
{green('cidr')} - {cyan('IP')}/{submask}
|
||||||
{green('mikrotik')} - /ip/firewall/address-list add list={cyan("LIST_NAME")} comment="{mk_comment(selected_service)}" address={cyan("IP")}/{cyan(submask)}
|
{green('mikrotik')} - /ip/firewall/address-list add list={cyan("LIST_NAME")} comment="{mk_comment(selected_service)}" address={cyan("IP")}/{submask}
|
||||||
{green('ovpn')} - push "route {cyan('IP')} {cyan(display_submask)}"
|
{green('ovpn')} - push "route {cyan('IP')} {display_submask}"
|
||||||
{green('Enter')} - {cyan('IP')}
|
{green('Enter')} - {cyan('IP')}
|
||||||
Ваш выбор: """)
|
Ваш выбор: """)
|
||||||
|
|
||||||
@@ -383,18 +418,16 @@ def process_file_format(filename, filetype, gateway, selected_service, mk_list_n
|
|||||||
|
|
||||||
formatters = {
|
formatters = {
|
||||||
'win': lambda ip: f"route add {ip} mask {display_submask} {gateway}",
|
'win': lambda ip: f"route add {ip} mask {display_submask} {gateway}",
|
||||||
'unix': lambda ip: f"ip route {ip}{submask} {gateway}",
|
'unix': lambda ip: f"ip route {ip}/{submask} {gateway}",
|
||||||
'cidr': lambda ip: f"{ip}{submask}",
|
'cidr': lambda ip: f"{ip}/{submask}",
|
||||||
'ovpn': lambda ip: f'push "route {ip} {display_submask}"',
|
'ovpn': lambda ip: f'push "route {ip} {display_submask}"',
|
||||||
'mikrotik': lambda ip: f'/ip/firewall/address-list add list={mk_list_name} '
|
'mikrotik': lambda ip: f'/ip/firewall/address-list add list={mk_list_name} comment="{mk_comment(selected_service)}" address={ip}/{submask}'
|
||||||
f'comment="{mk_comment(selected_service)}" address={ip}/{submask}'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if filetype.lower() in formatters:
|
if filetype.lower() in formatters:
|
||||||
write_file(filename, ips, formatters[filetype.lower()])
|
write_file(filename, ips, formatters[filetype.lower()])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Ну чо, погнали?!
|
# Ну чо, погнали?!
|
||||||
async def main():
|
async def main():
|
||||||
# Инициализация настроек из config.ini
|
# Инициализация настроек из config.ini
|
||||||
@@ -463,8 +496,7 @@ async def main():
|
|||||||
|
|
||||||
# Группировка IP-адресов в подсети
|
# Группировка IP-адресов в подсети
|
||||||
submask, _ = subnetting(subnet)
|
submask, _ = subnetting(subnet)
|
||||||
if submask == "24":
|
group_ips_in_subnets(filename, submask)
|
||||||
group_ips_in_subnets(filename)
|
|
||||||
|
|
||||||
process_file_format(filename, filetype, gateway, selected_services, mk_list_name, submask)
|
process_file_format(filename, filetype, gateway, selected_services, mk_list_name, submask)
|
||||||
|
|
||||||
@@ -478,4 +510,4 @@ async def main():
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
asyncio.run(main())
|
asyncio.run(main())
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
configparser~=7.0.0
|
configparser~=7.0.1
|
||||||
ipaddress~=1.0.23
|
ipaddress~=1.0.23
|
||||||
dnspython~=2.6.1
|
dnspython~=2.6.1
|
||||||
httpx~=0.27.0
|
httpx~=0.27.0
|
||||||
|
|||||||
Reference in New Issue
Block a user