X-Git-Url: https://defaria.com/gitweb/?a=blobdiff_plain;ds=inline;f=bin%2Fbice.pl;h=cd25b1bf015b5ab474ae908c236291b33400aa37;hb=cbfba1c8c330651d563f03ba6e2b04ce48c79896;hp=491a3047434f7d75d9c665d1e3c563851afd1145;hpb=81cbd130706633b1c19ff59371c2ef61d80c562b;p=clearscm.git
diff --git a/bin/bice.pl b/bin/bice.pl
index 491a304..cd25b1b 100755
--- a/bin/bice.pl
+++ b/bin/bice.pl
@@ -66,12 +66,23 @@ my $security_logfile = '/var/log/auth.log';
# Customize these variables
my $domain = 'DeFaria.com';
my $contact = 'Andrew@DeFaria.com';
-my $location = 'Santa Clara, California, USA';
-my $UTC = 'UTC-8';
+my $location = 'Phoenix, Arizona, USA';
+my $UTC = 'UTC-7';
my $mailhost = $domain;
# End customize these variables
-my $verbose;
+# Current IPset. This is the name of an IP match set (See
+# https://kirkkosinski.com/2013/11/mass-blocking-evil-ip-addresses-iptables-ip-sets/)
+# Each set can hold up to 65535 entries. We are currently on set 2.
+#
+# TODO: This code should handle the case where the set fills and we need to go
+# to the next set. Something like "ipset list | wc - " and
+# if it's > than say 60000, start a new set.
+#
+# Also, when a new set comes around we need to do:
+# $ iptables -A FORWARD -m set --mach-set src -j DROP
+my $currIPSet = 'BICE2';
+
my $update = 1;
my $email = 1;
my $hostname = `hostname`;
@@ -81,46 +92,19 @@ if ($hostname =~ /(\w*)\./) {
$hostname = $1;
} # if
-sub AddToIPTables (@) {
- my (@ips) = @_;
-
- # We shouldn't need to weed out duplicate but ya never know
- my $ipfilename = '/etc/ipblock';
+sub AddToIPSet($) {
+ my ($ip) = @_;
- my $result = open my $ipfile, '<', $ipfilename;
+ my ($status, @output) = Execute "/sbin/ipset add $currIPSet $ip 2>&1";
- my (%ips, @oldips);
-
- if ($result) {
- @oldips = <$ipfile>;
-
- close $ipfile if $ipfile;
+ if ($status) {
+ return if $output[0] =~ /already added/;
- chomp @oldips;
+ error "Unable to add $ip to ipset $currIPSet" . join ("\n", @output), 1;
+ } else {
+ return;
} # if
-
- map { $ips{$_} = 1 } @oldips;
- map { $ips{$_} = 1 } <@ips>;
-
- open $ipfile, '>', "$ipfilename"
- or error "Unable to open $ipfilename - $!", 1;
-
- foreach (sort keys %ips) {
- print $ipfile "$_\n";
- } # foreach
-
- close $ipfile;
-
- # Recreate the BICE chain
- `/sbin/iptables -F BICE`;
- `/sbin/iptables -X BICE`;
- `/sbin/iptables -N BICE`;
-
- # Add all new @ips to iptables
- `/sbin/iptables -A BICE -s $_ -p tcp -j DROP` foreach (sort keys %ips);
-
- return;
-} # AddToIPTables
+} # AddToIPSet
# Use whois(1) to get the email addresses of the responsible parties for an IP
# address. Note that a hash is used to eliminate duplicates.
@@ -128,17 +112,18 @@ sub GetEmailAddresses ($) {
my ($ip) = @_;
# List of whois servers to try
+ # Apparently whois.opensrs.net no longer offers whois service?
my @whois_list = (
'',
'whois.arin.net',
'whois.nsiregistry.net',
- 'whois.opensrs.net',
+ #'whois.opensrs.net',
'whois.networksolutions.com',
);
my %email_addresses;
- foreach (@whois_list) {
+ for (@whois_list) {
my @lines;
if ($_ eq "") {
@@ -147,108 +132,108 @@ sub GetEmailAddresses ($) {
@lines = grep {/.*\@.*/ } `whois -h $_ $ip`;
} # if
- foreach (@lines) {
+ for (@lines) {
my @fields = split /:/, $_;
-
+
$_ = $fields [@fields - 1];
-
+
if (/(\S+\@\S[\.\S]+)/) {
$email_addresses{$1} = "";
} # if
- } # foreach
+ } # for
# Break out of loop if we found email addresses
last unless keys %email_addresses;
- } # foreach
+ } # for
return keys %email_addresses;
} # GetEmailAddresses
# Send email to the responsible parties.
-sub SendEmail ($$$$$) {
- my ($to, $subject, $message, $ip, $violations) = @_;
+sub SendEmail ($$$$$$) {
+ my ($to, $subject, $message, $ip, $attempts, $violationNbr) = @_;
if ($email) {
- verbose "Reporting $ip ($violations violations) to $to";
+ verbose "$violationNbr: Reporting $ip ($attempts violations) to $to";
} else {
- verbose "Would have reported $ip ($violations violations) to $to";
+ verbose "$violationNbr: Would have reported $ip ($attempts violations) to $to";
return;
} # if
mail (
- from => "BICE\@$domain",
- to => $to,
- cc => $contact,
- subject => $subject,
- mode => 'html',
- data => $message,
+ from => "BICE\@$domain",
+ to => $to,
+ #cc => $contact,
+ subject => $subject,
+ mode => 'html',
+ data => $message,
);
} # SendEmail
sub processLogfile () {
my %violations;
-
+
# Note: Normally you must be root to open up $security_logfile
open my $readlog, '<', $security_logfile
or error "Unable to open $security_logfile - $!", 1;
-
+
flock $readlog, LOCK_EX
or error "Unable to flock $security_logfile", 1;
-
+
my @lines;
-
+
while (<$readlog>) {
my $newline = $_;
-
+
if (/^(\S+\s+\S+\s+\S+)\s+.*Invalid user (\w+) from (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/) {
my %violation = $violations{$3} ? %{$violations{$3}} : %_;
-
+
push @{$violation{$2}}, $1;
$violations{$3} = \%violation;
-
+
$newline =~ s/Invalid user/INVALID USER/;
} elsif (/^(\S+\s+\S+\s+\S+)\s+.*authentication failure.*ruser=(\S+).*rhost=(\S+)/) {
my %violation = $violations{$3} ? %{$violations{$3}} : %_;
-
+
push @{$violation{$2}}, $1;
$violations{$3} = \%violation;
-
+
$newline =~ s/authentication failure/AUTHENTICATION FAILURE/;
} elsif (/^(\S+\s+\S+\s+\S+)\s+.*Failed password for (\w+) from (\d{1,3}\.\d{1,3}\.d{1,3}\.d{1,3})/) {
my %violation = $violations{$3} ? %{$violations{$3}} : %_;
-
+
push @{$violation{$2}}, $1;
$violations{$3} = \%violation;
-
+
$newline =~ s/Failed password/FAILED PASSWORD/;
} # if
push @lines, $newline;
} # while
-
+
return %violations unless $update;
-
+
flock $readlog, LOCK_UN
or error "Unable to unlock $security_logfile", 1;
-
+
close $readlog;
-
+
open my $writelog, '>', $security_logfile
or error "Unable to open $security_logfile for writing - $!", 1;
-
+
flock $writelog, LOCK_EX
or error "Unable to flock $security_logfile", 1;
-
- print $writelog $_ foreach @lines;
-
+
+ print $writelog $_ for @lines;
+
flock $writelog, LOCK_UN
or error "Unable to unlock $security_logfile", 1;
close $writelog;
-
+
return %violations;
} # processLogfile
@@ -257,7 +242,7 @@ sub ReportBreakins () {
my %violations = processLogfile;
my $nbrViolations = keys %violations;
-
+
if ($nbrViolations == 0) {
verbose 'No violations found';
} elsif ($nbrViolations == 1) {
@@ -265,22 +250,23 @@ sub ReportBreakins () {
} else {
verbose "$nbrViolations sites attempting to violate our perimeter";
} # if
-
- foreach (sort keys %violations) {
- my $ip = $_;
+ my $violations;
+
+ for my $ip (sort keys %violations) {
my $attempts;
-
- $attempts += @{$violations{$ip}{$_}} foreach (keys %{$violations{$ip}});
-
- my @emails = GetEmailAddresses $ip;
+
+ $violations++;
+ $attempts += @{$violations{$ip}{$_}} for (keys %{$violations{$ip}});
+
+ my @emails = GetEmailAddresses $ip;
unless (@emails) {
verbose 'Unable to find any responsible parties for detected breakin '
. "attempts from IP $ip ($attempts breakin attempts)";
next;
} # unless
-
+
my $to = join ',', @emails;
my $subject = "Illegal attempts to break into $domain from your domain";
my $message = <<"END";
@@ -309,28 +295,27 @@ attempted and the time of the attempt:
END
# Report users
- foreach my $user (sort keys %{$violations{$ip}}) {
+ for my $user (sort keys %{$violations{$ip}}) {
if (@{$violations{$ip}{$user}} == 1) {
- $message .= "- The user $user attempted access on $violations{$ip}{$user}[0]
";
+ $message .= "- The user $user attempted access on $violations{$ip}{$user}[0]
";
} else {
$message .= "- The user $user attemped access on the following date/times:
";
$message .= "";
- $message .= "- $_
" foreach (@{$violations{$ip}{$user}});
+ $message .= "- $_
" for (@{$violations{$ip}{$user}});
$message .= "
";
- } # if
- } # foreach
+ } # if
+ } # for
$message .= '
Your prompt attention to this matter is expected '
. 'and will be appreciated.
';
- SendEmail $to, $subject, $message, $ip, $attempts;
- } # foreach
-
- AddToIPTables keys %violations;
+ SendEmail $to, $subject, $message, $ip, $attempts, $violations;
+ AddToIPSet $ip;
+ } # for
+
+ return;
} # ReportBreakins
## Main
-
-# Get options
GetOptions (
'verbose', sub { set_verbose },
'debug', sub { set_debug },
@@ -340,8 +325,7 @@ GetOptions (
'file=s', \$security_logfile,
) || Usage;
-Usage 'Must specify filename'
- unless $security_logfile;
+Usage 'Must specify filename' unless $security_logfile;
ReportBreakins;