Importing version 0.2.2

git-svn-id: https://svn.alkaloid.net/gpl/ldap2dns/trunk@2 06cd67b6-e706-0410-b29e-9de616bca6e9
This commit is contained in:
Ben Klang
2005-12-02 04:17:15 +00:00
parent ef7ba2e681
commit 56f7543fdf
10 changed files with 856 additions and 378 deletions

49
CHANGELOG Normal file
View File

@@ -0,0 +1,49 @@
Version 0.2.3
+ Check for next availabe server in /etc/ldap.conf
if first one is unavialable.
Version 0.2.2
- Tested with djbdns-1.05
- Removed compleatly the possibility to create a binary data.cdb file.
Reasons:
* It just takes a few milliseconds to create a data.cdb file with
tinydns-data.
* Its much safer to have an ASCII data file handy just in case
something goes wrong.
* I am too lazy to adopt ldap2dns for each new version of djbdns.
* ldap2dns does not have to be linked statically against any other
package.
- Now the output option takes parameters data and/or db instead
of numbers.
Version 0.2.1
- Additional attribute in DNSrrset: DNScipaddr
Canonical IP address, which when used instead
of DNSipaddr automatically resolves reverse.
- Using Environement Variables LDAP2DNS_UPDATE and
LDAP2DNS_OUTPUT for default values used by ldap2dns.
- If started as daemon, does not exit if connection to
LDAP server fails but tries to reconnect after a timeout.
- An external program can be called if ldap2dns detects a
modification in the database.
Version 0.2.0
- New schema, unfortunately not compatible with old one, but
now its unambigous.
- Mapping for reverse lookup works fine.
- ldap2dns now can be started by daemontools.
- Fixed a bug for DNSrrset's with type=TXT
- Much better naming scheme for dn's when using
import.pl
- RPM support

View File

@@ -1,18 +1,12 @@
# ldap2dns Makefile # $Id: Makefile,v 1.22 2001/02/16 09:51:23 jrief Exp $
VERSION=0.2.0 VERSION=0.2.2
RELEASE=1 RELEASE=2
WITHTINYDNS=-DWITH_TINYDNS
CC=gcc -O2 CC=gcc -O2
DJBDNSDIR=../djbdns-1.02
INC=-I$(DJBDNSDIR)
CFLAGS=$(INC) $(WITHTINYDNS) -DVERSION='"$(VERSION)"' CFLAGS=$(INC) $(WITHTINYDNS) -DVERSION='"$(VERSION)"'
OBJS=ldap2dns.o OBJS=ldap2dns.o
LIBS=-lldap -llber -lresolv LIBS=-lldap -llber -lresolv
LD=gcc LD=gcc
LDFLAGS= LDFLAGS=
ALIBS=$(DJBDNSDIR)/dns.a $(DJBDNSDIR)/env.a $(DJBDNSDIR)/libtai.a \
$(DJBDNSDIR)/cdb.a $(DJBDNSDIR)/alloc.a $(DJBDNSDIR)/buffer.a \
$(DJBDNSDIR)/unix.a $(DJBDNSDIR)/byte.a
INSTALL_PREFIX= INSTALL_PREFIX=
PREFIXDIR=$(INSTALL_PREFIX)/usr PREFIXDIR=$(INSTALL_PREFIX)/usr
LDAPCONFDIR=$(INSTALL_PREFIX)/etc/openldap LDAPCONFDIR=$(INSTALL_PREFIX)/etc/openldap
@@ -21,8 +15,8 @@ SPECFILE=ldap2dns.spec
all: ldap2dns all: ldap2dns
ldap2dns: $(OBJS) $(LIBS) $(ALIBS) ldap2dns: $(OBJS) $(LIBS)
$(LD) $(LDFLAGS) -o $@ $(OBJS) $(ALIBS) $(LIBS) $(LD) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
ln -f ldap2dns ldap2dnsd ln -f ldap2dns ldap2dnsd
ldap2dns.o: ldap2dns.c ldap2dns.o: ldap2dns.c
@@ -38,7 +32,7 @@ install: all
install -o root -g root -m 644 dns.oc.conf $(LDAPCONFDIR)/ install -o root -g root -m 644 dns.oc.conf $(LDAPCONFDIR)/
clean: clean:
rm -f $(OBJS) ldap2dns ldap2dnsd data* $(SPECFILE) rm -f $(OBJS) ldap2dns ldap2dnsd data* *.db $(SPECFILE)
tar: clean tar: clean
cd ..; \ cd ..; \

View File

