Возникла необходимость автоматически заводить обратные зоны на
DNS сервере получаемые из резервных копий конфигов Juniper и Cisco. Для сбора конфигов в данном случае используем rancid. Предупреждая вопросы по поводу не эффективного написания скрипта. Он написан так, а не иначе, по причине чтобы уменьшить количество обновляемых одновременно записей на ДНС сервере. Длительность обновления нескольких сотен хостов суммарно не превышает 10 минут.
#!/usr/bin/perl
#
# Timur Nigamov 2014
#timur.nigamov@gmail.ru
#
use strict;
use warnings;
use File::Temp qw/tempfile/;
use subs qw/msg/;
##############################################
##############################################
##############################################
#
#CONFIGURATION SCRIPT
#
my $domain="in-addr.arpa";
my $rr_domain="jun.domain-internet.net";
my $router_db="/export/home/rancid/var/juniper/router.db";
my $conf_path="/export/home/rancid/var/juniper/configs/";
my $history_file="/var/db/ip2rr_jun.hst";
my $log_file = "/var/log/ip2rr-jun.log";
my $nsupdate="/usr/local/bin/nsupdate ";
#my $nsupdate="/usr/local/bin/nsupdate -d ";
#my $nsupdate="/bin/cat";
my $nsupdate_log="/var/log/nsupdate_jun.log";
my $rndc_key_file="/usr/local/etc/mit.key";
my $rndc_key_name = "mit-key";
my $ttl=86400;
my $send_update_to="dns0.domain.com";
my $verbose="4";
my $log_open="0";
##############################################
#input $filename - config file name
#return @reverse - array with names interface and ip
#
sub conf2data
{
my $data="";
my @iface_unit="";
my $ifunit="";my $hostname="";my $undef="";
my $ifcount="0";
my @ifaces ="";
my $filename="";
$filename=shift;
open (DATA, "<", $filename);
my @conf= <DATA>;
close (DATA);
my $i=0;
my $ifc="0";
my $ifstart="";
foreach (@conf)
{
if ( m/host-name/)
{
(undef,$hostname)=split (' ', $_);
($hostname,undef)=split (';',$hostname);
}
if ( m/^interfaces /)
{
$ifstart=$i;
$i++;
while ($i < $#conf)
{
$data=$conf[$i];
if ($data=~ m/^}/){ $ifc=1;last;}
$data=~ s/{//;
$data=~ s/^\s+//;
$data=~ s/;//g;
if ($data =~ m/^description.*|.*inactive.*|.*unnumbered-address.*/)
{next;}
if ( $data=~ m/xe-|irb |ge-|fxp|et|lo0|^ae/ )
{
#print "ifunit=$data\n";
$data=~ s/;//g;
$ifunit = $data;
push (@ifaces,$ifunit);
++$ifcount;
++$i;
}
++$i;
}
}
if ($ifc > 0){last;};
++$i;
}
$data="";
$ifc=$i;
for (my $j=$ifstart; $j<=$ifc;$j++)
{
$data=$conf[$j];
$data=~ s/^\s+//;
$data=~ s/{//;
$data=~ s/\;//g;
if ($data=~m/^unit|address|^xe-\d+|^irb |^ge-|^et|^fxp|^lo0|^ae/)
{
# print "****IF=$data\n";
$data=~ s/^\s+//;
$data=~ s/\s+$//;
$data=~ s/\;//g;
push (@iface_unit,$data);
}
}
push(@iface_unit,"end");
#print "*****Interface unit**************\n@iface_unit\n*******end***********\n";
$i="";
my $ii="0";
my $host="";
my $if="";
my $unit_id="";
my $addr="";
my $got_unit="0";
my @reverse="";
my $j="0";
my $end_if="";
foreach $if (@ifaces)
{
$i=0;
$host="";
chomp($if);
$if=~ s/\s+//;
if ($if ne "")
{
#print "**IF none zero -> $if\n";
# foreach $data (@iface_unit)
for ($j=$ii; $j <=$#iface_unit;$j++)
{
$data=$iface_unit[$j];
if ($data eq "") {next;}
# print "****Data -> $data\n";
if ($data=~ m/end/)
{
last;}
if ($data=~ m/xe|irb|et|ge-|fxp|lo0|^ae/)
{
if ($i == "1") {$ii=$j; last;}
if ($data=~m/$if/)
{
$i="1";
# print "**Found IF -> $if -> Data $data\n ";
next;
}
}
if ($data=~m/unit/)
{
#$i=0;
# print "**Found unit -> $if -> Data $data\n ";
(undef,$unit_id)=split(" ",$data);
next;
}
if($data=~m/address/)
{
#$i=0;
# print "**Found address -> $if -> Data $data\n ";
(undef,$addr)=split(" ",$data); ($addr,undef)=split("/",$addr);
next if is_private_ip($addr);#skip private ip address
if ($unit_id eq ""){ $host=$hostname." ".$if." ".$addr."\n";}
else {$host=$hostname." ".$if.".".$unit_id." ".$addr."\n";}
# print "++++$host\n";
push (@reverse,$host);
}
}
}
#++$j;
}
#print "@reverse\n";
return @reverse;
}
####################################################################################
sub ip2dns {
my ($ip, $int, $rtr, $city) = @_;
my @ip_full=();
my $domain="in-addr.arpa";
if ($ip=~/:/) {
# Count additional zero bytes we should insert to ipv6 address
my @ip6array = (split /:/, $ip);
my $add = 8 - $#ip6array;
$domain="ip6.arpa";
# Add leading zeros to partially filled sections
for (my $i=0; $i<=$#ip6array; $i++){
$ip6array[$i] =~ s/^(\S)$/000$1/;
$ip6array[$i] =~ s/^(\S\S)$/00$1/;
$ip6array[$i] =~ s/^(\S\S\S)$/0$1/;
# Build new array containing ipv6 full address
push (@ip_full, split (//, $ip6array[$i]));
# Find :: and insert there proper number of zeros
if (not $ip6array[$i]){
for (my $q=1; $q<=$add; $q++) {
push (@ip_full, 0, 0, 0, 0);
}
}
}
}
else { @ip_full=split /\./, $ip };
# Reverse array containing ipv6 full address and put it to scalar
my $todns = join('.', reverse @ip_full) . ".$domain";
# Print result
return "$todns.\t$rtr-$int.$city.stream-internet.net.";
}
###################################################################################
sub is_private_ip($) {
$_=shift;
my $private=0;
$private=1 if (/^10\./
or /^172\.1[6-9]\./ or /^172\.2[0-9]\./ or /^172\.3[01]\./
or /^192\.168\./
);
return $private;
}
####################################################################################
sub rndc_secret($$) {
# usage: <secret> = rndc_secret(RNDC_KEY_FILE, RNDC_KEY_NAME)
#
my ($key_file, $key_name)=@_;
my $key_found = 0;
my $key_secret = '';
return 0 if not $key_file;
return 0 if not $key_name;
if (not -f $key_file) {
die "Rndc-key file '$key_file' not found.\n";
}
open FILE, '<', $key_file
or die "Can't open file '$key_file': $!\n";
while (<FILE>) {
if (not $key_found) {
next if not /\bkey\s+"([^"]+)"/;
$key_found=1 if "$key_name" eq "$1";
}
if ($key_found) {
$key_secret=$1 if /\bsecret\s+"([^"]+)"/;
}
last if $key_secret;
}
close FILE or die "Can't close file '$rndc_key_file': $!\n";
die "Error. Section key '$key_name' not found.\n" if not $key_found;
die "Error. Secret not found (key: '$key_name').\n" if not $key_secret;
return $key_secret;
}
####################################################################################
sub msg($@) {
my $level = shift;
return 0 if $level > $verbose;
my $now = localtime();
if ((not $log_open) and (-f $log_file)) {
# if (($log_open) and (-f $log_file)) {
open LOG, '>>', $log_file
or die "Can't open file '$log_file': $!\n";
$log_open = 1;
}
if ($log_open) {
# print in file
printf LOG "[%s] %s\n", $now, $_ foreach @_;
}
else {
# print in STDOUT
printf "[%s] %s\n", $now, $_ foreach @_;
}
}
###################################################################################
sub updatedns()
{
my $verbose="4";my $log_open="0";my @rtr_db="";my @addr="";my $city="";
my $router="";my $hostname="";my $ipaddr="";my $data="";my $int="";
my $ptr="";my @changes="";my $hist1="";my %history;
if (open (HISTORY,"<", $history_file))
{ while(<HISTORY>) { chomp; $history{$_} = 0; };
close HISTORY;
};
$data=$_[0]; print "Data--->$data\n"; if ($data eq"") {next;}
if ($data ne "")
{ ($router,$hostname,$int,$ipaddr)=split(" ",$data);
if ($router =~ s/(\S+)\.(\S+)$/$1/) { $city = $2; }
else {$city = "msk";}
if (($int=~ m/xe|irb|ge-|et|lo0|ae/) and (is_private_ip($ipaddr)!= 1))
{ $int=~s/\/+/-/g; $ptr=ip2dns($ipaddr,$int,$router,$city); # check in history
if (exists $history{$ptr}) { msg 5, "$ipaddr found in history file"; }
else { my ($arpa, $name)=split /\s+/, $ptr; msg 5, "update $arpa";
push @changes,"prereq yxrrset $arpa IN PTR\n",
"update delete $arpa IN PTR\n",
"send\n","update add $arpa $ttl IN PTR $name\n",
"send\n";
};
$history{$ptr}=1;
}
}
while (my ($rr, $flag)=each %history) {
if ($flag == 0) {my ($arpa, $name)=split /\s+/, $rr;
msg 5, "delete old record '$arpa' from dns server";
#push @changes, "update delete $arpa IN PTR $name\n\n";
delete $history{$rr};
}
}
msg 3, scalar(@changes)." changes made";
print "****Changes**************\n@changes***************\n";
if (@changes) {
msg 4, '# start ns-update procedure'; msg 5, "get dns-key '$rndc_key_name' from file '$rndc_key_file'";
my $rndc_key_secret=rndc_secret($rndc_key_file, $rndc_key_name);
my ($tmp, $tmpfile)=tempfile('ip2rr-jun.XXXXXX');
print $tmp "server $send_update_to\n" if $send_update_to;
print $tmp "key $rndc_key_name $rndc_key_secret\n" if $rndc_key_secret;
msg 5, 'dump @changes to tmpfile: ' . $tmpfile;
print $tmp $_ foreach (@changes);
close $tmp;
my $cmd = "$nsupdate $tmpfile";
$cmd .= " >> $nsupdate_log 2>&1" if -w $nsupdate_log;
msg 5, "system($cmd)";
system($cmd);
msg 5, "delete tmpfile: $tmpfile";
unlink($tmpfile);
msg 5, "save history to $history_file";
$hist1=$hist1.$_."\n" foreach (keys %history);
};
return ($hist1);
}
####################################################################################
#main
#
my @rtr_db="";my @addr="";my $city="";my $router="";
my $hostname="";my $ipaddr="";my $data="";my $int="";
my $ptr="";my @changes="";my @history=();my $rez="";
my @zone=""; @addr="";
open (RDB,$router_db) || die "Can't open routers db file";
while (<RDB>)
{ next if /^#/ or /:down/ or (not /cisco/ and not /juniper/);
chomp;
(my $r, undef,undef)=split(/:/);
push (@rtr_db,$r); }
close RDB;
foreach $router (@rtr_db)
{
if ($router ne "")
{
@zone=conf2data($conf_path.$router);
foreach $data (@zone){
$data = $router." ".$data;
$rez=&updatedns ($data); ;
push (@history,$rez);
}
}
}
open HISTORY, ">", $history_file or die "Can't write file '$history_file': $!";
print HISTORY "@history";
close HISTORY or die "Can't save file '$history_file': $!";
Аналогично скрипт для маршрутизаторов cisco
#!/usr/bin/perl
#
# Nigamov Timur 2013
#timur.nigamov@gmail.ru
#
use strict;
use warnings;
use File::Temp qw/tempfile/;
use subs qw/msg/;
##############################################
##############################################
##############################################
#
#CONFIGURATION SCRIPT
my $ranciddir = "/export/home/rancid/var";
my $domain="in-addr.arpa";
my $rr_domain="stream-internet.net";
my $history_file="/var/db/ip2rr_cisco.hst";
my $log_file = "/var/log/ip2rr-cisco.log";
my $nsupdate="/usr/local/bin/nsupdate ";
#my $nsupdate="/usr/local/bin/nsupdate -d ";
#my $nsupdate="/bin/cat";
my $nsupdate_log="/var/log/nsupdate_cisco.log";
my $rndc_key_file="/usr/local/etc/mtu.key";
my $rndc_key_name = "mit-key";
my $ttl=86400;
my $send_update_to="dns0.domain.com";
my $verbose="4";
my $log_open="0";
##############################################
#input $filename - config file name
#return @reverse - array with names interface and ip
#
sub conf2data
{
my @reverse;
my $section_open =0;my $ip="";
my $data=""; my @iface_unit="";
my $host ="";
my $int=""; my $hostname="";my $undef="";
my $ifcount="0"; my @ifaces ="";my $filename="";
$filename=shift;
open (DATA, "<", $filename);
my @conf= <DATA>;
close (DATA);
my $i=0;
my $ifc="0";
my $ifstart="";
foreach (@conf)
{
chomp;
if ( m/^hostname/)
{
(undef,$hostname)=split (' ', $_);
next;
}
if (!$section_open and /^interface\s+(\S+)\s*/i)
{# Make short names for interfaces
$_=lc($1); s/[\/\:\.]/\./g;
s/tengigabitethernet/te/ or s/HundredGigE/hu/ or s/hundredgige/hu/ or s/TenGigE/te/ or s/gigabitethernet/ge/ or s/GigabitEthernet/ge/ or s/tunnel/tun/
or s/fastethernet/fa/ or s/ethernet/e/ or s/serial/se/ or s/loopback/lo/ or s/port-channel/po/ or s/bundle-ether/be/ or s/Bundle-Ether/be/
or s/BE/be/ or s/vlan/vl/;
$int=$_; $section_open = 1; msg 5, "open section (\$int: $int). file $filename: $.";
}
elsif ($section_open and /\s+ipv6 address (2a02:\S+)/i) {
$ip=lc($1); $ip=~s/\/\d{1,3}//; # delete mask
$host=$hostname." ".$int." ".$ip."\n";
push (@reverse,$host);
# msg 4, "%-20s\t%-30s (%s)", "$ip", "$host", "file $filename: $.";
}
elsif ($section_open and /\s+ip address (\d+\.\d+\.\d+\.\d+)/) {
$ip=$1; next if is_private_ip($ip); # skip private ip address
$host=$hostname." ".$int." ".$ip."\n";
push (@reverse,$host);
# msg 4, "%-20s\t%-30s (%s)", "$ip", "$host", "file $filename: $.";
}
elsif ($section_open and /\s+ipv4 address (\d+\.\d+\.\d+\.\d+)/) {
$ip=$1; next if is_private_ip($ip); # skip private ip address
$host=$hostname." ".$int." ".$ip."\n";
push (@reverse,$host);
# msg 4, "%-20s\t%-30s (%s)", "$ip", "$host", "file $filename: $.";
}
elsif ($int and /^\S/) {
msg 5, "close section (\$int: $int). file $filename: $." if $int;
$section_open = 0; $int = '';
}
}
print "################Reverse#######################\n";
print "@reverse\n";
print "#############################################\n";
return @reverse;
}
####################################################################################
sub ip2dns {
my ($ip, $int, $rtr, $city) = @_;
my @ip_full=();
my $domain="in-addr.arpa";
if ($ip=~/:/) {
# Count additional zero bytes we should insert to ipv6 address
my @ip6array = (split /:/, $ip);
my $add = 8 - $#ip6array;
$domain="ip6.arpa";
# Add leading zeros to partially filled sections
for (my $i=0; $i<=$#ip6array; $i++){
$ip6array[$i] =~ s/^(\S)$/000$1/;
$ip6array[$i] =~ s/^(\S\S)$/00$1/;
$ip6array[$i] =~ s/^(\S\S\S)$/0$1/;
# Build new array containing ipv6 full address
push (@ip_full, split (//, $ip6array[$i]));
# Find :: and insert there proper number of zeros
if (not $ip6array[$i]){
for (my $q=1; $q<=$add; $q++) {
push (@ip_full, 0, 0, 0, 0);
}
}
}
}
else { @ip_full=split /\./, $ip };
# Reverse array containing ipv6 full address and put it to scalar
my $todns = join('.', reverse @ip_full) . ".$domain";
# Print result
return "$todns.\t$rtr-$int.$city.stream-internet.net.";
}
###################################################################################
sub is_private_ip($) {
$_=shift;
my $private=0;
$private=1 if (/^10\./
or /^172\.1[6-9]\./ or /^172\.2[0-9]\./ or /^172\.3[01]\./
or /^192\.168\./
);
return $private;
}
####################################################################################
sub rndc_secret($$) {
# usage: <secret> = rndc_secret(RNDC_KEY_FILE, RNDC_KEY_NAME)
#
my ($key_file, $key_name)=@_;
my $key_found = 0;
my $key_secret = '';
return 0 if not $key_file;
return 0 if not $key_name;
if (not -f $key_file) {
die "Rndc-key file '$key_file' not found.\n";
}
open FILE, '<', $key_file
or die "Can't open file '$key_file': $!\n";
while (<FILE>) {
if (not $key_found) {
next if not /\bkey\s+"([^"]+)"/;
$key_found=1 if "$key_name" eq "$1";
}
if ($key_found) {
$key_secret=$1 if /\bsecret\s+"([^"]+)"/;
}
last if $key_secret;
}
close FILE or die "Can't close file '$rndc_key_file': $!\n";
die "Error. Section key '$key_name' not found.\n" if not $key_found;
die "Error. Secret not found (key: '$key_name').\n" if not $key_secret;
return $key_secret;
}
####################################################################################
sub msg($@) {
my $level = shift;
return 0 if $level > $verbose;
my $now = localtime();
if ((not $log_open) and (-f $log_file)) {
# if (($log_open) and (-f $log_file)) {
open LOG, '>>', $log_file
or die "Can't open file '$log_file': $!\n";
$log_open = 1;
}
if ($log_open) {
# print in file
printf LOG "[%s] %s\n", $now, $_ foreach @_;
}
else {
# print in STDOUT
printf "[%s] %s\n", $now, $_ foreach @_;
}
}
###################################################################################
sub updatedns()
{
my $verbose="4";my $log_open="0";my @rtr_db="";my @addr="";my $city="";
my $router="";my $hostname="";my $ipaddr="";my $data="";my $int="";
my $ptr="";my @changes="";my $hist1="";my %history;
if (open (HISTORY,"<", $history_file))
{ while(<HISTORY>) { chomp; $history{$_} = 0; };
close HISTORY;
};
$data=$_[0]; print "Data--->$data\n"; if ($data eq"") {next;}
if ($data ne "")
{ ($router,$hostname,$int,$ipaddr)=split(" ",$data);
if ($router =~ s/(\S+)\.(\S+)$/$1/) { $city = $2; }
else {$city = "msk";}
if (is_private_ip($ipaddr)!= 1)
{ $int=~s/\/+/-/g; $ptr=ip2dns($ipaddr,$int,$router,$city); # check in history
if (exists $history{$ptr}) { msg 5, "$ipaddr found in history file"; }
else { my ($arpa, $name)=split /\s+/, $ptr; msg 5, "update $arpa";
push @changes,"prereq yxrrset $arpa IN PTR\n",
"update delete $arpa IN PTR\n",
"send\n","update add $arpa $ttl IN PTR $name\n",
"send\n";
};
$history{$ptr}=1;
}
}
while (my ($rr, $flag)=each %history) {
if ($flag == 0) {my ($arpa, $name)=split /\s+/, $rr;
msg 5, "delete old record '$arpa' from dns server";
#push @changes, "update delete $arpa IN PTR $name\n\n";
delete $history{$rr};
}
}
msg 3, scalar(@changes)." changes made";
print "****Changes**************\n@changes***************\n";
if (@changes) {
msg 4, '# start ns-update procedure'; msg 5, "get dns-key '$rndc_key_name' from file '$rndc_key_file'";
my $rndc_key_secret=rndc_secret($rndc_key_file, $rndc_key_name);
my ($tmp, $tmpfile)=tempfile('ip2rr-cisco.XXXXXX');
print $tmp "server $send_update_to\n" if $send_update_to;
print $tmp "key $rndc_key_name $rndc_key_secret\n" if $rndc_key_secret;
msg 5, 'dump @changes to tmpfile: ' . $tmpfile;
print $tmp $_ foreach (@changes);
close $tmp;
my $cmd = "$nsupdate $tmpfile";
$cmd .= " >> $nsupdate_log 2>&1" if -w $nsupdate_log;
msg 5, "system($cmd)";
system($cmd);
msg 5, "delete tmpfile: $tmpfile";
unlink($tmpfile);
msg 5, "save history to $history_file";
$hist1=$hist1.$_."\n" foreach (keys %history);
};
return ($hist1);
}
####################################################################################
#main
#
my $rtr_file="";my $r;
my @addr="";my $city="";my $router="";
my $hostname="";my $ipaddr="";my $data="";my $int="";
my $ptr="";my @changes="";my @history=();my $rez="";
my @zone=""; @addr="";my @routers = ();
foreach my $in_filename (glob("$ranciddir/*/router.db"))
{
open (RDB, $in_filename) or die "can't read $in_filename";
$in_filename =~ s/\/router\.db//;
while (<RDB>) {
next if /^#/ or /:down/ or not /cisco/;
chomp;($r, undef, undef) = split (/:/);
$rtr_file = "$in_filename/configs/$r";
push (@routers,$rtr_file);
}
close RDB;
}
#rint "@routers\n";
foreach $router (@routers)
{
if ($router ne "")
{
@zone=conf2data($router);
foreach $data (@zone){
$router=reverse ($router);
($r,undef)=split "/",$router;
$r=reverse ($r);
$router=reverse($router);
$data = $r." ".$data;
$rez=&updatedns ($data); ;
push (@history,$rez);
}
}
}
open HISTORY, ">", $history_file or die "Can't write file '$history_file': $!";
print HISTORY "@history";
close HISTORY or die "Can't save file '$history_file': $!";
#!/usr/bin/perl
#
# Timur Nigamov 2014
#timur.nigamov@gmail.ru
#
use strict;
use warnings;
use File::Temp qw/tempfile/;
use subs qw/msg/;
##############################################
##############################################
##############################################
#
#CONFIGURATION SCRIPT
#
my $domain="in-addr.arpa";
my $rr_domain="jun.domain-internet.net";
my $router_db="/export/home/rancid/var/juniper/router.db";
my $conf_path="/export/home/rancid/var/juniper/configs/";
my $history_file="/var/db/ip2rr_jun.hst";
my $log_file = "/var/log/ip2rr-jun.log";
my $nsupdate="/usr/local/bin/nsupdate ";
#my $nsupdate="/usr/local/bin/nsupdate -d ";
#my $nsupdate="/bin/cat";
my $nsupdate_log="/var/log/nsupdate_jun.log";
my $rndc_key_file="/usr/local/etc/mit.key";
my $rndc_key_name = "mit-key";
my $ttl=86400;
my $send_update_to="dns0.domain.com";
my $verbose="4";
my $log_open="0";
##############################################
#input $filename - config file name
#return @reverse - array with names interface and ip
#
sub conf2data
{
my $data="";
my @iface_unit="";
my $ifunit="";my $hostname="";my $undef="";
my $ifcount="0";
my @ifaces ="";
my $filename="";
$filename=shift;
open (DATA, "<", $filename);
my @conf= <DATA>;
close (DATA);
my $i=0;
my $ifc="0";
my $ifstart="";
foreach (@conf)
{
if ( m/host-name/)
{
(undef,$hostname)=split (' ', $_);
($hostname,undef)=split (';',$hostname);
}
if ( m/^interfaces /)
{
$ifstart=$i;
$i++;
while ($i < $#conf)
{
$data=$conf[$i];
if ($data=~ m/^}/){ $ifc=1;last;}
$data=~ s/{//;
$data=~ s/^\s+//;
$data=~ s/;//g;
if ($data =~ m/^description.*|.*inactive.*|.*unnumbered-address.*/)
{next;}
if ( $data=~ m/xe-|irb |ge-|fxp|et|lo0|^ae/ )
{
#print "ifunit=$data\n";
$data=~ s/;//g;
$ifunit = $data;
push (@ifaces,$ifunit);
++$ifcount;
++$i;
}
++$i;
}
}
if ($ifc > 0){last;};
++$i;
}
$data="";
$ifc=$i;
for (my $j=$ifstart; $j<=$ifc;$j++)
{
$data=$conf[$j];
$data=~ s/^\s+//;
$data=~ s/{//;
$data=~ s/\;//g;
if ($data=~m/^unit|address|^xe-\d+|^irb |^ge-|^et|^fxp|^lo0|^ae/)
{
# print "****IF=$data\n";
$data=~ s/^\s+//;
$data=~ s/\s+$//;
$data=~ s/\;//g;
push (@iface_unit,$data);
}
}
push(@iface_unit,"end");
#print "*****Interface unit**************\n@iface_unit\n*******end***********\n";
$i="";
my $ii="0";
my $host="";
my $if="";
my $unit_id="";
my $addr="";
my $got_unit="0";
my @reverse="";
my $j="0";
my $end_if="";
foreach $if (@ifaces)
{
$i=0;
$host="";
chomp($if);
$if=~ s/\s+//;
if ($if ne "")
{
#print "**IF none zero -> $if\n";
# foreach $data (@iface_unit)
for ($j=$ii; $j <=$#iface_unit;$j++)
{
$data=$iface_unit[$j];
if ($data eq "") {next;}
# print "****Data -> $data\n";
if ($data=~ m/end/)
{
last;}
if ($data=~ m/xe|irb|et|ge-|fxp|lo0|^ae/)
{
if ($i == "1") {$ii=$j; last;}
if ($data=~m/$if/)
{
$i="1";
# print "**Found IF -> $if -> Data $data\n ";
next;
}
}
if ($data=~m/unit/)
{
#$i=0;
# print "**Found unit -> $if -> Data $data\n ";
(undef,$unit_id)=split(" ",$data);
next;
}
if($data=~m/address/)
{
#$i=0;
# print "**Found address -> $if -> Data $data\n ";
(undef,$addr)=split(" ",$data); ($addr,undef)=split("/",$addr);
next if is_private_ip($addr);#skip private ip address
if ($unit_id eq ""){ $host=$hostname." ".$if." ".$addr."\n";}
else {$host=$hostname." ".$if.".".$unit_id." ".$addr."\n";}
# print "++++$host\n";
push (@reverse,$host);
}
}
}
#++$j;
}
#print "@reverse\n";
return @reverse;
}
####################################################################################
sub ip2dns {
my ($ip, $int, $rtr, $city) = @_;
my @ip_full=();
my $domain="in-addr.arpa";
if ($ip=~/:/) {
# Count additional zero bytes we should insert to ipv6 address
my @ip6array = (split /:/, $ip);
my $add = 8 - $#ip6array;
$domain="ip6.arpa";
# Add leading zeros to partially filled sections
for (my $i=0; $i<=$#ip6array; $i++){
$ip6array[$i] =~ s/^(\S)$/000$1/;
$ip6array[$i] =~ s/^(\S\S)$/00$1/;
$ip6array[$i] =~ s/^(\S\S\S)$/0$1/;
# Build new array containing ipv6 full address
push (@ip_full, split (//, $ip6array[$i]));
# Find :: and insert there proper number of zeros
if (not $ip6array[$i]){
for (my $q=1; $q<=$add; $q++) {
push (@ip_full, 0, 0, 0, 0);
}
}
}
}
else { @ip_full=split /\./, $ip };
# Reverse array containing ipv6 full address and put it to scalar
my $todns = join('.', reverse @ip_full) . ".$domain";
# Print result
return "$todns.\t$rtr-$int.$city.stream-internet.net.";
}
###################################################################################
sub is_private_ip($) {
$_=shift;
my $private=0;
$private=1 if (/^10\./
or /^172\.1[6-9]\./ or /^172\.2[0-9]\./ or /^172\.3[01]\./
or /^192\.168\./
);
return $private;
}
####################################################################################
sub rndc_secret($$) {
# usage: <secret> = rndc_secret(RNDC_KEY_FILE, RNDC_KEY_NAME)
#
my ($key_file, $key_name)=@_;
my $key_found = 0;
my $key_secret = '';
return 0 if not $key_file;
return 0 if not $key_name;
if (not -f $key_file) {
die "Rndc-key file '$key_file' not found.\n";
}
open FILE, '<', $key_file
or die "Can't open file '$key_file': $!\n";
while (<FILE>) {
if (not $key_found) {
next if not /\bkey\s+"([^"]+)"/;
$key_found=1 if "$key_name" eq "$1";
}
if ($key_found) {
$key_secret=$1 if /\bsecret\s+"([^"]+)"/;
}
last if $key_secret;
}
close FILE or die "Can't close file '$rndc_key_file': $!\n";
die "Error. Section key '$key_name' not found.\n" if not $key_found;
die "Error. Secret not found (key: '$key_name').\n" if not $key_secret;
return $key_secret;
}
####################################################################################
sub msg($@) {
my $level = shift;
return 0 if $level > $verbose;
my $now = localtime();
if ((not $log_open) and (-f $log_file)) {
# if (($log_open) and (-f $log_file)) {
open LOG, '>>', $log_file
or die "Can't open file '$log_file': $!\n";
$log_open = 1;
}
if ($log_open) {
# print in file
printf LOG "[%s] %s\n", $now, $_ foreach @_;
}
else {
# print in STDOUT
printf "[%s] %s\n", $now, $_ foreach @_;
}
}
###################################################################################
sub updatedns()
{
my $verbose="4";my $log_open="0";my @rtr_db="";my @addr="";my $city="";
my $router="";my $hostname="";my $ipaddr="";my $data="";my $int="";
my $ptr="";my @changes="";my $hist1="";my %history;
if (open (HISTORY,"<", $history_file))
{ while(<HISTORY>) { chomp; $history{$_} = 0; };
close HISTORY;
};
$data=$_[0]; print "Data--->$data\n"; if ($data eq"") {next;}
if ($data ne "")
{ ($router,$hostname,$int,$ipaddr)=split(" ",$data);
if ($router =~ s/(\S+)\.(\S+)$/$1/) { $city = $2; }
else {$city = "msk";}
if (($int=~ m/xe|irb|ge-|et|lo0|ae/) and (is_private_ip($ipaddr)!= 1))
{ $int=~s/\/+/-/g; $ptr=ip2dns($ipaddr,$int,$router,$city); # check in history
if (exists $history{$ptr}) { msg 5, "$ipaddr found in history file"; }
else { my ($arpa, $name)=split /\s+/, $ptr; msg 5, "update $arpa";
push @changes,"prereq yxrrset $arpa IN PTR\n",
"update delete $arpa IN PTR\n",
"send\n","update add $arpa $ttl IN PTR $name\n",
"send\n";
};
$history{$ptr}=1;
}
}
while (my ($rr, $flag)=each %history) {
if ($flag == 0) {my ($arpa, $name)=split /\s+/, $rr;
msg 5, "delete old record '$arpa' from dns server";
#push @changes, "update delete $arpa IN PTR $name\n\n";
delete $history{$rr};
}
}
msg 3, scalar(@changes)." changes made";
print "****Changes**************\n@changes***************\n";
if (@changes) {
msg 4, '# start ns-update procedure'; msg 5, "get dns-key '$rndc_key_name' from file '$rndc_key_file'";
my $rndc_key_secret=rndc_secret($rndc_key_file, $rndc_key_name);
my ($tmp, $tmpfile)=tempfile('ip2rr-jun.XXXXXX');
print $tmp "server $send_update_to\n" if $send_update_to;
print $tmp "key $rndc_key_name $rndc_key_secret\n" if $rndc_key_secret;
msg 5, 'dump @changes to tmpfile: ' . $tmpfile;
print $tmp $_ foreach (@changes);
close $tmp;
my $cmd = "$nsupdate $tmpfile";
$cmd .= " >> $nsupdate_log 2>&1" if -w $nsupdate_log;
msg 5, "system($cmd)";
system($cmd);
msg 5, "delete tmpfile: $tmpfile";
unlink($tmpfile);
msg 5, "save history to $history_file";
$hist1=$hist1.$_."\n" foreach (keys %history);
};
return ($hist1);
}
####################################################################################
#main
#
my @rtr_db="";my @addr="";my $city="";my $router="";
my $hostname="";my $ipaddr="";my $data="";my $int="";
my $ptr="";my @changes="";my @history=();my $rez="";
my @zone=""; @addr="";
open (RDB,$router_db) || die "Can't open routers db file";
while (<RDB>)
{ next if /^#/ or /:down/ or (not /cisco/ and not /juniper/);
chomp;
(my $r, undef,undef)=split(/:/);
push (@rtr_db,$r); }
close RDB;
foreach $router (@rtr_db)
{
if ($router ne "")
{
@zone=conf2data($conf_path.$router);
foreach $data (@zone){
$data = $router." ".$data;
$rez=&updatedns ($data); ;
push (@history,$rez);
}
}
}
open HISTORY, ">", $history_file or die "Can't write file '$history_file': $!";
print HISTORY "@history";
close HISTORY or die "Can't save file '$history_file': $!";
Аналогично скрипт для маршрутизаторов cisco
#!/usr/bin/perl
#
# Nigamov Timur 2013
#timur.nigamov@gmail.ru
#
use strict;
use warnings;
use File::Temp qw/tempfile/;
use subs qw/msg/;
##############################################
##############################################
##############################################
#
#CONFIGURATION SCRIPT
my $ranciddir = "/export/home/rancid/var";
my $domain="in-addr.arpa";
my $rr_domain="stream-internet.net";
my $history_file="/var/db/ip2rr_cisco.hst";
my $log_file = "/var/log/ip2rr-cisco.log";
my $nsupdate="/usr/local/bin/nsupdate ";
#my $nsupdate="/usr/local/bin/nsupdate -d ";
#my $nsupdate="/bin/cat";
my $nsupdate_log="/var/log/nsupdate_cisco.log";
my $rndc_key_file="/usr/local/etc/mtu.key";
my $rndc_key_name = "mit-key";
my $ttl=86400;
my $send_update_to="dns0.domain.com";
my $verbose="4";
my $log_open="0";
##############################################
#input $filename - config file name
#return @reverse - array with names interface and ip
#
sub conf2data
{
my @reverse;
my $section_open =0;my $ip="";
my $data=""; my @iface_unit="";
my $host ="";
my $int=""; my $hostname="";my $undef="";
my $ifcount="0"; my @ifaces ="";my $filename="";
$filename=shift;
open (DATA, "<", $filename);
my @conf= <DATA>;
close (DATA);
my $i=0;
my $ifc="0";
my $ifstart="";
foreach (@conf)
{
chomp;
if ( m/^hostname/)
{
(undef,$hostname)=split (' ', $_);
next;
}
if (!$section_open and /^interface\s+(\S+)\s*/i)
{# Make short names for interfaces
$_=lc($1); s/[\/\:\.]/\./g;
s/tengigabitethernet/te/ or s/HundredGigE/hu/ or s/hundredgige/hu/ or s/TenGigE/te/ or s/gigabitethernet/ge/ or s/GigabitEthernet/ge/ or s/tunnel/tun/
or s/fastethernet/fa/ or s/ethernet/e/ or s/serial/se/ or s/loopback/lo/ or s/port-channel/po/ or s/bundle-ether/be/ or s/Bundle-Ether/be/
or s/BE/be/ or s/vlan/vl/;
$int=$_; $section_open = 1; msg 5, "open section (\$int: $int). file $filename: $.";
}
elsif ($section_open and /\s+ipv6 address (2a02:\S+)/i) {
$ip=lc($1); $ip=~s/\/\d{1,3}//; # delete mask
$host=$hostname." ".$int." ".$ip."\n";
push (@reverse,$host);
# msg 4, "%-20s\t%-30s (%s)", "$ip", "$host", "file $filename: $.";
}
elsif ($section_open and /\s+ip address (\d+\.\d+\.\d+\.\d+)/) {
$ip=$1; next if is_private_ip($ip); # skip private ip address
$host=$hostname." ".$int." ".$ip."\n";
push (@reverse,$host);
# msg 4, "%-20s\t%-30s (%s)", "$ip", "$host", "file $filename: $.";
}
elsif ($section_open and /\s+ipv4 address (\d+\.\d+\.\d+\.\d+)/) {
$ip=$1; next if is_private_ip($ip); # skip private ip address
$host=$hostname." ".$int." ".$ip."\n";
push (@reverse,$host);
# msg 4, "%-20s\t%-30s (%s)", "$ip", "$host", "file $filename: $.";
}
elsif ($int and /^\S/) {
msg 5, "close section (\$int: $int). file $filename: $." if $int;
$section_open = 0; $int = '';
}
}
print "################Reverse#######################\n";
print "@reverse\n";
print "#############################################\n";
return @reverse;
}
####################################################################################
sub ip2dns {
my ($ip, $int, $rtr, $city) = @_;
my @ip_full=();
my $domain="in-addr.arpa";
if ($ip=~/:/) {
# Count additional zero bytes we should insert to ipv6 address
my @ip6array = (split /:/, $ip);
my $add = 8 - $#ip6array;
$domain="ip6.arpa";
# Add leading zeros to partially filled sections
for (my $i=0; $i<=$#ip6array; $i++){
$ip6array[$i] =~ s/^(\S)$/000$1/;
$ip6array[$i] =~ s/^(\S\S)$/00$1/;
$ip6array[$i] =~ s/^(\S\S\S)$/0$1/;
# Build new array containing ipv6 full address
push (@ip_full, split (//, $ip6array[$i]));
# Find :: and insert there proper number of zeros
if (not $ip6array[$i]){
for (my $q=1; $q<=$add; $q++) {
push (@ip_full, 0, 0, 0, 0);
}
}
}
}
else { @ip_full=split /\./, $ip };
# Reverse array containing ipv6 full address and put it to scalar
my $todns = join('.', reverse @ip_full) . ".$domain";
# Print result
return "$todns.\t$rtr-$int.$city.stream-internet.net.";
}
###################################################################################
sub is_private_ip($) {
$_=shift;
my $private=0;
$private=1 if (/^10\./
or /^172\.1[6-9]\./ or /^172\.2[0-9]\./ or /^172\.3[01]\./
or /^192\.168\./
);
return $private;
}
####################################################################################
sub rndc_secret($$) {
# usage: <secret> = rndc_secret(RNDC_KEY_FILE, RNDC_KEY_NAME)
#
my ($key_file, $key_name)=@_;
my $key_found = 0;
my $key_secret = '';
return 0 if not $key_file;
return 0 if not $key_name;
if (not -f $key_file) {
die "Rndc-key file '$key_file' not found.\n";
}
open FILE, '<', $key_file
or die "Can't open file '$key_file': $!\n";
while (<FILE>) {
if (not $key_found) {
next if not /\bkey\s+"([^"]+)"/;
$key_found=1 if "$key_name" eq "$1";
}
if ($key_found) {
$key_secret=$1 if /\bsecret\s+"([^"]+)"/;
}
last if $key_secret;
}
close FILE or die "Can't close file '$rndc_key_file': $!\n";
die "Error. Section key '$key_name' not found.\n" if not $key_found;
die "Error. Secret not found (key: '$key_name').\n" if not $key_secret;
return $key_secret;
}
####################################################################################
sub msg($@) {
my $level = shift;
return 0 if $level > $verbose;
my $now = localtime();
if ((not $log_open) and (-f $log_file)) {
# if (($log_open) and (-f $log_file)) {
open LOG, '>>', $log_file
or die "Can't open file '$log_file': $!\n";
$log_open = 1;
}
if ($log_open) {
# print in file
printf LOG "[%s] %s\n", $now, $_ foreach @_;
}
else {
# print in STDOUT
printf "[%s] %s\n", $now, $_ foreach @_;
}
}
###################################################################################
sub updatedns()
{
my $verbose="4";my $log_open="0";my @rtr_db="";my @addr="";my $city="";
my $router="";my $hostname="";my $ipaddr="";my $data="";my $int="";
my $ptr="";my @changes="";my $hist1="";my %history;
if (open (HISTORY,"<", $history_file))
{ while(<HISTORY>) { chomp; $history{$_} = 0; };
close HISTORY;
};
$data=$_[0]; print "Data--->$data\n"; if ($data eq"") {next;}
if ($data ne "")
{ ($router,$hostname,$int,$ipaddr)=split(" ",$data);
if ($router =~ s/(\S+)\.(\S+)$/$1/) { $city = $2; }
else {$city = "msk";}
if (is_private_ip($ipaddr)!= 1)
{ $int=~s/\/+/-/g; $ptr=ip2dns($ipaddr,$int,$router,$city); # check in history
if (exists $history{$ptr}) { msg 5, "$ipaddr found in history file"; }
else { my ($arpa, $name)=split /\s+/, $ptr; msg 5, "update $arpa";
push @changes,"prereq yxrrset $arpa IN PTR\n",
"update delete $arpa IN PTR\n",
"send\n","update add $arpa $ttl IN PTR $name\n",
"send\n";
};
$history{$ptr}=1;
}
}
while (my ($rr, $flag)=each %history) {
if ($flag == 0) {my ($arpa, $name)=split /\s+/, $rr;
msg 5, "delete old record '$arpa' from dns server";
#push @changes, "update delete $arpa IN PTR $name\n\n";
delete $history{$rr};
}
}
msg 3, scalar(@changes)." changes made";
print "****Changes**************\n@changes***************\n";
if (@changes) {
msg 4, '# start ns-update procedure'; msg 5, "get dns-key '$rndc_key_name' from file '$rndc_key_file'";
my $rndc_key_secret=rndc_secret($rndc_key_file, $rndc_key_name);
my ($tmp, $tmpfile)=tempfile('ip2rr-cisco.XXXXXX');
print $tmp "server $send_update_to\n" if $send_update_to;
print $tmp "key $rndc_key_name $rndc_key_secret\n" if $rndc_key_secret;
msg 5, 'dump @changes to tmpfile: ' . $tmpfile;
print $tmp $_ foreach (@changes);
close $tmp;
my $cmd = "$nsupdate $tmpfile";
$cmd .= " >> $nsupdate_log 2>&1" if -w $nsupdate_log;
msg 5, "system($cmd)";
system($cmd);
msg 5, "delete tmpfile: $tmpfile";
unlink($tmpfile);
msg 5, "save history to $history_file";
$hist1=$hist1.$_."\n" foreach (keys %history);
};
return ($hist1);
}
####################################################################################
#main
#
my $rtr_file="";my $r;
my @addr="";my $city="";my $router="";
my $hostname="";my $ipaddr="";my $data="";my $int="";
my $ptr="";my @changes="";my @history=();my $rez="";
my @zone=""; @addr="";my @routers = ();
foreach my $in_filename (glob("$ranciddir/*/router.db"))
{
open (RDB, $in_filename) or die "can't read $in_filename";
$in_filename =~ s/\/router\.db//;
while (<RDB>) {
next if /^#/ or /:down/ or not /cisco/;
chomp;($r, undef, undef) = split (/:/);
$rtr_file = "$in_filename/configs/$r";
push (@routers,$rtr_file);
}
close RDB;
}
#rint "@routers\n";
foreach $router (@routers)
{
if ($router ne "")
{
@zone=conf2data($router);
foreach $data (@zone){
$router=reverse ($router);
($r,undef)=split "/",$router;
$r=reverse ($r);
$router=reverse($router);
$data = $r." ".$data;
$rez=&updatedns ($data); ;
push (@history,$rez);
}
}
}
open HISTORY, ">", $history_file or die "Can't write file '$history_file': $!";
print HISTORY "@history";
close HISTORY or die "Can't save file '$history_file': $!";
Комментариев нет:
Отправить комментарий