summaryrefslogtreecommitdiffstats
path: root/Src
diff options
context:
space:
mode:
authorTom2012-04-19 17:50:03 +0200
committerTom2012-04-19 17:50:03 +0200
commite128a9d22fcb2fa47027ed4fe3f83b0577e4f1b6 (patch)
treea5a4e0090e4eb94343395e1f3403dff3fd3b632b /Src
parentimplemented databases save for guis (diff)
downloadimsi-catcher-detection-e128a9d22fcb2fa47027ed4fe3f83b0577e4f1b6.tar.gz
imsi-catcher-detection-e128a9d22fcb2fa47027ed4fe3f83b0577e4f1b6.tar.xz
imsi-catcher-detection-e128a9d22fcb2fa47027ed4fe3f83b0577e4f1b6.zip
finished database implementation and documentation in thesis, incorporated changes in thesis
Diffstat (limited to 'Src')
-rw-r--r--Src/PyCatcher/Databases/home.dbbin0 -> 5120 bytes
-rw-r--r--Src/PyCatcher/Databases/test.dbbin2048 -> 0 bytes
-rw-r--r--Src/PyCatcher/GUI/catcher_main.glade253
-rw-r--r--Src/PyCatcher/src/cellIDDatabase.py (renamed from Src/PyCatcher/src/CellIDDatabase.py)65
-rw-r--r--Src/PyCatcher/src/driverConnector.py2
-rw-r--r--Src/PyCatcher/src/localAreaDatabse.py (renamed from Src/PyCatcher/src/LocalAreaDatabse.py)42
-rw-r--r--Src/PyCatcher/src/pyCatcherController.py93
-rw-r--r--Src/PyCatcher/src/pyCatcherModel.py55
-rw-r--r--Src/PyCatcher/src/pyCatcherView.py38
-rw-r--r--Src/PyCatcher/src/rules.py39
-rw-r--r--Src/PyCatcher/src/settings.py18
11 files changed, 519 insertions, 86 deletions
diff --git a/Src/PyCatcher/Databases/home.db b/Src/PyCatcher/Databases/home.db
new file mode 100644
index 0000000..4c9ef1e
--- /dev/null
+++ b/Src/PyCatcher/Databases/home.db
Binary files differ
diff --git a/Src/PyCatcher/Databases/test.db b/Src/PyCatcher/Databases/test.db
deleted file mode 100644
index d2ee778..0000000
--- a/Src/PyCatcher/Databases/test.db
+++ /dev/null
Binary files 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 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<!-- interface-requires gtk+ 3.0 -->
+ <object class="GtkDialog" id="databases_window">
+ <property name="can_focus">False</property>
+ <property name="border_width">5</property>
+ <property name="type">popup</property>
+ <property name="modal">True</property>
+ <property name="window_position">center-on-parent</property>
+ <property name="destroy_with_parent">True</property>
+ <property name="type_hint">dialog</property>
+ <property name="transient_for">main_window</property>
+ <property name="has_resize_grip">False</property>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="dialog-vbox5">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">2</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="dialog-action_area5">
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <object class="GtkButton" id="btn_databases_close">
+ <property name="label" translatable="yes">Close</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_action_appearance">False</property>
+ <signal name="clicked" handler="_on_databases_close_clicked" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="box3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkLabel" id="label4">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">
+Cell ID Databases
+</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="cb_google">
+ <property name="label" translatable="yes">Google Mobile Maps Service</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_action_appearance">False</property>
+ <property name="xalign">0</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="cb_opencellid">
+ <property name="label" translatable="yes">OpenCellID Webservice</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_action_appearance">False</property>
+ <property name="xalign">0</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="box4">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkCheckButton" id="cb_cellid_database_local">
+ <property name="label" translatable="yes">Use local database: </property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_action_appearance">False</property>
+ <property name="xalign">0</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="te_cellid_database">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">•</property>
+ <property name="invisible_char_set">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="btn_web_services">
+ <property name="label" translatable="yes">Re-run Web Services</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_action_appearance">False</property>
+ <signal name="clicked" handler="_on_web_services_clicked" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHSeparator" id="separator1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">5</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label5">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">
+Local Area Database
+</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">6</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="box5">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkLabel" id="label6">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Current Location: </property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="te_current_location">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">•</property>
+ <property name="invisible_char_set">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">7</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="btn_localdb_add">
+ <property name="label" translatable="yes">Add current Scan to Location/
+ Create Location from Scan</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_action_appearance">False</property>
+ <signal name="clicked" handler="_on_localdb_add_clicked" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">8</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHSeparator" id="separator2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">9</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="0">btn_databases_close</action-widget>
+ </action-widgets>
+ </object>
<object class="GtkWindow" id="detail_view">
<property name="can_focus">False</property>
<property name="title" translatable="yes">Details</property>
@@ -498,6 +749,7 @@
<property name="label" translatable="yes">Databases</property>
<property name="use_underline">True</property>
<property name="icon_name">network-server</property>
+ <signal name="clicked" handler="_on_databases_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
@@ -696,7 +948,6 @@
<object class="GtkTreeView" id="tv_stations">
<property name="visible">True</property>
<property name="can_focus">True</property>
- <property name="hscroll_policy">natural</property>
<signal name="select-cursor-row" handler="_on_tv_stations_clicked" swapped="no"/>
<child internal-child="selection">
<object class="GtkTreeSelection" id="treeview-selection"/>
diff --git a/Src/PyCatcher/src/CellIDDatabase.py b/Src/PyCatcher/src/cellIDDatabase.py
index 2471a5a..d12ce60 100644
--- a/Src/PyCatcher/src/CellIDDatabase.py
+++ b/Src/PyCatcher/src/cellIDDatabase.py
@@ -3,10 +3,19 @@ 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':'262'
+ 'Germany':'de'
}
Provider = {
@@ -17,7 +26,7 @@ class Translator:
}
MCC = {
- 262:'de'
+ 'Germany':262
}
class CellIDDBStatus:
@@ -27,18 +36,16 @@ class CellIDDBStatus:
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)
+class CellIDDatabase:
- def fetch_id_from_OpenCellID(self,cid, lac, mcc, mnc):
+ def fetch_id_from_OpenCellID(self,cid, lac, country, provider):
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)
+ 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)
@@ -65,8 +72,10 @@ class CellIDDatabaseFetcher:
def fetch_id_from_Google(self, cid, lac, country):
+ latitude = 0
+ longitude = 0
device = "Motorola C123"
- country = Translator.MCC[country]
+ country = Translator.Country[country]
b_string = pack('>hqh2sh13sh5sh3sBiiihiiiiii',
21, 0,
len(country), country,
@@ -87,10 +96,38 @@ class CellIDDatabaseFetcher:
try:
bytes = http.file.read()
(a, b,errorCode, latitude, longitude, c, d, e) = unpack(">hBiiiiih",bytes)
- latitude = latitude / 1000000.0
- longitude = longitude / 1000000.0
+ latitude /= 1000000.0
+ longitude /= 1000000.0
status = CellIDDBStatus.CONFIRMED
except:
status = CellIDDBStatus.NOT_IN_DB
- return status, latitude, longitude \ No newline at end of file
+ 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
index 102408a..3cded04 100644
--- a/Src/PyCatcher/src/LocalAreaDatabse.py
+++ b/Src/PyCatcher/src/localAreaDatabse.py
@@ -1,38 +1,26 @@
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
-
-
+from settings import Database_path
class LocalAreaDatabase:
def __init__(self):
self._connection = None
self._cursor = None
- def load_or_create_database(self, path):
+ 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:
- print 'file has been created'
self._create_base_table()
- else:
- print 'connected to existing'
def _create_base_table(self):
sql = '''CREATE TABLE basestations(
@@ -59,12 +47,15 @@ class LocalAreaDatabase:
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
+
+ current_rx = int(base_station.rxlev)
+
+ if current_rx < old_rmin:
+ rmin = current_rx
else:
rmin = old_rmin
- if base_station.rxlev > old_rmax:
- rmax = base_station.rxlev
+ if current_rx > old_rmax:
+ rmax = current_rx
else:
rmax = old_rmax
sightings = old_sightings + 1
@@ -74,6 +65,8 @@ class LocalAreaDatabase:
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:
@@ -89,9 +82,12 @@ class LocalAreaDatabase:
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])
+ self._alter_station(base_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
+ 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