mirror of
				https://github.com/bklang/ldap2dns.git
				synced 2025-10-31 08:03:12 -04:00 
			
		
		
		
	
		
			
	
	
		
			191 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
		
		
			
		
	
	
			191 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
|  | #!/usr/bin/perl | ||
|  | # Script to import data from DNS into LDAP | ||
|  | # Copyright 2000, Jacob Rief | ||
|  | # $Id: export-ldap2dns.pl,v 1.1 2002/09/03 10:43:40 jrief Exp $ | ||
|  | 
 | ||
|  | ###### configure this ###### | ||
|  | # remember to allow zone transfers from Your nameserver | ||
|  | my $LDAPHOST = "localhost"; | ||
|  | my $LDAPBINDDN = "uid=root,o=tiscover"; | ||
|  | my $LDAPPASSWD = "1Fnegu!"; | ||
|  | my $BASEDN = "ou=dns,o=tiscover"; | ||
|  | 
 | ||
|  | ###### don't edit below this line ###### | ||
|  | use strict; | ||
|  | use Net::LDAP qw(LDAP_NO_SUCH_OBJECT LDAP_ALREADY_EXISTS); | ||
|  | 
 | ||
|  | my $ldap; | ||
|  | initialize(); | ||
|  | migrate_zones(); | ||
|  | 
 | ||
|  | sub initialize | ||
|  | { | ||
|  | 	$ldap = Net::LDAP->new($LDAPHOST) or die "Can't connect to LDAP server"; | ||
|  | 	my $mesg = $ldap->bind( dn => $LDAPBINDDN, password => $LDAPPASSWD ); | ||
|  | 	die "Unable to bind to LDAP ", $mesg->error if ($mesg->code); | ||
|  | } | ||
|  | 
 | ||
