File Coverage

blib/lib/Search/ESsearcher/Templates/postfix.pm
Criterion Covered Total %
statement 8 12 66.6
branch n/a
condition n/a
subroutine 3 7 42.8
pod 0 4 0.0
total 11 23 47.8


line stmt bran cond sub pod time code
1             package Search::ESsearcher::Templates::postfix;
2              
3 1     1   68340 use 5.006;
  1         10  
4 1     1   5 use strict;
  1         2  
  1         19  
5 1     1   4 use warnings;
  1         2  
  1         521  
6              
7             =head1 NAME
8              
9             Search::ESsearcher::Templates::syslog - Provides postfix support for essearcher.
10              
11             =head1 VERSION
12              
13             Version 0.1.1
14              
15             =cut
16              
17             our $VERSION = '0.1.1';
18              
19             =head1 LOGSTASH
20              
21             This uses a logstash configuration below.
22              
23             input {
24             syslog {
25             host => "10.10.10.10"
26             port => 11514
27             type => "syslog"
28             }
29             }
30            
31             filter { }
32            
33             output {
34             if [type] == "syslog" {
35             elasticsearch {
36             hosts => [ "127.0.0.1:9200" ]
37             }
38             }
39             }
40              
41             The important bit is "type" being set to "syslog". If that is not used,
42             use the command line options field and fieldv.
43              
44             Install L<https://github.com/whyscream/postfix-grok-patterns> for pulling apart
45             the postfix messages. These files are included with this as well. You will likely
46             not want to use 51-filter-postfix-aggregate.conf as that is a bit buggy.
47              
48              
49             =head1 Options
50              
51             =head2 --host <log host>
52              
53             The syslog server.
54              
55             The search is done with .keyword appended to the field name.
56              
57             =head2 --hostx <log host>
58              
59             The syslog server.
60              
61             Does not run the it through aonHost.
62              
63             The search is done with .keyword appended to the field name.
64              
65             =head2 --src <src server>
66              
67             The source server sending to the syslog server.
68              
69             The search is done with .keyword appended to the field name.
70              
71             =head2 --srcx <src server>
72              
73             The source server sending to the syslog server.
74              
75             Does not run the it through aonHost.
76              
77             The search is done with .keyword appended to the field name.
78              
79             =head2 --size <count>
80              
81             The number of items to return.
82              
83             =head2 --pid <pid>
84              
85             The PID that sent the message.
86              
87             =head2 --dgt <date>
88              
89             Date greater than.
90              
91             =head2 --dgte <date>
92              
93             Date greater than or equal to.
94              
95             =head2 --dlt <date>
96              
97             Date less than.
98              
99             =head2 --dlte <date>
100              
101             Date less than or equal to.
102              
103             =head2 --msg <message>
104              
105             Messages to match.
106              
107             =head2 --field <field>
108              
109             The term field to use for matching them all.
110              
111             =head2 --fieldv <fieldv>
112              
113             The value of the term field to matching them all.
114              
115             =head2 --mid <msg id>
116              
117             Search based on the message ID.
118              
119             =head2 --from <address>
120              
121             The from address to search for.
122              
123             =head2 --to <address>
124              
125             The to address to search for.
126              
127             =head2 --oto <address>
128              
129             The original to address to search for.
130              
131             =head2 --noq
132              
133             Search for rejected messages, NOQUEUE.
134              
135             =head2 --ip <ip>
136              
137             The client IP to search for.
138              
139             =head2 --chost <host>
140              
141             The client hostname to search for.
142              
143             =head2 --status <status>
144              
145             Search using SMTP status codes.
146              
147             =head2 --nocountry
148              
149             Do not display the country code for the client IP.
150              
151             =head2 --noregion
152              
153             Do not display the region code for the client IP.
154              
155             =head2 --nocity
156              
157             Do not display the city name for the client IP.
158              
159             =head2 --nopostal
160              
161             Do not display the postal code for the client IP.
162              
163             =head2 --aliaswarn
164              
165             Show alias warnings.
166              
167             =head2 --showkeys
168              
169             Show the parsed out /postfix\_.*/ keys.
170              
171             =head2 --nomsg
172              
173             Do not show the message.
174              
175             =head2 --showprogram
176              
177             Show the syslog program name as well.
178              
179             =head2 --showpid
180              
181             Show the syslog PID as well.
182              
183             =head1 AND, OR, or NOT shortcut
184              
185             , OR
186             + AND
187             ! NOT
188              
189             A list seperated by any of those will be transformed
190              
191             These may be used with program, facility, pid, or host.
192              
193             example: --program postfix,spamd
194            
195             results: postfix OR spamd
196              
197             =head1 HOST AND, OR, or NOT shortcut
198              
199             , OR
200             + AND
201             ! NOT
202              
203             A list of hosts seperated by any of those will be transformed.
204             A host name should always end in a period unless it is a FQDN.
205              
206             These may be used with host and src.
207              
208             example: --src foo.,mail.bar.
209              
210             results: /foo./ OR /mail.bar./
211              
212             =head1 date
213              
214             date
215              
216             /^-/ appends "now" to it. So "-5m" becomes "now-5m".
217              
218             /^u\:/ takes what is after ":" and uses Time::ParseDate to convert it to a
219             unix time value.
220              
221             Any thing not matching maching any of the above will just be passed on.
222              
223             =cut
224              
225              
226             sub search{
227 0     0 0   return '
228             [% USE JSON ( pretty => 1 ) %]
229             [% DEFAULT o.program = "postfix" %]
230             [% DEFAULT o.facility = "mail" %]
231             [% DEFAULT o.size = "50" %]
232             [% DEFAULT o.field = "type" %]
233             [% DEFAULT o.fieldv = "syslog" %]
234             {
235             "index": "logstash-*",
236             "body": {
237             "size": [% o.size.json %],
238             "query": {
239             "bool": {
240             "must": [
241             {
242             "term": { [% o.field.json %]: [% o.fieldv.json %] }
243             },
244             [% IF o.host %]
245             {"query_string": {
246             "default_field": "host.keyword",
247             "query": [% aonHost( o.host ).json %]
248             }
249             },
250             [% END %]
251             [% IF o.hostx %]
252             {"query_string": {
253             "default_field": "host.keyword",
254             "query": [% o.hostx.json %]
255             }
256             },
257             [% END %]
258             [% IF o.src %]
259             {"query_string": {
260             "default_field": "logsource.keyword",
261             "query": [% aonHost( o.src ).json %]
262             }
263             },
264             [% END %]
265             [% IF o.srcx %]
266             {"query_string": {
267             "default_field": "logsource.keyword",
268             "query": [% o.srcx.json %]
269             }
270             },
271             [% END %]
272             {"query_string": {
273             "default_field": "program",
274             "query": [% aon( o.program ).json %]
275             }
276             },
277             {"query_string": {
278             "default_field": "facility_label",
279             "query": [% aon( o.facility ).json %]
280             }
281             },
282             [% IF o.pid %]
283             {"query_string": {
284             "default_field": "pid",
285             "query": [% aon( o.pid ).json %]
286             }
287             },
288             [% END %]
289             [% IF o.msg %]
290             {"query_string": {
291             "default_field": "message",
292             "query": [% o.msg.json %]
293             }
294             },
295             [% END %]
296             [% IF o.from %]
297             {"query_string": {
298             "default_field": "postfix_from",
299             "query": [% aon( o.from ).json %]
300             }
301             },
302             [% END %]
303             [% IF o.to %]
304             {"query_string": {
305             "default_field": "postfix_to",
306             "query": [% aon( o.to ).json %]
307             }
308             },
309             [% END %]
310             [% IF o.oto %]
311             {"query_string": {
312             "default_field": "postfix_orig_to",
313             "query": [% aon( o.oto ).json %]
314             }
315             },
316             [% END %]
317             [% IF o.mid %]
318             {"query_string": {
319             "default_field": "postfix_message-id",
320             "query": [% aon( o.mid ).json %]
321             }
322             },
323             [% END %]
324             [% IF o.qid %]
325             {"query_string": {
326             "default_field": "postfix_queueid",
327             "query": [% aon( o.qid ).json %]
328             }
329             },
330             [% END %]
331             [% IF o.ip %]
332             {"query_string": {
333             "default_field": "postfix_client_ip",
334             "query": [% aon( o.ip ).json %]
335             }
336             },
337             [% END %]
338             [% IF o.chost %]
339             {"query_string": {
340             "default_field": "postfix_client_hostname",
341             "query": [% aon( o.chost ).json %]
342             }
343             },
344             [% END %]
345             [% IF o.status %]
346             {"query_string": {
347             "default_field": "postfix_status_code",
348             "query": [% aon( o.status ).json %]
349             }
350             },
351             [% END %]
352             [% IF ! o.aliaswarn %]
353             {"query_string": {
354             "default_field": "message",
355             "query": "NOT \"is older than source file\""
356             }
357             },
358             [% END %]
359             [% IF o.noq %]
360             {"query_string": {
361             "default_field": "message",
362             "query": "NOQUEUE"
363             }
364             },
365             [% END %]
366             [% IF o.dgt %]
367             {"range": {
368             "@timestamp": {
369             "gt": [% pd( o.dgt ).json %]
370             }
371             }
372             },
373             [% END %]
374             [% IF o.dgte %]
375             {"range": {
376             "@timestamp": {
377             "gte": [% pd( o.dgte ).json %]
378             }
379             }
380             },
381             [% END %]
382             [% IF o.dlt %]
383             {"range": {
384             "@timestamp": {
385             "lt": [% pd( o.dlt ).json %]
386             }
387             }
388             },
389             [% END %]
390             [% IF o.dlte %]
391             {"range": {
392             "@timestamp": {
393             "lte": [% pd( o.dlte ).json %]
394             }
395             }
396             },
397             [% END %]
398             ]
399             }
400             },
401             "sort": [
402             {
403             "@timestamp": {"order" : "desc"}}
404             ]
405             }
406             }
407             ';
408             }
409              
410             sub options{
411 0     0 0   return '
412             host=s
413             src=s
414             hostx=s
415             srcx=s
416             size=s
417             showpid
418             mid=s
419             showprogram
420             showpid
421             nocountry
422             noregion
423             nocity
424             nopostal
425             aliaswarn
426             from=s
427             to=s
428             oto=s
429             ip=s
430             status=s
431             chost=s
432             pid=s
433             dgt=s
434             dgte=s
435             dlt=s
436             dlte=s
437             msg=s
438             pid=s
439             field=s
440             fieldv=s
441             showkeys
442             nomsg
443             noq
444             qid=s
445             ';
446             }
447              
448             sub output{
449 0     0 0   return '[% c("cyan") %][% f.timestamp %] [% c("bright_blue") %][% f.logsource %]'.
450              
451             '[% IF o.showprogram %]'.
452             ' [% c("bright_green") %][% f.program %]'.
453             '[% END %]'.
454              
455             '[% IF o.showpid %]'.
456             ' [% c("bright_magenta") %][[% c("bright_yellow") %][% f.pid %][% c("bright_magenta") %]]'.
457             '[% END %]'.
458            
459             '[% IF ! o.nocountry %]'.
460             '[% IF f.geoip.country_code2 %]'.
461             ' [% c("yellow") %]('.
462             '[% c("bright_green") %][% f.geoip.country_code2 %]'.
463             '[% c("yellow") %])'.
464             '[% END %]'.
465             '[% END %]'.
466              
467             '[% IF ! o.region %]'.
468             '[% IF f.geoip.region_code %]'.
469             ' [% c("yellow") %]('.
470             '[% c("bright_green") %][% f.geoip.region_code %]'.
471             '[% c("yellow") %])'.
472             '[% END %]'.
473             '[% END %]'.
474              
475             '[% IF ! o.nocity %]'.
476             '[% IF f.geoip.city_name %]'.
477             ' [% c("yellow") %]('.
478             '[% c("bright_green") %][% f.geoip.city_name %]'.
479             '[% c("yellow") %])'.
480             '[% END %]'.
481             '[% END %]'.
482              
483             '[% IF ! o.nopostal %]'.
484             '[% IF f.geoip.postal_code %]'.
485             ' [% c("yellow") %]('.
486             '[% c("bright_green") %][% f.geoip.postal_code %]'.
487             '[% c("yellow") %])'.
488             '[% END %]'.
489             '[% END %]'.
490              
491             ' '.
492             '[% PERL %]'.
493             'use Term::ANSIColor;'.
494             'my $f=$stash->get("f");'.
495             'if (defined( $f->{postfix_queueid} ) ){'.
496             ' print color("bright_magenta").$f->{postfix_queueid};'.
497             ' my $qid=$f->{postfix_queueid};'.
498             ' delete($f->{postfix_queueid});'.
499             ' $f->{message}=~s/^$qid\://;'.
500             ' $stash->set("f", $f);'.
501             '}'.
502             '[% END %]'.
503            
504             '[% IF o.showkeys %]'.
505              
506             '[% PERL %]'.
507             'use Term::ANSIColor;'.
508             'my $f=$stash->get("f");'.
509             'my @pkeys=grep(/^postfix/, keys( %{$f} ) );'.
510             'if (defined( $f->{postfix_queueid} ) ){'.
511             ' delete($f->{postfix_queueid})'.
512             '}'.
513             'foreach my $pkey (@pkeys){'.
514             ' my $name=$pkey;'.
515             ' $name=~s/^postfix\_//;'.
516             ' if (defined( $f->{$pkey} ) ){'.
517             ' print " ".color("bright_cyan").$name.color("bright_yellow")."=".color("bright_green").$f->{$pkey};'.
518             ' }'.
519             '}'.
520             'print " "'.
521             '[% END %]'.
522             '[% END %]'.
523              
524             '[% IF ! o.nomsg %]'.
525             '[% PERL %]'.
526             'use Term::ANSIColor;'.
527             'my $f=$stash->get("f");'.
528              
529             'my $msg=color("white").$f->{message};'.
530              
531             'my $replace=color("cyan")."<".color("bright_magenta");'.
532             '$msg=~s/\</$replace/g;'.
533             '$replace=color("cyan").">".color("white");'.
534             '$msg=~s/\>/$replace/g;'.
535              
536             '$replace=color("bright_green")."(".color("cyan");'.
537             '$msg=~s/\(/$replace/g;'.
538             '$replace=color("bright_green").")".color("white");'.
539             '$msg=~s/\)/$replace/g;'.
540              
541             'my $green=color("bright_green");'.
542             'my $white=color("white");'.
543             'my $yellow=color("bright_yellow");'.
544             '$msg=~s/([A-Za-z\_\-]+)\=/$green$1$yellow=$white/g;'.
545              
546             'my $blue=color("bright_blue");'.
547             '$msg=~s/([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/$blue$1$white/g;'.
548            
549             '$replace=color("bright_red")."NOQUEUE".color("white");'.
550             '$msg=~s/NOQUEUE/$replace/g;'.
551              
552             '$replace=color("bright_red")."failed".color("white");'.
553             '$msg=~s/failed/$replace/g;'.
554              
555             '$replace=color("bright_red")."warning".color("white");'.
556             '$msg=~s/warning/$replace/g;'.
557              
558             '$replace=color("bright_red")."disconnect from".color("white");'.
559             '$msg=~s/disconnect\ from/$replace/g;'.
560              
561             '$replace=color("bright_red")."connect from".color("white");'.
562             '$msg=~s/connect\ from/$replace/g;'.
563              
564             '$replace=color("bright_red")."SASL LOGIN".color("white");'.
565             '$msg=~s/SASL LOGIN/$replace/g;'.
566              
567             '$replace=color("bright_red")."authentication".color("white");'.
568             '$msg=~s/authentication/$replace/g;'.
569              
570             '$replace=color("bright_red")."blocked using".color("white");'.
571             '$msg=~s/blocked using/$replace/g;'.
572              
573             '$replace=color("bright_red")."Service unavailable".color("white");'.
574             '$msg=~s/Service unavailable/$replace/g;'.
575            
576             'print $msg;'.
577             '[% END %]'.
578             '[% END %]'
579             ;
580             }
581              
582             sub help{
583 0     0 0   return '
584              
585             --host <log host> The syslog server.
586             --hostx <log host> The syslog server. This is passed raw.
587             --src <src server> The source server sending to the syslog server.
588             --srcx <src server> The source server sending to the syslog server. This is passed raw.
589             --size <count> The number of items to return.
590             --pid <pid> The PID that sent the message.
591              
592             --mid <msg id> Search based on the message ID.
593             --qid <queue id> Search based on the queue ID.
594             --from <address> The from address to search for.
595             --to <address> The to address to search for.
596             --oto <address> The original to address to search for.
597             --noq Search for rejected messages, NOQUEUE.
598             --ip <ip> The client IP to search for.
599             --chost <host> The client hostname to search for.
600             --status <status> Search using SMTP status codes.
601              
602             --nocountry Do not display the country code for the client IP.
603             --noregion Do not display the region code for the client IP.
604             --nocity Do not display the city name for the client IP.
605             --nopostal Do not display the postal code for the client IP.
606              
607             --aliaswarn Show alias warnings.
608              
609             --showkeys Show the parsed out /postfix\_.*/ keys.
610             --nomsg Do not show the message.
611              
612             --showprogram Show the syslog program name as well.
613             --showpid Show the syslog PID as well.
614              
615             --dgt <date> Date greater than.
616             --dgte <date> Date greater than or equal to.
617             --dlt <date> Date less than.
618             --dlte <date> Date less than or equal to.
619              
620             --msg <message> Messages to match.
621              
622             --field <field> The term field to use for matching them all.
623             --fieldv <fieldv> The value of the term field to matching them all.
624              
625              
626              
627             AND, OR, or NOT shortcut
628             , OR
629             + AND
630             ! NOT
631              
632             A list seperated by any of those will be transformed
633              
634             These may be used with program, facility, pid, or host.
635              
636             example: --program postfix,spamd
637              
638              
639              
640             HOST AND, OR, or NOT shortcut
641             , OR
642             + AND
643             ! NOT
644              
645             A list of hosts seperated by any of those will be transformed.
646             A host name should always end in a period unless it is a FQDN.
647              
648             These may be used with host and src.
649              
650             example: --src foo.,mail.bar.
651              
652             results: /foo./ OR /mail.bar./
653              
654              
655              
656             field and fieldv
657              
658             The search template is written with the expectation that logstash is setting
659             "type" with a value of "syslog". If you are using like "tag" instead of "type"
660             or the like, this allows you to change the field and value.
661              
662              
663              
664             date
665              
666             /^-/ appends "now" to it. So "-5m" becomes "now-5m".
667              
668             /^u\:/ takes what is after ":" and uses Time::ParseDate to convert it to a
669             unix time value.
670              
671             Any thing not matching maching any of the above will just be passed on.
672             ';
673              
674              
675             }