Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations bkrike on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Auto-generating firewall rules 2

Status
Not open for further replies.

goremon

Technical User
Mar 22, 2006
2
US
I don't know perl. I adapted the following script from something I found on the net, and I can't figure out why it doesn't work. It's supposed to monitor the system log for lines such as the following:

[tt]... sshd[9186]: Illegal user foo from x.x.x.x
... sshd[2756]: Did not receive identification string from y.y.y.y[/tt]

and generate a firewall rule to block any IP address that tries and fails to log in more than 3 times (I only allow public-key logins.) What actually happens is that it generates one rule and then stops working. Thanks for replies.

[tt]#!/usr/bin/perl

# usage: sshAction <logfile>
# example: sshAction /var/log/system.log

use File::Tail;

my %failedLogins;
my %alreadyBanned;

# ipfw rules in the range indicated below are reserved for use by this script.

my $startingRule = 100;
my $endingRule = 199;
my $LogAmount = 100;
my $Log;

die "usage " . "$0" . " <logfile>" unless (scalar(@ARGV) >= 1);

my $fileName = $ARGV[0];
my $Rule = $startingRule;
if ( $LogAmount ) { $Log = "log logamount $LogAmount"; }

$file = File::Tail->new(name=>$fileName, debug=>0, interval=>1);

while(my $line=$file->read)
{ if ( $line =~ /.*sshd.*Did not receive identification string from (.*)/ ||
$line =~ /.*sshd.*Timeout before authentication for (.*)/ ||
$line =~ /.*sshd.*Illegal user .* from (.*)/
)
{ if ( ++$failedLogins[$1] >= 3 && ! $alreadyBanned[$1] )
{ exec "ipfw -q add $Rule deny $Log all from $1 to any";
$alreadyBanned[$1] = "true";
if ( ++$Rule > $endingRule ) { $Rule = $startingRule; }
}
}
}[/tt]
 
these varaibles look incorrect:

++$failedLogins[$1]
$alreadyBanned[$1]
$alreadyBanned[$1]

try changing them all to:

++$failedLogins{$1}
$alreadyBanned{$1}
$alreadyBanned{$1}

they are hash keys not array indexes so you should be using {} instead of []
 
Looks as if it's simply "timing in", there's no more entries to read while it's tailing the line, so the while condition is no longer true.

How often does the logfile update? Consider using sleep, or something with a higher granularity, or build your own timing loop.

Does this run all the time, consider
Code:
while ($condition == 0) {
   $condition=&readconditionfile();
   ...
so to stop the process write a value other than 0 to the file that you'd read in the readconditionfile stub

HTH
--Paul

Paul
------------------------------------
Spend an hour a week on CPAN, helps cure all known programming ailments ;-)
 
KevinADC, thanks for pointing that out. I've made the edits you suggested and I'll let you know how it goes.

PaulTEG, thanks for your reply too. The problem is not that the script quits; it just stops responding after the first rule is generated.
 
I see in the File::Tail docs they use defined():

Code:
while([b]defined[/b]($line=$file->read))

you can try that, it may not really matter though. Of course you will need to declare $line first since you are using strict:

Code:
my $line;
while([b]defined[/b]($line=$file->read))
 
According to the doc, the read method blocks if there's nothing new to read to save CPU. After you've made Kevin and Paul's changes to the hash code, it still should block unless new records are written to the log.

Add a few print statements at selected points to aid with your debugging, it might help you to see what's going on...

Steve

[small]"Every program can be reduced by one instruction, and every program has at least one bug. Therefore, any program can be reduced to one instruction which doesn't work." (Object::perlDesignPatterns)[/small]
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top