5
@author: Gianluca Medici
7
This module is made to show a page inside ntop summarizing the geoLocation of all
8
host seen and visualize them on a world map. The map is interactive and shows in addiction
9
the information regarding each nation's packets count (represented with different tonality of colours).
10
Clicking on a region of a map or on a row of the country's table is possible to zoom to
11
that particular nation and see the approximate position of the cities in witch the hosts are located.
19
# Import modules for CGI handling
22
from StringIO import StringIO
31
from mako.template import Template
32
from mako.runtime import Context
33
from mako.lookup import TemplateLookup
34
from mako import exceptions
36
ntop.printHTMLHeader('ntop Python Configuration Error', 1, 1)
37
ntop.sendString("<b><center><font color=red>Please install <A HREF=http://www.makotemplates.org/>Mako</A> template engine</font><p></b><br>(1) 'sudo yum install python-setuptools' (on RedHat-like systems)<br>(2) 'sudo easy_install Mako'</font></center>")
38
ntop.printHTMLFooter()
41
ntop.printHTMLHeader('ntop Python Configuration Error', 1, 1)
42
ntop.sendString("<b><center><font color=red>Please install JSON support in python</font><p></b><br>E.g. 'sudo apt-get install python-json' (on Debian-like systems)</font></center>")
43
ntop.printHTMLFooter()
48
sys.setdefaultencoding("latin1")
59
def __init__(self, name, latitudine, longitudine, numHosts ):
63
self.__name=name.decode('latin1')
64
self.__latitudine=latitudine
65
self.__longitudine=longitudine
66
self.__totalHosts=numHosts
71
def getLatitude(self):
72
return self.__latitudine
74
def getLongitude(self):
75
return self.__longitudine
77
def getTotalHosts(self):
78
return self.__totalHosts
80
def addTotal(self, numHosts):
81
self.__totalHosts+=numHosts
84
return {'c':[{'v':float(self.__latitudine)}, {'v':float(self.__longitudine)} , {'v':self.__totalHosts} , {'v':self.__name}]}
86
class Country(object):
95
def __init__(self, code, name, numHosts):
101
self.__name = name.decode('latin1')
102
self.__total = numHosts
103
self.__dictionaryTown = {}
105
def addCity(self, city, latitude, longitude, numHosts):
106
if self.__dictionaryTown.has_key(city):
107
self.__dictionaryTown[city].addTotal(numHosts)
109
self.__dictionaryTown[city]= Town(city, latitude, longitude, numHosts)
120
def addTotal(self, total):
123
def getDictionaryCities(self):
124
return self.__dictionaryTown
128
return {'c':[{'v':self.__code}, {'v':self.__total} , {'v':self.__name} ]}
130
def dictToList(self):
134
for x in self.__dictionaryTown :
135
if self.__dictionaryTown[x].getName() == 'Unknown' and unk == -1:
137
rows.append(self.__dictionaryTown[x].getRow());
139
return {'lista':rows, 'unknown':unk}
142
Return a string of formatted json data for building the countries table and the cities table
144
def getJsonData(dictionaryCountries, totalHosts,unknownCountries, unknownCities):
145
dataJ={'rowsTCountries': None, 'tablesCities': []}
147
for x in dictionaryCountries:
148
mainRows.append(dictionaryCountries[x].getRow())
149
dataJ['tablesCities'].append({'code':dictionaryCountries[x].getCode(), 'citiesRows': dictionaryCountries[x].dictToList()})
151
dataJ['rowsTCountries']= mainRows
152
dataJ['totalHosts']= totalHosts
153
dataJ['unknownCountries']= unknownCountries
154
dataJ['unknownCities']= unknownCities
155
#pprint.pprint(dataJ, sys.stderr)
157
return json.dumps(dataJ, True)
161
if exceptions_so_far == 0:
162
dictionaryCountries = {}
167
flag = 's' # s (default) for sent packets r for received, b for both
168
SIXDECIMAL = decimal.Decimal(10) ** -6 # decimals are all fixed to 6 es. 0.000000
173
form = cgi.FieldStorage();
175
if form.getvalue('OP') == 'Change':
176
flag = form.getvalue('countHosts', 's')
178
while ntop.getNextHost(0):
182
countryCode = geo.get('country_code', '')
183
countryName = geo.get('country_name', '')
184
city = geo.get('city', '')
186
lat = str(geo.get('latitude', '0.000000'))
187
lon = str(geo.get('longitude', '0.000000'))
189
latitude = decimal.Decimal(lat).quantize(SIXDECIMAL)
190
longitude = decimal.Decimal(lon).quantize(SIXDECIMAL)
192
if not countryCode or countryCode == 'EU' or countryCode == 'AP' : # the country was not found therefore the city was not found, everything in the object is set accordingly
195
unknownCountries += 1
197
unknownCities += 1 # the country was found but not the city, to list this case the city name is set to Unknown
199
latitude = decimal.Decimal('0.000000')
200
longitude = decimal.Decimal('0.000000')
203
if dictionaryCountries.has_key(countryCode): # the dictionary of nations already has the nationCode listed
204
country = dictionaryCountries[countryCode]
207
country = Country(countryCode, countryName, 1)
208
dictionaryCountries[countryCode] = country
211
country.addCity(city, latitude, longitude, 1) # insert the city found in the citiesDictionary of this nation object
213
if os.getenv('REQUEST_METHOD', 'GET') == 'POST':
214
ntop.sendHTTPHeader(12)
215
ntop.sendString(getJsonData(dictionaryCountries, totalHosts, unknownCountries, unknownCities))
217
ntop.printHTMLHeader('Host Map: Region View', 1, 0)
220
ntop.printFlagedWarning('No hosts have been detected by ntop yet')
221
elif len(dictionaryCountries) == 0:
222
ntop.printFlagedWarning('No hosts have been successfully geo-located by ntop yet')
225
basedir = os.getenv('DOCUMENT_ROOT', '.')+'/python/templates'
226
mylookup = TemplateLookup(directories=[basedir],output_encoding='utf-8', input_encoding='latin1',encoding_errors='replace', default_filters=['decode.utf8'])
227
myTemplate = mylookup.get_template('GeoPacketVisualizer.tmpl')
229
ctx = Context(buf, countries = dictionaryCountries, totalHosts = totalHosts, unknownCountries = unknownCountries,
230
unknownCities = unknownCities, filename = os.path.basename(__file__))
231
myTemplate.render_context(ctx)
232
ntop.sendString(buf.getvalue())
234
ntop.sendString(exceptions.html_error_template().render())
236
ntop.printHTMLFooter()