#!/usr/bin/perl ############################################################################### # # # IPFire.org - A linux based firewall # # Copyright (C) 2007 Michael Tremer & Christian Schmidt # # # # 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 3 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, see . # # # ############################################################################### use strict; use Time::Local; # enable only the following on debugging purpose #use warnings; #use CGI::Carp 'fatalsToBrowser'; require '/var/ipfire/general-functions.pl'; require "${General::swroot}/lang.pl"; require "${General::swroot}/header.pl"; #workaround to suppress a warning when a variable is used only once my @dummy = ( ${Header::colouryellow} ); undef (@dummy); my %cgiparams=(); my %checked=(); my $errormessage = ''; my $filename = "${General::swroot}/wireless/config"; my $hostsfile = "${General::swroot}/main/hosts"; our %dhcpsettings=(); our %netsettings=(); $cgiparams{'ENABLED'} = 'off'; $cgiparams{'ACTION'} = ''; $cgiparams{'VALID'} = ''; $cgiparams{'SOURCE_IP'} =''; $cgiparams{'SOURCE_MAC'} =''; $cgiparams{'REMARK'} =''; &Header::getcgihash(\%cgiparams); &General::readhash("${General::swroot}/dhcp/settings", \%dhcpsettings); &General::readhash("${General::swroot}/ethernet/settings", \%netsettings); &Header::showhttpheaders(); open(FILE, $filename) or die 'Unable to open config file.'; my @current = ; close(FILE); if ($cgiparams{'ACTION'} eq 'add') { if ($cgiparams{'SOURCE_IP'} eq '' && $cgiparams{'SOURCE_MAC'} eq '') { goto ADDEXIT; } $cgiparams{'SOURCE_MAC'} =~ tr/-/:/; my $key = 0; foreach my $line (@current) { $key++; my @temp = split(/\,/,$line); if ($temp[1] ne '' && $cgiparams{'SOURCE_IP'} eq $temp[1] && $cgiparams{'EDITING'} ne $key) { $errormessage = $Lang::tr{'duplicate ip'}; goto ADDERROR; } if ($temp[2] ne '' && lc($cgiparams{'SOURCE_MAC'}) eq lc($temp[2]) && $cgiparams{'EDITING'} ne $key) { $errormessage = $Lang::tr{'duplicate mac'}; goto ADDERROR; } } if ($cgiparams{'SOURCE_IP'} eq '') { $cgiparams{'SOURCE_IP'} = 'NONE'; } else { unless(&General::validip($cgiparams{'SOURCE_IP'})) { $errormessage = $Lang::tr{'invalid fixed ip address'}; goto ADDERROR; } } if ($cgiparams{'SOURCE_MAC'} eq '') { $cgiparams{'SOURCE_MAC'} = 'NONE'; } else { unless(&General::validmac($cgiparams{'SOURCE_MAC'})) { $errormessage = $Lang::tr{'invalid fixed mac address'}; } } ADDERROR: if ($errormessage) { $cgiparams{'SOURCE_MAC'} = '' if $cgiparams{'SOURCE_MAC'} eq 'NONE'; $cgiparams{'SOURCE_IP'} = '' if $cgiparams{'SOURCE_IP'} eq 'NONE'; } else { if ($cgiparams{'EDITING'} eq 'no') { open(FILE,">>$filename") or die 'Unable to open config file.'; flock FILE, 2; print FILE "$key,$cgiparams{'SOURCE_IP'},$cgiparams{'SOURCE_MAC'},$cgiparams{'ENABLED'},$cgiparams{'REMARK'}\n"; } else { open(FILE,">$filename") or die 'Unable to open config file.'; flock FILE, 2; my $id = 0; foreach my $line (@current) { $id++; if ($cgiparams{'EDITING'} eq $id) { print FILE "$id,$cgiparams{'SOURCE_IP'},$cgiparams{'SOURCE_MAC'},$cgiparams{'ENABLED'},$cgiparams{'REMARK'}\n"; } else { print FILE "$line"; } } } close(FILE); undef %cgiparams; &General::log($Lang::tr{'wireless config added'}); system('/usr/local/bin/wirelessctrl'); } ADDEXIT: } if ($cgiparams{'ACTION'} eq 'edit') { my $id = 0; foreach my $line (@current) { $id++; if ($cgiparams{'ID'} eq $id) { chomp($line); my @temp = split(/\,/,$line); $cgiparams{'SOURCE_IP'} = $temp[1]; $cgiparams{'SOURCE_MAC'} = $temp[2]; $cgiparams{'ENABLED'} = $temp[3]; $cgiparams{'REMARK'} = $temp[4]; $cgiparams{'SOURCE_IP'} = '' if $cgiparams{'SOURCE_IP'} eq 'NONE'; $cgiparams{'SOURCE_MAC'} = '' if $cgiparams{'SOURCE_MAC'} eq 'NONE'; } } &General::log($Lang::tr{'wireless config changed'}); system('/usr/local/bin/wirelessctrl'); } if ($cgiparams{'ACTION'} eq 'remove' || $cgiparams{'ACTION'} eq 'toggle') { my $id = 0; open(FILE, ">$filename") or die 'Unable to open config file.'; flock FILE, 2; foreach my $line (@current) { $id++; unless ($cgiparams{'ID'} eq $id) { print FILE "$line"; } elsif ($cgiparams{'ACTION'} eq 'toggle') { chomp($line); my @temp = split(/\,/,$line); print FILE "$temp[0],$temp[1],$temp[2],$cgiparams{'ENABLE'},$temp[4]\n"; } } close(FILE); &General::log($Lang::tr{'wireless config changed'}); system('/usr/local/bin/wirelessctrl'); } $checked{'ENABLED'}{'off'} = ''; $checked{'ENABLED'}{'on'} = ''; $checked{'ENABLED'}{$cgiparams{'ENABLED'}} = "checked='checked'"; &Header::openpage($Lang::tr{'wireless configuration'}, 1, ''); &Header::openbigbox('100%', 'left', '', $errormessage); if ($errormessage) { &Header::openbox('100%', 'left', $Lang::tr{'error messages'}); print "$errormessage\n"; print " \n"; &Header::closebox(); } print "
\n"; my $buttontext = $Lang::tr{'add'}; if ($cgiparams{'ACTION'} eq 'edit') { &Header::openbox('100%', 'left', "$Lang::tr{'edit device'}"); $buttontext = $Lang::tr{'update'}; } else { &Header::openbox('100%', 'left', "$Lang::tr{'add device'}"); } print < $Lang::tr{'source ip'}:  $Lang::tr{'enabled'}  $Lang::tr{'source'} $Lang::tr{'mac address'}:  $Lang::tr{'remark'}: *
* $Lang::tr{'this field may be blank'}  
END ; if ($cgiparams{'ACTION'} eq 'edit') { print "\n"; } else { print "\n"; } &Header::closebox(); print "\n"; &Header::openbox('100%', 'left', "$Lang::tr{'devices on blue'}"); print < END ; open (FILE, "$filename"); my @current = ; close (FILE); print < $Lang::tr{'hostname'} $Lang::tr{'source ip'} $Lang::tr{'mac address'} $Lang::tr{'remark'} $Lang::tr{'action'} END ; my $id = 0; open (HOSTFILE, "$hostsfile"); my @curhosts = ; close (HOSTFILE); my $connstate = &Header::connectionstatus(); my @arp = `/sbin/arp -n`; shift @arp; foreach my $line (@current) { $id++; chomp($line); my $gif = ""; my $gdesc = ""; my $hname = ""; my $toggle = ""; my @temp = split(/\,/,$line); my $wirelessid = $temp[0]; my $sourceip = $temp[1]; my $sourcemac = $temp[2]; if ( $sourceip eq 'NONE' ) { foreach my $aline ( @arp ) { chomp($aline); my @atemp = split( m{\s+}, $aline ); my $aipaddr = $atemp[0]; my $amacaddr = lc( $atemp[2] ); if ( $amacaddr eq $sourcemac ) { $sourceip = $aipaddr; last; } } } # SourceIP could now have been set by the ARP probe. if ( $sourceip ne 'NONE' ) { foreach my $hline (@curhosts) { chomp($hline); my @htemp = split(/\,/,$hline); my $hkey = $htemp[0]; my $hipaddr = $htemp[1]; my $hostname = $htemp[2]; my $domainname = $htemp[3]; if ($sourceip eq $hipaddr) { $hname = "$hostname.$domainname"; last; } } if ( $hname eq "" ) { my ($aliases, $addrtype, $length, @addrs); ($hname, $aliases, $addrtype, $length, @addrs) = gethostbyaddr(pack("C4", split(/\./, $sourceip)), 2); } } if ($temp[3] eq 'on') { $gif = 'on.gif'; $toggle='off'; $gdesc=$Lang::tr{'click to disable'};} else { $gif = 'off.gif'; $toggle='on'; $gdesc=$Lang::tr{'click to enable'};} my $remark = &Header::cleanhtml($temp[4]); if ($cgiparams{'ACTION'} eq 'edit' && $cgiparams{'ID'} eq $id) { print "\n"; } elsif ($id % 2) { print "\n"; } else { print "\n"; } print "$hname\n"; print "$sourceip\n"; print "$sourcemac\n"; print "$remark\n"; print<
END ; print "\n"; } print "\n"; print "\n"; &Header::closebox(); if ( $dhcpsettings{"ENABLE_BLUE"} eq 'on') { &printblueleases; } &Header::closebigbox(); &Header::closepage(); sub printblueleases { our %entries = (); sub blueleasesort { # Sort by IP address my $qs ='IPADDR'; my @a = split(/\./,$entries{$a}->{$qs}); my @b = split(/\./,$entries{$b}->{$qs}); ($a[0]<=>$b[0]) || ($a[1]<=>$b[1]) || ($a[2]<=>$b[2]) || ($a[3]<=>$b[3]); } &Header::openbox('100%', 'left', "$Lang::tr{'current dhcp leases on blue'}"); print < $Lang::tr{'ip address'} $Lang::tr{'mac address'} $Lang::tr{'hostname'} $Lang::tr{'lease expires'} (local time d/m/y) END ; my ($ip, $endtime, $ether, $hostname, @record, $record); open(LEASES,"/var/state/dhcp/dhcpd.leases") or die "Can't open dhcpd.leases"; while (my $line = ) { next if( $line =~ /^\s*#/ ); chomp($line); my @temp = split (' ', $line); if ($line =~ /^\s*lease/) { $ip = $temp[1]; # All fields are not necessarily read. Clear everything $endtime = 0; $ether = ""; $hostname = ""; } elsif ($line =~ /^\s*ends never;/) { $endtime = 'never'; } elsif ($line =~ /^\s*ends/) { $line =~ /(\d+)\/(\d+)\/(\d+) (\d+):(\d+):(\d+)/; $endtime = timegm($6, $5, $4, $3, $2 - 1, $1 - 1900); } elsif ($line =~ /^\s*hardware ethernet/) { $ether = $temp[2]; $ether =~ s/;//g; } elsif ($line =~ /^\s*client-hostname/) { shift (@temp); $hostname = join (' ',@temp); $hostname =~ s/;//g; $hostname =~ s/\"//g; } elsif ($line eq "}") { # Select records in Blue subnet if ( &General::IpInSubnet ( $ip, $netsettings{"BLUE_NETADDRESS"}, $netsettings{"BLUE_NETMASK"} ) ) { @record = ('IPADDR',$ip,'ENDTIME',$endtime,'ETHER',$ether,'HOSTNAME',$hostname); $record = {}; # create a reference to empty hash %{$record} = @record; # populate that hash with @record $entries{$record->{'IPADDR'}} = $record; # add this to a hash of hashes } } } close(LEASES); my $id = 0; foreach my $key (sort blueleasesort keys %entries) { my $hostname = &Header::cleanhtml($entries{$key}->{HOSTNAME},"y"); if ($id % 2) { print ""; } else { print ""; } print <$entries{$key}->{IPADDR} $entries{$key}->{ETHER}  $hostname END ; if ($entries{$key}->{ENDTIME} eq 'never') { print "$Lang::tr{'no time limit'}"; } else { my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $dst); ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $dst) = localtime ($entries{$key}->{ENDTIME}); my $enddate = sprintf ("%02d/%02d/%d %02d:%02d:%02d",$mday,$mon+1,$year+1900,$hour,$min,$sec); if ($entries{$key}->{ENDTIME} < time() ){ print "$enddate"; } else { print "$enddate"; } } if ( $hostname eq '' ) { $hostname = $Lang::tr{'device'}; } print <
END ; $id++; } print ""; &Header::closebox(); }