]>
git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blob - config/guardian/guardian.pl
2 # based on V 1.7 guardian enhanced for IPFire and snort 2.8
3 # Read the readme file for changes
5 # Enhanced for IPFire by IPFire Team
6 # Added Portscan detection for non syslog system
7 # Added SSH-Watch for SSH-Bruteforce Attacks
8 # An suppected IP will be blocked on all interfaces
12 print "OS shows $OS\n";
17 if (defined($opt_h)) {
18 print "Guardian v1.7 \n";
19 print "guardian.pl [-hd] <-c config>\n";
20 print " -h shows help\n";
21 print " -d run in debug mode (doesn't fork, output goes to STDOUT)\n";
22 print " -c specifiy a configuration file other than the default (/etc/guardian.conf)\n";
28 print "My ip address and interface are: $hostipaddr $interface\n";
30 if ($hostipaddr !~ /\d+\.\d+\.\d+\.\d+/) {
31 print "This ip address is bad : $hostipaddr\n";
32 die "I need a good host ipaddress\n";
35 $networkaddr = $hostipaddr;
36 $networkaddr =~ s/\d+$/0/;
37 $gatewayaddr = `cat /var/ipfire/red/remote-ipaddress 2>/dev/null`;
38 $broadcastaddr = $hostipaddr;
39 $broadcastaddr =~ s/\d+$/255/;
42 print "My gatewayaddess is: $gatewayaddr\n";
44 # This is the target hash. If a packet was destened to any of these, then the
45 # sender of that packet will get denied, unless it is on the ignore list..
47 %targethash = ( "$networkaddr" => 1,
48 "$broadcastaddr" => 1,
49 "0" => 1, # This is what gets sent to &checkem if no
50 # destination was found.
57 if ( -e
$targetfile ) {
61 if (!defined($opt_d)) {
62 print "Becoming a daemon..\n";
64 } else { print "Running in debug mode..\n"; }
66 open (ALERT
, $alert_file) or die "can't open alert file: $alert_file: $!\n";
67 seek (ALERT
, 0, 2); # set the position to EOF.
68 # this is the same as a tail -f :)
70 open (ALERT2
, "/var/log/messages" ) or die "can't open /var/log/messages: $!\n";
71 seek (ALERT2
, 0, 2); # set the position to EOF.
72 # this is the same as a tail -f :)
79 if (defined($opt_d)) {
82 if (/\[\*\*\]\s+(.*)\s+\[\*\*\]/){
85 if (/(\d+\.\d+\.\d+\.\d+):\d+ -\> (\d+\.\d+\.\d+\.\d+):\d+/) {
86 &checkem
($1, $2, $type);
88 if (/(\d+\.\d+\.\d+\.\d+)+ -\> (\d+\.\d+\.\d+\.\d+)+/) {
89 &checkem
($1, $2, $type);
95 if (seek(ALERT2
,0,1)){
98 if ($_=~/.*sshd.*Failed password for root from.*/) {
99 my @array=split(/ /,$_);&checkssh
($array[11], "possible SSH-Bruteforce Attack");}
103 # Run this stuff every 30 seconds..
104 if ($counter == 30) {
105 &remove_blocks
; # This might get moved elsewhere, depending on how much load
106 # it puts on the system..
115 my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
116 $atime,$mtime,$ctime,$blksize,$blocks) = stat($alert_file);
117 if ($size < $previous_size) { # The filesize is smaller than last
118 close (ALERT
); # we checked, so we need to reopen it
119 open (ALERT
, "$alert_file"); # This should still work in our main while
120 $previous_size=$size; # loop (I hope)
121 write_log
("Log filename changed. Reopening $alert_file\n");
123 $previous_size=$size;
129 my ($source, $dest,$type) = @_;
132 return 1 if ($source eq $hostipaddr);
133 # this should prevent is from nuking ourselves
135 return 1 if ($source eq $gatewayaddr); # or our gateway
136 if ($ignore{$source} == 1) { # check our ignore list..
137 &write_log
("$source\t$type\n");
138 &write_log
("Ignoring attack because $source is in my ignore list\n");
142 # if the offending packet was sent to us, the network, or the broadcast, then
143 if ($targethash{$dest} == 1) {
144 &ipchain
($source, $dest, $type);
146 # you will see this if the destination was not in the $targethash, and the
147 # packet was not ignored before the target check..
149 &write_log
("Odd.. source = $source, dest = $dest - No action done.\n");
150 if (defined ($opt_d)) {
151 foreach $key (keys %targethash) {
152 &write_log
("targethash{$key} = $targethash{$key}\n");
159 my ($source,$type) = @_;
162 return 1 if ($source eq $hostipaddr);
163 # this should prevent is from nuking ourselves
165 return 1 if ($source eq $gatewayaddr); # or our gateway
167 if ($sshhash{$dest} eq "" ){
170 if ($sshhash{$dest} >= 3 ) {
171 &write_log
("source = $source, count $sshhash{$dest} - blocking for ssh attack.\n");
172 &ipchain
($source, "", $type);
174 # you will see this if the destination was not in the $sshhash, and the
175 # packet was not ignored before the target check..
177 &write_log
("Odd.. source = $source, ssh count only $sshhash{$dest} - No action done.\n");
178 if (defined ($opt_d)) {
179 foreach $key (keys %sshhash) {
180 &write_log
("sshhash{$key} = %sshhash{$key}\n");
183 $sshhash{$key} = $sshhash{$key}+1;
188 my ($source, $dest, $type) = @_;
189 &write_log
("$source\t$type\n");
190 if ($hash{$source} eq "") {
191 &write_log
("Running '$blockpath $source $interface'\n");
192 system ("$blockpath $source $interface");
193 $hash{$source} = time() + $TimeLimit;
195 # We have already blocked this one, but snort detected another attack. So
196 # we should update the time blocked..
197 $hash{$source} = time() + $TimeLimit;
201 sub build_ignore_hash
{
202 # This would cause is to ignore all broadcasts if it
203 # got set.. However if unset, then the attacker could spoof the packet to make
204 # it look like it came from the network, and a reply to the spoofed packet
205 # could be seen if the attacker were on the local network.
206 # $ignore{$networkaddr}=1;
208 # same thing as above, just with the broadcast instead of the network.
209 # $ignore{$broadcastaddr}=1;
211 $ignore{$gatewayaddr}=1;
212 $ignore{$hostipaddr}=1;
213 if ($ignorefile ne "") {
214 open (IGNORE
, $ignorefile);
218 next if (/\#/); #skip comments
219 next if (/^\s*$/); # and blank lines
224 print "Loaded $count addresses from $ignorefile\n";
226 print "No ignore file was loaded!\n";
232 $opt_c = "/etc/guardian.conf";
236 die "Need a configuration file.. please use to the -c option to name a configuration file\n";
239 open (CONF
, $opt_c) or die "Cannot read the config file $opt_c, $!\n";
242 next if (/^\s*$/); #skip blank lines
243 next if (/^#/); # skip comment lines
244 if (/LogFile\s+(.*)/) {
247 if (/Interface\s+(.*)/) {
249 if ( $interface eq "" ) {
250 $interface = `cat /var/ipfire/ethernet/settings | grep RED_DEV | cut -d"=" -f2`;
253 if (/AlertFile\s+(.*)/) {
256 if (/IgnoreFile\s+(.*)/) {
259 if (/TargetFile\s+(.*)/) {
262 if (/TimeLimit\s+(.*)/) {
265 if (/HostIpAddr\s+(.*)/) {
268 if (/HostGatewayByte\s+(.*)/) {
269 $hostgatewaybyte = $1;
273 if ($alert_file eq "") {
274 print "Warning! AlertFile is undefined.. Assuming /var/log/snort.alert\n";
275 $alert_file="/var/log/snort.alert";
277 if ($hostipaddr eq "") {
278 print "Warning! HostIpAddr is undefined! Attempting to guess..\n";
279 $hostipaddr = `cat /var/ipfire/red/local-ipaddress`;
280 print "Got it.. your HostIpAddr is $hostipaddr\n";
282 if ($ignorefile eq "") {
283 print "Warning! IgnoreFile is undefined.. going with default ignore list (hostname and gateway)!\n";
285 if ($hostgatewaybyte eq "") {
286 print "Warning! HostGatewayByte is undefined.. gateway will not be in ignore list!\n";
288 if ($logfile eq "") {
289 print "Warning! LogFile is undefined.. Assuming debug mode, output to STDOUT\n";
293 print "Warning! Logfile is not writeable! Engaging debug mode, output to STDOUT\n";
297 foreach $mypath (split (/:/, $ENV{PATH
})) {
298 if (-x
"$mypath/guardian_block.sh") {
299 $blockpath = "$mypath/guardian_block.sh";
301 if (-x
"$mypath/guardian_unblock.sh") {
302 $unblockpath = "$mypath/guardian_unblock.sh";
306 if ($blockpath eq "") {
307 print "Error! Could not find guardian_block.sh. Please consult the README. \n";
310 if ($unblockpath eq "") {
311 print "Warning! Could not find guardian_unblock.sh. Guardian will not be\n";
312 print "able to remove blocked ip addresses. Please consult the README file\n";
314 if ($TimeLimit eq "") {
315 print "Warning! Time limit not defined. Defaulting to absurdly long time limit\n";
316 $TimeLimit = 999999999;
322 my $date = localtime();
323 if (defined($opt_d)) { # we are in debug mode, and not daemonized
324 print STDOUT
$message;
326 open (LOG
, ">>$logfile");
327 print LOG
$date.": ".$message;
339 &write_log
("Guardian process id $$\n");
340 $home = (getpwuid($>))[7] || die "No home directory!\n";
341 chdir($home); # go to my homedir
342 setpgrp(0,0); # become process leader
346 print "Testing...\n";
350 sub sig_handler_setup
{
351 $SIG{INT
} = \
&clean_up_and_exit
; # kill -2
352 $SIG{TERM
} = \
&clean_up_and_exit
; # kill -9
353 $SIG{QUIT
} = \
&clean_up_and_exit
; # kill -3
354 # $SIG{HUP} = \&flush_and_reload; # kill -1
360 foreach $source (keys %hash) {
361 if ($hash{$source} < $time) {
362 &call_unblock
($source, "expiring block of $source\n");
363 delete ($hash{$source});
369 my ($source, $message) = @_;
370 &write_log
("$message");
371 system ("$unblockpath $source $interface");
374 sub clean_up_and_exit
{
376 &write_log
("received kill sig.. shutting down\n");
377 foreach $source (keys %hash) {
378 &call_unblock
($source, "removing $source for shutdown\n");
383 sub load_targetfile
{
385 open (TARG
, "$targetfile") or die "Cannot open $targetfile\n";
388 next if (/\#/); #skip comments
389 next if (/^\s*$/); # and blank lines
394 print "Loaded $count addresses from $targetfile\n";
399 print "Scanning for aliases on $interface and add them to the target hash...";
401 open (IFCONFIG
, "/sbin/ip addr show $interface |");
402 my @lines = <IFCONFIG
>;
405 foreach $line (@lines) {
406 if ( $line =~ /inet (\d+\.\d+\.\d+\.\d+)/) {
408 print " got $ip on $interface ... ";
409 $targethash{'$ip'} = "1";