@@ -1,16 +1,17 @@
<H1 align=center>LDAP to DNS gateway</H1> <H1 align=center>LDAP to DNS gateway</H1>
<P> <P>
<B>ldap2dns</B> is a program to create DNS records directly from a LDAP directory. <B>ldap2dns</B> is a program to create DNS (Domain Name Service) records directly
It can and should be be used to replace the secondary name-server by a second from a LDAP directory. It can and should be be used to replace the secondary
primary one.<BR> name-server by a second primary one.<BR>
<B>ldap2dns</B> helps to reduce all kind of administration overhead. <B>ldap2dns</B> reduces all kind of administration overhead:
No more flat file editing, no more zone file editing. After having installed No more flat file editing, no more zone file editing. After having installed
<B>ldap2dns</B>, the administrator only has to access the LDAP directory.<BR> <B>ldap2dns</B>, the administrator only has to access the LDAP directory.<BR>
If he desires he can add access control for each zone, create a webbased GUI Optionally she can add access control for each zone, create a GUI
and add all other kind of zone and resource record information without and add all other kind of zone and resource record information without
interfering with the DNS server.<BR> interfering with the DNS server.<BR>
<B>ldap2dns</B> is designed to write binary data.cdb files used by tinydns, but <B>ldap2dns</B> is designed to write ASCII data files used by <I>tinydns</I>
also may be used to write .db-files used by named.<BR> from the <I>djbdns</I> package, but also may be used to write .db-files used
by <I>named</I> as found in the <I>BIND</I> package.<BR>
<P> <P>
<H3>1. Introduction</H3> <H3>1. Introduction</H3>
@@ -22,7 +23,7 @@ DNS, information must be stored redundantly on two or more hosts.
The classical data replication through zone transfer is unreliable, insecure The classical data replication through zone transfer is unreliable, insecure
and difficult to administer.<BR> and difficult to administer.<BR>
To solve this problem some proprietary attempts have been proposed to To solve this problem some proprietary attempts have been proposed to
store DNS information in relational databases. The nature of DNS however store DNS information in relational databases. The nature of DNS, however,
is hierarchical and such should the database be. Using a relational database is hierarchical and such should the database be. Using a relational database
to store DNS information is undesirable, because it becomes difficult to store DNS information is undesirable, because it becomes difficult
to store free form information. Within a hierachical data scheme, the to store free form information. Within a hierachical data scheme, the
@@ -35,28 +36,28 @@ and generates a file suitable for name-servers.<BR>
Actually the most widely spread name-servers Actually the most widely spread name-servers
<A HREF="http://www.isc.org/products/BIND/">named</A> and <A HREF="http://www.isc.org/products/BIND/">named</A> and
<A HREF="http://cr.yp.to/djbdns/tinydns.html">tinydns</A> are <A HREF="http://cr.yp.to/djbdns/tinydns.html">tinydns</A> are
supported. <B>ldap2dns</B> has been specially designed to work with supported. <B>ldap2dns</B> specially has been designed to work with
tinydns and is the favored name server daemon for the author of this program. tinydns and is the favored name server daemon for the author of this program.
<B>ldap2dns</B> can also generate files suitable for named, but this feature <B>ldap2dns</B> can also generate files suitable for <I>named</I> version 8,
is not well supported. but this feature is not well supported.
There is a There is a
<A HREF="http://www.alternic.org/drafts/drafts-m-n/draft-miller-dns-ldap-schema-00.txt"> <A HREF="http://www.alternic.org/drafts/drafts-m-n/draft-miller-dns-ldap-schema-00.txt">
RFC</A> for a format description how to store DNS information in LDAP. RFC</A> for a format description how to store DNS information in LDAP.
This paper however is a draft RFC and expired in February 1999. The scheme this RFC This paper a draft RFC which expired in February 1999, looks as if it has been
describes, looks as if it has been designed to be used only by 'named'. This scheme specially designed to be used by <I>named</I>. This scheme
does not have strict attribute-value-pair mapping, making it difficult to be used by does not have strict attribute-value-pair mapping, making it difficult to be used by
user interfaces. It also lacks of an implementation (I have never heard of any).<BR> user interfaces. It also lacks of an implementation (or I have never heard of any).<BR>
Since tinydns is going another descriptive way, I implemented a similar object-scheme Since <I>tinydns</I> is going another descriptive way. Therefore I implemented a similar
more suitable for tinydns. Two objectclasses have been defined. <B>DNSzone</B> stores object-scheme more suitable for <I>tinydns</I>. Two object-classes have been defined.
all the information to define a DNS zone, such as the SOA (Start Of Authority), serial <B>DNSzone</B> stores all the information to define a DNS zone, such as the SOA
numbers etc. <B>DNSrrset</B> is used to store the information for a single resource record, (Start Of Authority), serial numbers etc. <B>DNSrrset</B> is used to store the information
such as the domain name, IP-addresses, class and type.<BR> for a single resource record, such as the domain name, IP-addresses, class and type.<BR>
Here are the tables: Here are the tables:
<P> <P>
<H4>DNSzone</H4> <H4>DNSzone</H4>
This object-class represents a DNS zone. It is the container for all the resource records This object-class represents a DNS zone. It is the container for all the resource records
within a zone. Zones can be primary or secondary, if used in conjunction with within a zone. Zones can be primary or secondary. If used in conjunction with
tinydns zones are always primary. Secondary zones don't make sense anyway! <I>tinydns</I> zones are always primary. Secondary zones don't make sense anyway!
In addition to being a container, the zone object has attributes related to In addition to being a container, the zone object has attributes related to
the management of the zone. These include the zone's SOA information. Each zone-object the management of the zone. These include the zone's SOA information. Each zone-object
can have none to many children of class <B>DNSrrset</B>.<BR> can have none to many children of class <B>DNSrrset</B>.<BR>
@@ -79,26 +80,26 @@ can have none to many children of class <B>DNSrrset</B>.<BR>
<TR><TD>DNStimestamp</TD><TD><I>timestamp</I></TD><TD>optional, only used with tinydns</TD></TR> <TR><TD>DNStimestamp</TD><TD><I>timestamp</I></TD><TD>optional, only used with tinydns</TD></TR>
</TABLE> </TABLE>
<UL> <UL>
<LI><B>DNSzonename:</B> This field is rquired to describe the zone's domain name, for instance <LI><B>DNSzonename:</B> This field is required to describe the zone's domain name, for instance
myorg.com. More than one <B>DNSzonename</B> my be specified for a <B>DNSzone</B> so that the myorg.com. More than one <B>DNSzonename</B> my be specified for a <B>DNSzone</B> so that the
same host is accessable with different zonenames.</LI> same host is accessable with different zonenames.</LI>
<LI><B>DNSserial:</B> This is the serial number as used for BIND's zone transfers. Here it is <LI><B>DNSserial:</B> This is the serial number as used for BIND's zone transfers. Here it is
used to inform <B>ldap2dns</B> that it has to rebuild its data-file. Without increasing the serial used to inform <B>ldap2dns</B> that it has to rebuild its data-file. Without increasing the serial
number <B>ldap2dns</B> will do nothing.</LI> number <B>ldap2dns</B> will ignore all modifications until it is restarted.</LI>
<LI><B>DNSrefresh, DNSretry, DNSexpire, DNSminimum:</B> You may safly ignore these numbers <LI><B>DNSrefresh, DNSretry, DNSexpire, DNSminimum:</B> You may safly ignore these numbers
if You don't do zone-transfers. Since Your secondary nameserver will connect to the LDAP if You don't do zone-transfers. Since Your secondary nameserver will connect to the LDAP
server the same way Your primary does, You don't need zone-transfers anyway.</LI> server the same way Your primary does, You don't need zone-transfers anyway.</LI>
<LI><B>DNSzonemaster:</B> Here You specify the canonical name of Your primary nameserver.</LI> <LI><B>DNSzonemaster:</B> Here you specify the canonical name of your primary nameserver.</LI>
<LI><B>DNSadminmailbox:</B> This is the contact address of Your DNS-administrator. The first dot <LI><B>DNSadminmailbox:</B> This is the contact address of Your DNS-administrator. The first dot
is converted to a <I>@</I>.</LI> is converted to a <I>@</I>.</LI>
<LI><B>DNStype:</B> Must be <B>SOA</B> (which stands for Start Of Authority)</LI> <LI><B>DNStype:</B> Must be <B>SOA</B> (Start Of Authority)</LI>
<LI><B>DNSclass:</B> Must be <B>IN</B> (which stands for Internet, or do You have anything else?)</LI> <LI><B>DNSclass:</B> Must be <B>IN</B> (Internet, or do still use Chaosnet?)</LI>
<LI><B>DNSttl:</B> This is the time-to-live value as used by <B>tinydns</B>. <LI><B>DNSttl:</B> This is the time-to-live value as used by <B>tinydns</B>.
If TTL is nonzero (or omitted), the timestamp is a starting time from whereon this zone's If TTL is nonzero (or omitted), the timestamp is a starting time from whereon this zone's
@@ -129,35 +130,36 @@ a given host name within a zone. It must be a child of a DNSzone object.<BR>
<P> <P>
<UL> <UL>
<LI><B>DNSrrset:</B> This object-class must be a direct child of DNSzone. Its <B>dn</B> must be <LI><B>DNSrrset:</B> This object-class must be a direct child of DNSzone. Its <B>dn</B> should be
specified as <PRE>cn=<I>domainname</I>,cn=<I>zonename</I>,...</PRE></LI> specified as <PRE>cn=<I>domainname</I>,cn=<I>zonename</I>,...</PRE></LI>
<LI><B>DNSdomainname</B> This is the partial domainname, ie. the part in front of the <LI><B>DNSdomainname</B> This is the partial domain-name, ie. the part in front of the
zonename.</LI> zone-name.</LI>
<LI><B>DNSipaddr:</B> This specifies the IP-address in dotted format. It can be used for <B>DNSrrset</B>'s <LI><B>DNSipaddr:</B> This specifies the IP-address in dotted format. It can be used for <B>DNSrrset</B>'s
of type <B>A, NS, MX</B> or <B>PTR</B>. <B>DNSipaddr</B> is multivalued to specifiy more than one of type <B>A, NS, MX</B> or <B>PTR</B>. <B>DNSipaddr</B> is multivalued to specifiy more than one
IP-address for a service. If used in combination with <B>PTR</B> it overrides the old-fashioned form IP-address for a service. If used in <B>DNSrrset</B>'s with <B>DNStype</B> = <B>PTR</B> it
used in <B>DNSdomainname</B> such as 13.178.23.in-addr.arpa for reverse lookups.</LI> overrides the old-fashioned form used in <B>DNSdomainname</B> such as 13.178.23.in-addr.arpa
for reverse lookups.</LI>
<LI><B>DNScname:</B> Whereever there is a mapping of a domainname to a canonical name, use <LI><B>DNScname:</B> Whenever there is a mapping of a domain-name to a canonical name, use
this attribute. <B>DNScname</B> may be used for <B>DNSrrset</B>'s with <B>DNStype CNAME, this attribute. <B>DNScname</B> may be used for <B>DNSrrset</B>'s with <B>DNStype CNAME,
NS, MX, PTR or TXT</B>. If the last character of a CNAME is a dot its name is considered NS, MX, PTR or TXT</B>. If the last character of a CNAME is a dot its name is considered
absolute. If it does not contain a dot, it name is prepended to the zonename.</LI> absolute. If it does not contain a dot, its name is prepended to the zone-name.</LI>
<LI><B>DNSpreference:</B> This number is the mail-exchange preference as used by BIND.</LI> <LI><B>DNSpreference:</B> This number is the mail-exchange preference as used by BIND.</LI>
<LI><B>DNStype:</B> This must be <B>A, CNAME, NS, MX, PTR</B> or <B>TXT</B>. It specifies <LI><B>DNStype:</B> This must be <B>A, CNAME, NS, MX, PTR</B> or <B>TXT</B>. It specifies
the DNSrrset type.</LI> the DNSrrset type.</LI>
<LI><B>DNSclass:</B> Must be <B>IN</B> (which stands for Internet, or do You have anything else?)</LI> <LI><B>DNSclass:</B> Must be <B>IN</B></LI>
<LI><B>DNSttl:</B> This is the time-to-live value as used by <B>tinydns</B>. <LI><B>DNSttl:</B> This is the time-to-live value as used by <B>tinydns</B>.
If TTL is nonzero (or omitted), the timestamp is a starting time from whereon this zone's If TTL is non-zero (or omitted), the time-stamp is a starting time from where-on this zone's
information is valid. If TTL is zero, the timestamp is an ending time (``time to die'').</LI> information is valid. If TTL is zero, the timestamp is an ending time (``time to die'').</LI>
<LI><B>DNStimestamp:</B> This is the timestamp as used by <B>tinydns</B>. It represents a <LI><B>DNStimestamp:</B> This is the timestamp as used by <B>tinydns</B>. It represents a
string as external TAI64 timestamp, printed as 16 lowercase hexadecimal characters</LI> string as external TAI64 time-stamp, printed as 16 lowercase hexadecimal characters</LI>
</UL> </UL>
<P> <P>
@@ -167,22 +169,25 @@ string as external TAI64 timestamp, printed as 16 lowercase hexadecimal characte
LDAP implementations may work but have not been tested. Also install the LDAP implementations may work but have not been tested. Also install the
development libraries and include files.</LI> development libraries and include files.</LI>
<LI>Install <A HREF="http://cr.yp.to/djbdns.html">djbdns</A> or if You really <LI>Install <A HREF="http://cr.yp.to/djbdns.html">djbdns</A> or if you really
have to, go with BIND.<BR> have to, go with BIND.<BR>
I suggest to install tinydns included in the <B>djbdns</B> package, because it is I suggest to install <I>tinydns</I> included in the <B>djbdns</B> package, because it is
safer, but You may have reasons why You want to use BIND.</LI> safer, but You may have reasons why You want to use BIND.</LI>
<LI>Install <B>ldap2dns</B><BR> <LI>Install <B>ldap2dns</B><BR>
Unpack the package with gzcat ldap2dns.tar.gz | tar x Unpack the package and build it:
If You use <B>tinydns</B> put the directory dns2ldap onto <PRE>
the same directory level where You have the directory dnscache. gzcat ldap2dns.tar.gz | tar x
cd into the package and type make.</LI> cd ldap2dns-version
make
make install
</PRE>
If you run <B>ldap2dns</B> togther with tinydns, go into
/var/tinydns and run ldap2tinydns-conf.
</LI>
<LI>If You do not want to use tinydns edit the Makefile, <LI>Add the extra object-classes to the slapd.conf file.
comment the lines starting with WITHTINYDNS and ALIBS. Then do a make.</LI> If You are using openldap-1.2.x:<BR>
<LI>Now add the extra object-classes to the slapd.conf file. To do this
if You are using openldap-1.2.x:<BR>
copy the files dns.oc.conf and dns.ac.conf into the directory /etc/openldap or copy the files dns.oc.conf and dns.ac.conf into the directory /etc/openldap or
appropriate and add the following two lines to Your slapd.conf file:<BR> appropriate and add the following two lines to Your slapd.conf file:<BR>
<PRE> <PRE>
@@ -195,10 +200,10 @@ appropriate and add the following line to Your slapd.conf file:<BR>
<PRE> <PRE>
include /etc/openldap/schema/dns.schema include /etc/openldap/schema/dns.schema
</PRE> </PRE>
Now restart Your LDAP server.</LI> Now restart your LDAP server.</LI>
<P> <P>
<LI>Start to populate Your LDAP server with DNS information, as a first test do <LI>Start to populate your LDAP server with DNS information. As a first test do
<PRE> <PRE>
$ ldapadd -D "<I>binddn</I>" -w <I>password</I> < example.ldif $ ldapadd -D "<I>binddn</I>" -w <I>password</I> < example.ldif
</PRE> </PRE>
@@ -210,17 +215,13 @@ $ ldapsearch -D "<I>binddn</I>" "objectclass=dnsrrset" </LI>
<LI>Test <B>ldap2dns</B> <LI>Test <B>ldap2dns</B>
<PRE> <PRE>
$ ./ldap2dns -D "<I>binddn</I>" [ -b "<I>searchbase</I>" ] [ -w <I>passwd</I> ] -o 7 -L $ ./ldap2dns -D "<I>binddn</I>" [ -b "<I>searchbase</I>" ] [ -w <I>passwd</I> ] -o data -o db -L
</PRE> </PRE>
This should create a 'data' file, a 'data.cdb' file, a 'corp.local.db' This should create a 'data' file, a 'corp.local.db' file and should print the
file and should print the DNS content. If You disabled the tinydns DNS content.<BR>
option no 'data.cdb' file is generated.<BR> Note: The <I>data</I> file is text data which can be processed with <B>tinydns-data</B>.
Note: The 'data' file is text data which can be processed with tinydns-data. <I>corp.local.db</I> is the file as used by <B>named</B>. If You are using bind, You also
The 'data.cdb' file is the binary version of 'data' processed as tinydns-data have to adopt the file <I>/etc/named.conf</I> and You have to restart named.</LI>
would. You must not restart tinydns to inform about the modification as You
would have with named.<BR>
'corp.local.db' is the file as used by named. If You are using bind, You also
have to adopt the file '/etc/named.conf' and You have to restart named. </LI>
</UL> </UL>
<P> <P>
@@ -229,10 +230,12 @@ If You are a tinydns user, run <B>ldap2dns</B> in /services/tinydns/root.<BR>
If You are an openldap user, the command line switches are the same as for ldapsearch If You are an openldap user, the command line switches are the same as for ldapsearch
or ldapadd. or ldapadd.
<PRE> <PRE>
$ ldap2dns -D "<I>binddn</I>" [ -w <I>passwd</I> ] -b "<I>searchbase</I>" -o 1 $ ldap2dns -D "<I>binddn</I>" [ -w <I>passwd</I> ] -b "<I>searchbase</I>" -o data -e "cd /var/tinydns/root && /usr/bin/tinydns-data"
</PRE> </PRE>
This generates a data.cdb file which is automatically updated by tinydns. The password This generates a data file which is converted into a data.cdb by tinydns-data as
is required if You restrict read queries to authenticated users only. Now test with soon as ldap2dns detects a modification in the LDAP directory.
The password is required if You restrict read queries to authenticated users only.
Test with
<PRE> <PRE>
$ dnsq any corp.local <I>ipaddr</I> $ dnsq any corp.local <I>ipaddr</I>
</PRE> </PRE>
@@ -241,10 +244,11 @@ Replace <I>ipaddr</I> with whatever You configured tinydns to listen to.
If You are a BIND user, run <B>ldap2dns</B> in /var/named with If You are a BIND user, run <B>ldap2dns</B> in /var/named with
<PRE> <PRE>
$ ldap2dns -D "<I>binddn</I>" -w <I>passwd</I> -b "<I>searchbase</I>" -o 4 $ ldap2dns -D "<I>binddn</I>" -w <I>passwd</I> -b "<I>searchbase</I>" -o db -e "kill -HUP `cat /var/run/named-pid`"
</PRE> </PRE>
Do not forget to add You primary definition to Your named.boot file and Do not forget to add You primary definition to Your named.boot file.
do not forget to restart named with Your named should be restarted automatically as soon as ldap2dns detects a modification
in the LDAP directory. If bind is not restarted, do so with
<PRE> <PRE>
# kill -HUP <I>PID</I> # kill -HUP <I>PID</I>
</PRE> </PRE>
@@ -253,15 +257,16 @@ Now run
$ nslookup - localhost $ nslookup - localhost
> ns1.corp.local > ns1.corp.local
</PRE> </PRE>
Note that nslookup only works with tinydns if Your nameserver resolves its IP-address Note that <B>nslookup</B> only works with <B>tinydns</B> if Your nameserver resolves its IP-address
backwards. backwards.
<P> <P>
<H3>4. Running ldap2dnsd</H3> <H3>4. Running ldap2dnsd</H3>
<B>ldap2dnsd</B> is a hard link onto <B>ldap2dns</B>. If invoked the program <B>ldap2dnsd</B> is a hard link onto <B>ldap2dns</B>. If invoked, the program
starts as backgound-daemon and contineously checks for modifications in the LDAP directory. starts as backgound-daemon and contineously checks for modifications in the LDAP directory.
If the the daemon sees a modification in the <B>DNSserial</B> numbers it updates the data.cdb If the the daemon sees a modification in the <B>DNSserial</B> numbers it updates the data
file. This check is done about once a minute.<BR> or .db files, depending what kind of output was configured. This check is done about once
a minute.<BR>
The command-line options for <B>ldap2dnsd</B> are the same as for <B>ldap2dns</B>. The command-line options for <B>ldap2dnsd</B> are the same as for <B>ldap2dns</B>.
Use the -u option to modify the update intervall. You may also use -u on <B>ldap2dns</B> Use the -u option to modify the update intervall. You may also use -u on <B>ldap2dns</B>
to start as a foreground daemon. This is useful if You want to run <B>ldap2dns</B> from to start as a foreground daemon. This is useful if You want to run <B>ldap2dns</B> from
@@ -270,7 +275,7 @@ in /service/tinydns and link /service/ldap2dns onto /service/tinydns/ldap2dns.
<PRE> <PRE>
# ln -s /service/tinydns/ldap2dns /service/ldap2dns # ln -s /service/tinydns/ldap2dns /service/ldap2dns
</PRE> </PRE>
After a few seconds <B>daemontools</B> starts <B>ldap2dns</B> which itself generates data.cdb After a few seconds <B>daemontools</B> starts <B>ldap2dns</B> which itself generates data
files whenever a modification is commited into the LDAP directory. files whenever a modification is commited into the LDAP directory.
<P> <P>
<B>ldap2dns</B> and <B>ldap2dnsd</B> recognize the following options: <B>ldap2dns</B> and <B>ldap2dnsd</B> recognize the following options:
@@ -278,22 +283,30 @@ files whenever a modification is commited into the LDAP directory.
-D <I>binddn</I> specify the distinguished name to bind to the LDAP directory -D <I>binddn</I> specify the distinguished name to bind to the LDAP directory
-w <I>bindpasswd</I> use bindpasswd as the password for simple authentication -w <I>bindpasswd</I> use bindpasswd as the password for simple authentication
-b <I>searchbase</I> use searchbase as the starting point for the search instead of the default -b <I>searchbase</I> use searchbase as the starting point for the search instead of the default
-o 1|2|4 output format number or any binary or-ed combination. Defaults to 1 -o Generate a "data" file to be processed by tinydns-data.
1: generate a binary file named 'data.cdb' to be used directly by tinydns -o db For each zone generate a "<zonename>.db" file to be used by named.
2: generate a text file named 'data' to be parsed by tinydns-data -L[<I>filename</I>] print output in LDIF format for reimport. If no filename is specified output goes to stdout.
4: for each zone generate a file named '<zonename>.db' to be used by named -h <I>host</I> specify the hostname of LDAP directory. Default is localhost.
-L[<I>filename</I>] print output in LDIF format for reimport, defaults to stdout if filename is omitted -p <I>port</I> portnumber to connect to LDAP directory. Defaults is 389
-h <I>host</I> specify the hostname of LDAP directory, defaults to localhost
-p <I>port</I> portnumber to connect to LDAP directory, defaults to 389
-v run in verbose mode -v run in verbose mode
-vv even more verbose -vv even more verbose
-V print version and exit -V print version and exit
-u <I>numsecs</I> update DNS data every numsecs. If started as ldap2dnsd this defaults to 59. -u <I>numsecs</I> update DNS data every numsecs.
</PRE> </PRE>
<B>ldap2dns</B> and <B>ldap2dnsd</B> recognizes the following environement variables:<BR>
<B>TINYDNSDIR</B>: Specifies the directory where ldap2dns writes its data file.<BR>
<B>LDAP2DNS_UPDATE</B>: Specifies the update intervall as the -u command line option would.<BR>
<B>LDAP2DNS_OUTPUT</B>: Specifies the default output, as the -o command line option would.
<P>
<B>ldap2dns</B> and <B>ldap2dnsd</B> use the following parameters from /etc/ldap.conf if not
specified on the command line:
<B>BASE</B>: The LDAP search base.<BR>
<B>HOST</B>: The LDAP server.<BR>
<B>PORT</B>: The LDAP port.
<P> <P>
<H3>5. Importing DNS data from Your named</H3> <H3>5. Importing DNS data from Your named</H3>
A perl-script 'import.pl' is contained in this package. Edit the first A perl-script <I>import.pl</I> is contained in this package. Edit the first
lines of the script to conform to Your configuration. lines of the script to conform to Your configuration.
If You have installed the Perl packages Net::LDAP and Net::DNS If You have installed the Perl packages Net::LDAP and Net::DNS
skip the following lines, otherwise do skip the following lines, otherwise do
@@ -303,7 +316,7 @@ skip the following lines, otherwise do
> install Net::DNS > install Net::DNS
> install Net::LDAP > install Net::LDAP
</PRE> </PRE>
Now check that Your nameserver allows zone transfers to Your host and run the import script: Now check that Your nameserver allows zone transfers to your host and run the import script:
<PRE> <PRE>
$ echo 'primary mydomain.org ' | ./import.pl $ echo 'primary mydomain.org ' | ./import.pl
</PRE> </PRE>
@@ -314,19 +327,17 @@ for a single domain or
to populate Your LDAP directory. to populate Your LDAP directory.
<P> <P>
<H3>5. To Do</H3> <H3>6. To Do</H3>
<UL> <UL>
<LI>Write a man page.</LI> <LI>Write a man page.</LI>
<LI><B>named</B> should be restarted automatically sending a HUP signal to the appropriate daemon.</LI>
<LI>named.conf should be created automatically.</LI> <LI>named.conf should be created automatically.</LI>
<LI>The option -o is not very nice.</LI>
</UL> </UL>
<P> <P>
<H3>6. Copyright</H3> <H3>7. Copyright and disclaimer</H3>
This program is licensed under the GPL version 2 or at Your choice any later This program is licensed under the GPL version 2 or at Your choice any later
version.<BR> version.<BR>
It was written in autumn 2000 by It is maintained by <A HREF="mailto:jacob.rief@tiscover.com?subject=ldap2dns">Jacob Rief</A>.
<A HREF="mailto:jacob.rief@bigfoot.com?subject=ldap2dns">Jacob Rief</A> If you run <B>ldap2dns</B> on a productive nameserver, please mail me
in the hope it may be useful. and tell me on what OS and with which nameserver you do so.

