1717]
1818
1919
20+ class NmapTask (object ):
21+ """
22+ NmapTask is a internal class used by process. Each time nmap
23+ starts a new task during the scan, a new class will be instanciated.
24+ Classes examples are: "Ping Scan", "NSE script", "DNS Resolve",..
25+ To each class an estimated time to complete is assigned and updated
26+ at least every second within the NmapProcess.
27+ A property NmapProcess.current_task points to the running task at
28+ time T and a dictionnary NmapProcess.tasks with "task name" as key
29+ is built during scan execution
30+ """
31+ def __init__ (self , name , starttime = 0 , extrainfo = '' ):
32+ self .name = name
33+ self .etc = 0
34+ self .progress = 0
35+ self .percent = 0
36+ self .remaining = 0
37+ self .status = 'started'
38+ self .starttime = starttime
39+ self .endtime = 0
40+ self .extrainfo = extrainfo
41+ self .updated = 0
42+
43+
2044class NmapProcess (Thread ):
2145 """
2246 NmapProcess is a class which wraps around the nmap executable.
@@ -95,12 +119,12 @@ def _run_init(self):
95119 self .__starttime = 0
96120 self .__endtime = 0
97121 self .__version = ''
98- self .__progress = 0
99- self .__etc = 0
100122 self .__elapsed = ''
101123 self .__summary = ''
102124 self .__stdout = ''
103125 self .__stderr = ''
126+ self .__current_task = ''
127+ self .__nmap_tasks = {}
104128
105129 def _whereis (self , program ):
106130 """
@@ -286,12 +310,17 @@ def ioreader_routine(proc_stdout, io_queue, data_pushed, producing):
286310 self .__state = self .CANCELLED
287311 elif self .rc == 0 :
288312 self .__state = self .DONE
289- self .__progress = 100
313+ if self .current_task :
314+ self .__nmap_tasks [self .current_task .name ].progress = 100
290315 else :
291316 self .__state = self .FAILED
292317 return self .rc
293318
294319 def run_background (self ):
320+ """
321+ run nmap scan in background as a thread.
322+ For privileged scans, consider NmapProcess.sudo_run_background()
323+ """
295324 super (NmapProcess , self ).start ()
296325
297326 def is_running (self ):
@@ -357,12 +386,42 @@ def __process_event(self, eventdata):
357386 edomdoc = pulldom .parseString (eventdata )
358387 for xlmnt , xmlnode in edomdoc :
359388 if xlmnt is not None and xlmnt == pulldom .START_ELEMENT :
360- if (xmlnode .nodeName == 'taskprogress' and
389+ if (xmlnode .nodeName == 'taskbegin' and
390+ xmlnode .attributes .keys ()):
391+ xt = xmlnode .attributes
392+ taskname = xt ['task' ].value
393+ starttime = xt ['time' ].value
394+ xinfo = ''
395+ if xt .has_key ('extrainfo' ):
396+ xinfo = xt ['extrainfo' ].value
397+ newtask = NmapTask (taskname , starttime , xinfo )
398+ self .__nmap_tasks [newtask .name ] = newtask
399+ self .__current_task = newtask .name
400+ rval = True
401+ elif (xmlnode .nodeName == 'taskend' and
361402 xmlnode .attributes .keys ()):
362- percent_done = xmlnode .attributes ['percent' ].value
363- etc_done = xmlnode .attributes ['etc' ].value
364- self .__progress = percent_done
365- self .__etc = etc_done
403+ xt = xmlnode .attributes
404+ tname = xt ['task' ].value
405+ xinfo = ''
406+ self .__nmap_tasks [tname ].endtime = xt ['time' ].value
407+ if xt .has_key ('extrainfo' ):
408+ xinfo = xt ['extrainfo' ].value
409+ self .__nmap_tasks [tname ].extrainfo = xinfo
410+ self .__nmap_tasks [tname ].status = "ended"
411+ rval = True
412+ elif (xmlnode .nodeName == 'taskprogress' and
413+ xmlnode .attributes .keys ()):
414+ xt = xmlnode .attributes
415+ tname = xt ['task' ].value
416+ percent = xt ['percent' ].value
417+ etc = xt ['etc' ].value
418+ remaining = xt ['remaining' ].value
419+ updated = xt ['time' ].value
420+ self .__nmap_tasks [tname ].percent = percent
421+ self .__nmap_tasks [tname ].progress = percent
422+ self .__nmap_tasks [tname ].etc = etc
423+ self .__nmap_tasks [tname ].remaining = remaining
424+ self .__nmap_tasks [tname ].updated = updated
366425 rval = True
367426 elif (xmlnode .nodeName == 'nmaprun' and
368427 xmlnode .attributes .keys ()):
@@ -465,13 +524,13 @@ def summary(self):
465524 return self .__summary
466525
467526 @property
468- def etc (self ):
527+ def tasks (self ):
469528 """
470- Accessor for estimated time to completion
529+ Accessor returning for the list of tasks ran during nmap scan
471530
472- :return: estimated time to completion
531+ :return: dict of NmapTask object
473532 """
474- return self .__etc
533+ return self .__nmap_tasks
475534
476535 @property
477536 def version (self ):
@@ -483,14 +542,41 @@ def version(self):
483542 """
484543 return self .__version
485544
545+ @property
546+ def current_task (self ):
547+ """
548+ Accessor for the current NmapTask beeing run
549+
550+ :return: NmapTask or None if no task started yet
551+ """
552+ rval = None
553+ if len (self .__current_task ):
554+ rval = self .tasks [self .__current_task ]
555+ return rval
556+
557+ @property
558+ def etc (self ):
559+ """
560+ Accessor for estimated time to completion
561+
562+ :return: estimated time to completion
563+ """
564+ rval = 0
565+ if self .current_task :
566+ rval = self .current_task .etc
567+ return rval
568+
486569 @property
487570 def progress (self ):
488571 """
489572 Accessor for progress status in percentage
490573
491574 :return: percentage of job processed.
492575 """
493- return self .__progress
576+ rval = 0
577+ if self .current_task :
578+ rval = self .current_task .progress
579+ return rval
494580
495581 @property
496582 def rc (self ):
@@ -524,13 +610,16 @@ def stderr(self):
524610
525611def main ():
526612 def mycallback (nmapscan = None ):
527- if nmapscan .is_running ():
528- print ("Progress: {0}% - ETC: {1}" ).format (nmapscan .progress ,
529- nmapscan .etc )
530- nm = NmapProcess ("localhost" , options = "-sV" ,
613+ if nmapscan .is_running () and nmapscan .current_task :
614+ ntask = nmapscan .current_task
615+ print "Task {0} ({1}): ETC: {2} DONE: {3}%" .format (ntask .name ,
616+ ntask .status ,
617+ ntask .etc ,
618+ ntask .progress )
619+ nm = NmapProcess ("scanme.nmap.org" ,
620+ options = "-A" ,
531621 event_callback = mycallback )
532622 rc = nm .run ()
533-
534623 if rc == 0 :
535624 print ("Scan started at {0} nmap version: {1}" ).format (nm .starttime ,
536625 nm .version )
0 commit comments