mirror of
https://github.com/nmap/nmap.git
synced 2026-01-09 07:59:03 +00:00
Remove extraports state inference from Ndiff. This was a feature that,
if there was only one extraports state, would create a Port object for each scanned port that was not listed explictly. So for example, if a scan of 100 ports had 5 open ports and an extraports of "filtered", Ndiff would create 95 port records in the "filtered" state in addition to the 5 "open". If there was more than one extraports state this was not possible. This turned out to be a slow operation, out of all proportion to its utility. Here are times for a diff of random-1.xml and random-2.xml, before and after: real 0m11.912s user 0m10.970s sys 0m0.249s real 0m0.773s user 0m0.726s sys 0m0.046s In most cases extraports are not shown in the output, so this was wasted effort. I know of only one place where it affected the output, when an extraports in the A scan because a non-extraports in a different state in the B scan. Then the previous state would be included in the <a> port, where now it will just be listed without a state.
This commit is contained in:
61
ndiff/ndiff
61
ndiff/ndiff
@@ -959,31 +959,6 @@ class Table(object):
|
||||
lines.append(u"".join(parts).rstrip())
|
||||
return u"\n".join(lines)
|
||||
|
||||
def parse_port_list(port_list):
|
||||
"""Parse a port list like
|
||||
"1-1027,1029-1033,1040,1043,1050,1058-1059,1067-1068,1076,1080,1083-1084"
|
||||
into a list of numbers. Raises ValueError if the port list is somehow
|
||||
invalid."""
|
||||
result = set()
|
||||
if port_list == u"":
|
||||
return list(result)
|
||||
chunks = port_list.split(u",")
|
||||
for chunk in chunks:
|
||||
if u"-" in chunk:
|
||||
start, end = chunk.split(u"-")
|
||||
start = int(start)
|
||||
end = int(end)
|
||||
if start >= end:
|
||||
raise ValueError(u"In range %s, start must be less than end." % chunk)
|
||||
else:
|
||||
start = int(chunk)
|
||||
end = start
|
||||
for p in range(start, end + 1):
|
||||
result.add(p)
|
||||
result = list(result)
|
||||
result.sort()
|
||||
return result
|
||||
|
||||
def warn(str):
|
||||
"""Print a warning to stderr."""
|
||||
print >> sys.stderr, str
|
||||
@@ -999,7 +974,6 @@ class NmapContentHandler(xml.sax.handler.ContentHandler):
|
||||
# popping on end.
|
||||
self.element_stack = []
|
||||
|
||||
self.scanned_ports = {}
|
||||
self.current_host = None
|
||||
self.current_port = None
|
||||
|
||||
@@ -1032,25 +1006,6 @@ class NmapContentHandler(xml.sax.handler.ContentHandler):
|
||||
start_timestamp = int(attrs.get(u"start"))
|
||||
self.scan.start_date = datetime.datetime.fromtimestamp(start_timestamp)
|
||||
self.scan.version = attrs.get(u"version")
|
||||
elif name == u"scaninfo":
|
||||
assert self.parent_element() == u"nmaprun"
|
||||
try:
|
||||
protocol = attrs[u"protocol"]
|
||||
except KeyError:
|
||||
warn(u"%s element missing the \"protocol\" attribute; skipping." % name)
|
||||
return
|
||||
try:
|
||||
services_str = attrs[u"services"]
|
||||
except KeyError:
|
||||
warn(u"%s element missing the \"services\" attribute; skipping." % name)
|
||||
return
|
||||
try:
|
||||
services = parse_port_list(services_str)
|
||||
except ValueError:
|
||||
warn(u"Services list \"%s\" cannot be parsed; skipping.")
|
||||
return
|
||||
assert protocol not in self.scanned_ports
|
||||
self.scanned_ports[protocol] = services
|
||||
elif name == u"host":
|
||||
assert self.parent_element() == u"nmaprun"
|
||||
self.current_host = Host()
|
||||
@@ -1175,21 +1130,7 @@ class NmapContentHandler(xml.sax.handler.ContentHandler):
|
||||
self.scan.end_date = datetime.datetime.fromtimestamp(end_timestamp)
|
||||
|
||||
def endElementAux(self, name):
|
||||
if name == u"nmaprun":
|
||||
self.scanned_ports = None
|
||||
elif name == u"host":
|
||||
if len(self.current_host.extraports) == 1:
|
||||
# We can infer the state of unlisted ports.
|
||||
extraports_state = self.current_host.extraports.keys()[0]
|
||||
known_specs = self.current_host.ports.keys()
|
||||
for protocol in self.scanned_ports:
|
||||
for portid in self.scanned_ports[protocol]:
|
||||
spec = portid, protocol
|
||||
if spec in known_specs:
|
||||
continue
|
||||
assert spec not in self.current_host.ports
|
||||
self.current_host.add_port(Port(spec, state = extraports_state))
|
||||
|
||||
if name == u"host":
|
||||
self.current_host.script_results.sort()
|
||||
self.current_host = None
|
||||
elif name == u"port":
|
||||
|
||||
@@ -32,12 +32,10 @@ class scan_test(unittest.TestCase):
|
||||
self.assertEqual(len(host.ports), 2)
|
||||
|
||||
def test_extraports(self):
|
||||
"""Test that the correct number of known ports is returned when there
|
||||
are extraports in only one state."""
|
||||
scan = Scan()
|
||||
scan.load_from_file("test-scans/single.xml")
|
||||
host = scan.hosts[0]
|
||||
self.assertEqual(len(host.ports), 100)
|
||||
self.assertEqual(len(host.ports), 5)
|
||||
self.assertEqual(host.extraports.items(), [("filtered", 95)])
|
||||
|
||||
def test_extraports_multi(self):
|
||||
@@ -170,7 +168,7 @@ class host_test(unittest.TestCase):
|
||||
s = Scan()
|
||||
s.load_from_file("test-scans/single.xml")
|
||||
h = s.hosts[0]
|
||||
self.assertEqual(len(h.ports), 100)
|
||||
self.assertEqual(len(h.ports), 5)
|
||||
self.assertEqual(len(h.extraports), 1)
|
||||
self.assertEqual(h.extraports.keys()[0], u"filtered")
|
||||
self.assertEqual(h.extraports.values()[0], 95)
|
||||
@@ -326,39 +324,6 @@ class scan_diff_test(unittest.TestCase):
|
||||
self.assertEqual(diff.host_diffs, {})
|
||||
self.assertEqual(set(diff.hosts), set(diff.host_diffs.keys()))
|
||||
|
||||
class parse_port_list_test(unittest.TestCase):
|
||||
"""Test the parse_port_list function."""
|
||||
def test_empty(self):
|
||||
ports = parse_port_list(u"")
|
||||
self.assertEqual(len(ports), 0)
|
||||
|
||||
def test_single(self):
|
||||
ports = parse_port_list(u"1,10,100")
|
||||
self.assertEqual(len(ports), 3)
|
||||
self.assertEqual(set(ports), set([1, 10, 100]))
|
||||
|
||||
def test_range(self):
|
||||
ports = parse_port_list(u"10-20")
|
||||
self.assertEqual(len(ports), 11)
|
||||
self.assertEqual(set(ports), set(range(10, 21)))
|
||||
|
||||
def test_combo(self):
|
||||
ports = parse_port_list(u"1,10,100-102,150")
|
||||
self.assertEqual(set(ports), set([1, 10, 100, 101, 102, 150]))
|
||||
|
||||
def test_dups(self):
|
||||
ports = parse_port_list(u"5,1-10")
|
||||
self.assertEqual(len(ports), 10)
|
||||
self.assertEqual(set(ports), set(range(1, 11)))
|
||||
|
||||
def test_invalid(self):
|
||||
self.assertRaises(ValueError, parse_port_list, u"a")
|
||||
self.assertRaises(ValueError, parse_port_list, u",1")
|
||||
self.assertRaises(ValueError, parse_port_list, u"1,,2")
|
||||
self.assertRaises(ValueError, parse_port_list, u"1,")
|
||||
self.assertRaises(ValueError, parse_port_list, u"1-2-3")
|
||||
self.assertRaises(ValueError, parse_port_list, u"10-1")
|
||||
|
||||
class host_diff_test(unittest.TestCase):
|
||||
"""Test the HostDiff class."""
|
||||
def test_empty(self):
|
||||
|
||||
Reference in New Issue
Block a user