View File

@@ -24,15 +24,18 @@ ldap2dns is designed to write binary data.cdb files used by tinydns, but also ma
used to write .db-files used by named. used to write .db-files used by named.
%prep %prep
%setup -a1 -q #%setup -a1 -q
%setup
%build %build
make -C %{djbdns} #make -C %{djbdns}
make DJBDNSDIR="%{djbdns}" VERSION=%{version} RPM_OPT_FLAGS="$RPM_OPT_FLAGS" #make DJBDNSDIR="%{djbdns}" VERSION=%{version} RPM_OPT_FLAGS="$RPM_OPT_FLAGS"
make VERSION=%{version} RPM_OPT_FLAGS="$RPM_OPT_FLAGS"
%install %install
[ -n "%{buildroot}" -a "%{buildroot}" != / ] && rm -rf %{buildroot} [ -n "%{buildroot}" -a "%{buildroot}" != / ] && rm -rf %{buildroot}
make DJBDNSDIR="%{djbdns}" INSTALL_PREFIX=$RPM_BUILD_ROOT install #make DJBDNSDIR="%{djbdns}" INSTALL_PREFIX=$RPM_BUILD_ROOT install
make INSTALL_PREFIX=$RPM_BUILD_ROOT install
%clean %clean
[ -n "%{buildroot}" -a "%{buildroot}" != / ] && rm -rf %{buildroot} [ -n "%{buildroot}" -a "%{buildroot}" != / ] && rm -rf %{buildroot}

3
TODO Normal file
View File

@@ -0,0 +1,3 @@
- Use env-variable LDAP2DNS_UPDATE for update intervalls
- If connection to ldapserver fialed retry later

View File

