This file is indexed.

/usr/sbin/autodns-dhcp_ddns is in autodns-dhcp 0.9.

This file is owned by root:root, with mode 0o755.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
#!/usr/bin/perl
# 
# autodns-dhcp_ddns
# The procedure here is simple.   
#  If a record has been added since the last change, delte any previous
#  mentions and add a new record. This can lead to expired records but this
#  should not be a problem.
#
# Copyright (C) 1999 Stephen Carville
#
# 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

# use inverse time functions
use Time::Local;
use strict;
use Socket;

my $DEBUG = 0;
my $version="0.7";

# these are the only valid character for a machine name -- used in checkname()
my $NAMECHARS="[a-zA-Z0-9\\-]";

# define the extra filters to apply for machine names -- in checkname()
# these filters allow for extra name filtering if needed. For example, this
# filter only allows "legitimate" names into my employers's DNS 
#my $CYPFILTER="cy(pci|pca|hpr|sun)t\\d{2}|\\d{3}";
# these are the active filters -- set this to "" if you don't need any extra
# filters.
my(@filters)=("");

# filter for a bogus ethernet address (look for seven octets :-)
#my $ETHER="\\w\\w:\\w\\w:\\w\\w:\\w\\w:\\w\\w:\\w\\w:\\w\\w";
# lets try filtering on the first two octets of the bogus address this may 
# cause a legitimate address to choke but all the info I can find indicates
# the 52:41 sequence has never been issued to any manufacturer
my $ETHER="\^52:41:";

# nsupdate command strings
my $IFEXIST="prereq yxdomain";
my $IFNOTEXIST="prereq nxdomain";
my $ADD="update add";
my $DELETE="update delete";

# use a default time to live of one hour
my $TTL="3600";

my $LEASE_TEMP="dhcpd.leases.last";
# my $UPDATE="nsupdate.data";

my (%newip,%newmac,%newname,$hostname,$hostip,$hard);
my ($nowtime,$lastime,$ip,$linea);
my ($home,$dhcpdleases,$update,$dhcpup,$dhcpdleases_temp,$domain,$dhcpdconf);
my (@ddnscommand,@OUTPUT,@SALIDA);
my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,
    $blksize,$blocks);

# get the program environment variables
$home = $ENV{DDNSHOME};
$dhcpdleases = $ENV{DHCPDLEASES};
$update = $ENV{UPDATE};
$dhcpdleases_temp = $ENV{DHCPDLEASES_TEMP};
$dhcpdconf = $ENV{DHCPDCONF};
$domain = $ENV{DNS_DOMAIN};
$dhcpup = $ENV{DHCPUP};

# get the current GMT
$nowtime=time();
# get last update time;
if (-e "$home/$LEASE_TEMP") {
    ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,
     $blksize,$blocks)=stat("$home/$LEASE_TEMP");
    $lastime=$mtime;
}
else {
    $lastime=0;
}

# now copy the dhcpd.leases file over to DDNSHOME

system "/bin/cp", $dhcpdleases, $dhcpdleases_temp;

# get the new data
# I have changed this to two global hashes:
# newip is indexed by IP and contains the last MAC asociated with that IP
# newmac is indexed by MAC and contains the last IP and the name for that MAC
load_new_data($nowtime,$lastime);

unless (open OUTPUT, ">$update") {
    print STDERR "Unable to open $update\n";
    die;
}
unless (open SALIDA, ">$dhcpup") {
    print STDERR "Unable to open $dhcpup\n";
    die;
}
unless (open ENTRADA, "<$dhcpdconf") {
    print STDERR "Unable to open $dhcpdconf\n";
    die;
}

if ($DEBUG == 1) {
    *OUTPUT=*STDERR;
}

# We parse the dhcpd.conf file getting the already fixed parameters to make
# sure a MAC doesn't get two IPs and fixed IPs aren't asigned again.
# I know this can only happen in a few cases, but this has gotta be strong.
while (<ENTRADA>) {
  if (/host.+hardware ethernet (.+); fixed-address (.+);.+/) {
     delete $newmac{$1};
     delete $newip{$2};
  }
}
seek(ENTRADA,0,0);

# now do the adds

#For each of the found ips (sorted numerically)
foreach $ip (sort ipcomp keys (%newip)) {
  #Get the mac for the ip we'll work with
  $hard=$newip{$ip};
  #For that mac, get it's IP and the host name
  ($hostip,$hostname) = split(/ /,$newmac{$hard});
  #Do not add the host if the IP doesn't match the one we were asking for
  unless ($hostip eq $ip) { next; }
  #Do not add the host if the name is not valid acording to our criteria
  unless (checkname($hostname)) { next; }
  #Do not add the host if the name already exists on dns
  if (gethostbyname("$hostname.$domain.")) { next; }
  #Check if we had added the same name on this round (only add the first one)
  if ( $newname{$hostname} ) { next; }
  #Mark the name so that we don't add the name more than once
  $newname{$hostname} = 1;

  @ddnscommand=add_record($hostname,$ip);

  while (($linea=<ENTRADA>) ne "range $ip;\n") {
    print SALIDA $linea
  }
  print SALIDA "host $hostname {hardware ethernet $hard; fixed-address $ip;}\n";
  print OUTPUT @ddnscommand;
}

