This commit is contained in:
Ground-Zerro
2024-09-15 00:38:00 +11:00
parent 7dc0b18c08
commit 3d1bf471bb
3 changed files with 65 additions and 34 deletions

View File

@@ -59,15 +59,21 @@ pip3 install -r requirements.txt
**Кто не знает "как", но кому "очень нужно":**
- Загляните в директорию "Windows" репозитория.
**New**
<details>
<summary>Что нового</summary>
- Добавлен Yandex DNS сервер. Запрос от @Noksa
- Опция в config.ini: Отключить отображение сведений о загруженой конфигурации.
- Кастомное имя конфигурационного файла. Запрос от @Noksa
- Добавлен сервис Github сopilot. Запрос от @aspirisen
- Добавлен сервис Github Copilot. Запрос от @aspirisen
- Keenetic CLI формат сохранения. Запрос от @vchikalkin
- Wireguard формат сохранения. Запрос от @sanikroot
- Агрегация маршрутов до /24, /16. Запрос от @sergeeximius
- ovpn формат сохранения. Запрос от @SonyLo
- OVPN формат сохранения. Запрос от @SonyLo
</details>
##### Протестировано в Ubuntu 20.04, macOS Sonoma и Windows 10/11

View File

@@ -78,12 +78,18 @@ threads =
# keenetic - ip route %IP%/32 %gateway% auto !%LIST_NAME%
filetype =
# адрес шлюза или имя интерфейса - используется при сохранении IP-адресов в 'win', 'unix' и 'keenetic' формате
# адрес шлюза или имя интерфейса - используется при сохранении IP-адресов в 'win' и 'unix' формате
# опции:
# пустое значение - пользователю будет выведен запрос с подсказкой
# укажите IP-адрес шлюза или имя интерфейса
gateway =
# адрес шлюза или имя интерфейса - используется при сохранении IP-адресов в 'keenetic' формате
# опции:
# пустое значение - пользователю будет выведен запрос с подсказкой
# укажите IP-адрес шлюза или имя интерфейса или IP-адрес шлюза и через пробел имя интерфейса
keenetic =
# имя списка - используется при сохранении IP-адресов в 'mikrotik' формате
# опции:
# пустое значение - пользователю будет выведен запрос с подсказкой
@@ -93,7 +99,7 @@ listname =
# Показывать сведения о загруженной конфигурации при запуске скрипта
# опции:
# yes или пустое значение - показывать
# no - не показывать
# no - скрыть
cfginfo = yes
# Команда для консоли после завершения скриптом всех операций, может быть полезно для автоматизации и комбинирования с другим скриптом, кодом или программой

77
main.py
View File