@@ -1,6 +1,6 @@
# schema for DNS data # schema for DNS data
# include this file into Your slapd.conf for openldap-2.0.x # include this file into Your slapd.conf for openldap-2.0.x
# $Id: dns.schema,v 1.3 2000/12/01 14:48:25 jrief Exp $ # $Id: dns.schema,v 1.4 2001/02/16 09:51:23 jrief Exp $
attributetype ( 1.2.840.113556.1.17.1 attributetype ( 1.2.840.113556.1.17.1
NAME 'DNSzonename' NAME 'DNSzonename'
@@ -98,14 +98,14 @@ attributetype ( 1.2.840.113556.1.17.20
objectclass ( 1.2.840.113556.1.17.21 objectclass ( 1.2.840.113556.1.17.21
NAME 'DNSzone' NAME 'DNSzone'
MUST ( objectclass $ cn ) MUST ( objectclass $ cn )
MAY ( zonedomainname $ serial $ refresh $ retry $ expire $ minimum MAY ( DNSdomainname $ DNSserial $ DNSrefresh $ DNSretry $ DNSexpire $ DNSminimum
$ adminmailbox $ zonemaster $ zonetype $ zoneclass $ rrcount $ DNSadminmailbox $ DNSzonemaster $ DNSzonetype $ DNSzoneclass $ DNSrrcount
$ ttl $ timestamp ) ) $ DNSttl $ DNStimestamp ) )
objectclass ( 1.2.840.113556.1.17.22 objectclass ( 1.2.840.113556.1.17.22
NAME 'DNSrrset' NAME 'DNSrrset'
SUP DNSzone SUP DNSzone
MUST ( objectclass $ cn ) MUST ( objectclass $ cn )
MAY ( dnsdomainname $ aliasedobjectname $ rr $ macaddress $ zoneclass MAY ( DNSdomainname $ DNSaliasedobjectname $ DNSrr $ DNSmacaddress $ DNSclass
$ zonetype $ ipaddr $ cname $ preference $ ttl $ timestamp ) ) $ DNStype $ DNSipaddr $ DNScname $ DNSpreference $ DNSttl $ DNStimestamp ) )

View File

@@ -23,7 +23,7 @@
> >
<BLOCKQUOTE> <BLOCKQUOTE>
<P> <P>
<!--#include file="README.html"---> <!--#include file="ldap2dns/README.html"-->
<P> <P>
<H3 align=center>Download</H3> <H3 align=center>Download</H3>
<TABLE border=2 cellpadding=4 align=center> <TABLE border=2 cellpadding=4 align=center>
@@ -33,6 +33,7 @@
<TR align=center><TD>0.1.3</TD><TD><A HREF="ldap2dns-0.1.3.tar.gz">ldap2dns</A></TD><TD></TD><TD></TD><TD>2000-Sep-28</TD></TR> <TR align=center><TD>0.1.3</TD><TD><A HREF="ldap2dns-0.1.3.tar.gz">ldap2dns</A></TD><TD></TD><TD></TD><TD>2000-Sep-28</TD></TR>
<TR align=center><TD>0.1.4</TD><TD><A HREF="ldap2dns-0.1.4.tar.gz">ldap2dns</A></TD><TD></TD><TD></TD><TD>2000-Oct-04</TD></TR> <TR align=center><TD>0.1.4</TD><TD><A HREF="ldap2dns-0.1.4.tar.gz">ldap2dns</A></TD><TD></TD><TD></TD><TD>2000-Oct-04</TD></TR>
<TR align=center><TD>0.2.0</TD><TD><A HREF="ldap2dns-0.2.0.tar.gz">ldap2dns</A></TD><TD><A HREF="ldap2dns-0.2.0-1.i386.rpm">ldap2dns</A></TD><TD><A HREF="ldap2dns-0.2.0-1.src.rpm">ldap2dns</A></TD><TD>2000-Dec-14</TD></TR> <TR align=center><TD>0.2.0</TD><TD><A HREF="ldap2dns-0.2.0.tar.gz">ldap2dns</A></TD><TD><A HREF="ldap2dns-0.2.0-1.i386.rpm">ldap2dns</A></TD><TD><A HREF="ldap2dns-0.2.0-1.src.rpm">ldap2dns</A></TD><TD>2000-Dec-14</TD></TR>
<TR align=center><TD>0.2.2</TD><TD><A HREF="ldap2dns-0.2.2.tar.gz">ldap2dns</A></TD><TD><A HREF="ldap2dns-0.2.2-2.i386.rpm">ldap2dns</A></TD><TD><A HREF="ldap2dns-0.2.2-2.src.rpm">ldap2dns</A></TD><TD>2001-Feb-16</TD></TR>
</TABLE> </TABLE>
</BLOCKQUOTE> </BLOCKQUOTE>

View File

@@ -1,6 +1,6 @@
/* /*
* Create data from an LDAP directory service to be used for tinydns * Create data from an LDAP directory service to be used for tinydns
* $Id: ldap2dns.c,v 1.20 2000/12/12 09:48:07 jrief Exp $ * $Id: ldap2dns.c,v 1.26 2001/02/27 10:08:31 jrief Exp $
* Copyright 2000 by Jacob Rief <jacob.rief@tiscover.com> * Copyright 2000 by Jacob Rief <jacob.rief@tiscover.com>
* License: GPL version 2 or later. See http://www.fsf.org for details * License: GPL version 2 or later. See http://www.fsf.org for details
*/ */
@@ -15,44 +15,17 @@
#define UPDATE_INTERVALL 59 #define UPDATE_INTERVALL 59
#define LDAP_CONF "/etc/openldap/ldap.conf" #define LDAP_CONF "/etc/openldap/ldap.conf"
#define OUTPUT_DATA 1
#if defined WITH_TINYDNS #define OUTPUT_DB 2
# include "uint16.h"
# include "uint32.h"
# include "str.h"
# include "byte.h"
# include "fmt.h"
# include "ip4.h"
# include "exit.h"
# include "readwrite.h"
# include "buffer.h"
# include "strerr.h"
# include "getln.h"
# include "cdb_make.h"
# include "stralloc.h"
# include "open.h"
# include "dns.h"
int fdcdb;
struct cdb_make cdb;
buffer b;
char bspace[1024];
static stralloc key;
static stralloc result;
static char* dottemp1;
static char* dottemp2;
static char tinydns_datafile[256];
static char tinydns_tempfile[256];
#endif
static char tinydns_textfile[256]; static char tinydns_textfile[256];
static char tinydns_texttemp[256];
static LDAP* ldap_con; static LDAP* ldap_con;
static FILE* bindfile; static FILE* namedmaster;
static FILE* namedzone;
static FILE* tinyfile; static FILE* tinyfile;
static FILE* ldifout; static FILE* ldifout;
static time_t time_now; static time_t time_now;
static int autoreverse;
static char* const* main_argv; static char* const* main_argv;
static int main_argc; static int main_argc;
@@ -75,14 +48,15 @@ static struct
{ {
char domainname[64]; char domainname[64];
char zonemaster[64]; char zonemaster[64];
char class[16];
char adminmailbox[64]; char adminmailbox[64];
unsigned long serial; unsigned long serial;
unsigned long refresh; unsigned long refresh;
unsigned long retry; unsigned long retry;
unsigned long expire; unsigned long expire;
unsigned long minimum; unsigned long minimum;
char timestamp[20];
int ttl; int ttl;
char timestamp[16];
} zone; } zone;
struct resourcerecord struct resourcerecord
@@ -92,9 +66,10 @@ struct resourcerecord
char class[16]; char class[16];
char type[16]; char type[16];
char ipaddr[256][32]; char ipaddr[256][32];
char cipaddr[32];
char cname[64]; char cname[64];
char timestamp[20];
int ttl; int ttl;
char timestamp[16];
int preference; int preference;
#if defined DRAFT_RFC #if defined DRAFT_RFC
char rr[1024]; char rr[1024];
@@ -116,6 +91,7 @@ static struct
unsigned int output; unsigned int output;
int verbose; int verbose;
char ldifname[128]; char ldifname[128];
char exec_command[128];
} options; } options;
@@ -129,96 +105,46 @@ static void die_exit(const char* message)
} }
#if defined WITH_TINYDNS
static void rr_add(char *buf, unsigned int len)
{
if (!stralloc_catb(&result, buf, len)) die_exit(0);
}
static void rr_addname(char *d)
{
rr_add(d,dns_domain_length(d));
}
static void rr_start(char type[2], unsigned long ttl, char ttd[8])
{
char buf[4];
if (!stralloc_copyb(&result, type,2)) die_exit(0);
rr_add("=",1);
uint32_pack_big(buf, ttl);
rr_add(buf,4);
rr_add(ttd,8);
}
static void rr_finish(char *owner)
{
if (byte_equal(owner,2,"\1*")) {
owner += 2;
result.s[2] = '*';
}
if (!stralloc_copyb(&key, owner, dns_domain_length(owner))) die_exit(0);
case_lowerb(key.s, key.len);
if (cdb_make_add(&cdb, key.s, key.len, result.s, result.len) == -1)
die_exit("Unable to create 'data.tmp'");
}
#endif
static void set_datadir(void) static void set_datadir(void)
{ {
char* ev = getenv("TINYDNSDIR"); char* ev = getenv("TINYDNSDIR");
int len; int len;
#if defined WITH_TINYDNS tinydns_textfile[0] = '\0';
tinydns_datafile[0] = 0; tinydns_texttemp[0] = '\0';
tinydns_tempfile[0] = 0;
#endif
tinydns_textfile[0] = 0;
if (ev && (len = strlen(ev))<240) { if (ev && (len = strlen(ev))<240) {
#if defined WITH_TINYDNS
strncpy(tinydns_datafile, ev, 240);
strncpy(tinydns_tempfile, ev, 240);
#endif
strncpy(tinydns_textfile, ev, 240); strncpy(tinydns_textfile, ev, 240);
strncpy(tinydns_texttemp, ev, 240);
if (ev[len-1]!='/') { if (ev[len-1]!='/') {
#if defined WITH_TINYDNS
tinydns_datafile[len] = '/';
tinydns_tempfile[len] = '/';
#endif
tinydns_textfile[len] = '/'; tinydns_textfile[len] = '/';
tinydns_texttemp[len] = '/';
} }
} }
#if defined WITH_TINYDNS
strcat(tinydns_datafile, "data.cdb");
strcat(tinydns_tempfile, "data.tmp");
#endif
strcat(tinydns_textfile, "data"); strcat(tinydns_textfile, "data");
strcat(tinydns_texttemp, "data.temp");
} }
static void print_usage(void) static void print_usage(void)
{ {
print_version(); print_version();
printf("usage: ldap2dns[d] [-D binddn] [-b searchbase] [-o 0|1|2|4] [-h host] [-p port] [-w password] [-L[filename]] [-u numsecs] [-v[v]] [-V]\n\n"); printf("usage: ldap2dns[d] [-D binddn] [-b searchbase] [-o data|db] [-h host] [-p port] [-w password] [-L[filename]] [-u numsecs] [-v[v]] [-V]\n\n");
printf("ldap2dns connects to an LDAP server reads the DNS information stored in objectclasses\n" printf("ldap2dns connects to an LDAP server reads the DNS information stored in objectclasses\n"
"\t\tDNSzone and DNSrrset and writes a file to be used by tinydns or named.\n" "\t\tDNSzone and DNSrrset and writes a file to be used by tinydns or named.\n"
"\t\tldap2dnsd starts as background-job and continouesly updates DNS information.\n"); "\t\tldap2dnsd starts as background-job and continouesly updates DNS information.\n");
printf("options:\n"); printf("options:\n");
printf(" -D binddn\tUse the distinguished name binddn to bind to the LDAP directory\n"); printf(" -D binddn\tUse the distinguished name binddn to bind to the LDAP directory\n");
printf(" -w bindpasswd\tUse bindpasswd as the password for simple authentication\n"); printf(" -w bindpasswd\tUse bindpasswd as the password for simple authentication\n");
printf(" -b use searchbase as the starting point for the search instead of the default\n"); printf(" -b Use searchbase as the starting point for the search instead of the default\n");
printf(" -o 1|2|4\toutput format number or any binary or-ed combination. Defaults to 1\n"); printf(" -o data\tGenerate a \"data\" file to be processed by tinydns-data\n");
printf("\t1: generate a binary file named 'data.cdb' to be used directly by tinydns\n"); printf(" -o db\tFor each zone generate a \"<zonename>.db\" file to be used by named\n");
printf("\t2: generate a text file named 'data' to be parsed by tinydns-data\n"); printf(" -L[filename] Print output in LDIF format for reimport\n");
printf("\t4: for each zone generate a file named '<zonename>.db' to be used by named\n"); printf(" -h host\tHostname of LDAP server, defaults to localhost\n");
printf(" -L[filename] print output in LDIF format for reimport\n"); printf(" -p port\tPortnumber to connect to LDAP server, defaults to %d\n", LDAP_PORT);
printf(" -h host\thostname of LDAP server, defaults to localhost\n");
printf(" -p port\tportnumber to connect to LDAP server, defaults to %d\n", LDAP_PORT);
printf(" -u numsecs\tUpdate DNS data after numsecs. Defaults to %d if started as daemon.\n\t\t" printf(" -u numsecs\tUpdate DNS data after numsecs. Defaults to %d if started as daemon.\n\t\t"
"Important notice: data.cdb is rewritten only after DNSserial in DNSzone is increased.\n", "Important notice: data.cdb is rewritten only after DNSserial in DNSzone is increased.\n",
UPDATE_INTERVALL); UPDATE_INTERVALL);
printf(" -e \"exec-cmd\" This command is executed after ldap2dns regenerated its data files\n");
printf(" -v\t\trun in verbose mode\n"); printf(" -v\t\trun in verbose mode\n");
printf(" -vv\t\teven more verbose\n"); printf(" -vv\t\teven more verbose\n");
printf(" -V\t\tprint version and exit\n\n"); printf(" -V\t\tprint version and exit\n\n");
@@ -229,8 +155,9 @@ static int parse_options()
extern char* optarg; extern char* optarg;
extern int optind, opterr, optopt; extern int optind, opterr, optopt;
char buf[256], value[128]; char buf[256], value[128];
int c; int len;
FILE* ldap_conf; FILE* ldap_conf;
char* ev;
strcpy(options.searchbase, ""); strcpy(options.searchbase, "");
strcpy(options.hostname, "localhost"); strcpy(options.hostname, "localhost");
@@ -239,33 +166,46 @@ static int parse_options()
while(fgets(buf, 256, ldap_conf)!=0) { while(fgets(buf, 256, ldap_conf)!=0) {
if (sscanf(buf, "BASE %128s", value)==1) if (sscanf(buf, "BASE %128s", value)==1)
strcpy(options.searchbase, value); strcpy(options.searchbase, value);
if (sscanf(buf, "HOST %128s:%d", value, &c)==2) { if (sscanf(buf, "HOST %128s:%d", value, &len)==2) {
strcpy(options.hostname, value); strcpy(options.hostname, value);
options.port = c; options.port = len;
} else if (sscanf(buf, "HOST %128s", value)==1) } else if (sscanf(buf, "HOST %128s", value)==1)
strcpy(options.hostname, value); strcpy(options.hostname, value);
if (sscanf(buf, "PORT %d", &c)==1) if (sscanf(buf, "PORT %d", &len)==1)
options.port = c; options.port = len;
} }
fclose(ldap_conf); fclose(ldap_conf);
} }
strcpy(options.binddn, ""); strcpy(options.binddn, "");
options.output = 1; len = strlen(main_argv[0]);
if (strcmp(main_argv[0]+len-9, "ldap2dnsd")==0) {
options.is_daemon = 1;
options.update_iv = UPDATE_INTERVALL;
} else {
options.is_daemon = 0;
options.update_iv = 0;
}
ev = getenv("LDAP2DNS_UPDATE");
if (ev && sscanf(ev, "%d", &len)==1 && len>0)
options.update_iv = len;
options.output = 0;
ev = getenv("LDAP2DNS_OUTPUT");
if (ev) {
if (strcmp(ev, "data")==0)
options.output = OUTPUT_DATA;
else if (strcmp(ev, "db")==0)
options.output = OUTPUT_DB;
}
options.verbose = 0; options.verbose = 0;
options.ldifname[0] = '\0'; options.ldifname[0] = '\0';
c = strlen(main_argv[0]);
if (strcmp(main_argv[0]+c-9, "ldap2dnsd")==0)
options.is_daemon = 1;
else
options.is_daemon = 0;
options.update_iv = 59;
strcpy(options.password, ""); strcpy(options.password, "");
while ( (c = getopt(main_argc, main_argv, "b:D:h:o:p:u:Vw:v::L::"))>0 ) { strcpy(options.exec_command, "");
while ( (len = getopt(main_argc, main_argv, "b:D:e:h:o:p:u:Vw:v::L::"))>0 ) {
if (optarg && strlen(optarg)>127) { if (optarg && strlen(optarg)>127) {
fprintf(stderr, "argument %s too long\n", optarg); fprintf(stderr, "argument %s too long\n", optarg);
continue; continue;
} }
switch (c) { switch (len) {
case 'b': case 'b':
strcpy(options.searchbase, optarg); strcpy(options.searchbase, optarg);
break; break;
@@ -273,7 +213,6 @@ static int parse_options()
if (sscanf(optarg, "%d", &options.update_iv)!=1) if (sscanf(optarg, "%d", &options.update_iv)!=1)
options.update_iv = UPDATE_INTERVALL; options.update_iv = UPDATE_INTERVALL;
if (options.update_iv<=0) options.update_iv = 1; if (options.update_iv<=0) options.update_iv = 1;
if (options.is_daemon==0) options.is_daemon = 2; /* foreground daemon */
break; break;
case 'D': case 'D':
strcpy(options.binddn, optarg); strcpy(options.binddn, optarg);
@@ -288,8 +227,10 @@ static int parse_options()
strcpy(options.ldifname, optarg); strcpy(options.ldifname, optarg);
break; break;
case 'o': case 'o':
if (sscanf(optarg, "%d", &options.output)!=1) if (strcmp(optarg, "data")==0)
options.output = 0; options.output |= OUTPUT_DATA;
else if (strcmp(optarg, "db")==0)
options.output |= OUTPUT_DB;
break; break;
case 'p': case 'p':
if (sscanf(optarg, "%d", &options.port)!=1) if (sscanf(optarg, "%d", &options.port)!=1)
@@ -307,11 +248,16 @@ static int parse_options()
case 'w': case 'w':
strcpy(options.password, optarg); strcpy(options.password, optarg);
break; break;
case 'e':
strcpy(options.exec_command, optarg);
break;
default: default:
print_usage(); print_usage();
exit(1); exit(1);
} }
} }
if (options.is_daemon==0 && options.update_iv>0)
options.is_daemon = 2; /* foreground daemon */
} }
@@ -341,86 +287,74 @@ static int expand_reverse(char target[64], const char* source)
} }
static void write_rr(struct resourcerecord* rr, int ipdx) static void write_rr(struct resourcerecord* rr, int ipdx, int znix)
{ {
char ip[4]; char ip[4];
char buf[4]; char buf[4];
if (strcasecmp(rr->class, "IN")) if (strcasecmp(rr->class, "IN"))
return; return;
#if defined WITH_TINYDNS
if (options.output&1) {
int dnsdn_len = strlen(rr->dnsdomainname);
int cname_len = strlen(rr->cname);
if (!dns_domain_fromdot(&dottemp1, rr->dnsdomainname, dnsdn_len)) die_exit(0);
if (!dns_domain_fromdot(&dottemp2, rr->cname, cname_len)) die_exit(0);
}
#endif
if (strcasecmp(rr->type, "NS")==0) { if (strcasecmp(rr->type, "NS")==0) {
if (tinyfile) if (tinyfile) {
fprintf(tinyfile, "&%s:%s:%s:%d:%s\n", rr->dnsdomainname, (ipdx>=0 ? rr->ipaddr[ipdx] : ""), rr->cname, rr->ttl, rr->timestamp); if (znix==0) {
if (bindfile) { if (ipdx<=0 && rr->cipaddr[0]) {
fprintf(bindfile, "%s.\tIN NS\t%s.\n", rr->dnsdomainname, rr->cname); fprintf(tinyfile, "&%s::%s:%d:%s\n", rr->dnsdomainname, rr->cname, rr->ttl, rr->timestamp);
if (rr->cname[0])
fprintf(tinyfile, "=%s:%s:%d:%s\n", rr->cname, rr->cipaddr, rr->ttl, rr->timestamp);
if (ipdx==0)
fprintf(tinyfile, "+%s:%s:%d:%s\n", rr->cname, rr->ipaddr[0], rr->ttl, rr->timestamp);
} else if (ipdx<0)
fprintf(tinyfile, "&%s::%s:%d:%s\n", rr->dnsdomainname, rr->cname, rr->ttl, rr->timestamp);
else if (ipdx==0)
fprintf(tinyfile, "&%s:%s:%s:%d:%s\n", rr->dnsdomainname, rr->ipaddr[0], rr->cname, rr->ttl, rr->timestamp);
else if (ipdx>0 && rr->cname[0])
fprintf(tinyfile, "+%s:%s:%d:%s\n", rr->cname, rr->ipaddr[ipdx], rr->ttl, rr->timestamp);
} else if (ipdx<=0) {
fprintf(tinyfile, "&%s::%s:%d:%s\n", rr->dnsdomainname, rr->cname, rr->ttl, rr->timestamp);
}
}
if (namedzone) {
fprintf(namedzone, "%s.\tIN NS\t%s.\n", rr->dnsdomainname, rr->cname);
if (ipdx>=0) if (ipdx>=0)
fprintf(bindfile, "%s.\tIN A\t%s\n", rr->cname, rr->ipaddr[ipdx]); fprintf(namedzone, "%s.\tIN A\t%s\n", rr->cname, rr->ipaddr[ipdx]);
} }
#if defined WITH_TINYDNS
if (options.output&1) {
rr_start(DNS_T_NS, rr->ttl, rr->timestamp);
rr_addname(dottemp2);
rr_finish(dottemp1);
if (ipdx>=0 && ip4_scan(rr->ipaddr[ipdx], ip)) {
rr_start(DNS_T_A, rr->ttl, rr->timestamp);
rr_add(ip, 4);
rr_finish(dottemp2);
}
}
#endif
} else if (strcasecmp(rr->type, "MX")==0) { } else if (strcasecmp(rr->type, "MX")==0) {
if (tinyfile) if (tinyfile) {
fprintf(tinyfile, "@%s:%s:%s:%d:%d:%s\n", rr->dnsdomainname, (ipdx>=0 ? rr->ipaddr[ipdx] : ""), rr->cname, rr->preference, rr->ttl, rr->timestamp); if (znix==0) {
if (bindfile) { if (ipdx<=0 && rr->cipaddr[0]) {
fprintf(bindfile, "%s.\tIN MX\t%d %s.\n", rr->dnsdomainname, rr->preference, rr->cname); fprintf(tinyfile, "@%s::%s:%d:%d:%s\n", rr->dnsdomainname, rr->cname, rr->preference, rr->ttl, rr->timestamp);
if (rr->cname[0])
fprintf(tinyfile, "=%s:%s:%d:%s\n", rr->cname, rr->cipaddr, rr->ttl, rr->timestamp);
if (ipdx==0)
fprintf(tinyfile, "+%s:%s:%d:%s\n", rr->cname, rr->ipaddr[0], rr->ttl, rr->timestamp);
} else if (ipdx<0)
fprintf(tinyfile, "@%s::%s:%d:%d:%s\n", rr->dnsdomainname, rr->cname, rr->preference, rr->ttl, rr->timestamp);
else if (ipdx==0)
fprintf(tinyfile, "@%s:%s:%s:%d:%d:%s\n", rr->dnsdomainname, rr->ipaddr[0], rr->cname, rr->preference, rr->ttl, rr->timestamp);
else if (ipdx>0 && rr->cname[0])
fprintf(tinyfile, "+%s:%s:%d:%s\n", rr->cname, rr->ipaddr[ipdx], rr->ttl, rr->timestamp);
} else if (ipdx<=0) {
fprintf(tinyfile, "@%s::%s:%d:%d:%s\n", rr->dnsdomainname, rr->cname, rr->preference, rr->ttl, rr->timestamp);
}
}
if (namedzone) {
fprintf(namedzone, "%s.\tIN MX\t%d %s.\n", rr->dnsdomainname, rr->preference, rr->cname);
if (ipdx>=0) if (ipdx>=0)
fprintf(bindfile, "%s.\tIN A\t%s\n", rr->cname, rr->ipaddr[ipdx]); fprintf(namedzone, "%s.\tIN A\t%s\n", rr->cname, rr->ipaddr[ipdx]);
} }
#if defined WITH_TINYDNS
if (options.output&1) {
rr_start(DNS_T_MX, rr->ttl, rr->timestamp);
uint16_pack_big(buf, rr->preference);
rr_add(buf, 2);
rr_addname(dottemp2);
rr_finish(dottemp1);
if (ipdx>=0 && ip4_scan(rr->ipaddr[ipdx], ip)) {
rr_start(DNS_T_A, rr->ttl, rr->timestamp);
rr_add(ip, 4);
rr_finish(dottemp2);
}
}
#endif
} else if ( strcasecmp(rr->type, "A")==0) { } else if ( strcasecmp(rr->type, "A")==0) {
if (tinyfile) if (tinyfile) {
fprintf(tinyfile, "%s%s:%s:%d:%s\n", (autoreverse ? "=" : "+"), rr->dnsdomainname, (ipdx>=0 ? rr->ipaddr[ipdx] : ""), rr->ttl, rr->timestamp); if (ipdx<=0 && rr->cipaddr[0])
if (bindfile && ipdx>=0) fprintf(tinyfile, "%s%s:%s:%d:%s\n", (znix==0 ? "=" : "+"), rr->dnsdomainname, rr->cipaddr, rr->ttl, rr->timestamp);
fprintf(bindfile, "%s.\tIN A\t%s\n", rr->dnsdomainname, rr->ipaddr[ipdx]); if (ipdx>=0)
#if defined WITH_TINYDNS fprintf(tinyfile, "+%s:%s:%d:%s\n", rr->dnsdomainname, rr->ipaddr[ipdx], rr->ttl, rr->timestamp);
if (options.output&1) {
char dptr[DNS_NAME4_DOMAIN];
if (ipdx>=0 && ip4_scan(rr->ipaddr[ipdx], ip)) {
rr_start(DNS_T_A, rr->ttl, rr->timestamp);
rr_add(ip, 4);
rr_finish(dottemp1);
} }
if (autoreverse) { if (namedzone) {
dns_name4_domain(dptr, ip); if (ipdx<=0 && rr->cipaddr[0])
rr_start(DNS_T_PTR, rr->ttl, rr->timestamp); fprintf(namedzone, "%s.\tIN A\t%s\n", rr->dnsdomainname, rr->cipaddr);
rr_addname(dottemp1); if (ipdx>=0)
rr_finish(dptr); fprintf(namedzone, "%s.\tIN A\t%s\n", rr->dnsdomainname, rr->ipaddr[ipdx]);
} }
}
#endif
} else if (strcasecmp(rr->type, "PTR")==0) { } else if (strcasecmp(rr->type, "PTR")==0) {
int ip[4] = {0, 0, 0, 0}; int ip[4] = {0, 0, 0, 0};
char buf[64]; char buf[64];
@@ -436,41 +370,18 @@ static void write_rr(struct resourcerecord* rr, int ipdx)
} }
if (tinyfile) if (tinyfile)
fprintf(tinyfile, "^%s:%s:%d:%s\n", buf, rr->cname, rr->ttl, rr->timestamp); fprintf(tinyfile, "^%s:%s:%d:%s\n", buf, rr->cname, rr->ttl, rr->timestamp);
if (bindfile) if (namedzone)
fprintf(bindfile, "%s.\tIN PTR\t%s.\n", buf, rr->cname); fprintf(namedzone, "%s.\tIN PTR\t%s.\n", buf, rr->cname);
#if defined WITH_TINYDNS
if (options.output&1) {
int dnsdn_len = strlen(buf);
if (!dns_domain_fromdot(&dottemp1, buf, dnsdn_len)) die_exit(0);
rr_start(DNS_T_PTR, rr->ttl, rr->timestamp);
rr_addname(dottemp2);
rr_finish(dottemp1);
}
#endif
} else if (strcasecmp(rr->type, "CNAME")==0) { } else if (strcasecmp(rr->type, "CNAME")==0) {
if (tinyfile) if (tinyfile)
fprintf(tinyfile, "C%s:%s:%d:%s\n", rr->dnsdomainname, rr->cname, rr->ttl, rr->timestamp); fprintf(tinyfile, "C%s:%s:%d:%s\n", rr->dnsdomainname, rr->cname, rr->ttl, rr->timestamp);
if (bindfile) if (namedzone)
fprintf(bindfile, "%s.\tIN CNAME\t%s.\n", rr->dnsdomainname, rr->cname); fprintf(namedzone, "%s.\tIN CNAME\t%s.\n", rr->dnsdomainname, rr->cname);
#if defined WITH_TINYDNS
if (options.output&1) {
rr_start(DNS_T_CNAME, rr->ttl, rr->timestamp);
rr_addname(dottemp2);
rr_finish(dottemp1);
}
#endif
} else if (strcasecmp(rr->type, "TXT")==0) { } else if (strcasecmp(rr->type, "TXT")==0) {
if (tinyfile) if (tinyfile)
fprintf(tinyfile, "'%s:%s:%d:%s\n", rr->dnsdomainname, rr->cname, rr->ttl, rr->timestamp); fprintf(tinyfile, "'%s:%s:%d:%s\n", rr->dnsdomainname, rr->cname, rr->ttl, rr->timestamp);
if (bindfile) if (namedzone)
fprintf(bindfile, "%s.\tIN TXT\t%s.\n", rr->dnsdomainname, rr->cname); fprintf(namedzone, "%s.\tIN TXT\t%s.\n", rr->dnsdomainname, rr->cname);
#if defined WITH_TINYDNS
if (options.output&1) {
rr_start(DNS_T_TXT, rr->ttl, rr->timestamp);
rr_addname(dottemp2);
rr_finish(dottemp1);
}
#endif
} }
} }
@@ -516,7 +427,7 @@ static void parse_rr(struct resourcerecord* rr)
#endif #endif
static void read_resourcerecords(char* dn) static void read_resourcerecords(char* dn, int znix)
{ {
LDAPMessage* res = NULL; LDAPMessage* res = NULL;
LDAPMessage* m; LDAPMessage* m;
@@ -535,9 +446,10 @@ static void read_resourcerecords(char* dn)
fprintf(ldifout, "dn: %s\n", dn); fprintf(ldifout, "dn: %s\n", dn);
rr.cn[0] = '\0'; rr.cn[0] = '\0';
strncpy(rr.dnsdomainname, zone.domainname, 64); strncpy(rr.dnsdomainname, zone.domainname, 64);
strcpy(rr.class, "IN"); strncpy(rr.class, "IN", 3);
rr.type[0] = '\0'; rr.type[0] = '\0';
rr.cname[0] = '\0'; rr.cname[0] = '\0';
rr.cipaddr[0] = '\0';
rr.ttl = time_now; rr.ttl = time_now;
rr.timestamp[0] = '\0'; rr.timestamp[0] = '\0';
rr.preference = 10; rr.preference = 10;
@@ -583,6 +495,12 @@ static void read_resourcerecords(char* dn)
if (options.ldifname[0]) if (options.ldifname[0])
fprintf(ldifout, "%s: %s\n", attr, rr.ipaddr[ipaddresses]); fprintf(ldifout, "%s: %s\n", attr, rr.ipaddr[ipaddresses]);
} }
} else if (strcasecmp(attr, "DNScipaddr")==0) {
int ip[4];
if (sscanf(bvals[0]->bv_val, "%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3])==4)
sprintf(rr.cipaddr, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
if (options.ldifname[0])
fprintf(ldifout, "%s: %s\n", attr, rr.cipaddr);
} else if (strcasecmp(attr, "DNScname")==0) { } else if (strcasecmp(attr, "DNScname")==0) {
if (!expand_domainname(rr.cname, bvals[0]->bv_val, bvals[0]->bv_len)) if (!expand_domainname(rr.cname, bvals[0]->bv_val, bvals[0]->bv_len))
rr.cname[0] = '\0'; rr.cname[0] = '\0';
@@ -628,7 +546,7 @@ static void read_resourcerecords(char* dn)
#endif #endif
do { do {
ipaddresses--; ipaddresses--;
write_rr(&rr, ipaddresses); write_rr(&rr, ipaddresses, znix);
} while (ipaddresses>0); } while (ipaddresses>0);
#if defined DRAFT_RFC #if defined DRAFT_RFC
if (rr.aliasedobjectname[0]) if (rr.aliasedobjectname[0])
@@ -654,34 +572,20 @@ static void write_zone(void)
zone.zonemaster, zone.adminmailbox, zone.serial, zone.refresh, zone.retry, zone.zonemaster, zone.adminmailbox, zone.serial, zone.refresh, zone.retry,
zone.expire, zone.minimum, zone.ttl, zone.timestamp); zone.expire, zone.minimum, zone.ttl, zone.timestamp);
} }
if (namedmaster) {
if (bindfile) { fprintf(namedmaster, "zone \"%s\" %s {\n\ttype master;\n\tfile \"%s.db\";\n};\n",
fprintf(bindfile, "; Automatically generated by ldap2dns - DO NOT EDIT!\n"); zone.domainname, zone.class, zone.domainname);
fprintf(bindfile, "%s. IN SOA %s. %s. ", zone.domainname, zone.zonemaster, zone.adminmailbox);
fprintf(bindfile, "(\n\t%d\t; Serial\n\t%d\t; Refresh\n\t%d\t; Retry\n\t%d\t; Expire\n\t%d )\t; Minimum\n", zone.serial, zone.refresh, zone.retry, zone.expire, zone.minimum);
} }
if (namedzone) {
#if defined WITH_TINYDNS fprintf(namedzone, "# Automatically generated by ldap2dns - DO NOT EDIT!\n");
if (options.output&1) { fprintf(namedzone, "$TTL %d\n", (zone.ttl>0) ? zone.ttl : 3600);
byte_zero(zone.timestamp, 8); fprintf(namedzone, "%s. IN SOA ", zone.domainname);
len = strlen(zone.domainname);
if (!dns_domain_fromdot(&dottemp1, zone.domainname, len)) die_exit(0);
uint32_pack_big(soa, zone.serial);
uint32_pack_big(soa+4, zone.refresh);
uint32_pack_big(soa+8, zone.retry);
uint32_pack_big(soa+12, zone.expire);
uint32_pack_big(soa+16, zone.minimum);
rr_start(DNS_T_SOA, zone.ttl, zone.timestamp);
len = strlen(zone.zonemaster); len = strlen(zone.zonemaster);
if (!dns_domain_fromdot(&dottemp2, zone.zonemaster, len)) die_exit(0); fprintf(namedzone, (zone.zonemaster[len-1]=='.') ? "%s " : "%s. ", zone.zonemaster);
rr_addname(dottemp2);
len = strlen(zone.adminmailbox); len = strlen(zone.adminmailbox);
if (!dns_domain_fromdot(&dottemp2, zone.adminmailbox, len)) die_exit(0); fprintf(namedzone, (zone.adminmailbox[len-1]=='.') ? "%s " : "%s. ", zone.adminmailbox);
rr_addname(dottemp2); fprintf(namedzone, "(\n\t%d\t; Serial\n\t%d\t; Refresh\n\t%d\t; Retry\n\t%d\t; Expire\n\t%d )\t; Minimum\n", zone.serial, zone.refresh, zone.retry, zone.expire, zone.minimum);
rr_add(soa, 20);
rr_finish(dottemp1);
} }
#endif
if (options.ldifname[0]) if (options.ldifname[0])
fprintf(ldifout, "\n"); fprintf(ldifout, "\n");
} }
@@ -725,6 +629,8 @@ static void read_dnszones(void)
if (tinyfile) if (tinyfile)
fprintf(tinyfile, "# Automatically generated by ldap2dns - DO NOT EDIT!\n"); fprintf(tinyfile, "# Automatically generated by ldap2dns - DO NOT EDIT!\n");
if (namedmaster)
fprintf(namedmaster, "# Automatically generated by ldap2dns - DO NOT EDIT!\n");
if ( (ldaperr = ldap_search_s(ldap_con, options.searchbase[0] ? options.searchbase : NULL, LDAP_SCOPE_SUBTREE, "objectclass=DNSzone", NULL, 0, &res))!=LDAP_SUCCESS ) if ( (ldaperr = ldap_search_s(ldap_con, options.searchbase[0] ? options.searchbase : NULL, LDAP_SCOPE_SUBTREE, "objectclass=DNSzone", NULL, 0, &res))!=LDAP_SUCCESS )
die_ldap(ldaperr); die_ldap(ldaperr);
for (m = ldap_first_entry(ldap_con, res); m; m = ldap_next_entry(ldap_con, m)) { for (m = ldap_first_entry(ldap_con, res); m; m = ldap_next_entry(ldap_con, m)) {
@@ -735,6 +641,7 @@ static void read_dnszones(void)
char zdn[256][64]; char zdn[256][64];
char ldif0; char ldif0;
strncpy(zone.class, "IN", 3);
zone.serial = time_now; zone.serial = time_now;
zone.refresh = 10800; zone.refresh = 10800;
zone.retry = 3600; zone.retry = 3600;
@@ -812,16 +719,16 @@ static void read_dnszones(void)
options.ldifname[0] = '\0'; options.ldifname[0] = '\0';
if (options.verbose&1) if (options.verbose&1)
printf("zonename: %s\n", zone.domainname); printf("zonename: %s\n", zone.domainname);
if (options.output&4) { if (options.output&OUTPUT_DB) {
char bindfilename[128]; char namedzonename[128];
sprintf(bindfilename, "%s.db", zone.domainname); sprintf(namedzonename, "%s.db", zone.domainname);
if ( !(bindfile = fopen(bindfilename, "w")) ) if ( !(namedzone = fopen(namedzonename, "w")) )
die_exit("Unable to open db-file for writing"); die_exit("Unable to open db-file for writing");
} }
write_zone(); write_zone();
read_resourcerecords(dn); read_resourcerecords(dn, i);
if (bindfile) if (namedzone)
fclose(bindfile); fclose(namedzone);
if (options.verbose&2) if (options.verbose&2)
printf("\n"); printf("\n");
if (options.ldifname[0]) if (options.ldifname[0])
@@ -852,11 +759,12 @@ int main(int argc, char** argv)
set_datadir(); set_datadir();
for (;;) { for (;;) {
int ldaperr; int ldaperr;
if ( !(ldap_con = ldap_init(options.hostname, options.port)) ) ldap_con = ldap_init(options.hostname, options.port);
die_exit("Unable to initialize connection to LDAP server"); ldaperr = ldap_con && ldap_simple_bind_s(ldap_con, options.binddn, options.password);
ldaperr = ldap_simple_bind_s(ldap_con, options.binddn, options.password);
if (ldaperr!=LDAP_SUCCESS) { if (ldaperr!=LDAP_SUCCESS) {
fprintf(stderr, "Warning - Could not connect to LDAP server %s:%d as '%s'\n", options.hostname, options.port, options.binddn); fprintf(stderr, "Warning - Could not connect to LDAP server %s:%d as '%s'\n", options.hostname, options.port, options.binddn);
if (options.is_daemon==0)
break;
sleep(options.update_iv); sleep(options.update_iv);
continue; continue;
} }
@@ -872,13 +780,6 @@ int main(int argc, char** argv)
goto skip; goto skip;
} }
} }
#if defined WITH_TINYDNS
if (options.output&1) {
fdcdb = open_trunc(tinydns_tempfile);
if (fdcdb == -1) die_exit("Unable to create 'data.tmp'");
if (cdb_make_start(&cdb, fdcdb) == -1) die_exit("Unable to create 'data.tmp'");
}
#endif
if (options.ldifname[0]) { if (options.ldifname[0]) {
if (options.ldifname[0]=='-') if (options.ldifname[0]=='-')
ldifout = stdout; ldifout = stdout;
@@ -888,21 +789,24 @@ int main(int argc, char** argv)
die_exit("Unable to open LDIF-file for writing"); die_exit("Unable to open LDIF-file for writing");
} }
time(&time_now); time(&time_now);
if ( options.output&2 && !(tinyfile = fopen(tinydns_textfile, "w")) ) if ( options.output&OUTPUT_DATA && !(tinyfile = fopen(tinydns_texttemp, "w")) )
die_exit("Unable to open file 'data' for writing"); die_exit("Unable to open file 'data.temp' for writing");
if ( options.output&OUTPUT_DB && !(namedmaster = fopen("named.zones", "w")) )
die_exit("Unable to open file 'named.zones' for writing");
read_dnszones(); read_dnszones();
if (tinyfile) if (namedmaster)
fclose(namedmaster);
if (tinyfile) {
fclose(tinyfile); fclose(tinyfile);
if (soa_numzones==0 || soa_checksum==0)
break;
if (rename(tinydns_texttemp, tinydns_textfile)==-1)
die_exit("Unable to move 'data.temp' to 'data'");
}
if (options.ldifname[0] && ldifout) if (options.ldifname[0] && ldifout)
fclose(ldifout); fclose(ldifout);
#if defined WITH_TINYDNS if (options.exec_command[0])
if (options.output&1) { system(options.exec_command);
if (cdb_make_finish(&cdb)==-1 || fsync(fdcdb)==-1 || close(fdcdb)==-1)
die_exit("Unable to create 'data.tmp'");
if (rename(tinydns_tempfile, tinydns_datafile)==-1)
die_exit("Unable to move 'data.tmp' to 'data.cdb'");
}
#endif
skip: skip:
if ( (ldaperr = ldap_unbind_s(ldap_con))!=LDAP_SUCCESS ) if ( (ldaperr = ldap_unbind_s(ldap_con))!=LDAP_SUCCESS )
die_ldap(ldaperr); die_ldap(ldaperr);

