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