Автоматическая синхронизация зон между DNS серверами

Возникла однажды нужда в том, чтобы резервный DNS сервер знал о новых или удаленных зонах с основного сервера. Стандартными средствами BIND задачу не решить, поэтому пришлось нарисовать пару скриптов для ее решения. Первый скрипт парсит конфигурационный файл DNS сервера выуживая оттуда доменные имена, и пишет их в файл. Второй забирает этот файл по http (можно и по ftp), проверяет были ли добавлены/удалены домены, и если были изменения, то пишет новый конфигурационный файл и перезапускает BIND. Всвязи с написанием этого скрипта, я нарисовал третий скрипт (аналог второго), который создает отдельный конфигурационный файл для каждой зоны (так же учтите, что он не заставляет DNS сервер перечитывать конфиги). Далее приведен код скриптов и прилеплен архив с ними. Первый скрипт:
  1. #!/usr/bin/env perl
  2.  
  3. use strict;
  4. use warnings;
  5.  
  6. my $nc_name = "/path/to/named.conf.txt";    # Путь к конфигу днс сервера
  7. my $zl_name = "/path/to/test.txt";          # файл, который я буду забирать
  8. my $write_conf = 0;
  9. my @zones = ();
  10.  
  11. # Получаем список доменов
  12. # парсим строки вида zone "zone.name"
  13. open(FIN, '<', $nc_name) || die "error: $!\n";
  14. while (<FIN>){
  15. 	chomp; $_ = lc;
  16. 	if (/zone[ ]+"(([a-z1-9\-]+?\.)+?[a-z1-9\-]+)"/){
  17. 		push(@zones, $1);
  18. 	}
  19. }
  20. close(FIN);
  21.  
  22. # Проверяем были ли добавлены/удалены зоны
  23. if (open(FIN, '<', $zl_name)){
  24. 	my @old_zones = ();
  25.  
  26. 	while (<FIN>){
  27. 		chomp; $_ = lc;
  28. 		next unless /([a-z1-9\-]+?\.)+?[a-z1-9\-]+/;
  29. 		push(@old_zones, $_);
  30. 	}
  31.  
  32. 	if ($#zones != $#old_zones){ $write_conf = 1; }
  33. 	else {
  34. 		foreach (@zones){
  35. 			if (!($_ ~~ @old_zones)){
  36. 				$write_conf = 1;
  37. 				last;
  38. 			}
  39. 		}
  40. 	}
  41.  
  42. 	close(FIN);
  43. } else {
  44. 	$write_conf = 1;
  45. }
  46.  
  47. # Пишем в файл (кот. второй скрипт будет забирать) найденные зоны
  48. if ($write_conf){
  49. 	@zones = sort(@zones);
  50. 	open(FOUT, '>', $zl_name) || die "error: $!\n";
  51. 	foreach (@zones){ print(FOUT "$_\n"); }
  52. 	close(FOUT);
  53. }
  54.  
  55. exit(0);
Второй скрипт:
  1. #!/usr/bin/env perl
  2.  
  3. use strict;
  4. use warnings;
  5. use File::Fetch;
  6.  
  7. # рабочая директория
  8. my $work_dir = '/tmp';
  9. # путь, где хранятся файлы зон
  10. my $szc_dir = '/etc/namedb/slave';
  11. # URL, откуда забирать список
  12. my $uri_zf = 'http://www.example.org/test.txt';
  13.  
  14. # имя конфигурационного файла
  15. my $config_file = 'dns.conf';
  16. # IP адреса авторитативных DNS серверов
  17. my $master_srv = 'ip; ip;';
  18. # шаблон зоны
  19. my $zone_template = 'zone "{zname}" { type slave; masters { {msrv} }; file "{fname}"; };';
  20. # команда управления DNS сервером
  21. my $rndc_bin = '/usr/sbin/rndc';
  22.  
  23. my $write_conf = 0;
  24. my @zones = ();
  25. my @deleted_zones = ();
  26.  
  27. # Качаем список доменов
  28. my $ff = File::Fetch->new(uri => $uri_zf);
  29. my $zl_file = $ff->fetch(to => $work_dir) || die 'error: ' . $ff->error;
  30.  
  31. open(FIN, '<', $zl_file) || die "error: can't open file $zl_file: $!\n";
  32. while (<FIN>){
  33. 	chomp; $_ = lc;
  34. 	next unless /([a-z1-9\-]+?\.)+?[a-z1-9\-]+/;
  35. 	push(@zones, $_);
  36. }
  37. close(FIN);
  38.  
  39. unlink($zl_file);
  40.  
  41. # Определяем - были ли добавлены/удалены домены
  42. if (open(FIN, '<', $config_file)){
  43. 	my @old_zones = ();
  44.  
  45. 	while (<FIN>){
  46. 		chomp; $_ = lc;
  47. 		if (/zone[ ]+"(([a-z1-9\-]+?\.)+?[a-z1-9\-]+)"/){
  48. 			push(@old_zones, $1);
  49. 		}
  50. 	}
  51.  
  52. 	$write_conf = ($#zones != $#old_zones);
  53. 	foreach (@old_zones){
  54. 		if (!($_ ~~ @zones)){
  55. 				$write_conf = 1;
  56. 				push(@deleted_zones, "$szc_dir/$_.db");
  57. 		}
  58. 	}
  59.  
  60. 	close(FIN);
  61. } else {
  62. 	$write_conf = 1;
  63. }
  64.  
  65. # Если были добавлены/удалены домены, то пишем
  66. # конфигурационный файл, заставляем сервер перечитать
  67. # конфиги и удаляем не используемые файлы зон
  68. if ($write_conf){
  69. 	my $buf = '';
  70. 	my $rndc_args = "$rndc_bin reload > /dev/null 2>&1";
  71.  
  72. 	open(FOUT, '>', $config_file) || die "error: can't open file $config_file: $!\n";
  73. 	foreach (@zones){
  74. 		$buf = $zone_template;
  75. 		$buf =~ s/{zname}/$_/g;
  76. 		$buf =~ s/{msrv}/$master_srv/g;
  77. 		$buf =~ s/{fname}/$szc_dir\/$_.db/g;
  78. 		print(FOUT "$buf\n");
  79. 	}
  80. 	close(FOUT);
  81.  
  82. 	unlink(@deleted_zones) if ($#deleted_zones >= 0);
  83. 	system($rndc_args) == 0 || die("command - $rndc_args failed: $?\n");
  84. }
  85.  
  86. exit(0);
Третий скрипт (полезен, если вам нужен отдельный конфигурационный файл для каждой зоны):
  1. #!/usr/bin/env perl
  2.  
  3. use strict;
  4. use warnings;
  5. use File::Fetch;
  6.  
  7. # рабочая директория
  8. my $work_dir = '/root/bind/tmp';
  9. # путь, где хранятся файлы зон
  10. my $szc_dir = '/etc/namedb/slave';
  11. # путь, куда будет писаться конфиг для зоны
  12. my $bind_incdir = '/etc/namedb/includes';
  13. # URL, откуда забирать список
  14. my $uri_zf = 'http://www.example.org/named.txt';
  15.  
  16. # IP адреса авторитативных DNS серверов
  17. my $master_srv = 'ip;';
  18. # шаблон зоны
  19. my $zone_template = 'zone "{zname}" {
  20. 	type slave;
  21. 	masters { {msrv} };
  22. 	file "{fname}";
  23. };';
  24.  
  25.  
  26. my $write_conf = 0;
  27. my @zones = ();
  28. my @deleted_zones = ();
  29.  
  30. # Качаем список доменов
  31. my $ff = File::Fetch->new(uri => $uri_zf);
  32. my $zl_file = $ff->fetch(to => $work_dir) || die 'error: ' . $ff->error;
  33.  
  34. open(FIN, '<', $zl_file) || die "error: can't open file $zl_file: $!\n";
  35. while (<FIN>){
  36. 	chomp; $_ = lc;
  37. 	next unless /([a-z1-9\-]+?\.)+?[a-z1-9\-]+/;
  38. 	push(@zones, $_);
  39. }
  40. close(FIN);
  41.  
  42. unlink($zl_file);
  43.  
  44. # Определяем - были ли добавлены/удалены домены
  45. if (open(FIN, '<', "$work_dir/dns_sync.txt")){
  46. 	my @old_zones = ();
  47.  
  48. 	while (<FIN>){ chomp; push(@old_zones, $_); }
  49. 	close(FIN);
  50.  
  51. 	$write_conf = ($#zones != $#old_zones);
  52. 	foreach (@old_zones){
  53. 		if (!($_ ~~ @zones)){
  54. 				$write_conf = 1;
  55. 				push(@deleted_zones, "$bind_incdir/$_.conf");
  56. 				push(@deleted_zones, "$szc_dir/$_.db");
  57. 		}
  58. 	}
  59. } else {
  60. 	$write_conf = 1;
  61. }
  62.  
  63. # Если были добавлены/удалены домены, то пишем
  64. # конфигурационные файлы, удаляем не используемые
  65. # файлы зон и конфиги к ним
  66. if ($write_conf){
  67. 	my $buf = '';
  68. 	my @error_zones = ();
  69.  
  70. 	open(FOUT_TMP, '>', "$work_dir/dns_sync.txt") || die "error: can't open file $work_dir/dns_sync.txt: $!\n";
  71. 	foreach (@zones){
  72. 		if (open(FOUT, '>', "$bind_incdir/$_.conf")){
  73. 			$buf = $zone_template;
  74. 			$buf =~ s/{zname}/$_/g;
  75. 			$buf =~ s/{msrv}/$master_srv/g;
  76. 			$buf =~ s/{fname}/$szc_dir\/$_.db/g;
  77. 			print(FOUT "$buf\n");
  78. 			close(FOUT);
  79.  
  80. 			print(FOUT_TMP "$_\n");
  81. 		} else {
  82. 			push(@error_zones, "Can't open file $_.conf: $!\n");
  83. 		}
  84. 	}
  85. 	close(FOUT_TMP);
  86.  
  87. 	unlink(@deleted_zones) if ($#deleted_zones >= 0);
  88. 	print(@error_zones) if ($#error_zones >= 0);
  89. }
  90.  
  91. exit(0);
ВложениеРазмер
Двоичные данные dns_autosync.tar.bz21.99 КБ