root/trunk/umit/core/NmapParser.py @ 5555

Revision 5096, 36.9 kB (checked in by luis, 4 years ago)

Adding trace support in NmapParser?. Fixing #339

Line 
1# -*- coding: utf-8 -*-
2#
3# Copyright (C) 2005-2006 Insecure.Com LLC.
4# Copyright (C) 2007-2008 Adriano Monteiro Marques
5#
6# Author: Adriano Monteiro Marques <adriano@umitproject.org>
7#         Guilherme Polo <ggpolo@gmail.com>
8#         João Paulo de Souza Medeiros <ignotus21@gmail.com>
9#         Luis A. Bastiao Silva <luis.kop@gmail.com>
10#
11# This program is free software; you can redistribute it and/or modify
12# it under the terms of the GNU General Public License as published by
13# the Free Software Foundation; either version 2 of the License, or
14# (at your option) any later version.
15#
16# This program is distributed in the hope that it will be useful,
17# but WITHOUT ANY WARRANTY; without even the implied warranty of
18# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19# GNU General Public License for more details.
20#
21# You should have received a copy of the GNU General Public License
22# along with this program; if not, write to the Free Software
23# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24
25import re
26import time
27import calendar
28
29from xml.sax import make_parser
30from xml.sax.handler import ContentHandler
31from xml.sax.saxutils import XMLGenerator
32from xml.sax.xmlreader import AttributesImpl
33
34UNKNOWN = "Unknown"
35
36class AttributesImplDict(dict, AttributesImpl):
37    """Use this for displaying AttributesImpl just like a dict."""
38
39class HostInfo(object):
40    def __init__(self, host_id):
41        self.osclass = []
42        self.osmatch = []
43        self.osfingerprint = []
44        self.portused = []
45        self.ports = []
46        self.extraports = []
47        self.tcpsequence = {}
48        self.hostnames = []
49        self.tcptssequence = {}
50        self.ipidsequence = {}
51        self.trace = {'port': '', 'proto': '', 'hop': []}
52        self.status = {}
53        self.address = []
54        self.hostscript = []
55
56        # Umit extension
57        self.id = host_id
58        self.comment = ''
59
60        # XXX this structure it not being used yet.
61        self.nmap_host = {
62                'status': {'state': '', 'reason': ''},
63                'smurf': {'responses': ''},
64                'times': {'to': '', 'srtt': '', 'rttvar': ''},
65                'hostscript': [],
66                'distance': {'value': ''},
67                'trace': {'port': '', 'proto': '', 'hop': []},
68                'address': [],
69                'hostnames': [],
70                'ports': [],
71                'uptime': {'seconds': '', 'lastboot': ''},
72                'tcpsequence': {'index': '', 'values': '', 'class': ''},
73                'tcptssequence': {'values': '', 'class': ''},
74                'ipidsequence': {'values': '', 'class': ''},
75                'os': {}
76                }
77
78    # Host ID
79    def get_id(self):
80        try:
81            return self._id
82        except AttributeError:
83            raise Exception("Id is not set yet.")
84
85    def set_id(self, host_id):
86        try:
87            self._id = int(host_id)
88        except (TypeError, ValueError):
89            raise Exception("Invalid id! It must represent an integer, "
90                    "received %r" % host_id)
91
92    # VENDOR
93    def get_vendor(self):
94        vendor = UNKNOWN
95        for address in self.address:
96            if address['addrtype'] != 'mac':
97                continue
98            try:
99                vendor = address['vendor']
100                break
101            except KeyError:
102                pass
103
104        return vendor
105
106    # TRACEROUTE
107    def get_hop_by_ttl(self, ttl):
108        for hop in self.trace['hop']:
109            if ttl == int(hop['ttl']):
110                return hop
111        return None
112
113    def get_number_of_hops(self):
114        count = 0
115        for hop in self.trace['hop']:
116            if int(hop['ttl']) > count:
117                count = int(hop['ttl'])
118        return count
119
120    # UPTIME
121    # FORMAT: {"seconds":"", "lastboot":""}
122    def set_uptime(self, uptime):
123        self._uptime = uptime
124
125    def get_uptime(self):
126        if self._uptime:
127            return self._uptime
128
129        # Avoid empty dict return
130        return {'seconds': '', 'lastboot': ''}
131
132    # HOSTNAME
133    def get_hostname(self):
134        hostname = []
135
136        if self.hostnames:
137            try:
138                hostname.append(self.hostnames[0]['name'])
139            except KeyError:
140                pass
141
142        for addr in self.address:
143            if addr['addrtype'] == 'mac':
144                format = '(%s)'
145            else:
146                format = '%s'
147            hostname.append(format % addr['addr'])
148
149        return ' '.join(hostname) or UNKNOWN
150
151    def get_open_ports(self):
152        open_count = 0
153        for port in self.ports:
154            if port['state'] == 'open':
155                open_count += 1
156
157        return open_count
158
159    def get_filtered_ports(self):
160        filtered_count = 0
161        for port in self.ports:
162            if port['state'] == 'filtered':
163                filtered_count += 1
164        for extra in self.extraports:
165            if extra['state'] == 'filtered':
166                filtered_count += int(extra['count'])
167
168        return filtered_count
169
170    def get_closed_ports(self):
171        closed_count = 0
172        for port in self.ports:
173            if port['state'] == 'closed':
174                closed_count += 1
175        for extra in self.extraports:
176            if extra['state'] == 'closed':
177                closed_count += int(extra['count'])
178
179        return closed_count
180
181    def get_scanned_ports(self):
182        scanned = len(self.ports)
183        for extra in self.extraports:
184            scanned += int(extra['count'])
185
186        return scanned
187
188    def get_services(self):
189        services = []
190        for port in self.ports:
191            services.append({
192                'service_name': port.get('name', UNKNOWN),
193                'portid': port.get('portid', ''),
194                'service_version': port.get('version', UNKNOWN),
195                'service_product': port.get('product', ''),
196                'port_state': port.get('state', UNKNOWN),
197                'protocol': port.get('protocol', '')})
198        return services
199
200    def _get_status_state(self):
201        return self.status.get('state', '')
202
203    def _get_type_address(self, addrtype):
204        for addr in self.address:
205            if addr['addrtype'] == addrtype:
206                return addr
207
208    def _get_ipv4(self):
209        return self._get_type_address('ipv4')
210
211    def _get_ipv6(self):
212        return self._get_type_address('ipv6')
213
214    def _get_mac(self):
215        return self._get_type_address('mac')
216
217    # Properties
218    id = property(get_id, set_id)
219    uptime = property(get_uptime, set_uptime)
220    services = property(get_services)
221    state = property(_get_status_state, doc="Get the host status state")
222    ip = property(_get_ipv4, doc="Return the first ipv4 address found")
223    ipv6 = property(_get_ipv6, doc="Return the first ipv6 address found")
224    mac = property(_get_mac, doc="Return the first mac address found")
225
226    _uptime = {}
227
228
229class ParserBasics(object):
230    def __init__ (self):
231        self.nmap = {
232                'nmaprun': {},
233                'runstats': {
234                    'finished': {},
235                    'hosts': {'up': '', 'down': '', 'total': ''}
236                    },
237                'verbose': {'level': ''},
238                'debugging': {'level': ''},
239                'scaninfo': [],
240                'taskbegin': [],
241                'taskprogress': [],
242                'taskend': [],
243                #'host': [],
244                'hosts': []
245                }
246
247    def set_host_comment(self, host_id, comment):
248        for host in self.nmap['hosts']:
249            if host.id == host_id:
250                host.comment = comment
251                break
252        else:
253            raise Exception("Comment could not be saved! Host not "
254                    "found at NmapParser!")
255
256    def get_host_comment(self, host_id):
257        for host in self.nmap.get('hosts', []):
258            if host.id == host_id:
259                return host.comment
260        else:
261            raise Exception("Comment could not be saved! Host not "
262                    "found at NmapParser!")
263
264    def get_profile(self):
265        return self.nmap['nmaprun'].get('profile', '')
266
267    def set_profile(self, profile):
268        self.nmap['nmaprun']['profile'] = profile
269
270    def get_profile_name(self):
271        return self.nmap['nmaprun'].get('profile_name', '')
272
273    def set_profile_name(self, name):
274        self.nmap['nmaprun']['profile_name'] = name
275
276    def get_profile_description(self):
277        return self.nmap['nmaprun'].get('description', '')
278
279    def set_profile_description(self, description):
280        self.nmap['nmaprun']['description'] = description
281
282    def get_profile_hint(self):
283        return self.nmap['nmaprun'].get('hint', '')
284
285    def set_profile_hint(self, hint):
286        self.nmap['nmaprun']['hint'] = hint
287
288    def get_profile_annotation(self):
289        return self.nmap['nmaprun'].get('annotation', '')
290
291    def set_profile_annotation(self, annotation):
292        self.nmap['nmaprun']['annotation'] = annotation
293
294    def get_profile_options(self):
295        options = self.nmap['nmaprun'].get('options', '')
296        if isinstance(options, list):
297            return ','.join(options)
298        elif isinstance(options, basestring):
299            return options
300
301    def set_profile_options(self, options):
302        if isinstance(options, (list, basestring)):
303            self.nmap['nmaprun']['options'] = options
304        elif isinstance(options, dict):
305            self.nmap['nmaprun']['options'] = options.keys()
306        else:
307            raise Exception("Profile option error: wrong argument format! "
308                    "Need a string, list or dict.")
309
310    def get_target(self):
311        return self.nmap['nmaprun'].get('target', '')
312
313    def set_target(self, target):
314        self.nmap['nmaprun']['target'] = target
315
316    def get_nmap_output(self):
317        return self.nmap['nmaprun'].get('nmap_output', '')
318
319    def set_nmap_output(self, nmap_output):
320        self.nmap['nmaprun']['nmap_output'] = nmap_output
321
322    def get_debugging_level (self):
323        return self.nmap['debugging'].get('level', '')
324
325    def set_debugging_level(self, level):
326        self.nmap['debugging']['level'] = level
327
328    def set_debugging(self, debug):
329        self.nmap['debugging'] = debug
330
331    def get_verbose_level (self):
332        return self.nmap['verbose'].get('level', '')
333
334    def set_verbose_level(self, level):
335        self.nmap['verbose']['level'] = level
336
337    def set_verbose(self, verbose):
338        self.nmap['verbose'] = verbose
339
340    def get_scaninfo(self):
341        return self.nmap.get('scaninfo', [])
342
343    def set_scaninfo(self, info):
344        self.nmap['scaninfo'] = info
345
346    def append_scaninfo(self, info):
347        self.nmap['scaninfo'].append(info)
348
349    def get_services_scanned(self):
350        services = [scan['services'] for scan in self.nmap.get('scaninfo', [])]
351        return ','.join(services)
352
353    def get_nmap_command(self):
354        return self._verify_output_options(self.nmap['nmaprun'].get('args', ''))
355
356    def set_nmap_command(self, command):
357        self.nmap['nmaprun']['args'] = self._verify_output_options(command)
358
359    def get_scan_type(self):
360        return [stype['type'] for stype in self.nmap.get('scaninfo', [])]
361
362    def get_protocol (self):
363        return [proto['protocol'] for proto in self.nmap.get('scaninfo', [])]
364
365    def get_num_services(self):
366        num = 0
367        for sinfo in self.nmap.get('scaninfo', []):
368            num += int(sinfo['numservices'])
369
370        return num
371
372    def get_date(self):
373        epoch = int(self.nmap['nmaprun'].get('start', '0'))
374        return time.localtime(epoch)
375
376    def get_start(self):
377        return self.nmap['nmaprun'].get('start', '0')
378
379    def set_start(self, start):
380        self.nmap['nmaprun']['start'] = start
381
382    def set_date(self, date):
383        if type(date) == type(int):
384            self.nmap['nmaprun']['start'] = date
385        else:
386            raise Exception("Wrong date format. Date should be saved "
387                    "in epoch format!")
388
389    def get_open_ports(self):
390        open_count = 0
391        for host in self.nmap.get('hosts', []):
392            open_count += host.get_open_ports()
393
394        return open_count
395
396    def get_filtered_ports(self):
397        filtered_count = 0
398        for host in self.nmap.get('hosts', []):
399            filtered_count += host.get_filtered_ports()
400
401        return filtered_count
402
403    def get_closed_ports(self):
404        closed_count = 0
405        for host in self.nmap['hosts']:
406            closed_count += host.get_closed_ports()
407
408        return closed_count
409
410    def get_formated_date(self):
411        date = self.get_date()
412        return '%s %s, %s - %s:%s' % (calendar.month_name[date[1]],
413                                      str(date[2]),
414                                      str(date[0]),
415                                      str(date[3]).zfill(2),
416                                      str(date[4]).zfill(2))
417
418    def get_scanner(self):
419        return self.nmap['nmaprun'].get('scanner', '')
420
421    def set_scanner(self, scanner):
422        self.nmap['nmaprun']['scanner'] = scanner
423
424    def get_scanner_version (self):
425        return self.nmap['nmaprun'].get('version', '')
426
427    def set_scanner_version(self, version):
428        self.nmap['nmaprun']['version'] = version
429
430    ## Addresses
431    def get_type_addresses(self, addrtype):
432        addresses = []
433        for host in self.nmap.get('hosts', []):
434            for addr in host.address:
435                if addr['addrtype'] == addrtype:
436                    addresses.append(addr['addr'])
437        return addresses
438
439    # IPv4
440    def get_ipv4_addresses(self):
441        return self.get_type_addresses('ipv4')
442
443    # MAC
444    def get_mac_addresses(self):
445        return self.get_type_addresses('mac')
446
447    # IPv6
448    def get_ipv6_addresses(self):
449        return self.get_type_addresses('ipv6')
450
451
452    def get_hostnames(self):
453        hostnames = []
454        for host in self.nmap.get('hosts', []):
455            hostnames.extend(host.hostnames)
456        return hostnames
457
458    def get_ports(self):
459        ports = []
460        for host in self.nmap.get('hosts', []):
461            ports.append(host.ports)
462
463        return ports
464
465    def get_hosts(self):
466        return self.nmap.get('hosts', None)
467
468    def get_runstats(self):
469        return self.nmap.get('runstats', None)
470
471    def set_runstats(self, stats):
472        self.nmap['runstats'] = stats
473
474    def get_hosts_down(self):
475        return self.nmap['runstats']['hosts'].get('down', 0)
476
477    def set_hosts_down(self, down):
478        self.nmap['runstats']['hosts']['down'] = int(down)
479
480    def get_hosts_up(self):
481        return self.nmap['runstats']['hosts'].get('up', 0)
482
483    def set_hosts_up(self, up):
484        self.nmap['runstats']['hosts']['up'] = int(up)
485
486    def get_hosts_total(self):
487        return self.nmap['runstats']['hosts'].get('total', 0)
488
489    def set_hosts_total(self, scanned):
490        self.nmap['runstats']['hosts']['total'] = int(scanned)
491
492    def get_finish_time(self):
493        return self.nmap['runstats']['finished'].get('timestr', '')
494
495    def set_finish_time(self, finish):
496        self.nmap['runstats']['finished']['timestr'] = finish
497
498    def get_finish_epoch_time(self):
499        return time.localtime(self.nmap['runstats']['finished'].get('time', 0))
500
501    def set_finish_epoch_time(self, epoch_time):
502        self.nmap['runstats']['finished']['time'] = float(epoch_time)
503
504    def get_scan_name(self):
505        return self.nmap.get('scan_name', '')
506
507    def set_scan_name(self, scan_name):
508        self.nmap['scan_name'] = scan_name
509
510    def get_formated_finish_date(self):
511        date = self.finish_epoch_time
512        return '%s %s, %s - %s:%s' % (calendar.month_name[date[1]],
513                                      str(date[2]),
514                                      str(date[0]),
515                                      str(date[3]).zfill(2),
516                                      str(date[4]).zfill(2))
517
518    def _verify_output_options(self, command):
519        found = re.findall('(-o[XGASN]{1}) {0,1}', command)
520        splited = command.split(' ')
521
522        if found:
523            for option in found:
524                pos = splited.index(option)
525                del splited[pos+1]
526                del splited[pos]
527
528        return ' '.join(splited)
529
530    def get_comments(self):
531        return [host.comment for host in self.nmap['hosts']]
532
533    profile = property(get_profile, set_profile)
534    profile_name = property(get_profile_name, set_profile_name)
535    profile_description = property(get_profile_description,
536                                   set_profile_description)
537    profile_hint = property(get_profile_hint, set_profile_hint)
538    profile_annotation = property(get_profile_annotation,
539                                  set_profile_annotation)
540    profile_options = property(get_profile_options, set_profile_options)
541    target = property(get_target, set_target)
542    nmap_output = property(get_nmap_output, set_nmap_output)
543    debugging_level = property(get_debugging_level, set_debugging_level)
544    verbose_level = property(get_verbose_level, set_verbose_level)
545    scaninfo = property(get_scaninfo, set_scaninfo)
546    services_scanned = property(get_services_scanned)
547    nmap_command = property(get_nmap_command, set_nmap_command)
548    scan_type = property(get_scan_type)
549    protocol = property(get_protocol)
550    num_services = property(get_num_services)
551    date = property(get_date, set_date)
552    open_ports = property(get_open_ports)
553    filtered_ports = property(get_filtered_ports)
554    closed_ports = property(get_closed_ports)
555    formated_date = property(get_formated_date)
556    scanner = property(get_scanner, set_scanner)
557    scanner_version = property(get_scanner_version, set_scanner_version)
558    ipv4 = property(get_ipv4_addresses)
559    mac = property(get_mac_addresses)
560    ipv6 = property(get_ipv6_addresses)
561    hostnames = property(get_hostnames)
562    ports = property(get_ports)
563    hosts = property(get_hosts)
564    runstats = property(get_runstats, set_runstats)
565    hosts_down = property(get_hosts_down, set_hosts_down)
566    hosts_up = property(get_hosts_up, set_hosts_up)
567    hosts_total = property(get_hosts_total, set_hosts_total)
568    finish_time = property(get_finish_time, set_finish_time)
569    finish_epoch_time = property(get_finish_epoch_time, set_finish_epoch_time)
570    formated_finish_date = property(get_formated_finish_date)
571    comments = property(get_comments)
572    start = property(get_start, set_start)
573    scan_name = property(get_scan_name, set_scan_name)
574
575
576class NmapParserSAX(ParserBasics, ContentHandler):
577    def __init__(self):
578        ParserBasics.__init__(self)
579        self.id_sequence = 0
580
581        self.in_run_stats = False
582        self.in_host = False
583        self.in_ports = False
584        self.in_port = False
585        self.in_os = False
586        self.in_trace = False
587
588        # _tmp_port is used while parsing a port entity
589        self._tmp_port = {}
590
591        self.nmap_xml_file = None
592        self.unsaved = False
593
594    def set_parser(self, parser):
595        self.parser = parser
596
597    def set_xml_file(self, nmap_xml_file):
598        self.nmap_xml_file = nmap_xml_file
599
600    def parse(self):
601        if self.nmap_xml_file:
602            if isinstance(self.nmap_xml_file, basestring):
603                self.parser.parse(self.nmap_xml_file)
604            else:
605                self.nmap_xml_file.seek(0)
606                self.parser.parse(self.nmap_xml_file)
607        else:
608            raise Exception("There's no file to be parsed!")
609
610    def generate_id(self):
611        self.id_sequence += 1
612        return self.id_sequence
613
614    def _parse_nmaprun(self, attrs):
615        d = self.nmap['nmaprun']
616
617        self.scanner = attrs.get('scanner', '')
618        self.scanner_version = attrs.get('version', '')
619        self.start = attrs.get('start', '')
620        self.nmap_command = attrs.get('args', '')
621        d['xmloutputversion'] = attrs.get('xmloutputversion', '')
622
623        # Umit extension
624        self.nmap_output = attrs.get('nmap_output', '')
625        self.profile = attrs.get('profile', '')
626        self.profile_name = attrs.get('profile_name', '')
627        self.profile_hint = attrs.get('hint', '')
628        self.profile_description = attrs.get('description', '')
629        self.profile_annotation = attrs.get('annotation', '')
630        self.profile_options = attrs.get('options', '')
631        self.target = attrs.get('target', '')
632        self.scan_name = attrs.get('scan_name', '')
633
634    def _parse_runstats_finished(self, attrs):
635        self.finish_time = attrs.get('timestr', '')
636        self.finish_epoch_time = attrs.get('time', 0)
637
638    def _parse_runstats_hosts(self, attrs):
639        self.hosts_up = attrs.get('up', 0)
640        self.hosts_down = attrs.get('down', 0)
641        self.hosts_total = attrs.get('total', 0)
642
643    def _parse_host(self, attrs):
644        self.host_info = HostInfo(self.generate_id())
645        # Umit extension
646        self.host_info.comment = attrs.get('comment', '')
647
648
649    def startElement(self, name, attrs):
650        # AttributesImplDict is used here so utils/xmldisplay.py can display
651        # instances of AttributesImpl without any effort.
652        attrs = AttributesImplDict(attrs)
653
654        if name == 'nmaprun':
655            self._parse_nmaprun(attrs)
656
657        elif name in ('verbose', 'debugging'):
658            getattr(self, 'set_%s' % name)(attrs.copy())
659
660        elif name in ('scaninfo', 'taskbegin', 'taskprogress', 'taskend'):
661            self.nmap[name].append(attrs.copy())
662
663        # Parse runstats
664        elif name == 'runstats':
665            self.in_run_stats = True
666        elif self.in_run_stats and name == 'finished':
667            self._parse_runstats_finished(attrs)
668        elif self.in_run_stats and name == 'hosts':
669            self._parse_runstats_hosts(attrs)
670
671        # Parse hosts
672        elif name == 'host':
673            self.in_host = True
674            self._parse_host(attrs)
675        elif self.in_host and name in ('status', 'times', 'smurf', 'distance',
676                'uptime', 'tcpsequence', 'tcptssequence', 'ipidsequence'):
677            setattr(self.host_info, name, attrs.copy())
678        elif self.in_host and name in ('address', 'hostscript'):
679            getattr(self.host_info, name).append(attrs.copy())
680        elif self.in_host and name == 'hostnames':
681            self.in_hostnames = True
682        elif self.in_host and self.in_hostnames and name == 'hostname':
683            self.host_info.hostnames.append(attrs.copy())
684        # port
685        elif self.in_host and name == 'ports':
686            self.in_ports = True
687        elif self.in_host and self.in_ports and name == 'extraports':
688            # XXX extrareasons not supported yet
689            self.host_info.extraports.append(attrs.copy())
690        elif self.in_host and self.in_ports and name == 'port':
691            self.in_port = True
692            self._tmp_port.update(attrs)
693        elif self.in_host and self.in_ports and \
694                self.in_port and name in ('state', 'service'):
695            self._tmp_port.update(attrs)
696        # os
697        elif self.in_host and name == 'os':
698            self.in_os = True
699        elif self.in_host and self.in_os and name in ('osmatch',
700                'osclass', 'portused', 'osfingerprint'):
701            getattr(self.host_info, name).append(attrs.copy())
702        # trace
703        elif self.in_host and name == 'trace':
704            self.in_trace = True
705            self.host_info.trace.update(attrs.copy())
706        elif self.in_trace and name == 'hop':
707            self.host_info.trace['hop'].append(attrs.copy())
708
709
710    def endElement(self, name):
711        if name == 'runstats':
712            self.in_run_stats = False
713        elif name == 'host':
714            self.in_host = False
715            self.nmap['hosts'].append(self.host_info)
716            del self.host_info
717        elif self.in_host and name == 'hostnames':
718            self.in_hostnames = False
719        elif self.in_host and name == 'ports':
720            self.in_ports = False
721        elif self.in_host and self.in_ports and name == 'port':
722            self.in_port = False
723            self.host_info.ports.append(self._tmp_port.copy())
724            self._tmp_port.clear()
725        elif self.in_host and self.in_os and name == 'os':
726            self.in_os = False
727        elif self.in_host and name == 'trace':
728            self.in_trace = False
729
730
731    def write_xml(self, xml_file):
732        xml_file = self._verify_file(xml_file)
733        self.write_parser = XMLGenerator(xml_file)
734
735        # First, start the document:
736        self.write_parser.startDocument()
737
738        # Nmaprun element:
739        self._write_nmaprun()
740
741        # Scaninfo element:
742        self._write_scaninfo()
743
744        # Verbose element:
745        self._write_verbose()
746
747        # Debugging element:
748        self._write_debugging()
749
750        # Hosts elements:
751        self._write_hosts()
752
753        # Runstats element:
754        self._write_runstats()
755
756        # End of the xml file:
757        self.write_parser.endElement('nmaprun')
758        self.write_parser.endDocument()
759
760    def _write_runstats(self):
761        ##################
762        # Runstats element
763        self.write_parser.startElement('runstats', AttributesImpl(dict()))
764
765        ## Finished element
766        self.write_parser.startElement('finished',
767                AttributesImpl({
768                    'time': str(time.mktime(self.finish_epoch_time)),
769                    'timestr': self.finish_time})
770                )
771        self.write_parser.endElement('finished')
772
773        ## Hosts element
774        self.write_parser.startElement('hosts',
775                AttributesImpl({
776                    'up': str(self.hosts_up),
777                    'down': str(self.hosts_down),
778                    'total': str(self.hosts_total)})
779                )
780        self.write_parser.endElement('hosts')
781
782
783        self.write_parser.endElement('runstats')
784        # End of Runstats element
785        #########################
786
787    def _write_hosts(self):
788        for host in self.hosts:
789            # Start host element
790            self.write_parser.startElement('host',
791                    AttributesImpl({
792                        'comment': host.comment})
793                    )
794
795            # Status element
796            self.write_parser.startElement('status',
797                    AttributesImpl({
798                        'state': host.status['state']})
799                    )
800            self.write_parser.endElement('status')
801
802
803            ##################
804            # Address elements
805            for address in host.address:
806                self.__remove_none(address)
807                self.write_parser.startElement('address',
808                        AttributesImpl({
809                            'addr': address.get('addr', ''),
810                            'vendor': address.get('vendor', ''),
811                            'addrtype': address.get('addrtype', '')})
812                        )
813                self.write_parser.endElement('address')
814            # End of Address elements
815            #########################
816
817
818            ###################
819            # Hostnames element
820            self.write_parser.startElement('hostnames', AttributesImpl({}))
821
822            for hname in host.hostnames:
823                if not isinstance(hname, dict):
824                    continue
825                self.write_parser.startElement('hostname',
826                        AttributesImpl({
827                            'name': hname.get('name', ''),
828                            'type': hname.get('type', '')})
829                        )
830                self.write_parser.endElement('hostname')
831
832            self.write_parser.endElement('hostnames')
833            # End of Hostnames element
834            ##########################
835
836
837            ###############
838            # Ports element
839            self.write_parser.startElement('ports', AttributesImpl({}))
840
841            ## Extraports elements
842            for export in host.extraports:
843                self.__remove_none(export)
844                self.write_parser.startElement('extraports',
845                        AttributesImpl({
846                            'count': str(export.get('count', '')),
847                            'state': export.get('state', '')})
848                        )
849                self.write_parser.endElement('extraports')
850
851            ## Port elements
852            for port in host.ports:
853                self.__remove_none(port)
854                self.write_parser.startElement('port',
855                    AttributesImpl({
856                        'portid': port.get('portid', ''),
857                        'protocol': port.get('protocol', '')})
858                    )
859
860                ### Port state
861                self.write_parser.startElement('state',
862                        AttributesImpl({
863                            'state': port.get('state', '')})
864                        )
865                self.write_parser.endElement('state')
866
867                ### Port service info
868                self.write_parser.startElement('service',
869                        AttributesImpl({
870                            'conf': port.get('conf', ''),
871                            'method': port.get('method', ''),
872                            'name': port.get('name', ''),
873                            'product': port.get('product', ''),
874                            'version': port.get('version', ''),
875                            'extrainfo': port.get('extrainfo', '')})
876                        )
877                self.write_parser.endElement('service')
878
879                self.write_parser.endElement('port')
880
881            self.write_parser.endElement('ports')
882            # End of Ports element
883            ######################
884
885
886            ############
887            # OS element
888            self.write_parser.startElement('os', AttributesImpl({}))
889
890            ## Ports used elements
891            for pu in host.portused:
892                if not isinstance(pu, dict):
893                    continue
894
895                self.__remove_none(pu)
896                self.write_parser.startElement('portused',
897                        AttributesImpl({
898                            'state': pu.get('state', ''),
899                            'proto': pu.get('proto', ''),
900                            'portid': pu.get('portid', '')})
901                        )
902                self.write_parser.endElement('portused')
903
904            ## Osclass elements
905            for oc in host.osclass:
906                if not isinstance(oc, dict):
907                    continue
908
909                self.__remove_none(oc)
910                self.write_parser.startElement('osclass',
911                        AttributesImpl({
912                            'vendor': oc.get('vendor', ''),
913                            'osfamily': oc.get('osfamily', ''),
914                            'type': oc.get('type', ''),
915                            'osgen': oc.get('osgen', ''),
916                            'accuracy': oc.get('accuracy', '')})
917                        )
918                self.write_parser.endElement('osclass')
919
920            ## Osmatch elements
921            for om in host.osmatch:
922                if not isinstance(om, dict):
923                    continue
924
925                self.__remove_none(om)
926                self.write_parser.startElement('osmatch',
927                        AttributesImpl({
928                            'name': om.get('name', ''),
929                            'accuracy': om.get('accuracy', '')})
930                        )
931                self.write_parser.endElement('osmatch')
932
933            ## Osfingerprint element
934            if isinstance(host.osfingerprint, dict):
935                self.__remove_none(host.osfingerprint)
936                self.write_parser.startElement('osfingerprint',
937                        AttributesImpl({
938                            'fingerprint': host.osfingerprint.get(
939                                'fingerprint', '')})
940                        )
941                self.write_parser.endElement('osfingerprint')
942
943
944            self.write_parser.endElement('os')
945            # End of OS element
946            ###################
947
948            # Uptime element
949            if isinstance(host.uptime, dict):
950                self.write_parser.startElement('uptime',
951                        AttributesImpl({
952                            'seconds': host.uptime.get('seconds', ''),
953                            'lastboot': host.uptime.get('lastboot', '')})
954                        )
955                self.write_parser.endElement('uptime')
956
957            #####################
958            # Sequences elementes
959            ## TCP Sequence element
960            if isinstance(host.tcpsequence, dict):
961                self.write_parser.startElement('tcpsequence',
962                        AttributesImpl({
963                            'index': host.tcpsequence.get('index', ''),
964                            'class': host.tcpsequence.get('class', ''),
965                            'difficulty': host.tcpsequence.get('difficulty',
966                                ''),
967                            'values': host.tcpsequence.get('values', '')})
968                        )
969                self.write_parser.endElement('tcpsequence')
970
971            ## IP ID Sequence element
972            if isinstance(host.ipidsequence, dict):
973                self.write_parser.startElement('ipidsequence',
974                        AttributesImpl({
975                            'class': host.ipidsequence.get('class', ''),
976                            'values': host.ipidsequence.get('values', '')})
977                        )
978                self.write_parser.endElement('ipidsequence')
979
980            ## TCP TS Sequence element
981            if isinstance(host.tcptssequence, dict):
982                self.write_parser.startElement('tcptssequence',
983                        AttributesImpl({
984                            'class': host.tcptssequence.get('class', ''),
985                            'values': host.tcptssequence.get('values', '')})
986                        )
987                self.write_parser.endElement('tcptssequence')
988            # End of sequences elements
989            ###########################
990           
991            # Trace elements
992           
993            if isinstance(host.trace, dict):
994                self.write_parser.startElement('trace',
995                        AttributesImpl({
996                            'port': host.trace.get('port', ''),
997                            'proto': host.trace.get('proto', '')})
998                        )
999               
1000                # Write hops:
1001                for hop in host.trace['hop']:
1002                    self.write_parser.startElement('hop',
1003                        AttributesImpl(hop))
1004                    self.write_parser.endElement('hop')
1005               
1006                self.write_parser.endElement('trace')
1007            # End trace elements
1008
1009            # End host element
1010            self.write_parser.endElement('host')
1011
1012    def _write_debugging(self):
1013        self.write_parser.startElement('debugging',
1014                AttributesImpl({
1015                    'level': str(self.debugging_level)})
1016                )
1017        self.write_parser.endElement('debugging')
1018
1019    def _write_verbose(self):
1020        self.write_parser.startElement('verbose',
1021                AttributesImpl({
1022                    'level': str(self.verbose_level)})
1023                )
1024        self.write_parser.endElement('verbose')
1025
1026    def _write_scaninfo(self):
1027        for scan in self.scaninfo:
1028            if not isinstance(scan, dict):
1029                continue
1030
1031            self.write_parser.startElement('scaninfo',
1032                    AttributesImpl({
1033                        'type': scan.get('type', ''),
1034                        'protocol': scan.get('protocol', ''),
1035                        'numservices': scan.get('numservices', ''),
1036                        'services': scan.get('services', '')})
1037                    )
1038            self.write_parser.endElement('scaninfo')
1039
1040    def _write_nmaprun(self):
1041        self.write_parser.startElement('nmaprun',
1042                AttributesImpl({
1043                    'annotation': str(self.profile_annotation),
1044                    'args': str(self.nmap_command),
1045                    'description': str(self.profile_description),
1046                    'hint': str(self.profile_hint),
1047                    'nmap_output': str(self.nmap_output),
1048                    'options': str(self.profile_options),
1049                    'profile': str(self.profile),
1050                    'profile_name': str(self.profile_name),
1051                    'scanner': str(self.scanner),
1052                    'start': str(self.start),
1053                    'startstr': str(self.formated_date),
1054                    'target': str(self.target),
1055                    'version': str(self.scanner_version),
1056                    'scan_name': str(self.scan_name)})
1057                )
1058
1059    def _verify_file(self, xml_file):
1060        # let errors be raised
1061        if isinstance(xml_file, basestring):
1062            xml_file = open(xml_file, 'w')
1063        else:
1064            mode = xml_file.mode
1065            if mode in ('r+', 'w', 'w+'):
1066                xml_file.seek(0)
1067        return xml_file
1068
1069    def __remove_none(self, dic):
1070        # saxutils will have problems if your dic contain any None items
1071        # (it will try to use the replace method, for example, which a
1072        # None object doesn't have).
1073        for k, v in dic.items():
1074            if k is None or v is None:
1075                del dic[k]
1076
1077    def is_unsaved(self):
1078        return self.unsaved
1079
1080
1081def nmap_parser_sax(nmap_xml_file=""):
1082    parser = make_parser()
1083    nmap_parser = NmapParserSAX()
1084
1085    parser.setContentHandler(nmap_parser)
1086    nmap_parser.set_parser(parser)
1087    nmap_parser.set_xml_file(nmap_xml_file)
1088
1089    return nmap_parser
1090
1091NmapParser = nmap_parser_sax
Note: See TracBrowser for help on using the browser.