Back importing ldap2dns from Jacob Rief - 0.2.0

git-svn-id: https://svn.alkaloid.net/gpl/ldap2dns/trunk@1 06cd67b6-e706-0410-b29e-9de616bca6e9
This commit is contained in:
Ben Klang
2005-12-02 04:09:15 +00:00
commit ef7ba2e681
11 changed files with 1871 additions and 0 deletions

55
Makefile Normal file
View File

@@ -0,0 +1,55 @@
# ldap2dns Makefile
VERSION=0.2.0
RELEASE=1
WITHTINYDNS=-DWITH_TINYDNS
CC=gcc -O2
DJBDNSDIR=../djbdns-1.02
INC=-I$(DJBDNSDIR)
CFLAGS=$(INC) $(WITHTINYDNS) -DVERSION='"$(VERSION)"'
OBJS=ldap2dns.o
LIBS=-lldap -llber -lresolv
LD=gcc
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=
PREFIXDIR=$(INSTALL_PREFIX)/usr
LDAPCONFDIR=$(INSTALL_PREFIX)/etc/openldap
TARFILE=/usr/src/redhat/SOURCES/ldap2dns-$(VERSION).tar.gz
SPECFILE=ldap2dns.spec
all: ldap2dns
ldap2dns: $(OBJS) $(LIBS) $(ALIBS)
$(LD) $(LDFLAGS) -o $@ $(OBJS) $(ALIBS) $(LIBS)
ln -f ldap2dns ldap2dnsd
ldap2dns.o: ldap2dns.c
$(CC) $(CFLAGS) -c $<
install: all
mkdir -p $(PREFIXDIR)/bin
mkdir -p $(LDAPCONFDIR)
install -s -o root -g root -m 755 ldap2dns $(PREFIXDIR)/bin/
ln -f $(PREFIXDIR)/bin/ldap2dns $(PREFIXDIR)/bin/ldap2dnsd
install -o root -g root -m 755 ldap2tinydns-conf $(PREFIXDIR)/bin/
install -o root -g root -m 644 dns.at.conf $(LDAPCONFDIR)/
install -o root -g root -m 644 dns.oc.conf $(LDAPCONFDIR)/
clean:
rm -f $(OBJS) ldap2dns ldap2dnsd data* $(SPECFILE)
tar: clean
cd ..; \
tar czf $(TARFILE) ldap2dns-$(VERSION) --exclude CVS
$(SPECFILE): Specfile
sed -e 's#%VERSION%#$(VERSION)#g' \
-e 's#%RELEASE%#$(RELEASE)#g' \
< $< > $@
rpm: tar $(SPECFILE)
rpm -ba $(SPECFILE)

332
README.html Normal file
View File

