Skip to content

Instantly share code, notes, and snippets.

@avaccari
Created June 21, 2016 15:50
Show Gist options
  • Save avaccari/4608831f4a268cf337f8d9339ba372c7 to your computer and use it in GitHub Desktop.
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
#!/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
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