«И не было спасения от спама, пока люди не придумали DNSBL!» А если серьёзно, то DNSBL – это DNS blocklist, то есть, черные списки, которые хранятся на серверах с использованием структуры DNS. Уже из самого названия понятно, что данные списки предназначены для того, чтобы почтовые сервера проверяли их, и, на основании полученных данных формировали репутацию адреса или хоста. Попасть в эти списки легко, а вот выбраться уже тяжелее. Но, речь сейчас не о том, как удалить адрес из черного списка, а о том, как проверить, не попал ли адрес вашего домена туда, с помощью Python.
Попасть в черные списки легко. Тут, можно сказать, все зависит от того, кто формирует правила добавления в них адреса. И если Луна совпала с Сатурном, то может статься так, что ваш белый и пушистый домен попадет в него с очень большой легкостью. Для примера, попасть можно по следующим причинам: подозрительная активность почтового сервера; неправильная настройка конфигурации сервера; жалобы клиентов; прокси и множество других причин.
Черных списков хостов достаточно много. Я, при не особо настойчивом поиске нашел 97 штук, которые работают более-менее стабильно. Некоторые из этих списков, такие как, к примеру, spamhaus.org приобрели хорошую репутацию и их стали использовать самые разнообразные сервисы.
Что потребуется?
Для начала, нам потребуется библиотека для работы с dns-серверами, dnspython. Для ее установки пишем в терминале:
Так же нам потребуется библиотека requests, для того, чтобы, во-первых, получать внешний ip-адрес компьютера, хоть это и не обязательно, а во-вторых, чтобы загружать список DNSBL, в-третьих, загружать список диапазонов адресов Cloudflare. Для ее установки пишем в терминале:
Ну и совсем не обязательная, но, тем не менее, радующая глаз библиотека colorama. С ее помощью довольно удобно выводить различные сообщения в терминал в цвете. Установим ее с помощью команды:
Теперь, когда все нужные библиотеки установлены, давайте импортируем их в скрипт, и сразу же инициализируем библиотеку colorama.
Проверка ip-адреса на принадлежность Cloudflare
Эта проверка делается для того, чтобы попусту не тратить ваше время и не мучить DNS-сервера. Впрочем, проверять или нет, тут уже все зависит от пользователя. А вот о том, входит ли адрес в диапазон сообщить нужно.
Создадим функцию ip_in_range(ip, addr), которая на входе принимает ip-адрес и диапазон адресов Cloudflare, проверяет, содержится ли адрес в диапазоне и возвращает в зависимости от этого True или False. Для выполнения данной проверки будем использовать библиотеку ipaddress и ее функции ip_address и ip_network. С помощью первой мы переводим строку в адрес. А с помощью второй создаем диапазон адресов из переданного адреса с указанным диапазоном.
На следующем этапе нам понадобиться вторая функция, которая тоже относиться к проверке адреса на принадлежность Cloudflare. Создадим ее, и назовем, к примеру: cloudf_detect(ip). Здесь, на входе функция получает ip-адрес. Затем загружает список диапазонов адресов и в цикле помещает их в предварительно созданный для этого список list_addr. Данный список не является пустым, я уже добавил в него один диапазон, так как данного диапазона нет при загрузке. А вот при проверке адреса с помощью Whois, он вдруг находиться. Затем запускаем еще один цикл, в котором пробегаемся по списку сформированных диапазонов адресов и передаем их в функцию проверки адреса. Если адрес есть в диапазонах, возвращаем True, если нет – False.
Получение внешнего ip-адреса
Тут все просто. Делаем запрос с помощью requests на сайт api.ipify.org, а в ответ нам прилетает наш внешний адрес. Если же по какой-то причине соединение с данным сайтом не получиться, обработаем исключение и вернем адрес локальной петли.
Проверка ip-адреса в черных списках
Для начала создадим функцию dns_bl_check(ip). На входе она принимает ip-адрес, даже если вы проверяете наличие домена в черных списках. Создаем словарь, в который будем помещать имя списка, в котором найдется адрес и, содержимое поля «TXT», в котором, преимущественно, указан адрес, куда можно обратиться за подробностями, если ваш адрес вдруг нашелся здесь.
После получаем список DNSBL, в которых будем проверять адрес. Я для списка создал на GitHub файлик, в который все это и запихал. Можно было бы использовать и локальный файл. Но так мне показалось немного удобнее. В списке содержится 97 адресов. Все их я проверил на валидность, и на момент написания статьи они работали. Получаем мы список с помощью requests. Затем создаем переменную, в которую помещаем текст результата запроса и разбиваем на строки, чтобы получился список строк. А уже по этим строкам запускаем цикл, где перебираем каждую и формируем запрос. Запрос формируется в обратном порядке, то есть, у вас должен получиться реверс: 2.0.0.127.dbl.spamhaus.org. Потому мы разбиваем строку на части по строкам, делаем реверс и собираем снова. Вторым параметром для сборки запроса служит адрес черного списка из строки.
Теперь создаем резольвер, устанавливаем таймаут для запроса, а также время его жизни.
Делаем запросы к записям типа «А» и «TXT». Получаем из них данные. Если данные получены, то печатаем строку с сервером, с которого получали данные и результат запроса, в данном случае BAD, так как искомый адрес найден, а значит, содержится в черном списке. Далее определяем паттерн для регулярного выражения, с помощью которого будем искать ссылки в ответах TXT. Если же ссылок найдено не будет, так и пишем, что ничего нет. И напоследок добавляем найденное в словарь. То есть, добавляем имя сервера, где искали, результат ответа по записи типа А, и найденную или не найденную ссылку на подробности.
Обрабатываем исключения, которые будут возникать при совершении запросов. Их может быть больше, но в основном, чаще всего, проявляются эти. Первое исключение возникает тогда, когда не найдено записей. Оно нам будет нужно, для того, чтобы печатать, что на данном сервере с вашим адресом все ОК. А следующие два, это исключение возникающее, когда время ожидания ответа истекает и когда нет ответа от сервера.
Дальше обрабатываем то, что получили. Если словарь, в который мы добавляли найденные записи пустой, радостно сообщаем об этом пользователю. Если же нет, печатаем его содержимое.
Получение данных от пользователя
И еще одна функция, main(). Здесь, для начала мы сообщаем пользователю его внешний IP-адрес. Затем запрашиваем адрес или домен для проверки. Ну и если он желает выйти, он может ввести х. После получаем ip-адрес, так как пользователь может ввести имя домена. В случае ошибки получения адреса завершаем работу скрипта. После того, как адрес получен, запускаем проверку, не является ли полученный адрес за Cloudflare. И если да, то предлагаем пользователю альтернативу, проверять или не проверять. В случае проверки запускаем функцию. Если нет, просто возвращаемся в пользовательское меню. Ну и если адреса за Cloudflare не обнаружено, просто запускаем функцию проверки.
Сказать по правде, не особо задумывался о том, что надо проверять адреса в черных списках. Да, о проверке прокси в черных списках слышал, и даже проверял. Но вот чтобы адрес компьютера… и, как оказалось зря. К примеру, мой адрес засветился уже более чем в 5-ти листах. И не во всех случаях виноват я )), адрес то динамически. Тем более, есть там и записи, что адрес был частью ботнета. А я то думаю, почему иногда тот же Cloudflare меня тормозит и заставляет проходить проверки. А одна из причин может быть в этом.
Что же, на этом, пожалуй, все. Ниже приведу пример работы скрипта на скриншоте. А также полный его код.
Спасибо за внимание. Надеюсь, что эта информация будет вам полезна
Попасть в черные списки легко. Тут, можно сказать, все зависит от того, кто формирует правила добавления в них адреса. И если Луна совпала с Сатурном, то может статься так, что ваш белый и пушистый домен попадет в него с очень большой легкостью. Для примера, попасть можно по следующим причинам: подозрительная активность почтового сервера; неправильная настройка конфигурации сервера; жалобы клиентов; прокси и множество других причин.
Черных списков хостов достаточно много. Я, при не особо настойчивом поиске нашел 97 штук, которые работают более-менее стабильно. Некоторые из этих списков, такие как, к примеру, spamhaus.org приобрели хорошую репутацию и их стали использовать самые разнообразные сервисы.
Что потребуется?
Для начала, нам потребуется библиотека для работы с dns-серверами, dnspython. Для ее установки пишем в терминале:
pip install dnspython
Так же нам потребуется библиотека requests, для того, чтобы, во-первых, получать внешний ip-адрес компьютера, хоть это и не обязательно, а во-вторых, чтобы загружать список DNSBL, в-третьих, загружать список диапазонов адресов Cloudflare. Для ее установки пишем в терминале:
pip install requests
Ну и совсем не обязательная, но, тем не менее, радующая глаз библиотека colorama. С ее помощью довольно удобно выводить различные сообщения в терминал в цвете. Установим ее с помощью команды:
pip install colorama
Теперь, когда все нужные библиотеки установлены, давайте импортируем их в скрипт, и сразу же инициализируем библиотеку colorama.
Python:
import re
import socket
from ipaddress import ip_network, ip_address
import dns
from colorama import Fore
from colorama import init
from dns import resolver
from requests import get, exceptions
init()
Проверка ip-адреса на принадлежность Cloudflare
Эта проверка делается для того, чтобы попусту не тратить ваше время и не мучить DNS-сервера. Впрочем, проверять или нет, тут уже все зависит от пользователя. А вот о том, входит ли адрес в диапазон сообщить нужно.
Создадим функцию ip_in_range(ip, addr), которая на входе принимает ip-адрес и диапазон адресов Cloudflare, проверяет, содержится ли адрес в диапазоне и возвращает в зависимости от этого True или False. Для выполнения данной проверки будем использовать библиотеку ipaddress и ее функции ip_address и ip_network. С помощью первой мы переводим строку в адрес. А с помощью второй создаем диапазон адресов из переданного адреса с указанным диапазоном.
Python:
def ip_in_range(ip, addr):
if ip_address(ip) in ip_network(addr):
return True
return False
На следующем этапе нам понадобиться вторая функция, которая тоже относиться к проверке адреса на принадлежность Cloudflare. Создадим ее, и назовем, к примеру: cloudf_detect(ip). Здесь, на входе функция получает ip-адрес. Затем загружает список диапазонов адресов и в цикле помещает их в предварительно созданный для этого список list_addr. Данный список не является пустым, я уже добавил в него один диапазон, так как данного диапазона нет при загрузке. А вот при проверке адреса с помощью Whois, он вдруг находиться. Затем запускаем еще один цикл, в котором пробегаемся по списку сформированных диапазонов адресов и передаем их в функцию проверки адреса. Если адрес есть в диапазонах, возвращаем True, если нет – False.
Python:
def cloudf_detect(ip):
list_addr = ["104.16.0.0/12"]
url = 'https://www.cloudflare.com/ips-v4'
req = get(url=url)
for adr in req.text.split("\n"):
list_addr.append(adr)
for addr in list_addr:
detect = ip_in_range(ip, addr)
if detect:
return True
return False
Получение внешнего ip-адреса
Тут все просто. Делаем запрос с помощью requests на сайт api.ipify.org, а в ответ нам прилетает наш внешний адрес. Если же по какой-то причине соединение с данным сайтом не получиться, обработаем исключение и вернем адрес локальной петли.
Python:
def public_ip():
try:
return get('https://api.ipify.org/').text
except exceptions.ConnectionError:
return '127.0.0.1'
Проверка ip-адреса в черных списках
Для начала создадим функцию dns_bl_check(ip). На входе она принимает ip-адрес, даже если вы проверяете наличие домена в черных списках. Создаем словарь, в который будем помещать имя списка, в котором найдется адрес и, содержимое поля «TXT», в котором, преимущественно, указан адрес, куда можно обратиться за подробностями, если ваш адрес вдруг нашелся здесь.
После получаем список DNSBL, в которых будем проверять адрес. Я для списка создал на GitHub файлик, в который все это и запихал. Можно было бы использовать и локальный файл. Но так мне показалось немного удобнее. В списке содержится 97 адресов. Все их я проверил на валидность, и на момент написания статьи они работали. Получаем мы список с помощью requests. Затем создаем переменную, в которую помещаем текст результата запроса и разбиваем на строки, чтобы получился список строк. А уже по этим строкам запускаем цикл, где перебираем каждую и формируем запрос. Запрос формируется в обратном порядке, то есть, у вас должен получиться реверс: 2.0.0.127.dbl.spamhaus.org. Потому мы разбиваем строку на части по строкам, делаем реверс и собираем снова. Вторым параметром для сборки запроса служит адрес черного списка из строки.
Python:
print(Fore.YELLOW + '\n- Проверка черных списков\n')
bad_dict = dict()
req = get('https://raw.githubusercontent.com/evgenycc/DNSBL-list/main/DNSBL')
read = req.text.splitlines()
for serv in read:
req = f"{'.'.join(reversed(ip.split('.')))}.{serv.strip()}"
Теперь создаем резольвер, устанавливаем таймаут для запроса, а также время его жизни.
Python:
resolv = dns.resolver.Resolver()
resolv.timeout = 5
resolv.lifetime = 5
Делаем запросы к записям типа «А» и «TXT». Получаем из них данные. Если данные получены, то печатаем строку с сервером, с которого получали данные и результат запроса, в данном случае BAD, так как искомый адрес найден, а значит, содержится в черном списке. Далее определяем паттерн для регулярного выражения, с помощью которого будем искать ссылки в ответах TXT. Если же ссылок найдено не будет, так и пишем, что ничего нет. И напоследок добавляем найденное в словарь. То есть, добавляем имя сервера, где искали, результат ответа по записи типа А, и найденную или не найденную ссылку на подробности.
Python:
resp = resolv.resolve(req, 'A')
resp_txt = resolv.resolve(req, 'TXT')
print(Fore.RED + f'{serv.strip():30}: [BAD]')
pattern = '(?:https?:\/\/)?(?:[\w\.]+)\.(?:[a-z]{2,6}\.?)(?:\/[\w\.]*)*\/?'
find = re.findall(pattern, str(resp_txt[0]))
if len(find) == 0:
find = ['No address']
bad_dict.update({serv.strip(): f'{resp[0]} {find[0]}'})
Обрабатываем исключения, которые будут возникать при совершении запросов. Их может быть больше, но в основном, чаще всего, проявляются эти. Первое исключение возникает тогда, когда не найдено записей. Оно нам будет нужно, для того, чтобы печатать, что на данном сервере с вашим адресом все ОК. А следующие два, это исключение возникающее, когда время ожидания ответа истекает и когда нет ответа от сервера.
Python:
except dns.resolver.NXDOMAIN:
print(Fore.GREEN + f'{serv.strip():30}: [OK]')
except (dns.resolver.LifetimeTimeout, dns.resolver.NoAnswer):
continue
Дальше обрабатываем то, что получили. Если словарь, в который мы добавляли найденные записи пустой, радостно сообщаем об этом пользователю. Если же нет, печатаем его содержимое.
Python:
if len(bad_dict) > 0:
len_str = len(f'IP-АДРЕС: "{ip.upper()}" ОБНАРУЖЕН В ЧЕРНЫХ СПИСКАХ')
print(Fore.BLUE + f'\nIP-АДРЕС: {ip.upper()} ОБНАРУЖЕН В ЧЕРНЫХ СПИСКАХ\n{"*"*len_str}')
for bad in bad_dict:
print(f' - {Fore.YELLOW + bad:30} : {Fore.RESET +bad_dict[bad]}')
else:
print(Fore.GREEN + '\n[+] IP-адрес в черных списках не обнаружен')
Получение данных от пользователя
И еще одна функция, main(). Здесь, для начала мы сообщаем пользователю его внешний IP-адрес. Затем запрашиваем адрес или домен для проверки. Ну и если он желает выйти, он может ввести х. После получаем ip-адрес, так как пользователь может ввести имя домена. В случае ошибки получения адреса завершаем работу скрипта. После того, как адрес получен, запускаем проверку, не является ли полученный адрес за Cloudflare. И если да, то предлагаем пользователю альтернативу, проверять или не проверять. В случае проверки запускаем функцию. Если нет, просто возвращаемся в пользовательское меню. Ну и если адреса за Cloudflare не обнаружено, просто запускаем функцию проверки.
Python:
def main():
print(Fore.CYAN + f'\n- Ваш внешний IP-адрес: {public_ip()}')
addr_input = input('- Введите IP-адрес или домен для проверки\n Для выхода введите "x"\n >>> ')
if addr_input.lower() == "x":
exit(0)
ip = ''
try:
ip = socket.gethostbyname(addr_input)
except socket.gaierror:
print(Fore.RED + '\n - Не удалось получить IP-адрес')
exit(0)
if cloudf_detect(ip):
print(Fore.RED + f'\n[!] ВНИМАНИЕ! Обнаружен адрес Cloudflare: {ip}')
dns_bl_check(ip)
Сказать по правде, не особо задумывался о том, что надо проверять адреса в черных списках. Да, о проверке прокси в черных списках слышал, и даже проверял. Но вот чтобы адрес компьютера… и, как оказалось зря. К примеру, мой адрес засветился уже более чем в 5-ти листах. И не во всех случаях виноват я )), адрес то динамически. Тем более, есть там и записи, что адрес был частью ботнета. А я то думаю, почему иногда тот же Cloudflare меня тормозит и заставляет проходить проверки. А одна из причин может быть в этом.
Что же, на этом, пожалуй, все. Ниже приведу пример работы скрипта на скриншоте. А также полный его код.
Python:
# pip install dnspython
# pip install requests
# pip install colorama
import re
import socket
from ipaddress import ip_network, ip_address
import dns
from colorama import Fore
from colorama import init
from dns import resolver
from requests import get, exceptions
init()
# проверка адреса в диапазоне cloudflare
def ip_in_range(ip, addr):
if ip_address(ip) in ip_network(addr):
return True
return False
# загрузка списка диапазонов адресов cloudflare
# запуск функции проверки ip-адреса
def cloudf_detect(ip):
list_addr = ["104.16.0.0/12"]
url = 'https://www.cloudflare.com/ips-v4'
req = get(url=url)
for adr in req.text.split("\n"):
list_addr.append(adr)
for addr in list_addr:
detect = ip_in_range(ip, addr)
if detect:
return True
return False
# получение внешнего ip-адреса компьютера
def public_ip():
try:
return get('https://api.ipify.org/').text
except exceptions.ConnectionError:
return '127.0.0.1'
# загрузка списка DNSBL, получение информации о наличии адреса в списках
def dns_bl_check(ip):
print(Fore.YELLOW + '\n- Проверка черных списков\n')
bad_dict = dict()
req = get('https://raw.githubusercontent.com/evgenycc/DNSBL-list/main/DNSBL')
read = req.text.splitlines()
for serv in read:
req = f"{'.'.join(reversed(ip.split('.')))}.{serv.strip()}"
try:
resolv = dns.resolver.Resolver()
resolv.timeout = 5
resolv.lifetime = 5
resp = resolv.resolve(req, 'A')
resp_txt = resolv.resolve(req, 'TXT')
print(Fore.RED + f'{serv.strip():30}: [BAD]')
pattern = '(?:https?:\/\/)?(?:[\w\.]+)\.(?:[a-z]{2,6}\.?)(?:\/[\w\.]*)*\/?'
find = re.findall(pattern, str(resp_txt[0]))
if len(find) == 0:
find = ['No address']
bad_dict.update({serv.strip(): f'{resp[0]} {find[0]}'})
except dns.resolver.NXDOMAIN:
print(Fore.GREEN + f'{serv.strip():30}: [OK]')
except (dns.resolver.LifetimeTimeout, dns.resolver.NoAnswer):
continue
if len(bad_dict) > 0:
len_str = len(f'IP-АДРЕС: "{ip.upper()}" ОБНАРУЖЕН В ЧЕРНЫХ СПИСКАХ')
print(Fore.BLUE + f'\nIP-АДРЕС: {ip.upper()} ОБНАРУЖЕН В ЧЕРНЫХ СПИСКАХ\n{"*"*len_str}')
for bad in bad_dict:
print(f' - {Fore.YELLOW + bad:30} : {Fore.RESET +bad_dict[bad]}')
else:
print(Fore.GREEN + '\n[+] IP-адрес в черных списках не обнаружен')
# получение пользовательского ввода
# запуск проверки на принадлежность адреса к cloudflare
# запуск проверки адреса в DNSBL
def main():
print(Fore.CYAN + f'\n- Ваш внешний IP-адрес: {public_ip()}')
addr_input = input('- Введите IP-адрес или домен для проверки\n Для выхода введите "x"\n >>> ')
if addr_input.lower() == "x":
exit(0)
ip = ''
try:
ip = socket.gethostbyname(addr_input)
except socket.gaierror:
print(Fore.RED + '\n - Не удалось получить IP-адрес')
exit(0)
if cloudf_detect(ip):
print(Fore.RED + f'\n[!] ВНИМАНИЕ! Обнаружен адрес Cloudflare: {ip}')
dns_bl_check(ip)
if __name__ == "__main__":
main()
Спасибо за внимание. Надеюсь, что эта информация будет вам полезна