@@ -0,0 +1,332 @@
<H1 align=center>LDAP to DNS gateway</H1>
<P>
<B>ldap2dns</B> is a program to create DNS records directly from a LDAP directory.
It can and should be be used to replace the secondary name-server by a second
primary one.<BR>
<B>ldap2dns</B> helps to reduce all kind of administration overhead.
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>
If he desires he can add access control for each zone, create a webbased GUI
and add all other kind of zone and resource record information without
interfering with the DNS server.<BR>
<B>ldap2dns</B> is designed to write binary data.cdb files used by tinydns, but
also may be used to write .db-files used by named.<BR>
<P>
<H3>1. Introduction</H3>
Often it is desirable to store DNS information in a database rather than
in flat text files. This can greatly help to reduce administration overhead
since associate information such as billing contact, account management, etc.
can be stored and processed inside the same database. Also due to the nature of
DNS, information must be stored redundantly on two or more hosts.
The classical data replication through zone transfer is unreliable, insecure
and difficult to administer.<BR>
To solve this problem some proprietary attempts have been proposed to
store DNS information in relational databases. The nature of DNS however
is hierarchical and such should the database be. Using a relational database
to store DNS information is undesirable, because it becomes difficult
to store free form information. Within a hierachical data scheme, the
administrator might define more than one IP-address for each canonical name.
To implement such a feature in a relational database without breaking the
normalization rules, one would have to add another table.<BR>
One of the most widely spread hierarchical database protocols is LDAP.
<B>ldap2dns</B> retrieves DNS information stored in an LDAP directory service
and generates a file suitable for name-servers.<BR>
Actually the most widely spread name-servers
<A HREF="http://www.isc.org/products/BIND/">named</A> and
<A HREF="http://cr.yp.to/djbdns/tinydns.html">tinydns</A> are
supported. <B>ldap2dns</B> has been specially designed to work with
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
is not well supported.
There is a
<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.
This paper however is a draft RFC and expired in February 1999. The scheme this RFC
describes, looks as if it has been designed to be used only by 'named'. This scheme
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>
Since tinydns is going another descriptive way, I implemented a similar object-scheme
more suitable for tinydns. Two objectclasses have been defined. <B>DNSzone</B> stores
all the information to define a DNS zone, such as the SOA (Start Of Authority), serial
numbers etc. <B>DNSrrset</B> is used to store the information for a single resource record,
such as the domain name, IP-addresses, class and type.<BR>
Here are the tables:
<P>
<H4>DNSzone</H4>
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
tinydns zones are always primary. Secondary zones don't make sense anyway!
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
can have none to many children of class <B>DNSrrset</B>.<BR>
<TABLE bgcolor=#EEEEEE>
<TR><TH>ATTRIBUTE</TH><TH>VALUE</TH><TH>Comment</TH></TR>
<TR><TD>objectclass</TD><TD>DNSzone</TD><TD>required</TD></TR>
<TR><TD>cn</TD><TD><I>common name</I></TD><TD>required</TD></TR>
<TR><TD>DNSzonename</TD><TD><I>Name of the zone</I></TD><TD>required, multivalued</TD></TR>
<TR><TD>DNSserial</TD><TD><I>Serial number of SOA</I></TD><TD>optional</TD></TR>
<TR><TD>DNSrefresh</TD><TD><I>Refresh time of SOA</I></TD><TD>optional, only used for zone transfers</TD></TR>
<TR><TD>DNSretry</TD><TD><I>Retry time of SOA</I></TD><TD>optional, only used for zone transfers</TD></TR>
<TR><TD>DNSexpire</TD><TD><I>Expire time of SOA</I></TD><TD>optional, only used for zone transfers</TD></TR>
<TR><TD>DNSminimum</TD><TD><I>Minimum time to live</I></TD><TD>optional, only used for zone transfers</TD></TR>
<TR><TD>DNSadminmailbox</TD><TD><I>Hostmaster's contact address</I></TD><TD>optional</TD></TR>
<TR><TD>DNSzonemaster</TD><TD><I>Primary nameserver for this zone</I></TD><TD>optional</TD></TR>
<TR><TD>DNStype</TD><TD>SOA</TD><TD>must be SOA</TD></TR>
<TR><TD>DNSclass</TD><TD>IN</TD><TD>must be IN</TD></TR>
<TR><TD>DNSttl</TD><TD><I>time to live</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>
<UL>
<LI><B>DNSzonename:</B> This field is rquired 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
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
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>
<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
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>DNSadminmailbox:</B> This is the contact address of Your DNS-administrator. The first dot
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>DNSclass:</B> Must be <B>IN</B> (which stands for Internet, or do You have anything else?)</LI>
<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
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
string as external TAI64 timestamp, printed as 16 lowercase hexadecimal characters</LI>
</UL>
<P>
<H4>DNSrrset</H4>
The Resource Record Set represents all of the resource records for
a given host name within a zone. It must be a child of a DNSzone object.<BR>
<TABLE bgcolor=#EEEEEE>
<TR><TH>ATTRIBUTE</TH><TH>VALUE</TH><TH>Comment</TH></TR>
<TR><TD>objectclass</TD><TD>DNSrrset</TD><TD>required</TD></TR>
<TR><TD>cn</TD><TD><I>common name</I></TD><TD>required</TD></TR>
<TR><TD>DNSdomainname</TD><TD><I>Name of this record</I></TD><TD>optional, relative to zonename</TD></TR>
<TR><TD>DNSipaddr</TD><TD><I>IP address</I></TD><TD>optional, mutivalued</TD></TR>
<TR><TD>DNScname</TD><TD><I>Canonical name</I></TD><TD>optional, without ending dot relative to zonename</TD></TR>
<TR><TD>DNSpreference</TD><TD><I>integer</I></TD><TD>optional, only used for MX records</TD></TR>
<TR><TD>DNStype</TD><TD>A, CNAME, NS, MX, PTR or TXT</TD><TD>must be any valid record type</TD></TR>
<TR><TD>DNSclass</TD><TD>IN</TD><TD>must be IN</TD></TR>
<TR><TD>DNSttl</TD><TD><I>time to live</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>
<P>
<UL>
<LI><B>DNSrrset:</B> This object-class must be a direct child of DNSzone. Its <B>dn</B> must be
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
zonename.</LI>
<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
IP-address for a service. If used in combination with <B>PTR</B> it 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
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
absolute. If it does not contain a dot, it name is prepended to the zonename.</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
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>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
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
string as external TAI64 timestamp, printed as 16 lowercase hexadecimal characters</LI>
</UL>
<P>
<H3>2. Installation</H3>
<UL>
<LI>Install an LDAP server such as <A HREF="www.openldap.org">openldap</A>. Other
LDAP implementations may work but have not been tested. Also install the
development libraries and include files.</LI>
<LI>Install <A HREF="http://cr.yp.to/djbdns.html">djbdns</A> or if You really
have to, go with BIND.<BR>
I suggest to install tinydns included in the <B>djbdns</B> package, because it is
safer, but You may have reasons why You want to use BIND.</LI>
<LI>Install <B>ldap2dns</B><BR>
Unpack the package with gzcat ldap2dns.tar.gz | tar x
If You use <B>tinydns</B> put the directory dns2ldap onto
the same directory level where You have the directory dnscache.
cd into the package and type make.</LI>
<LI>If You do not want to use tinydns edit the Makefile,
comment the lines starting with WITHTINYDNS and ALIBS. Then do a make.</LI>
<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
appropriate and add the following two lines to Your slapd.conf file:<BR>
<PRE>
include /etc/openldap/dns.at.conf
include /etc/openldap/dns.oc.conf
</PRE>
or, if You are using openldap-2.0.x:<BR>
copy the file dns.schema into the directory /etc/openldap/schema or
appropriate and add the following line to Your slapd.conf file:<BR>
<PRE>
include /etc/openldap/schema/dns.schema
</PRE>
Now restart Your LDAP server.</LI>
<P>
<LI>Start to populate Your LDAP server with DNS information, as a first test do
<PRE>
$ ldapadd -D "<I>binddn</I>" -w <I>password</I> < example.ldif
</PRE>
Replace 'myorg' and 'binddn' with whatever is appropriate on Your system.
Start a search and see if something was added
<PRE>
$ ldapsearch -D "<I>binddn</I>" "objectclass=dnsrrset" </LI>
</PRE>
<LI>Test <B>ldap2dns</B>
<PRE>
$ ./ldap2dns -D "<I>binddn</I>" [ -b "<I>searchbase</I>" ] [ -w <I>passwd</I> ] -o 7 -L
</PRE>
This should create a 'data' file, a 'data.cdb' file, a 'corp.local.db'
file and should print the DNS content. If You disabled the tinydns
option no 'data.cdb' file is generated.<BR>
Note: The 'data' file is text data which can be processed with tinydns-data.
The 'data.cdb' file is the binary version of 'data' processed as tinydns-data
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>
<P>
<H3>3. Running ldap2dns</H3>
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
or ldapadd.
<PRE>
$ ldap2dns -D "<I>binddn</I>" [ -w <I>passwd</I> ] -b "<I>searchbase</I>" -o 1
</PRE>
This generates a data.cdb file which is automatically updated by tinydns. The password
is required if You restrict read queries to authenticated users only. Now test with
<PRE>
$ dnsq any corp.local <I>ipaddr</I>
</PRE>
Replace <I>ipaddr</I> with whatever You configured tinydns to listen to.
<P>
If You are a BIND user, run <B>ldap2dns</B> in /var/named with
<PRE>
$ ldap2dns -D "<I>binddn</I>" -w <I>passwd</I> -b "<I>searchbase</I>" -o 4
</PRE>
Do not forget to add You primary definition to Your named.boot file and
do not forget to restart named with
<PRE>
# kill -HUP <I>PID</I>
</PRE>
Now run
<PRE>
$ nslookup - localhost
> ns1.corp.local
</PRE>
Note that nslookup only works with tinydns if Your nameserver resolves its IP-address
backwards.
<P>
<H3>4. Running ldap2dnsd</H3>
<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.
If the the daemon sees a modification in the <B>DNSserial</B> numbers it updates the data.cdb
file. 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>.
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
<A HREF="http://cr.yp.to/daemontools.html">daemontools</A>. To do this run <B>ldap2tinydns-conf</B>
in /service/tinydns and link /service/ldap2dns onto /service/tinydns/ldap2dns.
<PRE>
# ln -s /service/tinydns/ldap2dns /service/ldap2dns
</PRE>
After a few seconds <B>daemontools</B> starts <B>ldap2dns</B> which itself generates data.cdb
files whenever a modification is commited into the LDAP directory.
<P>
<B>ldap2dns</B> and <B>ldap2dnsd</B> recognize the following options:
<PRE>
-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
-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
1: generate a binary file named 'data.cdb' to be used directly by tinydns
2: generate a text file named 'data' to be parsed by tinydns-data
4: for each zone generate a file named '<zonename>.db' to be used by named
-L[<I>filename</I>] print output in LDIF format for reimport, defaults to stdout if filename is omitted
-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
-vv even more verbose
-V print version and exit
-u <I>numsecs</I> update DNS data every numsecs. If started as ldap2dnsd this defaults to 59.
</PRE>
<P>
<H3>5. Importing DNS data from Your named</H3>
A perl-script 'import.pl' is contained in this package. Edit the first
lines of the script to conform to Your configuration.
If You have installed the Perl packages Net::LDAP and Net::DNS
skip the following lines, otherwise do
<PRE>
# perl -MCPAN -e 'shell'
(...snip...)
> install Net::DNS
> install Net::LDAP
</PRE>
Now check that Your nameserver allows zone transfers to Your host and run the import script:
<PRE>
$ echo 'primary mydomain.org ' | ./import.pl
</PRE>
for a single domain or
<PRE>
# cat named.boot | ./import.pl
</PRE>
to populate Your LDAP directory.
<P>
<H3>5. To Do</H3>
<UL>
<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>The option -o is not very nice.</LI>
</UL>
<P>
<H3>6. Copyright</H3>
This program is licensed under the GPL version 2 or at Your choice any later
version.<BR>
It was written in autumn 2000 by
<A HREF="mailto:jacob.rief@bigfoot.com?subject=ldap2dns">Jacob Rief</A>
in the hope it may be useful.

