mirror of
https://github.com/nmap/nmap.git
synced 2025-12-09 22:21:29 +00:00
Add script output to Ndiff XML output.
This commit is contained in:
@@ -76,7 +76,7 @@ version 0, which was rather different. -->
|
|||||||
|
|
||||||
<!ELEMENT hostdiff (host | (a, b?) | b)>
|
<!ELEMENT hostdiff (host | (a, b?) | b)>
|
||||||
|
|
||||||
<!ELEMENT host (status | address | hostnames | ports | os | a | b)*>
|
<!ELEMENT host (status | address | hostnames | ports | os | hostscript | a | b)*>
|
||||||
|
|
||||||
<!ELEMENT status EMPTY>
|
<!ELEMENT status EMPTY>
|
||||||
<!ATTLIST status state %host-state; #REQUIRED>
|
<!ATTLIST status state %host-state; #REQUIRED>
|
||||||
@@ -93,13 +93,13 @@ version 0, which was rather different. -->
|
|||||||
<!ELEMENT ports ((extraports* | (a, b))?, (portdiff | port)*)>
|
<!ELEMENT ports ((extraports* | (a, b))?, (portdiff | port)*)>
|
||||||
|
|
||||||
|
|
||||||
<!ELEMENT portdiff ((a, b?) | b)>
|
<!ELEMENT portdiff (port | (a, b?) | b)>
|
||||||
|
|
||||||
<!ELEMENT extraports EMPTY>
|
<!ELEMENT extraports EMPTY>
|
||||||
<!ATTLIST extraports state %port-state; #REQUIRED
|
<!ATTLIST extraports state %port-state; #REQUIRED
|
||||||
count CDATA #REQUIRED>
|
count CDATA #REQUIRED>
|
||||||
|
|
||||||
<!ELEMENT port (state?, service?)>
|
<!ELEMENT port (state | service | script | a | b)*>
|
||||||
<!ATTLIST port protocol %protocol; #REQUIRED
|
<!ATTLIST port protocol %protocol; #REQUIRED
|
||||||
portid CDATA #REQUIRED>
|
portid CDATA #REQUIRED>
|
||||||
|
|
||||||
@@ -113,12 +113,17 @@ version 0, which was rather different. -->
|
|||||||
extrainfo CDATA #IMPLIED
|
extrainfo CDATA #IMPLIED
|
||||||
tunnel CDATA #IMPLIED>
|
tunnel CDATA #IMPLIED>
|
||||||
|
|
||||||
|
<!ELEMENT script EMPTY>
|
||||||
|
<!ATTLIST script id CDATA #REQUIRED
|
||||||
|
output CDATA #REQUIRED>
|
||||||
|
|
||||||
<!ELEMENT os (osmatch | a | b)*>
|
<!ELEMENT os (osmatch | a | b)*>
|
||||||
|
|
||||||
<!ELEMENT osmatch EMPTY>
|
<!ELEMENT osmatch EMPTY>
|
||||||
<!ATTLIST osmatch name CDATA #REQUIRED>
|
<!ATTLIST osmatch name CDATA #REQUIRED>
|
||||||
|
|
||||||
<!ENTITY % diff-elem "(host | hostname | extraports* | port | state | service | os | osmatch*)">
|
<!ELEMENT hostscript (script | a | b)*>
|
||||||
|
|
||||||
|
<!ENTITY % diff-elem "(host | hostname | extraports* | port | state | service | script | os | osmatch* | hostscript)">
|
||||||
<!ELEMENT a %diff-elem;>
|
<!ELEMENT a %diff-elem;>
|
||||||
<!ELEMENT b %diff-elem;>
|
<!ELEMENT b %diff-elem;>
|
||||||
|
|||||||
122
ndiff/ndiff
122
ndiff/ndiff
@@ -174,6 +174,12 @@ class Host(object):
|
|||||||
os_elem.appendChild(self.os_to_dom_fragment(document, os))
|
os_elem.appendChild(self.os_to_dom_fragment(document, os))
|
||||||
elem.appendChild(os_elem)
|
elem.appendChild(os_elem)
|
||||||
|
|
||||||
|
if len(self.script_results) > 0:
|
||||||
|
hostscript_elem = document.createElement(u"hostscript")
|
||||||
|
for sr in self.script_results:
|
||||||
|
hostscript_elem.appendChild(sr.to_dom_fragment(document))
|
||||||
|
elem.appendChild(hostscript_elem)
|
||||||
|
|
||||||
frag.appendChild(elem)
|
frag.appendChild(elem)
|
||||||
return frag
|
return frag
|
||||||
|
|
||||||
@@ -260,7 +266,8 @@ class Port(object):
|
|||||||
d = cmp(self.spec, other.spec)
|
d = cmp(self.spec, other.spec)
|
||||||
if d != 0:
|
if d != 0:
|
||||||
return d
|
return d
|
||||||
return cmp((self.spec, self.service), (other.spec, other.service))
|
return cmp((self.spec, self.service, self.script_results),
|
||||||
|
(other.spec, other.service, other.script_results))
|
||||||
|
|
||||||
def to_dom_fragment(self, document):
|
def to_dom_fragment(self, document):
|
||||||
frag = document.createDocumentFragment()
|
frag = document.createDocumentFragment()
|
||||||
@@ -272,6 +279,8 @@ class Port(object):
|
|||||||
state_elem.setAttribute(u"state", self.state)
|
state_elem.setAttribute(u"state", self.state)
|
||||||
elem.appendChild(state_elem)
|
elem.appendChild(state_elem)
|
||||||
elem.appendChild(self.service.to_dom_fragment(document))
|
elem.appendChild(self.service.to_dom_fragment(document))
|
||||||
|
for sr in self.script_results:
|
||||||
|
elem.appendChild(sr.to_dom_fragment(document))
|
||||||
frag.appendChild(elem)
|
frag.appendChild(elem)
|
||||||
return frag
|
return frag
|
||||||
|
|
||||||
@@ -450,6 +459,7 @@ class HostDiff(object):
|
|||||||
self.ports = []
|
self.ports = []
|
||||||
self.port_diffs = {}
|
self.port_diffs = {}
|
||||||
self.os_diffs = []
|
self.os_diffs = []
|
||||||
|
self.script_result_diffs = []
|
||||||
self.cost = 0
|
self.cost = 0
|
||||||
|
|
||||||
self.diff()
|
self.diff()
|
||||||
@@ -492,6 +502,9 @@ class HostDiff(object):
|
|||||||
self.extraports_changed = True
|
self.extraports_changed = True
|
||||||
self.cost += 1
|
self.cost += 1
|
||||||
|
|
||||||
|
self.script_result_diffs = ScriptResultDiff.diff_lists(self.host_a.script_results, self.host_b.script_results)
|
||||||
|
self.cost += len(self.script_result_diffs)
|
||||||
|
|
||||||
def include_diff(self, diff):
|
def include_diff(self, diff):
|
||||||
# Don't include the diff if the states are only extraports. Include all
|
# Don't include the diff if the states are only extraports. Include all
|
||||||
# diffs, even those with cost == 0, in verbose mode.
|
# diffs, even those with cost == 0, in verbose mode.
|
||||||
@@ -684,6 +697,28 @@ class HostDiff(object):
|
|||||||
if os_elem.hasChildNodes():
|
if os_elem.hasChildNodes():
|
||||||
host_elem.appendChild(os_elem)
|
host_elem.appendChild(os_elem)
|
||||||
|
|
||||||
|
# Host script changes.
|
||||||
|
if len(self.script_result_diffs) > 0 or verbose:
|
||||||
|
hostscript_elem = document.createElement(u"hostscript")
|
||||||
|
if len(host_a.script_results) == 0 and len(host_b.script_results) == 0:
|
||||||
|
pass
|
||||||
|
elif len(host_b.script_results) == 0:
|
||||||
|
a_elem = document.createElement(u"a")
|
||||||
|
for sr in host_a.script_results:
|
||||||
|
a_elem.appendChild(sr.to_dom_fragment(document))
|
||||||
|
a_elem.appendChild(hostscript_elem)
|
||||||
|
host_elem.appendChild(a_elem)
|
||||||
|
elif len(host_a.script_results) == 0:
|
||||||
|
b_elem = document.createElement(u"b")
|
||||||
|
for sr in host_b.script_results:
|
||||||
|
b_elem.appendChild(sr.to_dom_fragment(document))
|
||||||
|
b_elem.appendChild(hostscript_elem)
|
||||||
|
host_elem.appendChild(b_elem)
|
||||||
|
else:
|
||||||
|
for sr_diff in self.script_result_diffs:
|
||||||
|
hostscript_elem.appendChild(sr_diff.to_dom_fragment(document))
|
||||||
|
host_elem.appendChild(hostscript_elem)
|
||||||
|
|
||||||
hostdiff_elem.appendChild(host_elem)
|
hostdiff_elem.appendChild(host_elem)
|
||||||
|
|
||||||
return frag
|
return frag
|
||||||
@@ -694,6 +729,7 @@ class PortDiff(object):
|
|||||||
def __init__(self, port_a, port_b):
|
def __init__(self, port_a, port_b):
|
||||||
self.port_a = port_a
|
self.port_a = port_a
|
||||||
self.port_b = port_b
|
self.port_b = port_b
|
||||||
|
self.script_result_diffs = []
|
||||||
self.cost = 0
|
self.cost = 0
|
||||||
|
|
||||||
self.diff()
|
self.diff()
|
||||||
@@ -708,6 +744,9 @@ class PortDiff(object):
|
|||||||
if self.port_a.service != self.port_b.service:
|
if self.port_a.service != self.port_b.service:
|
||||||
self.cost += 1
|
self.cost += 1
|
||||||
|
|
||||||
|
self.script_result_diffs = ScriptResultDiff.diff_lists(self.port_a.script_results, self.port_b.script_results)
|
||||||
|
self.cost += len(self.script_result_diffs)
|
||||||
|
|
||||||
# PortDiffs are inserted into a Table and then printed, not printed out
|
# PortDiffs are inserted into a Table and then printed, not printed out
|
||||||
# directly. That's why this class has append_to_port_table instead of
|
# directly. That's why this class has append_to_port_table instead of
|
||||||
# print_text.
|
# print_text.
|
||||||
@@ -736,14 +775,83 @@ class PortDiff(object):
|
|||||||
frag = document.createDocumentFragment()
|
frag = document.createDocumentFragment()
|
||||||
portdiff_elem = document.createElement(u"portdiff")
|
portdiff_elem = document.createElement(u"portdiff")
|
||||||
frag.appendChild(portdiff_elem)
|
frag.appendChild(portdiff_elem)
|
||||||
a_elem = document.createElement(u"a")
|
if self.port_a.spec == self.port_b.spec and self.port_a.state == self.port_b.state:
|
||||||
b_elem = document.createElement(u"b")
|
port_elem = document.createElement(u"port")
|
||||||
portdiff_elem.appendChild(a_elem)
|
port_elem.setAttribute(u"portid", unicode(self.port_a.spec[0]))
|
||||||
portdiff_elem.appendChild(b_elem)
|
port_elem.setAttribute(u"protocol", self.port_a.spec[1])
|
||||||
|
if self.port_a.state is not None:
|
||||||
|
state_elem = document.createElement(u"state")
|
||||||
|
state_elem.setAttribute(u"state", self.port_a.state)
|
||||||
|
port_elem.appendChild(state_elem)
|
||||||
|
if self.port_a.service == self.port_b.service:
|
||||||
|
port_elem.appendChild(self.port_a.service.to_dom_fragment(document))
|
||||||
|
else:
|
||||||
|
a_elem = document.createElement(u"a")
|
||||||
|
a_elem.appendChild(self.port_a.service.to_dom_fragment(document))
|
||||||
|
port_elem.appendChild(a_elem)
|
||||||
|
b_elem = document.createElement(u"b")
|
||||||
|
b_elem.appendChild(self.port_b.service.to_dom_fragment(document))
|
||||||
|
port_elem.appendChild(b_elem)
|
||||||
|
for sr_diff in self.script_result_diffs:
|
||||||
|
port_elem.appendChild(sr_diff.to_dom_fragment(document))
|
||||||
|
portdiff_elem.appendChild(port_elem)
|
||||||
|
else:
|
||||||
|
a_elem = document.createElement(u"a")
|
||||||
|
a_elem.appendChild(self.port_a.to_dom_fragment(document))
|
||||||
|
portdiff_elem.appendChild(a_elem)
|
||||||
|
b_elem = document.createElement(u"b")
|
||||||
|
b_elem.appendChild(self.port_b.to_dom_fragment(document))
|
||||||
|
portdiff_elem.appendChild(b_elem)
|
||||||
|
|
||||||
a_elem.appendChild(self.port_a.to_dom_fragment(document))
|
return frag
|
||||||
b_elem.appendChild(self.port_b.to_dom_fragment(document))
|
|
||||||
|
|
||||||
|
class ScriptResultDiff(object):
|
||||||
|
def __init__(self, sr_a, sr_b):
|
||||||
|
"""One of sr_a and sr_b may be None."""
|
||||||
|
self.sr_a = sr_a
|
||||||
|
self.sr_b = sr_b
|
||||||
|
|
||||||
|
def diff_lists(a, b):
|
||||||
|
"""Return a list of ScriptResultDiffs from two sorted lists of
|
||||||
|
ScriptResults."""
|
||||||
|
diffs = []
|
||||||
|
i = 0
|
||||||
|
j = 0
|
||||||
|
# This algorithm is like a merge of sorted lists.
|
||||||
|
while i < len(a) and j < len(b):
|
||||||
|
if a[i].id < b[j].id:
|
||||||
|
diffs.append(ScriptResultDiff(a[i], None))
|
||||||
|
i += 1
|
||||||
|
elif a[i].id > b[j].id:
|
||||||
|
diffs.append(ScriptResultDiff(None, b[j]))
|
||||||
|
j += 1
|
||||||
|
else:
|
||||||
|
if a[i].output != b[j].output or verbose:
|
||||||
|
diffs.append(ScriptResultDiff(a[i], b[j]))
|
||||||
|
i += 1
|
||||||
|
j += 1
|
||||||
|
while i < len(a):
|
||||||
|
diffs.append(ScriptResultDiff(a[i], None))
|
||||||
|
i += 1
|
||||||
|
while j < len(b):
|
||||||
|
diffs.append(ScriptResultDiff(None, b[j]))
|
||||||
|
j += 1
|
||||||
|
return diffs
|
||||||
|
diff_lists = staticmethod(diff_lists)
|
||||||
|
|
||||||
|
def to_dom_fragment(self, document):
|
||||||
|
frag = document.createDocumentFragment()
|
||||||
|
if self.sr_a is not None and self.sr_b is not None and self.sr_a == self.sr_b:
|
||||||
|
frag.appendChild(self.sr_a.to_dom_fragment(document))
|
||||||
|
else:
|
||||||
|
if self.sr_a is not None:
|
||||||
|
a_elem = document.createElement(u"a")
|
||||||
|
a_elem.appendChild(self.sr_a.to_dom_fragment(document))
|
||||||
|
frag.appendChild(a_elem)
|
||||||
|
if self.sr_b is not None:
|
||||||
|
b_elem = document.createElement(u"b")
|
||||||
|
b_elem.appendChild(self.sr_b.to_dom_fragment(document))
|
||||||
|
frag.appendChild(b_elem)
|
||||||
return frag
|
return frag
|
||||||
|
|
||||||
class Table(object):
|
class Table(object):
|
||||||
|
|||||||
@@ -323,7 +323,7 @@ class scan_diff_test(unittest.TestCase):
|
|||||||
diff = ScanDiff(a, b)
|
diff = ScanDiff(a, b)
|
||||||
scan_apply_diff(a, diff)
|
scan_apply_diff(a, diff)
|
||||||
diff = ScanDiff(a, b)
|
diff = ScanDiff(a, b)
|
||||||
self.assertEqual(len(diff.host_diffs), 0, "%d != 0 in pair %s" % (len(diff.host_diffs), str(pair)))
|
self.assertEqual(diff.host_diffs, {})
|
||||||
self.assertEqual(set(diff.hosts), set(diff.host_diffs.keys()))
|
self.assertEqual(set(diff.hosts), set(diff.host_diffs.keys()))
|
||||||
|
|
||||||
class parse_port_list_test(unittest.TestCase):
|
class parse_port_list_test(unittest.TestCase):
|
||||||
@@ -712,4 +712,15 @@ def host_apply_diff(host, diff):
|
|||||||
else:
|
else:
|
||||||
host.ports[port.spec] = diff.port_diffs[port].port_b
|
host.ports[port.spec] = diff.port_diffs[port].port_b
|
||||||
|
|
||||||
|
for sr_diff in diff.script_result_diffs:
|
||||||
|
sr_a = sr_diff.sr_a
|
||||||
|
sr_b = sr_diff.sr_b
|
||||||
|
if sr_a is None:
|
||||||
|
host.script_results.append(sr_b)
|
||||||
|
elif sr_b is None:
|
||||||
|
host.script_results.remove(sr_a)
|
||||||
|
else:
|
||||||
|
host.script_results[host.script_results.index(sr_a)] = sr_b
|
||||||
|
host.script_results.sort()
|
||||||
|
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|||||||
Reference in New Issue
Block a user