View File

@@ -1,9 +1,13 @@
#!/bin/sh #!/bin/sh
mkdir ldap2tinydns mkdir ldap2tinydns
mkdir ldap2tinydns/env mkdir ldap2tinydns/env
echo "#!/bin/sh" > ldap2tinydns/run cat << EOF_run > ldap2tinydns/run
echo "exec 2>&1" >> ldap2tinydns/run #!/bin/sh
echo "exec envdir ./env softlimit -d250000 /usr/bin/ldap2dns -u 59" >> ldap2tinydns/run exec 2>&1
exec envdir ./env softlimit -d250000 /usr/bin/ldap2dns -e "cd /var/tinydns/root && /usr/bin/tinydns-data"
EOF_run
chmod 755 ldap2tinydns/run chmod 755 ldap2tinydns/run
echo "/var/tinydns/root" > ldap2tinydns/env/TINYDNSDIR echo "/var/tinydns/root" > ldap2tinydns/env/TINYDNSDIR
echo "30" > ldap2tinydns/env/LDAP2DNS_UPDATE
echo "DATA" > ldap2tinydns/env/LDAP2DNS_OUTPUT

509
zoneedit.pl Normal file
View File

@@ -0,0 +1,509 @@
#!/usr/sbin/perl
use CGI qw(:standard);
use Net::LDAP;
use strict;
use vars qw($LDAPHOST $BASEDN $BINDBASE $BINDUID $ANONBINDDN $ZONEEDIT $DEFAULT_MAIN @our_nameserver @zoneinfo @setinfo);
my $LDAPHOST = "ldap0.server";
my $BASEDN = "ou=dns,o=tiscover";
my $BINDBASE = "ou=people,o=tiscover";
my $BINDUID = "uid";
my $ANONBINDDN = "ou=dns,o=tiscover";
my $ZONEEDIT = "zoneedit.pl";
my $DEFAULT_MAIN = "index.html";
my $LOGFILE = "/opt/httpd/logs/zoneedit.log";
my @our_nameserver = ( "ns1.tis.co.at", "ns2.tis.co.at" );
my @zoneinfo = qw( DNSzonename DNSserial DNSclass DNStype DNSexpire DNSretry DNSminimum DNSzonemaster DNSrefresh DNSadminmailbox DNSttl );
my @setinfo = qw( DNSdomainname DNStype DNSclass DNScname DNSipaddr DNSttl );
################################################################################
eval {
main();
};
if ($@) {
errconfirm($@);
}
sub main
{
my $request = Apache->request();
my $query = new CGI;
my $call = $query->param('call');
if (defined $call) {
my $ldap = Net::LDAP->new($LDAPHOST) or die "can't make new LDAP object: $@";
my $user = $request->connection->user();
my $binddn = $BINDUID."=".$user.",$BINDBASE";
my ($ret, $password) = $request->get_basic_auth_pw();
my $mesg = $ldap->bind($binddn, password => $password);
die "Unable to bind to LDAP server.<BR>Reason: ".$mesg->error if ($mesg->code);
my $selet = $query->param('selet') if $query->param('selet');
if ($call eq "dnslist") {
dns_list($query, $ldap, $selet);
} elsif ($call eq "newzone") {
new_zone($query, $selet);
} elsif ($call eq "addzone") {
my $zonedn = add_zone($query, $ldap);
log_action($user, "add_zone", $zonedn);
$query->delete_all();
print $query->header, $query->start_html(-title=> 'Edit DNS Zone',
-target=> 'main',
-author=> 'jacob.rief@tiscover.com',
-BGCOLOR=> 'WHITE'),
"<CENTER><BR>";
edit_zone($query, $ldap, $zonedn, $selet);
print $query->end_html;
} elsif ($call eq "editzone") {
my $zonedn = $query->param('zonedn');
if (defined $query->param('modifyzone')) {
modify_zone($query, $ldap, $zonedn);
log_action($user, "modify_zone_soa", $zonedn);
} elsif (defined $query->param('addrrset')) {
add_rrset($query, $ldap, $zonedn);
log_action($user, "add_rrset", $zonedn);
} elsif (defined $query->param('modifyrrset')) {
my $setdn = $query->param('setdn');
modify_rrset($query, $ldap, $zonedn, $setdn);
log_action($user, "modify_rrset", $setdn);
} elsif (defined $query->param('deleterrset')) {
my $setdn = $query->param('setdn');
delete_rrset($query, $ldap, $zonedn, $setdn);
log_action($user, "delete_rrset", $setdn);
}
$query->delete_all();
print $query->header, $query->start_html(-title=> 'Edit DNS Zone',
-target=> 'main',
-author=> 'jacob.rief@tiscover.com',
-BGCOLOR=> 'WHITE'),
"<CENTER><BR>";
print_whois($ldap, $zonedn) if ($request->method eq "GET");
edit_zone($query, $ldap, $zonedn, $selet);
print $query->end_html;
} elsif ($call eq "deletezone") {
my $zonedn = $query->param('zonedn');
delete_zone($query, $ldap, $zonedn);
log_action($user, "delete_zone", $zonedn);
}
$ldap->unbind();
} else {
# print frame
print $query->header,
"<FRAMESET COLS=\"250,*\" BORDER=0 FRAMEBORDER=0 FRAMESPACING=0>",
" <FRAME SRC=\"$ZONEEDIT?call=dnslist&nslu=1\" NAME=\"menu\" NORESIZE MARGINWIDTH=0 MARGINHEIGHT=0>",
" <FRAME SRC=\"$DEFAULT_MAIN\" NAME=\"main\" MARGINWIDTH=0 MARGINHEIGHT=0>",
"</FRAMESET>";
}
}
sub errconfirm
{
my $errmsg = shift;
my $request = Apache->request();
$request->note_basic_auth_failure();
my $query = new CGI;
print $query->header, $query->start_html(-title=> 'DNS Zone Admin',
-target=> 'main',
-author=> 'jacob.rief@tiscover.com',
-BGCOLOR=> 'WHITE'),
"<CENTER><BR>",
$query->h2("An error occured"),
"<FONT color=red>Message: $errmsg</FONT><BR>\n",
$query->end_html;
$request->child_terminate();
}
sub log_action
{
my ($user, $action, $dn) = @_;
my ($sec,$min,$hour,$mday,$mon,$year) = localtime();
my @month = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
my ($m, $y) = ($month[$mon], $year+1900);
open(FILE, ">>$LOGFILE");
print FILE "[$mday/$m/$y:$hour:$min:$sec] $user $action $dn\n";
close(FILE);
}
sub list_attrs
{
my $attr = shift;
my (@list, $key, $value);
while (($key, $value) = each %$attr) {
push(@list, $key => $value);
}
return \@list;
}
sub dns_list
{
my ($query, $ldap, $selet) = @_;
my @letters = qw( 0 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z );
print $query->header, $query->start_html(-title=> 'Zone-Selector',
-target=> 'menu',
-author=> 'jacob.rief@tiscover.com',
-BGCOLOR=> 'WHITE');
my ($dnslookup, $resolver);
if ($selet =~ /\~/) {
$dnslookup = 1;
use Net::DNS;
$resolver = new Net::DNS::Resolver;
} else {
$dnslookup = 0;
}
print "<TABLE BORDER=0 CELLSPACING=1 CELLPADDING=1 COLS=1 BGCOLOR=#BBBBBB>\n",
"<TR ALIGN=center><TH><A HREF=\"$ZONEEDIT?call=newzone&selet=$selet\" TARGET=\"main\">Add New Zone</A></TH></TR>\n";
foreach my $let (@letters) {
if ($selet =~ /$let/) {
my $newselet = $selet;
$newselet =~ s/$let//;
print "<TR><TD><A HREF=\"$ZONEEDIT?call=dnslist&selet=$newselet\"><B>- $let</B></A></TD></TR>\n";
} else {
my $newselet = $selet.$let;
print "<TR><TD><A HREF=\"$ZONEEDIT?call=dnslist&selet=$newselet\"><B>+ $let</B></A></TD></TR>\n";
next;
}
my $mesg = $ldap->search(base => $BASEDN, filter => "(&(objectclass=DNSzone)(DNSzonename=$let*))");
my @entries = $mesg->entries;
my ($zonename, %dn_entry, @unsorted);
foreach my $entry (@entries) {
$zonename = $entry->get_value('DNSzonename');
push @unsorted, $zonename;
$dn_entry{$zonename} = $entry->dn();
}
@entries = sort @unsorted;
foreach $zonename (@entries) {
my $zonedn = $dn_entry{$zonename};
if ($dnslookup) {
my $query = $resolver->search($zonename, "NS");
my @ns;
if ($query) {
foreach my $rr ($query->answer) {
next unless $rr->type eq "NS";
push @ns, $rr->nsdname;
}
}
if (lc($ns[0]) eq lc($our_nameserver[0]) || lc($ns[1]) eq lc($our_nameserver[1])
|| lc($ns[0]) eq lc($our_nameserver[1]) || lc($ns[1]) eq lc($our_nameserver[0]) ) {
print "<TR ALIGN=center BGCOLOR=#AAFFAA><TD>";
} elsif (defined $ns[0] || defined $ns[1]) {
print "<TR ALIGN=center BGCOLOR=#FFAAAA><TD>";
} else {
print "<TR ALIGN=center BGCOLOR=#FFFFAA><TD>";
}
} else {
print "<TR ALIGN=center BGCOLOR=#EEEEEE><TD>";
}
print "<A HREF=\"$ZONEEDIT?call=editzone&zonedn=$zonedn&selet=$selet\" TARGET=\"main\">$zonename</A></TD></TR>\n";
}
}
print "<TR ALIGN=center><TH><A HREF=\"$ZONEEDIT?call=dnslist";
if ($dnslookup) {
$selet =~ s/\~//;
print "&selet=$selet\" TARGET=\"menu\">Without DNS-lookup</A></TH></TR>\n";
} else {
print "&selet=$selet~\" TARGET=\"menu\">With DNS-lookup</A></TH></TR>\n";
}
print "</TABLE>\n", $query->end_html;
}
sub print_zone_soa
{
my $zonedata = shift;
print "<TR><TD ALIGN=right>Serial: </TD><TD>",
textfield(-name=>'DNSserial', -size=>16, -maxlength=>24, -default=>$$zonedata{'DNSserial'}),
"</TD>", "<TD ALIGN=right>Refresh: </TD><TD>",
textfield(-name=>'DNSrefresh', -size=>16, -maxlength=>24, -default=>$$zonedata{'DNSrefresh'}),
"</TD></TR>\n",
"<TR><TD ALIGN=right>Retry: </TD><TD>",
textfield(-name=>'DNSretry', -size=>16, -maxlength=>24, -default=>$$zonedata{'DNSretry'}),
"</TD>", "<TD ALIGN=right>Expire: </TD><TD>",
textfield(-name=>'DNSexpire', -size=>16, -maxlength=>24, -default=>$$zonedata{'DNSexpire'}),
"</TD></TR>\n",
"<TR><TD ALIGN=right>Minimum: </TD><TD>",
textfield(-name=>'DNSminimum', -size=>16, -maxlength=>24, -default=>$$zonedata{'DNSminimum'}),
"</TD>", "<TD ALIGN=right>Adminmailbox: </TD><TD>",
textfield(-name=>'DNSadminmailbox', -size=>16, -maxlength=>24, -default=>$$zonedata{'DNSadminmailbox'}),
"</TD></TR>\n",
"<TR><TD ALIGN=right>Zonemaster: </TD><TD>",
textfield(-name=>'DNSzonemaster', -size=>16, -maxlength=>24, -default=>$$zonedata{'DNSzonemaster'}),
"</TD>", "<TD ALIGN=right>Time to live: </TD><TD>",
textfield(-name=>'DNSttl', -size=>16, -maxlength=>24, -default=>$$zonedata{'DNSttl'}),
"</TD><TR>\n";
}
sub new_zone
{
my ($query, $selet) = @_;
my %default_zonedata = (
"DNSzonename" => "",
"DNSserial" => "",
"DNSclass" => "IN",
"DNStype" => "SOA",
"DNSexpire" => "259200",
"DNSretry" => "3600",
"DNSminimum" => "86400",
"DNSzonemaster" => "ns1.tis.co.at.",
"DNSrefresh" => "10800",
"DNSadminmailbox" => "domreg.tis.co.at.",
"DNSttl" => "3600",
);
my ($sec,$min,$hour,$mday,$mon,$year) = localtime();
$default_zonedata{"DNSserial"} = sprintf "%04d%02d%02d01", $year+1900, $mon+1, $mday;
my $onsubmit = "{ parent.frames.menu.location='$ZONEEDIT?call=dnslist&selet=$selet'; }";
$query->param(call=>'addzone');
print $query->header, $query->start_html(-title=> 'Add DNS Zone',
-target=> 'main',
-author=> 'jacob.rief@tiscover.com',
-BGCOLOR=> 'WHITE'),
"<CENTER><BR>",
$query->h2('Add DNS zone'),
$query->start_multipart_form(-method=>'POST', -action=>"$ZONEEDIT", -target=>'main', -onSubmit=>$onsubmit),
$query->hidden('call'), $query->hidden('selet'),
"<TABLE BORDER=1 WIDTH=85% COLS=4>\n",
"<TR><TD ALIGN=right colspan=2> New Zonename: </TD><TD colspan=2>",
$query->textfield(-name=>'DNSzonename', -size=>40, -maxlength=>64),
"</TD></TR>\n";
print_zone_soa(\%default_zonedata);
print "<TR><TD colspan=2 ALIGN=center>",
$query->submit(-name=>" Submit "),
"</TD><TD colspan=2 ALIGN=center>",
$query->reset(),
"</TD></TR></TABLE>\n",
$query->end_form(),
$query->end_html;
}
sub add_zone
{
my ($query, $ldap) = @_;
my %zonedata;
foreach my $za (@zoneinfo) {
$zonedata{$za} = $query->param($za) if defined $query->param($za);
}
my ($zonename, $zonedn) = ($zonedata{'DNSzonename'}, "cn=$zonedata{'DNSzonename'},$BASEDN");
my $attrs = list_attrs(\%zonedata);
push(@$attrs, "objectclass", "DNSzone", "cn", "$zonename");
my $mesg = $ldap->add(dn=>$zonedn, attr=>$attrs);
die "Failed to add zone: $zonename<BR>Reason: ".$mesg->error if ($mesg->code);
my @attr = ( "cn", "NS1:", "objectclass", "DNSrrset", "dnstype", "NS", "dnsclass", "IN",
"dnsttl", "3600", "dnscname", $our_nameserver[0]."." );
my $dnch = "cn=NS1:,$zonedn";
die "Failed to add $dnch " if (($mesg = $ldap->add(dn=>$dnch, attr=>\@attr))->code);
@attr = ( "cn", "NS2:", "objectclass", "DNSrrset", "dnstype", "NS", "dnsclass", "IN",
"dnsttl", "3600", "dnscname", $our_nameserver[1]."." );
$dnch = "cn=NS2:,$zonedn";
die "Failed to add $dnch " if (($mesg = $ldap->add(dn=>$dnch, attr=>\@attr))->code);
@attr = ( "cn", "A:www", "objectclass", "DNSrrset", "dnstype", "A", "dnsclass", "IN",
"dnsdomainname", "www", "dnsttl", "3600", "dnsipaddr", "195.96.23.204" );
$dnch = "cn=A:www,$zonedn";
die "Failed to add $dnch<BR>Reason: ".$mesg->error if (($mesg = $ldap->add(dn=>$dnch, attr=>\@attr))->code);
return $zonedn;
}
sub modify_zone
{
my ($query, $ldap, $zonedn) = @_;
my %zonedata;
foreach my $za (@zoneinfo) {
$zonedata{$za} = $query->param($za) if defined $query->param($za);
}
my @zonename;
my $zn = ($ldap->search(base=>$zonedn, scope=>'base', filter=>"(objectclass=DNSzone)")->entry(0))->get_value('DNSzonename');
push @zonename, $zn;
for (my $zc = 0; defined $query->param("DNSzonename$zc"); $zc++) {
$zn = $query->param("DNSzonename$zc");
push @zonename, $zn if (length($zn)>3);
}
my $mesg = $ldap->modify($zonedn, delete => [ 'DNSzonename' ]);
$mesg = $ldap->modify($zonedn, replace => \%zonedata) unless ($mesg->code);
$mesg = $ldap->modify($zonedn, add => [ 'DNSzonename' => \@zonename ] ) unless ($mesg->code);
die "Unable to modify zone: $zonedn<BR>Reason: ".$mesg->error if ($mesg->code);
}
sub delete_zone
{
my ($query, $ldap, $zonedn) = @_;
my $zonedn = $query->param('zonedn');
my $mesg = $ldap->search(base=>$zonedn, filter => "(objectclass=DNSrrset)");
my @entries = $mesg->entries;
foreach my $entry (@entries) {
$mesg = $ldap->delete($entry->dn());
last if ($mesg->code);
}
$mesg = $ldap->delete($zonedn) unless ($mesg->code);
die "Unable to delete zone $zonedn.<BR>Reason: ".$mesg->error if ($mesg->code);
dnslist($query, $ldap);
}
sub edit_zone
{
my ($query, $ldap, $zonedn, $selet) = @_;
my @zonename = ($ldap->search(base=>$zonedn, scope=>'base', filter=>"(objectclass=DNSzone)")->entry(0))->get_value('DNSzonename');
my $zonemaster = shift @zonename;
$query->param(call=>'editzone');
$query->param(zonedn=>$zonedn);
$query->param(selet=>$selet);
# Table for SOA
print $query->h2("Edit DNS zone <I>$zonemaster</I>");
print $query->start_multipart_form(-method=>'POST', -action=>"$ZONEEDIT", -target=>'main'),
$query->hidden('call'), $query->hidden('zonedn'), $query->hidden('selet'),
"<TABLE BORDER=1 WIDTH=85% COLS=4>\n";
my $zc = 0;
my $entry = $ldap->search(base=>$zonedn, scope=>'base', filter=>"(objectclass=DNSzone)")->entry(0);
my %zonedata;
foreach my $za (@zoneinfo) {
$zonedata{$za} = $entry->get_value($za);
}
print_zone_soa(\%zonedata);
print "</TD></TR>\n";
foreach my $zn (@zonename) {
print "<TR><TD ALIGN=right colspan=2> Additional Zonename: </TD><TD colspan=2>",
$query->textfield(-name=>"DNSzonename$zc", -default=>$zn, -size=>40, -maxlength=>64),
"</TD></TR>\n";
$zc++;
}
print "<TR><TD ALIGN=right colspan=2> Add additional Zonename: </TD><TD colspan=2>",
$query->textfield(-name=>"DNSzonename$zc", -size=>40, -maxlength=>64),
"</TABLE></TD></TR>\n";
print "<TABLE BORDER=1 WIDTH=66% COLS=3><TR><TD align=center>",
$query->submit(-name=>"modifyzone", -value=>" Modify Zone "),
"</TD><TD align=center>";
my $onclick = "if(confirm('Do you really want to remove zone \"$zonemaster\" and all its resource records?'))"
."{ parent.frames.menu.location='$ZONEEDIT?call=deletezone&zonedn=$zonedn&selet=$selet'; parent.frames.main.location='$DEFAULT_MAIN'; }";
print $query->submit(-name=>"deletezone", -value=>" Delete Zone ", -onClick=>$onclick),
"</TD>\n", $query->end_form(),
"<TD align=center>", $query->start_multipart_form(-method=>'POST', -action=>"$ZONEEDIT", -target=>'main'),
$query->hidden('call'), $query->hidden('zonedn'), $query->hidden('selet'),
$query->submit(-name=>"resetform", -value=>" Reset Form "),
$query->end_form(), "</TD></TR></TABLE>\n";
# Tables for RRsets
my $mesg = $ldap->search(base=>$zonedn, filter => "(objectclass=DNSrrset)");
my @entries = $mesg->entries;
print "\n<TABLE BORDER=1 WIDTH=98% COLS=6 CELLSPACING=0 CELLPADDING=1>\n",
"<TR><TH width=20>Name $#entries</TH><TH width=15>Type</TH><TH width=40>IPaddr</TH><TH width=40>CNAME</TH><TH width=20>TTL</TH><TH></TH></TR>\n";
foreach $entry (@entries) {
my $setdn = $entry->dn();
my $domainname = $entry->get_value('DNSdomainname');
$domainname = "." if (!defined $domainname || length($domainname)<1);
my $ipaddr = $entry->get_value('DNSipaddr');
my $cname = $entry->get_value('DNScname');
my $type = $entry->get_value('DNStype');
my $ttl = $entry->get_value('DNSttl');
$query->param(setdn => $setdn);
print "<TR align=center>", $query->start_multipart_form(-method=>'POST', -action=>"$ZONEEDIT", -target=>'main'), $query->hidden('call'),
$query->hidden('selet'), $query->hidden('zonedn'), $query->hidden('setdn'),
"<TD><B>$domainname</B></TD>",
"<TD><B>$type</B></TD>",
"<TD>", $query->textfield(-name=>'DNSipaddr', -default=>$ipaddr, -size=>16, -maxlength=>16), "</TD>",
"<TD>", $query->textfield(-name=>'DNScname', -default=>$cname, -size=>16, -maxlength=>64), "</TD>",
"<TD>", $query->textfield(-name=>'DNSttl', -default=>$ttl, -size=>6, -maxlength=>6), "</TD>",
"<TD>", $query->submit(-name=>"modifyrrset", -value=>" Modify "),
$query->submit(-name=>"deleterrset", -value=>" Delete "), "</TD>",
$query->end_form(), "</TR>\n";
}
print "\n<TR align=center>", $query->start_multipart_form(-method=>'POST', -action=>"$ZONEEDIT", -target=>'main'), $query->hidden('call'),
$query->hidden('selet'), $query->hidden('zonedn'),
"<TD>", textfield(-name=>'DNSdomainname', -size=>8, -maxlength=>32), "</TD>",
"<TD>", $query->popup_menu(-name=>'DNStype', -values=>['CNAME','A','MX','NS','PTR','TXT'], -default=>"A"), "</TD>",
"<TD>", textfield(-name=>'DNSipaddr', -size=>16, -maxlength=>16), "</TD>",
"<TD>", textfield(-name=>'DNScname', -size=>16, -maxlength=>64), "</TD>",
"<TD>", textfield(-name=>'DNSttl', -default=>"3600", -size=>6, -maxlength=>6), "</TD>",
"<TD>", $query->submit(-name=>"addrrset", -value=>" Add "), "</TD>",
$query->end_form();
print "</TR></TABLE>\n";
}
sub add_rrset
{
my ($query, $ldap, $zonedn) = @_;
my ($domainname, $type, @setattrs) = ($query->param('DNSdomainname'), $query->param('DNStype'));
foreach my $za (@setinfo) {
next unless (defined $query->param($za));
push (@setattrs, $za, $query->param($za));
}
my $chdn = "$type:$domainname";
push (@setattrs, "objectclass", "DNSrrset", "cn", "$chdn");
$chdn = "cn=$chdn,$zonedn";
my $mesg = $ldap->add($chdn, attr => \@setattrs);
die "Unable to add rrset: $chdn ".$mesg->error if ($mesg->code);
my $newserial = $ldap->search(base=>$zonedn, scope=>'base', filter => "(objectclass=DNSzone)")->entry(0)->get_value('DNSserial')+1;
$mesg = $ldap->modify($zonedn, replace => { 'DNSserial', $newserial });
die "Unable to modify serial number for: $zonedn ".$mesg->error if ($mesg->code);
}
sub modify_rrset
{
my ($query, $ldap, $zonedn, $setdn) = @_;
my %setattrs;
foreach my $za (@setinfo) {
next unless (defined $query->param($za));
$setattrs{$za} = $query->param($za);
}
my $mesg = $ldap->modify($setdn, replace => \%setattrs);
die "Unable to modify rrset: $setdn".$mesg->error if ($mesg->code);
my $newserial = $ldap->search(base=>$zonedn, scope=>'base', filter => "(objectclass=DNSzone)")->entry(0)->get_value('DNSserial')+1;
$mesg = $ldap->modify($zonedn, replace => { 'DNSserial', $newserial });
die "Unable to modify serial number for: $zonedn ".$mesg->error if ($mesg->code);
}
sub delete_rrset
{
my ($query, $ldap, $zonedn, $setdn) = @_;
my $mesg = $ldap->delete($setdn);
die "Unable to modify rrset: $setdn".$mesg->error if ($mesg->code);
my $newserial = $ldap->search(base=>$zonedn, scope=>'base', filter => "(objectclass=DNSzone)")->entry(0)->get_value('DNSserial')+1;
$mesg = $ldap->modify($zonedn, replace => { 'DNSserial', $newserial });
die "Unable to modify serial number for: $zonedn ".$mesg->error if ($mesg->code);
}
sub print_whois
{
my ($ldap, $zonedn) = @_;
my ($zonename, $whois) = ($ldap->search(base=>$zonedn, scope=>'base', filter=>"(objectclass=DNSzone)")->entry(0))->get_value('DNSzonename');
use Net::Whois;
unless ($whois = new Net::Whois::Domain $zonename) {
print "<H4>Unable to contact Whois-server</H4>";
return;
};
unless ($whois->ok) {
print "<H4>No Whois-record found for zone <I>$zonename</I> trying with ";
# try with parent zone
if ($zonename =~ /[^.]+\.(.*)/) {
$zonename = $1;
}
print "<I>$zonename</I></H4>\n";
$whois = new Net::Whois::Domain($zonename);
return unless ($whois->ok);
}
print "<H3>Whois record for zone <I>$zonename</I></H3>\n";
print "Domain: ", $whois->domain, "<BR>\n";
print "Name: ", $whois->name, "<BR>\n";
print "Tag: ", $whois->tag, "<BR>\n";
print "Address:\n", map { " $_<BR>\n" } $whois->address;
print "Country: ", $whois->country, "<BR>\n";
print "Name Servers:<BR>\n", map { " $$_[0] ($$_[1])<BR>\n" } @{$whois->servers};
print "Record created:", $whois->record_created, "<BR>\n";
print "Record updated:", $whois->record_updated, "<BR>\n" ;
}