53
Specfile Normal file
View File

@@ -0,0 +1,53 @@
%define djbdns djbdns-1.02
Summary: LDAP to DNS gateway.
Name: ldap2dns
Version: %VERSION%
Release: %RELEASE%
Copyright: GPL
Group: Daemons/DNS
Source: ldap2dns-%{version}.tar.gz
Source1: http://cr.yp.to/djbdns/%{djbdns}.tar.gz
BuildRoot: /var/tmp/%{name}-root
Requires: openldap
%description
ldap2dns is a program to create DNS records directly from an LDAP database. It can
be be used to replace the secondary name-server by a second primary one.
ldap2dns helps to reduce all kind of administration overhead. No more flat file editing,
no more zone file editing. After having installed ldap2dns, the administrator only has
to access the LDAP database.
If he desires he can add access control for each zone, create a webbased GUI and add
all other kind of zone and resource record information without interfering with the DNS
server.
ldap2dns is designed to write binary data.cdb files used by tinydns, but also may be
used to write .db-files used by named.
%prep
%setup -a1 -q
%build
make -C %{djbdns}
make DJBDNSDIR="%{djbdns}" VERSION=%{version} RPM_OPT_FLAGS="$RPM_OPT_FLAGS"
%install
[ -n "%{buildroot}" -a "%{buildroot}" != / ] && rm -rf %{buildroot}
make DJBDNSDIR="%{djbdns}" INSTALL_PREFIX=$RPM_BUILD_ROOT install
%clean
[ -n "%{buildroot}" -a "%{buildroot}" != / ] && rm -rf %{buildroot}
%files
%defattr(-,root,root)
/usr/bin/ldap2dns
/usr/bin/ldap2dnsd
/usr/bin/ldap2tinydns-conf
%doc README.html
%doc import.pl
%config /etc/openldap/dns.at.conf
%config /etc/openldap/dns.oc.conf
%changelog
* Wed Dec 06 2000 Jacob Rief <jacob.rief@tiscover.com>
- initial revision for version 0.2.0

24
dns.at.conf Normal file
View File

@@ -0,0 +1,24 @@
# include this file into Your slapd.conf for openldap-1.2.x
# $Id: dns.at.conf,v 1.5 2000/12/04 12:59:57 jrief Exp $
attribute DNSzonename cis
attribute DNSserial cis
attribute DNSrefresh cis
attribute DNSretry cis
attribute DNSexpire cis
attribute DNSminimum cis
attribute DNSadminmailbox cis
attribute DNSzonemaster cis
attribute DNStype cis
attribute DNSclass cis
attribute DNSdomainname cis
attribute DNSipaddr cis
attribute DNScname cis
attribute DNSpreference cis
attribute DNSttl cis
attribute DNStimestamp cis
#attribute DNSaliasedobjectname cis
#attribute DNSrr cis
#attribute DNSrrcount cis
#attribute DNSmacaddress cis

45
dns.oc.conf Normal file
View File

@@ -0,0 +1,45 @@
# include this file into Your slapd.conf for openldap-1.2.x
# $Id: dns.oc.conf,v 1.4 2000/12/01 14:48:25 jrief Exp $
# child of anybody
# information to setup a DNS zone
objectclass DNSzone
requires
objectclass,
cn
allows
DNSzonename,
DNSserial,
DNSrefresh,
DNSretry,
DNSexpire,
DNSminimum,
DNSadminmailbox,
DNSzonemaster,
DNStype,
DNSclass,
DNSttl,
DNStimestamp
#DNSrrcount,
# child of a DNSzone
# information to setup a resource record
objectclass DNSrrset
requires
objectclass,
cn
allows
DNSdomainname,
DNSclass,
DNStype,
DNSipaddr,
DNScname,
DNSpreference,
DNSttl,
DNStimestamp
#DNSaliasedobjectname,
#DNSrr,
#DNSmacaddress,

111
dns.schema Normal file
View File

