Projet

Général

Profil

Paste
Télécharger au format
Statistiques
| Branche: | Révision:

root / plugins / jchkmail / jchkmail_counters_ @ 17f78427

Historique | Voir | Annoter | Télécharger (17,6 ko)

1 4ca52784 Stig Sandbeck Mathisen
#!/usr/bin/perl
2 aa6e39ff Jose-Marcio Martins da Cruz
# -*- perl -*-
3
4
=pod
5
6
=encoding UTF-8
7
8
=head1 NAME
9
10
  jchkmail_counters_
11
12
=head1 APPLICABLE SYSTEMS
13
14
  MTAs running j-chkmail mail filter - http://www.j-chkmail.org
15
16
=head1 CONFIGURATION
17
18
  [jchkmail_counters_*]
19
    user root
20
21
The following environment variables may be defined :
22
23
    # disable some instances of the plugin
24
    env.disable    no
25
26
=head1 BUGS/GOTCHAS
27
28
  None known, but some improvements to do...
29
30
=head1 AUTHOR
31
32
    Jose-Marcio Martins da Cruz - mailto:Jose-Marcio.Martins@mines-paristech.fr
33
    Ecole Nationale Superieure des Mines de Paris
34
35
  This plugin was inspired by the work of Christophe Decor
36
    Christophe Decor - mailto:decor@supagro.inra.fr
37
    INRA - Institut National de Recherche Agronomique
38
39
=head1 COPYRIGHT
40
  Copyright Jose-Marcio Martins da Cruz
41
42 17f78427 Lars Kruse
=head1 VERSION
43 aa6e39ff Jose-Marcio Martins da Cruz
44
  1.0 - Feb 2014
45
46
=head1 MAGIC MARKERS
47
48
 #%# family=contrib
49
 #%# capabilities=autoconf suggest
