123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247 |
- #!/usr/bin/perl
- # $Id: pdnsd_dhcp.pl,v 1.2 2001/03/25 20:01:34 tmm Exp $
- ##########################################################################
- #
- # Filename: pdnsd_dhcp.pl
- # Description: Dynamic DNS-DHCP update script for pdnsd
- # Author: Mike Stella
- # Modified by: Marko Stolle
- # Created: November 19, 2001
- # Last Updated: February 28, 2001
- # Email: fwd2m@gmx.de
- #
- ###########################################################################
- #
- # This code is Copyright (c) 1998-2001 by Mike Stella and Marko Stolle
- #
- # NO WARRANTY is given for this program. If it doesn't
- # work on your system, sorry. If it eats your hard drive,
- # again, sorry. It works fine on mine. Good luck!
- #
- # This program is free software; you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation; either version 2 of the License, or
- # (at your option) any later version.
- #
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License
- # along with this program; if not, write to the Free Software
- # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- #
- ###########################################################################
- #
- # This script reads a dhcpd.leases file and dynamically updates pdnsd with
- # hostname and ip information.
- #
- # It assumes that your DHCP server recieves hostnames from the
- # clients, and that your clients offer their hostnames to the server.
- # Some versions of Linux DHCP clients don't do that. I use ISC's
- # DHCPD, found at http://www.isc.org - though others may work just
- # fine.
- #
- # This version of the script updates the pdnsd database. The status
- # control socket of pdnsd has to be enabled (psnsd -d -s).
- #
- ###########################################################################
- #
- # 02/20/2001 - first working version
- # 02/21/2001 - security patches by Thomas Moestl
- # 02/22/2001 - re-read dhcpd.leases if ttl has expireds since last update
- # 02/24/2001 - try to get domainname if not specified
- # 02/28/2001 - randomized temporary filename
- # added possibility to save some RAM (read below)
- #
- ###########################################################################
- # You may save some memory if you use absolute values with sysopen
- # in sub update_dns and don't use tmpnam()..
- # Just switch the '#' in front of the 'until sysopen' in the sub
- # update_dns, check the necessary modes on your system using save_ram.pl
- # and add a '#' in front of the following three lines.
- # Not using the tmpnam() function may open a security breach on systems
- # with not absolute trustworthy local users (Risk: a user may write a
- # script which creates files with the same names as this script and block
- # it that way. Unlikely because the filenames are now even without tmpnam()
- # randomized and an attacker has to create a very large number of files.)
- use Fcntl;
- use strict;
- use POSIX qw(tmpnam);
- $|=1;
- ###########################################################################
- ### Globals - you can change these as needed
- # Domain name
- # if not changed script will try to get it from the system
- my $domain_name = "domain";
- # DHCPD lease file
- my $lease_file = "/var/lib/dhcp/dhcpd.leases";
- # path to pdnsd-ctl
- my $pdnsd_ctl = "/usr/local/sbin/pdnsd-ctl";
- # owning name server for the newly added records
- my $nameserver = "localhost.";
- # TTL (Time To Live) for the new records
- my $ttl = "86400";
- # number of seconds to check the lease file for updates
- my $update_freq = 30;
- my $debug = 0;
- ###########################################################################
- ### Don't mess with anything below unless you REALLY need to modify the
- ### code. And if you do, please let me know, I'm always interested in
- ### in improving this program.
- # Make a pid file
- `echo $$ > /var/run/pdnsd_update.pid`;
- my $logstr;
- my $modtime = 0;
- my $temp_dir = -d '/tmp' ? '/tmp' : $ENV{TMP} || $ENV{TEMP};
- use vars qw (%db);
- my $version = "1.03";
- ###########################################################################
- # Main Loop
- # try to find domainname if necessary
- if ($domain_name eq "domain") {
- $domain_name = `dnsdomainname`;
- }
- else {
- $domain_name = "$domain_name\n";
- }
- while (1) {
- # check the file's last updated time, if it's been changed, update
- # the DNS and save the time. Update DNS even if there a no changes on
- # the leases file if ttl since last DNS update has expired.
- # This will ALWAYS run once - on startup, since $modtime starts at zero.
-
- my @stats = stat ($lease_file);
- if (($stats[9] > $modtime) or (time >= $modtime+$ttl)){
- # clear the old hash
- undef %db;
- printf STDERR "updating DNS with dhcpd.leases\n";
- $modtime = time;
- &read_lease_file;
- &update_dns;
- }
- # wait till next check time
- sleep $update_freq;
- } # end main
- ###########################################################################
- ### write out the import file
- sub update_dns {
- my ($ip, $hostname, $fname);
- do { $fname = tmpnam() }
- until sysopen(DNSFILE, $fname, O_WRONLY|O_CREAT|O_EXCL, 0600);
- # do { $fname = "$temp_dir/d2d".int(rand(time())) }
- # until sysopen(DNSFILE, $fname, 1|64|128, 0600);
- while (($hostname,$ip) = each (%db)) {
- print DNSFILE "$ip $hostname.$domain_name";
- }
- close DNSFILE;
- system ("$pdnsd_ctl source $fname $nameserver $ttl");
- unlink($fname);
- }
- ### reads the lease file & makes a hash of what's in there.
- sub read_lease_file {
- unless (open(LEASEFILE,$lease_file)) {
- #`logger -t dns_update.pl error opening dhcpd lease file`;
- print STDERR "Can't open lease file\n";
- return;
- }
- my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
- my $curdate = sprintf "%02d%02d%02d%02d%02d%20d%20d",
- ($year+1900),($mon+1),$mday,$hour,$min,$sec;
- ## Loop here, reading from LEASEFILE
- while (<LEASEFILE>) {
- my ($ip, $hostname, $mac, $enddate,$endtime);
- if (/^\s*lease/i) {
-
- # find ip address
- $_ =~ /^\s*lease\s+(\S+)/;
- $ip = $1;
-
- # do the rest of the block - we're interested in hostname,
- # mac address, and the lease time
- while ($_ !~ /^}/) {
- $_ = <LEASEFILE>;
- # find hostname
- if ($_ =~ /^\s*client/i) {
- #chomp $_;
- #chop $_;
- $_ =~ /\"(.*)\"/;
- $hostname = $1;
-
- # change spaces to dash, remove dots - microsoft
- # really needs to not do this crap
- $hostname =~ s/\s+/-/g;
- $hostname =~ s/\.//g;
- }
- # get the lease end date
- elsif ($_ =~ /^\s*ends/i) {
- $_ =~ m/^\s*ends\s+\d\s+([^;]+);/;
- $enddate = $1;
- $enddate =~ s|[/: ]||g;
- }
- }
- # lowercase it - stupid dhcp clients
- $hostname =~ tr/[A-Z]/[a-z]/;
- ($debug < 1 ) || print STDERR "$hostname $ip $enddate $curdate\n";
-
- # Store hostname/ip in hash - this way we can do easy dupe checking
- if (($hostname ne "") and ($enddate > $curdate)) {
- $db{$hostname} = $ip;
- }
- }
- }
- close LEASEFILE;
- }
- ### left around for testing
- sub print_db {
- my ($key,$value);
- while (($key,$value) = each (%db)) {
- print "$key - $value\n";
- }
- }
|