diff --git a/README.md b/README.md index c5c9ac8..80a8eab 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,14 @@ # fail2ban-report Fail2ban report + +Example : + +Extract fail2ban logs in log.csv : + +./fail2ban-getlog log.csv + +Generate report.pdf from log.csv data using GeoLite2-Country.mmdb database : + +./fail2ban-report log.csv GeoLite2-Country.mmdb report.pdf + +You can download GeoLite2-Country database here : diff --git a/fail2ban-getlog b/fail2ban-getlog new file mode 100755 index 0000000..fc8aed4 --- /dev/null +++ b/fail2ban-getlog @@ -0,0 +1,30 @@ +#!/usr/bin/python3 +# coding: utf-8 +# Julien Pecqueur + +from sys import argv + +if len(argv) != 2: + print("Usage: fail2ban-getlog ") + print("Extract fail2ban logs to CSV file.") +else: + F_LOG = "/var/log/fail2ban.log" + f_old = open(argv[1], "r") + old = [] + for l in f_old: + old.append(l[0:-1]) + f_old.close() + print(len(old), "existing line(s).") + f_in = open(F_LOG, "r") + f_out = open(argv[1], "a+") + c = 0 + for l in f_in: + l = l[0:-1].split(" ") + if "Ban" in l: + l = l[-1]+";"+l[0]+";"+l[1][0:-4] + if not l in old: + f_out.write(l+"\n") + c += 1 + f_in.close() + f_out.close() + print("Added", c, "new line(s).") diff --git a/fail2ban-report b/fail2ban-report new file mode 100755 index 0000000..80efb40 --- /dev/null +++ b/fail2ban-report @@ -0,0 +1,82 @@ +#!/usr/bin/python3 +# coding: utf-8 +# Julien Pecqueur + +import pandas as pd +import matplotlib +matplotlib.use('Agg') +import geoip2.database +from matplotlib.backends.backend_pdf import PdfPages +from sys import argv + + +def load_file(file): + data = [] + f = open(file) + for l in f: + ip, date, time = l.split(";") + data.append([ip, date]) + return(data) + +def get_nb_ban_by_date(data): + d = {} + for ip, date in data: + if date in d.keys(): + d[date] += 1 + else: + d[date] = 1 + return(d) + +def get_nb_ban_by_ip(data): + d = {} + for ip, date in data: + if ip in d.keys(): + d[ip] += 1 + else: + d[ip] = 1 + return(d) + +def get_nb_ban_by_country(data, f_country): + reader = geoip2.database.Reader(f_country) + d = {} + for ip, date in data: + response = reader.country(ip) + country = response.country.name + if country in d.keys(): + d[country] += 1 + else: + d[country] = 1 + reader.close() + return(d) + +def generate_report(f_log, f_country, f_pdf): + + data = load_file(f_log) + + pp = PdfPages(f_pdf) + + nb_ban_by_date = get_nb_ban_by_date(data) + df = pd.DataFrame.from_dict(nb_ban_by_date, orient='index').rename(columns={0:"Bans"}).sort_index() + plot = df.plot(title="Bans by date", figsize=(10.0,4.0)) + fig = plot.get_figure() + fig.savefig(pp, format='pdf') + + nb_ban_by_country = get_nb_ban_by_country(data, f_country) + df = pd.DataFrame.from_dict(nb_ban_by_country, orient='index').rename(columns={0:"Bans"}).sort_values(by='Bans', ascending=True) #.query('Bans > 1') + plot = df.plot(title="Bans by country", kind='pie', subplots=True, legend=False, figsize=(10.0,10.0)) + fig = plot[0].get_figure() + fig.savefig(pp, format='pdf') + + nb_ban_by_ip = get_nb_ban_by_ip(data) + df = pd.DataFrame.from_dict(nb_ban_by_ip, orient='index').rename(columns={0:"Bans"}).sort_values(by='Bans', ascending=True) #.query('Bans > 1') + plot = df.plot(title="Bans by IP", kind='pie', legend=False, subplots=True, figsize=(10.0,10.0)) + fig = plot[0].get_figure() + fig.savefig(pp, format='pdf') + + pp.close() + +if len(argv) != 4: + print("Usage: fail2ban-report ") + print("Compute fail2ban CSV file and generate PDF report.") +else: + generate_report(argv[1], argv[2], argv[3]) diff --git a/log.csv b/log.csv new file mode 100644 index 0000000..037f7e2 --- /dev/null +++ b/log.csv @@ -0,0 +1,40 @@ +61.41.4.26;2017-08-22;06:33:24 +61.41.4.26;2017-08-22;06:45:13 +61.41.4.26;2017-08-22;06:57:36 +91.197.232.109;2017-08-22;07:03:14 +61.41.4.26;2017-08-22;07:09:54 +61.41.4.26;2017-08-22;07:22:57 +61.41.4.26;2017-08-22;07:34:47 +61.41.4.26;2017-08-22;07:46:39 +61.41.4.26;2017-08-22;07:58:55 +61.41.4.26;2017-08-22;08:10:52 +61.41.4.26;2017-08-22;08:22:44 +61.41.4.26;2017-08-22;08:34:33 +61.41.4.26;2017-08-22;08:46:44 +61.41.4.26;2017-08-22;08:58:43 +61.41.4.26;2017-08-22;09:10:45 +61.41.4.26;2017-08-22;09:22:26 +61.41.4.26;2017-08-22;09:34:24 +61.41.4.26;2017-08-22;09:46:37 +61.41.4.26;2017-08-22;09:59:33 +61.41.4.26;2017-08-22;10:11:24 +61.41.4.26;2017-08-22;10:23:16 +103.89.88.102;2017-08-22;15:00:57 +103.89.88.102;2017-08-23;00:45:33 +103.89.88.102;2017-08-23;00:56:12 +91.197.232.109;2017-08-23;04:07:52 +91.197.232.107;2017-08-23;11:03:01 +91.197.232.109;2017-08-23;11:41:29 +103.89.88.102;2017-08-23;16:01:43 +195.154.63.133;2017-08-23;20:26:55 +91.197.232.109;2017-08-23;23:50:12 +103.89.88.102;2017-08-24;02:44:35 +195.154.63.133;2017-08-24;03:32:24 +62.210.24.228;2017-08-24;10:57:14 +103.89.88.102;2017-08-24;12:38:36 +103.89.88.102;2017-08-24;21:20:16 +91.197.232.109;2017-08-24;23:56:20 +103.207.38.211;2017-08-25;01:19:37 +193.201.224.214;2017-08-25;02:26:16 +103.89.88.102;2017-08-25;03:27:00 +91.197.232.109;2017-08-25;03:43:36 diff --git a/report.pdf b/report.pdf new file mode 100644 index 0000000..ca6ced7 Binary files /dev/null and b/report.pdf differ