pdnsd_dhcp.pl 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. #!/usr/bin/perl
  2. # $Id: pdnsd_dhcp.pl,v 1.2 2001/03/25 20:01:34 tmm Exp $
  3. ##########################################################################
  4. #
  5. # Filename: pdnsd_dhcp.pl
  6. # Description: Dynamic DNS-DHCP update script for pdnsd
  7. # Author: Mike Stella
  8. # Modified by: Marko Stolle
  9. # Created: November 19, 2001
  10. # Last Updated: February 28, 2001
  11. # Email: fwd2m@gmx.de
  12. #
  13. ###########################################################################
  14. #
  15. # This code is Copyright (c) 1998-2001 by Mike Stella and Marko Stolle
  16. #
  17. # NO WARRANTY is given for this program. If it doesn't
  18. # work on your system, sorry. If it eats your hard drive,
  19. # again, sorry. It works fine on mine. Good luck!
  20. #
  21. # This program is free software; you can redistribute it and/or modify
  22. # it under the terms of the GNU General Public License as published by
  23. # the Free Software Foundation; either version 2 of the License, or
  24. # (at your option) any later version.
  25. #
  26. # This program is distributed in the hope that it will be useful,
  27. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  28. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  29. # GNU General Public License for more details.
  30. #
  31. # You should have received a copy of the GNU General Public License
  32. # along with this program; if not, write to the Free Software
  33. # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  34. #
  35. ###########################################################################
  36. #
  37. # This script reads a dhcpd.leases file and dynamically updates pdnsd with
  38. # hostname and ip information.
  39. #
  40. # It assumes that your DHCP server recieves hostnames from the
  41. # clients, and that your clients offer their hostnames to the server.
  42. # Some versions of Linux DHCP clients don't do that. I use ISC's
  43. # DHCPD, found at http://www.isc.org - though others may work just
  44. # fine.
  45. #
  46. # This version of the script updates the pdnsd database. The status
  47. # control socket of pdnsd has to be enabled (psnsd -d -s).
  48. #
  49. ###########################################################################
  50. #
  51. # 02/20/2001 - first working version
  52. # 02/21/2001 - security patches by Thomas Moestl
  53. # 02/22/2001 - re-read dhcpd.leases if ttl has expireds since last update
  54. # 02/24/2001 - try to get domainname if not specified
  55. # 02/28/2001 - randomized temporary filename
  56. # added possibility to save some RAM (read below)
  57. #
  58. ###########################################################################
  59. # You may save some memory if you use absolute values with sysopen
  60. # in sub update_dns and don't use tmpnam()..
  61. # Just switch the '#' in front of the 'until sysopen' in the sub
  62. # update_dns, check the necessary modes on your system using save_ram.pl
  63. # and add a '#' in front of the following three lines.
  64. # Not using the tmpnam() function may open a security breach on systems
  65. # with not absolute trustworthy local users (Risk: a user may write a
  66. # script which creates files with the same names as this script and block
  67. # it that way. Unlikely because the filenames are now even without tmpnam()
  68. # randomized and an attacker has to create a very large number of files.)
  69. use Fcntl;
  70. use strict;
  71. use POSIX qw(tmpnam);
  72. $|=1;
  73. ###########################################################################
  74. ### Globals - you can change these as needed
  75. # Domain name
  76. # if not changed script will try to get it from the system
  77. my $domain_name = "domain";
  78. # DHCPD lease file
  79. my $lease_file = "/var/lib/dhcp/dhcpd.leases";
  80. # path to pdnsd-ctl
  81. my $pdnsd_ctl = "/usr/local/sbin/pdnsd-ctl";
  82. # owning name server for the newly added records
  83. my $nameserver = "localhost.";
  84. # TTL (Time To Live) for the new records
  85. my $ttl = "86400";
  86. # number of seconds to check the lease file for updates
  87. my $update_freq = 30;
  88. my $debug = 0;
  89. ###########################################################################
  90. ### Don't mess with anything below unless you REALLY need to modify the
  91. ### code. And if you do, please let me know, I'm always interested in
  92. ### in improving this program.
  93. # Make a pid file
  94. `echo $$ > /var/run/pdnsd_update.pid`;
  95. my $logstr;
  96. my $modtime = 0;
  97. my $temp_dir = -d '/tmp' ? '/tmp' : $ENV{TMP} || $ENV{TEMP};
  98. use vars qw (%db);
  99. my $version = "1.03";
  100. ###########################################################################
  101. # Main Loop
  102. # try to find domainname if necessary
  103. if ($domain_name eq "domain") {
  104. $domain_name = `dnsdomainname`;
  105. }
  106. else {
  107. $domain_name = "$domain_name\n";
  108. }
  109. while (1) {
  110. # check the file's last updated time, if it's been changed, update
  111. # the DNS and save the time. Update DNS even if there a no changes on
  112. # the leases file if ttl since last DNS update has expired.
  113. # This will ALWAYS run once - on startup, since $modtime starts at zero.
  114. my @stats = stat ($lease_file);
  115. if (($stats[9] > $modtime) or (time >= $modtime+$ttl)){
  116. # clear the old hash
  117. undef %db;
  118. printf STDERR "updating DNS with dhcpd.leases\n";
  119. $modtime = time;
  120. &read_lease_file;
  121. &update_dns;
  122. }
  123. # wait till next check time
  124. sleep $update_freq;
  125. } # end main
  126. ###########################################################################
  127. ### write out the import file
  128. sub update_dns {
  129. my ($ip, $hostname, $fname);
  130. do { $fname = tmpnam() }
  131. until sysopen(DNSFILE, $fname, O_WRONLY|O_CREAT|O_EXCL, 0600);
  132. # do { $fname = "$temp_dir/d2d".int(rand(time())) }
  133. # until sysopen(DNSFILE, $fname, 1|64|128, 0600);
  134. while (($hostname,$ip) = each (%db)) {
  135. print DNSFILE "$ip $hostname.$domain_name";
  136. }
  137. close DNSFILE;
  138. system ("$pdnsd_ctl source $fname $nameserver $ttl");
  139. unlink($fname);
  140. }
  141. ### reads the lease file & makes a hash of what's in there.
  142. sub read_lease_file {
  143. unless (open(LEASEFILE,$lease_file)) {
  144. #`logger -t dns_update.pl error opening dhcpd lease file`;
  145. print STDERR "Can't open lease file\n";
  146. return;
  147. }
  148. my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
  149. my $curdate = sprintf "%02d%02d%02d%02d%02d%20d%20d",
  150. ($year+1900),($mon+1),$mday,$hour,$min,$sec;
  151. ## Loop here, reading from LEASEFILE
  152. while (<LEASEFILE>) {
  153. my ($ip, $hostname, $mac, $enddate,$endtime);
  154. if (/^\s*lease/i) {
  155. # find ip address
  156. $_ =~ /^\s*lease\s+(\S+)/;
  157. $ip = $1;
  158. # do the rest of the block - we're interested in hostname,
  159. # mac address, and the lease time
  160. while ($_ !~ /^}/) {
  161. $_ = <LEASEFILE>;
  162. # find hostname
  163. if ($_ =~ /^\s*client/i) {
  164. #chomp $_;
  165. #chop $_;
  166. $_ =~ /\"(.*)\"/;
  167. $hostname = $1;
  168. # change spaces to dash, remove dots - microsoft
  169. # really needs to not do this crap
  170. $hostname =~ s/\s+/-/g;
  171. $hostname =~ s/\.//g;
  172. }
  173. # get the lease end date
  174. elsif ($_ =~ /^\s*ends/i) {
  175. $_ =~ m/^\s*ends\s+\d\s+([^;]+);/;
  176. $enddate = $1;
  177. $enddate =~ s|[/: ]||g;
  178. }
  179. }
  180. # lowercase it - stupid dhcp clients
  181. $hostname =~ tr/[A-Z]/[a-z]/;
  182. ($debug < 1 ) || print STDERR "$hostname $ip $enddate $curdate\n";
  183. # Store hostname/ip in hash - this way we can do easy dupe checking
  184. if (($hostname ne "") and ($enddate > $curdate)) {
  185. $db{$hostname} = $ip;
  186. }
  187. }
  188. }
  189. close LEASEFILE;
  190. }
  191. ### left around for testing
  192. sub print_db {
  193. my ($key,$value);
  194. while (($key,$value) = each (%db)) {
  195. print "$key - $value\n";
  196. }
  197. }