|  | sub migrate_zones | ||
|  | { | ||
|  | 	my $mesg = $ldap->search(base=>$BASEDN, scope=>'sub', filter=>"(objectclass=dnszone)"); | ||
|  | 	my @oldzones = $mesg->entries(); | ||
|  | 	foreach my $oldzone (@oldzones) { | ||
|  | 		my @zonename = $oldzone->get_value('dnszonename'); | ||
|  | 		my $masterdn = dn_domain($zonename[0]) if ($#zonename>=0); | ||
|  | 		foreach my $zn (@zonename) { | ||
|  | 			my $newdn = dn_domain($zn); | ||
|  | 			next unless ($newdn =~ /^dc=\s*([^,]+).*/); | ||
|  | 			my $dc = $1; | ||
|  | 			my $soarecord = $oldzone->get_value('dnsserial')." " | ||
|  | 			    .$oldzone->get_value('dnsrefresh')." " | ||
|  | 			    .$oldzone->get_value('dnsretry')." " | ||
|  | 			    .$oldzone->get_value('dnsexpire')." " | ||
|  | 			    .$oldzone->get_value('dnsminimum'); | ||
|  | 			my %attrs = ( 'objectclass' => [ qw(dNSDomain dcObject) ], 'dc' => $dc, 'sOARecord' => [ $soarecord ] ); | ||
|  | 			$mesg = $ldap->modify($newdn, 'replace' => \%attrs); | ||
|  | 			while ($mesg->code()==LDAP_NO_SUCH_OBJECT) { | ||
|  | 			    repeat: | ||
|  | 				$mesg = $ldap->add($newdn, 'attrs' => list_attrs(\%attrs)); | ||
|  | 				last unless ($mesg->code()==LDAP_NO_SUCH_OBJECT); | ||
|  | 				my $filldn = $newdn; | ||
|  | 				do { | ||
|  | 					die("Invalid dn: $filldn") unless ($filldn =~ /[^,]+,((dc=[^,]+),.+)/); | ||
|  | 					$filldn = $1; | ||
|  | 					$mesg = $ldap->add($filldn, 'attrs' => [ 'objectclass'=>'dcObject', 'dc'=>$2) ]); | ||
|  | 				} until ($mesg->code()==0 || $mesg->code()==LDAP_ALREADY_EXISTS); | ||
|  | 				goto repeat; | ||
|  | 			} | ||
|  | 			die("Error from LDAP: \"".$mesg->error()."\" on $newdn (".$mesg->code().")") if ($mesg->code()); | ||
|  | 			if ($masterdn ne $newdn) { | ||
|  | 				$mesg = $ldap->modify($masterdn, 'replace' => [ 'objectclass' => 'alias' ]); | ||
|  | 				$mesg = $ldap->modify($masterdn, 'add' => [ 'alias' => $newdn ]); | ||
|  | 				$mesg = $ldap->modify($newdn, 'replace' => [ 'objectclass' => 'alias', 'alias' => $masterdn ]); | ||
|  | 			} | ||
|  | 			migrate_rrrecords($zn, $newdn, $oldzone->dn()); | ||
|  | 		} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | sub migrate_rrrecords | ||
|  | { | ||
|  | 	my ($zonename, $newzonedn, $oldzonedn) = (@_); | ||
|  | 	my @objectclass = qw(dNSDomain dcObject); | ||
|  | 	my $mesg = $ldap->search(base=>$oldzonedn, scope=>'sub', filter=>"(objectclass=dnsrrset)"); | ||
|  | 	my @rrsets = $mesg->entries(); | ||
|  | 	foreach my $rr (@rrsets) { | ||
|  | 		my $domainname = $rr->get_value('dnsdomainname'); | ||
|  | 		my $dn = dn_domain(length($domainname)>0 ? "$domainname.$zonename" : "$zonename"); | ||
|  | 		my $type = $rr->get_value('dnstype'); | ||
|  | 		print "dn: $dn (type: $type)\n"; | ||
|  | 		next unless ($dn =~ /^dc=\s*([^,]+).*/); | ||
|  | 		my %attrs = read_ldapobject($dn); | ||
|  | 		$attrs{'objectclass'} = \@objectclass; | ||
|  | 		$attrs{'dc'} = $1; | ||
|  | 		my @cname = $rr->get_value('dnscname'); | ||
|  | 		my @ipaddr = $rr->get_value('dnsipaddr'); | ||
|  | 		my $cipaddr = $rr->get_value('dnscipaddr'); | ||
|  | 		if ($type eq "A") { | ||
|  | 			push(@ipaddr, $cipaddr) if (length($cipaddr)>5); | ||
|  | 			my $ta = $attrs{'aRecord'}; | ||
|  | 			push(@$ta, @ipaddr) if ($#ipaddr>=0); | ||
|  | 		} elsif ($type eq "NS") { | ||
|  | 			my $ta = $attrs{'NSRecord'}; | ||
|  | 			foreach my $cn (@cname) { | ||
|  | 				if ($cn =~ /\.$/) { | ||
|  | 					push(@$ta, $cn); | ||
|  | 				} else { | ||
|  | 					push(@$ta, "$cn.$zonename"); | ||
|  | 				} | ||
|  | 			} | ||
|  | 		} elsif ($type eq "MX") { | ||
|  | 			my $ta = $attrs{'MXRecord'}; | ||
|  | 			my $pref = $rr->get_value('dnspreference'); | ||
|  | 			foreach my $cn (@cname) { | ||
|  | 				if ($cn =~ /\.$/) { | ||
|  | 					push(@$ta, "$pref $cn"); | ||
|  | 				} else { | ||
|  | 					push(@$ta, "$pref $cn.$zonename"); | ||
|  | 				} | ||
|  | 			} | ||
|  | 		} elsif ($type eq "CNAME") { | ||
|  | 			my $ta = $attrs{'cNAMERecord'}; | ||
|  | 			die("no CNAME") unless($#cname>=0); | ||
|  | 			foreach my $cn (@cname) { | ||
|  | 				if ($cn =~ /\.$/) { | ||
|  | 					push(@$ta, $cn); | ||
|  | 				} else { | ||
|  | 					push(@$ta, "$cn.$zonename"); | ||
|  | 				} | ||
|  | 			} | ||
|  | 		} | ||
|  | 		remove_unused(\%attrs); | ||
|  | 		$mesg = $ldap->modify($dn, 'replace' => \%attrs); | ||
|  | 		while ($mesg->code()==LDAP_NO_SUCH_OBJECT) { | ||
|  | 		    repeat: | ||
|  | 			$mesg = $ldap->add($dn, 'attrs' => list_attrs(\%attrs)); | ||
|  | 			last unless ($mesg->code()==LDAP_NO_SUCH_OBJECT); | ||
|  | 			my $filldn = $dn; | ||
|  | 			do { | ||
|  | 				die("Invalid dn: $filldn") unless ($filldn =~ /[^,]+,((dc=[^,]+),.+)/); | ||
|  | 				$filldn = $1; | ||
|  | 				$mesg = $ldap->add($filldn, 'attrs' => [ qw(objectclass dcObject dc $2) ]); | ||
|  | 			} until ($mesg->code()==0 || $mesg->code()==LDAP_ALREADY_EXISTS); | ||
|  | 			goto repeat; | ||
|  | 		} | ||
|  | 		die("Error from LDAP: \"".$mesg->error()."\" on $dn") if ($mesg->code()); | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | sub dn_domain | ||
|  | { | ||
|  | 	my ($domain)=(@_); | ||
|  | 	my @p = split /\./, lc($domain); | ||
|  | 	my $dc = 'dc='.join(',dc=', @p); | ||
|  | 	$dc .= ','.$BASEDN; | ||
|  | 	return $dc; | ||
|  | } | ||
|  | 
 | ||
|  | sub list_attrs | ||
|  | { | ||
|  |         my $attr = shift; | ||
|  |         my (@list, $key, $value); | ||
|  |         while (($key, $value) = each %$attr) { | ||
|  |                 push(@list, $key => $value); | ||
|  |         } | ||
|  |         return \@list; | ||
|  | } | ||
|  | 
 | ||
|  | sub read_ldapobject | ||
|  | { | ||
|  | 	my $dn = shift; | ||
|  | 	my %attrs = (); | ||
|  | 	$attrs{'aRecord'} = []; | ||
|  | 	$attrs{'cNAMERecord'} = []; | ||
|  | 	$attrs{'MXRecord'} = []; | ||
|  | 	$attrs{'NSRecord'} = []; | ||
|  | 	my $mesg = $ldap->search(base => $dn, scope => 'base', filter => "(objectclass=dcObject)"); | ||
|  | 	return %attrs if ($mesg->code()==LDAP_NO_SUCH_OBJECT); | ||
|  | 	return %attrs if ($mesg->count()==0); | ||
|  | 	my $obj = $mesg->entry(0); | ||
|  | 	my @tempa = $obj->get_value('aRecord'); | ||
|  | 	$attrs{'aRecord'} = \@tempa if ($#tempa>=0); | ||
|  | 	my @tempcname = $obj->get_value('cNAMERecord'); | ||
|  | 	$attrs{'cNAMERecord'} = \@tempcname if ($#tempcname>=0); | ||
|  | 	my @tempmx = $obj->get_value('MXRecord'); | ||
|  | 	$attrs{'MXRecord'} = \@tempmx if ($#tempmx>=0); | ||
|  | 	my @tempns = $obj->get_value('NSRecord'); | ||
|  | 	$attrs{'NSRecord'} = \@tempns if ($#tempns>=0); | ||
|  | 	return %attrs; | ||
|  | } | ||
|  | 
 | ||
|  | sub remove_unused | ||
|  | { | ||
|  | 	my $hash = shift; | ||
|  | 	foreach my $key (keys %$hash) { | ||
|  | 		my $ta = $$hash{$key}; | ||
|  | 		next if ($key eq "dc"); | ||
|  | 		delete $$hash{$key} if ($#$ta<0); | ||
|  | 	} | ||
|  | } | ||
|  | 
 |