@@ -0,0 +1,111 @@
# schema for DNS data
# 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 $
attributetype ( 1.2.840.113556.1.17.1
NAME 'DNSzonename'
SUP name )
attributetype ( 1.2.840.113556.1.17.2
NAME 'DNSserial'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
SINGLE-VALUE )
attributetype ( 1.2.840.113556.1.17.3
NAME 'DNSrefresh'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
SINGLE-VALUE )
attributetype ( 1.2.840.113556.1.17.4
NAME 'DNSretry'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
SINGLE-VALUE )
attributetype ( 1.2.840.113556.1.17.5
NAME 'DNSexpire'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
SINGLE-VALUE )
attributetype ( 1.2.840.113556.1.17.6
NAME 'DNSminimum'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
SINGLE-VALUE )
attributetype ( 1.2.840.113556.1.17.7
NAME 'DNSadminmailbox'
SUP name )
attributetype ( 1.2.840.113556.1.17.8
NAME 'DNSzonemaster'
SUP name )
attributetype ( 1.2.840.113556.1.17.9
NAME 'DNStype'
SUP name )
attributetype ( 1.2.840.113556.1.17.10
NAME 'DNSclass'
SUP name )
attributetype ( 1.2.840.113556.1.17.11
NAME 'DNSdomainname'
SUP name )
attributetype ( 1.2.840.113556.1.17.12
NAME 'DNSipaddr'
EQUALITY numericStringMatch
SUBSTR numericStringSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )
#attributetype ( 1.2.840.113556.1.17.13
# NAME 'DNSaliasedobjectname'
# SUP name )
#attributetype ( 1.2.840.113556.1.17.14
# NAME 'DNSrrcount'
# SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
# SINGLE-VALUE )
#attributetype ( 1.2.840.113556.1.17.15
# NAME 'DNSmacaddress'
# SYNTAX 1.3.6.1.4.1.1466.115.121.1.38
# SINGLE-VALUE )
attributetype ( 1.2.840.113556.1.17.16
NAME 'DNScname'
SUP name )
attributetype ( 1.2.840.113556.1.17.17
NAME 'DNSpreference'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
SINGLE-VALUE )
attributetype ( 1.2.840.113556.1.17.18
NAME 'DNSrr'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
SINGLE-VALUE )
attributetype ( 1.2.840.113556.1.17.19
NAME 'DNSttl'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
SINGLE-VALUE )
attributetype ( 1.2.840.113556.1.17.20
NAME 'DNStimestamp'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
SINGLE-VALUE )
objectclass ( 1.2.840.113556.1.17.21
NAME 'DNSzone'
MUST ( objectclass $ cn )
MAY ( zonedomainname $ serial $ refresh $ retry $ expire $ minimum
$ adminmailbox $ zonemaster $ zonetype $ zoneclass $ rrcount
$ ttl $ timestamp ) )
objectclass ( 1.2.840.113556.1.17.22
NAME 'DNSrrset'
SUP DNSzone
MUST ( objectclass $ cn )
MAY ( dnsdomainname $ aliasedobjectname $ rr $ macaddress $ zoneclass
$ zonetype $ ipaddr $ cname $ preference $ ttl $ timestamp ) )

45
example.ldif Normal file
View File

@@ -0,0 +1,45 @@
dn: ou=dns,o=myorg
objectclass: organizationalUnit
ou: dns
userpassword: dnsadmin
dn: cn=corp.local,ou=dns,o=myorg
objectclass: DNSzone
cn: corp.local
DNSzonename: corp.local
DNSserial: 12345
DNSrefresh: 10800
DNSretry: 3600
DNSexpire: 3600000
DNSminimum: 86400
DNSadminmailbox: domainmaster.myorg
DNSzonemaster: ldap.myorg
dn: cn=mail,cn=corp.local,ou=dns,o=myorg
objectclass: DNSrrset
cn: mail
DNScname: mail
DNStype: mx
DNSipaddr: 17.19.21.23
dn: cn=ns1,cn=corp.local,ou=dns,o=myorg
objectclass: DNSrrset
cn: ns1
DNScname: ns1
DNStype: ns
DNSipaddr: 17.19.23.24
dn: cn=ns2,cn=corp.local,ou=dns,o=myorg
objectclass: DNSrrset
cn: ns2
DNScname: ns2
DNStype: ns
DNSipaddr: 17.19.23.25
dn: cn=www,cn=corp.local,ou=dns,o=myorg
objectclass: DNSrrset
cn: www
DNSdomainname: www
DNStype: a
DNSipaddr: 17.19.23.30

241
import.pl Executable file
View File

@@ -0,0 +1,241 @@
#!/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_.+-]+)/);
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;
$attr{'DNScname'} = $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);
}
}
}

41
index.html Normal file
View File

@@ -0,0 +1,41 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<HTML>
<HEAD>
<TITLE>LDAP to DNS gateway</TITLE>
<STYLE TYPE="text/css">
H1 {
font-weight: bold;
font-size: 18pt;
line-height: 18pt;
font-family: arial,helvetica;
font-variant: normal;
font-style: normal;
}
</STYLE>
</HEAD>
<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
<BODY
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#000080"
ALINK="#FF0000"
>
<BLOCKQUOTE>
<P>
<!--#include file="README.html"--->
<P>
<H3 align=center>Download</H3>
<TABLE border=2 cellpadding=4 align=center>
<TR align=center><TH>Version</TH><TH>tar.gz</TH><TH>rpm</TH><TH>srpm</TH><TH>Released</TH></TR>
<TR align=center><TD>0.1.1</TD><TD><A HREF="ldap2dns-0.1.1.tar.gz">ldap2dns</A></TD><TD></TD><TD></TD><TD>2000-Sep-19</TD></TR>
<TR align=center><TD>0.1.2</TD><TD><A HREF="ldap2dns-0.1.2.tar.gz">ldap2dns</A></TD><TD></TD><TD></TD><TD>2000-Sep-22</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.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>
</TABLE>
</BLOCKQUOTE>
</BODY>
</HTML>

915
ldap2dns.c Normal file
View File