while ($linea=<ENTRADA>) { print SALIDA $linea }

close SALIDA;
close ENTRADA;

#
# check an ethernet id 
# Windows will try to grab multiple addresses.  I can't stop DHCP from 
# granting them but I can make sure only addresses granted to valid 
# ethernet addresses get into the DNS
#
sub checkethid {
  my ($ether)=@_;

  if ($ether =~m/$ETHER/) {
    return 1;
  }
return 0;
}

#
# check a name to see if it is a valid name
# first check the name is FQDN valid then does it fit our
# internal naming policy.  I may add an exception list here later.
# 
sub checkname {
  my ($name)=@_;
  my (@array,$letter,$filter);

  @array=split(//,$name);

  foreach $letter(@array) {
    unless ($letter=~m/$NAMECHARS/) {
      return 0;
    }
  }
  foreach $filter (@filters) {
    unless ($name=~m/$filter/) {
      return 0;
    }
  }
  return 1;
}

#
# add a record
#
sub add_record {
    my ($machine,$address) = @_;
    my ($xaddress,@c,$arpa);

# get reverse lookup for the new address
    $arpa=get_arpa($address);
# add the new forward record
    push @c, "$ADD $machine.$domain $TTL IN A $address\n\n";
# add the new reverse record
    push @c, "$ADD $arpa $TTL IN PTR $machine.$domain\n\n";

    return @c;
}

#
# get the reverse lookup value for an address
#
sub get_arpa {
    my ($address) = @_;
    my ($arpa,$a,$b,$c,$d);

   ($a,$b,$c,$d) = split /\./, $address;
    $arpa = "$d.$c.$b.$a.in-addr.arpa";
    return $arpa;
}

#
# load the current dhcpd.leases file
# here we look at the hostname, the lease start time and the lease end time.
# if a hostname does not exist, there will be no entry made in DNS.
sub load_new_data{
    my ($nowtime,$lastime)=@_;
    my(@DATA,$hn,$ip,$startime,$endtime,@date,@time,@a,$hard,$bogus);

    unless (open DATA,"$dhcpdleases_temp") {
	print STDERR "autodns-dhcp_ddns $version: can't open $dhcpdleases_temp\n";
	die;
    }

# set the bogus ethernet id flag to 0
    $bogus=0;

# parse each line in the file
    while (<DATA>) {

# get rid of semicolons and quote marks
	$_=~s/\"//g;
	$_=~s/\;//g;

	@a=split(" ",$_);
	
# get IP address
	if ($a[0] eq "lease") {
# start of a new entry so reset bogus
	  $bogus=0;
	  $ip= $a[1];
	}

# get the starting GMT for the lease
	if ($a[0] eq "starts") {
	  @date=split("/",$a[2]);
	  @time=split(":",$a[3]);
	  $startime=timegm($time[2],$time[1],$time[0],$date[2],$date[1]-1,$date[0]);
	}

# get the ending GMT for the lease
	if ($a[0] eq "ends") {
	    @date=split("/",$a[2]);	
	    @time=split(":",$a[3]);
	    $endtime=timegm($time[2],$time[1],$time[0],$date[2],$date[1]-1,$date[0]);
	}

# check if the Ethernet address is legit.  Some Win boxen will request
# multiple addresses using bogus ethernet id's (yuck!)

	if ($a[0] eq "hardware") {
# if it is a bogus address go to the next entry 
	  if (checkethid($hard=$a[2])) {
	    $bogus=$a[2];
	    next;
	  }
	}

# since dhcpd adds new leases to the end of the file, it is assumed that 
# a later entry is the most likely to be correct.  Therefore just overwrite 
# any duplicate hostnames found

	if ($a[0] eq "client-hostname") {
	    $hn=lc($a[1]);
# is this lease new and valid? (is it worthwhile here to check for bogosity?)
	    if ($startime > $lastime && $endtime > $nowtime) {
	      unless ($bogus) {
		$newip{$ip} = $hard;
		$newmac{$hard} = "$ip $hn";
	      }
	    }
# if the lease is not valid and not bogus we remove the posible valid leases
# that had been assigned before.
	    else {
	      unless ($bogus) {
		delete $newip{$ip};
		delete $newmac{$hard};
	      }
	    }
	}
    }
    close DATA;
}

sub ipcomp {
	my @ip1 = split(/\./,$a);
	my @ip2 = split(/\./,$b);
	my $ip1n = (((($ip1[0]*256)+$ip1[1])*256)+$ip1[2])*256+$ip1[3];
	my $ip2n = (((($ip2[0]*256)+$ip2[1])*256)+$ip2[2])*256+$ip2[3];
	return ($ip1n <=> $ip2n);
}