This is a
followup
on my
previous
work on
merging
all the computer related LDAP objects in Debian Edu.
As a step to try to see if it possible to merge the DNS and DHCP
LDAP objects, I have had a look at how the packages pdns-backend-ldap
and dhcp3-server-ldap in Debian use the LDAP server. The two
implementations are quite different in how they use LDAP.
To get this information, I started slapd with debugging enabled and
dumped the debug output to a file to get the LDAP searches performed
on a Debian Edu main-server. Here is a summary.
powerdns
Clues
on how to set up PowerDNS to use a LDAP backend is available on
the web.
PowerDNS have two modes of operation using LDAP as its backend.
One "strict" mode where the forward and reverse DNS lookups are done
using the same LDAP objects, and a "tree" mode where the forward and
reverse entries are in two different subtrees in LDAP with a structure
based on the DNS names, as in tjener.intern and
2.2.0.10.in-addr.arpa.
In tree mode, the server is set up to use a LDAP subtree as its
base, and uses a "base" scoped search for the DNS name by adding
"dc=tjener,dc=intern," to the base with a filter for
"(associateddomain=tjener.intern)" for the forward entry and
"dc=2,dc=2,dc=0,dc=10,dc=in-addr,dc=arpa," with a filter for
"(associateddomain=2.2.0.10.in-addr.arpa)" for the reverse entry. For
forward entries, it is looking for attributes named dnsttl, arecord,
nsrecord, cnamerecord, soarecord, ptrrecord, hinforecord, mxrecord,
txtrecord, rprecord, afsdbrecord, keyrecord, aaaarecord, locrecord,
srvrecord, naptrrecord, kxrecord, certrecord, dsrecord, sshfprecord,
ipseckeyrecord, rrsigrecord, nsecrecord, dnskeyrecord, dhcidrecord,
spfrecord and modifytimestamp. For reverse entries it is looking for
the attributes dnsttl, arecord, nsrecord, cnamerecord, soarecord,
ptrrecord, hinforecord, mxrecord, txtrecord, rprecord, aaaarecord,
locrecord, srvrecord, naptrrecord and modifytimestamp. The equivalent
ldapsearch commands could look like this:
ldapsearch -h ldap \
-b dc=tjener,dc=intern,ou=hosts,dc=skole,dc=skolelinux,dc=no \
-s base -x '(associateddomain=tjener.intern)' dNSTTL aRecord nSRecord \
cNAMERecord sOARecord pTRRecord hInfoRecord mXRecord tXTRecord \
rPRecord aFSDBRecord KeyRecord aAAARecord lOCRecord sRVRecord \
nAPTRRecord kXRecord certRecord dSRecord sSHFPRecord iPSecKeyRecord \
rRSIGRecord nSECRecord dNSKeyRecord dHCIDRecord sPFRecord modifyTimestamp
ldapsearch -h ldap \
-b dc=2,dc=2,dc=0,dc=10,dc=in-addr,dc=arpa,ou=hosts,dc=skole,dc=skolelinux,dc=no \
-s base -x '(associateddomain=2.2.0.10.in-addr.arpa)'
dnsttl, arecord, nsrecord, cnamerecord soarecord ptrrecord \
hinforecord mxrecord txtrecord rprecord aaaarecord locrecord \
srvrecord naptrrecord modifytimestamp
In Debian Edu/Lenny, the PowerDNS tree mode is used with
ou=hosts,dc=skole,dc=skolelinux,dc=no as the base, and these are two
example LDAP objects used there. In addition to these objects, the
parent objects all th way up to ou=hosts,dc=skole,dc=skolelinux,dc=no
also exist.
dn: dc=tjener,dc=intern,ou=hosts,dc=skole,dc=skolelinux,dc=no
objectclass: top
objectclass: dnsdomain
objectclass: domainrelatedobject
dc: tjener
arecord: 10.0.2.2
associateddomain: tjener.intern
dn: dc=2,dc=2,dc=0,dc=10,dc=in-addr,dc=arpa,ou=hosts,dc=skole,dc=skolelinux,dc=no
objectclass: top
objectclass: dnsdomain2
objectclass: domainrelatedobject
dc: 2
ptrrecord: tjener.intern
associateddomain: 2.2.0.10.in-addr.arpa
In strict mode, the server behaves differently. When looking for
forward DNS entries, it is doing a "subtree" scoped search with the
same base as in the tree mode for a object with filter
"(associateddomain=tjener.intern)" and requests the attributes dnsttl,
arecord, nsrecord, cnamerecord, soarecord, ptrrecord, hinforecord,
mxrecord, txtrecord, rprecord, aaaarecord, locrecord, srvrecord,
naptrrecord and modifytimestamp. For reverse entires it also do a
subtree scoped search but this time the filter is "(arecord=10.0.2.2)"
and the requested attributes are associateddomain, dnsttl and
modifytimestamp. In short, in strict mode the objects with ptrrecord
go away, and the arecord attribute in the forward object is used
instead.
The forward and reverse searches can be simulated using ldapsearch
like this:
ldapsearch -h ldap -b ou=hosts,dc=skole,dc=skolelinux,dc=no -s sub -x \
'(associateddomain=tjener.intern)' dNSTTL aRecord nSRecord \
cNAMERecord sOARecord pTRRecord hInfoRecord mXRecord tXTRecord \
rPRecord aFSDBRecord KeyRecord aAAARecord lOCRecord sRVRecord \
nAPTRRecord kXRecord certRecord dSRecord sSHFPRecord iPSecKeyRecord \
rRSIGRecord nSECRecord dNSKeyRecord dHCIDRecord sPFRecord modifyTimestamp
ldapsearch -h ldap -b ou=hosts,dc=skole,dc=skolelinux,dc=no -s sub -x \
'(arecord=10.0.2.2)' associateddomain dnsttl modifytimestamp
In addition to the forward and reverse searches , there is also a
search for SOA records, which behave similar to the forward and
reverse lookups.
A thing to note with the PowerDNS behaviour is that it do not
specify any objectclass names, and instead look for the attributes it
need to generate a DNS reply. This make it able to work with any
objectclass that provide the needed attributes.
The attributes are normally provided in the cosine (RFC 1274) and
dnsdomain2 schemas. The latter is used for reverse entries like
ptrrecord and recent DNS additions like aaaarecord and srvrecord.
In Debian Edu, we have created DNS objects using the object classes
dcobject (for dc), dnsdomain or dnsdomain2 (structural, for the DNS
attributes) and domainrelatedobject (for associatedDomain). The use
of structural object classes make it impossible to combine these
classes with the object classes used by DHCP.
There are other schemas that could be used too, for example the
dnszone structural object class used by Gosa and bind-sdb for the DNS
attributes combined with the domainrelatedobject object class, but in
this case some unused attributes would have to be included as well
(zonename and relativedomainname).
My proposal for Debian Edu would be to switch PowerDNS to strict
mode and not use any of the existing objectclasses (dnsdomain,
dnsdomain2 and dnszone) when one want to combine the DNS information
with DHCP information, and instead create a auxiliary object class
defined something like this (using the attributes defined for
dnsdomain and dnsdomain2 or dnszone):
objectclass ( some-oid NAME 'dnsDomainAux'
SUP top
AUXILIARY
MAY ( ARecord $ MDRecord $ MXRecord $ NSRecord $ SOARecord $ CNAMERecord $
DNSTTL $ DNSClass $ PTRRecord $ HINFORecord $ MINFORecord $
TXTRecord $ SIGRecord $ KEYRecord $ AAAARecord $ LOCRecord $
NXTRecord $ SRVRecord $ NAPTRRecord $ KXRecord $ CERTRecord $
A6Record $ DNAMERecord
))
This will allow any object to become a DNS entry when combined with
the domainrelatedobject object class, and allow any entity to include
all the attributes PowerDNS wants. I've sent an email to the PowerDNS
developers asking for their view on this schema and if they are
interested in providing such schema with PowerDNS, and I hope my
message will be accepted into their mailing list soon.
ISC dhcp
The DHCP server searches for specific objectclass and requests all
the object attributes, and then uses the attributes it want. This
make it harder to figure out exactly what attributes are used, but
thanks to the working example in Debian Edu I can at least get an idea
what is needed without having to read the source code.
In the DHCP server configuration, the LDAP base to use and the
search filter to use to locate the correct dhcpServer entity is
stored. These are the relevant entries from
/etc/dhcp3/dhcpd.conf:
ldap-base-dn "dc=skole,dc=skolelinux,dc=no";
ldap-dhcp-server-cn "dhcp";
The DHCP server uses this information to nest all the DHCP
configuration it need. The cn "dhcp" is located using the given LDAP
base and the filter "(&(objectClass=dhcpServer)(cn=dhcp))". The
search result is this entry:
dn: cn=dhcp,dc=skole,dc=skolelinux,dc=no
cn: dhcp
objectClass: top
objectClass: dhcpServer
dhcpServiceDN: cn=DHCP Config,dc=skole,dc=skolelinux,dc=no
The content of the dhcpServiceDN attribute is next used to locate the
subtree with DHCP configuration. The DHCP configuration subtree base
is located using a base scope search with base "cn=DHCP
Config,dc=skole,dc=skolelinux,dc=no" and filter
"(&(objectClass=dhcpService)(|(dhcpPrimaryDN=cn=dhcp,dc=skole,dc=skolelinux,dc=no)(dhcpSecondaryDN=cn=dhcp,dc=skole,dc=skolelinux,dc=no)))".
The search result is this entry:
dn: cn=DHCP Config,dc=skole,dc=skolelinux,dc=no
cn: DHCP Config
objectClass: top
objectClass: dhcpService
objectClass: dhcpOptions
dhcpPrimaryDN: cn=dhcp, dc=skole,dc=skolelinux,dc=no
dhcpStatements: ddns-update-style none
dhcpStatements: authoritative
dhcpOption: smtp-server code 69 = array of ip-address
dhcpOption: www-server code 72 = array of ip-address
dhcpOption: wpad-url code 252 = text
Next, the entire subtree is processed, one level at the time. When
all the DHCP configuration is loaded, it is ready to receive requests.
The subtree in Debian Edu contain objects with object classes
top/dhcpService/dhcpOptions, top/dhcpSharedNetwork/dhcpOptions,
top/dhcpSubnet, top/dhcpGroup and top/dhcpHost. These provide options
and information about netmasks, dynamic range etc. Leaving out the
details here because it is not relevant for the focus of my
investigation, which is to see if it is possible to merge dns and dhcp
related computer objects.
When a DHCP request come in, LDAP is searched for the MAC address
of the client (00:00:00:00:00:00 in this example), using a subtree
scoped search with "cn=DHCP Config,dc=skole,dc=skolelinux,dc=no" as
the base and "(&(objectClass=dhcpHost)(dhcpHWAddress=ethernet
00:00:00:00:00:00))" as the filter. This is what a host object look
like:
dn: cn=hostname,cn=group1,cn=THINCLIENTS,cn=DHCP Config,dc=skole,dc=skolelinux,dc=no
cn: hostname
objectClass: top
objectClass: dhcpHost
dhcpHWAddress: ethernet 00:00:00:00:00:00
dhcpStatements: fixed-address hostname
There is less flexiblity in the way LDAP searches are done here.
The object classes need to have fixed names, and the configuration
need to be stored in a fairly specific LDAP structure. On the
positive side, the invidiual dhcpHost entires can be anywhere without
the DN pointed to by the dhcpServer entries. The latter should make
it possible to group all host entries in a subtree next to the
configuration entries, and this subtree can also be shared with the
DNS server if the schema proposed above is combined with the dhcpHost
structural object class.
Conclusion
The PowerDNS implementation seem to be very flexible when it come
to which LDAP schemas to use. While its "tree" mode is rigid when it
come to the the LDAP structure, the "strict" mode is very flexible,
allowing DNS objects to be stored anywhere under the base cn specified
in the configuration.
The DHCP implementation on the other hand is very inflexible, both
regarding which LDAP schemas to use and which LDAP structure to use.
I guess one could implement ones own schema, as long as the
objectclasses and attributes have the names used, but this do not
really help when the DHCP subtree need to have a fairly fixed
structure.
Based on the observed behaviour, I suspect a LDAP structure like
this might work for Debian Edu:
ou=services
cn=machine-info (dhcpService) - dhcpServiceDN points here
cn=dhcp (dhcpServer)
cn=dhcp-internal (dhcpSharedNetwork/dhcpOptions)
cn=10.0.2.0 (dhcpSubnet)
cn=group1 (dhcpGroup/dhcpOptions)
cn=dhcp-thinclients (dhcpSharedNetwork/dhcpOptions)
cn=192.168.0.0 (dhcpSubnet)
cn=group1 (dhcpGroup/dhcpOptions)
ou=machines - PowerDNS base points here
cn=hostname (dhcpHost/domainrelatedobject/dnsDomainAux)
This is not tested yet. If the DHCP server require the dhcpHost
entries to be in the dhcpGroup subtrees, the entries can be stored
there instead of a common machines subtree, and the PowerDNS base
would have to be moved one level up to the machine-info subtree.
The combined object under the machines subtree would look something
like this:
dn: dc=hostname,ou=machines,cn=machine-info,dc=skole,dc=skolelinux,dc=no
dc: hostname
objectClass: top
objectClass: dhcpHost
objectclass: domainrelatedobject
objectclass: dnsDomainAux
associateddomain: hostname.intern
arecord: 10.11.12.13
dhcpHWAddress: ethernet 00:00:00:00:00:00
dhcpStatements: fixed-address hostname.intern
One could even add the LTSP configuration associated with a given
machine, as long as the required attributes are available in a
auxiliary object class.