@@ -0,0 +1,915 @@
/*
* 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 $
* Copyright 2000 by Jacob Rief <jacob.rief@tiscover.com>
* License: GPL version 2 or later. See http://www.fsf.org for details
*/
#include <lber.h>
#include <ldap.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#define UPDATE_INTERVALL 59
#define LDAP_CONF "/etc/openldap/ldap.conf"
#if defined WITH_TINYDNS
# 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 LDAP* ldap_con;
static FILE* bindfile;
static FILE* tinyfile;
static FILE* ldifout;
static time_t time_now;
static int autoreverse;
static char* const* main_argv;
static int main_argc;
static void print_version(void)
{
printf("ldap2dns, version %s\n", VERSION);
printf(" Copyright 2000 by Jacob Rief <jacob.rief@tiscover.com>\n\n");
}
static void die_ldap(int err)
{
fprintf(stderr, "Fatal error: %s\n", ldap_err2string(err));
exit(1);
}
static struct
{
char domainname[64];
char zonemaster[64];
char adminmailbox[64];
unsigned long serial;
unsigned long refresh;
unsigned long retry;
unsigned long expire;
unsigned long minimum;
int ttl;
char timestamp[16];
} zone;
struct resourcerecord
{
char cn[64];
char dnsdomainname[64];
char class[16];
char type[16];
char ipaddr[256][32];
char cname[64];
int ttl;
char timestamp[16];
int preference;
#if defined DRAFT_RFC
char rr[1024];
char aliasedobjectname[256];
char macaddress[32];
#endif
};
static struct
{
char searchbase[128];
char binddn[128];
char hostname[128];
char password[128];
int is_daemon;
int update_iv;
int port;
unsigned int output;
int verbose;
char ldifname[128];
} options;
static void die_exit(const char* message)
{
if (message)
fprintf(stderr, "Fatal error: %s\n", message);
else
fprintf(stderr, "Fatal memory error\n");
exit(1);
}
#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)
{
char* ev = getenv("TINYDNSDIR");
int len;
#if defined WITH_TINYDNS
tinydns_datafile[0] = 0;
tinydns_tempfile[0] = 0;
#endif
tinydns_textfile[0] = 0;
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);
if (ev[len-1]!='/') {
#if defined WITH_TINYDNS
tinydns_datafile[len] = '/';
tinydns_tempfile[len] = '/';
#endif
tinydns_textfile[len] = '/';
}
}
#if defined WITH_TINYDNS
strcat(tinydns_datafile, "data.cdb");
strcat(tinydns_tempfile, "data.tmp");
#endif
strcat(tinydns_textfile, "data");
}
static void print_usage(void)
{
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("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\tldap2dnsd starts as background-job and continouesly updates DNS information.\n");
printf("options:\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(" -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("\t1: generate a binary file named 'data.cdb' to be used directly by tinydns\n");
printf("\t2: generate a text file named 'data' to be parsed by tinydns-data\n");
printf("\t4: for each zone generate a file named '<zonename>.db' to be used by named\n");
printf(" -L[filename] print output in LDIF format for reimport\n");
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"
"Important notice: data.cdb is rewritten only after DNSserial in DNSzone is increased.\n",
UPDATE_INTERVALL);
printf(" -v\t\trun in verbose mode\n");
printf(" -vv\t\teven more verbose\n");
printf(" -V\t\tprint version and exit\n\n");
}
static int parse_options()
{
extern char* optarg;
extern int optind, opterr, optopt;
char buf[256], value[128];
int c;
FILE* ldap_conf;
strcpy(options.searchbase, "");
strcpy(options.hostname, "localhost");
options.port = LDAP_PORT;
if (ldap_conf = fopen(LDAP_CONF, "r")) {
while(fgets(buf, 256, ldap_conf)!=0) {
if (sscanf(buf, "BASE %128s", value)==1)
strcpy(options.searchbase, value);
if (sscanf(buf, "HOST %128s:%d", value, &c)==2) {
strcpy(options.hostname, value);
options.port = c;
} else if (sscanf(buf, "HOST %128s", value)==1)
strcpy(options.hostname, value);
if (sscanf(buf, "PORT %d", &c)==1)
options.port = c;
}
fclose(ldap_conf);
}
strcpy(options.binddn, "");
options.output = 1;
options.verbose = 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, "");
while ( (c = getopt(main_argc, main_argv, "b:D:h:o:p:u:Vw:v::L::"))>0 ) {
if (optarg && strlen(optarg)>127) {
fprintf(stderr, "argument %s too long\n", optarg);
continue;
}
switch (c) {
case 'b':
strcpy(options.searchbase, optarg);
break;
case 'u':
if (sscanf(optarg, "%d", &options.update_iv)!=1)
options.update_iv = UPDATE_INTERVALL;
if (options.update_iv<=0) options.update_iv = 1;
if (options.is_daemon==0) options.is_daemon = 2; /* foreground daemon */
break;
case 'D':
strcpy(options.binddn, optarg);
break;
case 'h':
strcpy(options.hostname, optarg);
break;
case 'L':
if (optarg==NULL)
strcpy(options.ldifname, "-");
else
strcpy(options.ldifname, optarg);
break;
case 'o':
if (sscanf(optarg, "%d", &options.output)!=1)
options.output = 0;
break;
case 'p':
if (sscanf(optarg, "%d", &options.port)!=1)
options.port = LDAP_PORT;
break;
case 'v':
if (optarg && optarg[0]=='v')
options.verbose = 3;
else
options.verbose = 1;
break;
case 'V':
print_version();
exit(0);
case 'w':
strcpy(options.password, optarg);
break;
default:
print_usage();
exit(1);
}
}
}
static int expand_domainname(char target[64], const char* source, int slen)
{
if (slen>64)
return 0;
if (source[slen-1]=='.') {
strncpy(target, source, slen-1);
target[slen-1] = '\0';
return 1;
}
strncpy(target, source, slen);
target[slen] = '\0';
if (zone.domainname[0]) {
if (zone.domainname[0]!='.')
strcat(target, ".");
strcat(target, zone.domainname);
return 1;
}
return 0;
}
static int expand_reverse(char target[64], const char* source)
{
}
static void write_rr(struct resourcerecord* rr, int ipdx)
{
char ip[4];
char buf[4];
if (strcasecmp(rr->class, "IN"))
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 (tinyfile)
fprintf(tinyfile, "&%s:%s:%s:%d:%s\n", rr->dnsdomainname, (ipdx>=0 ? rr->ipaddr[ipdx] : ""), rr->cname, rr->ttl, rr->timestamp);
if (bindfile) {
fprintf(bindfile, "%s.\tIN NS\t%s.\n", rr->dnsdomainname, rr->cname);
if (ipdx>=0)
fprintf(bindfile, "%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) {
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 (bindfile) {
fprintf(bindfile, "%s.\tIN MX\t%d %s.\n", rr->dnsdomainname, rr->preference, rr->cname);
if (ipdx>=0)
fprintf(bindfile, "%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) {
if (tinyfile)
fprintf(tinyfile, "%s%s:%s:%d:%s\n", (autoreverse ? "=" : "+"), rr->dnsdomainname, (ipdx>=0 ? rr->ipaddr[ipdx] : ""), rr->ttl, rr->timestamp);
if (bindfile && ipdx>=0)
fprintf(bindfile, "%s.\tIN A\t%s\n", rr->dnsdomainname, rr->ipaddr[ipdx]);
#if defined WITH_TINYDNS
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) {
dns_name4_domain(dptr, ip);
rr_start(DNS_T_PTR, rr->ttl, rr->timestamp);
rr_addname(dottemp1);
rr_finish(dptr);
}
}
#endif
} else if (strcasecmp(rr->type, "PTR")==0) {
int ip[4] = {0, 0, 0, 0};
char buf[64];
if (ipdx>0) {
/* does not make to have more than one IPaddr for a PTR record */
return;
}
if (ipdx==0 && sscanf(rr->ipaddr[0], "%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3])==4) {
/* lazy user, used DNSipaddr for reverse lookup */
sprintf(buf, "%d.%d.%d.%d.in-addr.arpa", ip[3], ip[2], ip[1], ip[0]);
} else {
strcpy(buf, rr->dnsdomainname);
}
if (tinyfile)
fprintf(tinyfile, "^%s:%s:%d:%s\n", buf, rr->cname, rr->ttl, rr->timestamp);
if (bindfile)
fprintf(bindfile, "%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) {
if (tinyfile)
fprintf(tinyfile, "C%s:%s:%d:%s\n", rr->dnsdomainname, rr->cname, rr->ttl, rr->timestamp);
if (bindfile)
fprintf(bindfile, "%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) {
if (tinyfile)
fprintf(tinyfile, "'%s:%s:%d:%s\n", rr->dnsdomainname, rr->cname, rr->ttl, rr->timestamp);
if (bindfile)
fprintf(bindfile, "%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
}
}
#if defined DRAFT_RFC
static void parse_rr(struct resourcerecord* rr)
{
char word1[64];
char word2[64];
int ip[4];
sscanf(rr->rr, "%16s %16s %64s %64s", rr->class, rr->type, word1, word2);
if (strcasecmp(rr->type, "NS")==0) {
if (sscanf(word1, "%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3])==4) {
sprintf(rr->ipaddr[0], "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
} else {
int len = strlen(word1);
expand_domainname(rr->cname, word1, len);
}
} else if (strcasecmp(rr->type, "MX")==0) {
if (sscanf(word1, "%d", &rr->preference)!=1)
rr->preference = 0;
if (sscanf(word2, "%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3])==4) {
sprintf(rr->ipaddr[0], "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
} else {
int len = strlen(word2);
expand_domainname(rr->cname, word2, len);
}
} else if (strcasecmp(rr->type, "A")==0) {
if (sscanf(word1, "%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3])==4)
sprintf(rr->ipaddr[0], "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
else
rr->ipaddr[0][0] = '\0';
} else if (strcasecmp(rr->type, "PTR")==0) {
expand_reverse(rr->dnsdomainname, word1);
} else if (strcasecmp(rr->type, "CNAME")==0) {
int len = strlen(word1);
expand_reverse(rr->cname, word1);
} else if (strcasecmp(rr->type, "TXT")==0) {
strncpy(rr->cname, word1, 64);
}
}
#endif
static void read_resourcerecords(char* dn)
{
LDAPMessage* res = NULL;
LDAPMessage* m;
int ldaperr;
if ( (ldaperr = ldap_search_s(ldap_con, dn, LDAP_SCOPE_ONELEVEL, "objectclass=DNSrrset", NULL, 0, &res))!=LDAP_SUCCESS )
die_ldap(ldaperr);
for (m = ldap_first_entry(ldap_con, res); m; m = ldap_next_entry(ldap_con, m)) {
BerElement* ber = NULL;
char* attr;
char* dn = ldap_get_dn(ldap_con, m);
struct resourcerecord rr;
int ipaddresses = 0;
if (options.ldifname[0])
fprintf(ldifout, "dn: %s\n", dn);
rr.cn[0] = '\0';
strncpy(rr.dnsdomainname, zone.domainname, 64);
strcpy(rr.class, "IN");
rr.type[0] = '\0';
rr.cname[0] = '\0';
rr.ttl = time_now;
rr.timestamp[0] = '\0';
rr.preference = 10;
#if defined DRAFT_RFC
rr.aliasedobjectname[0] = '\0';
rr.rr[0] = '\0';
#endif
for (attr = ldap_first_attribute(ldap_con, m, &ber); attr; attr = ldap_next_attribute(ldap_con, m, ber)) {
int len = strlen(attr);
struct berval** bvals;
char* dnsnname = "";
if ( (bvals = ldap_get_values_len(ldap_con, m, attr))!=NULL ) {
if (bvals[0] && bvals[0]->bv_len>0) {
if (strcasecmp(attr, "objectclass")==0) {
if (options.ldifname[0])
fprintf(ldifout, "%s: %s\n", attr, bvals[0]->bv_val);
} else if (strcasecmp(attr, "cn")==0) {
strncpy(rr.cn, bvals[0]->bv_val, 64);
if (options.ldifname[0])
fprintf(ldifout, "%s: %s\n", attr, rr.cn);
} else if (strcasecmp(attr, "DNSdomainname")==0) {
if (!expand_domainname(rr.dnsdomainname, bvals[0]->bv_val, bvals[0]->bv_len))
rr.dnsdomainname[0] = '\0';;
if (options.ldifname[0])
fprintf(ldifout, "%s: %s\n", attr, bvals[0]->bv_val);
} else if (strcasecmp(attr, "DNSclass")==0) {
if (sscanf(bvals[0]->bv_val, "%16s", &rr.class)!=1)
rr.class[0] = '\0';
if (options.ldifname[0])
fprintf(ldifout, "%s: %s\n", attr, rr.class);
} else if (strcasecmp(attr, "DNStype")==0) {
if (sscanf(bvals[0]->bv_val, "%16s", &rr.type)!=1)
rr.type[0] = '\0';
if (options.ldifname[0])
fprintf(ldifout, "%s: %s\n", attr, rr.type);
} else if (strcasecmp(attr, "DNSipaddr")==0) {
int ip[4];
for (ipaddresses = 0; bvals[ipaddresses] && ipaddresses<256; ipaddresses++) {
rr.ipaddr[ipaddresses][0] = '\0';
if (sscanf(bvals[ipaddresses]->bv_val, "%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3])==4)
sprintf(rr.ipaddr[ipaddresses], "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
if (options.ldifname[0])
fprintf(ldifout, "%s: %s\n", attr, rr.ipaddr[ipaddresses]);
}
} else if (strcasecmp(attr, "DNScname")==0) {
if (!expand_domainname(rr.cname, bvals[0]->bv_val, bvals[0]->bv_len))
rr.cname[0] = '\0';
if (options.ldifname[0])
fprintf(ldifout, "%s: %s\n", attr, bvals[0]->bv_val);
} else if (strcasecmp(attr, "DNSttl")==0) {
if (sscanf(bvals[0]->bv_val, "%d", &rr.ttl)!=1)
rr.ttl = time_now;
if (options.ldifname[0])
fprintf(ldifout, "%s: %d\n", attr, rr.ttl);
} else if (strcasecmp(attr, "DNStimestamp")==0) {
if (sscanf(bvals[0]->bv_val, "%16s", &rr.timestamp)!=1)
rr.timestamp[0] = '\0';
if (options.ldifname[0])
fprintf(ldifout, "%s: %s\n", attr, rr.timestamp);
} else if (strcasecmp(attr, "DNSpreference")==0) {
if (sscanf(bvals[0]->bv_val, "%d", &rr.preference)!=1)
rr.preference = 10;
if (options.ldifname[0])
fprintf(ldifout, "%s: %s\n", attr, bvals[0]->bv_val);
}
#if defined DRAFT_RFC
else if (strcasecmp(attr, "DNSrr")==0) {
strncpy(rr.rr, bvals[0]->bv_val, 1024);
if (options.ldifname[0])
fprintf(ldifout, "%s: %s\n", attr, rr.rr);
} else if (strcasecmp(attr, "DNSaliasedobjectname")==0) {
if (sscanf(bvals[0]->bv_val, "%256s", rr.aliasedobjectname)!=1)
rr.aliasedobjectname[0] = '\0';
if (options.ldifname[0])
fprintf(ldifout, "%s: %s\n", attr, rr.aliasedobjectname);
} else if (strcasecmp(attr, "DNSmacaddress")==0) {
}
#endif
}
ldap_value_free_len(bvals);
}
}
#if defined DRAFT_RFC
if (rr.rr[0]) {
parse_rr(&rr);
}
#endif
do {
ipaddresses--;
write_rr(&rr, ipaddresses);
} while (ipaddresses>0);
#if defined DRAFT_RFC
if (rr.aliasedobjectname[0])
read_resourcerecords(rr.aliasedobjectname);
#endif
if (options.ldifname[0])
fprintf(ldifout, "\n");
if (options.verbose&2)
printf("\trr: %s %s %s\n", rr.class, rr.type, rr.dnsdomainname);
free(dn);
}
ldap_msgfree(res);
}
static void write_zone(void)
{
int len;
char soa[20];
if (tinyfile) {
fprintf(tinyfile, "Z%s:%s:%s:%d:%d:%d:%d:%d:%d:%s\n", zone.domainname,
zone.zonemaster, zone.adminmailbox, zone.serial, zone.refresh, zone.retry,
zone.expire, zone.minimum, zone.ttl, zone.timestamp);
}
if (bindfile) {
fprintf(bindfile, "; Automatically generated by ldap2dns - DO NOT EDIT!\n");
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 defined WITH_TINYDNS
if (options.output&1) {
byte_zero(zone.timestamp, 8);
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);
if (!dns_domain_fromdot(&dottemp2, zone.zonemaster, len)) die_exit(0);
rr_addname(dottemp2);
len = strlen(zone.adminmailbox);
if (!dns_domain_fromdot(&dottemp2, zone.adminmailbox, len)) die_exit(0);
rr_addname(dottemp2);
rr_add(soa, 20);
rr_finish(dottemp1);
}
#endif
if (options.ldifname[0])
fprintf(ldifout, "\n");
}
static void calc_checksum(int* num, int* sum)
{
LDAPMessage* res = NULL;
LDAPMessage* m;
int ldaperr;
char* attr_list[2] = { "DNSserial", NULL };
*num = *sum = 0;
if ( ldaperr = ldap_search_s(ldap_con, options.searchbase[0] ? options.searchbase : NULL, LDAP_SCOPE_SUBTREE, "objectclass=DNSzone", attr_list, 0, &res)!=LDAP_SUCCESS )
die_ldap(ldaperr);
for (m = ldap_first_entry(ldap_con, res); m; m = ldap_next_entry(ldap_con, m)) {
BerElement* ber = NULL;
char* attr = ldap_first_attribute(ldap_con, m, &ber);
if (attr) {
struct berval** bvals = ldap_get_values_len(ldap_con, m, attr);
if (bvals!=NULL) {
unsigned tmp;
if (sscanf(bvals[0]->bv_val, "%u", &tmp)==1) {
(*num)++;
*sum += tmp;
}
ldap_value_free_len(bvals);
}
}
ber_free(ber, 0);
}
ldap_msgfree(res);
}
static void read_dnszones(void)
{
LDAPMessage* res = NULL;
LDAPMessage* m;
int ldaperr;
if (tinyfile)
fprintf(tinyfile, "# 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 )
die_ldap(ldaperr);
for (m = ldap_first_entry(ldap_con, res); m; m = ldap_next_entry(ldap_con, m)) {
BerElement* ber = NULL;
char* attr;
char* dn;
int i, zonenames = 0;
char zdn[256][64];
char ldif0;
zone.serial = time_now;
zone.refresh = 10800;
zone.retry = 3600;
zone.expire = 604800;
zone.minimum = 86400;
zone.ttl = time_now;
zone.timestamp[0] = '\0';
dn = ldap_get_dn(ldap_con, m);
if (options.ldifname[0])
fprintf(ldifout, "dn: %s\n", dn);
for (attr = ldap_first_attribute(ldap_con, m, &ber); attr; attr = ldap_next_attribute(ldap_con, m, ber)) {
struct berval** bvals = ldap_get_values_len(ldap_con, m, attr);
if (bvals!=NULL) {
if (bvals[0] && bvals[0]->bv_len>0) {
if (strcasecmp(attr, "objectclass")==0
|| strcasecmp(attr, "DNSclass")==0
|| strcasecmp(attr, "DNStype")==0
|| strcasecmp(attr, "cn")==0) {
if (options.ldifname[0])
fprintf(ldifout, "%s: %s\n", attr, bvals[0]->bv_val);
} else if (strcasecmp(attr, "DNSzonename")==0) {
for (zonenames = 0; bvals[zonenames] && zonenames<256; zonenames++) {
if (sscanf(bvals[zonenames]->bv_val, "%64s", &zdn[zonenames])!=1)
zdn[zonenames][0] = '\0';
if (options.ldifname[0])
fprintf(ldifout, "%s: %s\n", attr, zdn[zonenames]);
}
} else if (strcasecmp(attr, "DNSserial")==0) {
sscanf(bvals[0]->bv_val, "%u", &zone.serial);
if (options.ldifname[0])
fprintf(ldifout, "%s: %d\n", attr, zone.serial);
} else if (strcasecmp(attr, "DNSrefresh")==0) {
sscanf(bvals[0]->bv_val, "%u", &zone.refresh);
if (options.ldifname[0])
fprintf(ldifout, "%s: %d\n", attr, zone.refresh);
} else if (strcasecmp(attr, "DNSretry")==0) {
sscanf(bvals[0]->bv_val, "%u", &zone.retry);
if (options.ldifname[0])
fprintf(ldifout, "%s: %d\n", attr, zone.retry);
} else if (strcasecmp(attr, "DNSexpire")==0) {
sscanf(bvals[0]->bv_val, "%u", &zone.expire);
if (options.ldifname[0])
fprintf(ldifout, "%s: %d\n", attr, zone.expire);
} else if (strcasecmp(attr, "DNSminimum")==0) {
sscanf(bvals[0]->bv_val, "%u", &zone.minimum);
if (options.ldifname[0])
fprintf(ldifout, "%s: %d\n", attr, zone.minimum);
} else if (strcasecmp(attr, "DNSadminmailbox")==0) {
sscanf(bvals[0]->bv_val, "%64s", zone.adminmailbox);
if (options.ldifname[0])
fprintf(ldifout, "%s: %s\n", attr, zone.adminmailbox);
} else if (strcasecmp(attr, "DNSzonemaster")==0) {
sscanf(bvals[0]->bv_val, "%64s", zone.zonemaster);
if (options.ldifname[0])
fprintf(ldifout, "%s: %s\n", attr, zone.zonemaster);
} else if (strcasecmp(attr, "DNSttl")==0) {
if (sscanf(bvals[0]->bv_val, "%d", &zone.ttl)!=1)
zone.ttl = time_now;
if (options.ldifname[0])
fprintf(ldifout, "%s: %d\n", attr, zone.ttl);
} else if (strcasecmp(attr, "DNStimestamp")==0) {
if (sscanf(bvals[0]->bv_val, "%16s", &zone.timestamp)!=1)
zone.timestamp[0] = '\0';
if (options.ldifname[0])
fprintf(ldifout, "%s: %s\n", attr, zone.timestamp);
}
}
ldap_value_free_len(bvals);
}
}
ldif0 = options.ldifname[0];
for (i = 0; i<zonenames; i++) {
strncpy(zone.domainname, zdn[i], 64);
if (i>0)
options.ldifname[0] = '\0';
if (options.verbose&1)
printf("zonename: %s\n", zone.domainname);
if (options.output&4) {
char bindfilename[128];
sprintf(bindfilename, "%s.db", zone.domainname);
if ( !(bindfile = fopen(bindfilename, "w")) )
die_exit("Unable to open db-file for writing");
}
write_zone();
read_resourcerecords(dn);
if (bindfile)
fclose(bindfile);
if (options.verbose&2)
printf("\n");
if (options.ldifname[0])
fprintf(ldifout, "\n");
}
options.ldifname[0] = ldif0;
free(dn);
}
ldap_msgfree(res);
}
int main(int argc, char** argv)
{
int soa_numzones;
int soa_checksum;
umask(022);
main_argc = argc;
main_argv = argv;
parse_options();
if (options.is_daemon) {
if (options.is_daemon==1 && fork())
exit(0);
/* lowest priority */
nice(19);
}
set_datadir();
for (;;) {
int ldaperr;
if ( !(ldap_con = ldap_init(options.hostname, options.port)) )
die_exit("Unable to initialize connection to LDAP server");
ldaperr = ldap_simple_bind_s(ldap_con, options.binddn, options.password);
if (ldaperr!=LDAP_SUCCESS) {
fprintf(stderr, "Warning - Could not connect to LDAP server %s:%d as '%s'\n", options.hostname, options.port, options.binddn);
sleep(options.update_iv);
continue;
}
if (options.is_daemon) {
int num, sum;
calc_checksum(&num, &sum);
if (num!=soa_numzones || sum!=soa_checksum) {
if (options.verbose&1)
printf("DNSserial has changed in LDAP zone(s)\n");
soa_numzones = num;
soa_checksum = sum;
} else {
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]=='-')
ldifout = stdout;
else
ldifout = fopen(options.ldifname, "w");
if (!ldifout)
die_exit("Unable to open LDIF-file for writing");
}
time(&time_now);
if ( options.output&2 && !(tinyfile = fopen(tinydns_textfile, "w")) )
die_exit("Unable to open file 'data' for writing");
read_dnszones();
if (tinyfile)
fclose(tinyfile);
if (options.ldifname[0] && ldifout)
fclose(ldifout);
#if defined WITH_TINYDNS
if (options.output&1) {
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:
if ( (ldaperr = ldap_unbind_s(ldap_con))!=LDAP_SUCCESS )
die_ldap(ldaperr);
if (options.is_daemon==0)
break;
sleep(options.update_iv);
}
return 0;
}

9
ldap2tinydns-conf Executable file
View File

@@ -0,0 +1,9 @@
#!/bin/sh
mkdir ldap2tinydns
mkdir ldap2tinydns/env
echo "#!/bin/sh" > ldap2tinydns/run
echo "exec 2>&1" >> ldap2tinydns/run
echo "exec envdir ./env softlimit -d250000 /usr/bin/ldap2dns -u 59" >> ldap2tinydns/run
chmod 755 ldap2tinydns/run
echo "/var/tinydns/root" > ldap2tinydns/env/TINYDNSDIR