Created
June 21, 2016 15:50
-
-
Save avaccari/4608831f4a268cf337f8d9339ba372c7 to your computer and use it in GitHub Desktop.
Python server side script that uses Google maps API to generate map of a set of IPs stored as lines within a file and plots origin statistic
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# A script to graph the statistics of a set of IP blacklists generated by your favorite | |
# firewall program as long as the lists consist of a series of IP addresses one for each | |
# line. | |
import re | |
import sys | |
import json | |
import urllib2 | |
import socket | |
import pygeoip | |
import cStringIO | |
from os import chdir | |
from glob import glob | |
from random import randint | |
from collections import Counter | |
import numpy as np | |
import matplotlib | |
matplotlib.use('Agg') | |
import matplotlib.pyplot as plt | |
# The geoip data comes from here and should be updated once every so often: | |
# | |
# wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz | |
# | |
# gunzip GeoLiteCity.dat.gz | |
GEO_DATASET = 'GeoLiteCity.dat' | |
data = pygeoip.GeoIP(GEO_DATASET) | |
GEO_API = 'http://freegeoip.net/json/' | |
timeout = 1 | |
# Blacklists should be list of IP addresses one for each line. | |
BLACKLIST_DIR = '/etc/fail2ban/' # Location of blecklists | |
BLACKLIST_FILES = '*.blacklist' # Regular expression identifying blacklists name | |
chdir(BLACKLIST_DIR) | |
files = glob(BLACKLIST_FILES) | |
n_files = len(files) | |
coo = dict() | |
tot = dict() | |
grfd = dict() | |
ip_r = [] | |
def lookup_ip(ip): | |
serv = None | |
iplat = 0.0 | |
iplng = 0.0 | |
ipcty = '' | |
iploc = data.record_by_addr(ip) | |
if iploc is not None: | |
iplat = iploc['latitude'] | |
iplng = iploc['longitude'] | |
ipcty = iploc['country_name'] | |
serv = 0 | |
else: | |
qry = GEO_API + str(ip) | |
try: | |
j = json.loads(urllib2.urlopen(qry, timeout=timeout).read()) | |
except (urllib2.URLError, socket.timeout): | |
j = dict() | |
j['country_code'] = 'RD' | |
if j['country_code'] != 'RD': | |
iplat = j['latitude'] | |
iplng = j['longitude'] | |
ipcty = j['country_name'] | |
serv = 1 | |
return (serv, iplat, iplng, ip, ipcty) | |
for fl in files: | |
coo[fl] = [] | |
tot[fl] = 0 | |
grfd[fl] = 0 | |
for ip in open(fl, 'rb').readlines(): | |
ip_r.append(ip) | |
tot[fl] = tot[fl] + 1 | |
res = lookup_ip(ip[:-1]) | |
if res[0] is not None: | |
coo[fl].append(res[1:]) | |
grfd[fl] += res[0] | |
print "Content-Type: text/html" | |
print """ | |
<html> | |
<head> | |
<title>Attacks map</title> | |
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" /> | |
<style type="text/css"> | |
html { height: 100% } | |
body { height: 100%; | |
margin: 0; | |
padding: 0 } | |
div#map-canvas { width: 85%; | |
height: 85% } | |
div#plot-canvas { width: 85%; | |
border: 1px solid} | |
div#plot-canvas img { width: 33%; | |
vertical-align: top} | |
</style> | |
<script type="text/javascript" | |
src="http://maps.googleapis.com/maps/api/js?key=[YOUR GOOGLE API KEY HERE]"> | |
</script> | |
<script type="text/javascript"> | |
var circle; | |
function initialize() { | |
geocoder = new google.maps.Geocoder(); | |
var latlng = new google.maps.LatLng(0, 0); | |
var mapOptions = { | |
center: latlng, | |
zoom: 2, | |
mapTypeId: google.maps.MapTypeId.TERRAIN | |
}; | |
var map = new google.maps.Map(document.getElementById("map-canvas"), mapOptions);""" | |
color = dict() | |
for fl in files: | |
color[fl] = '#%06X' % randint(0x000000,0xFFFFFF) | |
for itm in coo[fl]: | |
print """ | |
latlng = new google.maps.LatLng(%s,%s); | |
var options = { | |
strokeColor: '%s', | |
strokeOpacity: 0.2, | |
strokeWeight: 1, | |
fillColor: '%s', | |
fillOpacity: 0.02, | |
map: map, | |
center: latlng, | |
radius: 100000, | |
title: '%s' | |
}; | |
circle = new google.maps.Circle(options);""" % (itm[0],itm[1],color[fl],color[fl],itm[2]) | |
# print """ | |
# latlng = new google.maps.LatLng(%s,%s); | |
# var options = { | |
# map: map, | |
# position: latlng, | |
# title: '%s' | |
# }; | |
# circle = new google.maps.Marker(options);""" % (itm[0],itm[1],itm[2])""" | |
print """ | |
} | |
google.maps.event.addDomListener(window, 'load', initialize); | |
</script> | |
</head> | |
<body> | |
<h1>Attacks statistics</h1> | |
<div id="plot-canvas">""" | |
ip_r = list(set(ip_r)) | |
width = 1.0 | |
top = 20 | |
ymax = 0.00 | |
title = {'1':'Top 20 Class-A', '2':'Top 20 Class-B', '3':'Top 20 Class-C'} | |
appnd = {'1':'0.0.0', '2':'0.0', '3':'0'} | |
for cl in ['1', '2', '3']: | |
ip_s = [re.search("([0-9]+\.){" + cl + "}", v).group(0) for i, v in enumerate(ip_r)] | |
labels, values = zip(*Counter(ip_s).most_common(top)) | |
ymax = max(ymax, max(values)) | |
countries = [lookup_ip(lbl + appnd[cl])[4] for lbl in labels] | |
indexes = np.arange(len(labels)) | |
rect = plt.bar(indexes, values, width, label=countries) | |
plt.ylim(0, 1.3 * ymax) | |
plt.xticks(indexes + 0.5 * width, labels, rotation="vertical") | |
for i, r in enumerate(rect): | |
plt.text(r.get_x() + 0.5 * r.get_width(), 1.05 * r.get_height(), countries[i], ha='center', va='bottom', rotation='vertical') | |
plt.title(title[cl]) | |
sio = cStringIO.StringIO() | |
plt.savefig(sio, format='png', bbox_inches='tight') | |
print """ | |
<img src="data:image/png;base64,%s"/>""" % sio.getvalue().encode("base64").strip() | |
plt.close() | |
sio.close() | |
print """ | |
</div> | |
The following map displays only the location of IP addresses that could be georeferenced. Different colors correspond to different services (total/geolite/freegeoip):</br>""" | |
for fl in files: | |
print """<font color="%s">%s (%s/%s/%s) </font> """ % (color[fl],fl,tot[fl],len(coo[fl]),grfd[fl]) | |
print """ | |
<div id="map-canvas"></div> | |
This maps makes use of geolite data created by maxmind, available from <a href="http://www.maxmind.com">http://www.maxmind.com</a> and, where necessary, georeferencing from <a href="http://freegeoip.net">http://freegeoip.net</a> | |
</body> | |
</html>""" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment