]> Raphaƫl G. Git Repositories - tools/blob - blacklist
Add new_ipv4 constructor that build NetAddr::IP object
[tools] / blacklist
1 #! /usr/bin/perl
2
3 use strict;
4 use warnings;
5
6 use IPC::System::Simple qw(capturex);
7 use Data::Validate::IP qw(is_ipv4 is_ipv6);
8 use NetAddr::IP::Util qw(shiftleft inet_4map6 ipv4to6);
9 use NetAddr::IP qw(:nofqdn Ones);
10
11 #IP v4 hash
12 my %ip4s = ();
13 #IP v6 hash
14 my %ip6s = ();
15 #Blacklist v4 array
16 my @blrule4s = ();
17 #Blacklist v6 array
18 my @blrule6s = ();
19
20 #IP whitelist
21 #my $iplist = qr/^(?:127\.|::1|2a01:4f8:190:22a6:|5\.9\.143\.173|85\.68\.|81\.67\.|89\.157\.|82\.241\.255\.46)/;
22 my %iplist = (
23 ipv4 => [
24 # Localhost
25 '127.0.0.0/8',
26 # Aurae
27 '144.76.27.210/32',
28 # Toulouse
29 '82.241.255.46/32',
30 # Akasha
31 '89.3.145.115/32'
32 ],
33 ipv6 => [
34 # Localhost
35 '::1/32',
36 # Aurae
37 '2a01:4f8:191:1405::/64'
38 ]
39 );
40
41 #Create a new NetAddr::IP object without calling slow gethostbyname (load /etc/resolv.conf)
42 sub new_ipv4($) {
43 #Extract ip and mask
44 my ($ip, $mask) = split('/', shift);
45 #Build base struct
46 my $self = {
47 #Set mask
48 mask => !defined($mask)||$mask==32?Ones:shiftleft(Ones, 32 - $mask),
49 #Mark as ipv4
50 isv6 => 0,
51 #Generate fake address
52 #XXX: NetAddr::IP expect a faked Socket6 gethostbyname struct
53 #XXX: see /usr/lib64/perl5/vendor_perl/NetAddr/IP/Util.pm +235
54 #addr => scalar ($ip, '', AF_INET, 16, NetAddr::IP::Util::inet_4map6(NetAddr::IP::Util::ipv4to6(pack('C4', split('\.', $ip)))))
55 addr => inet_4map6(ipv4to6(pack('C4', split('\.', $ip))))
56 };
57 #Return fake NetAddr::IP object
58 return bless $self, 'NetAddr::IP';
59 }
60
61 #User whitelist
62 my @userlist = ('rapsys');
63
64 #Extract sshd.service scan
65 #map {
66 # # Extract user and ip
67 # if (/Failed password for (?:invalid user )?(.+) from (.+) port [0-9]+ ssh2/ && grep($_ ne $1, @userlist)) {
68 # # Save ip
69 # my $ip = $2;
70 # # Check if v4 ip and not in whitelist
71 # if (is_ipv4($ip) && not scalar map { my $network = NetAddr::IP->new($_); my $netip = NetAddr::IP->new($ip); unless ($network->contains($netip)) { (); } } @{$iplist{ipv4}}) {
72 # # Add ip in v4 blacklist
73 # $ip4s{$ip}=1;
74 # # Check if v6 ip
75 # } elsif (is_ipv6($ip) && not scalar map { my $network = NetAddr::IP->new($_); my $netip = NetAddr::IP->new($ip); unless ($network->contains($netip)) { (); } } @{$iplist{ipv6}}) {
76 # $ip6s{$ip}=1;
77 # }
78 # }
79 #} capturex('journalctl', '-u', 'sshd.service');
80
81 #Extract kernel port scan
82 map {
83 #oct. 04 19:10:30 aurae.aoihime.eu kernel: net-fw DROP IN=enp3s0 OUT= MAC=50:46:5d:a1:a1:85:0c:86:10:f5:c6:4b:08:00 SRC=61.227.52.153 DST=144.76.27.210 LEN=52 TOS=0x00 PREC=0x00 TTL=116 ID=29123 DF PROTO=TCP SPT=64349 DPT=445 WINDOW=8192 RES=0x00 SYN URGP=0
84 if (/kernel: net-fw DROP .* SRC=([^\s]+) .* PROTO=([^\s]+) .* DPT=([^\s]+)/) {
85 # Save ip
86 my $ip = $1;
87 # Save proto
88 my $proto = lc($2);
89 # Save dpt
90 my $dpt = $3;
91 # Check if v4 ip and not in whitelist
92 if (is_ipv4($ip) && not scalar map { my $network = new_ipv4($_); my $netip = new_ipv4($ip); unless ($network->contains($netip)) { (); } } @{$iplist{ipv4}}) {
93 if (!defined $ip4s{$ip}) {
94 %{$ip4s{$ip}} = ('tcp' => {}, 'udp' => {});
95 }
96 $ip4s{$ip}{$proto}{$dpt}=1;
97 } elsif (is_ipv6($ip) && not scalar map { my $network = NetAddr::IP->new($_); my $netip = NetAddr::IP->new($ip); unless ($network->contains($netip)) { (); } } @{$iplist{ipv6}}) {
98 if (!defined $ip6s{$ip}) {
99 %{$ip6s{$ip}} = ('tcp' => {}, 'udp' => {});
100 }
101 $ip6s{$ip}{$proto}{$dpt}=1;
102 }
103 print $ip."\n";
104 #oct. 04 19:17:10 aurae.aoihime.eu kernel: audit: type=1100 audit(1570209430.543:17321294): pid=5890 uid=0 auid=4294967295 ses=4294967295 msg='op=PAM:authentication grantors=? acct="root" exe="/usr/sbin/sshd" hostname=195.154.112.70 addr=195.154.112.70 terminal=ssh res=failed'
105 } elsif (/op=PAM:authentication grantors=\? acct="(.+)" exe="\/usr\/(?:libexec\/dovecot\/auth|sbin\/sshd)" hostname=.+ addr=(.+) terminal=(dovecot|ssh) res=failed/ && grep($_ ne $1, @userlist)) {
106 # Save ip
107 my $ip = $2;
108 # Save proto
109 my $proto = 'tcp';
110 # Save dpt
111 my $dpt = $3 eq 'ssh' ? 22 : 445;
112 # Check if v4 ip and not in whitelist
113 if (is_ipv4($ip) && not scalar map { my $network = new_ipv4($_); my $netip = new_ipv4($ip); unless ($network->contains($netip)) { (); } } @{$iplist{ipv4}}) {
114 if (!defined $ip4s{$ip}) {
115 %{$ip4s{$ip}} = ('tcp' => {}, 'udp' => {});
116 }
117 # Add ip in v4 blacklist
118 $ip4s{$ip}{$proto}{$dpt}=1;
119 # Check if v6 ip
120 } elsif (is_ipv6($ip) && not scalar map { my $network = NetAddr::IP->new($_); my $netip = NetAddr::IP->new($ip); unless ($network->contains($netip)) { (); } } @{$iplist{ipv6}}) {
121 if (!defined $ip6s{$ip}) {
122 %{$ip6s{$ip}} = ('tcp' => {}, 'udp' => {});
123 }
124 $ip6s{$ip}{$proto}{$dpt}=1;
125 }
126 #nov. 30 15:30:07 aurae.aoihime.eu kernel: audit: type=1100 audit(1575124207.371:38129): pid=685 uid=985 auid=4294967295 ses=4294967295 msg='op=PAM:authentication grantors=? acct="toto" exe="/usr/bin/pwauth" hostname=? addr=? terminal=? res=failed'
127 #XXX: Until mod_authnz pass to pwauth the (SERVER_NAME|SERVER_ADDR) + REMOTE_ADDR+REMOTE_PORT in env it's impossible to know who did a failed auth
128 #XXX: see https://github.com/phokz/mod-auth-external/blob/master/mod_authnz_external/TODO
129 #} elsif (/op=PAM:authentication grantors=\? acct="(.+)" exe="\/usr\/bin\/pwauth" hostname=.+ addr=(.+) terminal=\? res=failed/ && grep($_ ne $1, @userlist)) {
130 # ...
131 }
132 } capturex('journalctl', '-m', '-t', 'kernel', '-o', 'cat', '--no-hostname');
133
134 #Process each ipv4s keys
135 map {
136 #Set proto as either tcp or udp
137 for my $proto (('tcp', 'udp')) {
138 #Check if branch is empty
139 if (!scalar keys %{$ip4s{$_}{$proto}}) {
140 #Prune it
141 delete $ip4s{$_}{$proto};
142 }
143 }
144 } keys %ip4s;
145
146 #Process each ipv6s keys
147 map {
148 #Set proto as either tcp or udp
149 for my $proto (('tcp', 'udp')) {
150 #Check if branch is empty
151 if (!scalar keys %{$ip6s{$_}{$proto}}) {
152 #Prune it
153 delete $ip6s{$_}{$proto};
154 }
155 }
156 } keys %ip6s;
157
158 #Open blrule4s file for reading
159 open (my $fh, '<', '/etc/shorewall/blrules') or die "Can't open < /etc/shorewall/blrules: $!";
160
161 #Populate with comments
162 @blrule4s = map { chomp($_); if (/^#/) { $_; } else { (); } } <$fh>;
163
164 #Prepend each specific ip from whitelist
165 map { push @blrule4s, "WHITELIST\tnet:$1\tall" if (/^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\/32$/); } @{$iplist{ipv4}};
166
167
168 #Build blacklist
169 map {
170 #Set proto from hash
171 for my $proto (keys %{$ip4s{$_}}) {
172 #Push rule
173 push @blrule4s, "DROP\t\tnet:".$_.(length($_)<12?"\t":'')."\tfw\t$proto\t".(scalar keys %{$ip4s{$_}{$proto}}>5||defined $ip4s{$_}{$proto}{0}?'#':'').join(",", keys %{$ip4s{$_}{$proto}});
174 }
175 } sort keys %ip4s;
176
177 #Close blrule4s file
178 close $fh or die "Can't close fh: $!";
179
180 #Open blrule4s file for writing
181 open ($fh, '>', '/etc/shorewall/blrules') or die "Can't open > /etc/shorewall/blrules: $!";
182
183 #Inject content of blacklist
184 map { print $fh $_."\n"; } @blrule4s;
185
186 #Close blrule4s file
187 close $fh or die "Can't close fh: $!";
188
189 #Print ipv6 to update hash
190 #XXX; right now it don't seems scanned at all...
191 for (sort keys %ip6s) {
192 #Set proto from hash
193 for my $proto (keys %{$ip6s{$_}}) {
194 #Print the ipv6 scanner
195 print $_."\t$proto\t".join(",", keys %{$ip6s{$_}{$proto}})."\n";
196 }
197 }
198
199 # Restart shorewall service
200 capturex('systemctl', 'restart', 'shorewall.service');