From e128a9d22fcb2fa47027ed4fe3f83b0577e4f1b6 Mon Sep 17 00:00:00 2001 From: Tom Date: Thu, 19 Apr 2012 17:50:03 +0200 Subject: finished database implementation and documentation in thesis, incorporated changes in thesis --- Src/PyCatcher/Databases/home.db | Bin 0 -> 5120 bytes Src/PyCatcher/Databases/test.db | Bin 2048 -> 0 bytes Src/PyCatcher/GUI/catcher_main.glade | 253 ++++++++++++++++++++++++++++++- Src/PyCatcher/src/CellIDDatabase.py | 96 ------------ Src/PyCatcher/src/LocalAreaDatabse.py | 97 ------------ Src/PyCatcher/src/cellIDDatabase.py | 133 ++++++++++++++++ Src/PyCatcher/src/driverConnector.py | 2 +- Src/PyCatcher/src/localAreaDatabse.py | 93 ++++++++++++ Src/PyCatcher/src/pyCatcherController.py | 93 +++++++++++- Src/PyCatcher/src/pyCatcherModel.py | 55 ++++--- Src/PyCatcher/src/pyCatcherView.py | 38 ++++- Src/PyCatcher/src/rules.py | 39 +++-- Src/PyCatcher/src/settings.py | 18 +-- 13 files changed, 675 insertions(+), 242 deletions(-) create mode 100644 Src/PyCatcher/Databases/home.db delete mode 100644 Src/PyCatcher/Databases/test.db delete mode 100644 Src/PyCatcher/src/CellIDDatabase.py delete mode 100644 Src/PyCatcher/src/LocalAreaDatabse.py create mode 100644 Src/PyCatcher/src/cellIDDatabase.py create mode 100644 Src/PyCatcher/src/localAreaDatabse.py (limited to 'Src') diff --git a/Src/PyCatcher/Databases/home.db b/Src/PyCatcher/Databases/home.db new file mode 100644 index 0000000..4c9ef1e Binary files /dev/null and b/Src/PyCatcher/Databases/home.db differ diff --git a/Src/PyCatcher/Databases/test.db b/Src/PyCatcher/Databases/test.db deleted file mode 100644 index d2ee778..0000000 Binary files a/Src/PyCatcher/Databases/test.db and /dev/null differ diff --git a/Src/PyCatcher/GUI/catcher_main.glade b/Src/PyCatcher/GUI/catcher_main.glade index 68241ef..f634bdb 100644 --- a/Src/PyCatcher/GUI/catcher_main.glade +++ b/Src/PyCatcher/GUI/catcher_main.glade @@ -1,6 +1,257 @@ + + False + 5 + popup + True + center-on-parent + True + dialog + main_window + False + + + False + vertical + 2 + + + False + end + + + + + + Close + True + True + True + False + + + + False + True + 1 + + + + + False + True + end + 0 + + + + + True + False + + + True + False + +Cell ID Databases + + + + False + True + 0 + + + + + Google Mobile Maps Service + True + True + False + False + 0 + True + + + False + True + 1 + + + + + OpenCellID Webservice + True + True + False + False + 0 + True + + + False + True + 2 + + + + + True + False + + + Use local database: + True + True + False + False + 0 + True + + + False + True + 0 + + + + + True + True + + True + + + False + True + 1 + + + + + False + True + 3 + + + + + Re-run Web Services + True + True + True + False + + + + False + True + 4 + + + + + True + False + + + False + True + 5 + + + + + True + False + +Local Area Database + + + + False + True + 6 + + + + + True + False + + + True + False + Current Location: + + + False + True + 0 + + + + + True + True + + True + + + False + True + 1 + + + + + False + True + 7 + + + + + Add current Scan to Location/ + Create Location from Scan + True + True + True + False + + + + False + True + 8 + + + + + True + False + + + False + True + 9 + + + + + False + True + 1 + + + + + + btn_databases_close + + False Details @@ -498,6 +749,7 @@ Databases True network-server + False @@ -696,7 +948,6 @@ True True - natural diff --git a/Src/PyCatcher/src/CellIDDatabase.py b/Src/PyCatcher/src/CellIDDatabase.py deleted file mode 100644 index 2471a5a..0000000 --- a/Src/PyCatcher/src/CellIDDatabase.py +++ /dev/null @@ -1,96 +0,0 @@ -import re -import urllib2 -from settings import Open_Cell_ID_Key -from struct import pack, unpack -from httplib import HTTP - -class Translator: - Country = { - 'Germany':'262' - } - - Provider = { - 'T-Mobile':'01', - 'Vodafone':'02', - 'E-Plus':'03', - 'O2':'07' - } - - MCC = { - 262:'de' - } - -class CellIDDBStatus: - CONFIRMED = 0 - APPROXIMATED = 1 - ERROR = 2 - NOT_LOOKED_UP = 3 - NOT_IN_DB = 4 - -class CellIDDatabaseFetcher: - - - def fetch(self, cid, lac, mcc, mnc): - print CID.fetch_id_from_Google(cid,lac,mcc) - print CID.fetch_id_from_OpenCellID(cid,lac,mcc,mnc) - - - def fetch_id_from_OpenCellID(self,cid, lac, mcc, mnc): - key_ocid = Open_Cell_ID_Key - - url = 'http://www.opencellid.org/cell/get?key=%s&mnc=%d&mcc=%d&lac=%d&cellid=%d'%(key_ocid, mnc, mcc, lac, cid) - response = urllib2.urlopen(url).read() - - status = (re.search(r'stat="(.+)"',response)).group(1) - - if status != 'ok': - status = CellIDDBStatus.ERROR - return - - match = re.search(r'lat="(\d+\.\d+)".*lon="(\d+\.\d+).*range="(\d+)"',response) - latitude,longitude,range = match.group(1),match.group(2),match.group(3) - - if int(range) > 10000: - status = CellIDDBStatus.APPROXIMATED - else: - status = CellIDDBStatus.CONFIRMED - - latitude = float(latitude) - longitude = float(longitude) - - if latitude == 0 or longitude == 0: - status = CellIDDBStatus.NOT_IN_DB - - return status, latitude, longitude - - - def fetch_id_from_Google(self, cid, lac, country): - device = "Motorola C123" - country = Translator.MCC[country] - b_string = pack('>hqh2sh13sh5sh3sBiiihiiiiii', - 21, 0, - len(country), country, - len(device), device, - len('1.3.1'), "1.3.1", - len('Web'), "Web", - 27, 0, 0, - 3, 0, cid, lac, - 0, 0, 0, 0) - - http = HTTP('www.google.com', 80) - http.putrequest('POST', '/glm/mmap') - http.putheader('Content-Type', 'application/binary') - http.putheader('Content-Length', str(len(b_string))) - http.endheaders() - http.send(b_string) - code, msg, headers = http.getreply() - try: - bytes = http.file.read() - (a, b,errorCode, latitude, longitude, c, d, e) = unpack(">hBiiiiih",bytes) - latitude = latitude / 1000000.0 - longitude = longitude / 1000000.0 - status = CellIDDBStatus.CONFIRMED - except: - status = CellIDDBStatus.NOT_IN_DB - - return status, latitude, longitude \ No newline at end of file diff --git a/Src/PyCatcher/src/LocalAreaDatabse.py b/Src/PyCatcher/src/LocalAreaDatabse.py deleted file mode 100644 index 102408a..0000000 --- a/Src/PyCatcher/src/LocalAreaDatabse.py +++ /dev/null @@ -1,97 +0,0 @@ -import sqlite3 -import os -from pyCatcherModel import BaseStationInformation - -class dummystation: - - def __init__(self): - self.arfcn = 0 - self.bsic = '2,3' - self.cell = 2 - self.country = 'Nirvana' - self.lac = 4 - self.provider = 'T-Schrott' - self.rxlev = -70 - - -class LocalAreaDatabase: - - def __init__(self): - self._connection = None - self._cursor = None - - def load_or_create_database(self, path): - if self._connection: - self._connection.close() - self._connection = None - - database_exists = os.path.exists(path) - self._connection = sqlite3.connect(path) - self._cursor = self._connection.cursor() - if not database_exists: - print 'file has been created' - self._create_base_table() - else: - print 'connected to existing' - - def _create_base_table(self): - sql = '''CREATE TABLE basestations( - cellid INTEGER, country TEXT, provider TEXT, arfcn INTEGER, bsic TEXT, lac INTEGER, - rxmin INTEGER, rxmax INTEGER, sightings INTEGER - ) - ''' - self._cursor.execute(sql) - self._connection.commit() - - def _insert_station(self, base_station): - values = ( base_station.cell, - base_station.country, - base_station.provider, - base_station.arfcn, - base_station.bsic, - base_station.lac, - base_station.rxlev, - base_station.rxlev, - 1 - ) - sql = 'INSERT INTO basestations VALUES (?,?,?,?,?,?,?,?,?)' - self._cursor.execute(sql, values) - self._connection.commit() - - def _alter_station(self, base_station, old_rmin, old_rmax, old_sightings): - if base_station.rxlev < old_rmin: - rmin = base_station.rxlev - else: - rmin = old_rmin - if base_station.rxlev > old_rmax: - rmax = base_station.rxlev - else: - rmax = old_rmax - sightings = old_sightings + 1 - values = (rmin,rmax,sightings,base_station.cell) - sql = 'UPDATE basestations SET rxmin=?, rxmax=?, sightings=? WHERE cellid=?' - self._cursor.execute(sql, values) - self._connection.commit() - - def get_station(self, cellID): - sql = 'SELECT * FROM basestations WHERE cellid =%d'%cellID - self._cursor.execute(sql) - try: - result = (self._cursor.fetchall())[0] - except: - result = None - return result - - def insert_or_alter_base_stations(self, base_station_list): - for station in base_station_list: - self.insert_or_alter_base_station(station) - - def insert_or_alter_base_station(self, base_station): - lookupresult = self.get_station(base_station.cell) - if lookupresult: - self._alter_station(station,lookupresult[6],lookupresult[7],lookupresult[8]) - else: - self._insert_station(base_station) - - def __del__(self): - self._connection.close() \ No newline at end of file diff --git a/Src/PyCatcher/src/cellIDDatabase.py b/Src/PyCatcher/src/cellIDDatabase.py new file mode 100644 index 0000000..d12ce60 --- /dev/null +++ b/Src/PyCatcher/src/cellIDDatabase.py @@ -0,0 +1,133 @@ +import re +import urllib2 +from settings import Open_Cell_ID_Key +from struct import pack, unpack +from httplib import HTTP +import sqlite3 +import os +from settings import Database_path + +class CIDDatabases: + NONE = 0 + GOOGLE = 1 + OPENCID = 2 + LOCAL = 3 + +class Translator: + Country = { + 'Germany':'de' + } + + Provider = { + 'T-Mobile':'01', + 'Vodafone':'02', + 'E-Plus':'03', + 'O2':'07' + } + + MCC = { + 'Germany':262 + } + +class CellIDDBStatus: + CONFIRMED = 0 + APPROXIMATED = 1 + ERROR = 2 + NOT_LOOKED_UP = 3 + NOT_IN_DB = 4 + +class CellIDDatabase: + + + def fetch_id_from_OpenCellID(self,cid, lac, country, provider): + key_ocid = Open_Cell_ID_Key + + mcc = Translator.MCC[country] + mnc = Translator.Provider[provider] + + url = 'http://www.opencellid.org/cell/get?key=%s&mnc=%s&mcc=%d&lac=%d&cellid=%d'%(key_ocid,mnc,mcc,lac,cid) + response = urllib2.urlopen(url).read() + + status = (re.search(r'stat="(.+)"',response)).group(1) + + if status != 'ok': + status = CellIDDBStatus.ERROR + return + + match = re.search(r'lat="(\d+\.\d+)".*lon="(\d+\.\d+).*range="(\d+)"',response) + latitude,longitude,range = match.group(1),match.group(2),match.group(3) + + if int(range) > 10000: + status = CellIDDBStatus.APPROXIMATED + else: + status = CellIDDBStatus.CONFIRMED + + latitude = float(latitude) + longitude = float(longitude) + + if latitude == 0 or longitude == 0: + status = CellIDDBStatus.NOT_IN_DB + + return status, latitude, longitude + + + def fetch_id_from_Google(self, cid, lac, country): + latitude = 0 + longitude = 0 + device = "Motorola C123" + country = Translator.Country[country] + b_string = pack('>hqh2sh13sh5sh3sBiiihiiiiii', + 21, 0, + len(country), country, + len(device), device, + len('1.3.1'), "1.3.1", + len('Web'), "Web", + 27, 0, 0, + 3, 0, cid, lac, + 0, 0, 0, 0) + + http = HTTP('www.google.com', 80) + http.putrequest('POST', '/glm/mmap') + http.putheader('Content-Type', 'application/binary') + http.putheader('Content-Length', str(len(b_string))) + http.endheaders() + http.send(b_string) + code, msg, headers = http.getreply() + try: + bytes = http.file.read() + (a, b,errorCode, latitude, longitude, c, d, e) = unpack(">hBiiiiih",bytes) + latitude /= 1000000.0 + longitude /= 1000000.0 + status = CellIDDBStatus.CONFIRMED + except: + status = CellIDDBStatus.NOT_IN_DB + + return status, latitude, longitude + + def fetch_id_from_local(self, cid, database): + database += '.db' + path = os.path.join(Database_path, database) + if os.path.exists(path): + connection = sqlite3.connect(path) + else: + return CellIDDBStatus.ERROR,0,0 + if connection: + cursor = connection.cursor() + else: + return CellIDDBStatus.ERROR,0,0 + + sql = 'SELECT * FROM basestations WHERE cellid =%d'%cid + cursor.execute(sql) + try: + result = (cursor.fetchall())[0] + except: + result = None + + if result: + cursor.close() + connection.close() + return CellIDDBStatus.CONFIRMED,0,0 + else: + cursor.close() + connection.close() + return CellIDDBStatus.NOT_IN_DB,0,0 \ No newline at end of file diff --git a/Src/PyCatcher/src/driverConnector.py b/Src/PyCatcher/src/driverConnector.py index de8a0d4..2e990fd 100644 --- a/Src/PyCatcher/src/driverConnector.py +++ b/Src/PyCatcher/src/driverConnector.py @@ -117,7 +117,7 @@ class ScanThread(threading.Thread): line = scan_process.stdout.readline() match = re.search(r'rxlev:\s(.\d+)',line) if match: - base_station.rxlev = match.group(1) + base_station.rxlev = int(match.group(1)) #get si2 line = scan_process.stdout.readline() match = re.search(r'si2\s(.+)',line) diff --git a/Src/PyCatcher/src/localAreaDatabse.py b/Src/PyCatcher/src/localAreaDatabse.py new file mode 100644 index 0000000..3cded04 --- /dev/null +++ b/Src/PyCatcher/src/localAreaDatabse.py @@ -0,0 +1,93 @@ +import sqlite3 +import os +from pyCatcherModel import BaseStationInformation +from settings import Database_path +class LocalAreaDatabase: + + def __init__(self): + self._connection = None + self._cursor = None + + def load_or_create_database(self, name): + if self._connection: + self._connection.close() + self._connection = None + + name += '.db' + path = os.path.join(Database_path ,name) + + database_exists = os.path.exists(path) + self._connection = sqlite3.connect(path) + self._cursor = self._connection.cursor() + if not database_exists: + self._create_base_table() + + def _create_base_table(self): + sql = '''CREATE TABLE basestations( + cellid INTEGER, country TEXT, provider TEXT, arfcn INTEGER, bsic TEXT, lac INTEGER, + rxmin INTEGER, rxmax INTEGER, sightings INTEGER + ) + ''' + self._cursor.execute(sql) + self._connection.commit() + + def _insert_station(self, base_station): + values = ( base_station.cell, + base_station.country, + base_station.provider, + base_station.arfcn, + base_station.bsic, + base_station.lac, + base_station.rxlev, + base_station.rxlev, + 1 + ) + sql = 'INSERT INTO basestations VALUES (?,?,?,?,?,?,?,?,?)' + self._cursor.execute(sql, values) + self._connection.commit() + + def _alter_station(self, base_station, old_rmin, old_rmax, old_sightings): + + current_rx = int(base_station.rxlev) + + if current_rx < old_rmin: + rmin = current_rx + else: + rmin = old_rmin + if current_rx > old_rmax: + rmax = current_rx + else: + rmax = old_rmax + sightings = old_sightings + 1 + values = (rmin,rmax,sightings,base_station.cell) + sql = 'UPDATE basestations SET rxmin=?, rxmax=?, sightings=? WHERE cellid=?' + self._cursor.execute(sql, values) + self._connection.commit() + + def get_station(self, cellID): + if not self._connection: + return None + sql = 'SELECT * FROM basestations WHERE cellid =%d'%cellID + self._cursor.execute(sql) + try: + result = (self._cursor.fetchall())[0] + except: + result = None + return result + + def insert_or_alter_base_stations(self, base_station_list): + for station in base_station_list: + self.insert_or_alter_base_station(station) + + def insert_or_alter_base_station(self, base_station): + lookupresult = self.get_station(base_station.cell) + if lookupresult: + self._alter_station(base_station,lookupresult[6],lookupresult[7],lookupresult[8]) + else: + self._insert_station(base_station) + + def __del__(self): + if self._cursor: + self._cursor.close() + if self._connection: + self._connection.close() \ No newline at end of file diff --git a/Src/PyCatcher/src/pyCatcherController.py b/Src/PyCatcher/src/pyCatcherController.py index 114ea8a..924ada9 100644 --- a/Src/PyCatcher/src/pyCatcherController.py +++ b/Src/PyCatcher/src/pyCatcherController.py @@ -6,14 +6,16 @@ from pyCatcherView import PyCatcherGUI from filters import ARFCNFilter,ProviderFilter, BandFilter900 from evaluators import EvaluatorSelect, BayesEvaluator, ConservativeEvaluator, WeightedEvaluator from rules import ProviderRule, ARFCNMappingRule, CountryMappingRule, LACMappingRule, UniqueCellIDRule, \ - LACMedianRule, NeighbourhoodStructureRule, PureNeighbourhoodRule, FullyDiscoveredNeighbourhoodsRule, RuleResult + LACMedianRule, NeighbourhoodStructureRule, PureNeighbourhoodRule, FullyDiscoveredNeighbourhoodsRule, RuleResult, CellIDDatabaseRule, LocationAreaDatabaseRule import pickle +from localAreaDatabse import LocalAreaDatabase +from cellIDDatabase import CellIDDatabase, CellIDDBStatus, CIDDatabases class PyCatcherController: def __init__(self): self._base_station_list = BaseStationInformationList() - store = gtk.ListStore(str,str,str,str, str) - store.append(('-','-','-','-', '-')) + store = gtk.ListStore(str,str,str,str, str,str,str) + store.append(('-','-','-','-', '-','-','-')) self.bs_tree_list_data = store self._gui = PyCatcherGUI(self) self._driver_connector = DriverConnector() @@ -27,6 +29,9 @@ class PyCatcherController: self._filters = [self.arfcn_filter, self.provider_filter] + self._local_area_database = LocalAreaDatabase() + self._cell_id_database = CellIDDatabase() + self._conservative_evaluator = ConservativeEvaluator() self._bayes_evaluator = BayesEvaluator() self._weighted_evaluator = WeightedEvaluator() @@ -50,10 +55,23 @@ class PyCatcherController: self.pure_neighbourhood_rule.is_active = True self.full_discovered_neighbourhoods_rule = FullyDiscoveredNeighbourhoodsRule() self.full_discovered_neighbourhoods_rule.is_active = False + self.cell_id_db_rule = CellIDDatabaseRule() + self.cell_id_db_rule.is_active = False + self.location_area_database_rule = LocationAreaDatabaseRule() + self.location_area_database_rule.is_active = False + self.location_area_database_rule.location_database_object = self._local_area_database self._rules = [self.provider_rule, self.country_mapping_rule, self.arfcn_mapping_rule, self.lac_mapping_rule, self.unique_cell_id_rule, self.lac_median_rule, self.neighbourhood_structure_rule, - self.pure_neighbourhood_rule, self.full_discovered_neighbourhoods_rule] + self.pure_neighbourhood_rule, self.full_discovered_neighbourhoods_rule, self.cell_id_db_rule, + self.location_area_database_rule] + + self.use_google = False + self.use_open_cell_id = False + self.use_local_db = (False, '') + + self._location = '' + gtk.main() def log_message(self, message): @@ -102,6 +120,72 @@ class PyCatcherController: elif evaluator == EvaluatorSelect.WEIGHTED: self._active_evaluator = self._weighted_evaluator + def update_with_web_services(self): + self._gui.log_line('Starting online lookups...') + for station in self._base_station_list._get_unfiltered_list(): + found = False + if self.use_google: + self._gui.log_line('Looking up %d on Google.'%station.cell) + (status, lat, long) = self._cell_id_database.fetch_id_from_Google(station.cell, station.lac, station.country) + if status == CellIDDBStatus.CONFIRMED: + self._gui.log_line('...found.') + found = True + station.latitude = lat + station.longitude = long + station.db_provider = CIDDatabases.GOOGLE + #TODO: remove else clause once new scans are available + else: + station.latitude = 0 + station.longitude = 0 + station.db_provider = CIDDatabases.NONE + station.db_status = status + if self.use_open_cell_id and not found: + self._gui.log_line('Looking up %d on OpenCellID.'%station.cell) + (status, lat, long) = self._cell_id_database.fetch_id_from_OpenCellID(station.cell, station.lac, station.country, station.provider) + if status == CellIDDBStatus.CONFIRMED: + self._gui.log_line('...found.') + found = True + station.latitude = lat + station.longitude = long + station.db_provider = CIDDatabases.OPENCID + elif staus == CellIDDBStatus.APPROXIMATED: + self._gui.log_line('...approximated.') + station.latitude = lat + station.longitude = long + station.db_provider = CIDDatabases.OPENCID + #TODO: remove else clause once new scans are available + else: + station.latitude = 0 + station.longitude = 0 + station.db_provider = CIDDatabases.NONE + station.db_status = status + if self.use_local_db[0] and not found: + self._gui.log_line('Looking up %d on Local.'%station.cell) + (status, lat, long) = self._cell_id_database.fetch_id_from_local(station.cell, self.use_local_db[1]) + if status == CellIDDBStatus.CONFIRMED: + self._gui.log_line('...found.') + station.db_provider = CIDDatabases.LOCAL + station.latitude = 0 + station.longitude = 0 + #TODO: remove else clause once new scans are available + else: + station.latitude = 0 + station.longitude = 0 + station.db_provider = CIDDatabases.NONE + station.db_status = status + self._gui.log_line('Finished online lookups.') + + def update_location_database(self): + self._local_area_database.load_or_create_database(self._location) + self._local_area_database.insert_or_alter_base_stations(self._base_station_list._get_unfiltered_list()) + self._gui.log_line('Done with database upgrade on %s.'%self._location) + + def set_new_location(self,new_location): + if new_location != self._location: + self._location = new_location + self._local_area_database.load_or_create_database(self._location) + self._gui.log_line('Location changed to %s'%self._location) + def save_project(self, path): filehandler = open(path, 'w') pickle.dump(self._base_station_list, filehandler) @@ -117,6 +201,7 @@ class PyCatcherController: self._gui.log_line('Project loaded from ' + path) def trigger_evaluation(self): + self._gui.log_line('Re-evaluation') self._base_station_list.evaluate(self._rules, self._active_evaluator) self._base_station_list.refill_store(self.bs_tree_list_data, self.band_filter, self._filters) self.trigger_redraw() diff --git a/Src/PyCatcher/src/pyCatcherModel.py b/Src/PyCatcher/src/pyCatcherModel.py index 112646b..4e17217 100644 --- a/Src/PyCatcher/src/pyCatcherModel.py +++ b/Src/PyCatcher/src/pyCatcherModel.py @@ -1,20 +1,33 @@ import datetime import gtk import math -from CellIDDatabase import CellIDDBStatus - -class LocationProvider: - GOOGLE = 0 - OPENCELLID = 1 - NONE = 2 - -class BaseStationInformation: +from cellIDDatabase import CellIDDBStatus +from cellIDDatabase import CIDDatabases +from rules import RuleResult + +class EnumTranslator: + CIDDBStatus = { + 0:'Confirmed.', + 1:'Approximated.', + 2:'Error.', + 3:'Not yet looked up.', + 4:'Not in database.' + } + CIDDB = { + 0:'None.', + 1:'Google.', + 2:'OpenCellID', + 3:'Local Cell DB' + } + +class BaseStationInformation: def __init__ (self): self.country = 'Nowhere' self.provider = 'Carry' self.arfcn = 0 self.rxlev = 0 + self.times_scanned = 0 self.system_info_t2 = [] self.system_info_t2bis = [] self.system_info_t2ter = [] @@ -29,10 +42,11 @@ class BaseStationInformation: self.evaluation_by = 'NYE' self.latitude = 0 self.longitude = 0 - self.locationprovider = LocationProvider.NONE + self.db_status = CellIDDBStatus.NOT_LOOKED_UP + self.db_provider = CIDDatabases.NONE def get_list_model(self): - return self.provider, str(self.arfcn), str(self.rxlev), self.evaluation, self.discovery_time + return self.provider, str(self.arfcn), str(self.rxlev), str(self.cell),self.evaluation, self.discovery_time,0 def get_neighbour_arfcn(self): if 1 < self.arfcn < 125: @@ -68,11 +82,6 @@ class BaseStationInformation: pass def create_report(self): - #TODO: remove this after scans with new data model are available - self.locationprovider = 'NONE' - self.longitude = 0 - self.latitude = 0 - report_params = '''------- Base Station Parameters ----------- Country: %s Provider: %s @@ -84,9 +93,10 @@ Cell ID: %s Neighbours: %s Latitude: %s Longitude: %s -Location Provider: %s +Database Status: %s +Database Provider: %s Evaluation: %s\n -'''%(self.country,self.provider, self.arfcn, self.rxlev, self.bsic, self.lac, self.cell, ', '.join(map(str,self.get_neighbour_arfcn())),self.latitude,self.longitude,self.locationprovider,self.evaluation) +'''%(self.country,self.provider, self.arfcn, self.rxlev, self.bsic, self.lac, self.cell, ', '.join(map(str,self.get_neighbour_arfcn())),self.latitude,self.longitude,EnumTranslator.CIDDBStatus[self.db_status], EnumTranslator.CIDDB[self.db_provider],self.evaluation) report_rules ='------- Rule Results -----------\n' for key in self.rules_report.keys(): @@ -129,7 +139,14 @@ class BaseStationInformationList: filtered_list = self._get_filtered_list(band_filter, filters) for station in filtered_list: - code += str(station.arfcn) + r' [color=red]; ' + if station.evaluation == RuleResult.OK: + code += str(station.arfcn) + r' [style = filled, fillcolor = green]; ' + elif station.evaluation == RuleResult.WARNING: + code += str(station.arfcn) + r' [style = filled, fillcolor = yellow]; ' + elif station.evaluation == RuleResult.CRITICAL: + code += str(station.arfcn) + r' [style = filled, fillcolor = red]; ' + else: + code += str(station.arfcn) + r' [style = filled, fillcolor = white]; ' for neighbour in station.get_neighbour_arfcn(): code += str(station.arfcn) + r' -> ' + str(neighbour) + r'; ' #TODO: make printing the source a fixed option @@ -179,5 +196,3 @@ class BaseStationInformationList: station.rules_report = rule_results.copy() station.evaluation, station.evaluation_report = evaluator.evaluate(rule_results) station.evaluation_by = evaluator.identifier - - diff --git a/Src/PyCatcher/src/pyCatcherView.py b/Src/PyCatcher/src/pyCatcherView.py index e39a247..c6f6457 100644 --- a/Src/PyCatcher/src/pyCatcherView.py +++ b/Src/PyCatcher/src/pyCatcherView.py @@ -1,5 +1,6 @@ import locale -import gtk +import gtk +from cellIDDatabase import CIDDatabases from xdot import DotWidget import datetime import time @@ -22,6 +23,7 @@ class PyCatcherGUI: self._evaluators_window = self._builder.get_object('evaluators_window') self._evaluation_window = self._builder.get_object('evaluation_window') self._evaluation_image = self._builder.get_object('evaluation_image') + self._databases_window = self._builder.get_object('databases_window') self._ok_image = gtk.gdk.pixbuf_new_from_file('../GUI/Images/ok.png') self._warning_image = gtk.gdk.pixbuf_new_from_file('../GUI/Images/warning.png') @@ -35,8 +37,10 @@ class PyCatcherGUI: self._add_column("Provider", 0) self._add_column("ARFCN", 1) self._add_column("Strength",2) - self._add_column("Evaluation",3) - self._add_column("Last seen", 4) + self._add_column("Cell ID",3) + self._add_column("Evaluation",4) + self._add_column("Last seen", 5) + self._add_column('# Scanned',6) self._bs_tree_view.set_model(self._catcher_controller.bs_tree_list_data) self._horizontal_container = self._builder.get_object('vbox2') @@ -106,11 +110,20 @@ class PyCatcherGUI: self._catcher_controller.neighbourhood_structure_rule.is_active = self._builder.get_object('cb_neighbourhood_structure').get_active() self._catcher_controller.pure_neighbourhood_rule.is_active = self._builder.get_object('cb_pure_neighbourhood').get_active() self._catcher_controller.full_discovered_neighbourhoods_rule.is_active = self._builder.get_object('cb_neighbours_discovered').get_active() + self._catcher_controller.cell_id_db_rule.is_active = self._builder.get_object('cb_cell_id_database').get_active() + self._catcher_controller.location_area_database_rule.is_active = self._builder.get_object('cb_local_area_database').get_active() self._catcher_controller.trigger_evaluation() def _update_evaluators(self): pass + def _update_databases(self): + self._catcher_controller.use_google = self._builder.get_object('cb_google').get_active() + self._catcher_controller.use_open_cell_id = self._builder.get_object('cb_opencellid').get_active() + self._catcher_controller.use_local_db = (self._builder.get_object('cb_cellid_database_local').get_active(), + self._builder.get_object('te_cellid_database').get_text()) + self._catcher_controller.set_new_location(self._builder.get_object('te_current_location').get_text()) + def show_info(self, message, title='PyCatcher', time_to_sleep=3, type='INFO'): gtk_type = {'INFO' : gtk.MESSAGE_INFO, 'ERROR': gtk.MESSAGE_ERROR} @@ -128,7 +141,15 @@ class PyCatcherGUI: def _on_graph_node_clicked (self, widget, url, event): print 'NODE CLICKED' - + + def _on_web_services_clicked(self, widget): + self._update_databases() + self._catcher_controller.update_with_web_services() + + def _on_localdb_add_clicked(self, widget): + self._update_databases() + self._catcher_controller.update_location_database() + def _on_main_window_destroy(self, widget): self._catcher_controller.shutdown() gtk.main_quit() @@ -186,6 +207,15 @@ class PyCatcherGUI: self._detail_window.hide() return True + def _on_databases_clicked(self, widget): + self._databases_window.show() + + def _on_databases_close_clicked(self, widget): + self._update_databases() + self._catcher_controller.trigger_evaluation() + self._databases_window.hide() + + def _on_save_clicked(self, widget): chooser = gtk.FileChooserDialog(title="Save Project", action=gtk.FILE_CHOOSER_ACTION_SAVE, diff --git a/Src/PyCatcher/src/rules.py b/Src/PyCatcher/src/rules.py index 312b26f..8a8ba09 100644 --- a/Src/PyCatcher/src/rules.py +++ b/Src/PyCatcher/src/rules.py @@ -1,4 +1,6 @@ -from settings import Provider_list, Provider_Country_list, LAC_mapping, ARFCN_mapping, LAC_threshold +from settings import Provider_list, Provider_Country_list, LAC_mapping, ARFCN_mapping, LAC_threshold, RX_threshold +from cellIDDatabase import CellIDDBStatus +import math class RuleResult: OK = 'Ok' @@ -116,7 +118,7 @@ class LACMedianRule (Rule): upper_bound = median + median * LAC_threshold lower_bound = median - median * LAC_threshold - if lower_bound < lac_to_test < upper_bound: + if lower_bound <= lac_to_test <= upper_bound: return RuleResult.OK else: return RuleResult.CRITICAL @@ -191,18 +193,35 @@ class FullyDiscoveredNeighbourhoodsRule (Rule): class LocationAreaDatabaseRule(Rule): identifier = 'Location Area Database' + def __init__(self): + self.location_database_object = None def check(self, arfcn, base_station_list): - pass + if not self.location_database_object: + return RuleResult.IGNORE + for item in base_station_list: + if item.arfcn == arfcn: + result = self.location_database_object.get_station(item.cell) + if not result: + return RuleResult.CRITICAL + rxmin = result[6] + rxmax = result[7] + rxmin_thresh = rxmin - math.fabs(rxmin * RX_threshold) + rxmax_thresh = rxmax + math.fabs(rxmax * RX_threshold) + if rxmin_thresh <= float(item.rxlev) <= rxmax_thresh: + return RuleResult.OK + else: + return RuleResult.CRITICAL class CellIDDatabaseRule (Rule): identifier = 'CellID Database' def check(self, arfcn, base_station_list): - pass - -class BDDLearningRule (Rule): - identifier = 'BDD Learning' - - def check(self, arfcn, base_station_list): - pass + for item in base_station_list: + if item.arfcn == arfcn: + if item.db_status == CellIDDBStatus.NOT_LOOKED_UP: + return RuleResult.IGNORE + if item.db_status == CellIDDBStatus.CONFIRMED: + return RuleResult.OK + else: + return RuleResult.CRITICAL diff --git a/Src/PyCatcher/src/settings.py b/Src/PyCatcher/src/settings.py index 8f5c002..11084dc 100644 --- a/Src/PyCatcher/src/settings.py +++ b/Src/PyCatcher/src/settings.py @@ -19,9 +19,10 @@ Commands = {'osmocon_command' : [Osmocon_lib + '/host/osmocon/osmocon', #Rules Configuration ------------------------------------------------------------------------------------------- -Provider_list = ['T-Mobile', 'O2', 'Vodafone', 'E-Plus'] +Provider_list = ['T-Mobile', 'O2', 'Vodafone', 'E-Plus', 'DB Systel GSM-R'] Provider_Country_list = { + 'DB Systel GSM-R':'Germany', 'T-Mobile':'Germany', 'O2':'Germany', 'Vodafone':'Germany', @@ -29,29 +30,28 @@ Provider_Country_list = { } LAC_mapping = { + 'DB Systel GSM-R': [0,999999], 'T-Mobile' : [21000,22000], - 'O2' : [0,9999], + 'O2' : [0,99999], 'Vodafone' : [0,100000], 'E-Plus' : [0,100000] } ARFCN_mapping = { + 'DB Systel GSM-R': [0,9999], 'T-Mobile' : [0,9999], 'O2' : [0,9999], 'Vodafone' : [0,9999], 'E-Plus' : [0,9999] } -LAC_threshold = 0.5 +LAC_threshold = 0 + +RX_threshold = 0.05 #Database Configuration ---------------------------------------------------------------------------------------- Open_Cell_ID_Key = 'd7a5bc3f21b44d4bf93d1ec2b3f83dc4' -Open_Cell_ID_Local = '' - - -#Evaluator Configuration --------------------------------------------------------------------------------------- +Database_path = '/home/tom/imsi-catcher-detection/Src/PyCatcher/Databases/' -Bayes_probabilities = {} -Bayes_database = '' \ No newline at end of file -- cgit v1.2.3-55-g7522