@@ -50,35 +50,48 @@ def read_config(cfg_file):
mk_list_name = config.get('listname') or ''
subnet = config.get('subnet') or ''
cfginfo = config.get('cfginfo') or 'yes'
ken_gateway = config.get('keenetic') or ''
if cfginfo == 'yes':
print(f"{yellow(f'Загружена конфигурация из {cfg_file}:')}")
print(f"{Style.BRIGHT}Сервисы для проверки:{Style.RESET_ALL} {service if service 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}Фильтр 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} {'только 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 'Keenetic CLI' if filetype == 'keenetic' else 'Wireguard' if filetype == 'wireguard' 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}Фильтрация IP-адресов Cloudflare:{Style.RESET_ALL} {'включена' if cloudflare in ['y', 'yes'] else 'вЫключена' if cloudflare in ['n', 'no'] else 'спросить у пользователя'}")
print(f"{Style.BRIGHT}Агрегация IP-адресов:{Style.RESET_ALL} {'до /16 подсети (255.255.0.0)' if subnet == '16' else 'до /24 подсети (255.255.255.0)' if subnet == '24' else 'вЫключена' if subnet in ['n', 'no'] 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 'Mikrotik CLI' if filetype == 'mikrotik' else 'open vpn' if filetype == 'ovpn' else 'Keenetic CLI' if filetype == 'keenetic' else 'Wireguard' if filetype == 'wireguard' else 'спросить у пользователя'}")
if filetype not in ['ip', 'cidr', 'mikrotik', 'ovpn', 'wireguard', 'keenetic']:
print(f"{Style.BRIGHT}Шлюз/Имя интерфейса для Windows и Linux route:{Style.RESET_ALL} {gateway if gateway else 'спросить у пользователя'}")
if filetype not in ['ip', 'unix', 'cidr', 'win', 'mikrotik', 'ovpn', 'wireguard']:
print(f"{Style.BRIGHT}Шлюз/Имя интерфейса для Keenetic CLI:{Style.RESET_ALL} {ken_gateway if ken_gateway else 'спросить у пользователя'}")
if filetype not in ['ip', 'unix', 'cidr', 'win', 'ovpn', 'wireguard', 'keenetic']:
print(f"{Style.BRIGHT}Имя списка для Mikrotik firewall:{Style.RESET_ALL} {mk_list_name if mk_list_name else 'спросить у пользователя'}")
print(f"{Style.BRIGHT}Сохранить результат в файл:{Style.RESET_ALL} {filename}")
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, ken_gateway
except Exception as e:
print(f"{yellow(f'Ошибка загрузки {cfg_file}:')} {e}\n{Style.BRIGHT}Используются настройки 'по умолчанию'.{Style.RESET_ALL}")
return '', 20, 'domain-ip-resolve.txt', '', '', '', '', [], '', ''
return '', 20, 'domain-ip-resolve.txt', '', '', '', '', [], '', '', ''
def gateway_input(gateway):
if not gateway:
input_gateway = input(f"Укажите {green('шлюз')} или {green('имя интерфейса')}: ")
input_gateway = input(f"Укажите {green('IP шлюза')} или {green('имя интерфейса')}: ")
return input_gateway.strip() if input_gateway else None
else:
return gateway
def ken_gateway_input(ken_gateway):
if not ken_gateway:
input_ken_gateway = input(f"Укажите {green('IP шлюза')} или {green('имя интерфейса')} или {green('IP шлюза')} и через пробел {green('имя интерфейса')}: ")
return input_ken_gateway.strip() if input_ken_gateway else None
else:
return ken_gateway
# Ограничение числа запросов
def get_semaphore(request_limit):
return defaultdict(lambda: Semaphore(request_limit))
@@ -169,6 +182,7 @@ async def resolve_domain(domain, resolver, semaphore, dns_server_name, null_ips_
print(f"{Fore.RED}Не удалось получить IP-адрес: {domain} - {dns_server_name}{Style.RESET_ALL}")
return []
async def resolve_dns(service, dns_names, dns_servers, cloudflare_ips, unique_ips_all_services, semaphore, null_ips_count, cloudflare_ips_count, total_domains_processed, include_cloudflare):
try:
print(f"{Fore.YELLOW}Анализ DNS имен платформы {service}...{Style.RESET_ALL}")
@@ -238,7 +252,6 @@ def check_service_config(service, urls, local_dns_names):
return services
# Промт на исключение IP-адресов cloudflare
def check_include_cloudflare(cloudflare):
if cloudflare.lower() == 'yes':
return True
@@ -293,7 +306,7 @@ def check_dns_servers(dns_servers, dns_server_indices):
return selected_dns_servers
# Для microtik ввод комментария comment для firewall
# microtik ввод комментария для firewall
def mk_list_name_input(mk_list_name):
if not mk_list_name:
input_mk_list_name = input(f"Введите {green('LIST_NAME')} для Mikrotik firewall: ")
@@ -309,8 +322,7 @@ def mk_comment(selected_service):
# Выбор формата сохранения списка разрешенных DNS имен
def subnetting(subnet):
# Если значение пустое, запрашиваем ввод от пользователя
if subnet.lower() == '':
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)"
@@ -376,7 +388,7 @@ def group_ips_in_subnets(filename, submask):
print(f"{red('Ошибка при обработке файла:')} {e}")
def process_file_format(filename, filetype, gateway, selected_service, mk_list_name, submask):
def process_file_format(filename, filetype, gateway, selected_service, mk_list_name, submask, ken_gateway):
def read_file(filename):
try:
with open(filename, 'r', encoding='utf-8-sig') as file:
@@ -403,11 +415,11 @@ def process_file_format(filename, filetype, gateway, selected_service, mk_list_n
{yellow('В каком формате сохранить файл?')}
{green('win')} - route add {cyan('IP')} mask {display_submask} {cyan('GATEWAY')}
{green('unix')} - ip route {cyan('IP')}/{submask} {cyan('GATEWAY')}
{green('keenetic')} - ip route {cyan('IP')}/{submask} {cyan('GATEWAY GATEWAY_NAME')} auto !{mk_comment(selected_service)}
{green('cidr')} - {cyan('IP')}/{submask}
{green('mikrotik')} - /ip/firewall/address-list add list={cyan("LIST_NAME")} comment="{mk_comment(selected_service)}" address={cyan("IP")}/{submask}
{green('keenetic')} - ip route {cyan('IP')}/{submask} {cyan('GATEWAY')} auto !{mk_comment(selected_service)}
{green('ovpn')} - push "route {cyan('IP')} {display_submask}"
{green('wireguard')} - {cyan('IP')}/{submask}, и т.д...
{green('wireguard')} - {cyan('IP')}/{submask}, {cyan('IP')}/{submask}, и т.д...
{green('Enter')} - {cyan('IP')}
Ваш выбор: """)
@@ -415,21 +427,25 @@ def process_file_format(filename, filetype, gateway, selected_service, mk_list_n
if not ips:
return
# Если формат требует указания шлюза, запрашиваем его
if filetype.lower() in ['win', 'unix', 'keenetic']:
gateway = gateway_input(gateway) # Сохраняем значение шлюза после ввода
# Запрашиваем IP шлюза для win и unix
if filetype.lower() in ['win', 'unix']:
gateway = gateway_input(gateway)
# Если выбран формат Mikrotik, запрашиваем mk_list_name
# Запрашиваем IP шлюза и Имя интерфейса для keenetic
if filetype.lower() in ['keenetic']:
ken_gateway = ken_gateway_input(ken_gateway)
# Запрашиваем mk_list_name для Mikrotik
if filetype.lower() == 'mikrotik':
mk_list_name = mk_list_name_input(mk_list_name) # Сохраняем значение mk_list_name после ввода
mk_list_name = mk_list_name_input(mk_list_name)
formatters = {
'win': lambda ip: f"route add {ip} mask {display_submask} {gateway}",
'unix': lambda ip: f"ip route {ip}/{submask} {gateway}",
'keenetic': lambda ip: f"ip route {ip}/{submask} {ken_gateway} auto !{mk_comment(selected_service)}",
'cidr': lambda ip: f"{ip}/{submask}",
'ovpn': lambda ip: f'push "route {ip} {display_submask}"',
'mikrotik': lambda ip: f'/ip/firewall/address-list add list={mk_list_name} comment="{mk_comment(selected_service)}" address={ip}/{submask}',
'keenetic': lambda ip: f"ip route {ip}/{submask} {gateway} auto !{mk_comment(selected_service)}",
'wireguard': lambda ip: f"{ip}/{submask}"
}
@@ -437,7 +453,7 @@ def process_file_format(filename, filetype, gateway, selected_service, mk_list_n
write_file(filename, ips, formatters[filetype.lower()])
# Ну чо, погнали?!
# Стартуем
async def main():
# Парсинг аргументов командной строки
parser = argparse.ArgumentParser(description="DNS resolver script with custom config file.")
@@ -451,7 +467,7 @@ async def main():
# Инициализация настроек из переданного конфигурационного файла
config_file = args.config
service, request_limit, filename, cloudflare, filetype, gateway, run_command, dns_server_indices, mk_list_name, subnet = read_config(config_file)
service, request_limit, filename, cloudflare, filetype, gateway, run_command, dns_server_indices, mk_list_name, subnet, ken_gateway = read_config(config_file)
# Load URLs
platform_db_url = "https://raw.githubusercontent.com/Ground-Zerro/DomainMapper/main/platformdb"
@@ -488,8 +504,9 @@ async def main():
for service in selected_services:
if service == 'Custom DNS list':
tasks.append(resolve_dns(service, local_dns_names, selected_dns_servers, cloudflare_ips, unique_ips_all_services,
semaphore, null_ips_count, cloudflare_ips_count, total_domains_processed, include_cloudflare))
tasks.append(resolve_dns(service, local_dns_names, selected_dns_servers, cloudflare_ips,
unique_ips_all_services, semaphore, null_ips_count, cloudflare_ips_count,
total_domains_processed, include_cloudflare))
else:
dns_names_url = urls[service]
async with httpx.AsyncClient() as client:
@@ -497,7 +514,8 @@ async def main():
response.raise_for_status()
dns_names = response.text.splitlines()
tasks.append(resolve_dns(service, dns_names, selected_dns_servers, cloudflare_ips, unique_ips_all_services,
semaphore, null_ips_count, cloudflare_ips_count, total_domains_processed, include_cloudflare))
semaphore, null_ips_count, cloudflare_ips_count, total_domains_processed,
include_cloudflare))
results = await asyncio.gather(*tasks)
@@ -518,7 +536,7 @@ async def main():
submask, _ = subnetting(subnet)
group_ips_in_subnets(filename, submask)
process_file_format(filename, filetype, gateway, selected_services, mk_list_name, submask)
process_file_format(filename, filetype, gateway, selected_services, mk_list_name, submask, ken_gateway)
if run_command:
print("\nВыполнение команды после завершения скрипта...")
@@ -528,5 +546,6 @@ async def main():
if os.name == 'nt':
input(f"Нажмите {green('Enter')} для выхода...")
if __name__ == "__main__":
asyncio.run(main())
asyncio.run(main())