]> git.proxmox.com Git - pmg-api.git/blobdiff - bin/pmg-smtp-filter
rename safe_browsing_score to clamav_heuristic_score
[pmg-api.git] / bin / pmg-smtp-filter
index 92221adf6daf59edeca0573222d77ab6bd6d1d52..ac2c384b23da09aee60e42eb72b656da8d0f5cb0 100755 (executable)
@@ -5,7 +5,7 @@ use warnings;
 
 use Carp;
 use Getopt::Long;
-use Time::HiRes qw (gettimeofday tv_interval);
+use Time::HiRes qw (usleep gettimeofday tv_interval);
 use POSIX qw(:sys_wait_h errno_h signal_h);
 
 use MIME::Parser;
@@ -28,12 +28,14 @@ use Mail::SpamAssassin::NetSet;
 use PMG::pmgcfg;
 use PMG::Utils;
 use PMG::Cluster;
+use PMG::ClusterConfig;
 
 use PMG::DBTools;
 use PMG::RuleDB;
 use PMG::RuleCache;
 use PMG::ModGroup;
 use PMG::AtomicFile;
+use PMG::LDAPConfig;
 use PMG::LDAPSet;
 use PMG::Config;
 use PMG::MailQueue;
@@ -47,7 +49,7 @@ use base qw(Net::Server::PreFork);
 
 my $opt_commandline = [$0, @ARGV];
 my $opt_max_dequeue = 1;
-my $opt_dequeue_time = 60*2;
+my $opt_dequeue_time = 30;
 
 my $opt_ext_port = 10024;
 my $opt_int_port = 10023;
@@ -78,9 +80,6 @@ my $min_spare_servers = 0;
 my $max_spare_servers = 0;
 my $max_requests = 1;
 
