Еще помучал скрипт dhcp2ldap.pl после тестирования на реальной и виртуальной сетке. В виртуальной сети DHCP настроен на малое время аренды адресов и частыми запросами на возобновление оных. В результате получилось такое:
Код: Выделить всё
#!/usr/bin/perl
####################################################################
# Edit These for Your Domain #
####################################################################
$LEASES = "/var/db/dhcpd/dhcpd.leases";
$DOMAIN = "domain.local";
$REVERSE = "0.168.192.in-addr.arpa";
$FORWARD_BASE = "zoneName=domain.local,ou=DNS,dc=domain,dc=local";
$REVERSE_BASE = "zoneName=0.168.192.in-addr.arpa,ou=DNS,dc=domain,dc=local";
$USER = 'cn=manager,dc=domain,dc=local';
$PASSWORD = "shajtanparol";
$LDAP_HOST = '127.0.0.1';
$UPDATE_TIME = 30; # In Seconds
$AUTO_VERIFY = 0; # Set this to positive if you would like dhcp2ldap
# to periodically re-read the entire leases file
# even if the time stamp hasn't changed
#
# It will perform the auto-verify after
# ($AUTO_VERIFY * $UPDATE_TIME) seconds
#
# This is probably a good idea unless your parse times
# are incredibly high
####################################################################
# Do Not Edit Below This Line #
####################################################################
use IO::Socket;
use Net::LDAP;
print "Initializing LDAP Connection...";
$ldap = Net::LDAP->new($LDAP_HOST) or die "$@";
$ldap->bind($USER, password => $PASSWORD) or die "$!\n";
print "Done\n";
$params = shift;
if($params eq "-d"){
daemonize();
}
if($params eq "-h"){
usage();
exit;
}
while(1){
if(changed($LEASES)){
parse($LEASES);
do_stuff();
}
sleep $UPDATE_TIME;
}
sub changed{
my $file = shift;
my $curstat = (stat($file))[9];
if($AUTO_VERIFY){
$check_count++;
}
if($oldstat != $curstat || (($check_count == $AUTO_VERIFY) && $AUTO_VERIFY)){
$oldstat = $curstat;
$check_count = 0;
print "Timestamp change or AUTO_VERIFY triggered...\n";
return 1;
}
else{
return 0;
}
}
sub daemonize{
chdir '/';
umask 0;
open STDIN, '/dev/null';
open STDOUT, '/dev/null';
open STDERR, '/dev/null';
if(fork()){
exit;
}
else{
setsid;
return;
}
}
sub parse {
my $ip,$hostname,@freeip=(),@date,$tstamp;
open IN, shift or die "Could not open leases file: $!\n";
while($_ = <IN>){
if(/^#/){
next;
}
chomp $_;
if(/lease/){
/\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}/;
$ip = $&;
while(!(/\}/)){
$_ = <IN>;
if (/\s+ends\s\d+\s/){
/\d+\/\d+\/\d+\s\d+\:\d+\:\d+/;
$_ = $&;
$tstamp=$&;
}
if (/\s+binding\s*state\s*free;/){
$freeip{$ip} = $tstamp;
}
if(/client-hostname/){
/\".*\"/;
$_ = $&;
/\w+\S*\w+/;
$_ = $&;
$hostname = lc;
$hosts{$hostname}{'ip'} = $ip;
$hosts{$hostname}{'datetime'} = $tstamp;
}
}
}
}
close IN;
}
sub do_stuff {
my $readd, $ip, $noadd=0, $ts_ip, $hostname;
foreach my $host (keys(%hosts)) {
$hostname = $host;
$ip = $hosts{$host}{'ip'};
$ts_ip = $hosts{$host}{'datetime'};
$lookup = "";
eval{$lookup = inet_ntoa((gethostbyname($hostname.".".$DOMAIN))[4]); };
($first,$second,$third,$fourth) = split(/\./,$ip);
($first_l,$second_l,$third_l,$fourth_l) = split(/\./,$lookup);
while(($frip,$ts_frip) = each(%freeip)){
if ($ip eq $frip){
if (($ip eq $lookup)&&($ts_frip gt $ts_ip)){
print "Removing old records for $hostname...\n";
$result = $ldap->delete("relativeDomainName=".$hostname.",".$FORWARD_BASE);
$result->code && warn "failed to remove entry: ", $result->error ;
$result = $ldap->delete("relativeDomainName=".$fourth_l.",".$REVERSE_BASE);
$result->code && warn "failed to remove entry: ", $result->error ;
}
if (!$lookup){
if ($ts_frip gt $ts_ip){
$noadd = 1;
}
if ($ts_frip le $ts_ip){
$noadd = 0;
}
}
}
}
if($noadd){
next;
}
if(!$lookup){
add();
$readd = 0;
next;
}
if($lookup eq $ip){
next;
}
if($lookup ne $ip){
print "Removing inaccurate records for $hostname...\n\n";
$result = $ldap->delete("relativeDomainName=".$hostname.",".$FORWARD_BASE);
$result->code && warn "failed to remove entry: ", $result->error ;
$result = $ldap->delete("relativeDomainName=".$fourth_l.",".$REVERSE_BASE);
$result->code && warn "failed to remove entry: ", $result->error ;
$readd = 1;
}
if($readd){
add();
$readd = 0;
}
sub add {
print "Adding entry for $host at $ip...\n";
$result = $ldap->add ("relativeDomainName=".$hostname.",".$FORWARD_BASE,
attr => [
'relativeDomainName'=> $host,
'objectClass'=> ['top','dNSZone'],
'dNSTTL' => '7200',
'zoneName' => $DOMAIN,
'aRecord' => $ip
]
);
$result->code && warn "failed to add entry: ", $result->error ;
$result = $ldap->add ( "relativeDomainName=".$fourth."," . $REVERSE_BASE,
attr => [
'relativeDomainName'=> "$fourth",
'objectClass'=> ['top','dNSZone'],
'dNSTTL' => '7200',
'zoneName' => $REVERSE,
'pTRRecord' => $hostname
]
);
$result->code && warn "failed to add entry: ", $result->error ;
}
}
}
sub usage{
print <<EOF;
dhcp2ldapd v1.1: Dynamic DNS Updates for the Bind9 LDAP backend
Copyright 2005 Travis Groth <travis\@netfoo.org> under the GNU GPL
Usage:
dhcp2ldapd [-d | -h]
-d runs dhcp2ldap in daemon mode
-h displays this help message
Please edit the config variables before running!
EOF
}
#############################################################################
#This program is free software; you can redistribute it and/or modify
#it under the terms of the GNU General Public License as published by
#the Free Software Foundation; either version 2 of the License, or
#(at your option) any later version.
#
#This program is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#GNU General Public License for more details.
#
#You should have received a copy of the GNU General Public License
#along with this program; if not, write to the Free Software
#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#############################################################################
Если кто-то дополнительно потестит - будет славно.
PS Сам я от связки DDNS-LDAP отказался.
В результате остановился на варианте DHCP-LDAP и DDNS классический - файлами.