File Coverage

blib/lib/Mail/MtPolicyd/Plugin/Fail2Ban.pm
Criterion Covered Total %
statement 9 22 40.9
branch 0 4 0.0
condition n/a
subroutine 3 5 60.0
pod 1 2 50.0
total 13 33 39.3


line stmt bran cond sub pod time code
1             package Mail::MtPolicyd::Plugin::Fail2Ban;
2              
3 1     1   1625 use Moose;
  1         3  
  1         10  
4 1     1   6672 use namespace::autoclean;
  1         5  
  1         12  
5              
6             our $VERSION = '1.23'; # VERSION
7             # ABSTRACT: mtpolicyd plugin to block an address with fail2ban
8              
9              
10             extends 'Mail::MtPolicyd::Plugin';
11             with 'Mail::MtPolicyd::Plugin::Role::UserConfig' => {
12             'uc_attributes' => [ 'enabled' ],
13             };
14              
15 1     1   117 use IO::Socket::UNIX;
  1         2  
  1         14  
16              
17             has 'enabled' => ( is => 'rw', isa => 'Str', default => 'on' );
18              
19             has 'socket' => ( is => 'ro', isa => 'Str', default => '/var/run/fail2ban/fail2ban.sock' );
20             has 'jail' => ( is => 'ro', isa => 'Str', default => 'postfix' );
21              
22             has '_socket' => ( is => 'ro', isa => 'IO::Socket::UNIX', lazy => 1,
23             default => sub {
24             my $self = shift;
25             my $socket = IO::Socket::UNIX->new(
26             Peer => $self->socket,
27             ) or die "cant connect fail2ban socket: $!";
28              
29             return( $socket );
30             },
31             );
32              
33             sub run {
34 0     0 1   my ( $self, $r ) = @_;
35 0           my $ip = $r->attr('client_address');
36 0           my $session = $r->session;
37              
38 0           my $enabled = $self->get_uc( $session, 'enabled' );
39 0 0         if( $enabled eq 'off' ) {
40 0           return;
41             }
42              
43 0 0         if( ! $r->is_already_done($self->name.'-fail2ban') ) {
44 0           $self->log( $r, 'adding ip '.$ip.' to fail2ban jail '.$self->jail );
45 0           $self->add_fail2ban( $r, $ip );
46             }
47              
48 0           return;
49             }
50              
51             # The protocol used is based in tickle, an python specific serialization protocol
52             # this command is captured from the output of:
53             # strace -s 1024 -f fail2ban-client set postfix banip 123.123.123.123
54             # ...
55             # sendto(3, "\200\2]q\0(U\3setq\1U\7postfixq\2U\5banipq\3U\017123.123.123.123q\4e.<F2B_END_COMMAND>", 71, 0, NU
56             has '_command_pattern' => (
57             is => 'ro', isa => 'Str',
58             default => "\200\2]q\0(U\3setq\1U%c%sq\2U\5banipq\3U%c%sq\4e.<F2B_END_COMMAND>",
59             );
60              
61             sub add_fail2ban {
62 0     0 0   my ( $self, $r, $ip ) = @_;
63              
64 0           $self->_socket->print(
65             sprintf($self->_command_pattern,
66             length($self->jail),
67             $self->jail,
68             length($ip),
69             $ip
70             )
71             );
72              
73 0           return;
74             }
75              
76             __PACKAGE__->meta->make_immutable;
77              
78             1;
79              
80             __END__
81              
82             =pod
83              
84             =encoding UTF-8
85              
86             =head1 NAME
87              
88             Mail::MtPolicyd::Plugin::Fail2Ban - mtpolicyd plugin to block an address with fail2ban
89              
90             =head1 VERSION
91              
92             version 1.23
93              
94             =head1 DESCRIPTION
95              
96             This plugin can be used to block an ip with iptable thru the fail2ban daemon.
97              
98             For more information abount fail2ban read:
99              
100             http://www.fail2ban.org/
101              
102             This plugin will directly talk to the daemon thru the unix domain socket and
103             execute an banip command:
104              
105             set <JAIL> banip <IP>
106              
107             =head1 PARAMETERS
108              
109             =over
110              
111             =item socket (default: /var/run/fail2ban/fail2ban.sock)
112              
113             Path to the fail2ban unix socket.
114              
115             Make sure mtpolicyd is allowed to write to this socket!
116              
117             =item jail (default: postfix)
118              
119             The jail in which the ip should be banned.
120              
121             =back
122              
123             =head1 EXAMPLE
124              
125             Execute a ban on all client-ips which send a mail with a score of >=15:
126              
127             <Plugin ScoreBan>
128             module = "ScoreAction"
129             threshold = 15
130             <Plugin ban-ip>
131             module = "Fail2Ban"
132             socket = "/var/run/fail2ban/fail2ban.sock"
133             jail = "postfix"
134             </Plugin>
135             </Plugin>
136              
137             =head1 FAIL2BAN CONFIGURATION
138              
139             To allow mtpolicyd to access fail2ban you must make sure fail2ban can write
140             to the fail2ban unix socket.
141              
142             chgrp mtpolicyd /var/run/fail2ban/fail2ban.sock
143             chmod g+rwx /var/run/fail2ban/fail2ban.sock
144              
145             You may want to add this to the fail2ban startup script.
146              
147             You may want to use the predefined postfix jail.
148             To activate it create /etc/fail2ban/jail.local and enable the postfix fail by
149             setting enabled=true.
150              
151             [postfix]
152             enabled = true
153              
154             =head1 AUTHOR
155              
156             Markus Benning <ich@markusbenning.de>
157              
158             =head1 COPYRIGHT AND LICENSE
159              
160             This software is Copyright (c) 2014 by Markus Benning <ich@markusbenning.de>.
161              
162             This is free software, licensed under:
163              
164             The GNU General Public License, Version 2, June 1991
165              
166             =cut