mirror of
https://github.com/Ground-Zerro/DomainMapper.git
synced 2025-12-10 01:47:18 +07:00
Compare commits
37 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e9a6930711 | ||
|
|
a332a2c3a5 | ||
|
|
c74bbc6e97 | ||
|
|
6283d2d872 | ||
|
|
42856a4b31 | ||
|
|
496454eb03 | ||
|
|
e3794dff97 | ||
|
|
966e996160 | ||
|
|
ae95c589bb | ||
|
|
1193ae11a5 | ||
|
|
31eeb55792 | ||
|
|
eb234e261b | ||
|
|
567bef6a58 | ||
|
|
db6c7fd811 | ||
|
|
dfe73df66a | ||
|
|
7cc7815fb3 | ||
|
|
cd060dcee3 | ||
|
|
eba22848ee | ||
|
|
0edc4b5193 | ||
|
|
906e95cbc4 | ||
|
|
41b2d62647 | ||
|
|
67ab4758ed | ||
|
|
7b51669140 | ||
|
|
471400e27f | ||
|
|
e8f1f58474 | ||
|
|
ec2bc3eeb3 | ||
|
|
ed4b35dbd6 | ||
|
|
80c6106aa1 | ||
|
|
854d559f59 | ||
|
|
8a46dce764 | ||
|
|
1979b77567 | ||
|
|
1c333426b4 | ||
|
|
9ee7ae7e0d | ||
|
|
9890368164 | ||
|
|
9ce98ce052 | ||
|
|
0bf247a225 | ||
|
|
4291f321f5 |
180
README.md
180
README.md
@@ -1,9 +1,31 @@
|
||||
## Domain Mapper
|
||||
<details>
|
||||
<summary>Что нового (нажать, чтобы открыть)</summary>
|
||||
|
||||
- Добавлен сервис Jetbrains. [Запрос @SocketSomeone](https://github.com/Ground-Zerro/DomainMapper/issues/40)
|
||||
- Добавлен сервис Discord. [Запрос @AHuMex](https://github.com/Ground-Zerro/DomainMapper/issues/38)
|
||||
- [Комбинированный режим объединения IP-адресов в подсеть.](https://github.com/Ground-Zerro/DomainMapper/issues/36)
|
||||
- Возможность загрузки списков сервисов и DNS-серверов из локального файла. [Запрос @Noksa](https://github.com/Ground-Zerro/DomainMapper/issues/26)
|
||||
- Вспомагательные [утилиты](https://github.com/Ground-Zerro/DomainMapper/tree/main/utilities) для поиска субдоменов.
|
||||
- Добавлен сервис Twitch. [Запрос @shevernitskiy](https://github.com/Ground-Zerro/DomainMapper/issues/31)
|
||||
- Добавлен Yandex DNS сервер. [Запрос @Noksa](https://github.com/Ground-Zerro/DomainMapper/issues/26)
|
||||
- Опция в config.ini: Отключить отображение сведений о загруженой конфигурации.
|
||||
- Передача имени конфигурационного файла ключом в терминале/командной строке. [Запрос @Noksa](https://github.com/Ground-Zerro/DomainMapper/issues/25)
|
||||
- Добавлен сервис Github Copilot. [Запрос @aspirisen](https://github.com/Ground-Zerro/DomainMapper/issues/23)
|
||||
- Keenetic CLI формат сохранения. [Запрос @vchikalkin](https://github.com/Ground-Zerro/DomainMapper/pull/20)
|
||||
- Wireguard формат сохранения. [Запрос @sanikroot](https://github.com/Ground-Zerro/DomainMapper/issues/18)
|
||||
- Агрегация маршрутов до /24, /16. [Запрос @sergeeximius](https://github.com/Ground-Zerro/DomainMapper/issues/8)
|
||||
- OVPN формат сохранения. [Запрос @SonyLo](https://github.com/Ground-Zerro/DomainMapper/pull/13)
|
||||
- Mikrotik формат сохранения. [Запрос @Shaman2010](https://github.com/Ground-Zerro/DomainMapper/pull/9)
|
||||
|
||||
</details>
|
||||
|
||||
**Описание:** Инструмент на языке Python, предназначенный для разрешения DNS имен популярных веб-сервисов в IP-адреса.
|
||||
|
||||
Имеется поддержка следующих сервисов:
|
||||
|
||||
<details>
|
||||
<summary>Поддерживаемые сервисы (нажать, чтобы открыть)</summary>
|
||||
|
||||
- [Antifilter - community edition](https://community.antifilter.download/)
|
||||
- Youtube
|
||||
- Facebook
|
||||
@@ -20,64 +42,112 @@
|
||||
- Search engines
|
||||
- [Github сopilot](https://github.com/features/copilot)
|
||||
- Twitch
|
||||
- Discord
|
||||
- Jetbrains
|
||||
- Личный список
|
||||
|
||||
|
||||
**Функции:**
|
||||
- Скрипт использует списки доменных имен популярных сервисов и разрешает их в IP-адреса.
|
||||
- Итоговый список содержит только уникальные IP-адреса исключая дубликаты, также фильтруются IP-адреса самих DNS-серверов, заглушки в виде редиректа на localhost и (по желанию) IP-адреса Cloudflare.
|
||||
- Выбор между системным DNS сервером, популярными публичными, либо их комбинации.
|
||||
- Разрешение DNS имени происходит используя каждый из указанных пользователем DNS серверов и не останавливается при первом же успешном получении его IP-адреса.
|
||||
- Пользователь может создать свой список с DNS именами, необходимыми лично ему.
|
||||
- Агрегация маршрутов до /16 (255.255.0.0), /24 (255.255.255.0).
|
||||
|
||||
|
||||
**Автоматизация:**
|
||||
Конфигурационный файл позволяет настроить работу скрипта в "молчаливом" режиме - без промтов к пользователю.
|
||||
Так же в конфигурационном файле можно добавить выполнение кастомной команды в консоли для запуска другого скрипта или программы при завершении его работы.
|
||||
|
||||
|
||||
**Зависимости:** Для работы Domain Mapper необходимо наличие следующих библиотек Python:
|
||||
- configparser, ipaddress, dnspython, httpx, colorama.
|
||||
|
||||
*Не забудьте установить их перед запуском:*
|
||||
```
|
||||
pip3 install -r requirements.txt
|
||||
```
|
||||
|
||||
|
||||
**Использование:**
|
||||
- Запустить с помощью Python. Для работы необходим только "main.py" и (по желанию) файл "config.ini".
|
||||
|
||||
**Работа с личным списком DNS:**
|
||||
- Создать файл "custom-dns-list.txt", записать в него DNS имена (одна строчка - одно имя) и положить рядом со скриптом. Список будет подхвачен при запуске и отображен в меню как "Custom DNS list".
|
||||
|
||||
**Использование скрипта с кастомным конфигурационным файлом**
|
||||
- Можно передавать путь к конфигурационному файлу при запуске скрипта с помощью опции `-c` (или `--config`). Если параметр не указан, по умолчанию будет использоваться файл config.ini.
|
||||
|
||||
Пример использования: `main.py -с myconfig.ini` или `python main.py -с config2.ini` или `main.py -с srv5.ini` и т.п.
|
||||
|
||||
**Кто не знает "как", но кому "очень нужно":**
|
||||
- Загляните в директорию "Windows" репозитория.
|
||||
|
||||
|
||||
<details>
|
||||
<summary>Что нового</summary>
|
||||
|
||||
- Вспомагательные [утилиты](https://github.com/Ground-Zerro/DomainMapper/tree/main/utilities) для поиска субдоменов.
|
||||
- Добавлен сервис Twitch. [Запрос @shevernitskiy](https://github.com/Ground-Zerro/DomainMapper/issues/31)
|
||||
- Добавлен Yandex DNS сервер. [Запрос @Noksa](https://github.com/Ground-Zerro/DomainMapper/issues/26)
|
||||
- Опция в config.ini: Отключить отображение сведений о загруженой конфигурации.
|
||||
- Кастомное имя конфигурационного файла. [Запрос @Noksa](https://github.com/Ground-Zerro/DomainMapper/issues/25)
|
||||
- Добавлен сервис Github Copilot. [Запрос @aspirisen](https://github.com/Ground-Zerro/DomainMapper/issues/23)
|
||||
- Keenetic CLI формат сохранения. [Запрос @vchikalkin](https://github.com/Ground-Zerro/DomainMapper/pull/20)
|
||||
- Wireguard формат сохранения. [Запрос @sanikroot](https://github.com/Ground-Zerro/DomainMapper/issues/18)
|
||||
- Агрегация маршрутов до /24, /16. [Запрос @sergeeximius](https://github.com/Ground-Zerro/DomainMapper/issues/8)
|
||||
- OVPN формат сохранения. [Запрос @SonyLo](https://github.com/Ground-Zerro/DomainMapper/pull/13)
|
||||
- Mikrotik формат сохранения.[Запрос @Shaman2010](https://github.com/Ground-Zerro/DomainMapper/pull/9)
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
**Функции:**
|
||||
- Преобразование доменных имен популярных сервисов в IP-адреса.
|
||||
- Агрегация маршрутов в /16 (255.255.0.0) и /24 (255.255.255.0) подсети. Комбинированный режим /24 + /32.
|
||||
- Фильтрация IP-адресов Cloudflare (опционально).
|
||||
- Восемь вариантов сохранения результатов.
|
||||
|
||||
|
||||
**Ключевые особенности**
|
||||
- Возможность выбора системного, публичного DNS-сервера или их комбинации.
|
||||
- При разрешении доменного имени используется каждый из указанных DNS-серверов, при этом процесс продолжается до получения всех возможных IP-адресов, а не останавливается на первом успешном ответе.
|
||||
- Автоматическое исключение дубликатов IP-адресов, а также "заглушек" (например, IP самих DNS-серверов, редиректов на `0.0.0.0` и `localhost`).
|
||||
- Поддержка работы в "тихом" режиме без взаимодействия с пользователем, настройка через конфигурационный файл.
|
||||
- В конфигурационном файле можно указать команду для автоматического запуска другого скрипта или программы по завершении работы.
|
||||
|
||||
|
||||
### Использование:
|
||||
|
||||
1. Установите зависимости:
|
||||
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
2. Отредактируйте `config.ini` под свои задачи (опционально)
|
||||
|
||||
3. Запустите скрипт:
|
||||
|
||||
```bash
|
||||
python main.py
|
||||
```
|
||||
|
||||
|
||||
<details>
|
||||
<summary>Локальный режим работы (нажать, чтобы открыть)</summary>
|
||||
|
||||
В этом режиме списки DNS-серверов и сервисов загружаются из локальных файлов в папке со скриптом, а не из сети.
|
||||
|
||||
Для включения загрузки списка сервисов из локального файла `platformdb`, укажите `localplatform = yes` в config.ini.
|
||||
- Формат файла `platformdb`: название сервиса и путь к локальному файлу через двоеточие.
|
||||
Поддерживается работа как с файлами на локальной машине, так и их загрузка из сети по http(s).
|
||||
Пример:
|
||||
```
|
||||
Torrent Truckers: platforms/dns-ttruckers.lst
|
||||
Search engines: dns-search-engines.txt
|
||||
Twitch: platforms/service/dns-twitch.txt
|
||||
Adobe: https://raw.githubusercontent.com/Ground-Zerro/DomainMapper/main/platforms/dns-adobe.txt
|
||||
```
|
||||
|
||||
Для включения загрузки списка DNS-серверов из локального файла `dnsdb`, укажите `localdns = yes` в config.ini.
|
||||
- Формат файла `dnsdb`: название DNS-сервера и его IP-адреса через двоеточие и пробел.
|
||||
Важно - нужно обязательно указать два IP-адреса для каждого названия (можно один и тот же), это необходимо для правильной работы кода.
|
||||
Пример:
|
||||
```
|
||||
SkyDNS: 77.88.8.8 77.88.8.8
|
||||
Alternate DNS: 76.76.19.19 76.223.122.150
|
||||
AdGuard DNS: 94.140.14.14 94.140.15.15
|
||||
```
|
||||
|
||||
Важно: названия сервисов и нумерация DNS-серверов в config.ini должны соответствовать тем, что указаны в файлах `platformdb` и `dnsdb`.
|
||||
|
||||
- Формат файла с доменными именами: по одному домену на строку.
|
||||
Пример:
|
||||
```
|
||||
ab.chatgpt.com
|
||||
api.openai.com
|
||||
arena.openai.com
|
||||
```
|
||||
Указание URL вместо доменного имени (например, `ab.chatgpt.com/login` вместо `ab.chatgpt.com`) приведет к ошибке.
|
||||
</details>
|
||||
|
||||
|
||||
<details>
|
||||
<summary>Запуск скрипта с файлом конфигурации, отличным от `config.ini` (нажать, чтобы открыть)</summary>
|
||||
|
||||
- Указать путь к другому конфигурационному файлу при запуске скрипта можно с помощью опции `-c` (или `--config`). Если параметр не указан, по умолчанию будет использоваться файл `config.ini`.
|
||||
|
||||
Пример использования: `main.py -c myconfig.ini`, `python main.py -c config2.ini` или `main.py -c srv5.ini` и т.д.
|
||||
</details>
|
||||
|
||||
|
||||
<details>
|
||||
<summary>Личный (локальный) список с доменными именами (нажать, чтобы открыть)</summary>
|
||||
|
||||
- Создайте файл `custom-dns-list.txt`, запишите в него доменные имена и разместите его рядом со скриптом. Список будет автоматически подхвачен при запуске и появится в меню как "Custom DNS list".
|
||||
|
||||
- Пример файла `custom-dns-list.txt`:
|
||||
```
|
||||
ab.chatgpt.com
|
||||
api.openai.com
|
||||
arena.openai.com
|
||||
```
|
||||
Указание URL вместо доменного имени (например, `ab.chatgpt.com/login` вместо `ab.chatgpt.com`) приведет к ошибке.
|
||||
</details>
|
||||
|
||||
|
||||
<details>
|
||||
<summary>Для пользователей Windows, не знающих "как", но кому "очень нужно" (нажать, чтобы открыть)</summary>
|
||||
|
||||
- Загляните в директорию [Windows](https://github.com/Ground-Zerro/DomainMapper/tree/main/Windows) репозитория.
|
||||
</details>
|
||||
|
||||
|
||||
##### Протестировано в Ubuntu 20.04, macOS Sonoma и Windows 10/11
|
||||
|
||||
@@ -91,6 +91,8 @@ move /y domain-ip-resolve.txt %UserProfile%\Desktop\domain-ip-resolve.txt
|
||||
echo Программа завершена.
|
||||
del /q /f main.py
|
||||
endlocal
|
||||
echo файл скопирован в %UserProfile%\Desktop\domain-ip-resolve.txt
|
||||
pause
|
||||
exit /b 0
|
||||
|
||||
::То-ли при выгрузке на github, то-ли при скачивании с него, в файл как-то попадает BOM... Как это починить я ХЗ.
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
[DomainMapper]
|
||||
# Локальный режим - загружать список сервисов и/или DNS серверов из локального файла
|
||||
# yes - включить
|
||||
# no или пусто - выключить
|
||||
localplatform = yes
|
||||
localdns = yes
|
||||
|
||||
# Имена сервисов, разделенные запятыми, для разрешения доменных имен в IP-адреса без запроса у пользователя
|
||||
# опции:
|
||||
# пустое значение - пользователю будет выведено меню выбора
|
||||
@@ -19,6 +25,8 @@
|
||||
# Search engines - поисковые системы
|
||||
# Github Copilot - ИИ помощник от github
|
||||
# Twitch
|
||||
# Discord
|
||||
# Jetbrains
|
||||
# custom - Custom DNS list, это файл "custom-dns-list.txt" расположенный в одном каталоге со скриптом
|
||||
service =
|
||||
|
||||
@@ -53,6 +61,7 @@ cloudflare =
|
||||
# пустое значение - пользователю будет выведено меню выбора
|
||||
# 16 - группировка подсетей до /16 (255.255.0.0)
|
||||
# 24 - группировка подсетей до /24 (255.255.255.0)
|
||||
# mix - /24 и /32 в одном файле
|
||||
# no - оставить как есть
|
||||
subnet =
|
||||
|
||||
|
||||
371
main.py
371
main.py
@@ -13,24 +13,31 @@ from colorama import Fore, Style, init
|
||||
# Цвета
|
||||
init(autoreset=True)
|
||||
|
||||
|
||||
def yellow(text):
|
||||
return f"{Fore.YELLOW}{text}{Style.RESET_ALL}"
|
||||
|
||||
|
||||
def green(text):
|
||||
return f"{Fore.GREEN}{text}{Style.RESET_ALL}"
|
||||
|
||||
|
||||
def cyan(text):
|
||||
return f"{Fore.CYAN}{text}{Style.RESET_ALL}"
|
||||
|
||||
|
||||
def red(text):
|
||||
return f"{Fore.RED}{text}{Style.RESET_ALL}"
|
||||
|
||||
|
||||
def magneta(text):
|
||||
return f"{Fore.MAGENTA}{text}{Style.RESET_ALL}"
|
||||
|
||||
|
||||
def blue(text):
|
||||
return f"{Fore.BLUE}{text}{Style.RESET_ALL}"
|
||||
|
||||
|
||||
# Читаем конфигурацию
|
||||
def read_config(cfg_file):
|
||||
try:
|
||||
@@ -49,33 +56,53 @@ def read_config(cfg_file):
|
||||
dns_server_indices = list(map(int, config.get('dnsserver', '').split())) if config.get('dnsserver') else []
|
||||
mk_list_name = config.get('listname') or ''
|
||||
subnet = config.get('subnet') or ''
|
||||
cfginfo = config.get('cfginfo') or 'yes'
|
||||
cfginfo = config.get('cfginfo') or 'yes' # Не возвращаем его в main
|
||||
ken_gateway = config.get('keenetic') or ''
|
||||
localplatform = config.get('localplatform') or ''
|
||||
localdns = config.get('localdns') or ''
|
||||
|
||||
if cfginfo == 'yes':
|
||||
if cfginfo in ['yes', 'y']:
|
||||
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 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} {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 in ['y', 'yes'] else 'вЫключена' if cloudflare in ['n', 'no'] else 'спросить у пользователя'}")
|
||||
print(
|
||||
f"{Style.BRIGHT}Агрегация IP-адресов:{Style.RESET_ALL} {'mix режим /24 (255.255.255.0) + /32 (255.255.255.255)' if subnet == 'mix' else 'до /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 in ['win', 'unix', '']:
|
||||
print(
|
||||
f"{Style.BRIGHT}Шлюз/Имя интерфейса для Windows и Linux route:{Style.RESET_ALL} {gateway if gateway else 'спросить у пользователя'}")
|
||||
if filetype in ['keenetic', '']:
|
||||
print(
|
||||
f"{Style.BRIGHT}Шлюз/Имя интерфейса для Keenetic CLI:{Style.RESET_ALL} {ken_gateway if ken_gateway else 'спросить у пользователя'}")
|
||||
if filetype in ['mikrotik', '']:
|
||||
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 'не указано'}")
|
||||
print(
|
||||
f"{Style.BRIGHT}Выполнить по завершению:{Style.RESET_ALL} {run_command if run_command else 'не указано'}")
|
||||
if localplatform in ['yes', 'y'] or localdns in ['yes', 'y']:
|
||||
print(f"\n{red('!!! Включен локальный режим !!!')}")
|
||||
print(
|
||||
f"{Style.BRIGHT}Список сервисов будет загружен из:{Style.RESET_ALL} {'файла platformdb' if localplatform in ['yes', 'y'] else 'сети'}")
|
||||
print(
|
||||
f"{Style.BRIGHT}Список DNS серверов будет загружен из:{Style.RESET_ALL} {'файла dnsdb' if localdns in ['yes', 'y'] else 'сети'}")
|
||||
|
||||
return service, request_limit, filename, cloudflare, filetype, gateway, run_command, dns_server_indices, mk_list_name, subnet, ken_gateway
|
||||
return service, request_limit, filename, cloudflare, filetype, gateway, run_command, dns_server_indices, mk_list_name, subnet, ken_gateway, localplatform, localdns
|
||||
|
||||
except Exception as e:
|
||||
print(f"{yellow(f'Ошибка загрузки {cfg_file}:')} {e}\n{Style.BRIGHT}Используются настройки 'по умолчанию'.{Style.RESET_ALL}")
|
||||
return '', 20, 'domain-ip-resolve.txt', '', '', '', '', [], '', '', ''
|
||||
print(
|
||||
f"{yellow(f'Ошибка загрузки {cfg_file}:')} {e}\n{Style.BRIGHT}Используются настройки 'по умолчанию'.{Style.RESET_ALL}")
|
||||
return '', 20, 'domain-ip-resolve.txt', '', '', '', '', [], '', '', '', '', ''
|
||||
|
||||
|
||||
# IP шлюза для win и unix
|
||||
def gateway_input(gateway):
|
||||
if not gateway:
|
||||
input_gateway = input(f"Укажите {green('IP шлюза')} или {green('имя интерфейса')}: ")
|
||||
@@ -84,9 +111,11 @@ def gateway_input(gateway):
|
||||
return gateway
|
||||
|
||||
|
||||
# IP шлюза и имя интерфейса для keenetic
|
||||
def ken_gateway_input(ken_gateway):
|
||||
if not ken_gateway:
|
||||
input_ken_gateway = input(f"Укажите {green('IP шлюза')} или {green('имя интерфейса')} или {green('IP шлюза')} и через пробел {green('имя интерфейса')}: ")
|
||||
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
|
||||
@@ -102,6 +131,7 @@ def init_semaphores(request_limit):
|
||||
return get_semaphore(request_limit)
|
||||
|
||||
|
||||
# Загрузка списка платформ из сети
|
||||
async def load_urls(url):
|
||||
try:
|
||||
async with httpx.AsyncClient() as client:
|
||||
@@ -120,6 +150,21 @@ async def load_urls(url):
|
||||
return {}
|
||||
|
||||
|
||||
# Загрузка списка платформ из локального файла
|
||||
async def load_urls_from_file():
|
||||
try:
|
||||
with open('platformdb', 'r') as file:
|
||||
urls = {}
|
||||
for line in file:
|
||||
if line.strip():
|
||||
service, url = line.split(': ', 1)
|
||||
urls[service.strip()] = url.strip()
|
||||
return urls
|
||||
except Exception as e:
|
||||
print(f"Ошибка при загрузке списка платформ: {e}")
|
||||
return {}
|
||||
|
||||
|
||||
# Загрузка списка DNS серверов
|
||||
async def load_dns_servers(url):
|
||||
try:
|
||||
@@ -139,6 +184,21 @@ async def load_dns_servers(url):
|
||||
return {}
|
||||
|
||||
|
||||
# Загрузка списка DNS серверов из локального файла
|
||||
async def load_dns_from_file():
|
||||
try:
|
||||
with open('dnsdb', 'r') as file:
|
||||
dns_servers = {}
|
||||
for line in file:
|
||||
if line.strip():
|
||||
service, servers = line.split(': ', 1)
|
||||
dns_servers[service.strip()] = servers.strip().split()
|
||||
return dns_servers
|
||||
except Exception as e:
|
||||
print(f"Ошибка при загрузке списка DNS серверов: {e}")
|
||||
return {}
|
||||
|
||||
|
||||
# Загрузка IP-адресов cloudflare
|
||||
async def get_cloudflare_ips():
|
||||
try:
|
||||
@@ -162,7 +222,25 @@ async def get_cloudflare_ips():
|
||||
return set()
|
||||
|
||||
|
||||
async def resolve_domain(domain, resolver, semaphore, dns_server_name, null_ips_count, cloudflare_ips, cloudflare_ips_count, total_domains_processed, include_cloudflare):
|
||||
# Загрузка списков DNS имен из сети и локальных файлов
|
||||
async def load_dns_names(url_or_file):
|
||||
if url_or_file.startswith("http"):
|
||||
async with httpx.AsyncClient() as client:
|
||||
try:
|
||||
response = await client.get(url_or_file)
|
||||
response.raise_for_status()
|
||||
return response.text.splitlines()
|
||||
except httpx.HTTPStatusError as e:
|
||||
print(f"Ошибка при загрузке DNS имен: {e}")
|
||||
return []
|
||||
else:
|
||||
# Локальный файл
|
||||
with open(url_or_file, 'r', encoding='utf-8') as file:
|
||||
return file.read().splitlines()
|
||||
|
||||
|
||||
async def resolve_domain(domain, resolver, semaphore, dns_server_name, null_ips_count, cloudflare_ips,
|
||||
cloudflare_ips_count, total_domains_processed, include_cloudflare):
|
||||
async with semaphore:
|
||||
try:
|
||||
total_domains_processed[0] += 1
|
||||
@@ -183,9 +261,10 @@ async def resolve_domain(domain, resolver, semaphore, dns_server_name, null_ips_
|
||||
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):
|
||||
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}")
|
||||
print(f"{Fore.YELLOW}Загрузка DNS имен платформы {service}...{Style.RESET_ALL}")
|
||||
|
||||
tasks = []
|
||||
for server_name, servers in dns_servers:
|
||||
@@ -194,7 +273,9 @@ async def resolve_dns(service, dns_names, dns_servers, cloudflare_ips, unique_ip
|
||||
for domain in dns_names:
|
||||
domain = domain.strip()
|
||||
if domain:
|
||||
tasks.append(resolve_domain(domain, resolver, semaphore[server_name], server_name, null_ips_count, cloudflare_ips, cloudflare_ips_count, total_domains_processed, include_cloudflare))
|
||||
tasks.append(resolve_domain(domain, resolver, semaphore[server_name], server_name, null_ips_count,
|
||||
cloudflare_ips, cloudflare_ips_count, total_domains_processed,
|
||||
include_cloudflare))
|
||||
|
||||
results = await asyncio.gather(*tasks)
|
||||
|
||||
@@ -252,16 +333,13 @@ def check_service_config(service, urls, local_dns_names):
|
||||
return services
|
||||
|
||||
|
||||
# Промт cloudflare фильтр
|
||||
def check_include_cloudflare(cloudflare):
|
||||
if cloudflare.lower() == 'yes':
|
||||
return True
|
||||
elif cloudflare.lower() == 'no':
|
||||
return False
|
||||
else:
|
||||
return input(f"\n{yellow('Исключить IP адреса Cloudflare из итогового списка?')}"
|
||||
f"\n{green('yes')} - исключить"
|
||||
f"\n{green('Enter')} - оставить: ").strip().lower() == "yes"
|
||||
|
||||
if cloudflare in ['yes', 'y', 'no', 'n']:
|
||||
return cloudflare in ['yes', 'y']
|
||||
return input(f"\n{yellow('Исключить IP адреса Cloudflare из итогового списка?')}"
|
||||
f"\n{green('yes')} - исключить"
|
||||
f"\n{green('Enter')} - оставить: ").strip().lower() in ['yes', 'y']
|
||||
|
||||
def check_dns_servers(dns_servers, dns_server_indices):
|
||||
# Получение системных DNS серверов
|
||||
@@ -306,7 +384,7 @@ def check_dns_servers(dns_servers, dns_server_indices):
|
||||
return selected_dns_servers
|
||||
|
||||
|
||||
# microtik ввод комментария для 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: ")
|
||||
@@ -315,80 +393,79 @@ def mk_list_name_input(mk_list_name):
|
||||
return mk_list_name
|
||||
|
||||
|
||||
# Для mikrotik уплотняем имена сервисов
|
||||
# Уплотняем имена сервисов
|
||||
def mk_comment(selected_service):
|
||||
return ",".join(["".join(word.title() for word in s.split()) for s in selected_service])
|
||||
|
||||
|
||||
# Выбор формата сохранения списка разрешенных DNS имен
|
||||
def subnetting(subnet):
|
||||
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()
|
||||
# Промт на объединение IP в подсети
|
||||
def subnet_input(subnet):
|
||||
if not subnet: # Проверяем, является ли значение пустым
|
||||
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('mix')} - сократить до /24 (255.255.255.0) и /32 (255.255.255.255)"
|
||||
f"\n{green('Enter')} - пропустить: "
|
||||
).strip().lower()
|
||||
|
||||
# Обрабатываем ввод или параметр
|
||||
if subnet == '16':
|
||||
return "16", "255.255.0.0"
|
||||
elif subnet == '24':
|
||||
return "24", "255.255.255.0"
|
||||
else:
|
||||
return "32", "255.255.255.255"
|
||||
return subnet if subnet in {'16', '24', 'mix'} else '32'
|
||||
|
||||
|
||||
def group_ips_in_subnets(filename, submask):
|
||||
# Агрегация маршрутов
|
||||
def group_ips_in_subnets(filename, subnet):
|
||||
try:
|
||||
# Чтение всех IP-адресов из файла
|
||||
with open(filename, 'r', encoding='utf-8-sig') as file:
|
||||
ips = {line.strip() for line in file if line.strip()} # Собираем уникальные IP адреса
|
||||
|
||||
# Обработка подсетей в зависимости от маски
|
||||
if submask == "24":
|
||||
# Множество для хранения всех подсетей /24
|
||||
subnets = set()
|
||||
subnets = set()
|
||||
|
||||
# Преобразование всех IP в их подсети /24
|
||||
def process_ips(subnet):
|
||||
for ip in ips:
|
||||
try:
|
||||
# Преобразуем IP в сеть /24 (маска 255.255.255.0)
|
||||
network_24 = ipaddress.ip_network(f"{ip}/24", strict=False)
|
||||
subnets.add(str(network_24.network_address))
|
||||
if subnet == "16":
|
||||
# Преобразуем в /16 (два последних октета заменяются на 0.0)
|
||||
network = ipaddress.IPv4Network(f"{ip}/16", strict=False)
|
||||
subnets.add(f"{network.network_address}")
|
||||
elif subnet == "24":
|
||||
# Преобразуем в /24 (последний октет заменяется на 0)
|
||||
network = ipaddress.IPv4Network(f"{ip}/24", strict=False)
|
||||
subnets.add(f"{network.network_address}")
|
||||
except ValueError as e:
|
||||
print(f"{red('Ошибка в IP адресе:')} {ip} - {e}")
|
||||
print(f"Ошибка в IP адресе: {ip} - {e}")
|
||||
|
||||
# Перезаписываем файл с уникальными подсетями /24
|
||||
with open(filename, 'w', encoding='utf-8-sig') as file:
|
||||
for subnet in sorted(subnets):
|
||||
file.write(subnet + '\n')
|
||||
if subnet in ["24", "16"]:
|
||||
process_ips(subnet)
|
||||
print(f"{Style.BRIGHT}IP-адреса агрегированы до /{subnet} подсети{Style.RESET_ALL}")
|
||||
|
||||
print(f"{Style.BRIGHT}IP-адреса агрегированы до /{submask} подсети{Style.RESET_ALL}")
|
||||
|
||||
elif submask == "16":
|
||||
# Множество для хранения всех объединенных подсетей /16
|
||||
subnets = set()
|
||||
|
||||
# Преобразование всех IP в их подсети /16
|
||||
elif subnet == "mix":
|
||||
octet_groups = {}
|
||||
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}")
|
||||
key = '.'.join(ip.split('.')[:3]) # Группировка по первым трем октетам
|
||||
if key not in octet_groups:
|
||||
octet_groups[key] = []
|
||||
octet_groups[key].append(ip)
|
||||
|
||||
# Перезаписываем файл с уникальными подсетями /16
|
||||
with open(filename, 'w', encoding='utf-8-sig') as file:
|
||||
for subnet in sorted(subnets):
|
||||
file.write(subnet + '\n')
|
||||
# IP-адреса с совпадающими первыми тремя октетами
|
||||
network_24 = {key + '.0' for key, group in octet_groups.items() if
|
||||
len(group) > 1} # Базовый IP для /24 подсетей
|
||||
# Удаляем IP с совпадающими первыми тремя октетами из множества
|
||||
ips -= {ip for group in octet_groups.values() if len(group) > 1 for ip in group}
|
||||
# Оставляем только IP без указания маски для /24 и одиночных IP
|
||||
subnets.update(ips) # IP без маски для одиночных IP
|
||||
subnets.update(network_24) # Базовые IP для /24 подсетей
|
||||
print(f"{Style.BRIGHT}IP-адреса агрегированы до масок /24 и /32{Style.RESET_ALL}")
|
||||
|
||||
print(f"{Style.BRIGHT}IP-адреса агрегированы до /{submask} подсети{Style.RESET_ALL}")
|
||||
with open(filename, 'w', encoding='utf-8-sig') as file:
|
||||
for subnet in sorted(subnets):
|
||||
file.write(subnet + '\n')
|
||||
|
||||
except Exception as e:
|
||||
print(f"{red('Ошибка при обработке файла:')} {e}")
|
||||
print(f"Ошибка при обработке файла: {e}")
|
||||
|
||||
|
||||
def process_file_format(filename, filetype, gateway, selected_service, mk_list_name, submask, ken_gateway):
|
||||
# Выбор формата сохранения результатов
|
||||
def process_file_format(filename, filetype, gateway, selected_service, mk_list_name, subnet, ken_gateway):
|
||||
def read_file(filename):
|
||||
try:
|
||||
with open(filename, 'r', encoding='utf-8-sig') as file:
|
||||
@@ -398,28 +475,26 @@ def process_file_format(filename, filetype, gateway, selected_service, mk_list_n
|
||||
return None
|
||||
|
||||
def write_file(filename, ips, formatter):
|
||||
if filetype.lower() == 'wireguard':
|
||||
formatted_ips = [formatter(ip.strip()) for ip in ips]
|
||||
with open(filename, 'w', encoding='utf-8-sig') as file:
|
||||
file.write(', '.join(formatted_ips)) # Join with ", " to include a space after each comma
|
||||
else:
|
||||
with open(filename, 'w', encoding='utf-8-sig') as file:
|
||||
for ip in ips:
|
||||
file.write(formatter(ip.strip()) + '\n')
|
||||
formatted_ips = [formatter(ip.strip()) for ip in ips]
|
||||
with open(filename, 'w', encoding='utf-8-sig') as file:
|
||||
if filetype.lower() == 'wireguard':
|
||||
file.write(', '.join(formatted_ips))
|
||||
else:
|
||||
file.write('\n'.join(formatted_ips))
|
||||
|
||||
# Определение маски подсети для отображения пользователю и ее корректной записи в файл
|
||||
display_submask = "255.255.0.0" if submask == "16" else "255.255.255.0" if submask == "24" else "255.255.255.255"
|
||||
# Определение маски подсети
|
||||
net_mask = subnet if subnet == "mix" else "255.255.0.0" if subnet == "16" else "255.255.255.0" if subnet == "24" else "255.255.255.255"
|
||||
|
||||
if not filetype:
|
||||
filetype = input(f"""
|
||||
{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('ovpn')} - push "route {cyan('IP')} {display_submask}"
|
||||
{green('wireguard')} - {cyan('IP')}/{submask}, {cyan('IP')}/{submask}, и т.д...
|
||||
{green('win')} - route add {cyan('IP')} mask {net_mask} {cyan('GATEWAY')}
|
||||
{green('unix')} - ip route {cyan('IP')}/{subnet} {cyan('GATEWAY')}
|
||||
{green('keenetic')} - ip route {cyan('IP')}/{subnet} {cyan('GATEWAY GATEWAY_NAME')} auto !{mk_comment(selected_service)}
|
||||
{green('cidr')} - {cyan('IP')}/{subnet}
|
||||
{green('mikrotik')} - /ip/firewall/address-list add list={cyan("LIST_NAME")} comment="{mk_comment(selected_service)}" address={cyan("IP")}/{subnet}
|
||||
{green('ovpn')} - push "route {cyan('IP')} {net_mask}"
|
||||
{green('wireguard')} - {cyan('IP')}/{subnet}, {cyan('IP')}/{subnet}, и т.д...
|
||||
{green('Enter')} - {cyan('IP')}
|
||||
Ваш выбор: """)
|
||||
|
||||
@@ -427,28 +502,49 @@ def process_file_format(filename, filetype, gateway, selected_service, mk_list_n
|
||||
if not ips:
|
||||
return
|
||||
|
||||
# Запрашиваем IP шлюза для win и unix
|
||||
if filetype.lower() in ['win', 'unix']:
|
||||
# Дополнительные запросы в зависимости от формата файла
|
||||
if filetype in ['win', 'unix']: # Запрашиваем IP шлюза для win и unix
|
||||
gateway = gateway_input(gateway)
|
||||
|
||||
# Запрашиваем IP шлюза и Имя интерфейса для keenetic
|
||||
if filetype.lower() in ['keenetic']:
|
||||
elif filetype == 'keenetic': # Запрашиваем IP шлюза и имя интерфейса для keenetic
|
||||
ken_gateway = ken_gateway_input(ken_gateway)
|
||||
|
||||
# Запрашиваем mk_list_name для Mikrotik
|
||||
if filetype.lower() == 'mikrotik':
|
||||
elif filetype == 'mikrotik': # Запрашиваем ввод комментария для microtik firewall
|
||||
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}',
|
||||
'wireguard': lambda ip: f"{ip}/{submask}"
|
||||
'win': lambda ip: f"route add {ip} mask {net_mask} {gateway}",
|
||||
'unix': lambda ip: f"ip route {ip}/{subnet} {gateway}",
|
||||
'keenetic': lambda ip: f"ip route {ip}/{subnet} {ken_gateway} auto !{mk_comment(selected_service)}",
|
||||
'cidr': lambda ip: f"{ip}/{subnet}",
|
||||
'ovpn': lambda ip: f'push "route {ip} {net_mask}"',
|
||||
'mikrotik': lambda
|
||||
ip: f'/ip/firewall/address-list add list={mk_list_name} comment="{mk_comment(selected_service)}" address={ip}/{subnet}',
|
||||
'wireguard': lambda ip: f"{ip}/{subnet}"
|
||||
}
|
||||
|
||||
# mix формат
|
||||
if subnet == "mix":
|
||||
if filetype.lower() == 'win': # Обработка для win
|
||||
mix_formatter = lambda ip: f"{ip.strip()} mask 255.255.255.0" if ip.endswith(
|
||||
'.0') else f"{ip.strip()} mask 255.255.255.255"
|
||||
elif filetype.lower() == 'ovpn': # Обработка для ovpn
|
||||
mix_formatter = lambda ip: f"{ip.strip()} 255.255.255.0" if ip.endswith(
|
||||
'.0') else f"{ip.strip()} 255.255.255.255"
|
||||
else: # Обработка для остальных форматов
|
||||
mix_formatter = lambda ip: f"{ip.strip()}/24" if ip.endswith('.0') else f"{ip.strip()}/32"
|
||||
|
||||
formatters.update({
|
||||
'win': lambda ip: f"route add {mix_formatter(ip)} {gateway}",
|
||||
'unix': lambda ip: f"ip route {mix_formatter(ip)} {gateway}",
|
||||
'keenetic': lambda ip: f"ip route {mix_formatter(ip)} {ken_gateway} auto !{mk_comment(selected_service)}",
|
||||
'cidr': lambda ip: f"{mix_formatter(ip)}",
|
||||
'ovpn': lambda ip: f'push "route {mix_formatter(ip)}"',
|
||||
'mikrotik': lambda
|
||||
ip: f'/ip/firewall/address-list add list={mk_list_name} comment="{mk_comment(selected_service)}" address={mix_formatter(ip)}',
|
||||
'wireguard': lambda ip: f"{mix_formatter(ip)}"
|
||||
})
|
||||
|
||||
# Запись в файл
|
||||
if filetype.lower() in formatters:
|
||||
write_file(filename, ips, formatters[filetype.lower()])
|
||||
|
||||
@@ -467,13 +563,18 @@ async def main():
|
||||
|
||||
# Инициализация настроек из переданного конфигурационного файла
|
||||
config_file = args.config
|
||||
service, request_limit, filename, cloudflare, filetype, gateway, run_command, dns_server_indices, mk_list_name, subnet, ken_gateway = read_config(config_file)
|
||||
service, request_limit, filename, cloudflare, filetype, gateway, run_command, dns_server_indices, mk_list_name, subnet, ken_gateway, localplatform, localdns = read_config(
|
||||
config_file)
|
||||
|
||||
# Load URLs
|
||||
platform_db_url = "https://raw.githubusercontent.com/Ground-Zerro/DomainMapper/main/platformdb"
|
||||
urls = await load_urls(platform_db_url)
|
||||
# Загрузка списка платформ
|
||||
if localplatform in ['yes', 'y']:
|
||||
urls = await load_urls_from_file()
|
||||
|
||||
# Load local DNS names from "custom-dns-list.txt" if it exists
|
||||
else:
|
||||
platform_db_url = "https://raw.githubusercontent.com/Ground-Zerro/DomainMapper/main/platformdb"
|
||||
urls = await load_urls(platform_db_url)
|
||||
|
||||
# Подхват "custom-dns-list.txt" если существует
|
||||
local_dns_names = []
|
||||
if os.path.exists('custom-dns-list.txt'):
|
||||
with open('custom-dns-list.txt', 'r', encoding='utf-8-sig') as file:
|
||||
@@ -483,17 +584,22 @@ async def main():
|
||||
selected_services = check_service_config(service, urls, local_dns_names)
|
||||
|
||||
# Загрузка списка DNS-серверов
|
||||
dns_db_url = "https://raw.githubusercontent.com/Ground-Zerro/DomainMapper/main/dnsdb"
|
||||
dns_servers = await load_dns_servers(dns_db_url)
|
||||
if localdns in ['yes', 'y']:
|
||||
dns_servers = await load_dns_from_file()
|
||||
|
||||
else:
|
||||
dns_db_url = "https://raw.githubusercontent.com/Ground-Zerro/DomainMapper/main/dnsdb"
|
||||
dns_servers = await load_dns_servers(dns_db_url)
|
||||
|
||||
# Выбор DNS-серверов
|
||||
selected_dns_servers = check_dns_servers(dns_servers, dns_server_indices)
|
||||
|
||||
# Инициализация IP-адресов Cloudflare
|
||||
cloudflare_ips = await get_cloudflare_ips()
|
||||
|
||||
# Фильтр Cloudflare
|
||||
include_cloudflare = check_include_cloudflare(cloudflare)
|
||||
if include_cloudflare: # Загрузка IP-адресов Cloudflare
|
||||
cloudflare_ips = await get_cloudflare_ips()
|
||||
else:
|
||||
cloudflare_ips = set()
|
||||
|
||||
unique_ips_all_services = set()
|
||||
semaphore = init_semaphores(request_limit)
|
||||
@@ -507,12 +613,10 @@ async def main():
|
||||
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:
|
||||
response = await client.get(dns_names_url)
|
||||
response.raise_for_status()
|
||||
dns_names = response.text.splitlines()
|
||||
url_or_file = urls[service]
|
||||
dns_names = await load_dns_names(url_or_file)
|
||||
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))
|
||||
@@ -533,10 +637,11 @@ async def main():
|
||||
print(f"{Style.BRIGHT}Разрешено IP-адресов из DNS имен:{Style.RESET_ALL} {len(unique_ips_all_services)}")
|
||||
|
||||
# Группировка IP-адресов в подсети
|
||||
submask, _ = subnetting(subnet)
|
||||
group_ips_in_subnets(filename, submask)
|
||||
subnet = subnet_input(subnet)
|
||||
if subnet != '32': # Если не '32', вызываем функцию для агрегации
|
||||
group_ips_in_subnets(filename, subnet)
|
||||
|
||||
process_file_format(filename, filetype, gateway, selected_services, mk_list_name, submask, ken_gateway)
|
||||
process_file_format(filename, filetype, gateway, selected_services, mk_list_name, subnet, ken_gateway)
|
||||
|
||||
if run_command:
|
||||
print("\nВыполнение команды после завершения скрипта...")
|
||||
|
||||
@@ -13,4 +13,6 @@ Google: https://raw.githubusercontent.com/Ground-Zerro/DomainMapper/main/platfor
|
||||
Torrent Truckers: https://raw.githubusercontent.com/Ground-Zerro/DomainMapper/main/platforms/dns-ttruckers.txt
|
||||
Search engines: https://raw.githubusercontent.com/Ground-Zerro/DomainMapper/main/platforms/dns-search-engines.txt
|
||||
Github Copilot: https://raw.githubusercontent.com/Ground-Zerro/DomainMapper/main/platforms/dns-github-сopilot.txt
|
||||
Twitch: https://raw.githubusercontent.com/Ground-Zerro/DomainMapper/main/platforms/dns-twitch.txt
|
||||
Twitch: https://raw.githubusercontent.com/Ground-Zerro/DomainMapper/main/platforms/dns-twitch.txt
|
||||
Discord: https://raw.githubusercontent.com/Ground-Zerro/DomainMapper/refs/heads/main/platforms/dns-discord.txt
|
||||
Jetbrains: https://raw.githubusercontent.com/Ground-Zerro/DomainMapper/refs/heads/main/platforms/dns-jetbrains.txt
|
||||
|
||||
1488
platforms/dns-discord.txt
Normal file
1488
platforms/dns-discord.txt
Normal file
File diff suppressed because it is too large
Load Diff
97
platforms/dns-jetbrains.txt
Normal file
97
platforms/dns-jetbrains.txt
Normal file
@@ -0,0 +1,97 @@
|
||||
jetbrains.com.cn
|
||||
jb.gg
|
||||
myjetbrains.com
|
||||
jetbrains.com
|
||||
intellij.net
|
||||
academy.jetbrains.com
|
||||
account.jetbrains.com
|
||||
adobe.fls.jetbrains.com
|
||||
amazon.fls.jetbrains.com
|
||||
ap-help.api.jetbrains.com
|
||||
api-test.sandbox-resellers.jetbrains.com
|
||||
autoconfig.api.jetbrains.com
|
||||
autodiscover.api.jetbrains.com
|
||||
blog.jetbrains.com
|
||||
blogs.jetbrains.com
|
||||
ca.jetbrains.com
|
||||
cai.jetbrains.com
|
||||
cloudconfig.jetbrains.com
|
||||
code-with-me.jetbrains.com
|
||||
code2art.jetbrains.com
|
||||
codewithme-lobby-production.api.jetbrains.com
|
||||
codewithme-lobby-staging.api.jetbrains.com
|
||||
codewithme-lobby.api.jetbrains.com
|
||||
codewithme-relay-europe-north1-1.api.jetbrains.com
|
||||
codewithme-relay-europe-north1-2.api.jetbrains.com
|
||||
comments.blog.jetbrains.com
|
||||
configr.jetbrains.com
|
||||
confluence.jetbrains.com
|
||||
datalore-forum.jetbrains.com
|
||||
datalore.jetbrains.com
|
||||
dotcover-support.jetbrains.com
|
||||
dotmemory-support.jetbrains.com
|
||||
dotnet-ea.services.jetbrains.com
|
||||
dotpeek-support.jetbrains.com
|
||||
dottrace-support.jetbrains.com
|
||||
download-cdn.jetbrains.com
|
||||
dunnhumby.fls.jetbrains.com
|
||||
ea.jetbrains.com
|
||||
eap.jetbrains.com
|
||||
employee-guides.jetbrains.com
|
||||
fleet-relay.api.jetbrains.com
|
||||
ge.jetbrains.com
|
||||
geo2.datalore.jetbrains.com
|
||||
guide.master-zdchint.mau.jetbrains.com
|
||||
guide.staging-zdchint.mau.jetbrains.com
|
||||
hacktoberfest2020.mau.jetbrains.com
|
||||
handle.prod.csat.mau.jetbrains.com
|
||||
handle.staging.csat.mau.jetbrains.com
|
||||
hello.jetbrains.com
|
||||
ij-perf.jetbrains.com
|
||||
index-cdn.jetbrains.com
|
||||
int.api.jetbrains.com
|
||||
internship.jetbrains.com
|
||||
jb-team.fls.jetbrains.com
|
||||
jbstats.jetbrains.com
|
||||
jetarchive.jetbrains.com
|
||||
jetbrains.com
|
||||
jetpeople.jetbrains.com
|
||||
local.api.jetbrains.com
|
||||
lp.jetbrains.com
|
||||
lservice.jetbrains.com
|
||||
mail.jetbrains.com
|
||||
marketplace.jetbrains.com
|
||||
merchandise.jetbrains.com
|
||||
mkto-mailer.jetbrains.com
|
||||
mta-sts.jetbrains.com
|
||||
oauth.fls.jetbrains.com
|
||||
oauth2-proxy-api.api.jetbrains.com
|
||||
package-search.jetbrains.com
|
||||
package-search.services.jetbrains.com
|
||||
plugins.jetbrains.com
|
||||
renew-your-ssl-certificate.jetbrains.com
|
||||
resharper-plugins.jetbrains.com
|
||||
resources.jetbrains.com
|
||||
skyscanner.fls.jetbrains.com
|
||||
slack-bdt.mau.jetbrains.com
|
||||
slack-mps.jetbrains.com
|
||||
slack.jetbrains.com
|
||||
spotify.fls.jetbrains.com
|
||||
stackexchange.master-zdchint.mau.jetbrains.com
|
||||
stackexchange.staging-zdchint.mau.jetbrains.com
|
||||
staging.zdviewcount.mau.jetbrains.com
|
||||
support.jetbrains.com
|
||||
sv.fls.jetbrains.com
|
||||
teamcity-support.jetbrains.com
|
||||
teamcity.jetbrains.com
|
||||
tiles.datalore.jetbrains.com
|
||||
tiles2.datalore.jetbrains.com
|
||||
uploads.jetbrains.com
|
||||
uploads.services.jetbrains.com
|
||||
upsource.jetbrains.com
|
||||
view.datalore.jetbrains.com
|
||||
www.jetbrains.com
|
||||
www.onboard.jetbrains.com
|
||||
youtube.master-zdchint.mau.jetbrains.com
|
||||
youtube.staging-zdchint.mau.jetbrains.com
|
||||
zillow.fls.jetbrains.com
|
||||
5
platforms/dns-num.txt
Normal file
5
platforms/dns-num.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
themoviedb.org
|
||||
tmdb.org
|
||||
image.tmdb.org
|
||||
api.themoviedb.org
|
||||
tmdb-image-prod.b-cdn.net
|
||||
@@ -22,4 +22,5 @@ tiktokv.com
|
||||
us.tiktok.com
|
||||
verify-sg.tiktok.com
|
||||
v16-tiktokcdn-com.akamaized.net
|
||||
v16-va.tiktokcdn.com
|
||||
v16-va.tiktokcdn.com
|
||||
mcs-va.tiktokv.com
|
||||
|
||||
@@ -2,4 +2,6 @@ configparser~=7.0.1
|
||||
ipaddress~=1.0.23
|
||||
dnspython~=2.6.1
|
||||
httpx~=0.27.0
|
||||
colorama~=0.4.6
|
||||
colorama~=0.4.6
|
||||
requests~=2.31.0
|
||||
beautifulsoup4~=4.12.3
|
||||
@@ -27,13 +27,16 @@ def parse_page(url):
|
||||
domain = columns[0].text.strip() # Извлечение столбца 'Domain'
|
||||
data.add(domain) # Добавляем в множество
|
||||
|
||||
time.sleep(random.uniform(1, 3)) # Задержка между запросами
|
||||
time.sleep(random.choice([2, 3, 4, 5])) # Случайная задержка между запросами
|
||||
|
||||
if attempt > 0:
|
||||
print(f"Успешная загрузка {url} после {attempt}-й попытки.")
|
||||
return data
|
||||
|
||||
except requests.exceptions.HTTPError as e:
|
||||
if response.status_code == 429:
|
||||
print(f"Ошибка загрузки {url}. Пробуем еще раз...")
|
||||
time.sleep(3) # Фиксированная задержка перед повторной попыткой
|
||||
print(f"Ошибка загрузки {url}. Пробуем еще раз... (Попытка {attempt + 1})")
|
||||
time.sleep(5) # Фиксированная задержка перед повторной попыткой
|
||||
else:
|
||||
raise e
|
||||
|
||||
@@ -47,52 +50,42 @@ def parse_all_pages(base_url):
|
||||
recent_pages_data = [] # Список для хранения данных последних страниц
|
||||
|
||||
while keep_parsing:
|
||||
print(f"Парсим страницы с {page} по {page + 2}")
|
||||
pages = [f"{base_url}?page={p}" for p in range(page, page + 3)]
|
||||
print(f"Парсим страницу {page}")
|
||||
url = f"{base_url}?page={page}"
|
||||
|
||||
try:
|
||||
with ThreadPoolExecutor(max_workers=3) as executor:
|
||||
future_to_url = {executor.submit(parse_page, url): url for url in pages}
|
||||
for future in as_completed(future_to_url):
|
||||
url = future_to_url[future]
|
||||
try:
|
||||
result = future.result()
|
||||
if result is None: # Если страница пуста или не существует
|
||||
print(f"Страница {url.split('=')[-1]} не существует или пуста. Проверяем еще раз...")
|
||||
empty_page_attempts += 1
|
||||
time.sleep(3) # Ожидание перед повторной проверкой
|
||||
if empty_page_attempts >= 3:
|
||||
print(f"Страница {url.split('=')[-1]} пуста после 3 попыток. Остановка.")
|
||||
keep_parsing = False
|
||||
break
|
||||
else:
|
||||
continue # Переходим к следующей попытке
|
||||
else:
|
||||
empty_page_attempts = 0 # Обнуляем счётчик, если нашли данные
|
||||
all_domains.update(result) # Добавляем новые домены в множество
|
||||
print(f"Разбор {url} завершен.")
|
||||
|
||||
# Добавляем данные страницы в список для сравнения
|
||||
recent_pages_data.append(result)
|
||||
if len(recent_pages_data) > 3: # Храним данные только последних 3 страниц
|
||||
recent_pages_data.pop(0)
|
||||
|
||||
# Проверяем, повторяются ли данные на последних трёх страницах
|
||||
if len(recent_pages_data) == 3 and recent_pages_data[0] == recent_pages_data[1] == recent_pages_data[2]:
|
||||
print(f"Данные на последних трёх страницах одинаковы. Остановка парсинга.")
|
||||
keep_parsing = False
|
||||
break
|
||||
except Exception as e:
|
||||
print(f"Ошибка парсинга {url}: {e}")
|
||||
raise e
|
||||
except requests.exceptions.HTTPError as e:
|
||||
if '429' in str(e):
|
||||
print("Ошибка 429. Пауза 4 секунды.")
|
||||
time.sleep(3) # Пауза 3 секунды при ошибке 429
|
||||
result = parse_page(url)
|
||||
if result is None: # Если страница пуста или не существует
|
||||
print(f"Страница {page} не существует или пуста. Проверяем еще раз...")
|
||||
empty_page_attempts += 1
|
||||
time.sleep(5) # Ожидание перед повторной проверкой
|
||||
if empty_page_attempts >= 3:
|
||||
print(f"Страница {page} пуста после 3 попыток. Остановка.")
|
||||
keep_parsing = False
|
||||
break
|
||||
else:
|
||||
continue # Переходим к следующей попытке
|
||||
else:
|
||||
raise e # Пробрасываем другие ошибки, если они не 429
|
||||
empty_page_attempts = 0 # Обнуляем счётчик, если нашли данные
|
||||
all_domains.update(result) # Добавляем новые домены в множество
|
||||
print(f"Разбор страницы {page} завершен.")
|
||||
|
||||
page += 3 # Переход к следующему набору страниц
|
||||
# Добавляем данные страницы в список для сравнения
|
||||
recent_pages_data.append(result)
|
||||
if len(recent_pages_data) > 3: # Храним данные только последних 3 страниц
|
||||
recent_pages_data.pop(0)
|
||||
|
||||
# Проверяем, повторяются ли данные на последних трёх страницах
|
||||
if len(recent_pages_data) == 3 and recent_pages_data[0] == recent_pages_data[1] == recent_pages_data[2]:
|
||||
print(f"Данные на последних трёх страницах одинаковы. Остановка парсинга.")
|
||||
keep_parsing = False
|
||||
break
|
||||
|
||||
except Exception as e:
|
||||
print(f"Ошибка парсинга страницы {page}: {e}")
|
||||
raise e
|
||||
|
||||
page += 1 # Переход к следующей странице
|
||||
|
||||
return all_domains
|
||||
|
||||
|
||||
Reference in New Issue
Block a user