This is an automated email from the git hooks/post-receive script. New commit to branch develop in repository mum. See http://git.chorem.org/mum.git commit 2488f0fd400c522e27e563830ca7d4b4e1767edf Author: Alexis Guilbaud <guilbaud@codelutin.com> Date: Wed Feb 25 11:16:31 2015 +0100 nmap detection can now be launch with a hostname + exception if the host doesn't exists handled --- app/app.py | 33 ++++++------- app/module_loader.py | 64 +++++++++++++++---------- app/modules/HostNotFoundException.py | 13 +++++ app/modules/detection_modules/nmap_detection.py | 28 +++++++++-- views/scan.html | 2 +- 5 files changed, 89 insertions(+), 51 deletions(-) diff --git a/app/app.py b/app/app.py index 4fb4db3..8fcddfe 100755 --- a/app/app.py +++ b/app/app.py @@ -28,24 +28,25 @@ ERROR = "40" # Pour lancer la detection nmap avec un nouveau thread class ThreadDetect(threading.Thread): - def __init__(self, ip_range, ws): + def __init__(self, param, ws): threading.Thread.__init__(self) - self.ip_range = ip_range + self.param = param self.ws = ws def run(self): db = module_loader.load_db() conn_mod_list = module_loader.get_conection_modules_list() - scanned_ip = module_loader.run_nmap_detection(self.ip_range, db, self.ws, + scanned_ip = module_loader.run_nmap_detection(self.param, db, self.ws, module_loader.get_conection_modules_list(), module_loader.get_info_mod_monitoring()) - self.ws.send(json.dumps({SUCCESS_MODULE: scanned_ip})) - # now launching full detection - for ip in json.loads(scanned_ip): - conn = module_loader.load_conn("ssh", ip, "aguilbaud", "/home/aguilbaud/.ssh/id_rsa") - module_loader.run_all_detection_modules(db.get_host_os(ip), conn, db, self.ws) - module_loader.run_all_monitoring_modules("unix", conn, db, self.ws) - print "done" + if scanned_ip is not None: + self.ws.send(json.dumps({SUCCESS_MODULE: scanned_ip})) + # now launching full detection + for ip in json.loads(scanned_ip): + conn = module_loader.load_conn("ssh", ip, "aguilbaud", "/home/aguilbaud/.ssh/id_rsa") + module_loader.run_all_detection_modules(db.get_host_os(ip), conn, db, self.ws) + module_loader.run_all_monitoring_modules("unix", conn, db, self.ws) + print "first monitoring done" @route('/') @@ -95,15 +96,9 @@ def angular(): # Lancement de la detection apres reception d'une plage d'ip -def start_first_detection(ip_range, ws): - # Verification que la plage d'ip est bien formatee - if re.search('^\d{1,3}(-\d{1,3})?[.]\d{1,3}(-\d{1,3})?[.]\d{1,3}(-\d{1,3})?[.]\d{1,3}(-\d{1,3})?$', ip_range): - # Si oui on lance la detection avec le module nmap_detection - t = ThreadDetect(ip_range, ws) - t.start() - else: - # Si non, on envoie un message d'erreur - ws.send(json.dumps({ERROR: "Ip range incorrectly formatted"})) +def start_first_detection(param, ws): + t = ThreadDetect(param, ws) + t.start() @error(404) def error404(error): diff --git a/app/module_loader.py b/app/module_loader.py index c8a0951..d79199f 100644 --- a/app/module_loader.py +++ b/app/module_loader.py @@ -4,10 +4,12 @@ import modules.connection_modules import modules.detection_modules import modules.monitoring_modules import modules.storage_modules -import modules.ModuleNotCompatibleException as moduleNotCompatibleException -import modules.CommandNotFoundException as commandNotFoundException +import modules.ModuleNotCompatibleException +import modules.CommandNotFoundException +import modules.HostNotFoundException import json +import re """ Loads dynamically modules from packages connection_modules, detection_modules, monitoring_modules, storage_modules. @@ -24,17 +26,27 @@ def load_db(): return db_instance -def run_nmap_detection(ip_range, db, ws, list_mod_conn, dict_mod_monitoring): +def run_nmap_detection(param, db, ws, list_mod_conn, dict_mod_monitoring): """ Instanciates the nmap_detection module from detection_modules, and runs the detection. - :param ip_range: addresses to execute the nmap detection + :param param: parameter to put in nmap command. can be a hostname, a ip address or a ip range :param db: an instance of a database module :param ws: a websocket connection :return: a list containing the IP adresses checked """ nmap_mod = __import__("modules.detection_modules.nmap_detection", fromlist=modules.detection_modules) - nmap_mod_instance = getattr(nmap_mod, "nmap_detection")(db, ws, list_mod_conn, dict_mod_monitoring) - return nmap_mod_instance.check_ip_range(ip_range) + nmap_mod_instance = getattr(nmap_mod, "nmap_detection")(db, ws, list_mod_conn, dict_mod_monitoring, + modules.HostNotFoundException) + try: + if re.search('^\d{1,3}(-\d{1,3})?[.]\d{1,3}(-\d{1,3})?[.]\d{1,3}(-\d{1,3})?[.]\d{1,3}(-\d{1,3})?$', param): + ip_range = nmap_mod_instance.check_ip_range(param) + else: + ip_range = nmap_mod_instance.launch_detection_with_hostname(param) + return ip_range + except modules.HostNotFoundException.HostNotFoundException as hnfe: + print hnfe.__str__() + ws.send(json.dumps({"40": hnfe.__str__()})) + return None def load_conn(conn_name, addr_host, username, key_location): # /home/aguilbaud/.ssh/id_rsa @@ -46,7 +58,7 @@ def load_conn(conn_name, addr_host, username, key_location): # /home/aguilbau :return: the instance of connection module created """ conn = __import__("modules.connection_modules." + conn_name, fromlist=modules.connection_modules) - conn_instance = getattr(conn, conn_name)(addr_host, username, key_location, commandNotFoundException) + conn_instance = getattr(conn, conn_name)(addr_host, username, key_location, modules.CommandNotFoundException) return conn_instance @@ -66,10 +78,10 @@ def run_all_detection_modules(os, conn, db, ws): mod_instance = getattr(mod, mod_name)(conn, db) # on appelle le constructeur try: mod_instance.run_detection() - except commandNotFoundException as cnfe: - print cnfe.__str__ + except modules.CommandNotFoundException.CommandNotFoundException as cnfe: + print cnfe.__str__() if ws is not None: - ws.send(json.dumps({"40": cnfe.__str__})) + ws.send(json.dumps({"40": cnfe.__str__()})) def run_all_monitoring_modules(os, conn, db, ws): @@ -84,18 +96,18 @@ def run_all_monitoring_modules(os, conn, db, ws): __import__("modules.monitoring_modules." + os) pack_mod_os = __import__("modules.monitoring_modules." + os, fromlist=modules.monitoring_modules.__all__) for mod_name in pack_mod_os.__all__: - mod = __import__ ("modules.monitoring_modules." + os + "." + mod_name, fromlist=modules.monitoring_modules.unix.__all__) # on charge le module - mod_instance = getattr(mod, mod_name)(conn, db, moduleNotCompatibleException) # on appelle le constructeur + mod = __import__("modules.monitoring_modules." + os + "." + mod_name, fromlist=modules.monitoring_modules.unix.__all__) # on charge le module + mod_instance = getattr(mod, mod_name)(conn, db, modules.ModuleNotCompatibleException) # on appelle le constructeur try: mod_instance.check() - except moduleNotCompatibleException as mnce: - print mnce.__str__ + except modules.ModuleNotCompatibleException.ModuleNotCompatibleException as mnce: + print mnce.__str__() if ws is not None: - ws.send(json.dumps({"40": mnce.__str__})) - except commandNotFoundException as cnfe: - print cnfe.__str__ + ws.send(json.dumps({"40": mnce.__str__()})) + except modules.CommandNotFoundException.CommandNotFoundException as cnfe: + print cnfe.__str__() if ws is not None: - ws.send(json.dumps({"40": cnfe.__str__})) + ws.send(json.dumps({"40": cnfe.__str__()})) def run_one_monitoring_module(mod_name, os, conn, db, ws): @@ -110,17 +122,17 @@ def run_one_monitoring_module(mod_name, os, conn, db, ws): """ __import__("modules.monitoring_modules." + os) mod = __import__("modules.monitoring_modules." + os + "." + mod_name, fromlist=modules.monitoring_modules.unix.__all__) - mod_instance = getattr(mod, mod_name)(conn, db, moduleNotCompatibleException) # on appelle le constructeur + mod_instance = getattr(mod, mod_name)(conn, db, modules.ModuleNotCompatibleException) # on appelle le constructeur try: mod_instance.check() - except moduleNotCompatibleException as mnce: - print mnce.__str__ + except modules.ModuleNotCompatibleException.ModuleNotCompatibleException as mnce: + print mnce.__str__() if ws is not None: - ws.send(json.dumps({"40": mnce.__str__})) - except commandNotFoundException as cnfe: - print cnfe.__str__ + ws.send(json.dumps({"40": mnce.__str__()})) + except modules.CommandNotFoundException.CommandNotFoundException as cnfe: + print cnfe.__str__() if ws is not None: - ws.send(json.dumps({"40": cnfe.__str__})) + ws.send(json.dumps({"40": cnfe.__str__()})) def get_info_mod_monitoring(): @@ -158,5 +170,5 @@ def create_global_conf(db): """ dict_mod = {} for os in modules.monitoring_modules.__all__: - dict_mod[os] = get_info_mod_monitoring(os) + dict_mod[os] = get_info_mod_monitoring() db.create_global_conf(dict_mod) \ No newline at end of file diff --git a/app/modules/HostNotFoundException.py b/app/modules/HostNotFoundException.py new file mode 100644 index 0000000..505e7cc --- /dev/null +++ b/app/modules/HostNotFoundException.py @@ -0,0 +1,13 @@ +__author__ = 'aguilbaud' + +""" +Raised if the address or hostname passed to nmap cannot have been found +""" + + +class HostNotFoundException(Exception): + def __init__(self, addr_host): + self.addr_host = addr_host + + def __str__(self): + return "Host '" + self.addr_host + "' seems to not exist." \ No newline at end of file diff --git a/app/modules/detection_modules/nmap_detection.py b/app/modules/detection_modules/nmap_detection.py index 3b4b6ec..fdb04fd 100644 --- a/app/modules/detection_modules/nmap_detection.py +++ b/app/modules/detection_modules/nmap_detection.py @@ -6,12 +6,13 @@ import json class nmap_detection: - def __init__(self, db, ws, list_mod_conn, dict_mod_monitoring): + def __init__(self, db, ws, list_mod_conn, dict_mod_monitoring, hnfe): self.db = db self.ws = ws self.scanned_ip = [] self.list_mod_conn = list_mod_conn self.dict_mod_monitoring = dict_mod_monitoring + self.HostNotFoundException = hnfe # function for splitting the different ranges of the IP adress # launch the nmap detection of each ip under this range @@ -96,6 +97,22 @@ class nmap_detection: except pexpect.ExceptionPexpect: self.ws.send(json.dumps({"40": "nmap command not avaliable on server"})) + def launch_detection_with_hostname(self, hostname): + self.ws.send(json.dumps({"30": "Scanning host : " + hostname})) + try: + child = pexpect.spawn('nmap', ['-A', '-Pn', hostname, '-oX', 'res.xml']) + while child.isalive(): + child.expect('Completed', timeout=None) + except pexpect.EOF: + #try: + self.parse_res(hostname) + return json.dumps(self.scanned_ip) + #except: + # self.ws.send(json.dumps({"40": "Database error"})) + except pexpect.TIMEOUT: + self.ws.send(json.dumps({"40": "Timeout on nmap execution"})) + except pexpect.ExceptionPexpect: + self.ws.send(json.dumps({"40": "nmap command not avaliable on server"})) # parse the xml result to keep only interesting values # save directly it on the database @@ -107,9 +124,10 @@ class nmap_detection: # get every <host> of the collection hosts = collection.getElementsByTagName("host") - # if host cannot have been detected, adds it empty + # if host cannot have been detected, throws an exception if hosts == []: - self.db.add_host(ip, {}) + exception_inst = getattr(self.HostNotFoundException, "HostNotFoundException")(ip) + raise exception_inst # Get the nodes of each <host> and recuperaton of their attributes # JSON = dictionary list @@ -147,5 +165,5 @@ class nmap_detection: dict_host['openports'] = list_dict_port # the host have its IP for ID on the db self.db.add_host(dict_host['addr'], json.dumps(dict_host), self.list_mod_conn, self.dict_mod_monitoring) - pexpect.run("rm -f res.xml") - self.scanned_ip.append(ip) \ No newline at end of file + self.scanned_ip.append(dict_host['addr']) + pexpect.run("rm -f res.xml") \ No newline at end of file diff --git a/views/scan.html b/views/scan.html index 0618a35..4965ce4 100644 --- a/views/scan.html +++ b/views/scan.html @@ -3,7 +3,7 @@ <h1 class="page-header">Scan for new machines</h1> <div ng-show="validated == false" class="ng-hide"> <form class="form-inline" ng_submit="post_val()"> - <label for="input_ip_range">IP range to scan (example : 198.116.0.1-10)</label> + <label for="input_ip_range">Enter a hostname, a single IP or an IP range to scan (example : 198.116.0.1-10)</label> <input type="ip_range" class="form-control" id="input_ip_range" ng-model="ip_range"/> <button type="submit" class="btn btn-primary" ng-click="validated = true">Scan now</button> </form> -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.