#!/usr/bin/perl # Script to import data from DNS into LDAP # Copyright 2000, Jacob Rief # $Id: import.pl,v 1.24 2000/12/14 12:44:29 jrief Exp $ ###### configure this ###### # remember to allow zone transfers from Your nameserver $LDAPHOST = "ldap.myorg.com"; $LDAPBINDDN = "ou=dns,o=myorg"; $LDAPPASSWD = "secret"; $NAMESERVER = "ns1.myorg.com"; $BASEDN = "ou=dns,o=myorg"; $FULL_QUALIFIED_NAME = 0; ###### don't edit below this line ###### use Net::DNS; use Net::LDAP; $ldap = Net::LDAP->new($LDAPHOST) or die "Can't connect to LDAP server"; $mesg = $ldap->bind( dn => $LDAPBINDDN, password => $LDAPPASSWD ); die "Unable to bind to LDAP ", $mesg->error if ($mesg->code); @domains; while (<>) { chomp; $_ = lc; if (/primary\s+([0-9A-Za-z._+-]+)\s+/) { push(@domains, $1); } } if ($#domains>=0) { @domains = sort(@domains); for ($i = 1; $i<=$#domains; $i++) { if ($domains[$i-1] eq $domains[$i]) { print "Warning: removing double entry for zone: $domains[$i]\n"; splice(@domains, $i, 1); } } print "Adding ". ($#domains+1) ." zones to LDAP server\n"; foreach(@domains) { read_zone($_); } } else { print "No domain added to LDAP server\n"; } sub add_attrs { my ($attr, $zonename) = @_; # correct DNScname if (defined $$attr{'DNScname'}) { # check if DNScname is a real name if ($$attr{'DNScname'} =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)/) { $$attr{'DNSipaddr'} = "$1.$2.$3.$4"; undef $$attr{'DNScname'}; } } my ($tail); if ($$attr{'DNSdomainname'} eq $zonename) { $tail = ""; } else { split /\.$zonename/, $$attr{'DNSdomainname'}; die "Corrupt DNSdomainname" unless (defined @_[0]); $tail = @_[0]; } if ($FULL_QUALIFIED_NAME) { $$attr{'DNSdomainname'} = "$zonename." if ($tail eq ""); $$attr{'DNSdomainname'} = "$tail.$zonename." unless ($tail eq ""); $$attr{'DNScname'} .= "." if (defined $$attr{'DNScname'}); } else { $$attr{'DNSdomainname'} = "$tail"; if (defined $$attr{'DNScname'}) { split /\.$zonename/, $$attr{'DNScname'}; $$attr{'DNScname'} = @_[0] if (defined @_[0]); } } my $rrdn; if ($$attr{'DNStype'} eq "A") { # A records are multivalued, use one rrset for all ipaddresses $$attr{'cn'} = "A:$tail"; $rrdn = "cn=$$attr{'cn'},cn=$zonename,$BASEDN"; $mesg = $ldap->search(base=>$rrdn, scope=>"base", filter => "(objectclass=DNSrrset)"); if ($mesg->count==0) { $mesg = $ldap->add(dn=>$rrdn, attr=>list_attrs($attr)); die "Failed to add entry:", $rrdn, " ", $mesg->error if ($mesg->code); } else { $mesg = $ldap->modify(dn=>$rrdn, add=>{ 'DNSipaddr'=>$$attr{'DNSipaddr'} }); die "Failed to modify entry:", $rrdn, " ", $mesg->error if ($mesg->code); } } else { # All other records are siglevalued, use one rrset for each entry my $i = 0; do { $i++; $$attr{'cn'} = "$$attr{'DNStype'}$i:$tail"; $rrdn = "cn=$$attr{'cn'},cn=$zonename,$BASEDN"; $mesg = $ldap->search(base=>$rrdn, scope=>"base", filter=>"(objectclass=DNSrrset)"); } while ($mesg->count>0); if ($FULL_QUALIFIED_NAME) { $$attr{'DNScname'} = "$$attr{'DNStype'}$i.$zonename." unless defined $$attr{'DNScname'}; } else { $$attr{'DNScname'} = "$$attr{'DNStype'}$i" unless defined $$attr{'DNScname'}; } $mesg = $ldap->add(dn=>$rrdn, attr=>list_attrs($attr)); die "Failed to add entry:", $rrdn, " ", $mesg->error if ($mesg->code); } } sub list_attrs { my $attr = shift; my (@list, $key, $value); while (($key, $value) = each %$attr) { push(@list, $key => $value); } return \@list; } sub read_zone { my $zonename = shift; $res = new Net::DNS::Resolver; $res->nameservers($NAMESERVER); @zone = $res->axfr($zonename); while (!@zone) { print "Query failed for $zonename: ", $res->errorstring, ".\n"; if ($res->errorstring eq "couldn't connect") { print "Trying to reconnect\n"; sleep(10); @zone = $res->axfr($zonename); } else { return; } } print "---------- reading zone $zonename ----------\n"; foreach $rr (@zone) { $rr->print; if ($rr->type eq "SOA") { die "Invalid SOA record for ", $rr->name, " " unless ($rr->string =~ /^([0-9a-zA-Z_.+-]+)\.\s+(\d+)\s+(\w+)\s+(\w+)\s+([0-9a-zA-Z_.+-]+)\s+([0-9a-zA-Z_.+-]+)\s+\((.*)\)/s); die "Corrupt SOA record for ", $rr->name, " " unless ($1 eq $rr->name && $2 eq $rr->ttl && $3 eq $rr->class && $4 eq $rr->type); my %attr; $attr{'objectclass'} = "DNSzone"; $attr{'DNSzonename'} = lc $1; $attr{'DNSttl'} = $2; $attr{'DNSclass'} = $3; $attr{'DNStype'} = $4; $attr{'DNSzonemaster'} = lc $5; $attr{'DNSadminmailbox'} = lc $6; my $soa = $7; die "Invalid SOA fields for ", $zonename, " " unless ($soa =~ /\s*(\d+)\D*(\d+)\D*(\d+)\D*(\d+)\D*(\d+)\s*/s); $attr{'DNSserial'} = $1; $attr{'DNSrefresh'} = $2; $attr{'DNSretry'} = $3; $attr{'DNSexpire'} = $4; $attr{'DNSminimum'} = $5; $attr{'cn'} = $zonename; $mesg = $ldap->add(dn=>"cn=$zonename,$BASEDN", attr=>list_attrs(\%attr)); die "Failed to add entry:", $zonename, " ", $mesg->error if ($mesg->code); } elsif ($rr->type eq "A") { die "Invalid A record for ", $rr->name, " " unless ($rr->string =~ /^([0-9a-zA-Z_.+-]+)\.\s+(\d+)\s+(\w+)\s+(\w+)\s+([0-9.]+)/); die "Corrupt A record for ", $rr->name, " " unless ($1 eq $rr->name && $2 eq $rr->ttl && $3 eq $rr->class && $4 eq $rr->type && $5 eq $rr->address); next if $1 eq "localhost.$zonename"; my %attr; $attr{'objectclass'} = "DNSrrset"; $attr{'DNSdomainname'} = lc $1; $attr{'DNSttl'} = $2; $attr{'DNSclass'} = $3; $attr{'DNStype'} = $4; $attr{'DNSipaddr'} = $5; add_attrs(\%attr, $zonename); } elsif ($rr->type eq "MX") { die "Invalid MX record for ", $rr->name, " " unless ($rr->string =~ /^([0-9a-zA-Z_.+-]+)\.\s+(\d+)\s+(\w+)\s+(\w+)\s+(\d+)\s+([0-9a-zA-Z_.+-]+)/); die "Corrupt MX record for ", $rr->name, " " unless ($1 eq $rr->name && $2 eq $rr->ttl && $3 eq $rr->class && $4 eq $rr->type); my %attr; $attr{'objectclass'} = "DNSrrset"; $attr{'DNSdomainname'} = lc $1; $attr{'DNSttl'} = $2; $attr{'DNSclass'} = $3; $attr{'DNStype'} = $4; $attr{'DNSpreference'} = $5; $attr{'DNScname'} = lc $6; add_attrs(\%attr, $zonename); } elsif ($rr->type eq "NS") { die "Invalid NS record for ", $rr->name, " " unless ($rr->string =~ /^([0-9a-zA-Z_.+-]+)\.\s+(\d+)\s+(\w+)\s+(\w+)\s+([0-9a-zA-Z_.+-]+)/); die "Corrupt NS record for ", $rr->name, " " unless ($1 eq $rr->name && $2 eq $rr->ttl && $3 eq $rr->class && $4 eq $rr->type); my %attr; $attr{'objectclass'} = "DNSrrset"; $attr{'DNSdomainname'} = lc $1; $attr{'DNSttl'} = $2; $attr{'DNSclass'} = $3; $attr{'DNStype'} = $4; $attr{'DNScname'} = lc $5; add_attrs(\%attr, $zonename); } elsif ($rr->type eq "CNAME" || $rr->type eq "TXT") { die "Invalid ", $rr->type, " record for ", $rr->name, " " unless ($rr->string =~ /^([0-9a-zA-Z_.+-]+)\.\s+(\d+)\s+(\w+)\s+(\w+)\s+([0-9a-zA-Z_.+-\s\"=:]+)/); die "Corrupt ", $rr->type, " record for ", $rr->name, " " unless ($1 eq $rr->name && $2 eq $rr->ttl && $3 eq $rr->class && $4 eq $rr->type); my %attr; $attr{'objectclass'} = "DNSrrset"; $attr{'DNSdomainname'} = $1; $attr{'DNSttl'} = $2; $attr{'DNSclass'} = $3; $attr{'DNStype'} = $4; if ($rr->type eq "CNAME") { $attr{'DNScname'} = $5; } elsif ($rr->type eq "TXT") { $attr{'DNStxt'} = $5; } add_attrs(\%attr, $zonename); } elsif ($rr->type eq "PTR") { die "Invalid PTR record for ", $rr->name, " " unless ($rr->string =~ /^([0-9.]+\.in-addr\.arpa)\.\s+(\d+)\s+(\w+)\s+(\w+)\s+([0-9a-zA-Z_.+-]+)/); die "Corrupt PTR record for ", $rr->name, " " unless ($1 eq $rr->name && $2 eq $rr->ttl && $3 eq $rr->class && $4 eq $rr->type); my %attr; $attr{'objectclass'} = "DNSrrset"; $attr{'DNSdomainname'} = "$1."; $attr{'DNSttl'} = $2; $attr{'DNSclass'} = $3; $attr{'DNStype'} = $4; $attr{'DNScname'} = $5; if ($attr{'DNSdomainname'} =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)/) { $attr{'DNSipaddr'} = "$4.$3.$2.$1"; $attr{'cn'} = "PTR:$1"; # Only for C-level domains yet } else { die "Corrupt IP address for", $rr->name; } my $rrdn = "cn=$attr{'cn'},cn=$zonename,$BASEDN"; $mesg = $ldap->add(dn=>$rrdn, attr=>list_attrs(\%attr)); die "Failed to add entry:", $rrdn, " ", $mesg->error if ($mesg->code); } } }