#!/usr/bin/perl -Tw
#
# LMS version 1.8.0rc5 Rosha
#
#  (C) 2001-2005 LMS Developers
#
#  Please, see the doc/AUTHORS for more information about authors!
#
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License Version 2 as
#  published by the Free Software Foundation.
#
#  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.
#
#  $Id: lms-antyvir,v 1.7.2.1 2005/12/07 08:56:14 alec Exp $

use DBI;
use strict;
use Config::IniFiles;
use POSIX qw(strftime); 
use Getopt::Long;
use vars qw($configfile $quiet $help $version);

$ENV{'PATH'}='/sbin:/usr/sbin:/usr/local/sbin:/bin:/usr/bin:/usr/local/bin';

my $_version = '1.8.0rc5 Rosha';

sub dotquad2u32($)
{
	my $dq = shift||'0.0.0.0'; 
	my @dq = split('\.',$dq,4); 
	return ((($dq[0] << 8) + $dq[1] << 8) + $dq[2] << 8) + $dq[3]; 
}

my %options = (
	"--config-file|C=s"     =>      \$configfile,
	"--quiet|q"             =>      \$quiet,
	"--help|h"              =>      \$help,
	"--version|v"           =>      \$version
);

Getopt::Long::config("no_ignore_case");
GetOptions(%options);

if($help)
{
        print STDERR <<EOF;
lms-antyvir, version $_version
(C) 2001-2005 LMS Developers
(C) 2001-2005 Wojciech Swiadkowski

-C, --config-file=/etc/lms/lms.ini      alternate config file (default: /etc/lms
-h, --help                      print this help and exit;
-v, --version                   print version info and exit;
-q, --quiet                     suppress any output, except errors;

EOF
    exit 0;
}

if($version)
{
     print STDERR <<EOF;
lms-antyvir, version $_version
(C) 2001-2005 LMS Developers
(C) 2001-2005 Wojciech Swiadkowski

EOF
    exit 0;
}

if(!$configfile)
{
	$configfile = "/etc/lms/lms.ini";
}

if(!$quiet)
{
	print STDOUT "lms-antyvir, version $_version\n";
	print STDOUT "(C) 2001-2005 LMS Developers\n";
	print STDOUT "(C) 2001-2005 Wojciech Swiadkowski\n";
	print STDOUT "Using file $configfile as config.\n";
}

if(! -r $configfile)
{
	print STDERR "Fatal error: Unable to read configuration file $configfile, exiting.\n";
	exit 1;
}

my $ini = new Config::IniFiles -file => $configfile;
print @Config::IniFiles::errors;

my $dbtype = $ini->val('database', 'type') || 'mysql';
my $dbhost = $ini->val('database', 'host') || 'localhost';
my $dbuser = $ini->val('database', 'user') || 'root';
my $dbpasswd = $ini->val('database', 'password') || '';
my $dbname = $ini->val('database', 'database') || 'lms';

my $antyvir_log = $ini->val('antyvir', 'logfile') || '/tmp/antyvir';
my $ports = $ini->val('antyvir', 'ports') || '135 445';
my $interfaces = $ini->val('antyvir', 'interfaces') || 'eth0';
my $packets = $ini->val('antyvir', 'packets') || '1000';
my $threshold = $ini->val('antyvir', 'threshold') || '50';
my $field = $ini->val('antyvir', 'field') || '11'; # or 6 for older tcpdump versions
my $logmessage = $ini->val('antyvir', 'message') || '';

my $dbase;
my $utsfmt;

if($dbtype eq "mysql")
{
        $dbase = DBI->connect("DBI:mysql:database=$dbname;host=$dbhost","$dbuser","$dbpasswd", { RaiseError => 1 });
}
elsif($dbtype eq "postgres")
{
        $dbase = DBI->connect("DBI:Pg:dbname=$dbname;host=$dbhost","$dbuser","$dbpasswd", { RaiseError => 1 });
}
else
{
        print STDERR "Fatal error: unsupported database type: $dbtype, exiting.\n";
        exit 1;
}

my $antyvir_log_ip = "$antyvir_log"."-ip";

# get data from last script call
system("killall -9 tcpdump 2>/dev/null");
system("cat $antyvir_log.* 2>/dev/null | cut -d ' ' -f $field | cut -d '.' -f -4 > $antyvir_log");
system("cat $antyvir_log 2>/dev/null | sort -u > $antyvir_log_ip");

my @port = split(' ', $ports);
my @interface = split(' ', $interfaces);

# run tcpdump for all defined interfaces and ports
foreach my $iface (@interface)
{
        foreach my $pt (@port)
	{
    		system("tcpdump -i $iface -enp -c $packets port $pt > $antyvir_log.$iface.$pt 2>/dev/null &");
	}
}

my $date = strftime("%Y/%m/%d %H:%M", localtime());
$logmessage =~ s/\%DATE/$date/g; 

open(LOGFILE, $antyvir_log_ip);
my @iplist = <LOGFILE>;
close(LOGFILE);

foreach my $ip (@iplist)
{
	open(LOGFILE, $antyvir_log);
        my @list = <LOGFILE>;
	close(LOGFILE);

	my $found = 0;

        foreach my $temp (@list)
	{
    		if($temp eq $ip) { $found++; }
	}

        if($found > $threshold)
        {
		$ip =~ s/\n//g;
		print STDERR "IP: $ip probably infected. Found $found packets.\n" unless $quiet;
         
		if($logmessage)
    		{ 
        		$dbase->do("UPDATE nodes SET warning = 1 WHERE ipaddr = inet_aton('$ip')");
			my $dbq = $dbase->prepare("SELECT ownerid FROM nodes WHERE ownerid != 0 AND ipaddr = inet_aton('$ip')");
			$dbq->execute();
			if(my $row = $dbq->fetchrow_hashref())
			{
				$dbase->do("UPDATE customers SET message = '$logmessage' WHERE id = $row->{'ownerid'}"); 
			}
		}
        }
}

$dbase->disconnect();
