Самодельный DNS-blacklist с использованием PERL и BIND

Немного теории


DNSBL (DNS Block List) или RBL (Real-time Block List) используется для централизованного хранения записей о блокировке IP-адресов, например, в случае, если с адреса активно рассылается спам. Почтовый сервер, на который приходит письмо, берёт IP-адрес отправителя, и запрашивает для этого адреса запись в DNS-зоне. Запись для хоста должна быть как в зоне обратного просмотра reverse DNS,- октеты ip-адреса располагаются задом наперёд. Рассмотрим пример:
Пусть dnsbl-зона имеет имя rbl.sended2.me.
Для добавления адреса 1.2.3.4 в эту зону необходимо создать запись типа A с именем 4.3.2.1.rbl.sended2.me. и адресом 127.0.0.1. Вообще говоря, адрес может быть любой,- если DNS-сервер даёт ответ (т.е. запись найдена),- принимается решение о блокировке приёма почты (или начислении штрафных очков, если используется сервис комплексной защиты от спама, такой как SpamAssasine). Если dns-сервер ответит, что запись не найдена,- значит хост-отправитель не такой уж и плохой ;-)

Собственный RBL


Для создания собственной зоны понадобится DNS-сервер (в этой статье используется BIND, список адресов, которые надо заблокировать и немного знания скриптового языка, например PERL. В качестве примера будем использовать тот-же домен rbl.sended2.me и вымышленные адреса dns-серверов ns1 и ns2. Пусть список ip-адресов для блокировки уже загружен в массив @hosts:

# Определяем переменные, которые будут использоваться для создания зоны
#
# rbl_admin - адрес электронной почты администратора зоны,
# может использоваться для запросов на разблокировку.
# В формате DNS,- вместо @ используем . (точку)
$rbl_admin = "admin.rbl.sended.me"
# tempfile - путь к файлу, в который будем записывать зону DNS
$tempfile='/tmp/rbl.sended2.me.zone';
# ttl - время жизни для записей в секундах (Time To Live)
$ttl = 3600;
# serial - серийный номер зоны.
# Чаще всего рекомендуют задавать датой в формате YYYYMMDDHH,
# где YYYY- 4цифры года, MM - 2 цифры месяца,
# DD,- 2 цифры дня и HH,- 2 цифры дня
# или порядковый номер изменения в течении дня.
$serial = strftime("%Y%m%d%H",localtime());
# date - дата создания зоны
$date = strftime("%Y-%m-%d",localtime());

# создаём файл и записываем заголовок
open(VOTELIST,"> $tempfile");
print VOTELIST <\$ORIGIN $zone_name.
@ $ttl IN SOA ns1.sended2.me. $rbl_admin. (
$serial 10800 1800 604800 $ttl )
$ttl IN NS ns1.sended2.me.
$ttl IN NS ns2.sended2.me.
$ttl IN TXT "Ask $rbl_admin with subj: RBL_REMOVE: '"
$ttl IN TXT "RBL-Date: $date"
HERE
# запускаем цикл по адресам.
# Предполагается, что адреса в списке уже отсортированы:
my $last_origin="no last origin";
foreach my $ip (@hosts){
my @octets=reverse split(/\./,$result->{inet});
# создаём новый $origin
my $origin="$octets[1].$octets[2].$octets[3].$zone_name.";
print VOTELIST "\$ORIGIN $origin\n" if ($origin ne $last_origin);
print VOTELIST "$octets[0]\t$ttl\tIN\tA\t127.0.0.2\n";
$last_origin=$origin;
};
close(VOTELIST);


На выходе скрипта получим готовый файл зоны DNS, который останется только скормить BIND'у

P.S. ключевые слова: иштв зукд ;-)