Actually using ldapdns1), I want to have dynamic DNS (ddns) stored in LDAP tree.
Basically I wrote an perl script that monitor dhcpd.lease2) for change and update my DIT3). An entry looks like that :
dn: dc=iro023,dc=machines,dc=irovision,dc=ch,ou=dns,o=iro objectClass: dNSDomain objectClass: ieee802Device dc: iro023 macAddress: 00:11:85:11:ec:14 seeAlso: uid=iro023$,ou=machines,o=iro aRecord: 172.16.30.135
As you see there's a seeAlso attribute pointing to somewhere else in the DIT. This is a MS Windows machine join in our Samba domain. As you can see, below, the entry contains its mac address too.
for
dn: uid=iro023$,ou=machines,o=iro objectClass: top objectClass: account objectClass: posixAccount objectClass: sambaSamAccount objectClass: ieee802Device cn: iro023$ uid: iro023$ uidNumber: 10075 gidNumber: 515 homeDirectory: /dev/null loginShell: /bin/false description: Computer gecos: Computer sambaSID: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX displayName: IRO023$ sambaAcctFlags: [W ] macAddress: 00:11:85:11:ec:14 sambaNTPassword: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX sambaPwdLastSet: XXXXXXXXXX
What we do is to record the mac address of the machine, when registering into the Samba domain, and use this information to give the DNS name, so it stay in sync.
Machines that are not part of the Samba domain and are not part of anything (if any), we just use the provided client-hostname.
So that's what does the script. It sync all that, take care of registering reverse DNS (and keeping seeAlso pointing where it should) :
dn: dc=135,dc=30,dc=16,dc=172,dc=in-addr,dc=arpa,ou=dns,o=iro dc: 135 cNAMERecord: iro023.machines.irovision.ch seeAlso: dc=iro023,dc=machines,dc=irovision,dc=ch,ou=dns,o=iro objectClass: dNSDomain
Unfortunately I'm having troubles with that. I don't know when it ends. I put some complex code to manage when machine should be deleted but it doesn't work at all.
To solve that problem, I need to put the end time of the lease into the entry, and by the way the time to live and the start time would be useful, but there's no provision for that provided by actual schema. A discussion about a DHCP schema is available on IETF mailing list for some working draft.
Schema I have found for DHCP are the following :
Just looking at what interest me :
NAME dhcpClient DESCRIPTION This represents client-specific DHCP assignments. TYPE Structural DERIVED FROM dhcpRule POSSIBLE SUPERIORS ( OrganizationalUnit dhcpRule ) MUST CONTAIN ( cn dhcpClientIdentifier ) MAY CONTAIN ( dhcpClassMember dhcpReservedAddress )
and
NAME dhcpAddress
DESCRIPTION This class represents an IP Address, which may or
may not have been leased.
TYPE Structural
DERIVED FROM Top
POSSIBLE SUPERIORS ( )
MUST CONTAIN ( cn dhcpAddressState )
MAY CONTAIN ( dhcpExpirationTime dhcpStartTimeOfState
dhcpLastTransactionTime dhcpBootpFlag
dhcpDomainName dhcpDnsStatus
dhcpRequestedHostName dhcpAssignedHostName
dhcpReservedForClient dhcpAssignedToClient
dhcpRelayAgentInfo dhcpOptionSetting
dhcpParameterSetting dhcpFieldSetting )
The idea is the following :
dhcpClient is created.dhcpClient is set in attribute dhcpAssignedToClient.Here is what interest me :
NAME 'DHCPLease'
DESCRIPTION 'This class specifies individual lease
information.'
TYPE Structural
DERIVED FROM Top
POSSIBLE SUPERIORS ( DHCPSubnet )
MUST CONTAIN ( IPAddress $ LeaseType )
MAY CONTAIN ( UniqueID $ ClientName $ LeaseExpiration $
LeaseState $ Description )
I think there's already things that can carry client information in LDAP. In RFC 2307, we already find interesting class like :
Another class that would be interesting is DNSDomain defined in RFC 1274. RFC 4524 (it obsoletes RFC 1274) doesn't bring this class forward as this class is used as experimental in RFC 1279. I'm not sure what all that means ...
But all in all, I think I don't want to redefine everything. We know we have IP host, we have IEEE 802.2 devices, we have domain and domain related object (in RFC 4524). LDAP server maintains a createTimestamp and modifyTimestamp, defined in RFC 4512.
So all we need, in the end, is TTL. This would be sufficient. This attribute has been proposed in draft IETF Asid LDAP CACHE 01
I came across RFC 2589. This RFC define attribute entryTTL. This is what I need. No need for a brand new schema, just use what is already available.
The idea is to use ldapdns as follow
[ INTERNET ]
+-------------+ ^ ^
| LDAP master |<---------+ | |
+-------------+<-------+ | | |
| | +-------------+ +-DNS-----------+ |
| +-LDAP-| ldapdns 1 |<-----------+ | |
| | +-------------+<---------+ | | |
+-------------+ | | | | +-------+--------+ |
| LDAP slave |<-------(-+ | +------DNS-| pdns_recusor 1 |<---+ |
+-------------+<-------+ | | +----------------+ | |
| +---(-+ +-DNS---------(---+
| +-------------+ | | | +-DNS-[CLIENTS]
+-LDAP-| ldapdns 2 |<-------+ | +-------+--------+
+-------------+<-----------+--------DNS-| pdns_recusor 2 |<-----DNS-[CLIENTS]
+----------------+
DNS entries in LDAP are used by ldapdns. It is configured with cosine schema (in ldapdns.conf):
# the schema of LDAP database and queries (rfc1279, msdns, cosine, ldapdns) SCHEMA=cosine
So we have a tree like that :
ou=dns,o=iro
|
+ dc=ch
|
+ dc=irovision
|
+ dc=www
All entries below ou=dns,o=irovision are dnsDomain class and also dynamicObject. The dynamicObject class might not be available on your LDAP server if it doesn't implement RFC 2589. The entryTtl value is given a value corresponding to the time to live given to the lease by the DHCP server.
When registering a computer in the directory, the script looks if this computer is already registered in a Windows domain. If it is, the name set during registration is used instead of the name given by the computer to the DHCP server.
To find the machine account the MAC address is used. So each Windows machine account has ieee802device class. The address is actually set manually but I successfully wrote a script to do that auto-magically (sadly this script is lost as it was written at my previous job, but I'll write it again).
What we have here is the following :
ou=machines,o=iro | + uid=iro001 + uid=iro002 + ...
If nothing is found in there, the name provided by the DHCP server is used.
OpenLDAP has a nasty bug, so you can patch : http://www.openldap.org/its/index.cgi/Incoming?id=6490. The bug in itself shouldn't happen in normal case, but the script can crash the server. If there's a bug (in the script) which send a refresh request to openLDAP with an empty DN the server segfault. corrected in CVS. See bug 6490.
Nothing to do, really.
In order to use entryTtl as “Time To Live” in DNS answer, I made a first patch against the official ldapdns-2.06 source code. So when you request a DNS entry, the TTL is set according to the time to live set in the DIT. It allows to have caching DNS server (I use PowerDNS recursor in front of my ldapdns servers to do caching and recursion).
Here is an example of request made to ldapdns server and the same request made to the DIT (edited to remove comments and useless information). The TTL match the one found in the DIT.
$ dig @vs121.servers.irovision.ch iro025.machines.irovision.ch ;; QUESTION SECTION: ;iro025.machines.irovision.ch. IN A ;; ANSWER SECTION: iro025.machines.irovision.ch. 5003 IN A 172.16.30.112 $ ldapsearch -h vs121.servers.irovision.ch -x -b dc=iro025,dc=machines,dc=irovision,dc=ch,ou=dns,o=iro "entryTtl" # iro025, machines, irovision, ch, dns, iro dn: dc=iro025,dc=machines,dc=irovision,dc=ch,ou=dns,o=iro entryTtl: 5003
It also works with reverse DNS request.
The patch is quite experimental by now. It actually running on one production server at my work place to test it in real environment. I will also port the patch to Debian version of ldapdns as it's the only place I know bug fixes are still done on this software, so more to come. ldapdns-entryttl patch
You need to have the refresh extended operation available. I wrote it and you'll find it on the mailing list http://markmail.org/thread/tay3nyjeixor6xyu (well there are links pointing back to here to get the code, but you'd better follow the list thread to see if there's any change).
There's also a patch, but it's not needed actually. I hope this code will get into the main distribution of perl-ldap extension.
It's available in latest release of perl-ldap
There's also a bunch of extension from CPAN I use (and one from nowhere, I think). Here is the use section :
use strict; use Config::File qw(read_config_file); use Net::LDAP; use Net::LDAP::Constant qw(LDAP_SUCCESS); use Net::LDAP::Extension::Refresh; use Getopt::Std; use Data::Dumper; use Net::DHCP::ParseLeaseFile; use Date::Parse; use Linux::Inotify2; use File::Copy; use POSIX; use File::Temp qw(tmpnam); use Sys::Syslog;
The Net::DCHP::ParseLeaseFile comes from nowhere I think. I couldn't find this again (but I found it 2008 when I first wrote the script). The Data::Dumper may not be necessary, I'll check and update this.
The configuration file works like that :
# User and and group to use USER=nobody GROUP=nogroup # Server configuration (support only simple) AUTH = simple # Can be ldap, ldaps and ldapi, default to ldap SCHEME = ldap # Default to 2 VERSION = 3 # Default to 389 for ldap and 686 for ldaps PORT = 389 ## Default to localhost #SERVER = ## If not set, anonymous bind #BIND_DN = xxxx #BIND_PW = xxxx ## If not set, won't search for existing machines #MACHINES_SUFFIX = ## If not set, die #DNS_SUFFIX = #RDNS_SUFFIX = # Default to ieee802device MACHINES_OBJECTCLASS = ieee802device # Default to dnsdomain DNS_OBJECTCLASS = dnsdomain MACHINES_NAME_ATTR = cn DNS_NAME_ATTR = dc #DNS_DOMAIN_NAME = # TLS Configuration (no support for now) STARTTLS = no TLS_VERIFY = none #TLS_CAFILE = #TLS_CERT = #TLS_KEYCERT = #TLS_KEYPASS = #TLS_CAPATH = #TLS_CIPHERS = LEASE_FILE = /var/lib/dhcp3/dhcpd.leases DDS_LEASE_EXPIRE_DIFF = 15
The TLS part is not supported as there's no code to handle this. The only authentication available is simple, so user and password.
The user that the script use must have the manage right on DNS_SUFFIX and RDNS_SUFFIX.
The script will drop its privileges to USER and GROUP after the configuration file is read.
The DDS_LEASE_EXPIRE_DIFF is the time, in second, of how big the difference between the LDAP entryTtl and the DHCP TTL can be. This avoid to be always refreshing all entries at every run of the script (and you don't need atomic precision for that).
The script is available at http://www.tchetch.net/code/perl/ldap_ddns.pl.txt, it is not stable at all (but it's running for some days now on production servers without problem) so use it at you own risk.
dhcpd.lease synchronized with you directoryseeAlso (the reverse DNS entry point to the forward DNS entry, not the other way around).seeAlso attribute