Возникла однажды нужда в том, чтобы резервный DNS сервер знал о новых или удаленных зонах с основного сервера. Стандартными средствами BIND задачу не решить, поэтому пришлось нарисовать пару скриптов для ее решения. Первый скрипт парсит конфигурационный файл DNS сервера выуживая оттуда доменные имена, и пишет их в файл. Второй забирает этот файл по http (можно и по ftp), проверяет были ли добавлены/удалены домены, и если были изменения, то пишет новый конфигурационный файл и перезапускает BIND. Всвязи с написанием этого скрипта, я нарисовал третий скрипт (аналог второго), который создает отдельный конфигурационный файл для каждой зоны (так же учтите, что он не заставляет DNS сервер перечитывать конфиги). Далее приведен код скриптов и прилеплен архив с ними.
Первый скрипт:
#!/usr/bin/env perl
use strict;
use warnings;
my $nc_name = "/path/to/named.conf.txt"; # Путь к конфигу днс сервера
my $zl_name = "/path/to/test.txt"; # файл, который я буду забирать
my $write_conf = 0;
my @zones = ();
# Получаем список доменов
# парсим строки вида zone "zone.name"
open(FIN, '<', $nc_name) || die "error: $!\n";
while (<FIN>){
chomp; $_ = lc;
if (/zone[ ]+"(([a-z1-9\-]+?\.)+?[a-z1-9\-]+)"/){
push(@zones, $1);
}
}
close(FIN);
# Проверяем были ли добавлены/удалены зоны
if (open(FIN, '<', $zl_name)){
my @old_zones = ();
while (<FIN>){
chomp; $_ = lc;
next unless /([a-z1-9\-]+?\.)+?[a-z1-9\-]+/;
push(@old_zones, $_);
}
if ($#zones != $#old_zones){ $write_conf = 1; }
else {
foreach (@zones){
if (!($_ ~~ @old_zones)){
$write_conf = 1;
last;
}
}
}
close(FIN);
} else {
$write_conf = 1;
}
# Пишем в файл (кот. второй скрипт будет забирать) найденные зоны
if ($write_conf){
@zones = sort(@zones);
open(FOUT, '>', $zl_name) || die "error: $!\n";
foreach (@zones){ print(FOUT "$_\n"); }
close(FOUT);
}
exit(0);
Второй скрипт:
#!/usr/bin/env perl
use strict;
use warnings;
use File::Fetch;
# рабочая директория
my $work_dir = '/tmp';
# путь, где хранятся файлы зон
my $szc_dir = '/etc/namedb/slave';
# URL, откуда забирать список
my $uri_zf = 'http://www.example.org/test.txt';
# имя конфигурационного файла
my $config_file = 'dns.conf';
# IP адреса авторитативных DNS серверов
my $master_srv = 'ip; ip;';
# шаблон зоны
my $zone_template = 'zone "{zname}" { type slave; masters { {msrv} }; file "{fname}"; };';
# команда управления DNS сервером
my $rndc_bin = '/usr/sbin/rndc';
my $write_conf = 0;
my @zones = ();
my @deleted_zones = ();
# Качаем список доменов
my $ff = File::Fetch->new(uri => $uri_zf);
my $zl_file = $ff->fetch(to => $work_dir) || die 'error: ' . $ff->error;
open(FIN, '<', $zl_file) || die "error: can't open file $zl_file: $!\n";
while (<FIN>){
chomp; $_ = lc;
next unless /([a-z1-9\-]+?\.)+?[a-z1-9\-]+/;
push(@zones, $_);
}
close(FIN);
unlink($zl_file);
# Определяем - были ли добавлены/удалены домены
if (open(FIN, '<', $config_file)){
my @old_zones = ();
while (<FIN>){
chomp; $_ = lc;
if (/zone[ ]+"(([a-z1-9\-]+?\.)+?[a-z1-9\-]+)"/){
push(@old_zones, $1);
}
}
$write_conf = ($#zones != $#old_zones);
foreach (@old_zones){
if (!($_ ~~ @zones)){
$write_conf = 1;
push(@deleted_zones, "$szc_dir/$_.db");
}
}
close(FIN);
} else {
$write_conf = 1;
}
# Если были добавлены/удалены домены, то пишем
# конфигурационный файл, заставляем сервер перечитать
# конфиги и удаляем не используемые файлы зон
if ($write_conf){
my $buf = '';
my $rndc_args = "$rndc_bin reload > /dev/null 2>&1";
open(FOUT, '>', $config_file) || die "error: can't open file $config_file: $!\n";
foreach (@zones){
$buf = $zone_template;
$buf =~ s/{zname}/$_/g;
$buf =~ s/{msrv}/$master_srv/g;
$buf =~ s/{fname}/$szc_dir\/$_.db/g;
print(FOUT "$buf\n");
}
close(FOUT);
unlink(@deleted_zones) if ($#deleted_zones >= 0);
system($rndc_args) == 0 || die("command - $rndc_args failed: $?\n");
}
exit(0);
Третий скрипт (полезен, если вам нужен отдельный конфигурационный файл для каждой зоны):
#!/usr/bin/env perl
use strict;
use warnings;
use File::Fetch;
# рабочая директория
my $work_dir = '/root/bind/tmp';
# путь, где хранятся файлы зон
my $szc_dir = '/etc/namedb/slave';
# путь, куда будет писаться конфиг для зоны
my $bind_incdir = '/etc/namedb/includes';
# URL, откуда забирать список
my $uri_zf = 'http://www.example.org/named.txt';
# IP адреса авторитативных DNS серверов
my $master_srv = 'ip;';
# шаблон зоны
my $zone_template = 'zone "{zname}" {
type slave;
masters { {msrv} };
file "{fname}";
};';
my $write_conf = 0;
my @zones = ();
my @deleted_zones = ();
# Качаем список доменов
my $ff = File::Fetch->new(uri => $uri_zf);
my $zl_file = $ff->fetch(to => $work_dir) || die 'error: ' . $ff->error;
open(FIN, '<', $zl_file) || die "error: can't open file $zl_file: $!\n";
while (<FIN>){
chomp; $_ = lc;
next unless /([a-z1-9\-]+?\.)+?[a-z1-9\-]+/;
push(@zones, $_);
}
close(FIN);
unlink($zl_file);
# Определяем - были ли добавлены/удалены домены
if (open(FIN, '<', "$work_dir/dns_sync.txt")){
my @old_zones = ();
while (<FIN>){ chomp; push(@old_zones, $_); }
close(FIN);
$write_conf = ($#zones != $#old_zones);
foreach (@old_zones){
if (!($_ ~~ @zones)){
$write_conf = 1;
push(@deleted_zones, "$bind_incdir/$_.conf");
push(@deleted_zones, "$szc_dir/$_.db");
}
}
} else {
$write_conf = 1;
}
# Если были добавлены/удалены домены, то пишем
# конфигурационные файлы, удаляем не используемые
# файлы зон и конфиги к ним
if ($write_conf){
my $buf = '';
my @error_zones = ();
open(FOUT_TMP, '>', "$work_dir/dns_sync.txt") || die "error: can't open file $work_dir/dns_sync.txt: $!\n";
foreach (@zones){
if (open(FOUT, '>', "$bind_incdir/$_.conf")){
$buf = $zone_template;
$buf =~ s/{zname}/$_/g;
$buf =~ s/{msrv}/$master_srv/g;
$buf =~ s/{fname}/$szc_dir\/$_.db/g;
print(FOUT "$buf\n");
close(FOUT);
print(FOUT_TMP "$_\n");
} else {
push(@error_zones, "Can't open file $_.conf: $!\n");
}
}
close(FOUT_TMP);
unlink(@deleted_zones) if ($#deleted_zones >= 0);
print(@error_zones) if ($#error_zones >= 0);
}
exit(0);
Последние комментарии
Может кто…