From cac71422e8968a97a070fce8646bf274328e63c1 Mon Sep 17 00:00:00 2001 From: david Date: Sat, 5 May 2012 18:02:41 +0000 Subject: [PATCH] Make osclasses a substructure of osmatch. --- zenmap/radialnet/gui/RadialNet.py | 36 +++++++------ zenmap/radialnet/util/integration.py | 11 +++- zenmap/zenmapCore/NetworkInventory.py | 4 +- zenmap/zenmapCore/NmapParser.py | 68 +++++++++---------------- zenmap/zenmapCore/SearchResult.py | 10 ++-- zenmap/zenmapGUI/Icons.py | 10 +++- zenmap/zenmapGUI/ScanHostDetailsPage.py | 5 +- 7 files changed, 68 insertions(+), 76 deletions(-) diff --git a/zenmap/radialnet/gui/RadialNet.py b/zenmap/radialnet/gui/RadialNet.py index 3523b0414..eb0e8acfb 100644 --- a/zenmap/radialnet/gui/RadialNet.py +++ b/zenmap/radialnet/gui/RadialNet.py @@ -1851,29 +1851,19 @@ class NetNode(Node): if host.uptime.get("seconds") or host.uptime.get("lastboot"): return host.uptime elif info == "device_type": - if len(host.osclasses) == 0: + osmatch = host.get_best_osmatch() + if osmatch is None: + return None + osclasses = osmatch['osclasses'] + if len(osclasses) == 0: return None types = ["router", "wap", "switch", "firewall"] for type in types: - if type in host.osclasses[0].get("type", "").lower(): + if type in osclasses[0].get("type", "").lower(): return type elif info == "os": os = {} - os_classes = [] - for osclass in host.osclasses: - os_class = {} - - os_class["type"] = osclass.get("type", "") - os_class["vendor"] = osclass.get("vendor", "") - #os_class["accuracy"] = int(osclass.get("accuracy", "")) - os_class["accuracy"] = osclass.get("accuracy", "") - os_class["os_family"] = osclass.get("osfamily", "") - os_class["os_gen"] = osclass.get("osgen", "") - - os_classes.append(os_class) - os["classes"] = os_classes - # osmatches if len(host.osmatches) > 0 and \ host.osmatches[0]["accuracy"] != "" and \ @@ -1883,6 +1873,20 @@ class NetNode(Node): os["matches"] = host.osmatches os["matches"][0]["db_line"] = 0 # not supported + os_classes = [] + for osclass in host.osmatches[0]["osclasses"]: + os_class = {} + + os_class["type"] = osclass.get("type", "") + os_class["vendor"] = osclass.get("vendor", "") + #os_class["accuracy"] = int(osclass.get("accuracy", "")) + os_class["accuracy"] = osclass.get("accuracy", "") + os_class["os_family"] = osclass.get("osfamily", "") + os_class["os_gen"] = osclass.get("osgen", "") + + os_classes.append(os_class) + os["classes"] = os_classes + # ports_used if len(host.ports_used) > 0: if os == None: diff --git a/zenmap/radialnet/util/integration.py b/zenmap/radialnet/util/integration.py index 6561ae933..88be49d42 100644 --- a/zenmap/radialnet/util/integration.py +++ b/zenmap/radialnet/util/integration.py @@ -125,12 +125,21 @@ class TracerouteHostInfo(object): self.hostname = None self.ports = [] self.extraports = [] - self.osclasses = [] self.osmatches = [] def get_hostname(self): return self.hostname + def get_best_osmatch(self): + if not self.osmatches: + return None + def osmatch_key(osmatch): + try: + return -float(osmatch["accuracy"]) + except ValueError: + return 0 + return sorted(self.osmatches, key = osmatch_key)[0] + hostnames = property(lambda self: self.hostname and [self.hostname] or []) def make_graph_from_hosts(hosts): diff --git a/zenmap/zenmapCore/NetworkInventory.py b/zenmap/zenmapCore/NetworkInventory.py index 202a1b719..dc286626f 100644 --- a/zenmap/zenmapCore/NetworkInventory.py +++ b/zenmap/zenmapCore/NetworkInventory.py @@ -257,8 +257,7 @@ class NetworkInventory(object): # OS detection fields # Replace old_host's OS detection fields with new_host's if old_host has no # OS detection info or new_host's info is newer. - if len(new_host.osclasses) > 0 and (len(old_host.osclasses) == 0 or old_date < new_date): - old_host.osclasses = new_host.osclasses + if len(new_host.osmatches) > 0 and (len(old_host.osmatches) == 0 or old_date < new_date): old_host.osmatches = new_host.osmatches old_host.ports_used = new_host.ports_used @@ -633,7 +632,6 @@ if __name__ == "__main__": #for port in host.ports: # print " %s: %s" % (port["portid"], port["port_state"]) #print " OS matches: %s" % host.osmatches - #print " OS classes: %s" % host.osclasses #print " Ports used: %s" % host.ports_used #print " Trace: %s" % host.trace #if "hops" in host.trace: diff --git a/zenmap/zenmapCore/NmapParser.py b/zenmap/zenmapCore/NmapParser.py index ef9efa1e3..0585ad92c 100644 --- a/zenmap/zenmapCore/NmapParser.py +++ b/zenmap/zenmapCore/NmapParser.py @@ -111,13 +111,12 @@ from zenmapCore.NmapOptions import NmapOptions, split_quoted, join_quoted from zenmapCore.StringPool import unique # The version of the Nmap DTD this file understands and emits. -XML_OUTPUT_VERSION = "1.03" +XML_OUTPUT_VERSION = "1.04" class HostInfo(object): def __init__(self): self.comment = None; self._tcpsequence = {} - self._osclasses = [] self._osmatches = [] self._ports = [] self._ports_used = [] @@ -137,8 +136,7 @@ class HostInfo(object): clone = HostInfo() clone.comment = self.comment clone._tcpsequence = copy.deepcopy(self._tcpsequence) - clone._osclasses = map(lambda d: copy.deepcopy(d), self._osclasses) - clone._osmatches = self._osmatches + clone._osmatches = copy.deepcopy(self._osmatches) clone._ports = copy.deepcopy(self._ports) clone._ports_used = self._ports_used clone._extraports = self._extraports @@ -188,17 +186,12 @@ class HostInfo(object): return self._ipidsequence return {} - # osclasses is a list containing dicts of the form + # osmatches is a list of dicts of the form + # {'name': u'Linux 2.6.24', 'accuracy': u'98', 'line': u'1000', + # 'osclasses': ...} + # where each 'osclasses' element is a dict of the form # {'vendor': u'Linux', 'osfamily': u'Linux', 'type': u'general purpose', # 'osgen': u'2.6.X', 'accuracy': u'98'} - def set_osclasses(self, classes): - self._osclasses = classes - - def get_osclasses(self): - return self._osclasses - - # osmatches is a list of dicts of the form - # {'name': u'Linux 2.6.24', 'accuracy': u'98', 'line': u'1000'} def set_osmatches(self, matches): self._osmatches = matches @@ -222,22 +215,6 @@ class HostInfo(object): return osmatches[-1] - def get_best_osclass(self): - """Return the OS class with the highest accuracy. If there is a tie, one - of the best matches will be returned.""" - if not self._osclasses: - return None - def osclass_key(osclass): - # Sort first by accuracy, then by name so it's deterministic. - try: - accuracy = float(osclass.get("accuracy", "")) - except ValueError: - accuracy = 0 - return (accuracy, osclass.get("name")) - osclasses = self.osclasses[:] - osclasses.sort(cmp = lambda a, b: cmp(osclass_key(a), osclass_key(b))) - return osclasses[-1] - # ports_used is a list like # [{'state': u'open', 'portid': u'22', 'proto': u'tcp'}, # {'state': u'closed', 'portid': u'25', 'proto': u'tcp'}, @@ -429,7 +406,6 @@ class HostInfo(object): # Properties tcpsequence = property(get_tcpsequence, set_tcpsequence) - osclasses = property(get_osclasses, set_osclasses) osmatches = property(get_osmatches, set_osmatches) ports = property(get_ports, set_ports) ports_used = property(get_ports_used, set_ports_used) @@ -876,7 +852,9 @@ class NmapParserSAX(ParserBasics, ContentHandler): self.dic_port["service_extrainfo"] = attrs.get("extrainfo", "") def _parse_host_osmatch(self, attrs): - self.list_osmatch.append(self._parsing(attrs, [], ['name', 'accuracy', 'line'])) + osmatch = self._parsing(attrs, [], ['name', 'accuracy', 'line']) + osmatch['osclasses'] = [] + self.list_osmatch.append(osmatch) def _parse_host_portused(self, attrs): self.list_portused.append(self._parsing(attrs, ['state', 'proto', 'portid'], [])) @@ -972,12 +950,12 @@ class NmapParserSAX(ParserBasics, ContentHandler): self.in_os = True self.list_portused = [] self.list_osmatch = [] - self.list_osclass = [] elif self.in_host and self.in_os and name == "osmatch": self._parse_host_osmatch(attrs) elif self.in_host and self.in_os and name == "portused": self._parse_host_portused(attrs) elif self.in_host and self.in_os and name == "osclass": + self.list_osclass = [] self._parse_host_osclass(attrs) elif self.in_host and name == "uptime": self._parse_host_uptime(attrs) @@ -1015,15 +993,16 @@ class NmapParserSAX(ParserBasics, ContentHandler): self.in_port = False self.list_ports.append(self.dic_port) del(self.dic_port) + elif self.in_host and self.in_os and name == "osmatch": + self.list_osmatch[-1]['osclasses'].extend(self.list_osclass) + self.list_osclass = [] elif self.in_host and self.in_os and name == "os": self.in_os = False self.host_info.set_ports_used(self.list_portused) self.host_info.set_osmatches(self.list_osmatch) - self.host_info.set_osclasses(self.list_osclass) del(self.list_portused) del(self.list_osmatch) - del(self.list_osclass) elif self.in_host and self.in_trace and name == "trace": self.in_trace = False @@ -1213,22 +1192,21 @@ class NmapParserSAX(ParserBasics, ContentHandler): portid = pu.get("portid", "")))) writer.endElement("portused") - ## Osclass elements - for oc in host.osclasses: - writer.startElement("osclass", - Attributes(dict(vendor = oc.get("vendor", ""), - osfamily = oc.get("osfamily", ""), - type = oc.get("type", ""), - osgen = oc.get("osgen", ""), - accuracy = oc.get("accuracy", "")))) - writer.endElement("osclass") - ## Osmatch elements for om in host.osmatches: writer.startElement("osmatch", Attributes(dict(name = om.get("name", ""), accuracy = om.get("accuracy", ""), line = om.get("line", "")))) + ## Osclass elements + for oc in om['osclasses']: + writer.startElement("osclass", + Attributes(dict(vendor = oc.get("vendor", ""), + osfamily = oc.get("osfamily", ""), + type = oc.get("type", ""), + osgen = oc.get("osgen", ""), + accuracy = oc.get("accuracy", "")))) + writer.endElement("osclass") writer.endElement("osmatch") writer.endElement("os") @@ -1358,7 +1336,7 @@ if __name__ == '__main__': for p in host.ports: print "\t%s" % repr(p) print " Ports used:", repr(host.ports_used) - print " OS Class:", repr(host.osclasses) + print " OS Matches:", repr(host.osmatches) print " Hostnames:", repr(host.hostnames) print " IP:", repr(host.ip) print " IPv6:", repr(host.ipv6) diff --git a/zenmap/zenmapCore/SearchResult.py b/zenmap/zenmapCore/SearchResult.py index 4324058f8..7ad032080 100644 --- a/zenmap/zenmapCore/SearchResult.py +++ b/zenmap/zenmapCore/SearchResult.py @@ -148,15 +148,14 @@ class HostSearch(object): os = os.lower() os_str = "" - osclasses = host.get_osclasses() osmatches = host.get_osmatches() - for osclass in osclasses: - os_str += osclass['vendor'].lower() + " " +\ - osclass['osfamily'].lower() + " " +\ - osclass['type'].lower() for osmatch in osmatches: os_str += osmatch['name'].lower() + for osclass in osmatch['osmatches']: + os_str += osclass['vendor'].lower() + " " +\ + osclass['osfamily'].lower() + " " +\ + osclass['type'].lower() if os in os_str: return True @@ -566,7 +565,6 @@ if __name__ == "__main__": #port_filtered="", #port_closed="", #service="", - #osclass="Microsoft | Windows | 95/98/ME | General Purpose", #osmatch="gentoo", #product="Apache"\ # ): diff --git a/zenmap/zenmapGUI/Icons.py b/zenmap/zenmapGUI/Icons.py index 4dfbc9528..e44f35049 100644 --- a/zenmap/zenmapGUI/Icons.py +++ b/zenmap/zenmapGUI/Icons.py @@ -148,8 +148,11 @@ if pixmap_path: iconfactory.add_default() def get_os_icon(host): - osclass = host.get_best_osclass() osmatch = host.get_best_osmatch() + if osmatch and osmatch['osclasses']: + osclass = osmatch['osclasses'][0] + else: + osclass = None if osclass and osmatch: return get_os(osclass['osfamily'], osmatch['name'], 'icon') @@ -157,8 +160,11 @@ def get_os_icon(host): return get_os(None, None, 'icon') def get_os_logo(host): - osclass = host.get_best_osclass() osmatch = host.get_best_osmatch() + if osmatch and osmatch['osclasses']: + osclass = osmatch['osclasses'][0] + else: + osclass = None if osclass and osmatch: return get_os(osclass['osfamily'], osmatch['name'], 'logo') diff --git a/zenmap/zenmapGUI/ScanHostDetailsPage.py b/zenmap/zenmapGUI/ScanHostDetailsPage.py index 622b83bb2..83495ba03 100644 --- a/zenmap/zenmapGUI/ScanHostDetailsPage.py +++ b/zenmap/zenmapGUI/ScanHostDetailsPage.py @@ -140,7 +140,6 @@ class HostDetails(HIGVBox): os = host.get_best_osmatch() if os: os['portsused'] = host.get_ports_used() - os['osclass'] = host.get_osclasses() self.set_os(os) self.set_tcpseq(host.get_tcpsequence()) @@ -154,7 +153,7 @@ class HostDetails(HIGVBox): self.hostnames_expander = gtk.Expander(''+_('Hostnames')+'') self.os_expander = gtk.Expander(''+_('Operating System')+'') self.portsused_expander = gtk.Expander(''+_('Ports used')+'') - self.osclass_expander = gtk.Expander(''+_('OS Class')+'') + self.osclass_expander = gtk.Expander(''+_('OS Classes')+'') self.tcp_expander = gtk.Expander(''+_('TCP Sequence')+'') self.ip_expander = gtk.Expander(''+_('IP ID Sequence')+'') self.tcpts_expander = gtk.Expander(''+_('TCP TS Sequence')+'') @@ -368,7 +367,7 @@ class HostDetails(HIGVBox): except:pass try: - self.set_osclass(os['osclass']) + self.set_osclass(os['osclasses']) self.osclass_expander.set_use_markup(True) table.attach(self.osclass_expander,0,2,y1,y2) except:pass