-# create spool directories
-PMG::MailQueue::create_sppoldirs();
-
 if (!$opt_testmode) {
 
     my $pmg_cfg = PMG::Config->new();
@@ -371,6 +370,9 @@ sub load_config {
     $self->{pmg_cfg} = PMG::Config->new();
     $self->{cinfo} = PVE::INotify::read_file("cluster.conf");
 
+    # create spool directories
+    PMG::MailQueue::create_spooldirs($self->{cinfo}->{local}->{cid});
+
     eval {
        my $dbh = PMG::DBTools::open_ruledb ($database);
        $self->{ruledb} = PMG::RuleDB->new ($dbh);
@@ -387,7 +389,8 @@ sub load_config {
     }
 
     # create LDAP object
-    $self->{ldap} = PMG::LDAPSet->new_from_pmg_cfg($self->{pmg_cfg}, 1);
+    my $ldapconf = PVE::INotify::read_file('pmg-ldap.conf');
+    $self->{ldap} = PMG::LDAPSet->new_from_ldap_cfg($ldapconf, 1);
 
     $self->{reload_config} = 0;
 }
@@ -493,11 +496,32 @@ sub child_finish_hook {
     $self->{ruledb}->close () if $self->{ruledb};
 }
 
+my $last_dequeue_time = 0;
+
 sub run_dequeue {
     my $self = shift;
 
+    my $err;
+
     # do database maintainance here
 
+    # this is called every 30 secends
+    eval {
+       PMG::Utils::update_node_status_rrd();
+    };
+    if ($err = $@) {
+       $self->log(0, "ERROR: $err");
+       # continue
+    }
+
+    my $ctime = time();
+    my $tdiff = $ctime - $last_dequeue_time;
+
+    # return if tdiff less than 2 minutes
+    return if $tdiff < 2*60;
+
+    $last_dequeue_time = $ctime;
+
     $self->log (2, "starting database maintainance");
 
     my ($csec, $usec) = gettimeofday ();
@@ -509,10 +533,8 @@ sub run_dequeue {
     eval {
        $dbh = PMG::DBTools::open_ruledb($database);
     };
-    my $err = $@;
-
-    if ($err) {
-       $self->log (0, msgquote("ERROR: $err"));
+    if ($err = $@) {
+       $self->log (0, "ERROR: $err");
        return;
     }
 
@@ -525,7 +547,7 @@ sub run_dequeue {
     my $ptime = int (($csec_end-$csec)*1000 + ($usec_end - $usec)/1000);
 
     if ($err) {
-       $self->log (0, msgquote($err));
+       $self->log (0, $err);
     } else {
        $self->log (2, "end database maintainance ($ptime ms)");
     }
@@ -602,6 +624,8 @@ sub handle_smtp {
 
     $queue = $smtp->{queue};
     $queue->{sa} = $self->{sa};
+    $queue->{clamav_heuristic_score} =
+       $opt_testmode ? 100 : $pmg_cfg->get('spam', 'clamav_heuristic_score');
 
     $queue->{lic_valid} = 1;
 
@@ -647,9 +671,17 @@ sub handle_smtp {
 
 
        # test for virus first
-       $queue->{vinfo} = PMG::Utils::analyze_virus(
+       my $vinfo = PMG::Utils::analyze_virus(
            $queue, $queue->{dataname}, $pmg_cfg, $opt_testmode);
 
+       if ($vinfo && $vinfo =~ m/^Heuristics\.(.+)$/) {
+           my $hit = $1;
+           $queue->{clamav_heuristic} = $hit;
+           $vinfo = undef;
+       }
+
+       $queue->{vinfo} = $vinfo;
+
        # always add this headers to incoming mails
        # to enable user to report false negatives
        if (!$msginfo->{trusted}) {
@@ -747,38 +779,35 @@ sub handle_smtp {
 
     eval {
        my $dbh = $self->{ruledb}->{dbh};
+
        my $where = "";
        foreach my $rid (@$matching_rules) {
            $where .= $where ? " OR ID = $rid" : "ID = $rid";
        }
-       if ($where) {
-           $dbh->do ("UPDATE Rule " .
-                     "SET Count = Count + 1 " .
-                     "WHERE $where");
-       }
+
+       $dbh->do ("UPDATE Rule SET Count = Count + 1 WHERE $where") if $where;
 
        my $insert_cmds = "SELECT nextval ('cstatistic_id_seq');INSERT INTO CStatistic " .
            "(CID, RID, ID, Time, Bytes, Direction, Spamlevel, VirusInfo, PTime, Sender) VALUES (" .
-           "$lcid, currval ('cstatistic_id_seq'), currval ('cstatistic_id_seq'),";
+           "$lcid, currval('cstatistic_id_seq'), currval('cstatistic_id_seq'),";
 
        $insert_cmds .= $queue->{rtime} . ',';
        $insert_cmds .= $queue->{bytes} . ',';
-       $insert_cmds .= $dbh->quote ($msginfo->{trusted} ? 0 : 1) . ',';
+       $insert_cmds .= $dbh->quote($msginfo->{trusted} ? 0 : 1) . ',';
        $insert_cmds .= ($queue->{sa_score} || 0) . ',';
-       $insert_cmds .= $dbh->quote ($queue->{vinfo}) . ',';
+       $insert_cmds .= $dbh->quote($queue->{vinfo}) . ',';
        $insert_cmds .= $time_total . ',';
-       $insert_cmds .= $dbh->quote ($msginfo->{sender}) . ');';
+       $insert_cmds .= $dbh->quote($msginfo->{sender}) . ');';
 
        foreach my $r (@{$msginfo->{targets}}) {
-           my $tmp = $dbh->quote ($r);
+           my $tmp = $dbh->quote($r);
            my $blocked = $queue->{status}->{$r} eq 'blocked' ? 1 : 0;
            $insert_cmds .= "INSERT INTO CReceivers (CStatistic_CID, CStatistic_RID, Receiver, Blocked) " .
                "VALUES ($lcid, currval ('cstatistic_id_seq'), $tmp, '$blocked'); ";
        }
 
-       $dbh->do ($insert_cmds);
+       $dbh->do($insert_cmds);
     };
-
     # save $err (because log clears $@)
     $err = $@;
 
@@ -787,13 +816,14 @@ sub handle_smtp {
     my $ptspam = ($queue->{ptime_spam} || 0)/1000;
     my $ptclam = ($queue->{ptime_clam} || 0)/1000;
 
-    $self->log (3, "$queue->{logid}: processing time: ${time_total} seconds ($ptspam, $ptclam)");
+    $self->log(3, "$queue->{logid}: processing time: ${time_total} seconds ($ptspam, $ptclam)");
 
     $msginfo->{test_fh}->close if $opt_testmode;
 
-    die $err if ($err);
+    die $err if $err;
 }
 
+my $initial_memory_usage;
 
 sub process_request {
   my $self = shift;
@@ -829,6 +859,9 @@ sub process_request {
   kill(15, $prop->{ppid}) if $opt_testmode;
 
   my $mem = PVE::ProcFSTools::read_memory_usage();
+  if (!defined($initial_memory_usage) || ($prop->{requests} < 10)) {
+      $initial_memory_usage = $mem->{resident};
+  }
 
   if ($opt_testmode) {
       $self->log (0, "memory usage: $mem->{size} bytes");
@@ -836,10 +869,13 @@ sub process_request {
       if ($self->{errors}) {
          $self->log (0, "fast exit because of errors (free $mem->{size} bytes)");
          $self->done (1);
-      } elsif ($mem->{size} > (300*1024*1024)) {
-         $self->log (0, "fast exit to reduce server load (free $mem->{size} bytes)");
-         $self->done (1);
-     }
+      } else {
+         my $diff = $mem->{resident} - $initial_memory_usage;
+         if ($diff > 5*1024*1024) {
+             $self->log (0, "fast exit to reduce server load (free $diff bytes)");
+             $self->done (1);
+         }
+      }
   }
 
   $self->done (1) if $err;
@@ -882,12 +918,14 @@ sub pre_server_close_hook {
     }
 
     # nicely shutdown childs (give them max 30 seconds to shut down)
-    my $previous_alarm = alarm (30);
+    my $previous_alarm = alarm(30);
     eval {
        local $SIG{ALRM} = sub { die "Timed Out!\n" };
 
        my $pid;
        1 while ((($pid = waitpid (-1, 0)) > 0) || ($! == EINTR));
+
+       alarm(0); # avoid race
     };
     alarm ($previous_alarm);
 }
@@ -903,17 +941,20 @@ if (!$opt_testmode) {
     $server->run ();
 } else {
     if (fork) {
-       $server->run ();
+       $server->run();
     } else {
-       sleep (1);
+
        my $sender ='sender@proxtest.com';
        my $targets = ['target1@proxtest.com',
                       'target2@proxtest.com',
                       'target3@proxtest.com'];
 
-       my $smtp = Net::SMTP->new ('127.0.0.1', Port => 10023);
-
-       die "unable to connect $!" if !$smtp;
+       my $smtp;
+       while (!$smtp) {
+           $smtp = Net::SMTP->new ('127.0.0.1', Port => 10023);
+           last if $smtp;
+           usleep(10);
+       }
 
        # syslog ('info', "connected to " . $smtp->domain);