comparison maltfilter @ 69:b090ddfccdab

Cleanups. Improve IP/host definitions.
author Matti Hamalainen <ccr@tnsp.org>
date Wed, 26 Aug 2009 15:19:08 +0300
parents bac5931b8312
children adb4795f451e
comparison
equal deleted inserted replaced
68:bac5931b8312 69:b090ddfccdab
10 use Date::Parse; 10 use Date::Parse;
11 use Net::IP; 11 use Net::IP;
12 use Net::DNS; 12 use Net::DNS;
13 use LWP::UserAgent; 13 use LWP::UserAgent;
14 14
15 my $progversion = "0.16.0"; 15 my $progversion = "0.16.2";
16 my $progbanner = 16 my $progbanner =
17 "Malicious Attack Livid Termination Filter daemon (maltfilter) v$progversion\n". 17 "Malicious Attack Livid Termination Filter daemon (maltfilter) v$progversion\n".
18 "Programmed by Matti 'ccr' Hamalainen <ccr\@tnsp.org>\n". 18 "Programmed by Matti 'ccr' Hamalainen <ccr\@tnsp.org>\n".
19 "(C) Copyright 2009 Tecnic Software productions (TNSP)\n"; 19 "(C) Copyright 2009 Tecnic Software productions (TNSP)\n";
20 20
28 "LOGFILE" => "", 28 "LOGFILE" => "",
29 "STATS_MAX_AGE" => 336, # in hours 29 "STATS_MAX_AGE" => 336, # in hours
30 30
31 "PASSWD" => "/etc/passwd", 31 "PASSWD" => "/etc/passwd",
32 "SYSACCT_MIN_UID" => 1, 32 "SYSACCT_MIN_UID" => 1,
33 "SYSACCT_MAX_UID" => 100, 33 "SYSACCT_MAX_UID" => 999,
34 34
35 "FILTER" => 0, 35 "FILTER" => 0,
36 "FILTER_THRESHOLD" => 3, 36 "FILTER_THRESHOLD" => 3,
37 "FILTER_MAX_AGE" => 168, # in hours 37 "FILTER_MAX_AGE" => 168, # in hours
38 "FILTER_TARGET" => "DROP", 38 "FILTER_TARGET" => "DROP",
60 "DRONEBL_MAX_AGE" => 30, # in minutes 60 "DRONEBL_MAX_AGE" => 30, # in minutes
61 "DRONEBL_RPC_URI" => "http://dronebl.org/RPC2", 61 "DRONEBL_RPC_URI" => "http://dronebl.org/RPC2",
62 "DRONEBL_RPC_KEY" => "", 62 "DRONEBL_RPC_KEY" => "",
63 ); 63 );
64 64
65 # List loopback and private netblocks by default here
65 my @noaction_ips_def = ( 66 my @noaction_ips_def = (
66 "127.0.0.1", 67 "127.0.0.0/8",
68 "10.0.0.0/8",
69 "172.16.0.0/12",
70 "192.168.0.0/16"
67 ); 71 );
68 72
69 my %systemacct = (); 73 my %systemacct = ();
70 sub check_add_hit($$$$$$); 74 sub check_add_hit($$$$$$);
71 75
139 ### Global variables 143 ### Global variables
140 ############################################################################# 144 #############################################################################
141 my $reportmode = 0; # Full report mode 145 my $reportmode = 0; # Full report mode
142 my @scanfiles = (); # Files to scan 146 my @scanfiles = (); # Files to scan
143 my @scanfiles_once = (); # Files to scan only once during startup or HUP (e.g. not continuously followed) 147 my @scanfiles_once = (); # Files to scan only once during startup or HUP (e.g. not continuously followed)
144 my @noaction_ips = (); # IPs not to block 148 my @noaction_ips = (); # IPs not to filter
145 my %filehandles = (); # Global hash holding opened scanned log filehandles 149 my %filehandles = (); # Global hash holding opened scanned log filehandles
146 my $pid_file = ""; # Name of Maltfilter daemon pid file 150 my $pid_file = ""; # Name of Maltfilter daemon pid file
147 my @configfiles = (); # Array of configuration file names 151 my @configfiles = (); # Array of configuration file names
148 my $LOGFILE; # Maltfilter logfile handle 152 my $LOGFILE; # Maltfilter logfile handle
149 my %dronebl = (); 153 my %dronebl = ();
154 # Gathered information about hosts 158 # Gathered information about hosts
155 # $statlist{$ip}-> 159 # $statlist{$ip}->
156 # "date1" = timestamp of first hit 160 # "date1" = timestamp of first hit
157 # "date2" = timestamp of latest hit 161 # "date2" = timestamp of latest hit
158 # "hits" = number of hits to this IP 162 # "hits" = number of hits to this IP
163 # "dronebl" = 1 == queued for submission, 2 == submitted
159 # $statlist{$ip}{"reason"}{$class}-> 164 # $statlist{$ip}{"reason"}{$class}->
160 # "msg" = reason message (array if $reportmode) 165 # "msg" = reason message (array if $reportmode)
161 # "hits" = hits to this class 166 # "hits" = hits to this class
162 # "date1" = timestamp of first hit 167 # "date1" = timestamp of first hit
163 # "date2" = timestamp of latest hit 168 # "date2" = timestamp of latest hit
524 # Create submission data 529 # Create submission data
525 my $xml = "<?xml version=\"1.0\"?>\n<request key=\"".$settings{"DRONEBL_RPC_KEY"}."\">\n"; 530 my $xml = "<?xml version=\"1.0\"?>\n<request key=\"".$settings{"DRONEBL_RPC_KEY"}."\">\n";
526 my $entries = 0; 531 my $entries = 0;
527 while (my ($ip, $entry) = each(%dronebl)) { 532 while (my ($ip, $entry) = each(%dronebl)) {
528 if ($entry->{"sent"} == 0 && $entry->{"tries"} < 3) { 533 if ($entry->{"sent"} == 0 && $entry->{"tries"} < 3) {
529 $xml .= "<add ip=\"".$ip."\" type=\"".$entry->{"type"}."\" />\n"; 534 # $xml .= "<add ip=\"".$ip."\" type=\"".$entry->{"type"}."\" />\n";
535 $xml .= "<add ip=\"".$ip."\" type=\"1\" />\n";
530 $entries++; 536 $entries++;
531 } 537 }
532 } 538 }
533 $xml .= "</request>\n"; 539 $xml .= "</request>\n";
534 540
539 # return; 545 # return;
540 } else { 546 } else {
541 mlog(1, "[DroneBL] Trying to submit $entries entries.\n"); 547 mlog(1, "[DroneBL] Trying to submit $entries entries.\n");
542 } 548 }
543 549
550 if (0) {
544 # Submit via HTTP XML-RPC 551 # Submit via HTTP XML-RPC
545 my $tmp = LWP::UserAgent->new; 552 my $tmp = LWP::UserAgent->new;
546 $tmp->agent("Maltfilter/".$progversion); 553 $tmp->agent("Maltfilter/".$progversion);
547 $tmp->timeout(10); 554 $tmp->timeout(10);
548 my $req = HTTP::Request->new(POST => $settings{"DRONEBL_RPC_URI"}); 555 my $req = HTTP::Request->new(POST => $settings{"DRONEBL_RPC_URI"});
550 $req->content($xml); 557 $req->content($xml);
551 $req->user_agent("Maltfilter/".$progversion); 558 $req->user_agent("Maltfilter/".$progversion);
552 my $res = $tmp->request($req); 559 my $res = $tmp->request($req);
553 560
554 if ($res->is_success) { 561 if ($res->is_success) {
555 mlog(2, "[DroneBL] [".$res->code."] ".$res->message."\n"); 562 mlog(3, "[DroneBL] [".$res->code."] ".$res->message."\n");
556 print $res->content."\n"; 563 print $res->content."\n";
564
565
557 # while (my ($ip, $entry) = each(%dronebl)) { 566 # while (my ($ip, $entry) = each(%dronebl)) {
558 # $entry->{"sent"} = 1; 567 # $entry->{"sent"} = 1;
568 # $statlist{$ip}{"dronebl"} = 2 if (defined($statlist{$ip}));
559 # } 569 # }
560 } else { 570 } else {
561 mlog(-1, "[DroneBL] Submission failed: [".$res->code."] ".$res->message."\n"); 571 mlog(-1, "[DroneBL] Submission failed: [".$res->code."] ".$res->message."\n");
562 } 572 }
563 573 }
564 # Remove submitted expired entries 574
575 # Clean up expired entries, warning about unsubmitted ones.
565 while (my ($ip, $entry) = each(%dronebl)) { 576 while (my ($ip, $entry) = each(%dronebl)) {
566 if (!check_time3($entry->{"date"})) { 577 if (!check_time3($entry->{"date"})) {
567 mlog(1, "[DroneBL] $ip submission expired.\n") unless ($entry->{"sent"} > 0); 578 mlog(1, "[DroneBL] $ip submission expired.\n") unless ($entry->{"sent"} > 0);
568 delete($dronebl{$ip}); 579 delete($dronebl{$ip});
569 } 580 }
571 } 582 }
572 583
573 sub dronebl_queue($$$) 584 sub dronebl_queue($$$)
574 { 585 {
575 my ($mip, $mdate, $mtype) = @_; 586 my ($mip, $mdate, $mtype) = @_;
587
588 return unless ($settings{"DRONEBL"} > 0);
589 return if check_hosts_array(\@noaction_ips, $mip);
590
576 if (!defined($dronebl{$mip})) { 591 if (!defined($dronebl{$mip})) {
577 mlog(3, "[DroneBL] Queueing $mip \@ $mdate ($mtype)\n"); 592 mlog(3, "[DroneBL] Queueing $mip \@ $mdate ($mtype)\n");
578 $dronebl{$mip}{"type"} = $mtype; 593 $dronebl{$mip}{"type"} = $mtype;
579 $dronebl{$mip}{"date"} = $mdate; 594 $dronebl{$mip}{"date"} = $mdate;
580 $dronebl{$mip}{"sent"} = 0; 595 $dronebl{$mip}{"sent"} = 0;
581 $dronebl{$mip}{"tries"} = 0; 596 $dronebl{$mip}{"tries"} = 0;
597 $statlist{$mip}{"dronebl"} = 1 if (defined($statlist{$mip}));
582 } 598 }
583 } 599 }
584 600
585 ############################################################################# 601 #############################################################################
586 ### Evidence gathering 602 ### Evidence gathering
697 sub check_hosts_array($$) 713 sub check_hosts_array($$)
698 { 714 {
699 my $chk_host = $_[1]; 715 my $chk_host = $_[1];
700 my $chk_ip = new Net::IP($chk_host); 716 my $chk_ip = new Net::IP($chk_host);
701 foreach my $host (@{$_[0]}) { 717 foreach my $host (@{$_[0]}) {
702 if ($chk_host eq $host) {
703 return 1;
704 }
705 my $ip = new Net::IP($host); 718 my $ip = new Net::IP($host);
706 if (defined($chk_ip) && defined($ip)) { 719 if (defined($chk_ip) && defined($ip)) {
707 if ($chk_ip->binip() eq $ip->binip()) { 720 my $res = $chk_ip->overlaps($ip);
708 return 1; 721 if (defined($res)) {
709 } 722 return 1 if ($res == $IP_IDENTICAL);
710 } 723 return 2 if ($res == $IP_B_IN_A_OVERLAP);
724 return 3 if ($res == $IP_A_IN_B_OVERLAP);
725 }
726 }
727 return 4 if ($chk_host eq $host);
711 } 728 }
712 return 0; 729 return 0;
713 } 730 }
714 731
715 ### Check IP/host against | separated list of IPs/hosts 732 ### Check IP/host against | separated list of IPs/hosts
847 864
848 sub update_entry($$$$$$) 865 sub update_entry($$$$$$)
849 { 866 {
850 my ($struct, $mip, $mdate, $mclass, $mreason, $addhits) = @_; 867 my ($struct, $mip, $mdate, $mclass, $mreason, $addhits) = @_;
851 868
869 return if check_hosts_array(\@noaction_ips, $mip);
870
852 $struct->{$mip} = {} unless defined($struct->{$mip}); 871 $struct->{$mip} = {} unless defined($struct->{$mip});
853 my $entry = $struct->{$mip}; 872 my $entry = $struct->{$mip};
854 $entry->{"reason"}{$mclass} = {} unless defined($entry->{"reason"}{$mclass}); 873 $entry->{"reason"}{$mclass} = {} unless defined($entry->{"reason"}{$mclass});
855 my $reason = $entry->{"reason"}{$mclass}; 874 my $reason = $entry->{"reason"}{$mclass};
856 875
913 # Update date of last hit 932 # Update date of last hit
914 $filterlist{$mip} = $mdate; 933 $filterlist{$mip} = $mdate;
915 } 934 }
916 935
917 # Separate check for DroneBL 936 # Separate check for DroneBL
918 if ($settings{"DRONEBL"} > 0 && $mtype > 0 && $cnt >= $settings{"DRONEBL_THRESHOLD"} && check_time3($mdate)) { 937 if ($mtype > 0 && $cnt >= $settings{"DRONEBL_THRESHOLD"} && check_time3($mdate)) {
919 dronebl_queue($mip, $mdate, $mtype); 938 dronebl_queue($mip, $mdate, $mtype);
920 } 939 }
921 } 940 }
922 941
923 942
1090 if ($key eq "SCANFILE") { 1109 if ($key eq "SCANFILE") {
1091 push(@scanfiles, $value); 1110 push(@scanfiles, $value);
1092 } elsif ($key eq "SCANFILE_ONCE") { 1111 } elsif ($key eq "SCANFILE_ONCE") {
1093 push(@scanfiles_once, $value); 1112 push(@scanfiles_once, $value);
1094 } elsif ($key eq "NOACTION_IPS") { 1113 } elsif ($key eq "NOACTION_IPS") {
1095 push(@noaction_ips_def, $value); 1114 push(@noaction_ips, $value);
1096 } elsif (defined($settings{$key})) { 1115 } elsif (defined($settings{$key})) {
1097 $settings{$key} = $value; 1116 $settings{$key} = $value;
1098 } else { 1117 } else {
1099 mlog(-1, "[$filename:$line] Unknown setting '$key' = '$value'\n"); 1118 mlog(-1, "[$filename:$line] Unknown setting '$key' = '$value'\n");
1100 $errors = 1; 1119 $errors = 1;
1119 @scanfiles = (); 1138 @scanfiles = ();
1120 undef(@scanfiles); 1139 undef(@scanfiles);
1121 1140
1122 @scanfiles_once = (); 1141 @scanfiles_once = ();
1123 undef(@scanfiles_once); 1142 undef(@scanfiles_once);
1143
1144 @noaction_ips = ();
1145 undef(@noaction_ips);
1124 1146
1125 foreach my $filename (@configfiles) { 1147 foreach my $filename (@configfiles) {
1126 mdie("Errors in configuration file '$filename', bailing out.\n") 1148 mdie("Errors in configuration file '$filename', bailing out.\n")
1127 unless (malt_read_config($filename) == 0); 1149 unless (malt_read_config($filename) == 0);
1128 } 1150 }
1133 1155
1134 %saw = (); 1156 %saw = ();
1135 @scanfiles_once = grep(!$saw{$_}++, @scanfiles_once); 1157 @scanfiles_once = grep(!$saw{$_}++, @scanfiles_once);
1136 1158
1137 %saw = (); 1159 %saw = ();
1138 @noaction_ips = grep(!$saw{$_}++, @noaction_ips_def); 1160 push(@noaction_ips, @noaction_ips_def);
1161 @noaction_ips = grep(!$saw{$_}++, @noaction_ips);
1139 undef(%saw); 1162 undef(%saw);
1140 1163
1141 mlog(-1, "Not acting on IPs: ".join(", ", @noaction_ips)."\n"); 1164 mlog(-1, "Not acting on IPs: ".join(", ", @noaction_ips)."\n");
1142 1165
1143 # Check if we have anything to do 1166 # Check if we have anything to do