50
51
=cut
52
53
use strict;
54
use warnings;
55
56
use lib $ENV{'MUNIN_LIBDIR'};
57
use Munin::Plugin;
58
59
my $SMCF     = "/etc/mail/jchkmail/j-chkmail.cf";
60
my $FSTATS   = "/var/jchkmail/files/j-stats";
61
my $WORKDIR  = "/var/jchkmail/wdb";
62
my $CONSTDIR = "/var/jchkmail/cdb";
63
64
# ------------------------------------------------
65
#
66
#
67
my $debug = 0;
68
69
my $AppName = $0;
70
$AppName = `basename $AppName`;
71
chomp $AppName;
72
73
my $AppExt = undef;
74
if ($AppName =~ /_([a-z0-9.-]+)$/i) {
75
  $AppExt = $1;
76
}
77
78
my $disable = defined $ENV{'disable'} &&  $ENV{'disable'} =~ /yes|oui/i;
79
80
my %StaticData = ();
81
GetStaticData(\%StaticData);
82
83
my $AppType = "";
84
if (defined $AppExt && exists $StaticData{config}{"$AppExt+type"}) {
85
  $AppType = $StaticData{config}{"$AppExt+type"};
86
}
87
88
# valider results from Munin::Plugin
89
# statefile is used only by jchkmail_counters_ratiospamham
90
my $StateFile = undef;
91
if (exists $ENV{MUNIN_PLUGSTATE} && defined $ENV{MUNIN_PLUGSTATE}) {
92
  $StateFile = "$ENV{MUNIN_PLUGSTATE}/$AppName.state-joe";
93
}
94
if (exists $ENV{statefile} && defined $ENV{statefile}) {
95
  $StateFile = $ENV{statefile};
96
}
97
98
# ------------------------------------------------
99
#
100
#
101
if ($#ARGV >= 0 && $ARGV[0] eq "autoconf") {
102 17f78427 Lars Kruse
103 aa6e39ff Jose-Marcio Martins da Cruz
  unless (-f $SMCF) {
104
    print "no\n";
105
    exit 0;
106
  }
107
  print "yes\n";
108
  exit 0;
109
}
110
111
# ------------------------------------------------
112
#
113
#
114
if ($#ARGV >= 0 && $ARGV[0] eq "suggest") {
115
116
  # results from /var/jchkmail/files/j-stats
117
  if (-f $SMCF && -f $FSTATS) {
118
    my %Data = ();
119
    my $line = GetStatsLine(\%Data);
120
    exit 1 unless defined $line && $line ne "";
121
122
    foreach my $k (keys %{$StaticData{config}}) {
123
      next unless $k =~ /(.*)[+]type$/;
124
      my $graph = $1;
125
      my $type  = $StaticData{config}{$k};
126
      if ($type =~ /^(counters|ratio)$/) {
127
        next unless exists $StaticData{config}{$graph . "+data"};
128
        my $data = $StaticData{config}{$graph . "+data"};
129
        $data =~ tr#,/# #;
130
        my @fields = split " ", $data;
131
        my $ok     = 1;
132
        my $bad    = "";
133
        for my $f (@fields) {
134
          unless (exists $Data{$f}) {
135
            $ok = 0;
136
            $bad .= " $f";
137
          }
138
        }
139
        if ($ok) {
140
          print "$graph\n" if $ok;
141
        } else {
142
          printf "# %-12s - Lacking fields : %s\n", $graph, $bad;
143
        }
144
      }
145
    }
146
  }
147
148
  # results from /var/jchkmail/wdb
149
  if (-f $SMCF && (-d $WORKDIR || -d $CONSTDIR)) {
150
    foreach my $k (keys %{$StaticData{config}}) {
151
      next unless $k =~ /(.*)[+]type$/;
152
      my $graph = $1;
153
      my $type  = $StaticData{config}{$k};
154
      if ($type =~ /^(dbcounters)$/) {
155
        next unless exists $StaticData{config}{$graph . "+data"};
156
        my $data = $StaticData{config}{$graph . "+data"};
157
        $data =~ tr#,/# #;
158
        my @fields = split " ", $data;
159
        my $ok     = 1;
160
        my $bad    = "";
161
        for my $f (@fields) {
162
          unless (-f "$WORKDIR/$f.db" || -f "$CONSTDIR/$f.db") {
163
            $ok = 0;
164
            $bad .= " $f";
165
          }
166
        }
167
        if ($ok) {
168
          print "$graph\n" if $ok;
169
        } else {
170
          printf "# %-12s - Lacking fields : %s\n", $graph, $bad;
171
        }
172
      }
173
    }
174
  }
175
  exit 0;
176
}
177
178
# ------------------------------------------------
179
#
180
#
181
if (defined $AppExt && $AppType eq "counters") {
182
  my %Data = ();
183
  my $line = GetStatsLine(\%Data);
184
  exit 1 unless defined $line && $line ne "";
185
186
  my $DataAggregate = $StaticData{config}{"$AppExt+data"};
187
  printf "# Data Aggregate : %s\n", $DataAggregate;
188
  my @Values = split " ", $DataAggregate;
189
  if ($#ARGV >= 0 && $ARGV[0] eq "config") {
190
    my @Keys = grep {$_ =~ /^$AppExt-/;} keys %{$StaticData{config}};
191
    foreach my $k (@Keys) {
192
      my $v = $StaticData{config}{$k};
193
      $k =~ s/^$AppExt-//;
194
      printf "%-16s %s\n", $k, $v;
195
    }
196
    printf "graph_order %s\n", (join " ", sort @Values);
197
    foreach my $k (@Values) {
198
      if (exists $Data{$k}) {
199
        my $label = $k;
200
        if (exists $StaticData{label}{$k}) {
201
          $label = $StaticData{label}{$k};
202
        }
203
        printf "%s.label %s\n", $k, $label;
204
        if (exists $StaticData{label}{"$k.info"}) {
205
          $label = $StaticData{label}{"$k.info"};
206
        }
207
        printf "%s.info %s\n", $k, $label;
208
        printf "%s.min 0\n", $k;
209
        printf "%s.type DERIVE\n", $k;
210
      }
211
    }
212
    exit 0;
213
  }
214
215
  if ($#ARGV < 0) {
216
    foreach my $k (@Values) {
217
      if (exists $Data{$k}) {
218
        printf "%s.value %s\n", $k, $Data{$k};
219
      }
220
    }
221
    exit 0;
222
  }
223
  exit 1;
224
}
225
226
# ------------------------------------------------
227
#
228
#
229
if (defined $AppExt && $AppType eq "ratio") {
230
  my %Data = ();
231
232
  my $line = GetStatsLine(\%Data);
233
  exit 1 unless defined $line && $line ne "";
234
235
  my $DataAggregate = $StaticData{config}{"$AppExt+data"};
236
  printf "# Data Aggregate : %s\n", $DataAggregate;
237
  my ($Ratios, $Base, undef) = split "/", $DataAggregate;
238
  exit 1 unless defined $Ratios && defined $Base;
239
240
  my @Values = split ",",    $Ratios;
241
  my @Den    = split "[ ]+", $Base;
242
243
  if ($#ARGV >= 0 && $ARGV[0] eq "config") {
244
    my @Keys = grep {$_ =~ /^$AppExt-/;} keys %{$StaticData{config}};
245
    foreach my $k (@Keys) {
246
      my $v = $StaticData{config}{$k};
247
      $k =~ s/^$AppExt-//;
248
      printf "%-16s %s\n", $k, $v;
249
    }
250
251
    my $nr = 0;
252
    printf "graph_order %s\n", (join " ", sort @Values);
253
    foreach my $num (@Values) {
254
      printf "# running for %s\n", $num;
255
      my @Num = split "[ ]+", $num;
256
257
      my $k = sprintf "%s%02d", $AppExt, $nr++;
258
      my $label = $k;
259
      if (exists $StaticData{label}{$k}) {
260
        $label = $StaticData{label}{$k};
261
      }
262
      printf "%s.label %s\n", $k, $label;
263
      if (exists $StaticData{label}{"$k.info"}) {
264
        $label = $StaticData{label}{"$k.info"};
265
      }
266
      printf "%s.info %s\n", $k, $label;
267
      printf "%s.min 0\n",   $k;
268
      printf "%s.max 100\n", $k;
269
      printf "%s.type GAUGE\n", $k;
270
    }
271
    exit 0;
272
  }
273
274
  if ($#ARGV < 0) {
275
    my %Old = ();
276
    my %Diff = ();
277
    if (EvalBoolean($StaticData{config}{"$AppExt+state"})) {
278
      ReadState(\%Old);
279
      %Diff = ();
280
      DiffFromState(\%Old, \%Data, \%Diff);
281
    } else {
282
      %Diff = %Data;
283
    }
284
    if ($debug) {
285
      foreach my $k (sort keys %Data) {
286
        printf "# DIFF %-16s %12d %12d %12d\n", $k, $Old{$k}, $Data{$k},
287
          $Diff{$k};
288
      }
289
    }
290
    my $nr = 0;
291
    foreach my $num (@Values) {
292
      printf "# running for %s\n", $num;
293
      my @Num = split "[ ]+", $num;
294
      my $n   = 0;
295
      my $d   = 0;
296
      foreach my $k (@Num) {
297
        if (exists $Diff{$k}) {
298
          $n += $Diff{$k};
299
        }
300
      }
301
      foreach my $k (@Den) {
302
        if (exists $Diff{$k}) {
303
          $d += $Diff{$k};
304
        }
305
      }
306
      my $k = sprintf "%s%02d", $AppExt, $nr++;
307
      printf "%s.value %s\n", $k, $d > 0 ? ((100. * $n) / $d) : 0;
308
    }
309
    if (EvalBoolean($StaticData{config}{"$AppExt+state"})) {
310
      SaveState(\%Data);
311
    }
312
    exit 0;
313
  }
314
  exit 1;
315
}
316
317
# ------------------------------------------------
318
#
319
#
320
if (defined $AppExt && $AppType eq "dbcounters") {
321
  my $DataAggregate = $StaticData{config}{"$AppExt+data"};
322
  printf "# Data Aggregate : %s\n", $DataAggregate;
323
  my @Values = split " ", $DataAggregate;
324
  if ($#ARGV >= 0 && $ARGV[0] eq "config") {
325
    my @Keys = grep {$_ =~ /^$AppExt-/;} keys %{$StaticData{config}};
326
    foreach my $k (@Keys) {
327
      my $v = $StaticData{config}{$k};
328
      $k =~ s/^$AppExt-//;
329
      printf "%-16s %s\n", $k, $v;
330
    }
331
    printf "graph_order %s\n", (join " ", sort @Values);
332
    foreach my $k (@Values) {
333
      if (1) {
334
        my $label = $k;
335
        if (exists $StaticData{label}{$k}) {
336
          $label = $StaticData{label}{$k};
337
        }
338
        printf "%s.label %s\n", $k, $label;
339
        if (exists $StaticData{label}{"$k.info"}) {
340
          $label = $StaticData{label}{"$k.info"};
341
        }
342
        printf "%s.info %s\n", $k, $label;
343
        printf "%s.type GAUGE\n", $k;
344
      }
345
    }
346
    exit 0;
347
  }
348
349
  if ($#ARGV < 0) {
350
    foreach my $k (@Values) {
351
      my $dbfile = "$WORKDIR/$k.db";
352
      $dbfile = "$CONSTDIR/$k.db" unless -f $dbfile;
353
      next unless -f $dbfile;
354
      my @DATA = `j-makemap -c -b $dbfile`;
355
      chomp @DATA;
356
      my $nrec = 0;
357
      foreach my $line (@DATA) {
358
        if ($line =~ /\s+(\d+)\s+records/) {
359
          $nrec = $1;
360
          printf "%s.value %s\n", $k, $nrec;
361
          last;
362
        }
363
      }
364
    }
365
    exit 0;
366
  }
367
  exit 1;
368
}
369
370
# ------------------------------------------------
371
#
372
#
373
sub GetStatsLine {
374
  my ($h, undef) = @_;
375
  return undef unless -f $FSTATS;
376
  my $line = `tail -1 $FSTATS`;
377
  return undef unless defined $line && $line ne "";
378
379
  my @Values = split / /, $line;
380
  my $time = time();
381
  if ($Values[0] =~ /^\d+$/) {
382
    $time = shift @Values;
383
  }
384
  $h->{timestamp} = $time;
385
  foreach my $lx (@Values) {
386
    $lx = lc $lx;
387
    if ($lx =~ /(\S+)=\((\d+)\)/) {
388
      $h->{$1} = $2;
389
    }
390
  }
391
  return $line;
392
}
393
394
# ------------------------------------------------
395
#
396
#
397
sub ReadState {
398
  my ($h, undef) = @_;
399
  return 0 unless defined $h;
400
401
  return 0 unless defined $StateFile && $StateFile ne "" && -f $StateFile;
402
403
  open FSTATE, "< $StateFile" || return 0;
404
  while (my $s = <FSTATE>) {
405
    chomp $s;
406
    next if $s =~ /^\s*$/;
407
    next if $s =~ /^\s*#/;
408
    my ($a, $b) = split " ", $s;
409
    $b = 0 unless defined $b;
410
    $h->{$a} = $b;
411
  }
412
  close FSTATE;
413
  {
414
    my %St = Munin::Plugin::restore_state();
415
    foreach my $k (sort keys %St) {
416
      printf "# %-20s %s\n", $k, $St{$k};
417
    }
418
  }
419
  return 1;
420
}
421
422
# ------------------------------------------------
423
#
424
#
425
sub SaveState {
426
  my ($h, undef) = @_;
427
428
  return 0 unless defined $StateFile && $StateFile ne "";
429
  my @ST = qw();
430
  open FSTATE, "> $StateFile" || return 0;
431
  foreach my $k (keys %{$h}) {
432
    push @ST, (sprintf "%s %s\n", $k, $h->{$k});
433
    printf FSTATE "%-20s %s\n", $k, $h->{$k};
434
  }
435
  close FSTATE;
436 17f78427 Lars Kruse
437 aa6e39ff Jose-Marcio Martins da Cruz
  Munin::Plugin::save_state(%$h);
438
  return 1;
439
}
440
441
# ------------------------------------------------
442
#
443
#
444
sub DiffFromState {
445
  my ($old, $new, $delta, undef) = @_;
446
  return 0 unless defined $old && defined $new;
447
  $delta = $new unless defined $delta;
448
449
  return 0 unless exists $old->{timestamp};
450
  return 0 unless exists $new->{timestamp};
451
  my $dt = $new->{timestamp} - $old->{timestamp};
452
  return 0 unless $dt > 1;
453
454
  $delta->{timestamp} = $new->{timestamp};
455
  foreach my $k (sort keys %{$new}) {
456
    next if $k eq "timestamp";
457
    if (exists $old->{$k}) {
458
      $delta->{$k} = $new->{$k} - $old->{$k};
459
      $delta->{$k} *= 300. / $dt;
460
    } else {
461
      $delta->{$k} = 0.;
462
    }
463
  }
464
  return 1;
465
}
466
467
# ------------------------------------------------
468
#
469
#
470
sub GetStaticData {
471
  my ($h, undef) = @_;
472
  my @DATA = <DATA>;
473
  my @SOPT = qw();
474
  chomp @DATA;
475
  my $in  = 0;
476
  my $key = "";
477
  foreach my $s (@DATA) {
478
    if ($key eq "") {
479
      if ($s =~ /==\s+BEGIN\s+(\S+)\s+==/) {
480
        $key = $1;
481
      }
482
      next;
483
    }
484
    if ($s =~ /==\s+END\s+(\S*\s+)?==/) {
485
      $key = "";
486
      next;
487
    }
488
    next if $s =~ /^\s*$/;
489
    push @{$h->{$key}{_data_}}, $s;
490
    my ($a, $b) = split " ", $s, 2;
491
    next unless defined $a && $a ne "";
492
    $b = "" unless defined $b;
493
    $h->{$key}{$a} = $b;
494
  }
495
}
496
497
# ------------------------------------------------
498
#
499
#
500
sub EvalBoolean {
501
  my ($v, undef) = @_;
502
503
  # return defined $v && $v =~ /^(1|yes|true|oui|vrai)$/i;
504
  if (defined $v) {
505
    return 1 if $v =~ /^(1|yes|true|oui|vrai)$/i;
506
  }
507
  return 0;
508
}
509
510
# ------------------------------------------------
511
#
512
#
513
__DATA__
514
515
== BEGIN label ==
516
conn                      Connections
517
conn.info                 SMTP Connections per time unit
518
msgs                      Messages
519 17f78427 Lars Kruse
msgs.info                 Messages per time unit
520 aa6e39ff Jose-Marcio Martins da Cruz
rcpt                      Recipients
521
rcpt.info                 Recipients per time unit
522
523
greymsgs                  Greylisted Messages
524
greymsgs.info             Greylisted Messages per time unit
525
greyrcpt                  Greylisted Recipients
526
greyrcpt.info             Greylisted Recipients per time unit
527
528
bayesham                  Legitimate (Stat Filter)
529
bayesham.info             Legitimate Messages - Statistical Filter
530
bayesspam                 Unwanted (Stat Filter)
531
bayesspam.info            Unwanted Messages - Statistical Filter
532
533
matching                  Pattern Matching
534
matching.info             Unwanted Messages - Pattern Matching Filter
535
urlbl                     URL Blacklist
536
urlbl.info                Unwanted Messages - URL Blacklist
537
538
throttle                  Connection Rate
539
throttle.info             Connections rejected by connection rate
540
badrcpt                   Bad Recipients
541
badrcpt.info              Connections rejected - excessive bad recipients
542
localuser                 Internal addresses
543
localuser.info            Messages sent to internal use only addresses
544
badmx                     Bad Sender MX
545
badmx.info                Messages rejected - Bad Sender MX
546
rcptrate                  Recipient Rate
547
rcptrate.info             Messages rejected by recipient rate
548
549
files                     Files
550
files.info                Files
551
xfiles                    X-Files
552
xfiles.info               X-Files
553
554
kbytes                    Volume (KBytes)
555
kbytes.info               Volume (KBytes) per time unit
556
557
j-greyvalid               Grey Validated records
558
j-greyvalid.info          Grey Validated records
559 17f78427 Lars Kruse
j-greypend                Grey Waiting records
560
j-greypend.info           Grey Waiting records
561 aa6e39ff Jose-Marcio Martins da Cruz
j-greywhitelist           Grey Whitelisted records
562
j-greywhitelist.info      Grey Whitelisted records
563
j-greyblacklist           j-greyblacklist
564
j-greyblacklist.info      j-greyblacklist
565
566
ratiospamham              Ratio Messages
567
ratiospamham.info         Ratio Messages
568
ratiospamham00            Legitimate messages
569
ratiospamham00.info       Legitimate messages
570
ratiospamham01            Unwanted messages
571
ratiospamham01.info       Unwanted messages
572
573
== END label ==
574
575
576
== BEGIN config ==
577
activity-graph_title        j-chkmail - Filter activity
578 212768ed dipohl
activity-graph_category     mail
579 aa6e39ff Jose-Marcio Martins da Cruz
activity-graph_vlabel       counts per second
580
activity-graph_scale        no
581
activity+data               conn msgs rcpt
582
activity+type               counters
583
activity+enable             yes
584
585
greylisting-graph_title     j-chkmail - Greylisting activity
586 212768ed dipohl
greylisting-graph_category  mail
587 aa6e39ff Jose-Marcio Martins da Cruz
greylisting-graph_vlabel    counts per second
588
greylisting-graph_scale     no
589
greylisting+data            greymsgs greyrcpt
590
greylisting+type            counters
591
greylisting+enable          yes
592
593
statfilter-graph_title      j-chkmail - Statistical classification
594 212768ed dipohl
statfilter-graph_category   mail
595 aa6e39ff Jose-Marcio Martins da Cruz
statfilter-graph_vlabel     counts per second
596
statfilter-graph_scale      no
597
statfilter+data             bayesham bayesspam
598
statfilter+type             counters
599
statfilter+enable           yes
600
601
contentfilter-graph_title      j-chkmail - Content Filtering
602 212768ed dipohl
contentfilter-graph_category   mail
603 aa6e39ff Jose-Marcio Martins da Cruz
contentfilter-graph_vlabel     counts per second
604
contentfilter-graph_scale      no
605
contentfilter+data             bayesspam matching urlbl
606
contentfilter+type             counters
607
contentfilter+enable           yes
608
609
behaviour-graph_title       j-chkmail - Behaviour filtering - rejections
610 212768ed dipohl
behaviour-graph_category    mail
611 aa6e39ff Jose-Marcio Martins da Cruz
behaviour-graph_vlabel      counts per second
612
behaviour-graph_scale       no
613
behaviour+data              throttle badrcpt localuser badmx rcptrate
614
behaviour+type              counters
615
behaviour+enable            yes
616
617
xfiles-graph_title          j-chkmail - Suspected files filtering
618 212768ed dipohl
xfiles-graph_category       mail
619 aa6e39ff Jose-Marcio Martins da Cruz
xfiles-graph_vlabel         counts per second
620
xfiles-graph_scale          no
621
xfiles+data                 files xfiles
622
xfiles+type                 counters
623
xfiles+enable               yes
624
625
volume-graph_title          j-chkmail - Volume handled by the filter
626 212768ed dipohl
volume-graph_category       mail
627 aa6e39ff Jose-Marcio Martins da Cruz
volume-graph_vlabel         KBytes per second
628
volume-graph_scale          no
629
volume+data                 kbytes
630
volume+type                 counters
631
volume+enable               yes
632
633
ratiospamham-graph_title       j-chkmail - Statistical classification
634 212768ed dipohl
ratiospamham-graph_category    mail
635 aa6e39ff Jose-Marcio Martins da Cruz
ratiospamham-graph_vlabel      Ratio (%)
636
ratiospamham-graph_scale       yes
637
ratiospamham-graph_args        --lower-limit 0 --upper-limit 100 --rigid
638
ratiospamham+data              bayesham, bayesspam / bayesham bayesspam
639
ratiospamham+type              ratio
640
ratiospamham+state             yes
641
ratiospamham+enable            yes
642
643
greydb-graph_title             j-chkmail - Greylisting Database Size
644 212768ed dipohl
greydb-graph_category          mail
645 aa6e39ff Jose-Marcio Martins da Cruz
greydb-graph_vlabel            records
646
greydb-graph_scale             no
647
greydb-graph_args              --lower-limit 0
648
greydb+data                    j-greypend j-greyvalid j-greywhitelist
649
greydb+type                    dbcounters
650
greydb+enable                  yes
651
652
cdb-graph_title                j-chkmail - Static databases
653 212768ed dipohl
cdb-graph_category             mail
654 aa6e39ff Jose-Marcio Martins da Cruz
cdb-graph_vlabel               records
655
cdb-graph_scale                no
656
cdb-graph_args                 --lower-limit 0
657
cdb+data                       j-policy j-urlbl j-bayes j-rcpt
658
cdb+type                       dbcounters
659
cdb+enable                     yes
660
661
== END config ==